antlr3 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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