antlr3 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ANTLR-LICENSE.txt +26 -0
- data/History.txt +66 -0
- data/README.txt +139 -0
- data/bin/antlr4ruby +33 -0
- data/java/RubyTarget.java +524 -0
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +176 -0
- data/lib/antlr3/constants.rb +88 -0
- data/lib/antlr3/debug.rb +701 -0
- data/lib/antlr3/debug/event-hub.rb +210 -0
- data/lib/antlr3/debug/record-event-listener.rb +25 -0
- data/lib/antlr3/debug/rule-tracer.rb +55 -0
- data/lib/antlr3/debug/socket.rb +360 -0
- data/lib/antlr3/debug/trace-event-listener.rb +92 -0
- data/lib/antlr3/dfa.rb +247 -0
- data/lib/antlr3/dot.rb +174 -0
- data/lib/antlr3/error.rb +657 -0
- data/lib/antlr3/main.rb +561 -0
- data/lib/antlr3/modes/ast-builder.rb +41 -0
- data/lib/antlr3/modes/filter.rb +56 -0
- data/lib/antlr3/profile.rb +322 -0
- data/lib/antlr3/recognizers.rb +1280 -0
- data/lib/antlr3/streams.rb +985 -0
- data/lib/antlr3/streams/interactive.rb +91 -0
- data/lib/antlr3/streams/rewrite.rb +412 -0
- data/lib/antlr3/test/call-stack.rb +57 -0
- data/lib/antlr3/test/config.rb +23 -0
- data/lib/antlr3/test/core-extensions.rb +269 -0
- data/lib/antlr3/test/diff.rb +165 -0
- data/lib/antlr3/test/functional.rb +207 -0
- data/lib/antlr3/test/grammar.rb +371 -0
- data/lib/antlr3/token.rb +592 -0
- data/lib/antlr3/tree.rb +1415 -0
- data/lib/antlr3/tree/debug.rb +163 -0
- data/lib/antlr3/tree/visitor.rb +84 -0
- data/lib/antlr3/tree/wizard.rb +481 -0
- data/lib/antlr3/util.rb +149 -0
- data/lib/antlr3/version.rb +27 -0
- data/samples/ANTLRv3Grammar.g +621 -0
- data/samples/Cpp.g +749 -0
- data/templates/AST.stg +335 -0
- data/templates/ASTDbg.stg +40 -0
- data/templates/ASTParser.stg +153 -0
- data/templates/ASTTreeParser.stg +272 -0
- data/templates/Dbg.stg +192 -0
- data/templates/Ruby.stg +1514 -0
- data/test/functional/ast-output/auto-ast.rb +797 -0
- data/test/functional/ast-output/construction.rb +555 -0
- data/test/functional/ast-output/hetero-nodes.rb +753 -0
- data/test/functional/ast-output/rewrites.rb +1327 -0
- data/test/functional/ast-output/tree-rewrite.rb +1662 -0
- data/test/functional/debugging/debug-mode.rb +689 -0
- data/test/functional/debugging/profile-mode.rb +165 -0
- data/test/functional/debugging/rule-tracing.rb +74 -0
- data/test/functional/delegation/import.rb +379 -0
- data/test/functional/lexer/basic.rb +559 -0
- data/test/functional/lexer/filter-mode.rb +245 -0
- data/test/functional/lexer/nuances.rb +47 -0
- data/test/functional/lexer/properties.rb +104 -0
- data/test/functional/lexer/syn-pred.rb +32 -0
- data/test/functional/lexer/xml.rb +206 -0
- data/test/functional/main/main-scripts.rb +245 -0
- data/test/functional/parser/actions.rb +224 -0
- data/test/functional/parser/backtracking.rb +244 -0
- data/test/functional/parser/basic.rb +282 -0
- data/test/functional/parser/calc.rb +98 -0
- data/test/functional/parser/ll-star.rb +143 -0
- data/test/functional/parser/nuances.rb +165 -0
- data/test/functional/parser/predicates.rb +103 -0
- data/test/functional/parser/properties.rb +242 -0
- data/test/functional/parser/rule-methods.rb +132 -0
- data/test/functional/parser/scopes.rb +274 -0
- data/test/functional/token-rewrite/basic.rb +318 -0
- data/test/functional/token-rewrite/via-parser.rb +100 -0
- data/test/functional/tree-parser/basic.rb +750 -0
- data/test/unit/sample-input/file-stream-1 +2 -0
- data/test/unit/sample-input/teststreams.input2 +2 -0
- data/test/unit/test-dfa.rb +52 -0
- data/test/unit/test-exceptions.rb +44 -0
- data/test/unit/test-recognizers.rb +55 -0
- data/test/unit/test-scheme.rb +62 -0
- data/test/unit/test-streams.rb +459 -0
- data/test/unit/test-tree-wizard.rb +535 -0
- data/test/unit/test-trees.rb +854 -0
- 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
|