antlr3 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -1,13 +1,456 @@
1
1
  #!/usr/bin/ruby
2
2
  # encoding: utf-8
3
3
 
4
+ require 'antlr3'
4
5
  require 'rake/tasklib'
6
+ require 'shellwords'
5
7
 
6
8
  module ANTLR3
9
+
10
+ =begin rdoc ANTLR3::CompileTask
11
+
12
+ A rake task-generating utility concerning ANTLR grammar file
13
+ compilation. This is a general utility -- the grammars do
14
+ not have to be targetted for Ruby output; it handles all
15
+ known ANTLR language targets.
16
+
17
+ require 'antlr3/task'
18
+
19
+ ANTLR3::CompileTask.define(
20
+ :name => 'grammars', :output_directory => 'lib/parsers'
21
+ ) do | t |
22
+ t.grammar_set( 'antlr/MainParser.g', 'antlr/MainTree.g' )
23
+
24
+ t.grammar_set( 'antlr/Template.g' ) do | gram |
25
+ gram.output_directory = 'lib/parsers/template'
26
+ gram.debug = true
27
+ end
28
+ end
29
+
30
+
31
+ TODO: finish documentation
32
+
33
+ =end
34
+
7
35
  class CompileTask < Rake::TaskLib
36
+ attr_reader :grammar_sets, :options
37
+ attr_accessor :name
38
+
39
+ def self.define( *grammar_files )
40
+ lib = new( *grammar_files )
41
+ block_given? and yield( lib )
42
+ lib.define
43
+ return( lib )
44
+ end
45
+
46
+ def initialize( *grammar_files )
47
+ grammar_files = [ grammar_files ].flatten!
48
+ options = Hash === grammar_files.last ? grammar_files.pop : {}
49
+ @grammar_sets = []
50
+ @name = options.fetch( :name, 'antlr-grammars' )
51
+ @options = options
52
+ grammar_files.empty? or grammar_set( grammar_files )
53
+ end
54
+
55
+ def target_files
56
+ @grammar_sets.inject( [] ) do | list, set |
57
+ list.concat( set.target_files )
58
+ end
59
+ end
60
+
61
+ def grammar_set( *grammar_files )
62
+ grammar_files = [ grammar_files ].flatten!
63
+ options = @options.merge(
64
+ Hash === grammar_files.last ? grammar_files.pop : {}
65
+ )
66
+ set = GrammarSet.new( grammar_files, options )
67
+ block_given? and yield( set )
68
+ @grammar_sets << set
69
+ return( set )
70
+ end
8
71
 
72
+ def define
73
+ namespace( @name ) do
74
+ desc( "trash all ANTLR-generated source code")
75
+ task( 'clobber' ) do
76
+ for set in @grammar_sets
77
+ set.clean
78
+ end
79
+ end
80
+
81
+ for set in @grammar_sets
82
+ set.define_tasks
83
+ end
84
+
85
+ desc( "compile ANTLR grammars" )
86
+ task( 'compile' => target_files )
87
+ end
88
+ end
9
89
 
90
+
91
+ class CompileTask::GrammarSet
92
+ attr_accessor :antlr_jar, :debug,
93
+ :trace, :profile, :compile_options,
94
+ :java_options
95
+ attr_reader :load_path, :grammars
96
+ attr_writer :output_directory
97
+
98
+ def initialize( grammar_files, options = {} )
99
+ @load_path = grammar_files.map { | f | File.dirname( f ) }
100
+ @load_path.push( '.', @output_directory )
101
+
102
+ if extra_load = options[ :load_path ]
103
+ extra_load = [ extra_load ].flatten
104
+ @load_path.unshift( extra_load )
105
+ end
106
+ @load_path.uniq!
107
+
108
+ @grammars = grammar_files.map do | file |
109
+ GrammarFile.new( self, file )
110
+ end
111
+ @output_directory = nil
112
+ dir = options[ :output_directory ] and @output_directory = dir.to_s
113
+
114
+ @antlr_jar = options.fetch( :antlr_jar, ANTLR3.antlr_jar )
115
+ @debug = options.fetch( :debug, false )
116
+ @trace = options.fetch( :trace, false )
117
+ @profile = options.fetch( :profile, false )
118
+ @compile_options =
119
+ case opts = options[ :compile_options ]
120
+ when Array then opts
121
+ else Shellwords.shellsplit( opts.to_s )
122
+ end
123
+ @java_options =
124
+ case opts = options[ :java_options ]
125
+ when Array then opts
126
+ else Shellwords.shellsplit( opts.to_s )
127
+ end
128
+ end
129
+
130
+ def target_files
131
+ @grammars.map { | gram | gram.target_files }.flatten
132
+ end
133
+
134
+ def output_directory
135
+ @output_directory || '.'
136
+ end
137
+
138
+ def define_tasks
139
+ directory( @output_directory )
140
+ file( @antlr_jar )
141
+
142
+ for grammar in @grammars
143
+ deps = [ @output_directory, @antlr_jar ]
144
+ if vocab = grammar.token_vocab and
145
+ tfile = find_tokens_file( vocab, grammar )
146
+ file( tfile )
147
+ deps << tfile
148
+ end
149
+ grammar.define_tasks( deps )
150
+ end
151
+ end
152
+
153
+ def clean
154
+ for grammar in @grammars
155
+ grammar.clean
156
+ end
157
+ if test( ?d, output_directory ) and ( Dir.entries( output_directory ) - %w( . .. ) ).empty?
158
+ rmdir( output_directory )
159
+ end
160
+ end
10
161
 
