diff options
| author | Luke Kanies <luke@madstop.com> | 2005-04-13 15:24:36 +0000 |
|---|---|---|
| committer | Luke Kanies <luke@madstop.com> | 2005-04-13 15:24:36 +0000 |
| commit | 6ee8b4e7a9731f969347e317456e8d9712fe2641 (patch) | |
| tree | 0e2aa758bb523b4a2f1c752a625bd2d95462edf4 /lib/blink/parser | |
| parent | 5416017c05e44fc635ad14ffdf1ac1163a4cc6e5 (diff) | |
| download | puppet-6ee8b4e7a9731f969347e317456e8d9712fe2641.tar.gz puppet-6ee8b4e7a9731f969347e317456e8d9712fe2641.tar.xz puppet-6ee8b4e7a9731f969347e317456e8d9712fe2641.zip | |
reorganizing
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@96 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/blink/parser')
| -rw-r--r-- | lib/blink/parser/grammar.ra | 451 | ||||
| -rw-r--r-- | lib/blink/parser/interpreter.rb | 222 | ||||
| -rw-r--r-- | lib/blink/parser/lexer.rb | 182 | ||||
| -rw-r--r-- | lib/blink/parser/makefile | 5 | ||||
| -rw-r--r-- | lib/blink/parser/parser.rb | 683 |
5 files changed, 1543 insertions, 0 deletions
diff --git a/lib/blink/parser/grammar.ra b/lib/blink/parser/grammar.ra new file mode 100644 index 000000000..ab429a662 --- /dev/null +++ b/lib/blink/parser/grammar.ra @@ -0,0 +1,451 @@ +#/usr/bin/ruby + +# $Id$ +# vim: syntax=ruby + +# the parser + +class Blink::Parser::Parser +token WORD LBRACK QTEXT RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE FALSE EQUALS +token QMARK LPAREN RPAREN +rule +program: statements { + if val[0].is_a?(Array) + result = val[0] + else + result = AST::ASTArray.new([val[0]]) + end + # this is mainly so we can test the parser separately from the + # interpreter + if Blink[:parseonly] + begin + puts result.tree(0) + rescue NoMethodError => detail + puts detail + exit(78) + end + else + require 'blink/parser/interpreter' + result = Blink::Parser::Interpreter.new(result) + end +} + +statements: statement + | statements statement { + if val[0].is_a?(Array) + val[0].push(val[1]) + result = val[0] + else + result = AST::ASTArray.new([val[0],val[1]]) + end +} + +statement: object + | assignment + | selector + | functioncall + +object: WORD LBRACK rvalue RBRACK LBRACE params endcomma RBRACE { + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::ObjectDef.new( + :pin => "[]", + :line => @lexer.line, + :object => leaf, + :name => val[2], + :params => val[5] + ) +} + +assignment: WORD EQUALS rvalue { + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::VarDef.new( + :pin => "=", + :line => @lexer.line, + :name => leaf, + :value => val[2] + ) +} + +params: param { result = val[0] } + | params COMMA param { + if val[0].is_a?(Array) + val[0].push(val[2]) + result = val[0] + else + result = [val[0],val[2]] + end +} + +param: QTEXT FARROW rvalue { + leaf = AST::String.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::ObjectParam.new( + :pin => "=>", + :line => @lexer.line, + :param => leaf, + :value => val[2] + ) +} + +rvalues: rvalue + | rvalues rvalue { + if val[0].is_a?(Array) + result = val[0].push(val[1]) + else + result = AST::Array.new(val[0],val[1]) + end +} + +rvalue: QTEXT { + result = AST::String.new( + :line => @lexer.line, + :value => val[0] + ) +} + | selector + | object + | functioncall + | WORD { # these are variable names + result = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) +} + +selector: WORD QMARK svalues { + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::Selector.new( + :pin => "?", + :line => @lexer.line, + :param => leaf, + :value => val[2] + ) +} + +# I'm probably going to regret reusing 'param' here... +svalues: param + | LBRACE sintvalues RBRACE { result = val[1] } + +sintvalues: param + | sintvalues param { + if val[0].is_a?(Array) + val[0].push(val[1]) + result = val[0] + else + result = AST::ASTArray.new([val[0],val[1]]) + end +} + +functioncall: WORD LPAREN rvalues RPAREN { + result = AST::FunctionCall.new( + :pin => '()', + :name => AST::Word.new(:value => val[0], :line => @lexer.line), + :values => val[2] + ) +} + | WORD LPAREN RPAREN { + result = FunctionDef.new( + :pin => '()', + :name => val[0] + ) +} + +endcomma: # nothing + | COMMA { result = nil } + +end +---- header ---- +require 'blink/parser/lexer' +#require 'blink/parser/interpreter' + +module Blink + class ParseError < Racc::ParseError; end +end + +---- inner ---- +def file=(file) + @lexer.file = file +end + +def initialize + @lexer = Blink::Parser::Lexer.new() + if Blink[:debug] + @yydebut = true + end +end + +def on_error(token,value,stack) + #puts "Parse stack:" + #puts stack + #on '%s' at '%s' in\n'%s'" % [token,value,stack] + error = "line %s: parse error after '%s'" % [@lexer.line,@lexer.last] + + if @lexer.file + error += (" in '%s'" % @lexer.file) + end + + raise Blink::ParseError.new(error) +end + +# how should I do error handling here? +def parse + yyparse(@lexer,:scan) + #begin + # yyparse(@lexer,:scan) + #rescue Racc::ParseError => detail + # raise Racc::ParseError.new("line %s: parse error after '%s'" % + # [@lexer.line,@lexer.last]) + #end +end + +def string=(string) + @lexer.string = string +end + +# the parent class for all of our syntactical objects +class AST + attr_accessor :line + @@pink = "[0;31m" + @@green = "[0;32m" + @@yellow = "[0;33m" + @@reset = "[0m" + + @@indent = " " * 4 + @@indline = @@pink + ("-" * 4) + @@reset + @@midline = @@yellow + ("-" * 4) + @@reset + + def AST.indention + return @@indent * @@indention + end + + def AST.midline + return @@midline + end + + def typewrap(string) + #return self.class.to_s.sub(/.+::/,'') + "(" + @@green + string +@@reset+ ")" + return @@green + string +@@reset+ "(" + self.class.to_s.sub(/.+::/,'') + ")" + end + + def initialize(*rest) + begin + args = Hash[*rest] + rescue ArgumentError + raise ArgumentError.new("Arguments must be passed as name => value pairs") + end + args.each { |param,value| + method = param.to_s + "=" + unless self.respond_to?(method) + raise "Invalid parameter %s to object class %s" % + [method,self.class.to_s] + end + + begin + #Blink.debug("sending %s to %s" % [method, self.class]) + self.send(method,value) + rescue => detail + # XXX this should be more normal error correction + raise "Could not set parameter %s on class %s: %s" % + [method,self.class.to_s,detail] + end + } + end + + class ASTArray < Array + def tree(indent = 0) + #puts((AST.indent * indent) + self.pin) + self.collect { |child| + child.tree(indent) + }.join("\n" + (AST.midline * (indent+1)) + "\n") + end + end + + # this differentiation is used by the interpreter + # XXX i now need a standard mechanism for descending into children + + # these objects have children + class Branch < AST + include Enumerable + attr_accessor :pin + + def each + @children.each { |child| + yield child + } + end + + def tree(indent = 0) + return ((@@indline * indent) + self.typewrap(self.pin)) + "\n" + + self.collect { |child| + child.tree(indent + 1) + }.join("\n") + end + end + + # and these ones don't + class Leaf < AST + attr_accessor :value, :type + + def tree(indent = 0) + return ((@@indent * indent) + self.typewrap(self.value)) + end + + def to_s + return @value + end + end + + class String < AST::Leaf + attr_accessor :value + end + + class Word < AST::Leaf + attr_accessor :value + end + + class ObjectDef < AST::Branch + attr_accessor :name, :object + attr_reader :params + + def []=(index,obj) + @params[index] = obj + end + + def [](index) + return @params[index] + end + + def each + #Blink.debug("each called on %s" % self) + [@object,@name,@params].flatten.each { |param| + #Blink.debug("yielding param %s" % param) + yield param + } + end + + def initialize(*args) + super(*args) + end + + def params=(params) + if params.is_a?(Array) + @params = params + else + @params = [params] + end + end + + def tree(indent = 0) + return [ + @object.tree(indent + 1), + @name.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @params.collect { |param| + begin + param.tree(indent + 1) + rescue NoMethodError => detail + puts "failed to tree" + puts @params + p param + raise + end + }.join("\n") + ].join("\n") + end + + def to_s + return "%s => { %s }" % [@name, + @params.collect { |param| + param.to_s + }.join("\n") + ] + end + end + + class ObjectParam < AST::Branch + attr_accessor :value, :param + + def each + [@param,@value].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @param.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@param,@value] + end + end + + class Selector < AST::Branch + attr_accessor :param, :value + + def tree(indent = 0) + return [ + @param.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def each + [@param,@value].each { |child| yield child } + end + end + + class VarDef < AST::Branch + attr_accessor :name, :value + + def each + [@name,@value].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @name.tree(indent + 1), + ((@@indline * 4 * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@name,@value] + end + end + + class FunctionCall < AST::Branch + attr_accessor :name, :values + + def each + [@name,@values].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @name.tree(indent + 1), + ((@@indline * 4 * indent) + self.typewrap(self.pin)), + @values.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@name,@values] + end + end +end diff --git a/lib/blink/parser/interpreter.rb b/lib/blink/parser/interpreter.rb new file mode 100644 index 000000000..0e117fb61 --- /dev/null +++ b/lib/blink/parser/interpreter.rb @@ -0,0 +1,222 @@ +#!/usr/local/bin/ruby -w + +# $Id$ + +# the interpreter +# +# this builds our virtual pinball machine, into which we'll place our host-specific +# information and out of which we'll receive our host-specific configuration + +require 'strscan' +require 'blink' +require 'blink/parser/parser' + + +module Blink + class IntepreterError < RuntimeError; end + module Parser + #--------------------------------------------------------------- + class Interpreter + # just shorten the constant path a bit, using what amounts to an alias + AST = Blink::Parser::Parser::AST + + # make it a class method, since it's not an instance method... + def Interpreter.descend(root,depthfirst = true,&block) + #Blink.debug("root is %s of type %s" % [root,root.class]) + root.each_with_index { |thing,index| + # this is a problem... + # we want to descend into all syntactical objects, but + # we don't want to descend into Blink::Objects because + # that would mean operating directly on attributes, which + # we don't want + if depthfirst + if thing.is_a?(AST::Branch) + Blink.debug("descending thing %s of type %s" % + [thing,thing.class]) + Interpreter.descend(thing,&block) + end + block.call(thing,index,root) + else + block.call(thing,index,root) + if thing.is_a?(AST::Branch) + Blink.debug("descending thing %s of type %s" % + [thing,thing.class]) + Interpreter.descend(thing,&block) + end + end + } + end + + #------------------------------------------------------------ + def askfunc(name,*args) + if func = Blink::Function[name] + # XXX when we're remote, we'll need to do this differently... + func.call(*args) + else + raise "Undefined function %s" % name + end + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # when we have an 'eval' function, we should do that instead + # for now, we only support variables in strings + def strinterp(string) + regex = Regexp.new('\$\{(\w+)\}}') + while match = regex.match(string) do + string.sub!(regex,self.varvalue(match[0])) + end + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # basically just return the variable value from the symbol + # table + def varvalue(variable) + unless @symtable.include?(variable) + raise "Undefined variable %s" % variable + end + + return @symtable[variable] + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # create our interpreter + def initialize(tree) + @tree = tree + + @symtable = Hash.new(nil) + @factable = Hash.new(nil) + @objectable = Hash.new { |hash,key| + #hash[key] = IObject.new(key) + hash[key] = {:name => key} + } + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # execute all of the passes (probably just one, in the end) + def run + regex = %r{^pass} + self.methods.sort.each { |method,value| + if method =~ regex + Blink.debug("calling %s" % method) + self.send(method) + end + } + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # i don't know how to deal with evaluation here -- + # all Leafs need to be turned into real values, but only in + # those trees which i know are under 'true' branches + def pass1_umeverything + Interpreter.descend(@tree) { |object,index,parent| + case object + # handle the leaves first + when AST::String then + # interpolate all variables in the string in-place + self.strinterp(object.value) + when AST::Word then + if parent.is_a?(AST::VarDef) # if we're in an assignment + # um, we pretty much don't do anything + else + # this is where i interpolate the variable, right? + # replace the variable AST with a string AST, I guess + # unless, of course, the variable points to another + # object... + # crap, what if it does? + end + when AST::VarDef then + unless object.name.is_a?(AST::Word) + raise InterpreterError.new("invalid variable name") + end + + # this is quite probably more than a simple value... + case object.value + when AST::String then + @symtable[object.name.value] = object.value.value + when AST::Word then + # just copy whatever's already in the symtable + @symtable[object.name.value] = + @symtable[object.value.value] + else + # um, i have no idea what to do in other cases... + end + when AST::FunctionCall then + when AST::ObjectDef then + object.params.each { |param| + } + end + } + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + # this pass creates the actual objects + # eventually it will probably be one of the last passes, but + # it's the easiest to create, so... + + # XXX this won't really work for the long term -- + # this will cause each operation on an object to be treated + # as an independent copy of the object, which will fail + # purposefully + def disabled_pass1_mkobjects + Interpreter.descend(@tree) { |object,index,parent| + case object + when Blink::Parser::Parser::AST::ObjectDef then # yuk + args = {} + object.each { |param| + # heh, this is weird + # the parameter object stores its value in @value + # and that's an object, so you have to call .value + # again + args[param.param] = param.value.value + } + + args[:name] = object.name.value + klass = "Blink::Objects::" + object.type.capitalize + newobj = eval(klass).new(args) + parent[index] = newobj + when Blink::Parser::Parser::AST::ObjectParam then + # nothing + end + } + end + #------------------------------------------------------------ + + #------------------------------------------------------------ + def disabled_pass2_exeobjects + Blink.debug("tree is %s" % @tree) + Blink.debug("tree type is %s" % @tree.class) + Interpreter.descend(@tree) { |object,index,parent| + #Blink.debug("object is %s" % object) + puts("object is %s" % object) + case + when object.is_a?(Blink::Objects) then + object.evaluate + end + } + end + + class IObject < Hash + attr_accessor :name + + @ohash = {} + @oarray = [] + + def initialize(name) + if @ohash.include?(name) + raise "%s already exists" % name + else + @ohash[name] = self + @oarray.push(self) + end + end + end + end + #--------------------------------------------------------------- + end +end diff --git a/lib/blink/parser/lexer.rb b/lib/blink/parser/lexer.rb new file mode 100644 index 000000000..66e75a315 --- /dev/null +++ b/lib/blink/parser/lexer.rb @@ -0,0 +1,182 @@ +#!/usr/local/bin/ruby -w + +# $Id$ + +# the scanner/lexer + +require 'strscan' +require 'blink' + + +module Blink + class LexError < RuntimeError; end + module Parser + #--------------------------------------------------------------- + class Lexer + attr_reader :line, :last, :file + + @@tokens = { + %r{#.+} => :COMMENT, + %r{\[} => :LBRACK, + %r{\]} => :RBRACK, + %r{\{} => :LBRACE, + %r{\}} => :RBRACE, + %r{\(} => :LPAREN, + %r{\)} => :RPAREN, + %r{"} => :DQUOTE, + %r{\n} => :RETURN, + %r{'} => :SQUOTE, + %r{=} => :EQUALS, + %r{,} => :COMMA, + %r{\?} => :QMARK, + %r{\\} => :BACKSLASH, + %r{=>} => :FARROW, + %r{\w+} => :WORD, + %r{:\w+} => :SYMBOL + } + + # scan the whole file + # basically just used for testing + def fullscan + array = [] + + self.scan { |token,str| + #Blink.debug("got token '%s' => '%s'" % [token,str]) + if token.nil? + return array + else + array.push([token,str]) + end + } + return array + end + + # this is probably pretty damned inefficient... + # it'd be nice not to have to load the whole file first... + def file=(file) + @file = file + File.open(file) { |of| + str = "" + of.each { |line| str += line } + @scanner = StringScanner.new(str) + } + end + + def initialize + @line = 1 + @last = "" + @scanner = nil + @file = nil + @skip = %r{\s+} + end + + def rest + @scanner.rest + end + + # this is the heart of the lexer + def scan + Blink.debug("entering scan") + if @scanner.nil? + raise TypeError.new("Invalid or empty string") + end + + @scanner.skip(@skip) + until @scanner.eos? do + yielded = false + sendbreak = false # gah, this is a nasty hack + stoken = nil + sregex = nil + value = "" + + # first find out which type of token we've got + @@tokens.each { |regex,token| + # we're just checking, which doesn't advance the scan + # pointer + tmp = @scanner.check(regex) + if tmp.nil? + #blink.debug("did not match %s to '%s'" % + # [regex,@scanner.rest]) + next + end + + # find the longest match + if tmp.length > value.length + value = tmp + stoken = token + sregex = regex + else + # we've already got a longer match + next + end + } + + # error out if we didn't match anything at all + if stoken.nil? + raise "Could not match '%s'" % @scanner.rest + end + + value = @scanner.scan(sregex) + + if value == "" + raise "Didn't match regex on token %s" % stoken + end + + # token-specific operations + # if this gets much more complicated, it should + # be moved up to where the tokens themselves are defined + # which will get me about 75% of the way to a lexer generator + case stoken + when :COMMENT then + # just throw comments away + when :RETURN then + Blink.debug("one more line") + @line += 1 + @scanner.skip(@skip) + when :DQUOTE then + #Blink.debug("searching '%s' after '%s'" % [self.rest,value]) + value = self.slurpstring(value) + yield [:QTEXT,value] + @last = value + #stoken = :QTEXT + Blink.debug("got string '%s' => '%s'" % [:QTEXT,value]) + when :SYMBOL then + value.sub!(/^:/,'') + yield [:QTEXT,value] + @last = value + Blink.debug("got token '%s' => '%s'" % [:QTEXT,value]) + else + yield [stoken,value] + @last = value + Blink.debug("got token '%s' => '%s'" % [stoken,value]) + end + @scanner.skip(@skip) + end + @scanner = nil + yield [false,false] + end + + # we've encountered an opening quote... + # slurp in the rest of the string and return it + def slurpstring(quote) + #Blink.debug("searching '%s'" % self.rest) + str = @scanner.scan_until(/[^\\]#{quote}/) + #str = @scanner.scan_until(/"/) + if str.nil? + raise Blink::LexError.new("Unclosed quote after '%s' in '%s'" % + [self.last,self.rest]) + else + str.sub!(/#{quote}$/,"") + str.gsub!(/\\#{quote}/,quote) + end + + return str + end + + def string=(string) + @scanner = StringScanner.new(string) + end + end + #--------------------------------------------------------------- + end +end diff --git a/lib/blink/parser/makefile b/lib/blink/parser/makefile new file mode 100644 index 000000000..eea119d56 --- /dev/null +++ b/lib/blink/parser/makefile @@ -0,0 +1,5 @@ +#parser.rb: grammar.ry +# ryacc --output parser grammar + +parser.rb: grammar.ra + racc -o$@ grammar.ra diff --git a/lib/blink/parser/parser.rb b/lib/blink/parser/parser.rb new file mode 100644 index 000000000..2c341f410 --- /dev/null +++ b/lib/blink/parser/parser.rb @@ -0,0 +1,683 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by racc 1.4.4 +# from racc grammer file "grammar.ra". +# + +require 'racc/parser' + + +require 'blink/parser/lexer' +#require 'blink/parser/interpreter' + +module Blink + class ParseError < Racc::ParseError; end +end + + +module Blink + + module Parser + + class Parser < Racc::Parser + +module_eval <<'..end grammar.ra modeval..id5273b1fd0f', 'grammar.ra', 171 +def file=(file) + @lexer.file = file +end + +def initialize + @lexer = Blink::Parser::Lexer.new() + if Blink[:debug] + @yydebut = true + end +end + +def on_error(token,value,stack) + #puts "Parse stack:" + #puts stack + #on '%s' at '%s' in\n'%s'" % [token,value,stack] + error = "line %s: parse error after '%s'" % [@lexer.line,@lexer.last] + + if @lexer.file + error += (" in '%s'" % @lexer.file) + end + + raise Blink::ParseError.new(error) +end + +# how should I do error handling here? +def parse + yyparse(@lexer,:scan) + #begin + # yyparse(@lexer,:scan) + #rescue Racc::ParseError => detail + # raise Racc::ParseError.new("line %s: parse error after '%s'" % + # [@lexer.line,@lexer.last]) + #end +end + +def string=(string) + @lexer.string = string +end + +# the parent class for all of our syntactical objects +class AST + attr_accessor :line + @@pink = "[0;31m" + @@green = "[0;32m" + @@yellow = "[0;33m" + @@reset = "[0m" + + @@indent = " " * 4 + @@indline = @@pink + ("-" * 4) + @@reset + @@midline = @@yellow + ("-" * 4) + @@reset + + def AST.indention + return @@indent * @@indention + end + + def AST.midline + return @@midline + end + + def typewrap(string) + #return self.class.to_s.sub(/.+::/,'') + "(" + @@green + string +@@reset+ ")" + return @@green + string +@@reset+ "(" + self.class.to_s.sub(/.+::/,'') + ")" + end + + def initialize(*rest) + begin + args = Hash[*rest] + rescue ArgumentError + raise ArgumentError.new("Arguments must be passed as name => value pairs") + end + args.each { |param,value| + method = param.to_s + "=" + unless self.respond_to?(method) + raise "Invalid parameter %s to object class %s" % + [method,self.class.to_s] + end + + begin + #Blink.debug("sending %s to %s" % [method, self.class]) + self.send(method,value) + rescue => detail + # XXX this should be more normal error correction + raise "Could not set parameter %s on class %s: %s" % + [method,self.class.to_s,detail] + end + } + end + + class ASTArray < Array + def tree(indent = 0) + #puts((AST.indent * indent) + self.pin) + self.collect { |child| + child.tree(indent) + }.join("\n" + (AST.midline * (indent+1)) + "\n") + end + end + + # this differentiation is used by the interpreter + # XXX i now need a standard mechanism for descending into children + + # these objects have children + class Branch < AST + include Enumerable + attr_accessor :pin + + def each + @children.each { |child| + yield child + } + end + + def tree(indent = 0) + return ((@@indline * indent) + self.typewrap(self.pin)) + "\n" + + self.collect { |child| + child.tree(indent + 1) + }.join("\n") + end + end + + # and these ones don't + class Leaf < AST + attr_accessor :value, :type + + def tree(indent = 0) + return ((@@indent * indent) + self.typewrap(self.value)) + end + + def to_s + return @value + end + end + + class String < AST::Leaf + attr_accessor :value + end + + class Word < AST::Leaf + attr_accessor :value + end + + class ObjectDef < AST::Branch + attr_accessor :name, :object + attr_reader :params + + def []=(index,obj) + @params[index] = obj + end + + def [](index) + return @params[index] + end + + def each + #Blink.debug("each called on %s" % self) + [@object,@name,@params].flatten.each { |param| + #Blink.debug("yielding param %s" % param) + yield param + } + end + + def initialize(*args) + super(*args) + end + + def params=(params) + if params.is_a?(Array) + @params = params + else + @params = [params] + end + end + + def tree(indent = 0) + return [ + @object.tree(indent + 1), + @name.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @params.collect { |param| + begin + param.tree(indent + 1) + rescue NoMethodError => detail + puts "failed to tree" + puts @params + p param + raise + end + }.join("\n") + ].join("\n") + end + + def to_s + return "%s => { %s }" % [@name, + @params.collect { |param| + param.to_s + }.join("\n") + ] + end + end + + class ObjectParam < AST::Branch + attr_accessor :value, :param + + def each + [@param,@value].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @param.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@param,@value] + end + end + + class Selector < AST::Branch + attr_accessor :param, :value + + def tree(indent = 0) + return [ + @param.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def each + [@param,@value].each { |child| yield child } + end + end + + class VarDef < AST::Branch + attr_accessor :name, :value + + def each + [@name,@value].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @name.tree(indent + 1), + ((@@indline * 4 * indent) + self.typewrap(self.pin)), + @value.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@name,@value] + end + end + + class FunctionCall < AST::Branch + attr_accessor :name, :values + + def each + [@name,@values].each { |child| yield child } + end + + def tree(indent = 0) + return [ + @name.tree(indent + 1), + ((@@indline * 4 * indent) + self.typewrap(self.pin)), + @values.tree(indent + 1) + ].join("\n") + end + + def to_s + return "%s => %s" % [@name,@values] + end + end +end +..end grammar.ra modeval..id5273b1fd0f + +##### racc 1.4.4 generates ### + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 18, :_reduce_1, + 1, 19, :_reduce_none, + 2, 19, :_reduce_3, + 1, 20, :_reduce_none, + 1, 20, :_reduce_none, + 1, 20, :_reduce_none, + 1, 20, :_reduce_none, + 8, 21, :_reduce_8, + 3, 22, :_reduce_9, + 1, 26, :_reduce_10, + 3, 26, :_reduce_11, + 3, 28, :_reduce_12, + 1, 29, :_reduce_none, + 2, 29, :_reduce_14, + 1, 25, :_reduce_15, + 1, 25, :_reduce_none, + 1, 25, :_reduce_none, + 1, 25, :_reduce_none, + 3, 23, :_reduce_19, + 1, 30, :_reduce_none, + 3, 30, :_reduce_21, + 1, 31, :_reduce_none, + 2, 31, :_reduce_23, + 4, 24, :_reduce_24, + 3, 24, :_reduce_25, + 0, 27, :_reduce_none, + 1, 27, :_reduce_27 ] + +racc_reduce_n = 28 + +racc_shift_n = 46 + +racc_action_table = [ + 17, 17, 19, 19, 21, 30, 11, 38, 11, 17, + 21, 19, 22, 29, 35, 27, 9, 10, 12, 10, + 12, 17, 17, 19, 19, 21, 33, 3, 13, 3, + 39, 21, 43, 44, 21 ] + +racc_action_check = [ + 28, 12, 28, 12, 32, 21, 3, 32, 17, 11, + 10, 11, 10, 13, 28, 12, 3, 3, 3, 17, + 17, 30, 9, 30, 9, 22, 25, 6, 5, 0, + 33, 39, 40, 42, 43 ] + +racc_action_pointer = [ + 27, nil, nil, 3, nil, 28, 25, nil, nil, 20, + 6, 7, -1, 13, nil, nil, nil, 5, nil, nil, + nil, -4, 21, nil, nil, 21, nil, nil, -2, nil, + 19, nil, 0, 24, nil, nil, nil, nil, nil, 27, + 22, nil, 26, 30, nil, nil ] + +racc_action_default = [ + -28, -5, -6, -28, -7, -28, -1, -2, -4, -28, + -28, -28, -28, -28, -3, -16, -18, -28, -9, -15, + -17, -28, -28, -20, -19, -28, -13, -25, -28, 46, + -28, -22, -28, -28, -14, -24, -12, -23, -21, -28, + -26, -10, -28, -27, -8, -11 ] + +racc_goto_table = [ + 23, 8, 18, 7, 25, 26, 5, 8, 2, 14, + 4, 40, 31, 42, 2, 6, 4, 28, 24, 32, + nil, 34, 37, 36, nil, nil, nil, nil, nil, 41, + nil, nil, nil, 45 ] + +racc_goto_check = [ + 11, 4, 8, 3, 8, 8, 1, 4, 6, 3, + 7, 9, 11, 10, 6, 2, 7, 12, 13, 14, + nil, 8, 11, 8, nil, nil, nil, nil, nil, 11, + nil, nil, nil, 11 ] + +racc_goto_pointer = [ + nil, 6, 15, 3, 1, nil, 8, 10, -7, -28, + -27, -10, 5, 8, -3 ] + +racc_goto_default = [ + nil, nil, nil, nil, 20, 1, 15, 16, nil, nil, + nil, nil, nil, nil, nil ] + +racc_token_table = { + false => 0, + Object.new => 1, + :WORD => 2, + :LBRACK => 3, + :QTEXT => 4, + :RBRACK => 5, + :LBRACE => 6, + :RBRACE => 7, + :SYMBOL => 8, + :FARROW => 9, + :COMMA => 10, + :TRUE => 11, + :FALSE => 12, + :EQUALS => 13, + :QMARK => 14, + :LPAREN => 15, + :RPAREN => 16 } + +racc_use_result_var = true + +racc_nt_base = 17 + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ +'$end', +'error', +'WORD', +'LBRACK', +'QTEXT', +'RBRACK', +'LBRACE', +'RBRACE', +'SYMBOL', +'FARROW', +'COMMA', +'TRUE', +'FALSE', +'EQUALS', +'QMARK', +'LPAREN', +'RPAREN', +'$start', +'program', +'statements', +'statement', +'object', +'assignment', +'selector', +'functioncall', +'rvalue', +'params', +'endcomma', +'param', +'rvalues', +'svalues', +'sintvalues'] + +Racc_debug_parser = false + +##### racc system variables end ##### + + # reduce 0 omitted + +module_eval <<'.,.,', 'grammar.ra', 31 + def _reduce_1( val, _values, result ) + if val[0].is_a?(Array) + result = val[0] + else + result = AST::ASTArray.new([val[0]]) + end + # this is mainly so we can test the parser separately from the + # interpreter + if Blink[:parseonly] + begin + puts result.tree(0) + rescue NoMethodError => detail + puts detail + exit(78) + end + else + require 'blink/parser/interpreter' + result = Blink::Parser::Interpreter.new(result) + end + result + end +.,., + + # reduce 2 omitted + +module_eval <<'.,.,', 'grammar.ra', 41 + def _reduce_3( val, _values, result ) + if val[0].is_a?(Array) + val[0].push(val[1]) + result = val[0] + else + result = AST::ASTArray.new([val[0],val[1]]) + end + result + end +.,., + + # reduce 4 omitted + + # reduce 5 omitted + + # reduce 6 omitted + + # reduce 7 omitted + +module_eval <<'.,.,', 'grammar.ra', 60 + def _reduce_8( val, _values, result ) + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::ObjectDef.new( + :pin => "[]", + :line => @lexer.line, + :object => leaf, + :name => val[2], + :params => val[5] + ) + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 73 + def _reduce_9( val, _values, result ) + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::VarDef.new( + :pin => "=", + :line => @lexer.line, + :name => leaf, + :value => val[2] + ) + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 74 + def _reduce_10( val, _values, result ) + result = val[0] + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 83 + def _reduce_11( val, _values, result ) + if val[0].is_a?(Array) + val[0].push(val[2]) + result = val[0] + else + result = [val[0],val[2]] + end + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 96 + def _reduce_12( val, _values, result ) + leaf = AST::String.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::ObjectParam.new( + :pin => "=>", + :line => @lexer.line, + :param => leaf, + :value => val[2] + ) + result + end +.,., + + # reduce 13 omitted + +module_eval <<'.,.,', 'grammar.ra', 105 + def _reduce_14( val, _values, result ) + if val[0].is_a?(Array) + result = val[0].push(val[1]) + else + result = AST::Array.new(val[0],val[1]) + end + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 112 + def _reduce_15( val, _values, result ) + result = AST::String.new( + :line => @lexer.line, + :value => val[0] + ) + result + end +.,., + + # reduce 16 omitted + + # reduce 17 omitted + + # reduce 18 omitted + +module_eval <<'.,.,', 'grammar.ra', 128 + def _reduce_19( val, _values, result ) + leaf = AST::Word.new( + :line => @lexer.line, + :value => val[0] + ) + result = AST::Selector.new( + :pin => "?", + :line => @lexer.line, + :param => leaf, + :value => val[2] + ) + result + end +.,., + + # reduce 20 omitted + +module_eval <<'.,.,', 'grammar.ra', 131 + def _reduce_21( val, _values, result ) + result = val[1] + result + end +.,., + + # reduce 22 omitted + +module_eval <<'.,.,', 'grammar.ra', 142 + def _reduce_23( val, _values, result ) + if val[0].is_a?(Array) + val[0].push(val[1]) + result = val[0] + else + result = AST::ASTArray.new([val[0],val[1]]) + end + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 150 + def _reduce_24( val, _values, result ) + result = AST::FunctionCall.new( + :pin => '()', + :name => AST::Word.new(:value => val[0], :line => @lexer.line), + :values => val[2] + ) + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 156 + def _reduce_25( val, _values, result ) + result = FunctionDef.new( + :pin => '()', + :name => val[0] + ) + result + end +.,., + + # reduce 26 omitted + +module_eval <<'.,.,', 'grammar.ra', 158 + def _reduce_27( val, _values, result ) + result = nil + result + end +.,., + + def _reduce_none( val, _values, result ) + result + end + + end # class Parser + + end # module Parser + +end # module Blink |
