antlr3 1.2.3

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.
Files changed (85) hide show
  1. data/ANTLR-LICENSE.txt +26 -0
  2. data/History.txt +66 -0
  3. data/README.txt +139 -0
  4. data/bin/antlr4ruby +33 -0
  5. data/java/RubyTarget.java +524 -0
  6. data/java/antlr-full-3.2.1.jar +0 -0
  7. data/lib/antlr3.rb +176 -0
  8. data/lib/antlr3/constants.rb +88 -0
  9. data/lib/antlr3/debug.rb +701 -0
  10. data/lib/antlr3/debug/event-hub.rb +210 -0
  11. data/lib/antlr3/debug/record-event-listener.rb +25 -0
  12. data/lib/antlr3/debug/rule-tracer.rb +55 -0
  13. data/lib/antlr3/debug/socket.rb +360 -0
  14. data/lib/antlr3/debug/trace-event-listener.rb +92 -0
  15. data/lib/antlr3/dfa.rb +247 -0
  16. data/lib/antlr3/dot.rb +174 -0
  17. data/lib/antlr3/error.rb +657 -0
  18. data/lib/antlr3/main.rb +561 -0
  19. data/lib/antlr3/modes/ast-builder.rb +41 -0
  20. data/lib/antlr3/modes/filter.rb +56 -0
  21. data/lib/antlr3/profile.rb +322 -0
  22. data/lib/antlr3/recognizers.rb +1280 -0
  23. data/lib/antlr3/streams.rb +985 -0
  24. data/lib/antlr3/streams/interactive.rb +91 -0
  25. data/lib/antlr3/streams/rewrite.rb +412 -0
  26. data/lib/antlr3/test/call-stack.rb +57 -0
  27. data/lib/antlr3/test/config.rb +23 -0
  28. data/lib/antlr3/test/core-extensions.rb +269 -0
  29. data/lib/antlr3/test/diff.rb +165 -0
  30. data/lib/antlr3/test/functional.rb +207 -0
  31. data/lib/antlr3/test/grammar.rb +371 -0
  32. data/lib/antlr3/token.rb +592 -0
  33. data/lib/antlr3/tree.rb +1415 -0
  34. data/lib/antlr3/tree/debug.rb +163 -0
  35. data/lib/antlr3/tree/visitor.rb +84 -0
  36. data/lib/antlr3/tree/wizard.rb +481 -0
  37. data/lib/antlr3/util.rb +149 -0
  38. data/lib/antlr3/version.rb +27 -0
  39. data/samples/ANTLRv3Grammar.g +621 -0
  40. data/samples/Cpp.g +749 -0
  41. data/templates/AST.stg +335 -0
  42. data/templates/ASTDbg.stg +40 -0
  43. data/templates/ASTParser.stg +153 -0
  44. data/templates/ASTTreeParser.stg +272 -0
  45. data/templates/Dbg.stg +192 -0
  46. data/templates/Ruby.stg +1514 -0
  47. data/test/functional/ast-output/auto-ast.rb +797 -0
  48. data/test/functional/ast-output/construction.rb +555 -0
  49. data/test/functional/ast-output/hetero-nodes.rb +753 -0
  50. data/test/functional/ast-output/rewrites.rb +1327 -0
  51. data/test/functional/ast-output/tree-rewrite.rb +1662 -0
  52. data/test/functional/debugging/debug-mode.rb +689 -0
  53. data/test/functional/debugging/profile-mode.rb +165 -0
  54. data/test/functional/debugging/rule-tracing.rb +74 -0
  55. data/test/functional/delegation/import.rb +379 -0
  56. data/test/functional/lexer/basic.rb +559 -0
  57. data/test/functional/lexer/filter-mode.rb +245 -0
  58. data/test/functional/lexer/nuances.rb +47 -0
  59. data/test/functional/lexer/properties.rb +104 -0
  60. data/test/functional/lexer/syn-pred.rb +32 -0
  61. data/test/functional/lexer/xml.rb +206 -0
  62. data/test/functional/main/main-scripts.rb +245 -0
  63. data/test/functional/parser/actions.rb +224 -0
  64. data/test/functional/parser/backtracking.rb +244 -0
  65. data/test/functional/parser/basic.rb +282 -0
  66. data/test/functional/parser/calc.rb +98 -0
  67. data/test/functional/parser/ll-star.rb +143 -0
  68. data/test/functional/parser/nuances.rb +165 -0
  69. data/test/functional/parser/predicates.rb +103 -0
  70. data/test/functional/parser/properties.rb +242 -0
  71. data/test/functional/parser/rule-methods.rb +132 -0
  72. data/test/functional/parser/scopes.rb +274 -0
  73. data/test/functional/token-rewrite/basic.rb +318 -0
  74. data/test/functional/token-rewrite/via-parser.rb +100 -0
  75. data/test/functional/tree-parser/basic.rb +750 -0
  76. data/test/unit/sample-input/file-stream-1 +2 -0
  77. data/test/unit/sample-input/teststreams.input2 +2 -0
  78. data/test/unit/test-dfa.rb +52 -0
  79. data/test/unit/test-exceptions.rb +44 -0
  80. data/test/unit/test-recognizers.rb +55 -0
  81. data/test/unit/test-scheme.rb +62 -0
  82. data/test/unit/test-streams.rb +459 -0
  83. data/test/unit/test-tree-wizard.rb +535 -0
  84. data/test/unit/test-trees.rb +854 -0
  85. metadata +205 -0
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ require 'antlr3'
5
+ require 'antlr3/test/core-extensions'
6
+ require 'antlr3/test/grammar'
7
+ require 'antlr3/test/call-stack'
8
+
9
+ require 'test/unit'
10
+ require 'spec'
11
+
12
+ module ANTLR3
13
+ module Test
14
+ module Location
15
+ attr_accessor :test_path
16
+
17
+ def test_group
18
+ File.basename( test_path, '.rb' )
19
+ end
20
+
21
+ def test_directory
22
+ File.dirname( test_path )
23
+ end
24
+
25
+ def local_path(*parts)
26
+ File.join( test_directory, *parts )
27
+ end
28
+
29
+ def output_directory(name = test_group)
30
+ local_path( name )
31
+ end
32
+
33
+ end # module Location
34
+
35
+ module NameSpace
36
+ def import( ruby_file )
37
+ constants_before = constants
38
+ class_eval(File.read(ruby_file), ruby_file, 1)
39
+ constants - constants_before
40
+ end
41
+
42
+ def import_grammar_targets(grammar)
43
+ # reverse because delegates need to be in the test class's name
44
+ # space before the masters
45
+ for file in grammar.target_files
46
+ import(file)
47
+ end
48
+ end
49
+ end
50
+
51
+ module GrammarManager
52
+ include Location
53
+ include NameSpace
54
+
55
+ DEFAULT_COMPILE_OPTIONS = {}
56
+
57
+ def add_default_compile_option( name, value )
58
+ DEFAULT_COMPILE_OPTIONS[ name ] = value
59
+ end
60
+ module_function :add_default_compile_option
61
+
62
+ if ANTLR_JAR = ENV['ANTLR_JAR'] || ANTLR3.antlr_jar
63
+ add_default_compile_option( :antlr_jar, ANTLR_JAR )
64
+
65
+ Grammar.global_dependency( ANTLR_JAR )
66
+ end
67
+
68
+ def const_missing( name )
69
+ if g = grammars[ name.to_s ]
70
+ compile( g )
71
+ grammars.delete( name.to_s )
72
+ const_get( name )
73
+ else
74
+ super
75
+ end
76
+ end
77
+
78
+ def grammars
79
+ @grammars ||= {}
80
+ end
81
+
82
+ def grammar_count
83
+ grammars.length
84
+ end
85
+
86
+ def load_grammar( name )
87
+ path = local_path( name.to_s )
88
+ path =~ /\.g$/ or path << '.g'
89
+ grammar = Grammar.new( path, :output_directory => output_directory )
90
+ register_grammar( grammar )
91
+ return grammar
92
+ end
93
+
94
+ def inline_grammar(source, options = {})
95
+ call = call_stack.find { |call| call.file != __FILE__}
96
+ grammar = Grammar.inline source,
97
+ :output_directory => output_directory,
98
+ :file => (call.file rescue nil),
99
+ :line => (call.line rescue nil)
100
+ register_grammar(grammar)
101
+ return grammar
102
+ end
103
+
104
+ def compile_options(defaults = nil)
105
+ @compile_options ||= DEFAULT_COMPILE_OPTIONS.clone
106
+ @compile_options.update(defaults) if defaults
107
+ return @compile_options
108
+ end
109
+
110
+ def compile(grammar, options = {})
111
+ grammar.compile( compile_options.merge(options) )
112
+ import_grammar_targets( grammar )
113
+ return grammar
114
+ end
115
+
116
+ private
117
+
118
+ def register_grammar(grammar)
119
+ name = grammar.name
120
+
121
+ if conflict = grammars[ name ] and conflict.source != grammar.source
122
+ message = "Multiple grammars exist with the name ``#{name}''"
123
+ raise NameError, message
124
+ else
125
+ grammars[ name ] = grammar
126
+ end
127
+ end
128
+ end # module GrammarManager
129
+
130
+ class Functional < ::Test::Unit::TestCase
131
+ extend GrammarManager
132
+
133
+ def self.inherited(klass)
134
+ super
135
+ klass.test_path = call_stack[0].file
136
+ end
137
+
138
+ def local_path(*args)
139
+ self.class.local_path(*args)
140
+ end
141
+
142
+ def test_path
143
+ self.class.test_path
144
+ end
145
+
146
+ def output_directory
147
+ self.class.output_directory
148
+ end
149
+
150
+ def inline_grammar( source )
151
+ call = call_stack.find { |call| call.file != __FILE__}
152
+ grammar = Grammar.inline source,
153
+ :output_directory => output_directory,
154
+ :file => call.file,
155
+ :line => call.line
156
+ end
157
+
158
+ def compile_and_load( grammar, options = {} )
159
+ self.class.compile( grammar, options )
160
+ end
161
+ end # class Functional
162
+
163
+
164
+
165
+ module CaptureOutput
166
+ require 'stringio'
167
+ def output_buffer
168
+ defined?(@output_buffer) or @output_buffer = StringIO.new('')
169
+ @output_buffer
170
+ end
171
+
172
+ def output
173
+ output_buffer.string
174
+ end
175
+
176
+ def say(*args)
177
+ output_buffer.puts(*args)
178
+ end
179
+
180
+ def capture(*args)
181
+ output_buffer.write(*args)
182
+ end
183
+ end
184
+
185
+ module RaiseErrors
186
+ def emit_error_message(msg)
187
+ # do nothing
188
+ end
189
+
190
+ def report_error(error)
191
+ raise error
192
+ end
193
+ end
194
+
195
+ module CollectErrors
196
+ def reported_errors
197
+ defined?(@reported_errors) or @reported_errors = []
198
+ return @reported_errors
199
+ end
200
+
201
+ def emit_error_message(msg)
202
+ reported_errors << msg
203
+ end
204
+ end
205
+
206
+ end # module Test
207
+ end # module ANTLR3
@@ -0,0 +1,371 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ require 'antlr3'
5
+ require 'antlr3/test/core-extensions'
6
+ require 'antlr3/test/call-stack'
7
+
8
+
9
+ if RUBY_VERSION =~ /^1\.9/
10
+ require 'digest/md5'
11
+ MD5 = Digest::MD5
12
+ else
13
+ require 'md5'
14
+ end
15
+
16
+
17
+ module ANTLR3
18
+ module Test
19
+ module DependantFile
20
+ attr_accessor :path, :force
21
+ alias force? force
22
+
23
+ GLOBAL_DEPENDENCIES = []
24
+
25
+ def dependencies
26
+ @dependencies ||= GLOBAL_DEPENDENCIES.clone
27
+ end
28
+
29
+ def depends_on(path)
30
+ path = File.expand_path path.to_s
31
+ dependencies << path if test(?f, path)
32
+ return path
33
+ end
34
+
35
+ def stale?
36
+ force and return(true)
37
+ target_files.any? do |target|
38
+ not test(?f, target) or
39
+ dependencies.any? { |dep| test(?>, dep, target) }
40
+ end
41
+ end
42
+ end # module DependantFile
43
+
44
+ class Grammar
45
+ include DependantFile
46
+
47
+ GRAMMAR_TYPES = %w(lexer parser tree combined)
48
+ TYPE_TO_CLASS = {
49
+ 'lexer' => 'Lexer',
50
+ 'parser' => 'Parser',
51
+ 'tree' => 'TreeParser'
52
+ }
53
+ CLASS_TO_TYPE = TYPE_TO_CLASS.invert
54
+
55
+ def self.global_dependency(path)
56
+ path = File.expand_path path.to_s
57
+ GLOBAL_DEPENDENCIES << path if test(?f, path)
58
+ return path
59
+ end
60
+
61
+ def self.inline(source, *args)
62
+ InlineGrammar.new(source, *args)
63
+ end
64
+
65
+ ##################################################################
66
+ ######## CONSTRUCTOR #############################################
67
+ ##################################################################
68
+ def initialize(path, options = {})
69
+ @path = path.to_s
70
+ @source = prepare_source(File.read(@path))
71
+ @output_directory = options.fetch(:output_directory, '.')
72
+ @verbose = options.fetch( :verbose, $VERBOSE )
73
+ study
74
+ build_dependencies
75
+
76
+ yield(self) if block_given?
77
+ end
78
+
79
+ ##################################################################
80
+ ######## ATTRIBUTES AND ATTRIBUTE-ISH METHODS ####################
81
+ ##################################################################
82
+ attr_reader :type, :name, :source
83
+ attr_accessor :output_directory, :verbose
84
+
85
+ def lexer_class_name
86
+ self.name + "::Lexer"
87
+ end
88
+
89
+ def lexer_file_name
90
+ if lexer? then base = name
91
+ elsif combined? then base = name + 'Lexer'
92
+ else return(nil)
93
+ end
94
+ return(base + '.rb')
95
+ end
96
+
97
+ def parser_class_name
98
+ name + "::Parser"
99
+ end
100
+
101
+ def parser_file_name
102
+ if parser? then base = name
103
+ elsif combined? then base = name + 'Parser'
104
+ else return(nil)
105
+ end
106
+ return(base + '.rb')
107
+ end
108
+
109
+ def tree_parser_class_name
110
+ name + "::TreeParser"
111
+ end
112
+
113
+ def tree_parser_file_name
114
+ tree? and name + '.rb'
115
+ end
116
+
117
+ def has_lexer?
118
+ @type == 'combined' || @type == 'lexer'
119
+ end
120
+
121
+ def has_parser?
122
+ @type == 'combined' || @type == 'parser'
123
+ end
124
+
125
+ def lexer?
126
+ @type == "lexer"
127
+ end
128
+
129
+ def parser?
130
+ @type == "parser"
131
+ end
132
+
133
+ def tree?
134
+ @type == "tree"
135
+ end
136
+
137
+ alias has_tree? tree?
138
+
139
+ def combined?
140
+ @type == "combined"
141
+ end
142
+
143
+
144
+ def target_files(include_imports = true)
145
+ targets = []
146
+
147
+ for target_type in %w(lexer parser tree_parser)
148
+ target_name = self.send(:"#{target_type}_file_name") and
149
+ targets.push( output_directory / target_name )
150
+ end
151
+
152
+ targets.concat( imported_target_files ) if include_imports
153
+ return targets
154
+ end
155
+
156
+ def imports
157
+ @source.scan(/^\s*import\s+(\w+)\s*;/).
158
+ tap { |list| list.flatten! }
159
+ end
160
+
161
+ def imported_target_files
162
+ imports.map! do |delegate|
163
+ output_directory / "#{@name}_#{delegate}.rb"
164
+ end
165
+ end
166
+
167
+ ##################################################################
168
+ ##### COMMAND METHODS ############################################
169
+ ##################################################################
170
+ def compile(options = {})
171
+ if options[:force] or stale?
172
+ compile!(options)
173
+ end
174
+ end
175
+
176
+ def compile!(options = {})
177
+ command = build_command(options)
178
+
179
+ blab( command )
180
+ output = IO.popen(command) do |pipe|
181
+ pipe.read
182
+ end
183
+
184
+ case status = $?.exitstatus
185
+ when 0, 130
186
+ post_compile(options)
187
+ else compilation_failure!(command, status, output)
188
+ end
189
+
190
+ return target_files
191
+ end
192
+
193
+ def clean!
194
+ deleted = []
195
+ for target in target_files
196
+ if test(?f, target)
197
+ File.delete(target)
198
+ deleted << target
199
+ end
200
+ end
201
+ return deleted
202
+ end
203
+
204
+ def inspect
205
+ sprintf( "grammar %s (%s)", @name, @path )
206
+ end
207
+
208
+ private
209
+ def post_compile(options)
210
+ # do nothing for now
211
+ end
212
+
213
+ def blab( string, *args )
214
+ $stderr.printf( string + "\n", *args ) if @verbose
215
+ end
216
+
217
+ def default_antlr_jar
218
+ ENV[ 'ANTLR_JAR' ] || ANTLR3.antlr_jar
219
+ end
220
+
221
+ def compilation_failure!(command, status, output)
222
+ for f in target_files
223
+ test(?f, f) and File.delete(f)
224
+ end
225
+ raise CompilationFailure.new(self, command, status, output)
226
+ end
227
+
228
+ def build_dependencies
229
+ depends_on(@path)
230
+
231
+ if @source =~ /tokenVocab\s*=\s*(\S+)\s*;/
232
+ foreign_grammar_name = $1
233
+ token_file = output_directory / foreign_grammar_name + '.tokens'
234
+ grammar_file = File.dirname( path ) / foreign_grammar_name << '.g'
235
+ depends_on(token_file)
236
+ depends_on(grammar_file)
237
+ end
238
+ end
239
+
240
+ def shell_escape(token)
241
+ token = token.to_s.dup
242
+ token.empty? and return "''"
243
+ token.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, '\\\1')
244
+ token.gsub!(/\n/, "'\n'")
245
+ return token
246
+ end
247
+
248
+ def build_command(options)
249
+ parts = %w(java)
250
+ jar_path = options.fetch( :antlr_jar, default_antlr_jar )
251
+ parts.push('-cp', jar_path)
252
+ parts << 'org.antlr.Tool'
253
+ parts.push('-fo', output_directory)
254
+ options[:profile] and parts << '-profile'
255
+ options[:debug] and parts << '-debug'
256
+ options[:trace] and parts << '-trace'
257
+ options[:debug_st] and parts << '-XdbgST'
258
+ parts << File.expand_path(@path)
259
+ parts.map! { |part| shell_escape(part) }.join(' ') << ' 2>&1'
260
+ end
261
+
262
+ def prepare_source(text)
263
+ text.gsub(/([^\\])%/,'\1\\%').freeze
264
+ end
265
+
266
+ def study
267
+ @source =~ /^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/ or
268
+ raise Grammar::FormatError[source, path]
269
+ @name = $2
270
+ @type = $1 || 'combined'
271
+ end
272
+ end # class Grammar
273
+
274
+ class Grammar::InlineGrammar < Grammar
275
+ attr_accessor :host_file, :host_line
276
+
277
+ def initialize(source, options = {})
278
+ host = call_stack.find { |call| call.file != __FILE__ }
279
+
280
+ @host_file = File.expand_path(options[:file] || host.file)
281
+ @host_line = (options[:line] || host.line)
282
+ @output_directory = options.fetch(:output_directory, File.dirname(@host_file))
283
+ @verbose = options.fetch( :verbose, $VERBOSE )
284
+
285
+ source = source.to_s.fixed_indent(0)
286
+ source.strip!
287
+ @source = prepare_source(source)
288
+ study
289
+ write_to_disk
290
+ build_dependencies
291
+
292
+ yield(self) if block_given?
293
+ end
294
+
295
+ def output_directory
296
+ @output_directory and return @output_directory
297
+ File.basename( @host_file )
298
+ end
299
+
300
+ def path=(v)
301
+ previous, @path = @path, v.to_s
302
+ previous == @path or write_to_disk
303
+ end
304
+
305
+ def inspect
306
+ sprintf( 'inline grammar %s (%s:%s)', name, @host_file, @host_line )
307
+ end
308
+ private
309
+ def write_to_disk
310
+ @path ||= output_directory / @name + '.g'
311
+ test(?d, output_directory) or Dir.mkdir( output_directory )
312
+ unless test(?f, @path) and MD5.digest(@source) == MD5.digest(File.read(@path))
313
+ open(@path, 'w') { |f| f.write(@source) }
314
+ end
315
+ end
316
+ end # class Grammar::InlineGrammar
317
+
318
+ class Grammar::CompilationFailure < StandardError
319
+ JAVA_TRACE = /^(org\.)?antlr\.\S+\(\S+\.java:\d+\)\s*/
320
+ attr_reader :grammar, :command, :status, :output
321
+
322
+ def initialize(grammar, command, status, output)
323
+ @command = command
324
+ @status = status
325
+ @output = output.gsub( JAVA_TRACE, '' )
326
+
327
+ message = <<-END.here_indent! % [command, status, grammar, @output]
328
+ | command ``%s'' failed with status %s
329
+ | %p
330
+ | ~ ~ ~ command output ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
331
+ | %s
332
+ END
333
+
334
+ super( message.chomp! || message )
335
+ end
336
+ end # error Grammar::CompilationFailure
337
+
338
+ class Grammar::FormatError < StandardError
339
+ attr_reader :file, :source
340
+
341
+ def self.[](*args)
342
+ new(*args)
343
+ end
344
+
345
+ def initialize(source, file = nil)
346
+ @file = file
347
+ @source = source
348
+ message = ''
349
+ if file.nil? # inline
350
+ message << "bad inline grammar source:\n"
351
+ message << ("-" * 80) << "\n"
352
+ message << @source
353
+ message[-1] == ?\n or message << "\n"
354
+ message << ("-" * 80) << "\n"
355
+ message << "could not locate a grammar name and type declaration matching\n"
356
+ message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
357
+ else
358
+ message << 'bad grammar source in file %p' % @file
359
+ message << ("-" * 80) << "\n"
360
+ message << @source
361
+ message[-1] == ?\n or message << "\n"
362
+ message << ("-" * 80) << "\n"
363
+ message << "could not locate a grammar name and type declaration matching\n"
364
+ message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/"
365
+ end
366
+ super(message)
367
+ end
368
+ end # error Grammar::FormatError
369
+
370
+ end
371
+ end