1*16467b97STreehugger Robot#!/usr/bin/ruby 2*16467b97STreehugger Robot 3*16467b97STreehugger Robot 4*16467b97STreehugger Robotrequire 'erb' 5*16467b97STreehugger Robotrequire 'antlr3' 6*16467b97STreehugger Robot 7*16467b97STreehugger Robotmodule ANTLR3 8*16467b97STreehugger Robotmodule Template 9*16467b97STreehugger Robotmodule Builder 10*16467b97STreehugger Robot extend ClassMacros 11*16467b97STreehugger Robot 12*16467b97STreehugger Robot module ClassMethods 13*16467b97STreehugger Robot attr_writer :template_library 14*16467b97STreehugger Robot 15*16467b97STreehugger Robot def template_library 16*16467b97STreehugger Robot @template_library ||= ANTLR3::Template::Group.new 17*16467b97STreehugger Robot end 18*16467b97STreehugger Robot 19*16467b97STreehugger Robot def return_scope_members 20*16467b97STreehugger Robot super.push( :template ) 21*16467b97STreehugger Robot end 22*16467b97STreehugger Robot 23*16467b97STreehugger Robot def load_templates( group_file ) 24*16467b97STreehugger Robot @template_library = 25*16467b97STreehugger Robot ANTLR3::Template::Group.load( group_file ) 26*16467b97STreehugger Robot end 27*16467b97STreehugger Robot 28*16467b97STreehugger Robot def define_template( name, source, &block ) 29*16467b97STreehugger Robot template_library.define_template( name, source, &block ) 30*16467b97STreehugger Robot end 31*16467b97STreehugger Robot end 32*16467b97STreehugger Robot 33*16467b97STreehugger Robot def self.included( klass ) 34*16467b97STreehugger Robot super 35*16467b97STreehugger Robot Class === klass and klass.extend( ClassMethods ) 36*16467b97STreehugger Robot end 37*16467b97STreehugger Robot 38*16467b97STreehugger Robot def initialize( input, options = {} ) 39*16467b97STreehugger Robot templates = @templates || options.fetch( :templates ) do 40*16467b97STreehugger Robot self.class.template_library or ANTLR3::Template::Group.new 41*16467b97STreehugger Robot end 42*16467b97STreehugger Robot super( input, options ) 43*16467b97STreehugger Robot self.templates = templates 44*16467b97STreehugger Robot end 45*16467b97STreehugger Robot 46*16467b97STreehugger Robot shared_attribute( :templates ) 47*16467b97STreehugger Robot 48*16467b97STreehugger Robot def create_template( source, values = {} ) 49*16467b97STreehugger Robot @templates.new( source, values ) 50*16467b97STreehugger Robot end 51*16467b97STreehugger Robot 52*16467b97STreehugger Robot def fetch_template( name, values = {} ) 53*16467b97STreehugger Robot @templates.fetch( name, values ) 54*16467b97STreehugger Robot end 55*16467b97STreehugger Robotend 56*16467b97STreehugger Robot 57*16467b97STreehugger Robotmodule RewriteBuilder 58*16467b97STreehugger Robot include Builder 59*16467b97STreehugger Robot 60*16467b97STreehugger Robot def self.included( klass ) 61*16467b97STreehugger Robot super 62*16467b97STreehugger Robot Class === klass and klass.extend( Builder::ClassMethods ) 63*16467b97STreehugger Robot end 64*16467b97STreehugger Robot 65*16467b97STreehugger Robotprivate 66*16467b97STreehugger Robot 67*16467b97STreehugger Robot def cast_input( input, options ) 68*16467b97STreehugger Robot case input 69*16467b97STreehugger Robot when TokenSource then TokenRewriteStream.new( input, options ) 70*16467b97STreehugger Robot when IO, String 71*16467b97STreehugger Robot if lexer_class = self.class.associated_lexer 72*16467b97STreehugger Robot TokenRewriteStream.new( lexer_class.new( input, options ), options ) 73*16467b97STreehugger Robot else 74*16467b97STreehugger Robot raise ArgumentError, Util.tidy( <<-END, true ) 75*16467b97STreehugger Robot | unable to automatically convert input #{ input.inspect } 76*16467b97STreehugger Robot | to a ANTLR3::TokenStream object as #{ self.class } 77*16467b97STreehugger Robot | does not appear to have an associated lexer class 78*16467b97STreehugger Robot END 79*16467b97STreehugger Robot end 80*16467b97STreehugger Robot else 81*16467b97STreehugger Robot super 82*16467b97STreehugger Robot end 83*16467b97STreehugger Robot end 84*16467b97STreehugger Robot 85*16467b97STreehugger Robotend 86*16467b97STreehugger Robot 87*16467b97STreehugger Robot 88*16467b97STreehugger Robotautoload :GroupFile, 'antlr3/template/group-file' 89*16467b97STreehugger Robot 90*16467b97STreehugger Robotclass Group < Module 91*16467b97STreehugger Robot autoload :Lexer, 'antlr3/template/group-file' 92*16467b97STreehugger Robot autoload :Parser, 'antlr3/template/group-file' 93*16467b97STreehugger Robot 94*16467b97STreehugger Robot def self.parse( source, options = {} ) 95*16467b97STreehugger Robot namespace = options.fetch( :namespace, ::Object ) 96*16467b97STreehugger Robot lexer = Lexer.new( source, options ) 97*16467b97STreehugger Robot parser = Parser.new( lexer, options ) 98*16467b97STreehugger Robot return( parser.group( namespace ) ) 99*16467b97STreehugger Robot end 100*16467b97STreehugger Robot 101*16467b97STreehugger Robot def self.load( group_file, options = {} ) 102*16467b97STreehugger Robot unless( File.file?( group_file ) ) 103*16467b97STreehugger Robot dir = $LOAD_PATH.find do | d | 104*16467b97STreehugger Robot File.file?( File.join( dir, group_file ) ) 105*16467b97STreehugger Robot end or raise( LoadError, "no such template group file to load %s" % group_file ) 106*16467b97STreehugger Robot group_file = File.join( dir, group_file ) 107*16467b97STreehugger Robot end 108*16467b97STreehugger Robot namespace = options.fetch( :namespace, ::Object ) 109*16467b97STreehugger Robot input = ANTLR3::FileStream.new( group_file, options ) 110*16467b97STreehugger Robot lexer = Lexer.new( input, options ) 111*16467b97STreehugger Robot parser = Parser.new( lexer, options ) 112*16467b97STreehugger Robot return( parser.group( namespace ) ) 113*16467b97STreehugger Robot end 114*16467b97STreehugger Robot 115*16467b97STreehugger Robot def self.new( &block ) 116*16467b97STreehugger Robot super do 117*16467b97STreehugger Robot const_set( :TEMPLATES, {} ) 118*16467b97STreehugger Robot block_given? and module_eval( &block ) 119*16467b97STreehugger Robot end 120*16467b97STreehugger Robot end 121*16467b97STreehugger Robot 122*16467b97STreehugger Robot def new( source, values = {} ) 123*16467b97STreehugger Robot erb = ERB.new( source, nil, '%' ) 124*16467b97STreehugger Robot template = Context.new( values ) 125*16467b97STreehugger Robot template.extend( self ) 126*16467b97STreehugger Robot sclass = class << template; self; end 127*16467b97STreehugger Robot erb.def_method( sclass, 'to_s' ) 128*16467b97STreehugger Robot return( template ) 129*16467b97STreehugger Robot end 130*16467b97STreehugger Robot 131*16467b97STreehugger Robot def fetch( name, values = {} ) 132*16467b97STreehugger Robot self::TEMPLATES.fetch( name.to_s ).new( values ) 133*16467b97STreehugger Robot end 134*16467b97STreehugger Robot 135*16467b97STreehugger Robot def templates 136*16467b97STreehugger Robot self::TEMPLATES 137*16467b97STreehugger Robot end 138*16467b97STreehugger Robot 139*16467b97STreehugger Robot def template_defined?( name ) 140*16467b97STreehugger Robot self::TEMPLATES.has_key?( name.to_s ) 141*16467b97STreehugger Robot end 142*16467b97STreehugger Robot 143*16467b97STreehugger Robot def define_template( name, source, parameters = nil, &block ) 144*16467b97STreehugger Robot name = name.to_s.dup.freeze 145*16467b97STreehugger Robot Context.define( self, name, parameters ) do | tclass | 146*16467b97STreehugger Robot self::TEMPLATES[ name ] = tclass 147*16467b97STreehugger Robot ERB.new( source, nil, '%' ).def_method( tclass, 'to_s' ) 148*16467b97STreehugger Robot 149*16467b97STreehugger Robot define_template_methods( tclass ) 150*16467b97STreehugger Robot end 151*16467b97STreehugger Robot return( self ) 152*16467b97STreehugger Robot end 153*16467b97STreehugger Robot 154*16467b97STreehugger Robot def alias_template( new_name, old_name ) 155*16467b97STreehugger Robot new_name, old_name = new_name.to_s.dup.freeze, old_name.to_s 156*16467b97STreehugger Robot context = self::TEMPLATES.fetch( old_name.to_s ) do 157*16467b97STreehugger Robot raise( NameError, 158*16467b97STreehugger Robot "undefined template `%s' for template group %p" % [ old_name, self ] 159*16467b97STreehugger Robot ) 160*16467b97STreehugger Robot end 161*16467b97STreehugger Robot context.define_alias( new_name ) do | tclass | 162*16467b97STreehugger Robot self::TEMPLATES[ new_name ] = tclass 163*16467b97STreehugger Robot define_template_methods( tclass ) 164*16467b97STreehugger Robot end 165*16467b97STreehugger Robot return( self ) 166*16467b97STreehugger Robot end 167*16467b97STreehugger Robot 168*16467b97STreehugger Robotprivate 169*16467b97STreehugger Robot 170*16467b97STreehugger Robot def define_template_methods( context ) 171*16467b97STreehugger Robot name = context.name 172*16467b97STreehugger Robot if params = context.parameters 173*16467b97STreehugger Robot init = params.names.map do | param | 174*16467b97STreehugger Robot "___[ #{ param.inspect } ] = #{ param }" 175*16467b97STreehugger Robot end.join( "\n" ) 176*16467b97STreehugger Robot 177*16467b97STreehugger Robot module_eval( <<-END ) 178*16467b97STreehugger Robot module_function 179*16467b97STreehugger Robot 180*16467b97STreehugger Robot def #{ name }( #{ params } ) 181*16467b97STreehugger Robot TEMPLATES[ #{ name.inspect } ].new do | ___ | 182*16467b97STreehugger Robot #{ init } 183*16467b97STreehugger Robot end 184*16467b97STreehugger Robot end 185*16467b97STreehugger Robot 186*16467b97STreehugger Robot def #{ name }!( #{ params } ) 187*16467b97STreehugger Robot TEMPLATES[ #{ name.inspect } ].new do | ___ | 188*16467b97STreehugger Robot #{ init } 189*16467b97STreehugger Robot end.to_s 190*16467b97STreehugger Robot end 191*16467b97STreehugger Robot END 192*16467b97STreehugger Robot 193*16467b97STreehugger Robot else 194*16467b97STreehugger Robot 195*16467b97STreehugger Robot module_eval( <<-END ) 196*16467b97STreehugger Robot module_function 197*16467b97STreehugger Robot 198*16467b97STreehugger Robot def #{ name }( values = {} ) 199*16467b97STreehugger Robot TEMPLATES[ #{ name.inspect } ].new( values ) 200*16467b97STreehugger Robot end 201*16467b97STreehugger Robot 202*16467b97STreehugger Robot def #{ name }!( values = {} ) 203*16467b97STreehugger Robot TEMPLATES[ #{ name.inspect } ].new( values ).to_s 204*16467b97STreehugger Robot end 205*16467b97STreehugger Robot END 206*16467b97STreehugger Robot 207*16467b97STreehugger Robot end 208*16467b97STreehugger Robot end 209*16467b97STreehugger Robotend 210*16467b97STreehugger Robot 211*16467b97STreehugger Robotclass Context 212*16467b97STreehugger Robot VARIABLE_FORM = /^(@)?[a-z_\x80-\xff][\w\x80-\xff]*$/ 213*16467b97STreehugger Robot SETTER_FORM = /^([a-z_\x80-\xff][\w\x80-\xff]*)=$/ 214*16467b97STreehugger Robot ATTR_FORM = /^[a-z_\x80-\xff][\w\x80-\xff]*$/ 215*16467b97STreehugger Robot 216*16467b97STreehugger Robot class << self 217*16467b97STreehugger Robot attr_accessor :group, :name, :parameters 218*16467b97STreehugger Robot protected :group=, :name= 219*16467b97STreehugger Robot 220*16467b97STreehugger Robot def define_alias( name ) 221*16467b97STreehugger Robot new = clone 222*16467b97STreehugger Robot new.name = name 223*16467b97STreehugger Robot new.group = @group 224*16467b97STreehugger Robot block_given? and yield( new ) 225*16467b97STreehugger Robot return( new ) 226*16467b97STreehugger Robot end 227*16467b97STreehugger Robot 228*16467b97STreehugger Robot def define( group, name, parameters ) 229*16467b97STreehugger Robot Class.new( self ) do 230*16467b97STreehugger Robot include( group ) 231*16467b97STreehugger Robot 232*16467b97STreehugger Robot @group = group 233*16467b97STreehugger Robot @name = name 234*16467b97STreehugger Robot @parameters = parameters 235*16467b97STreehugger Robot 236*16467b97STreehugger Robot block_given? and yield( self ) 237*16467b97STreehugger Robot end 238*16467b97STreehugger Robot end 239*16467b97STreehugger Robot end 240*16467b97STreehugger Robot 241*16467b97STreehugger Robot def method_missing( method, *args ) 242*16467b97STreehugger Robot case name = method.to_s 243*16467b97STreehugger Robot when SETTER_FORM then return( self[ $1 ] = args.first ) 244*16467b97STreehugger Robot when ATTR_FORM 245*16467b97STreehugger Robot args.empty? and has_ivar?( name ) and return( self[ name ] ) 246*16467b97STreehugger Robot end 247*16467b97STreehugger Robot super 248*16467b97STreehugger Robot end 249*16467b97STreehugger Robot 250*16467b97STreehugger Robot def []=( name, value ) 251*16467b97STreehugger Robot instance_variable_set( make_ivar( name ), value ) 252*16467b97STreehugger Robot end 253*16467b97STreehugger Robot 254*16467b97STreehugger Robot def []( name ) 255*16467b97STreehugger Robot name = make_ivar( name ) 256*16467b97STreehugger Robot instance_variable_defined?( name ) ? instance_variable_get( name ) : nil 257*16467b97STreehugger Robot end 258*16467b97STreehugger Robot 259*16467b97STreehugger Robot def <<( variable_map ) 260*16467b97STreehugger Robot variable_map.each_pair do | name, value | 261*16467b97STreehugger Robot self[ name ] = value 262*16467b97STreehugger Robot end 263*16467b97STreehugger Robot return( self ) 264*16467b97STreehugger Robot end 265*16467b97STreehugger Robot 266*16467b97STreehugger Robot def initialize( variable_map = nil ) 267*16467b97STreehugger Robot variable_map and self << variable_map 268*16467b97STreehugger Robot block_given? and yield( self ) 269*16467b97STreehugger Robot end 270*16467b97STreehugger Robot 271*16467b97STreehugger Robotprivate 272*16467b97STreehugger Robot 273*16467b97STreehugger Robot def has_ivar?( name ) 274*16467b97STreehugger Robot instance_variable_defined?( make_ivar( name ) ) 275*16467b97STreehugger Robot end 276*16467b97STreehugger Robot 277*16467b97STreehugger Robot def make_ivar( name ) 278*16467b97STreehugger Robot name = name.to_s 279*16467b97STreehugger Robot VARIABLE_FORM =~ name or 280*16467b97STreehugger Robot raise ArgumentError, "cannot convert %p to an instance variable name" % name 281*16467b97STreehugger Robot $1 ? name : "@#{ name }" 282*16467b97STreehugger Robot end 283*16467b97STreehugger Robot 284*16467b97STreehugger Robotend 285*16467b97STreehugger Robot 286*16467b97STreehugger RobotParameter = Struct.new( :name, :default ) 287*16467b97STreehugger Robotclass Parameter 288*16467b97STreehugger Robot def to_s 289*16467b97STreehugger Robot default ? "#{ name } = #{ default }" : "#{ name }" 290*16467b97STreehugger Robot end 291*16467b97STreehugger Robotend 292*16467b97STreehugger Robot 293*16467b97STreehugger Robotclass ParameterList < ::Array 294*16467b97STreehugger Robot attr_accessor :splat, :block 295*16467b97STreehugger Robot 296*16467b97STreehugger Robot def self.default 297*16467b97STreehugger Robot new.add( :values ) do | p | 298*16467b97STreehugger Robot p.default = '{}' 299*16467b97STreehugger Robot end 300*16467b97STreehugger Robot end 301*16467b97STreehugger Robot 302*16467b97STreehugger Robot def names 303*16467b97STreehugger Robot names = map { | param | param.name.to_s } 304*16467b97STreehugger Robot @splat and names << @splat.to_s 305*16467b97STreehugger Robot @block and names << @block.to_s 306*16467b97STreehugger Robot return( names ) 307*16467b97STreehugger Robot end 308*16467b97STreehugger Robot 309*16467b97STreehugger Robot def add( name, options = nil ) 310*16467b97STreehugger Robot param = 311*16467b97STreehugger Robot case name 312*16467b97STreehugger Robot when Parameter then name 313*16467b97STreehugger Robot else Parameter.new( name.to_s ) 314*16467b97STreehugger Robot end 315*16467b97STreehugger Robot if options 316*16467b97STreehugger Robot default = options[ :default ] and param.default = default 317*16467b97STreehugger Robot param.splat = options.fetch( :splat, false ) 318*16467b97STreehugger Robot param.block = options.fetch( :block, false ) 319*16467b97STreehugger Robot end 320*16467b97STreehugger Robot block_given? and yield( param ) 321*16467b97STreehugger Robot push( param ) 322*16467b97STreehugger Robot return( self ) 323*16467b97STreehugger Robot end 324*16467b97STreehugger Robot 325*16467b97STreehugger Robot def to_s 326*16467b97STreehugger Robot signature = join( ', ' ) 327*16467b97STreehugger Robot @splat and signature << ", *" << @splat.to_s 328*16467b97STreehugger Robot @block and signature << ", &" << @block.to_s 329*16467b97STreehugger Robot return( signature ) 330*16467b97STreehugger Robot end 331*16467b97STreehugger Robotend 332*16467b97STreehugger Robotend 333*16467b97STreehugger Robotend 334