162
+ def find_tokens_file( vocab, grammar )
163
+ gram = @grammars.find { | gram | gram.name == vocab } and
164
+ return( gram.tokens_file )
165
+ file = locate( "#{ vocab }.tokens" ) and return( file )
166
+ warn( Util.tidy( <<-END, true ) )
167
+ | unable to locate .tokens file `#{ vocab }' referenced in #{ grammar.path }
168
+ | -- ignoring dependency
169
+ END
170
+ return( nil )
171
+ end
11
172
 
173
+ def locate( file_name )
174
+ dir = @load_path.find do | dir |
175
+ File.file?( File.join( dir, file_name ) )
176
+ end
177
+ dir and return( File.join( dir, file_name ) )
178
+ end
179
+
180
+ def compile( grammar )
181
+ sh( build_command( grammar ) )
182
+ end
183
+
184
+ def build_command( grammar )
185
+ parts = [ 'java', '-cp', @antlr_jar ]
186
+ parts.concat( @java_options )
187
+ parts << 'org.antlr.Tool' << '-fo' << output_directory
188
+ parts << '-debug' if @debug
189
+ parts << '-profile' if @profile
190
+ parts << '-trace' if @trace
191
+ parts.concat( @compile_options )
192
+ parts << grammar.path
193
+ return Shellwords.shelljoin( parts )
194
+ end
12
195
  end
196
+
197
+ class GrammarFile
198
+ LANGUAGES = {
199
+ "ActionScript" => [".as"],
200
+ "CSharp2" => [".cs"],
201
+ "C" => [".c", ".h"],
202
+ "ObjC" => [".m", ".h"],
203
+ "CSharp3" => [".cs"],
204
+ "Cpp" => [".cpp", ".h"],
205
+ "Ruby" => [".rb"],
206
+ "Java" => [".java"],
207
+ "JavaScript" => [".js"],
208
+ "Python" => [".py"],
209
+ "Delphi" => [".pas"],
210
+ "Perl5" => [".pm"]
211
+ }.freeze
212
+ GRAMMAR_TYPES = %w(lexer parser tree combined)
213
+
214
+ ##################################################################
215
+ ######## CONSTRUCTOR #############################################
216
+ ##################################################################
217
+
218
+ def initialize( group, path, options = {} )
219
+ @group = group
220
+ @path = path.to_s
221
+ @imports = []
222
+ @language = 'Java'
223
+ @token_vocab = nil
224
+ @tasks_defined = false
225
+ @extra_dependencies = []
226
+ if extra = options[ :extra_dependencies ]
227
+ extra = [ extra ].flatten
228
+ @extra_dependencies.concat( extra )
229
+ end
230
+
231
+ study
232
+ yield( self ) if block_given?
233
+ fetch_imports
234
+ end
235
+
236
+ ##################################################################
237
+ ######## ATTRIBUTES AND ATTRIBUTE-ISH METHODS ####################
238
+ ##################################################################
239
+ attr_reader :type, :name, :language, :source,
240
+ :token_vocab, :imports, :imported_grammars,
241
+ :path, :group
242
+
243
+ for attr in [ :output_directory, :load_path, :antlr_jar ]
244
+ class_eval( <<-END )
245
+ def #{ attr }
246
+ @group.#{ attr }
247
+ end
248
+ END
249
+ end
250
+
251
+ def lexer_files
252
+ if lexer? then base = @name
253
+ elsif combined? then base = @name + 'Lexer'
254
+ else return( [] )
255
+ end
256
+ return( file_names( base ) )
257
+ end
258
+
259
+ def parser_files
260
+ if parser? then base = @name
261
+ elsif combined? then base = @name + 'Parser'
262
+ else return( [] )
263
+ end
264
+ return( file_names( base ) )
265
+ end
266
+
267
+ def tree_parser_files
268
+ return( tree? ? file_names( @name ) : [] )
269
+ end
270
+
271
+ def file_names( base )
272
+ LANGUAGES.fetch( @language ).map do | ext |
273
+ File.join( output_directory, base + ext )
274
+ end
275
+ end
276
+
277
+ for type in GRAMMAR_TYPES
278
+ class_eval( <<-END )
279
+ def #{ type }?
280
+ @type == #{ type.inspect }
281
+ end
282
+ END
283
+ end
284
+
285
+ def delegate_files( delegate_suffix )
286
+ file_names( "#{ name }_#{ delegate_suffix }" )
287
+ end
288
+
289
+ def tokens_file
290
+ File.join( output_directory, name + '.tokens' )
291
+ end
292
+
293
+ def target_files( all = true )
294
+ targets = [ tokens_file ]
295
+
296
+ for target_type in %w( lexer parser tree_parser )
297
+ for file in self.send( :"#{ target_type }_files")
298
+ targets << file
299
+ end
300
+ end
301
+
302
+ if all
303
+ for grammar in @imported_grammars
304
+ targets.concat( grammar.target_files )
305
+ end
306
+ end
307
+
308
+ return targets
309
+ end
310
+
311
+ def update
312
+ touch( @path )
313
+ end
314
+
315
+ def all_imported_files
316
+ imported_files = []
317
+ for grammar in @imported_grammars
318
+ imported_files.push( grammar.path, *grammar.all_imported_files )
319
+ end
320
+ return imported_files
321
+ end
322
+
323
+ def clean
324
+ deleted = []
325
+ for target in target_files
326
+ if test( ?f, target )
327
+ rm( target )
328
+ deleted << target
329
+ end
330
+ end
331
+
332
+ for grammar in @imported_grammars
333
+ deleted.concat( grammar.clean )
334
+ end
335
+
336
+ return deleted
337
+ end
338
+
339
+ def define_tasks( shared_depends )
340
+ unless @tasks_defined
341
+ depends = [ @path, *all_imported_files ]
342
+ for f in depends
343
+ file( f )
344
+ end
345
+ depends = shared_depends + depends
346
+
347
+ target_files.each do | target |
348
+ file( target => depends ) do
349
+ @group.compile( self )
350
+ end
351
+ end
352
+
353
+ @tasks_defined = true
354
+ end
355
+ end
356
+
357
+ private
358
+
359
+ def fetch_imports
360
+ @imported_grammars = @imports.map do | imp |
361
+ file = group.locate( "#{ imp }.g" ) or raise( Util.tidy( <<-END ) )
362
+ | #{ @path }: unable to locate imported grammar file #{ imp }.g
363
+ | search directories ( @load_path ):
364
+ | - #{ load_path.join( "\n - " ) }
365
+ END
366
+ Imported.new( self, file )
367
+ end
368
+ end
369
+
370
+ def study
371
+ @source = File.read( @path )
372
+ @source =~ /^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/ or
373
+ raise Grammar::FormatError[ @source, @path ]
374
+ @name = $2
375
+ @type = $1 || 'combined'
376
+ if @source =~ /^\s*options\s*\{(.*?)\}/m
377
+ option_block = $1
378
+ if option_block =~ /\s*language\s*=\s*(\S+)\s*;/
379
+ @language = $1
380
+ LANGUAGES.has_key?( @language ) or
381
+ raise( Grammar::FormatError, "Unknown ANTLR target language: %p" % @language )
382
+ end
383
+ option_block =~ /\s*tokenVocab\s*=\s*(\S+)\s*;/ and
384
+ @token_vocab = $1
385
+ end
386
+
387
+ @source.scan(/^\s*import\s+(\w+\s*(?:,\s*\w+\s*)*);/) do
388
+ list = $1.strip
389
+ @imports.concat( list.split( /\s*,\s*/ ) )
390
+ end
391
+ end
392
+ end # class Grammar
393
+
394
+ class GrammarFile::Imported < GrammarFile
395
+ def initialize( owner, path )
396
+ @owner = owner
397
+ @path = path.to_s
398
+ @imports = []
399
+ @language = 'Java'
400
+ @token_vocab = nil
401
+ study
402
+ fetch_imports
403
+ end
404
+
405
+ for attr in [ :load_path, :output_directory, :antlr_jar, :verbose, :group ]
406
+ class_eval( <<-END )
407
+ def #{ attr }
408
+ @owner.#{ attr }
409
+ end
410
+ END
411
+ end
412
+
413
+ def delegate_files( suffix )
414
+ @owner.delegate_files( "#{ @name }_#{ suffix }" )
415
+ end
416
+
417
+ def target_files
418
+ targets = [ tokens_file ]
419
+ targets.concat( @owner.delegate_files( @name ) )
420
+ return( targets )
421
+ end
13
422
  end
423
+
424
+ class GrammarFile::FormatError < StandardError
425
+ attr_reader :file, :source
426
+
427
+ def self.[](*args)
428
+ new(*args)
429
+ end
430
+
431
+ def initialize(source, file = nil)
432
+ @file = file
433
+ @source = source
434
+ message = ''
435
+ if file.nil? # inline
436
+ message << "bad inline grammar source:\n"
437
+ message << ("-" * 80) << "\n"
438
+ message << @source
439
+ message[-1] == ?\n or message << "\n"
440
+ message << ("-" * 80) << "\n"
441
+ message << "could not locate a grammar name and type declaration matching\n"
442
+ message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
443
+ else
444
+ message << 'bad grammar source in file %p' % @file
445
+ message << ("-" * 80) << "\n"
446
+ message << @source
447
+ message[-1] == ?\n or message << "\n"
448
+ message << ("-" * 80) << "\n"
449
+ message << "could not locate a grammar name and type declaration matching\n"
450
+ message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
451
+ end
452
+ super(message)
453
+ end
454
+ end # error Grammar::FormatError
455
+ end # class CompileTask
456
+ end # module ANTLR3
@@ -5,7 +5,6 @@ require 'antlr3'
5
5
  require 'antlr3/test/core-extensions'
6
6
  require 'antlr3/test/call-stack'
7
7
 
8
-
9
8
  if RUBY_VERSION =~ /^1\.9/
10
9
  require 'digest/md5'
11
10
  MD5 = Digest::MD5
@@ -13,7 +12,6 @@ else
13
12
  require 'md5'
14
13
  end
15
14
 
16
-
17
15
  module ANTLR3
18
16
  module Test
19
17
  module DependantFile
@@ -696,6 +696,7 @@ Tree adaptors are tasked with:
696
696
  module TreeAdaptor
697
697
  include TokenFactory
698
698
  include Constants
699
+ include Error
699
700
 
700
701
  def add_child( tree, child )
701
702
  tree.add_child( child ) if tree and child
@@ -20,7 +20,7 @@ module ANTLR3
20
20
  #
21
21
  MAJOR_VERSION = 1
22
22
  MINOR_VERSION = 3
23
- PATCH_VERSION = 0
23
+ PATCH_VERSION = 1
24
24
  VERSION = [ MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION ]
25
25
  VERSION_STRING = VERSION.join('.').freeze
26
26
 
@@ -28,7 +28,7 @@ $:.unshift( this_directory ) unless $:.include?( this_directory )
28
28
 
29
29
  antlr_load_failed = proc do
30
30
  load_path = $LOAD_PATH.map { |dir| ' - ' \<\< dir }.join( $/ )
31
- raise LoadError, \<\<-'END'.strip!
31
+ raise LoadError, \<\<-END.strip!
32
32
 
33
33
  Failed to load the ANTLR3 runtime library (version <runtimeLibraryVersion()>):
34
34
 
@@ -1498,4 +1498,4 @@ placeAction(scope, name) ::= <<
1498
1498
  <endif>
1499
1499
  >>
1500
1500
 
1501
- runtimeLibraryVersion() ::= "1.3.0"
1501
+ runtimeLibraryVersion() ::= "1.3.1"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: antlr3
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle Yetter
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-02 00:00:00 -05:00
12
+ date: 2010-01-07 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15