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/call-stack' 7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverif RUBY_VERSION =~ /^1\.9/ 9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver require 'digest/md5' 10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver MD5 = Digest::MD5 11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverelse 12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver require 'md5' 13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend 14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule ANTLR3 16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule Test 17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule DependantFile 18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_accessor :path, :force 19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver alias force? force 20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GLOBAL_DEPENDENCIES = [] 22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def dependencies 24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @dependencies ||= GLOBAL_DEPENDENCIES.clone 25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def depends_on( path ) 28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver path = File.expand_path path.to_s 29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dependencies << path if test( ?f, path ) 30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return path 31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def stale? 34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver force and return( true ) 35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target_files.any? do |target| 36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver not test( ?f, target ) or 37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver dependencies.any? { |dep| test( ?>, dep, target ) } 38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # module DependantFile 41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Grammar 43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver include DependantFile 44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GRAMMAR_TYPES = %w(lexer parser tree combined) 46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver TYPE_TO_CLASS = { 47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 'lexer' => 'Lexer', 48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 'parser' => 'Parser', 49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 'tree' => 'TreeParser' 50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver } 51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver CLASS_TO_TYPE = TYPE_TO_CLASS.invert 52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def self.global_dependency( path ) 54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver path = File.expand_path path.to_s 55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver GLOBAL_DEPENDENCIES << path if test( ?f, path ) 56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return path 57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def self.inline( source, *args ) 60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver InlineGrammar.new( source, *args ) 61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ######## CONSTRUCTOR ############################################# 65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def initialize( path, options = {} ) 67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @path = path.to_s 68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source = File.read( @path ) 69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @output_directory = options.fetch( :output_directory, '.' ) 70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @verbose = options.fetch( :verbose, $VERBOSE ) 71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver study 72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver build_dependencies 73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver yield( self ) if block_given? 75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ######## ATTRIBUTES AND ATTRIBUTE-ISH METHODS #################### 79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_reader :type, :name, :source 81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_accessor :output_directory, :verbose 82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def lexer_class_name 84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver self.name + "::Lexer" 85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def lexer_file_name 88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if lexer? then base = name 89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver elsif combined? then base = name + 'Lexer' 90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else return( nil ) 91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return( base + '.rb' ) 93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def parser_class_name 96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver name + "::Parser" 97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def parser_file_name 100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if parser? then base = name 101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver elsif combined? then base = name + 'Parser' 102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else return( nil ) 103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return( base + '.rb' ) 105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def tree_parser_class_name 108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver name + "::TreeParser" 109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def tree_parser_file_name 112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tree? and name + '.rb' 113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def has_lexer? 116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == 'combined' || @type == 'lexer' 117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def has_parser? 120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == 'combined' || @type == 'parser' 121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def lexer? 124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == "lexer" 125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def parser? 128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == "parser" 129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def tree? 132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == "tree" 133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver alias has_tree? tree? 136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def combined? 138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type == "combined" 139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def target_files( include_imports = true ) 142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver targets = [] 143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for target_type in %w(lexer parser tree_parser) 145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver target_name = self.send( :"#{ target_type }_file_name" ) and 146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver targets.push( output_directory / target_name ) 147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver targets.concat( imported_target_files ) if include_imports 150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return targets 151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def imports 154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source.scan( /^\s*import\s+(\w+)\s*;/ ). 155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver tap { |list| list.flatten! } 156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def imported_target_files 159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver imports.map! do |delegate| 160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver output_directory / "#{ @name }_#{ delegate }.rb" 161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ##### COMMAND METHODS ############################################ 166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ################################################################## 167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def compile( options = {} ) 168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if options[ :force ] or stale? 169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver compile!( options ) 170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def compile!( options = {} ) 174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver command = build_command( options ) 175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver blab( command ) 177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver output = IO.popen( command ) do |pipe| 178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver pipe.read 179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver case status = $?.exitstatus 182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver when 0, 130 183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver post_compile( options ) 184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else compilation_failure!( command, status, output ) 185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return target_files 188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def clean! 191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver deleted = [] 192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for target in target_files 193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if test( ?f, target ) 194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver File.delete( target ) 195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver deleted << target 196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return deleted 199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def inspect 202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver sprintf( "grammar %s (%s)", @name, @path ) 203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverprivate 206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def post_compile( options ) 208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver # do nothing for now 209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def blab( string, *args ) 212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver $stderr.printf( string + "\n", *args ) if @verbose 213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def default_antlr_jar 216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver ENV[ 'ANTLR_JAR' ] || ANTLR3.antlr_jar 217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def compilation_failure!( command, status, output ) 220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver for f in target_files 221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver test( ?f, f ) and File.delete( f ) 222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver raise CompilationFailure.new( self, command, status, output ) 224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def build_dependencies 227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver depends_on( @path ) 228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if @source =~ /tokenVocab\s*=\s*(\S+)\s*;/ 230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver foreign_grammar_name = $1 231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver token_file = output_directory / foreign_grammar_name + '.tokens' 232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver grammar_file = File.dirname( path ) / foreign_grammar_name << '.g' 233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver depends_on( token_file ) 234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver depends_on( grammar_file ) 235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def shell_escape( token ) 239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver token = token.to_s.dup 240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver token.empty? and return "''" 241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver token.gsub!( /([^A-Za-z0-9_\-.,:\/@\n])/n, '\\\1' ) 242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver token.gsub!( /\n/, "'\n'" ) 243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver return token 244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def build_command( options ) 247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts = %w(java) 248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver jar_path = options.fetch( :antlr_jar, default_antlr_jar ) 249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts.push( '-cp', jar_path ) 250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts << 'org.antlr.Tool' 251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts.push( '-fo', output_directory ) 252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver options[ :profile ] and parts << '-profile' 253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver options[ :debug ] and parts << '-debug' 254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver options[ :trace ] and parts << '-trace' 255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver options[ :debug_st ] and parts << '-XdbgST' 256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts << File.expand_path( @path ) 257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver parts.map! { |part| shell_escape( part ) }.join( ' ' ) << ' 2>&1' 258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def study 261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source =~ /^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/ or 262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver raise Grammar::FormatError[ source, path ] 263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @name = $2 264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @type = $1 || 'combined' 265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # class Grammar 267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Grammar::InlineGrammar < Grammar 269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_accessor :host_file, :host_line 270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def initialize( source, options = {} ) 272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver host = call_stack.find { |call| call.file != __FILE__ } 273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @host_file = File.expand_path( options[ :file ] || host.file ) 275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @host_line = ( options[ :line ] || host.line ) 276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @output_directory = options.fetch( :output_directory, File.dirname( @host_file ) ) 277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @verbose = options.fetch( :verbose, $VERBOSE ) 278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source = source.to_s.fixed_indent( 0 ) 280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source.strip! 281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver study 283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver write_to_disk 284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver build_dependencies 285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver yield( self ) if block_given? 287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def output_directory 290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @output_directory and return @output_directory 291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver File.basename( @host_file ) 292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def path=( v ) 295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver previous, @path = @path, v.to_s 296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver previous == @path or write_to_disk 297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def inspect 300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver sprintf( 'inline grammar %s (%s:%s)', name, @host_file, @host_line ) 301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverprivate 304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def write_to_disk 306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @path ||= output_directory / @name + '.g' 307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver test( ?d, output_directory ) or Dir.mkdir( output_directory ) 308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver unless test( ?f, @path ) and MD5.digest( @source ) == MD5.digest( File.read( @path ) ) 309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver open( @path, 'w' ) { |f| f.write( @source ) } 310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # class Grammar::InlineGrammar 313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Grammar::CompilationFailure < StandardError 315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver JAVA_TRACE = /^(org\.)?antlr\.\S+\(\S+\.java:\d+\)\s*/ 316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_reader :grammar, :command, :status, :output 317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def initialize( grammar, command, status, output ) 319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @command = command 320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @status = status 321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @output = output.gsub( JAVA_TRACE, '' ) 322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message = <<-END.here_indent! % [ command, status, grammar, @output ] 324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver | command ``%s'' failed with status %s 325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver | %p 326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver | ~ ~ ~ command output ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ 327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver | %s 328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver END 329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver super( message.chomp! || message ) 331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # error Grammar::CompilationFailure 333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Grammar::FormatError < StandardError 335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver attr_reader :file, :source 336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def self.[]( *args ) 338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver new( *args ) 339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver def initialize( source, file = nil ) 342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @file = file 343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver @source = source 344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message = '' 345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver if file.nil? # inline 346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << "bad inline grammar source:\n" 347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << ( "-" * 80 ) << "\n" 348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << @source 349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message[ -1 ] == ?\n or message << "\n" 350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << ( "-" * 80 ) << "\n" 351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << "could not locate a grammar name and type declaration matching\n" 352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/" 353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver else 354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << 'bad grammar source in file %p' % @file 355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << ( "-" * 80 ) << "\n" 356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << @source 357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message[ -1 ] == ?\n or message << "\n" 358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << ( "-" * 80 ) << "\n" 359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << "could not locate a grammar name and type declaration matching\n" 360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver message << "/^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/" 361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver super( message ) 363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver end 364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend # error Grammar::FormatError 365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend 367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend 368