1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#!/usr/bin/ruby
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# encoding: utf-8
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3'
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3/test/core-extensions'
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3/test/grammar'
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3/test/call-stack'
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'test/unit'
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'spec'
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule ANTLR3
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule Test
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule Location
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  attr_accessor :test_path
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def test_group
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    File.basename( test_path, '.rb' )
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def test_directory
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    File.dirname( test_path )
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def local_path( *parts )
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    File.join( test_directory, *parts )
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def output_directory( name = test_group )
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    local_path( name )
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # module Location
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule NameSpace
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  #
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # import( ruby_file )   => [ new constants, ... ]
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # Read the source code from the path given by +ruby_file+ and
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # evaluate it within the class body. Return new constants
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # created in the class after the evaluation.
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # 
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def import( ruby_file )
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    constants_before = constants
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    class_eval( File.read( ruby_file ), ruby_file, 1 )
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    constants - constants_before
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def import_grammar_targets( grammar )
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    for file in grammar.target_files
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      import( file )
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule GrammarManager
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  include Location
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  include NameSpace
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  DEFAULT_COMPILE_OPTIONS = {}
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def add_default_compile_option( name, value )
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    DEFAULT_COMPILE_OPTIONS[ name ] = value
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  module_function :add_default_compile_option
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  if ANTLR_JAR = ENV[ 'ANTLR_JAR' ] || ANTLR3.antlr_jar
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    add_default_compile_option( :antlr_jar, ANTLR_JAR )
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    Grammar.global_dependency( ANTLR_JAR )
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  #
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # Compile and load inline grammars on demand when their constant name
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # is referenced in the code. This makes it easier to catch big errors
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # quickly as test cases are run, instead of waiting a few minutes
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # for all grammars to compile, and then discovering there's a big dumb
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # error ruining most of the grammars.
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # 
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def const_missing( name )
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    if g = grammars[ name.to_s ]
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      compile( g )
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      grammars.delete( name.to_s )
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      const_get( name )
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    elsif superclass.respond_to?( :grammars )
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      superclass.const_missing( name )
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # ^-- for some reason, in ruby 1.9, rspec runs examples as instances of
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # anonymous subclasses, of the actual test class, which messes up the
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # assumptions made in the test code. Grammars are stored in @grammars belonging
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # to the test class, so in 1.9, this method is called with @grammars = {}
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      # since it's a subclass
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      super
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # 
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # An index of grammar file objects created in the test class
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # (defined inline or loaded from a file)
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # 
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def grammars
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @grammars ||= {}
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def grammar_count
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammars.length
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def load_grammar( name )
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    path = local_path( name.to_s )
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    path =~ /\.g$/ or path << '.g'
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar = Grammar.new( path, :output_directory => output_directory )
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    register_grammar( grammar )
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return grammar
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def inline_grammar( source, options = {} )
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    call = call_stack.find { |call| call.file != __FILE__ }
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar = Grammar.inline source,
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :output_directory => output_directory,
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :file => ( call.file rescue nil ),
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :line => ( call.line rescue nil )
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    register_grammar( grammar )
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return grammar
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def compile_options( defaults = nil )
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @compile_options ||= DEFAULT_COMPILE_OPTIONS.clone
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @compile_options.update( defaults ) if defaults
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return @compile_options
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def compile( grammar, options = {} )
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar.compile( compile_options.merge( options ) )
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    import_grammar_targets( grammar )
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return grammar
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverprivate
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def register_grammar( grammar )
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    name = grammar.name
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @grammars ||= {}
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    if conflict = @grammars[ name ] and conflict.source != grammar.source
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      message = "Multiple grammars exist with the name ``#{ name }''"
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      raise NameError, message
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @grammars[ name ] = grammar
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # module GrammarManager
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Functional < ::Test::Unit::TestCase
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  extend GrammarManager
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def self.inherited( klass )
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    super
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    klass.test_path = call_stack[ 0 ].file
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def local_path( *args )
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    self.class.local_path( *args )
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def test_path
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    self.class.test_path
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def output_directory
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    self.class.output_directory
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def inline_grammar( source )
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    call = call_stack.find { |call| call.file != __FILE__ }
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    grammar = Grammar.inline source,
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :output_directory => output_directory,
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :file => call.file,
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                :line => call.line
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def compile_and_load( grammar, options = {} )
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    self.class.compile( grammar, options )
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # class Functional
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule CaptureOutput
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  require 'stringio'
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def output_buffer
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    defined?( @output_buffer ) or @output_buffer = StringIO.new( '' )
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @output_buffer
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def output
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    output_buffer.string
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def say( *args )
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    output_buffer.puts( *args )
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def capture( *args )
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    output_buffer.write( *args )
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule RaiseErrors
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def emit_error_message( msg )
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # do nothing
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def report_error( error )
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    raise error
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule CollectErrors
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def reported_errors
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    defined?( @reported_errors ) or @reported_errors = []
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return @reported_errors
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def emit_error_message( msg )
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    reported_errors << msg
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # module Test
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # module ANTLR3
232