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