diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 0369a6d28..03891160b 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -1,137 +1,138 @@ # the parent class for all of our syntactical objects require 'puppet' require 'puppet/util/autoload' require 'puppet/file_collection/lookup' # The base class for all of the objects that make up the parse trees. # Handles things like file name, line #, and also does the initialization # for all of the parameters of all of the child objects. class Puppet::Parser::AST # Do this so I don't have to type the full path in all of the subclasses AST = Puppet::Parser::AST include Puppet::FileCollection::Lookup include Puppet::Util::Errors include Puppet::Util::MethodHelper include Puppet::Util::Docs attr_accessor :parent, :scope # don't fetch lexer comment by default def use_docs self.class.use_docs end # allow our subclass to specify they want documentation class << self attr_accessor :use_docs def associates_doc self.use_docs = true end end # Does this ast object set something? If so, it gets evaluated first. def self.settor? if defined?(@settor) @settor else false end end # Evaluate the current object. Just a stub method, since the subclass # should override this method. # of the contained children and evaluates them in turn, returning a # list of all of the collected values, rejecting nil values def evaluate(*options) raise Puppet::DevError, "Did not override #evaluate in #{self.class}" end # Throw a parse error. def parsefail(message) self.fail(Puppet::ParseError, message) end # Wrap a statemp in a reusable way so we always throw a parse error. def parsewrap exceptwrap :type => Puppet::ParseError do yield end end # The version of the evaluate method that should be called, because it # correctly handles errors. It is critical to use this method because # it can enable you to catch the error where it happens, rather than # much higher up the stack. def safeevaluate(*options) # We duplicate code here, rather than using exceptwrap, because this # is called so many times during parsing. begin return self.evaluate(*options) rescue Puppet::Error => detail raise adderrorcontext(detail) rescue => detail error = Puppet::Error.new(detail.to_s) # We can't use self.fail here because it always expects strings, # not exceptions. raise adderrorcontext(error, detail) end end # Initialize the object. Requires a hash as the argument, and # takes each of the parameters of the hash and calls the settor # method for them. This is probably pretty inefficient and should # likely be changed at some point. def initialize(args) set_options(args) end # evaluate ourselves, and match def evaluate_match(value, scope) obj = self.safeevaluate(scope) obj = obj.downcase if obj.respond_to?(:downcase) value = value.downcase if value.respond_to?(:downcase) obj = Puppet::Parser::Scope.number?(obj) || obj value = Puppet::Parser::Scope.number?(value) || value # "" == undef for case/selector/if obj == value or (obj == "" and value == :undef) end end # And include all of the AST subclasses. require 'puppet/parser/ast/arithmetic_operator' require 'puppet/parser/ast/astarray' require 'puppet/parser/ast/asthash' require 'puppet/parser/ast/boolean_operator' require 'puppet/parser/ast/branch' require 'puppet/parser/ast/caseopt' require 'puppet/parser/ast/casestatement' require 'puppet/parser/ast/collection' require 'puppet/parser/ast/collexpr' require 'puppet/parser/ast/comparison_operator' require 'puppet/parser/ast/definition' require 'puppet/parser/ast/else' require 'puppet/parser/ast/function' require 'puppet/parser/ast/hostclass' require 'puppet/parser/ast/ifstatement' require 'puppet/parser/ast/in_operator' require 'puppet/parser/ast/leaf' require 'puppet/parser/ast/match_operator' require 'puppet/parser/ast/minus' require 'puppet/parser/ast/node' require 'puppet/parser/ast/nop' require 'puppet/parser/ast/not' require 'puppet/parser/ast/relationship' require 'puppet/parser/ast/resource' require 'puppet/parser/ast/resource_defaults' +require 'puppet/parser/ast/resource_instance' require 'puppet/parser/ast/resource_override' require 'puppet/parser/ast/resource_reference' require 'puppet/parser/ast/resourceparam' require 'puppet/parser/ast/selector' require 'puppet/parser/ast/tag' require 'puppet/parser/ast/vardef' diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 432300c7a..b62c820ca 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -1,78 +1,62 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST # The basic container class. This object behaves almost identically # to a normal array except at initialization time. Note that its name # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many # bugs when it was just 'AST::Array', because things like # 'object.is_a?(Array)' never behaved as I expected. class ASTArray < Branch include Enumerable # True if this ASTArray represents a list of statements in a # context that defines a namespace. Classes and definitions may # only appear in such a context. attr_accessor :is_a_namespace # Return a child by index. Probably never used. def [](index) @children[index] end # Evaluate our children. def evaluate(scope) - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - items << ac - end - else - items << child - end - } - - rets = items.flatten.collect { |child| + result = [] + @children.each do |child| if child.respond_to? :instantiate if is_a_namespace # no problem, just don't evaluate it. else msg = "Classes, definitions, and nodes may only appear at toplevel or inside other classes" error = Puppet::Error.new(msg) error.line = child.line error.file = child.file raise error end else - child.safeevaluate(scope) + item = child.safeevaluate(scope) + if !item.nil? + # nil values are implicitly removed. + result.push(item) + end end - } - rets.reject { |o| o.nil? } + end + result end def push(*ary) ary.each { |child| #Puppet.debug "adding %s(%s) of type %s to %s" % # [child, child.object_id, child.class.to_s.sub(/.+::/,''), # self.object_id] @children.push(child) } self end def to_s "[" + @children.collect { |c| c.to_s }.join(', ') + "]" end end - - # A simple container class, containing the parameters for an object. - # Used for abstracting the grammar declarations. Basically unnecessary - # except that I kept finding bugs because I had too many arrays that - # meant completely different things. - class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 4e296e82f..db4c2b024 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -1,64 +1,52 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST # Each individual option in a case statement. class CaseOpt < AST::Branch attr_accessor :value, :statements # CaseOpt is a bit special -- we just want the value first, # so that CaseStatement can compare, and then it will selectively # decide whether to fully evaluate this option def each [@value,@statements].each { |child| yield child } end # Are we the default option? def default? # Cache the @default value. return @default if defined?(@default) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - else - @default = true if @value.is_a?(AST::Default) - end + @value.each { |subval| + if subval.is_a?(AST::Default) + @default = true + break + end + } @default ||= false @default end # You can specify a list of values; return each in turn. def eachvalue(scope) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - else - yield @value.safeevaluate(scope) - end + @value.each { |subval| + yield subval.safeevaluate(scope) + } end def eachopt - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval - } - else - yield @value - end + @value.each { |subval| + yield subval + } end # Evaluate the actual statements; this only gets called if # our option matched. def evaluate(scope) @statements.safeevaluate(scope) end end end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 0c58538d5..23207149f 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -1,78 +1,67 @@ require 'puppet/parser/ast/resource_reference' # Any normal puppet resource declaration. Can point to a definition or a # builtin type. class Puppet::Parser::AST -class Resource < AST::ResourceReference +class Resource < AST::Branch associates_doc - attr_accessor :title, :type, :exported, :virtual - attr_reader :parameters + attr_accessor :type, :instances, :exported, :virtual # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) - # Evaluate all of the specified params. - paramobjects = parameters.collect { |param| - param.safeevaluate(scope) - } - - resource_titles = @title.safeevaluate(scope) - - # it's easier to always use an array, even for only one name - resource_titles = [resource_titles] unless resource_titles.is_a?(Array) - # We want virtual to be true if exported is true. We can't # just set :virtual => self.virtual in the initialization, # because sometimes the :virtual attribute is set *after* # :exported, in which case it clobbers :exported if :exported # is true. Argh, this was a very tough one to track down. virt = self.virtual || self.exported - # This is where our implicit iteration takes place; if someone - # passed an array as the name, then we act just like the called us - # many times. - fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) + # First level of implicit iteration: build a resource for each + # instance. This handles things like: + # file { '/foo': owner => blah; '/bar': owner => blah } + @instances.collect { |instance| - resource_titles.flatten.collect { |resource_title| - exceptwrap :type => Puppet::ParseError do - resource = Puppet::Parser::Resource.new( - fully_qualified_type, resource_title, - :parameters => paramobjects, - :file => self.file, - :line => self.line, - :exported => self.exported, - :virtual => virt, - :source => scope.source, - :scope => scope, - - :strict => true - ) + # Evaluate all of the specified params. + paramobjects = instance.parameters.collect { |param| + param.safeevaluate(scope) + } - # And then store the resource in the compiler. - # At some point, we need to switch all of this to return - # resources instead of storing them like this. - scope.compiler.add_resource(scope, resource) - resource - end - }.reject { |resource| resource.nil? } - end + resource_titles = instance.title.safeevaluate(scope) + + # it's easier to always use an array, even for only one name + resource_titles = [resource_titles] unless resource_titles.is_a?(Array) + + fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) + + # Second level of implicit iteration; build a resource for each + # title. This handles things like: + # file { ['/foo', '/bar']: owner => blah } + resource_titles.flatten.collect { |resource_title| + exceptwrap :type => Puppet::ParseError do + resource = Puppet::Parser::Resource.new( + fully_qualified_type, resource_title, + :parameters => paramobjects, + :file => self.file, + :line => self.line, + :exported => self.exported, + :virtual => virt, + :source => scope.source, + :scope => scope, - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else + :strict => true + ) - @parameters = AST::ASTArray.new( - - :line => params.line, - :file => params.file, - - :children => [params] - ) - end + # And then store the resource in the compiler. + # At some point, we need to switch all of this to return + # resources instead of storing them like this. + scope.compiler.add_resource(scope, resource) + resource + end + } + }.flatten.reject { |resource| resource.nil? } end end end diff --git a/lib/puppet/parser/ast/resource_instance.rb b/lib/puppet/parser/ast/resource_instance.rb new file mode 100644 index 000000000..ebfb17bf1 --- /dev/null +++ b/lib/puppet/parser/ast/resource_instance.rb @@ -0,0 +1,9 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + class ResourceInstance < Branch + # A simple container for a parameter for an object. Consists of a + # title and a set of parameters. + attr_accessor :title, :parameters + end +end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index e0be889ff..d638202ab 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -1,68 +1,67 @@ require 'puppet/parser/ast/resource' class Puppet::Parser::AST # Set a parameter on a resource specification created somewhere else in the # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < Resource + class ResourceOverride < AST::Branch associates_doc - attr_accessor :object - attr_reader :parameters + attr_accessor :object, :parameters # Iterate across all of our children. def each [@object,@parameters].flatten.each { |param| #Puppet.debug("yielding param #{param}") yield param } end # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) # Get our object reference. resource = @object.safeevaluate(scope) hash = {} # Evaluate all of the specified params. params = @parameters.collect { |param| param.safeevaluate(scope) } # Now we just create a normal resource, but we call a very different # method on the scope. resource = [resource] unless resource.is_a?(Array) resource = resource.collect do |r| res = Puppet::Parser::Resource.new( r.type, r.title, :parameters => params, :file => file, :line => line, :source => scope.source, :scope => scope ) # Now we tell the scope that it's an override, and it behaves as # necessary. scope.compiler.add_override(res) res end # decapsulate array in case of only one item return(resource.length == 1 ? resource.pop : resource) end # Create our ResourceDef. Handles type checking for us. def initialize(hash) @checked = false super #self.typecheck(@type.value) end end end diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 3185c435d..1f1ec158a 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -1,861 +1,790 @@ # vim: syntax=ruby # the parser class Puppet::Parser::Parser token STRING DQPRE DQMID DQPOST token LBRACK RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE token FALSE EQUALS APPENDS LESSEQUAL NOTEQUAL DOT COLON LLCOLLECT RRCOLLECT token QMARK LPAREN RPAREN ISEQUAL GREATEREQUAL GREATERTHAN LESSTHAN token IF ELSE IMPORT DEFINE ELSIF VARIABLE CLASS INHERITS NODE BOOLEAN token NAME SEMIC CASE DEFAULT AT LCOLLECT RCOLLECT CLASSNAME CLASSREF token NOT OR AND UNDEF PARROW PLUS MINUS TIMES DIV LSHIFT RSHIFT UMINUS token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB token IN prechigh right NOT nonassoc UMINUS left IN MATCH NOMATCH left TIMES DIV left MINUS PLUS left LSHIFT RSHIFT left NOTEQUAL ISEQUAL left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL left AND left OR preclow rule program: statements { val[0].is_a_namespace = true result = val[0] } | nil statements: statement { - result = ast AST::ASTArray, :children => [val[0]] + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) } | statements statement { - val[0].push(val[1]) + if val[1] + val[0].push(val[1]) + end result = val[0] } # The main list of valid statements statement: resource | virtualresource | collection | assignment | casestatement | ifstatement_begin | import | fstatement | definition | hostclass | nodedef | resourceoverride | append | relationship relationship: relationship_side edge relationship_side { result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) } | relationship edge relationship_side { result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) } relationship_side: resource | resourceref | collection edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB fstatement: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN funcvalues COMMA RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN RPAREN { result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], :arguments => AST::ASTArray.new({}), :ftype => :statement } | NAME funcvalues { - args = aryfy(val[1]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[1], :ftype => :statement } -funcvalues: namestring - | resourceref +funcvalues: namestring { result = aryfy(val[0]) } + | resourceref { result = aryfy(val[0]) } | funcvalues COMMA namestring { - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + val[0].push(val[2]) + result = val[0] } | funcvalues COMMA resourceref { - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - - val[0].push(val[2]) - - result = val[0] + val[0].push(val[2]) + result = val[0] } # This is *almost* an rvalue, but I couldn't get a full # rvalue to work without scads of shift/reduce conflicts. namestring: name | variable | type | boolean | funcrvalue | selector | quotedtext | hasharrayaccesses | CLASSNAME { result = ast AST::Name, :value => val[0][:value] } resource: classname LBRACE resourceinstances endsemi RBRACE { @lexer.commentpop - array = val[2] - array = [array] if array.instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - - result.push ast( - AST::Resource, - :type => val[0], - :title => instance[0], - - :parameters => instance[1]) - } + result = ast(AST::Resource, :type => val[0], :instances => val[2]) } | classname LBRACE params endcomma RBRACE { # This is a deprecated syntax. error "All resource specifications require names" } | classref LBRACE params endcomma RBRACE { # a defaults setting for a type @lexer.commentpop result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) } # Override a value set elsewhere in the configuration. resourceoverride: resourceref LBRACE anyparams endcomma RBRACE { @lexer.commentpop result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] } # Exported and virtual resources; these don't get sent to the client # unless they get collected elsewhere in the db. virtualresource: at resource { type = val[0] if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect without storeconfigs being set") end error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults method = type.to_s + "=" - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + # Just mark our resource as exported and pass it through. + val[1].send(method, true) result = val[1] } at: AT { result = :virtual } | AT AT { result = :exported } # A collection statement. Currently supports no arguments at all, but eventually # will, I assume. collection: classref collectrhand LBRACE anyparams endcomma RBRACE { @lexer.commentpop Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ type = val[0].downcase args = {:type => type} if val[1].is_a?(AST::CollExpr) args[:query] = val[1] args[:query].type = type args[:form] = args[:query].form else args[:form] = val[1] end if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") end args[:override] = val[3] result = ast AST::Collection, args } | classref collectrhand { if val[0] =~ /^[a-z]/ Puppet.warning addcontext("Collection names must now be capitalized") end type = val[0].downcase args = {:type => type } if val[1].is_a?(AST::CollExpr) args[:query] = val[1] args[:query].type = type args[:form] = args[:query].form else args[:form] = val[1] end if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") end result = ast AST::Collection, args } collectrhand: LCOLLECT collstatements RCOLLECT { if val[1] result = val[1] result.form = :virtual else result = :virtual end } | LLCOLLECT collstatements RRCOLLECT { if val[1] result = val[1] result.form = :exported else result = :exported end } # A mini-language for handling collection comparisons. This is organized # to avoid the need for precedence indications. collstatements: nil | collstatement | collstatements colljoin collstatement { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] } collstatement: collexpr | LPAREN collstatements RPAREN { result = val[1] result.parens = true } colljoin: AND { result=val[0][:value] } | OR { result=val[0][:value] } collexpr: colllval ISEQUAL simplervalue { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val } | colllval NOTEQUAL simplervalue { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val } colllval: variable | name resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] } -resourceinstances: resourceinst +resourceinstances: resourceinst { result = aryfy(val[0]) } | resourceinstances SEMIC resourceinst { - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else val[0].push val[2] result = val[0] - end } endsemi: # nothing | SEMIC undef: UNDEF { result = ast AST::Undef, :value => :undef } name: NAME { result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] } type: CLASSREF { result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] } resourcename: quotedtext | name | type | selector | variable | array | hasharrayaccesses assignment: VARIABLE EQUALS expression { raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ # this is distinct from referencing a variable variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] } | hasharrayaccess EQUALS expression { result = ast AST::VarDef, :name => val[0], :value => val[2] } append: VARIABLE APPENDS expression { variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] } params: # nothing { result = ast AST::ASTArray } - | param { result = val[0] } + | param { result = aryfy(val[0]) } | params COMMA param { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } param: NAME FARROW rvalue { result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] } addparam: NAME PARROW rvalue { result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], :add => true } anyparam: param | addparam anyparams: # nothing { result = ast AST::ASTArray } - | anyparam { result = val[0] } + | anyparam { result = aryfy(val[0]) } | anyparams COMMA anyparam { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } -rvalues: rvalue - | rvalues comma rvalue { - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end -} +rvalues: rvalue { result = aryfy(val[0]) } + | rvalues comma rvalue { result = val[0].push(val[2]) } simplervalue: quotedtext | name | type | boolean | selector | variable rvalue: quotedtext | name | type | boolean | selector | variable | array | hash | hasharrayaccesses | resourceref | funcrvalue | undef # We currently require arguments in these functions. funcrvalue: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :rvalue } | NAME LPAREN RPAREN { result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], :arguments => AST::ASTArray.new({}), :ftype => :rvalue } quotedtext: STRING { result = ast AST::String, :value => val[0][:value], :line => val[0][:line] } | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] } dqrval: expression dqtail { result = [val[0]] + val[1] } dqtail: DQPOST { result = [ast(AST::String,val[0])] } | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] } boolean: BOOLEAN { result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] } resourceref: NAME LBRACK rvalues RBRACK { Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] } | classref LBRACK rvalues RBRACK { result = ast AST::ResourceReference, :type => val[0], :title => val[2] } ifstatement_begin: IF ifstatement { result = val[1] } ifstatement: expression LBRACE statements RBRACE else { @lexer.commentpop args = { :test => val[0], :statements => val[2] } args[:else] = val[4] if val[4] result = ast AST::IfStatement, args } | expression LBRACE RBRACE else { @lexer.commentpop args = { :test => val[0], :statements => ast(AST::Nop) } args[:else] = val[3] if val[3] result = ast AST::IfStatement, args } else: # nothing | ELSIF ifstatement { result = ast AST::Else, :statements => val[1] } | ELSE LBRACE statements RBRACE { @lexer.commentpop result = ast AST::Else, :statements => val[2] } | ELSE LBRACE RBRACE { @lexer.commentpop result = ast AST::Else, :statements => ast(AST::Nop) } # Unlike yacc/bison, it seems racc # gives tons of shift/reduce warnings # with the following syntax: # # expression: ... # | expression arithop expressio { ... } # # arithop: PLUS | MINUS | DIVIDE | TIMES ... # # So I had to develop the expression by adding one rule # per operator :-( expression: rvalue | expression IN rvalue { result = ast AST::InOperator, :lval => val[0], :rval => val[2] } | expression MATCH regex { result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression NOMATCH regex { result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression PLUS expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression MINUS expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression DIV expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression TIMES expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression LSHIFT expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression RSHIFT expression { result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | MINUS expression =UMINUS { result = ast AST::Minus, :value => val[1] } | expression NOTEQUAL expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression ISEQUAL expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression GREATERTHAN expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression GREATEREQUAL expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression LESSTHAN expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression LESSEQUAL expression { result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | NOT expression { result = ast AST::Not, :value => val[1] } | expression AND expression { result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | expression OR expression { result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] } | LPAREN expression RPAREN { result = val[1] } casestatement: CASE rvalue LBRACE caseopts RBRACE { @lexer.commentpop - options = val[3] - options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) - result = ast AST::CaseStatement, :test => val[1], :options => options + result = ast AST::CaseStatement, :test => val[1], :options => val[3] } -caseopts: caseopt +caseopts: caseopt { result = aryfy(val[0]) } | caseopts caseopt { - if val[0].instance_of?(AST::ASTArray) val[0].push val[1] result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end } caseopt: casevalues COLON LBRACE statements RBRACE { @lexer.commentpop result = ast AST::CaseOpt, :value => val[0], :statements => val[3] } | casevalues COLON LBRACE RBRACE { @lexer.commentpop result = ast( AST::CaseOpt, :value => val[0], :statements => ast(AST::ASTArray) ) } -casevalues: selectlhand +casevalues: selectlhand { result = aryfy(val[0]) } | casevalues COMMA selectlhand { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } selector: selectlhand QMARK svalues { result = ast AST::Selector, :param => val[0], :values => val[2] } svalues: selectval | LBRACE sintvalues endcomma RBRACE { @lexer.commentpop result = val[1] } sintvalues: selectval | sintvalues comma selectval { if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] else result = ast AST::ASTArray, :children => [val[0],val[2]] end } selectval: selectlhand FARROW rvalue { result = ast AST::ResourceParam, :param => val[0], :value => val[2] } selectlhand: name | type | quotedtext | variable | funcrvalue | boolean | undef | DEFAULT { result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] } | regex # These are only used for importing, and we don't interpolate there. string: STRING { result = [val[0][:value]] } strings: string | strings COMMA string { result = val[0] += val[2] } import: IMPORT strings { val[1].each do |file| import(file) end - result = AST::ASTArray.new(:children => []) + result = nil } # Disable definition inheritance for now. 8/27/06, luke #definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { definition: DEFINE classname argumentlist LBRACE statements RBRACE { @lexer.commentpop result = Puppet::Parser::AST::Definition.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :code => val[4], :line => val[0][:line])) @lexer.indefine = false #} | DEFINE NAME argumentlist parent LBRACE RBRACE { } | DEFINE classname argumentlist LBRACE RBRACE { @lexer.commentpop result = Puppet::Parser::AST::Definition.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) @lexer.indefine = false } #hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { hostclass: CLASS classname argumentlist classparent LBRACE statements RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop val[5].is_a_namespace = true result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line])) } | CLASS classname argumentlist classparent LBRACE RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :parent => val[3], :line => val[0][:line])) } nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { @lexer.commentpop result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :code => val[4], :line => val[0][:line])) } | NODE hostnames nodeparent LBRACE RBRACE { @lexer.commentpop result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) } classref: CLASSREF { result = val[0][:value] } classname: NAME { result = val[0][:value] } | CLASSNAME { result = val[0][:value] } | CLASS { result = "class" } # Multiple hostnames, as used for node names. These are all literal # strings, not AST objects. hostnames: nodename { result = [result] } | hostnames COMMA nodename { result = val[0] result << val[2] } nodename: hostname { result = ast AST::HostName, :value => val[0] } hostname: NAME { result = val[0][:value] } | STRING { result = val[0][:value] } | DEFAULT { result = val[0][:value] } | regex nil: { result = nil } nothing: { result = ast AST::ASTArray, :children => [] } argumentlist: nil | LPAREN nothing RPAREN { result = nil } | LPAREN arguments RPAREN { result = val[1] result = [result] unless result[0].is_a?(Array) } arguments: argument | arguments COMMA argument { result = val[0] result = [result] unless result[0].is_a?(Array) result << val[2] } argument: NAME EQUALS rvalue { Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value], val[2]] } | NAME { Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value]] } | VARIABLE EQUALS rvalue { result = [val[0][:value], val[2]] } | VARIABLE { result = [val[0][:value]] } nodeparent: nil | INHERITS hostname { result = val[1] } classparent: nil | INHERITS classnameordefault { result = val[1] } classnameordefault: classname | DEFAULT variable: VARIABLE { result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] } -array: LBRACK rvalues RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} - | LBRACK rvalues COMMA RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} | LBRACK RBRACK { - result = ast AST::ASTArray -} +array: LBRACK rvalues RBRACK { result = val[1] } + | LBRACK rvalues COMMA RBRACK { result = val[1] } + | LBRACK RBRACK { result = ast AST::ASTArray } comma: FARROW | COMMA endcomma: # nothing | COMMA { result = nil } regex: REGEX { result = ast AST::Regex, :value => val[0][:value] } hash: LBRACE hashpairs RBRACE { if val[1].instance_of?(AST::ASTHash) result = val[1] else result = ast AST::ASTHash, { :value => val[1] } end } | LBRACE hashpairs COMMA RBRACE { if val[1].instance_of?(AST::ASTHash) result = val[1] else result = ast AST::ASTHash, { :value => val[1] } end } | LBRACE RBRACE { result = ast AST::ASTHash } hashpairs: hashpair | hashpairs COMMA hashpair { if val[0].instance_of?(AST::ASTHash) result = val[0].merge(val[2]) else result = ast AST::ASTHash, :value => val[0] result.merge(val[2]) end } hashpair: key FARROW rvalue { result = ast AST::ASTHash, { :value => { val[0] => val[2] } } } key: NAME { result = val[0][:value] } | quotedtext { result = val[0] } hasharrayaccess: VARIABLE LBRACK rvalue RBRACK { result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] } hasharrayaccesses: hasharrayaccess | hasharrayaccess LBRACK rvalue RBRACK { result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] } end ---- header ---- require 'puppet' require 'puppet/util/loadedfile' require 'puppet/parser/lexer' require 'puppet/parser/ast' module Puppet class ParseError < Puppet::Error; end class ImportError < Racc::ParseError; end class AlreadyImportedError < ImportError; end end ---- inner ---- # It got too annoying having code in a file that needs to be compiled. require 'puppet/parser/parser_support' # Make emacs happy # Local Variables: # mode: ruby # End: # $Id$ diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index e4f5149b9..0f851a5a8 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -1,2689 +1,2651 @@ # # DO NOT MODIFY!!!! # This file is automatically generated by Racc 1.4.6 # from Racc grammer file "". # require 'racc/parser.rb' require 'puppet' require 'puppet/util/loadedfile' require 'puppet/parser/lexer' require 'puppet/parser/ast' module Puppet class ParseError < Puppet::Error; end class ImportError < Racc::ParseError; end class AlreadyImportedError < ImportError; end end module Puppet module Parser class Parser < Racc::Parser -module_eval(<<'...end grammar.ra/module_eval...', 'grammar.ra', 851) +module_eval(<<'...end grammar.ra/module_eval...', 'grammar.ra', 780) # It got too annoying having code in a file that needs to be compiled. require 'puppet/parser/parser_support' # Make emacs happy # Local Variables: # mode: ruby # End: # $Id$ ...end grammar.ra/module_eval... ##### State transition tables begin ### racc_action_table = [ 256, 257, 228, 82, 54, 72, 75, 181, 251, 48, 72, 75, 194, 205, 210, 163, 156, 348, 46, 47, 344, 184, 201, 203, 206, 209, 162, 352, 54, 182, 351, 169, 54, -168, 72, 75, 241, 242, 102, 305, 106, 158, 58, 193, 230, 60, 204, 208, 193, 306, 213, 196, 197, 198, 200, 202, 97, 207, 211, 72, 75, 72, 75, 163, 199, 59, 58, 71, 245, 60, 58, 83, 86, 60, 162, 92, 244, 72, 75, 169, 78, 100, 352, 269, 89, 351, 63, 94, 64, 59, 228, 326, 71, 59, 162, 59, 83, 86, 83, 268, 92, 65, 92, 184, 76, 78, 307, 137, 163, 89, 162, 89, 72, 75, 83, 268, 241, 242, 92, 162, 59, 163, 59, 137, 169, 62, 254, 89, 207, 211, 72, 75, 162, 308, 102, 199, 106, 169, 59, 255, 213, 196, 197, 198, -166, 162, 309, 207, 211, 83, 268, 310, 97, 92, 199, 72, 75, 355, 137, 102, -170, 106, 89, 71, 218, 356, 173, 83, 86, 220, 313, 92, -171, 59, 72, 75, 78, 100, 37, 218, 89, 249, 38, 94, 220, 246, 247, 173, 71, 11, 210, 59, 83, 86, 246, 367, 92, 271, 201, 37, -167, 78, 37, 38, 270, 89, 38, 71, 246, 247, 11, 83, 86, 11, 14, 92, 59, 72, 75, 76, 78, 102, 278, 106, 89, 277, 213, 196, 197, 198, 200, 202, 275, 207, 211, 59, 246, 274, 152, 97, 199, 37, 318, 72, 75, 127, 319, 102, -169, 106, 71, 63, 11, 14, 83, 86, -167, 37, 92, 207, 211, 127, -169, 78, 100, 97, 199, 89, 11, 14, 94, -166, 117, 72, 75, -185, 71, 82, 59, 336, 83, 86, 197, 198, 92, 231, 338, 207, 211, 78, 100, 181, 48, 89, 199, 74, 94, 240, -168, 72, 75, 241, 242, 102, 59, 106, 71, 184, 176, 37, 83, 86, 59, 38, 92, 345, 322, 175, 76, 78, 11, 97, -172, 89, -171, 72, 75, -170, 59, 102, 214, 106, 71, 64, 59, 215, 83, 86, 173, 217, 92, -23, -23, -23, -23, 78, 100, 97, 155, 89, 72, 75, 94, 122, 102, 152, 106, 82, 71, 223, 59, 122, 83, 86, 72, 75, 92, -168, 102, 225, 106, 78, 100, -166, 276, 89, 226, 117, 94, 44, 45, 41, 42, 71, -169, -167, 59, 83, 86, 72, 75, 92, 226, 102, 229, 106, 78, 71, 52, -168, 89, 83, 86, 72, 75, 92, -166, 102, -169, 106, 78, 59, 197, 198, 89, -167, -171, 207, 211, 365, 231, 152, 71, 234, 199, 59, 83, 86, 50, 210, 92, -21, -21, -21, -21, 78, 71, 201, 372, 89, 83, 86, 49, 374, 92, 72, 75, 228, -220, 78, 59, 226, 354, 89, 377, 72, 75, 40, 39, 102, 237, 106, 341, nil, 59, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, nil, 97, 162, 199, nil, nil, 83, 268, nil, nil, 92, nil, 71, nil, nil, 137, 83, 86, nil, 89, 92, 44, 45, 41, 42, 78, 100, 72, 75, 89, 59, 102, 94, 106, 213, 196, 197, 198, 200, 202, 59, 207, 211, nil, 213, 196, 197, 198, 199, 97, nil, 207, 211, 72, 75, nil, nil, 102, 199, 106, 71, nil, nil, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, nil, nil, 94, nil, nil, 72, 75, nil, 71, 102, 59, 106, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, 72, 75, 94, nil, 102, nil, 106, nil, 71, nil, 59, nil, 83, 86, 72, 75, 92, nil, 102, nil, nil, 78, 100, nil, nil, 89, nil, nil, 94, nil, nil, nil, nil, 71, nil, nil, 59, 83, 86, 72, 75, 92, nil, 102, nil, 106, 78, 71, nil, nil, 89, 83, 143, nil, nil, 92, nil, nil, nil, nil, 137, 59, nil, nil, 89, 72, 75, nil, nil, 102, nil, 106, 71, nil, nil, 59, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, nil, 97, nil, 89, nil, 72, 75, nil, nil, 102, nil, 106, 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, nil, nil, 94, nil, nil, 72, 75, nil, 71, 102, 59, 106, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, 72, 75, 94, nil, 102, nil, 106, nil, 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, 72, 75, 94, nil, 102, nil, 106, 71, nil, nil, 59, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, nil, 97, nil, 89, nil, 72, 75, nil, nil, 102, nil, 106, 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, nil, 72, 75, 78, 100, 97, nil, 89, 72, 75, 94, nil, 102, nil, 106, nil, 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, 162, nil, 94, nil, 83, 268, nil, 71, 92, nil, 59, 83, 86, 137, nil, 92, nil, 89, nil, nil, 78, 72, 75, nil, 89, 102, nil, 106, 59, nil, nil, nil, nil, nil, nil, 59, nil, nil, nil, nil, 72, 75, nil, 97, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 71, nil, nil, nil, 83, 86, nil, nil, 92, 177, nil, 72, 75, 78, 100, nil, nil, 89, nil, 71, 94, nil, nil, 83, 86, nil, nil, 92, 59, 72, 75, 76, 78, 102, 339, 106, 89, nil, nil, nil, nil, nil, nil, nil, 71, nil, nil, 59, 83, 86, nil, 97, 92, nil, 72, 75, 76, 78, 102, nil, 106, 89, 71, nil, 72, 75, 83, 86, nil, nil, 92, nil, 59, nil, nil, 78, 100, nil, nil, 89, 72, 75, 94, nil, nil, nil, nil, 71, nil, nil, 59, 83, 86, nil, nil, 92, nil, 162, nil, nil, 78, 83, 268, nil, 89, 92, nil, 72, 75, nil, 137, 102, nil, 162, 89, 59, nil, 83, 268, nil, nil, 92, nil, 72, 75, 59, 137, 102, nil, 106, 89, nil, nil, 72, 75, nil, nil, 102, nil, 106, 71, 59, nil, nil, 83, 268, nil, nil, 92, nil, nil, nil, nil, 137, nil, 97, 71, 89, nil, nil, 83, 86, nil, nil, 92, nil, 71, nil, 59, 78, 83, 86, nil, 89, 92, nil, nil, nil, nil, 78, 100, 72, 75, 89, 59, 102, 94, 106, 213, 196, 197, 198, 200, 202, 59, 207, 211, nil, nil, nil, 72, 75, 199, 97, 102, 189, 106, 72, 75, nil, nil, 102, nil, 106, 71, nil, nil, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 72, 75, 89, nil, 71, 94, nil, nil, 83, 86, nil, 71, 92, 59, nil, 83, 86, 78, nil, 92, nil, 89, nil, nil, 78, 72, 75, nil, 89, 102, nil, 106, 59, 162, nil, nil, nil, 83, 268, 59, nil, 92, nil, 72, 75, nil, 137, 102, nil, 106, 89, nil, nil, nil, nil, nil, nil, nil, 71, nil, nil, 59, 83, 86, nil, 97, 92, nil, nil, nil, nil, 78, nil, 72, 75, 89, 71, 102, nil, 106, 83, 86, nil, nil, 92, nil, 59, nil, nil, 78, 100, nil, nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, nil, nil, 94, nil, nil, nil, nil, nil, 71, nil, 59, nil, 83, 86, 212, nil, 92, nil, nil, nil, nil, 78, 100, 205, 210, 89, nil, nil, 94, nil, nil, nil, 201, 203, 206, 209, 59, nil, 205, 210, nil, nil, nil, nil, nil, nil, nil, 201, 203, 206, 209, nil, nil, nil, nil, nil, 204, 208, nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, 204, 208, nil, 199, 213, 196, 197, 198, 200, 202, nil, 207, 211, 205, 210, nil, nil, nil, 199, nil, nil, nil, 201, 203, 206, 209, nil, nil, 205, 210, nil, nil, nil, nil, nil, nil, nil, 201, 203, 206, 209, nil, nil, nil, nil, nil, 204, 208, nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, 204, 208, nil, 199, 213, 196, 197, 198, 200, 202, nil, 207, 211, 205, 210, nil, nil, nil, 199, nil, nil, nil, 201, 203, 206, 209, nil, nil, 205, 210, nil, nil, nil, nil, nil, nil, 273, 201, 203, 206, 209, nil, nil, nil, nil, nil, nil, 208, nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, 204, 208, nil, 199, 213, 196, 197, 198, 200, 202, nil, 207, 211, 205, 210, nil, nil, nil, 199, nil, nil, nil, 201, 203, 206, 209, nil, nil, 26, 210, 33, 1, nil, 7, 12, nil, 17, 201, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 210, nil, 213, 196, 197, 198, 200, 202, 201, 207, 211, nil, nil, nil, nil, nil, 199, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, 324, nil, nil, 199, nil, nil, nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, 379, nil, 26, 199, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, 382, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 296, nil, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, 364, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 381, nil, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, 383, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 357, nil, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, 363, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 375, nil, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, 304, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, nil, 349, nil, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, 26, nil, 33, 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, 14 ] racc_action_check = [ 180, 180, 152, 86, 156, 106, 106, 272, 174, 7, 277, 277, 106, 180, 180, 65, 55, 277, 7, 7, 272, 86, 180, 180, 180, 180, 65, 296, 17, 80, 296, 65, 158, 95, 202, 202, 174, 174, 202, 218, 202, 55, 156, 106, 152, 156, 180, 180, 277, 219, 180, 180, 180, 180, 180, 180, 202, 180, 180, 181, 181, 368, 368, 239, 180, 156, 17, 202, 165, 17, 158, 202, 202, 158, 239, 202, 165, 182, 182, 239, 202, 202, 349, 182, 202, 349, 22, 202, 22, 17, 143, 243, 181, 158, 368, 202, 181, 181, 368, 368, 181, 22, 368, 143, 181, 181, 220, 368, 163, 181, 182, 368, 355, 355, 182, 182, 243, 243, 182, 163, 181, 62, 368, 182, 163, 22, 178, 182, 281, 281, 351, 351, 62, 221, 351, 281, 351, 62, 182, 178, 285, 285, 285, 285, 101, 355, 221, 285, 285, 355, 355, 224, 351, 355, 285, 341, 341, 300, 355, 341, 91, 341, 355, 351, 308, 300, 226, 351, 351, 308, 227, 351, 90, 355, 184, 184, 351, 351, 12, 122, 351, 171, 12, 351, 122, 171, 171, 229, 341, 12, 286, 351, 341, 341, 343, 343, 341, 184, 286, 1, 87, 341, 30, 1, 183, 341, 30, 184, 183, 183, 1, 184, 184, 30, 30, 184, 341, 196, 196, 184, 184, 196, 195, 196, 184, 195, 286, 286, 286, 286, 286, 286, 188, 286, 286, 184, 188, 188, 231, 196, 286, 120, 232, 197, 197, 120, 233, 197, 103, 197, 196, 85, 120, 120, 196, 196, 105, 43, 196, 280, 280, 43, 84, 196, 196, 197, 280, 196, 43, 43, 196, 81, 215, 23, 23, 78, 197, 23, 196, 250, 197, 197, 279, 279, 197, 252, 253, 279, 279, 197, 197, 77, 71, 197, 279, 23, 197, 160, 68, 26, 26, 160, 160, 26, 197, 26, 23, 268, 67, 234, 23, 23, 211, 234, 23, 274, 234, 66, 23, 23, 234, 26, 107, 23, 108, 198, 198, 109, 207, 198, 114, 198, 26, 115, 23, 119, 26, 26, 64, 121, 26, 35, 35, 35, 35, 26, 26, 198, 52, 26, 29, 29, 26, 51, 29, 50, 29, 127, 198, 132, 26, 36, 198, 198, 307, 307, 198, 133, 307, 136, 307, 198, 198, 138, 192, 198, 139, 33, 198, 34, 34, 34, 34, 29, 140, 142, 198, 29, 29, 305, 305, 29, 315, 305, 144, 305, 29, 307, 16, 327, 29, 307, 307, 199, 199, 307, 328, 199, 330, 199, 307, 29, 297, 297, 307, 331, 332, 297, 297, 337, 153, 175, 305, 154, 297, 307, 305, 305, 9, 288, 305, 28, 28, 28, 28, 305, 199, 288, 352, 305, 199, 199, 8, 356, 199, 298, 298, 173, 367, 199, 305, 172, 298, 199, 369, 200, 200, 3, 2, 200, 157, 200, 263, nil, 199, 288, 288, 288, 288, 288, 288, nil, 288, 288, nil, nil, nil, 200, 298, 288, nil, nil, 298, 298, nil, nil, 298, nil, 200, nil, nil, 298, 200, 200, nil, 298, 200, 4, 4, 4, 4, 200, 200, 39, 39, 200, 298, 39, 200, 39, 293, 293, 293, 293, 293, 293, 200, 293, 293, nil, 283, 283, 283, 283, 293, 39, nil, 283, 283, 201, 201, nil, nil, 201, 283, 201, 39, nil, nil, nil, 39, 39, nil, nil, 39, nil, nil, nil, nil, 39, 39, 201, nil, 39, nil, nil, 39, nil, nil, 46, 46, nil, 201, 46, 39, 46, 201, 201, nil, nil, 201, nil, nil, nil, nil, 201, 201, nil, nil, 201, nil, 46, 201, nil, nil, 47, 47, nil, nil, 47, 201, 47, 46, nil, nil, nil, 46, 46, nil, nil, 46, nil, nil, nil, nil, 46, 46, 47, nil, 46, 48, 48, 46, nil, 48, nil, 48, nil, 47, nil, 46, nil, 47, 47, 49, 49, 47, nil, 49, nil, nil, 47, 47, nil, nil, 47, nil, nil, 47, nil, nil, nil, nil, 48, nil, nil, 47, 48, 48, 176, 176, 48, nil, 176, nil, 176, 48, 49, nil, nil, 48, 49, 49, nil, nil, 49, nil, nil, nil, nil, 49, 48, nil, nil, 49, 203, 203, nil, nil, 203, nil, 203, 176, nil, nil, 49, 176, 176, nil, nil, 176, nil, nil, nil, nil, 176, nil, 203, nil, 176, nil, 204, 204, nil, nil, 204, nil, 204, 203, nil, 176, nil, 203, 203, nil, nil, 203, nil, nil, nil, nil, 203, 203, 204, nil, 203, nil, nil, 203, nil, nil, 205, 205, nil, 204, 205, 203, 205, 204, 204, nil, nil, 204, nil, nil, nil, nil, 204, 204, nil, nil, 204, nil, 205, 204, nil, nil, 100, 100, nil, nil, 100, 204, 100, 205, nil, nil, nil, 205, 205, nil, nil, 205, nil, nil, nil, nil, 205, 205, 100, nil, 205, 63, 63, 205, nil, 63, nil, 63, nil, 100, nil, 205, nil, 100, 100, nil, nil, 100, nil, nil, nil, nil, 100, 100, nil, nil, 100, 208, 208, 100, nil, 208, nil, 208, 63, nil, nil, 100, 63, 63, nil, nil, 63, nil, nil, nil, nil, 63, nil, 208, nil, 63, nil, 209, 209, nil, nil, 209, nil, 209, 208, nil, 63, nil, 208, 208, nil, nil, 208, nil, nil, 269, 269, 208, 208, 209, nil, 208, 276, 276, 208, nil, 276, nil, 276, nil, 209, nil, 208, nil, 209, 209, nil, nil, 209, nil, nil, nil, nil, 209, 209, nil, nil, 209, 269, nil, 209, nil, 269, 269, nil, 276, 269, nil, 209, 276, 276, 269, nil, 276, nil, 269, nil, nil, 276, 256, 256, nil, 276, 256, nil, 256, 269, nil, nil, nil, nil, nil, nil, 276, nil, nil, nil, nil, 74, 74, nil, 256, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 256, nil, nil, nil, 256, 256, nil, nil, 256, 74, nil, 254, 254, 256, 256, nil, nil, 256, nil, 74, 256, nil, nil, 74, 74, nil, nil, 74, 256, 75, 75, 74, 74, 75, 254, 75, 74, nil, nil, nil, nil, nil, nil, nil, 254, nil, nil, 74, 254, 254, nil, 75, 254, nil, 248, 248, 254, 254, 248, nil, 248, 254, 75, nil, 245, 245, 75, 75, nil, nil, 75, nil, 254, nil, nil, 75, 75, nil, nil, 75, 244, 244, 75, nil, nil, nil, nil, 248, nil, nil, 75, 248, 248, nil, nil, 248, nil, 245, nil, nil, 248, 245, 245, nil, 248, 245, nil, 225, 225, nil, 245, 225, nil, 244, 245, 248, nil, 244, 244, nil, nil, 244, nil, 82, 82, 245, 244, 82, nil, 82, 244, nil, nil, 210, 210, nil, nil, 210, nil, 210, 225, 244, nil, nil, 225, 225, nil, nil, 225, nil, nil, nil, nil, 225, nil, 210, 82, 225, nil, nil, 82, 82, nil, nil, 82, nil, 210, nil, 225, 82, 210, 210, nil, 82, 210, nil, nil, nil, nil, 210, 210, 213, 213, 210, 82, 213, 210, 213, 284, 284, 284, 284, 284, 284, 210, 284, 284, nil, nil, nil, 102, 102, 284, 213, 102, 102, 102, 230, 230, nil, nil, 230, nil, 230, 213, nil, nil, nil, 213, 213, nil, nil, 213, nil, nil, nil, nil, 213, 213, 214, 214, 213, nil, 102, 213, nil, nil, 102, 102, nil, 230, 102, 213, nil, 230, 230, 102, nil, 230, nil, 102, nil, nil, 230, 228, 228, nil, 230, 228, nil, 228, 102, 214, nil, nil, nil, 214, 214, 230, nil, 214, nil, 94, 94, nil, 214, 94, nil, 94, 214, nil, nil, nil, nil, nil, nil, nil, 228, nil, nil, 214, 228, 228, nil, 94, 228, nil, nil, nil, nil, 228, nil, 97, 97, 228, 94, 97, nil, 97, 94, 94, nil, nil, 94, nil, 228, nil, nil, 94, 94, nil, nil, 94, nil, 97, 94, nil, nil, 206, 206, nil, nil, 206, 94, 206, 97, nil, nil, nil, 97, 97, nil, nil, 97, nil, nil, nil, nil, 97, 97, 206, nil, 97, nil, nil, 97, nil, nil, nil, nil, nil, 206, nil, 97, nil, 206, 206, 111, nil, 206, nil, nil, nil, nil, 206, 206, 111, 111, 206, nil, nil, 206, nil, nil, nil, 111, 111, 111, 111, 206, nil, 124, 124, nil, nil, nil, nil, nil, nil, nil, 124, 124, 124, 124, nil, nil, nil, nil, nil, 111, 111, nil, nil, 111, 111, 111, 111, 111, 111, nil, 111, 111, nil, nil, 124, 124, nil, 111, 124, 124, 124, 124, 124, 124, nil, 124, 124, 130, 130, nil, nil, nil, 124, nil, nil, nil, 130, 130, 130, 130, nil, nil, 131, 131, nil, nil, nil, nil, nil, nil, nil, 131, 131, 131, 131, nil, nil, nil, nil, nil, 130, 130, nil, nil, 130, 130, 130, 130, 130, 130, nil, 130, 130, nil, nil, 131, 131, nil, 130, 131, 131, 131, 131, 131, 131, nil, 131, 131, 287, 287, nil, nil, nil, 131, nil, nil, nil, 287, 287, 287, 287, nil, nil, 186, 186, nil, nil, nil, nil, nil, nil, 186, 186, 186, 186, 186, nil, nil, nil, nil, nil, nil, 287, nil, nil, 287, 287, 287, 287, 287, 287, nil, 287, 287, nil, nil, 186, 186, nil, 287, 186, 186, 186, 186, 186, 186, nil, 186, 186, 291, 291, nil, nil, nil, 186, nil, nil, nil, 291, 291, 291, 291, nil, nil, 19, 292, 19, 19, nil, 19, 19, nil, 19, 292, 19, nil, 19, nil, 19, nil, nil, 19, 19, nil, 289, nil, 291, 291, 291, 291, 291, 291, 289, 291, 291, nil, nil, nil, nil, nil, 291, 292, 292, 292, 292, 292, 292, nil, 292, 292, nil, nil, 237, nil, nil, 292, nil, nil, nil, nil, 289, 289, 289, 289, 289, 289, nil, 289, 289, nil, nil, 372, nil, 237, 289, 237, 237, nil, 237, 237, nil, 237, nil, 237, nil, 237, nil, 237, nil, nil, 237, 237, 372, 378, 372, 372, nil, 372, 372, nil, 372, nil, 372, nil, 372, nil, 372, nil, nil, 372, 372, nil, 212, nil, 378, nil, 378, 378, nil, 378, 378, nil, 378, nil, 378, nil, 378, nil, 378, nil, nil, 378, 378, 212, 323, 212, 212, nil, 212, 212, nil, 212, nil, 212, nil, 212, nil, 212, nil, nil, 212, 212, nil, 374, nil, 323, nil, 323, 323, nil, 323, 323, nil, 323, nil, 323, nil, 323, nil, 323, nil, nil, 323, 323, 374, 380, 374, 374, nil, 374, 374, nil, 374, nil, 374, nil, 374, nil, 374, nil, nil, 374, 374, nil, 303, nil, 380, nil, 380, 380, nil, 380, 380, nil, 380, nil, 380, nil, 380, nil, 380, nil, nil, 380, 380, 303, 319, 303, 303, nil, 303, 303, nil, 303, nil, 303, nil, 303, nil, 303, nil, nil, 303, 303, nil, 362, nil, 319, nil, 319, 319, nil, 319, 319, nil, 319, nil, 319, nil, 319, nil, 319, nil, nil, 319, 319, 362, 217, 362, 362, nil, 362, 362, nil, 362, nil, 362, nil, 362, nil, 362, nil, nil, 362, 362, nil, 295, nil, 217, nil, 217, 217, nil, 217, 217, nil, 217, nil, 217, nil, 217, nil, 217, nil, nil, 217, 217, 295, nil, 295, 295, nil, 295, 295, nil, 295, nil, 295, nil, 295, nil, 295, nil, nil, 295, 295, 0, nil, 0, 0, nil, 0, 0, nil, 0, nil, 0, nil, 0, nil, 0, nil, nil, 0, 0 ] racc_action_pointer = [ 1795, 163, 443, 413, 433, nil, nil, 3, 434, 420, nil, nil, 142, nil, nil, nil, 398, 26, nil, 1483, nil, nil, 80, 271, nil, nil, 297, nil, 367, 348, 166, nil, nil, 375, 315, 277, 337, nil, nil, 501, nil, nil, nil, 221, nil, nil, 557, 583, 608, 622, 315, 329, 348, nil, nil, 4, nil, nil, nil, nil, nil, nil, 97, 780, 298, -9, 309, 302, 275, nil, nil, 286, nil, nil, 923, 966, nil, 279, 269, nil, 6, 248, 1060, nil, 239, 245, -3, 177, nil, nil, 149, 137, nil, nil, 1209, 10, nil, 1239, nil, nil, 755, 121, 1137, 225, nil, 233, 3, 299, 301, 304, nil, 1298, nil, nil, 322, 325, nil, nil, nil, 323, 205, 331, 144, nil, 1313, nil, nil, 351, nil, nil, 1359, 1374, 352, 344, nil, nil, 328, nil, 350, 364, 361, nil, 362, 79, 374, nil, nil, nil, nil, nil, nil, nil, -9, 408, 386, nil, 2, 452, 30, nil, 251, nil, nil, 84, nil, 50, nil, nil, nil, nil, nil, 174, 439, 436, -14, 381, 647, nil, 114, nil, -4, 57, 75, 197, 172, nil, 1435, nil, 225, nil, nil, nil, 363, nil, nil, 213, 215, 241, 323, 401, 453, 527, 32, 673, 699, 729, 1265, 265, 806, 832, 1070, 249, 1612, 1118, 1166, 270, nil, 1757, 24, 24, 91, 121, nil, nil, 142, 1044, 126, 161, 1191, 147, 1144, 198, 233, 238, 273, nil, nil, 1552, nil, 39, nil, nil, nil, 66, 1017, 1001, nil, nil, 991, nil, 270, nil, 273, 279, 948, nil, 904, nil, nil, nil, nil, nil, nil, 451, nil, nil, nil, nil, 283, 850, nil, nil, -5, nil, 308, nil, 857, 8, nil, 226, 198, 67, nil, 466, 1073, 86, 172, 1420, 411, 1515, nil, 1481, 1496, 456, nil, 1776, -4, 356, 443, nil, 145, nil, nil, 1694, nil, 387, nil, 362, 129, nil, nil, nil, nil, nil, nil, 380, nil, nil, nil, 1716, nil, nil, nil, 1634, nil, nil, nil, 376, 383, nil, 385, 392, 393, nil, nil, nil, nil, 410, nil, nil, nil, 153, nil, 183, nil, nil, nil, nil, nil, 51, nil, 128, 430, nil, nil, 110, 435, nil, nil, nil, nil, nil, 1735, nil, nil, nil, nil, 439, 59, 445, nil, nil, 1571, nil, 1653, nil, nil, nil, 1593, nil, 1675, nil, nil, nil ] racc_action_default = [ -196, -233, -233, -50, -233, -8, -9, -233, -233, -22, -10, -187, -188, -11, -185, -12, -233, -233, -13, -1, -14, -2, -233, -186, -15, -3, -233, -16, -5, -233, -233, -17, -6, -233, -18, -7, -196, -188, -186, -233, -51, -26, -27, -233, -24, -25, -233, -233, -233, -85, -92, -196, -233, -195, -193, -196, -189, -191, -192, -221, -194, -4, -196, -233, -85, -196, -53, -231, -42, -174, -43, -213, -117, -33, -233, -233, -44, -31, -74, -32, -233, -36, -233, -122, -37, -233, -73, -38, -172, -72, -39, -40, -173, -41, -233, -103, -111, -233, -132, -112, -233, -104, -233, -108, -110, -105, -233, -114, -106, -113, -109, -233, -125, -107, -233, -233, -49, -175, -176, -178, -233, -233, -197, -198, -83, -19, -22, -186, -21, -23, -82, -84, -233, -75, -86, -81, -70, -74, -76, -219, -79, -68, -77, -73, -233, -171, -170, -80, -78, -90, -91, -93, -233, -219, -196, 384, -233, -233, -233, -207, -233, -57, -213, -196, -59, -233, -66, -65, -56, -73, -95, -233, -219, -233, -233, -92, -233, -30, -233, -118, -233, -233, -233, -233, -233, -142, -233, -149, -233, -216, -229, -225, -233, -228, -224, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, -20, -233, -206, -233, -204, -233, -201, -230, -233, -71, -220, -233, -233, -85, -233, -220, -233, -233, -233, -209, -190, -233, -208, -233, -54, -62, -61, -233, -233, -233, -217, -218, -233, -124, -233, -55, -219, -233, -233, -28, -233, -120, -119, -35, -34, -168, -166, -233, -169, -160, -167, -161, -73, -233, -123, -116, -233, -152, -218, -214, -233, -233, -222, -137, -139, -138, -133, -140, -144, -141, -146, -151, -148, -145, -134, -150, -147, -143, -135, -233, -128, -136, -233, -154, -233, -158, -177, -233, -180, -233, -199, -233, -233, -200, -45, -69, -87, -46, -88, -219, -89, -94, -48, -233, -211, -210, -212, -233, -184, -58, -60, -97, -98, -63, -102, -99, -100, -101, -64, -96, -47, -233, -232, -29, -121, -233, -163, -219, -115, -215, -227, -226, -223, -128, -127, -233, -233, -155, -153, -233, -233, -179, -205, -203, -202, -67, -233, -182, -183, -52, -165, -218, -233, -233, -126, -129, -233, -159, -233, -181, -164, -162, -233, -131, -233, -157, -130, -156 ] racc_goto_table = [ 22, 9, 68, 112, 53, 118, 61, 36, 91, 222, 19, 267, 70, 93, 2, 227, 139, 191, 51, 22, 9, 179, 77, 56, 73, 149, 21, 141, 133, 232, 115, 172, 153, 2, 146, 263, 125, 116, 135, 148, 147, 299, 129, 22, 126, 260, 160, 350, 250, 174, 128, 171, 43, 68, 121, 329, 334, 298, 368, 91, 258, 265, 123, 70, 93, 317, 343, 301, 136, 154, 183, 119, 224, 178, 233, 73, 55, 123, 157, 66, 238, 159, 120, 219, 221, 190, 325, 321, 195, 16, 188, nil, nil, nil, nil, nil, nil, nil, 342, nil, 370, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 216, nil, nil, nil, nil, 260, 129, 22, 126, 263, nil, nil, 353, nil, 128, 337, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 81, nil, nil, nil, 53, nil, 53, nil, 243, nil, nil, 149, 301, nil, nil, nil, nil, nil, 252, nil, nil, 68, 261, 236, 68, nil, 138, 91, 146, nil, 91, 70, 93, nil, 70, 93, nil, nil, nil, 166, nil, 235, 166, 259, 272, nil, 73, nil, 302, 347, nil, 81, 361, nil, 261, 290, 360, 315, 376, 294, 146, nil, 312, 340, 311, 133, nil, 149, nil, 373, nil, 146, nil, 22, 9, 135, 148, 147, 22, 9, 369, nil, 263, 295, 327, 327, nil, 2, 303, nil, 146, 146, 2, nil, 68, 333, 333, nil, 22, 9, 91, 320, 88, nil, 70, 93, nil, nil, 323, 261, nil, nil, 2, nil, nil, 146, 259, 190, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 88, nil, nil, nil, nil, nil, nil, nil, 87, nil, 261, nil, 166, nil, nil, 61, 146, nil, nil, nil, nil, nil, nil, 61, nil, 88, nil, nil, 22, 9, 81, 262, nil, 81, 142, nil, 22, 9, nil, nil, nil, nil, 2, 61, nil, nil, nil, nil, nil, nil, 2, nil, 22, 9, nil, nil, 22, 9, nil, 87, nil, 371, 362, 262, nil, nil, 2, 261, nil, nil, 2, nil, nil, 146, 138, nil, nil, nil, nil, nil, 261, nil, 61, nil, nil, nil, 146, nil, 166, nil, nil, nil, nil, 328, 328, 22, 9, 114, 61, nil, 61, nil, 84, 81, nil, 22, 9, 22, 9, 2, 90, 22, 9, 22, 9, 378, 132, 380, 262, 2, nil, 2, nil, nil, nil, 2, nil, 2, 140, nil, nil, 170, 88, 88, nil, 88, 145, nil, nil, nil, nil, 167, nil, nil, 167, nil, nil, 262, nil, nil, 170, nil, nil, 84, nil, nil, nil, nil, nil, nil, nil, 90, nil, nil, nil, 88, 87, 266, nil, 87, 170, nil, nil, nil, nil, nil, 88, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 88, 88, nil, nil, 266, nil, nil, nil, nil, 262, 88, nil, nil, nil, nil, 142, nil, nil, nil, nil, nil, nil, 262, nil, nil, 88, nil, nil, nil, nil, nil, nil, nil, nil, 331, 331, nil, nil, nil, nil, nil, nil, nil, nil, 87, nil, nil, 167, nil, 253, nil, nil, nil, nil, 88, nil, nil, nil, nil, 266, nil, nil, nil, nil, nil, 84, 264, nil, 84, nil, nil, nil, 282, 90, 145, nil, 90, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 266, nil, nil, nil, nil, nil, nil, nil, nil, nil, 264, nil, nil, 314, nil, 316, nil, 124, 145, nil, nil, 140, nil, 88, 130, 131, nil, nil, nil, 145, nil, nil, nil, 335, nil, 167, 88, nil, nil, nil, 330, 330, nil, nil, nil, nil, nil, nil, 332, 332, 84, nil, nil, 180, nil, nil, nil, 266, 90, nil, nil, 346, nil, nil, nil, 264, nil, nil, nil, nil, 266, nil, 185, 145, nil, 186, nil, nil, 187, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 358, nil, 359, nil, 264, nil, nil, nil, nil, nil, nil, nil, 145, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 366, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 264, nil, nil, nil, nil, nil, nil, nil, 145, nil, nil, nil, nil, 264, nil, nil, nil, nil, nil, nil, nil, 145, nil, 279, 280, 281, nil, 283, 284, 285, 286, 287, 288, 289, nil, 291, 292, 293, nil, nil, 297, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 180 ] racc_goto_check = [ 37, 21, 30, 62, 64, 72, 4, 32, 28, 82, 2, 70, 31, 29, 52, 36, 35, 85, 32, 37, 21, 60, 22, 78, 21, 53, 3, 47, 30, 36, 37, 35, 38, 52, 28, 68, 19, 5, 31, 29, 50, 66, 7, 37, 21, 23, 41, 63, 36, 41, 5, 57, 20, 30, 74, 46, 46, 65, 58, 28, 61, 69, 3, 31, 29, 56, 71, 68, 33, 74, 57, 73, 34, 22, 75, 21, 76, 3, 77, 40, 79, 3, 20, 80, 81, 30, 42, 83, 84, 1, 57, nil, nil, nil, nil, nil, nil, nil, 70, nil, 63, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 19, nil, nil, nil, nil, 23, 7, 37, 21, 68, nil, nil, 66, nil, 5, 36, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 24, nil, nil, nil, 64, nil, 64, nil, 41, nil, nil, 53, 68, nil, nil, nil, nil, nil, 38, nil, nil, 30, 30, 78, 30, nil, 24, 28, 28, nil, 28, 31, 29, nil, 31, 29, nil, nil, nil, 24, nil, 3, 24, 21, 22, nil, 21, nil, 72, 85, nil, 24, 36, nil, 30, 64, 82, 35, 70, 64, 28, nil, 53, 60, 47, 30, nil, 53, nil, 68, nil, 28, nil, 37, 21, 31, 29, 50, 37, 21, 36, nil, 68, 2, 30, 30, nil, 52, 2, nil, 28, 28, 52, nil, 30, 29, 29, nil, 37, 21, 28, 32, 49, nil, 31, 29, nil, nil, 2, 30, nil, nil, 52, nil, nil, 28, 21, 30, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 49, nil, nil, nil, nil, nil, nil, nil, 26, nil, 30, nil, 24, nil, nil, 4, 28, nil, nil, nil, nil, nil, nil, 4, nil, 49, nil, nil, 37, 21, 24, 24, nil, 24, 26, nil, 37, 21, nil, nil, nil, nil, 52, 4, nil, nil, nil, nil, nil, nil, 52, nil, 37, 21, nil, nil, 37, 21, nil, 26, nil, 62, 2, 24, nil, nil, 52, 30, nil, nil, 52, nil, nil, 28, 24, nil, nil, nil, nil, nil, 30, nil, 4, nil, nil, nil, 28, nil, 24, nil, nil, nil, nil, 24, 24, 37, 21, 54, 4, nil, 4, nil, 25, 24, nil, 37, 21, 37, 21, 52, 27, 37, 21, 37, 21, 2, 54, 2, 24, 52, nil, 52, nil, nil, nil, 52, nil, 52, 25, nil, nil, 54, 49, 49, nil, 49, 27, nil, nil, nil, nil, 25, nil, nil, 25, nil, nil, 24, nil, nil, 54, nil, nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, nil, nil, 49, 26, 26, nil, 26, 54, nil, nil, nil, nil, nil, 49, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 49, 49, nil, nil, 26, nil, nil, nil, nil, 24, 49, nil, nil, nil, nil, 26, nil, nil, nil, nil, nil, nil, 24, nil, nil, 49, nil, nil, nil, nil, nil, nil, nil, nil, 26, 26, nil, nil, nil, nil, nil, nil, nil, nil, 26, nil, nil, 25, nil, 54, nil, nil, nil, nil, 49, nil, nil, nil, nil, 26, nil, nil, nil, nil, nil, 25, 25, nil, 25, nil, nil, nil, 54, 27, 27, nil, 27, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, 25, nil, nil, 54, nil, 54, nil, 51, 27, nil, nil, 25, nil, 49, 51, 51, nil, nil, nil, 27, nil, nil, nil, 54, nil, 25, 49, nil, nil, nil, 25, 25, nil, nil, nil, nil, nil, nil, 27, 27, 25, nil, nil, 51, nil, nil, nil, 26, 27, nil, nil, 54, nil, nil, nil, 25, nil, nil, nil, nil, 26, nil, 51, 27, nil, 51, nil, nil, 51, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 54, nil, 54, nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 54, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, 51, 51, 51, nil, 51, 51, 51, 51, 51, 51, 51, nil, 51, 51, 51, nil, nil, 51, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 51 ] racc_goto_pointer = [ nil, 89, 10, 26, -13, 7, nil, -1, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, -7, 48, 1, -1, -136, 116, 346, 252, 354, -15, -10, -21, -11, 6, 19, -64, -33, -124, 0, -18, nil, 57, -16, -153, nil, nil, nil, -189, -22, nil, 218, -9, 528, 14, -25, 335, nil, -166, -12, -285, nil, -54, -120, -23, -249, -13, -157, -173, nil, -147, -121, -171, -203, -28, 38, 18, -80, 59, 23, 6, -78, -39, -38, -113, -147, -18, -89, nil ] racc_goto_default = [ nil, nil, nil, 168, 25, 28, 32, 35, 5, 6, 10, 13, 15, 18, 20, 24, 27, 31, 34, 4, nil, 99, nil, 79, 101, 103, 105, 108, 109, 113, 95, 96, 8, nil, nil, nil, nil, 85, nil, 30, nil, nil, 161, 239, 164, 165, nil, nil, 144, 107, 110, 111, 67, 134, 98, 150, 151, nil, 248, 104, nil, nil, nil, nil, 69, nil, nil, 300, 80, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 57, nil, nil, nil, nil, nil, nil, 192 ] racc_reduce_table = [ 0, 0, :racc_error, 1, 70, :_reduce_1, 1, 70, :_reduce_none, 1, 71, :_reduce_3, 2, 71, :_reduce_4, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 3, 87, :_reduce_19, 3, 87, :_reduce_20, 1, 88, :_reduce_none, 1, 88, :_reduce_none, 1, 88, :_reduce_none, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 4, 81, :_reduce_28, 5, 81, :_reduce_29, 3, 81, :_reduce_30, 2, 81, :_reduce_31, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, + 1, 91, :_reduce_32, + 1, 91, :_reduce_33, 3, 91, :_reduce_34, 3, 91, :_reduce_35, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_none, 1, 92, :_reduce_44, 5, 74, :_reduce_45, 5, 74, :_reduce_46, 5, 74, :_reduce_47, 5, 85, :_reduce_48, 2, 75, :_reduce_49, 1, 108, :_reduce_50, 2, 108, :_reduce_51, 6, 76, :_reduce_52, 2, 76, :_reduce_53, 3, 109, :_reduce_54, 3, 109, :_reduce_55, 1, 110, :_reduce_none, 1, 110, :_reduce_none, 3, 110, :_reduce_58, 1, 111, :_reduce_none, 3, 111, :_reduce_60, 1, 112, :_reduce_61, 1, 112, :_reduce_62, 3, 113, :_reduce_63, 3, 113, :_reduce_64, 1, 114, :_reduce_none, 1, 114, :_reduce_none, 4, 116, :_reduce_67, - 1, 102, :_reduce_none, + 1, 102, :_reduce_68, 3, 102, :_reduce_69, 0, 103, :_reduce_none, 1, 103, :_reduce_none, 1, 118, :_reduce_72, 1, 93, :_reduce_73, 1, 95, :_reduce_74, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 1, 117, :_reduce_none, 3, 77, :_reduce_82, 3, 77, :_reduce_83, 3, 86, :_reduce_84, 0, 104, :_reduce_85, 1, 104, :_reduce_86, 3, 104, :_reduce_87, 3, 122, :_reduce_88, 3, 124, :_reduce_89, 1, 125, :_reduce_none, 1, 125, :_reduce_none, 0, 107, :_reduce_92, 1, 107, :_reduce_93, 3, 107, :_reduce_94, - 1, 126, :_reduce_none, + 1, 126, :_reduce_95, 3, 126, :_reduce_96, 1, 115, :_reduce_none, 1, 115, :_reduce_none, 1, 115, :_reduce_none, 1, 115, :_reduce_none, 1, 115, :_reduce_none, 1, 115, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 1, 123, :_reduce_none, 4, 97, :_reduce_115, 3, 97, :_reduce_116, 1, 99, :_reduce_117, 2, 99, :_reduce_118, 2, 129, :_reduce_119, 1, 130, :_reduce_120, 2, 130, :_reduce_121, 1, 96, :_reduce_122, 4, 90, :_reduce_123, 4, 90, :_reduce_124, 2, 79, :_reduce_125, 5, 131, :_reduce_126, 4, 131, :_reduce_127, 0, 132, :_reduce_none, 2, 132, :_reduce_129, 4, 132, :_reduce_130, 3, 132, :_reduce_131, 1, 120, :_reduce_none, 3, 120, :_reduce_133, 3, 120, :_reduce_134, 3, 120, :_reduce_135, 3, 120, :_reduce_136, 3, 120, :_reduce_137, 3, 120, :_reduce_138, 3, 120, :_reduce_139, 3, 120, :_reduce_140, 3, 120, :_reduce_141, 2, 120, :_reduce_142, 3, 120, :_reduce_143, 3, 120, :_reduce_144, 3, 120, :_reduce_145, 3, 120, :_reduce_146, 3, 120, :_reduce_147, 3, 120, :_reduce_148, 2, 120, :_reduce_149, 3, 120, :_reduce_150, 3, 120, :_reduce_151, 3, 120, :_reduce_152, 5, 78, :_reduce_153, - 1, 134, :_reduce_none, + 1, 134, :_reduce_154, 2, 134, :_reduce_155, 5, 135, :_reduce_156, 4, 135, :_reduce_157, - 1, 136, :_reduce_none, + 1, 136, :_reduce_158, 3, 136, :_reduce_159, 3, 98, :_reduce_160, 1, 138, :_reduce_none, 4, 138, :_reduce_162, 1, 140, :_reduce_none, 3, 140, :_reduce_164, 3, 139, :_reduce_165, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_none, 1, 137, :_reduce_173, 1, 137, :_reduce_none, 1, 141, :_reduce_175, 1, 142, :_reduce_none, 3, 142, :_reduce_177, 2, 80, :_reduce_178, 6, 82, :_reduce_179, 5, 82, :_reduce_180, 7, 83, :_reduce_181, 6, 83, :_reduce_182, 6, 84, :_reduce_183, 5, 84, :_reduce_184, 1, 106, :_reduce_185, 1, 101, :_reduce_186, 1, 101, :_reduce_187, 1, 101, :_reduce_188, 1, 145, :_reduce_189, 3, 145, :_reduce_190, 1, 147, :_reduce_191, 1, 148, :_reduce_192, 1, 148, :_reduce_193, 1, 148, :_reduce_194, 1, 148, :_reduce_none, 0, 72, :_reduce_196, 0, 149, :_reduce_197, 1, 143, :_reduce_none, 3, 143, :_reduce_199, 3, 143, :_reduce_200, 1, 150, :_reduce_none, 3, 150, :_reduce_202, 3, 151, :_reduce_203, 1, 151, :_reduce_204, 3, 151, :_reduce_205, 1, 151, :_reduce_206, 1, 146, :_reduce_none, 2, 146, :_reduce_208, 1, 144, :_reduce_none, 2, 144, :_reduce_210, 1, 152, :_reduce_none, 1, 152, :_reduce_none, 1, 94, :_reduce_213, 3, 119, :_reduce_214, 4, 119, :_reduce_215, 2, 119, :_reduce_216, 1, 127, :_reduce_none, 1, 127, :_reduce_none, 0, 105, :_reduce_none, 1, 105, :_reduce_220, 1, 133, :_reduce_221, 3, 128, :_reduce_222, 4, 128, :_reduce_223, 2, 128, :_reduce_224, 1, 153, :_reduce_none, 3, 153, :_reduce_226, 3, 154, :_reduce_227, 1, 155, :_reduce_228, 1, 155, :_reduce_229, 4, 121, :_reduce_230, 1, 100, :_reduce_none, 4, 100, :_reduce_232 ] racc_reduce_n = 233 racc_shift_n = 384 racc_token_table = { false => 0, :error => 1, :STRING => 2, :DQPRE => 3, :DQMID => 4, :DQPOST => 5, :LBRACK => 6, :RBRACK => 7, :LBRACE => 8, :RBRACE => 9, :SYMBOL => 10, :FARROW => 11, :COMMA => 12, :TRUE => 13, :FALSE => 14, :EQUALS => 15, :APPENDS => 16, :LESSEQUAL => 17, :NOTEQUAL => 18, :DOT => 19, :COLON => 20, :LLCOLLECT => 21, :RRCOLLECT => 22, :QMARK => 23, :LPAREN => 24, :RPAREN => 25, :ISEQUAL => 26, :GREATEREQUAL => 27, :GREATERTHAN => 28, :LESSTHAN => 29, :IF => 30, :ELSE => 31, :IMPORT => 32, :DEFINE => 33, :ELSIF => 34, :VARIABLE => 35, :CLASS => 36, :INHERITS => 37, :NODE => 38, :BOOLEAN => 39, :NAME => 40, :SEMIC => 41, :CASE => 42, :DEFAULT => 43, :AT => 44, :LCOLLECT => 45, :RCOLLECT => 46, :CLASSNAME => 47, :CLASSREF => 48, :NOT => 49, :OR => 50, :AND => 51, :UNDEF => 52, :PARROW => 53, :PLUS => 54, :MINUS => 55, :TIMES => 56, :DIV => 57, :LSHIFT => 58, :RSHIFT => 59, :UMINUS => 60, :MATCH => 61, :NOMATCH => 62, :REGEX => 63, :IN_EDGE => 64, :OUT_EDGE => 65, :IN_EDGE_SUB => 66, :OUT_EDGE_SUB => 67, :IN => 68 } racc_nt_base = 69 racc_use_result_var = true 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", "STRING", "DQPRE", "DQMID", "DQPOST", "LBRACK", "RBRACK", "LBRACE", "RBRACE", "SYMBOL", "FARROW", "COMMA", "TRUE", "FALSE", "EQUALS", "APPENDS", "LESSEQUAL", "NOTEQUAL", "DOT", "COLON", "LLCOLLECT", "RRCOLLECT", "QMARK", "LPAREN", "RPAREN", "ISEQUAL", "GREATEREQUAL", "GREATERTHAN", "LESSTHAN", "IF", "ELSE", "IMPORT", "DEFINE", "ELSIF", "VARIABLE", "CLASS", "INHERITS", "NODE", "BOOLEAN", "NAME", "SEMIC", "CASE", "DEFAULT", "AT", "LCOLLECT", "RCOLLECT", "CLASSNAME", "CLASSREF", "NOT", "OR", "AND", "UNDEF", "PARROW", "PLUS", "MINUS", "TIMES", "DIV", "LSHIFT", "RSHIFT", "UMINUS", "MATCH", "NOMATCH", "REGEX", "IN_EDGE", "OUT_EDGE", "IN_EDGE_SUB", "OUT_EDGE_SUB", "IN", "$start", "program", "statements", "nil", "statement", "resource", "virtualresource", "collection", "assignment", "casestatement", "ifstatement_begin", "import", "fstatement", "definition", "hostclass", "nodedef", "resourceoverride", "append", "relationship", "relationship_side", "edge", "resourceref", "funcvalues", "namestring", "name", "variable", "type", "boolean", "funcrvalue", "selector", "quotedtext", "hasharrayaccesses", "classname", "resourceinstances", "endsemi", "params", "endcomma", "classref", "anyparams", "at", "collectrhand", "collstatements", "collstatement", "colljoin", "collexpr", "colllval", "simplervalue", "resourceinst", "resourcename", "undef", "array", "expression", "hasharrayaccess", "param", "rvalue", "addparam", "anyparam", "rvalues", "comma", "hash", "dqrval", "dqtail", "ifstatement", "else", "regex", "caseopts", "caseopt", "casevalues", "selectlhand", "svalues", "selectval", "sintvalues", "string", "strings", "argumentlist", "classparent", "hostnames", "nodeparent", "nodename", "hostname", "nothing", "arguments", "argument", "classnameordefault", "hashpairs", "hashpair", "key" ] Racc_debug_parser = false ##### State transition tables end ##### # reduce 0 omitted module_eval(<<'.,.,', 'grammar.ra', 31) def _reduce_1(val, _values, result) val[0].is_a_namespace = true result = val[0] result end .,., # reduce 2 omitted module_eval(<<'.,.,', 'grammar.ra', 37) def _reduce_3(val, _values, result) - result = ast AST::ASTArray, :children => [val[0]] + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) result end .,., module_eval(<<'.,.,', 'grammar.ra', 40) def _reduce_4(val, _values, result) - val[0].push(val[1]) + if val[1] + val[0].push(val[1]) + end result = val[0] result end .,., # reduce 5 omitted # reduce 6 omitted # reduce 7 omitted # reduce 8 omitted # reduce 9 omitted # reduce 10 omitted # reduce 11 omitted # reduce 12 omitted # reduce 13 omitted # reduce 14 omitted # reduce 15 omitted # reduce 16 omitted # reduce 17 omitted # reduce 18 omitted -module_eval(<<'.,.,', 'grammar.ra', 61) +module_eval(<<'.,.,', 'grammar.ra', 63) def _reduce_19(val, _values, result) result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 64) +module_eval(<<'.,.,', 'grammar.ra', 66) def _reduce_20(val, _values, result) result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., # reduce 21 omitted # reduce 22 omitted # reduce 23 omitted # reduce 24 omitted # reduce 25 omitted # reduce 26 omitted # reduce 27 omitted -module_eval(<<'.,.,', 'grammar.ra', 72) +module_eval(<<'.,.,', 'grammar.ra', 74) def _reduce_28(val, _values, result) - args = aryfy(val[2]) - result = ast AST::Function, + result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement result end .,., -module_eval(<<'.,.,', 'grammar.ra', 80) +module_eval(<<'.,.,', 'grammar.ra', 81) def _reduce_29(val, _values, result) - args = aryfy(val[2]) - result = ast AST::Function, + result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement result end .,., module_eval(<<'.,.,', 'grammar.ra', 87) def _reduce_30(val, _values, result) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], :arguments => AST::ASTArray.new({}), :ftype => :statement result end .,., module_eval(<<'.,.,', 'grammar.ra', 94) def _reduce_31(val, _values, result) - args = aryfy(val[1]) - result = ast AST::Function, + result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[1], :ftype => :statement result end .,., -# reduce 32 omitted +module_eval(<<'.,.,', 'grammar.ra', 101) + def _reduce_32(val, _values, result) + result = aryfy(val[0]) + result + end +.,., -# reduce 33 omitted +module_eval(<<'.,.,', 'grammar.ra', 102) + def _reduce_33(val, _values, result) + result = aryfy(val[0]) + result + end +.,., -module_eval(<<'.,.,', 'grammar.ra', 105) +module_eval(<<'.,.,', 'grammar.ra', 104) def _reduce_34(val, _values, result) - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + val[0].push(val[2]) + result = val[0] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 110) +module_eval(<<'.,.,', 'grammar.ra', 108) def _reduce_35(val, _values, result) - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - - val[0].push(val[2]) - - result = val[0] + val[0].push(val[2]) + result = val[0] result end .,., # reduce 36 omitted # reduce 37 omitted # reduce 38 omitted # reduce 39 omitted # reduce 40 omitted # reduce 41 omitted # reduce 42 omitted # reduce 43 omitted -module_eval(<<'.,.,', 'grammar.ra', 130) +module_eval(<<'.,.,', 'grammar.ra', 123) def _reduce_44(val, _values, result) result = ast AST::Name, :value => val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 134) +module_eval(<<'.,.,', 'grammar.ra', 127) def _reduce_45(val, _values, result) @lexer.commentpop - array = val[2] - array = [array] if array.instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - - result.push ast( - AST::Resource, - :type => val[0], - :title => instance[0], - - :parameters => instance[1]) - } + result = ast(AST::Resource, :type => val[0], :instances => val[2]) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 153) +module_eval(<<'.,.,', 'grammar.ra', 130) def _reduce_46(val, _values, result) # This is a deprecated syntax. error "All resource specifications require names" result end .,., -module_eval(<<'.,.,', 'grammar.ra', 156) +module_eval(<<'.,.,', 'grammar.ra', 133) def _reduce_47(val, _values, result) # a defaults setting for a type @lexer.commentpop result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 163) +module_eval(<<'.,.,', 'grammar.ra', 140) def _reduce_48(val, _values, result) @lexer.commentpop result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 170) +module_eval(<<'.,.,', 'grammar.ra', 147) def _reduce_49(val, _values, result) type = val[0] if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect without storeconfigs being set") end error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults method = type.to_s + "=" - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + # Just mark our resource as exported and pass it through. + val[1].send(method, true) result = val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 192) +module_eval(<<'.,.,', 'grammar.ra', 163) def _reduce_50(val, _values, result) result = :virtual result end .,., -module_eval(<<'.,.,', 'grammar.ra', 193) +module_eval(<<'.,.,', 'grammar.ra', 164) def _reduce_51(val, _values, result) result = :exported result end .,., -module_eval(<<'.,.,', 'grammar.ra', 198) +module_eval(<<'.,.,', 'grammar.ra', 169) def _reduce_52(val, _values, result) @lexer.commentpop Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ type = val[0].downcase args = {:type => type} if val[1].is_a?(AST::CollExpr) args[:query] = val[1] args[:query].type = type args[:form] = args[:query].form else args[:form] = val[1] end if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") end args[:override] = val[3] result = ast AST::Collection, args result end .,., -module_eval(<<'.,.,', 'grammar.ra', 217) +module_eval(<<'.,.,', 'grammar.ra', 188) def _reduce_53(val, _values, result) if val[0] =~ /^[a-z]/ Puppet.warning addcontext("Collection names must now be capitalized") end type = val[0].downcase args = {:type => type } if val[1].is_a?(AST::CollExpr) args[:query] = val[1] args[:query].type = type args[:form] = args[:query].form else args[:form] = val[1] end if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") end result = ast AST::Collection, args result end .,., -module_eval(<<'.,.,', 'grammar.ra', 238) +module_eval(<<'.,.,', 'grammar.ra', 209) def _reduce_54(val, _values, result) if val[1] result = val[1] result.form = :virtual else result = :virtual end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 246) +module_eval(<<'.,.,', 'grammar.ra', 217) def _reduce_55(val, _values, result) if val[1] result = val[1] result.form = :exported else result = :exported end result end .,., # reduce 56 omitted # reduce 57 omitted -module_eval(<<'.,.,', 'grammar.ra', 259) +module_eval(<<'.,.,', 'grammar.ra', 230) def _reduce_58(val, _values, result) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] result end .,., # reduce 59 omitted -module_eval(<<'.,.,', 'grammar.ra', 264) +module_eval(<<'.,.,', 'grammar.ra', 235) def _reduce_60(val, _values, result) result = val[1] result.parens = true result end .,., -module_eval(<<'.,.,', 'grammar.ra', 268) +module_eval(<<'.,.,', 'grammar.ra', 239) def _reduce_61(val, _values, result) result=val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 269) +module_eval(<<'.,.,', 'grammar.ra', 240) def _reduce_62(val, _values, result) result=val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 272) +module_eval(<<'.,.,', 'grammar.ra', 243) def _reduce_63(val, _values, result) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val result end .,., -module_eval(<<'.,.,', 'grammar.ra', 277) +module_eval(<<'.,.,', 'grammar.ra', 248) def _reduce_64(val, _values, result) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val result end .,., # reduce 65 omitted # reduce 66 omitted -module_eval(<<'.,.,', 'grammar.ra', 286) +module_eval(<<'.,.,', 'grammar.ra', 257) def _reduce_67(val, _values, result) - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] result end .,., -# reduce 68 omitted +module_eval(<<'.,.,', 'grammar.ra', 260) + def _reduce_68(val, _values, result) + result = aryfy(val[0]) + result + end +.,., -module_eval(<<'.,.,', 'grammar.ra', 291) +module_eval(<<'.,.,', 'grammar.ra', 262) def _reduce_69(val, _values, result) - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else - val[0].push val[2] + val[0].push val[2] result = val[0] - end result end .,., # reduce 70 omitted # reduce 71 omitted -module_eval(<<'.,.,', 'grammar.ra', 303) +module_eval(<<'.,.,', 'grammar.ra', 270) def _reduce_72(val, _values, result) result = ast AST::Undef, :value => :undef result end .,., -module_eval(<<'.,.,', 'grammar.ra', 307) +module_eval(<<'.,.,', 'grammar.ra', 274) def _reduce_73(val, _values, result) result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 311) +module_eval(<<'.,.,', 'grammar.ra', 278) def _reduce_74(val, _values, result) result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] result end .,., # reduce 75 omitted # reduce 76 omitted # reduce 77 omitted # reduce 78 omitted # reduce 79 omitted # reduce 80 omitted # reduce 81 omitted -module_eval(<<'.,.,', 'grammar.ra', 323) +module_eval(<<'.,.,', 'grammar.ra', 290) def _reduce_82(val, _values, result) raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ # this is distinct from referencing a variable variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 329) +module_eval(<<'.,.,', 'grammar.ra', 296) def _reduce_83(val, _values, result) result = ast AST::VarDef, :name => val[0], :value => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 333) +module_eval(<<'.,.,', 'grammar.ra', 300) def _reduce_84(val, _values, result) variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 339) +module_eval(<<'.,.,', 'grammar.ra', 306) def _reduce_85(val, _values, result) result = ast AST::ASTArray result end .,., -module_eval(<<'.,.,', 'grammar.ra', 341) +module_eval(<<'.,.,', 'grammar.ra', 308) def _reduce_86(val, _values, result) - result = val[0] + result = aryfy(val[0]) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 343) +module_eval(<<'.,.,', 'grammar.ra', 310) def _reduce_87(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) + val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 352) +module_eval(<<'.,.,', 'grammar.ra', 315) def _reduce_88(val, _values, result) result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 356) +module_eval(<<'.,.,', 'grammar.ra', 319) def _reduce_89(val, _values, result) result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], :add => true result end .,., # reduce 90 omitted # reduce 91 omitted -module_eval(<<'.,.,', 'grammar.ra', 365) +module_eval(<<'.,.,', 'grammar.ra', 328) def _reduce_92(val, _values, result) result = ast AST::ASTArray result end .,., -module_eval(<<'.,.,', 'grammar.ra', 367) +module_eval(<<'.,.,', 'grammar.ra', 330) def _reduce_93(val, _values, result) - result = val[0] + result = aryfy(val[0]) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 369) +module_eval(<<'.,.,', 'grammar.ra', 332) def _reduce_94(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) + val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end result end .,., -# reduce 95 omitted - -module_eval(<<'.,.,', 'grammar.ra', 379) - def _reduce_96(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] +module_eval(<<'.,.,', 'grammar.ra', 336) + def _reduce_95(val, _values, result) + result = aryfy(val[0]) + result end +.,., +module_eval(<<'.,.,', 'grammar.ra', 337) + def _reduce_96(val, _values, result) + result = val[0].push(val[2]) result end .,., # reduce 97 omitted # reduce 98 omitted # reduce 99 omitted # reduce 100 omitted # reduce 101 omitted # reduce 102 omitted # reduce 103 omitted # reduce 104 omitted # reduce 105 omitted # reduce 106 omitted # reduce 107 omitted # reduce 108 omitted # reduce 109 omitted # reduce 110 omitted # reduce 111 omitted # reduce 112 omitted # reduce 113 omitted # reduce 114 omitted -module_eval(<<'.,.,', 'grammar.ra', 408) +module_eval(<<'.,.,', 'grammar.ra', 361) def _reduce_115(val, _values, result) - args = aryfy(val[2]) - result = ast AST::Function, + result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :rvalue result end .,., -module_eval(<<'.,.,', 'grammar.ra', 414) +module_eval(<<'.,.,', 'grammar.ra', 366) def _reduce_116(val, _values, result) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], :arguments => AST::ASTArray.new({}), :ftype => :rvalue result end .,., -module_eval(<<'.,.,', 'grammar.ra', 420) +module_eval(<<'.,.,', 'grammar.ra', 372) def _reduce_117(val, _values, result) result = ast AST::String, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 421) +module_eval(<<'.,.,', 'grammar.ra', 373) def _reduce_118(val, _values, result) result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 423) +module_eval(<<'.,.,', 'grammar.ra', 375) def _reduce_119(val, _values, result) result = [val[0]] + val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 425) +module_eval(<<'.,.,', 'grammar.ra', 377) def _reduce_120(val, _values, result) result = [ast(AST::String,val[0])] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 426) +module_eval(<<'.,.,', 'grammar.ra', 378) def _reduce_121(val, _values, result) result = [ast(AST::String,val[0])] + val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 429) +module_eval(<<'.,.,', 'grammar.ra', 381) def _reduce_122(val, _values, result) result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 433) +module_eval(<<'.,.,', 'grammar.ra', 385) def _reduce_123(val, _values, result) Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 436) +module_eval(<<'.,.,', 'grammar.ra', 388) def _reduce_124(val, _values, result) result = ast AST::ResourceReference, :type => val[0], :title => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 440) +module_eval(<<'.,.,', 'grammar.ra', 392) def _reduce_125(val, _values, result) result = val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 444) +module_eval(<<'.,.,', 'grammar.ra', 396) def _reduce_126(val, _values, result) @lexer.commentpop args = { :test => val[0], :statements => val[2] } args[:else] = val[4] if val[4] result = ast AST::IfStatement, args result end .,., -module_eval(<<'.,.,', 'grammar.ra', 455) +module_eval(<<'.,.,', 'grammar.ra', 407) def _reduce_127(val, _values, result) @lexer.commentpop args = { :test => val[0], :statements => ast(AST::Nop) } args[:else] = val[3] if val[3] result = ast AST::IfStatement, args result end .,., # reduce 128 omitted -module_eval(<<'.,.,', 'grammar.ra', 468) +module_eval(<<'.,.,', 'grammar.ra', 420) def _reduce_129(val, _values, result) result = ast AST::Else, :statements => val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 471) +module_eval(<<'.,.,', 'grammar.ra', 423) def _reduce_130(val, _values, result) @lexer.commentpop result = ast AST::Else, :statements => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 475) +module_eval(<<'.,.,', 'grammar.ra', 427) def _reduce_131(val, _values, result) @lexer.commentpop result = ast AST::Else, :statements => ast(AST::Nop) result end .,., # reduce 132 omitted -module_eval(<<'.,.,', 'grammar.ra', 493) +module_eval(<<'.,.,', 'grammar.ra', 445) def _reduce_133(val, _values, result) result = ast AST::InOperator, :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 496) +module_eval(<<'.,.,', 'grammar.ra', 448) def _reduce_134(val, _values, result) result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 499) +module_eval(<<'.,.,', 'grammar.ra', 451) def _reduce_135(val, _values, result) result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 502) +module_eval(<<'.,.,', 'grammar.ra', 454) def _reduce_136(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 505) +module_eval(<<'.,.,', 'grammar.ra', 457) def _reduce_137(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 508) +module_eval(<<'.,.,', 'grammar.ra', 460) def _reduce_138(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 511) +module_eval(<<'.,.,', 'grammar.ra', 463) def _reduce_139(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 514) +module_eval(<<'.,.,', 'grammar.ra', 466) def _reduce_140(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 517) +module_eval(<<'.,.,', 'grammar.ra', 469) def _reduce_141(val, _values, result) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 520) +module_eval(<<'.,.,', 'grammar.ra', 472) def _reduce_142(val, _values, result) result = ast AST::Minus, :value => val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 523) +module_eval(<<'.,.,', 'grammar.ra', 475) def _reduce_143(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 526) +module_eval(<<'.,.,', 'grammar.ra', 478) def _reduce_144(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 529) +module_eval(<<'.,.,', 'grammar.ra', 481) def _reduce_145(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 532) +module_eval(<<'.,.,', 'grammar.ra', 484) def _reduce_146(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 535) +module_eval(<<'.,.,', 'grammar.ra', 487) def _reduce_147(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 538) +module_eval(<<'.,.,', 'grammar.ra', 490) def _reduce_148(val, _values, result) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 541) +module_eval(<<'.,.,', 'grammar.ra', 493) def _reduce_149(val, _values, result) result = ast AST::Not, :value => val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 544) +module_eval(<<'.,.,', 'grammar.ra', 496) def _reduce_150(val, _values, result) result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 547) +module_eval(<<'.,.,', 'grammar.ra', 499) def _reduce_151(val, _values, result) result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 550) +module_eval(<<'.,.,', 'grammar.ra', 502) def _reduce_152(val, _values, result) result = val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 554) +module_eval(<<'.,.,', 'grammar.ra', 506) def _reduce_153(val, _values, result) @lexer.commentpop - options = val[3] - options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) - result = ast AST::CaseStatement, :test => val[1], :options => options + result = ast AST::CaseStatement, :test => val[1], :options => val[3] result end .,., -# reduce 154 omitted +module_eval(<<'.,.,', 'grammar.ra', 510) + def _reduce_154(val, _values, result) + result = aryfy(val[0]) + result + end +.,., -module_eval(<<'.,.,', 'grammar.ra', 562) +module_eval(<<'.,.,', 'grammar.ra', 512) def _reduce_155(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - val[0].push val[1] + val[0].push val[1] result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 571) +module_eval(<<'.,.,', 'grammar.ra', 517) def _reduce_156(val, _values, result) @lexer.commentpop result = ast AST::CaseOpt, :value => val[0], :statements => val[3] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 574) +module_eval(<<'.,.,', 'grammar.ra', 520) def _reduce_157(val, _values, result) @lexer.commentpop result = ast( AST::CaseOpt, :value => val[0], :statements => ast(AST::ASTArray) ) result end .,., -# reduce 158 omitted +module_eval(<<'.,.,', 'grammar.ra', 530) + def _reduce_158(val, _values, result) + result = aryfy(val[0]) + result + end +.,., -module_eval(<<'.,.,', 'grammar.ra', 586) +module_eval(<<'.,.,', 'grammar.ra', 532) def _reduce_159(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) + val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 595) +module_eval(<<'.,.,', 'grammar.ra', 537) def _reduce_160(val, _values, result) result = ast AST::Selector, :param => val[0], :values => val[2] result end .,., # reduce 161 omitted -module_eval(<<'.,.,', 'grammar.ra', 600) +module_eval(<<'.,.,', 'grammar.ra', 542) def _reduce_162(val, _values, result) @lexer.commentpop result = val[1] result end .,., # reduce 163 omitted -module_eval(<<'.,.,', 'grammar.ra', 606) +module_eval(<<'.,.,', 'grammar.ra', 548) def _reduce_164(val, _values, result) if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] else result = ast AST::ASTArray, :children => [val[0],val[2]] end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 615) +module_eval(<<'.,.,', 'grammar.ra', 557) def _reduce_165(val, _values, result) result = ast AST::ResourceParam, :param => val[0], :value => val[2] result end .,., # reduce 166 omitted # reduce 167 omitted # reduce 168 omitted # reduce 169 omitted # reduce 170 omitted # reduce 171 omitted # reduce 172 omitted -module_eval(<<'.,.,', 'grammar.ra', 626) +module_eval(<<'.,.,', 'grammar.ra', 568) def _reduce_173(val, _values, result) result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] result end .,., # reduce 174 omitted -module_eval(<<'.,.,', 'grammar.ra', 631) +module_eval(<<'.,.,', 'grammar.ra', 573) def _reduce_175(val, _values, result) result = [val[0][:value]] result end .,., # reduce 176 omitted -module_eval(<<'.,.,', 'grammar.ra', 633) +module_eval(<<'.,.,', 'grammar.ra', 575) def _reduce_177(val, _values, result) result = val[0] += val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 636) +module_eval(<<'.,.,', 'grammar.ra', 578) def _reduce_178(val, _values, result) val[1].each do |file| import(file) end - result = AST::ASTArray.new(:children => []) + result = nil result end .,., -module_eval(<<'.,.,', 'grammar.ra', 646) +module_eval(<<'.,.,', 'grammar.ra', 588) def _reduce_179(val, _values, result) @lexer.commentpop result = Puppet::Parser::AST::Definition.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :code => val[4], :line => val[0][:line])) @lexer.indefine = false #} | DEFINE NAME argumentlist parent LBRACE RBRACE { result end .,., -module_eval(<<'.,.,', 'grammar.ra', 654) +module_eval(<<'.,.,', 'grammar.ra', 596) def _reduce_180(val, _values, result) @lexer.commentpop result = Puppet::Parser::AST::Definition.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) @lexer.indefine = false result end .,., -module_eval(<<'.,.,', 'grammar.ra', 662) +module_eval(<<'.,.,', 'grammar.ra', 604) def _reduce_181(val, _values, result) @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop val[5].is_a_namespace = true result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line])) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 670) +module_eval(<<'.,.,', 'grammar.ra', 612) def _reduce_182(val, _values, result) @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), ast_context(true).merge(:arguments => val[2], :parent => val[3], :line => val[0][:line])) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 679) +module_eval(<<'.,.,', 'grammar.ra', 621) def _reduce_183(val, _values, result) @lexer.commentpop result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :code => val[4], :line => val[0][:line])) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 684) +module_eval(<<'.,.,', 'grammar.ra', 626) def _reduce_184(val, _values, result) @lexer.commentpop result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) result end .,., -module_eval(<<'.,.,', 'grammar.ra', 688) +module_eval(<<'.,.,', 'grammar.ra', 630) def _reduce_185(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 690) +module_eval(<<'.,.,', 'grammar.ra', 632) def _reduce_186(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 691) +module_eval(<<'.,.,', 'grammar.ra', 633) def _reduce_187(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 692) +module_eval(<<'.,.,', 'grammar.ra', 634) def _reduce_188(val, _values, result) result = "class" result end .,., -module_eval(<<'.,.,', 'grammar.ra', 697) +module_eval(<<'.,.,', 'grammar.ra', 639) def _reduce_189(val, _values, result) result = [result] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 700) +module_eval(<<'.,.,', 'grammar.ra', 642) def _reduce_190(val, _values, result) result = val[0] result << val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 705) +module_eval(<<'.,.,', 'grammar.ra', 647) def _reduce_191(val, _values, result) result = ast AST::HostName, :value => val[0] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 708) +module_eval(<<'.,.,', 'grammar.ra', 650) def _reduce_192(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 709) +module_eval(<<'.,.,', 'grammar.ra', 651) def _reduce_193(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 710) +module_eval(<<'.,.,', 'grammar.ra', 652) def _reduce_194(val, _values, result) result = val[0][:value] result end .,., # reduce 195 omitted -module_eval(<<'.,.,', 'grammar.ra', 714) +module_eval(<<'.,.,', 'grammar.ra', 656) def _reduce_196(val, _values, result) result = nil result end .,., -module_eval(<<'.,.,', 'grammar.ra', 718) +module_eval(<<'.,.,', 'grammar.ra', 660) def _reduce_197(val, _values, result) result = ast AST::ASTArray, :children => [] result end .,., # reduce 198 omitted -module_eval(<<'.,.,', 'grammar.ra', 723) +module_eval(<<'.,.,', 'grammar.ra', 665) def _reduce_199(val, _values, result) result = nil result end .,., -module_eval(<<'.,.,', 'grammar.ra', 726) +module_eval(<<'.,.,', 'grammar.ra', 668) def _reduce_200(val, _values, result) result = val[1] result = [result] unless result[0].is_a?(Array) result end .,., # reduce 201 omitted -module_eval(<<'.,.,', 'grammar.ra', 732) +module_eval(<<'.,.,', 'grammar.ra', 674) def _reduce_202(val, _values, result) result = val[0] result = [result] unless result[0].is_a?(Array) result << val[2] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 738) +module_eval(<<'.,.,', 'grammar.ra', 680) def _reduce_203(val, _values, result) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value], val[2]] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 742) +module_eval(<<'.,.,', 'grammar.ra', 684) def _reduce_204(val, _values, result) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value]] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 745) +module_eval(<<'.,.,', 'grammar.ra', 687) def _reduce_205(val, _values, result) result = [val[0][:value], val[2]] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 747) +module_eval(<<'.,.,', 'grammar.ra', 689) def _reduce_206(val, _values, result) result = [val[0][:value]] result end .,., # reduce 207 omitted -module_eval(<<'.,.,', 'grammar.ra', 752) +module_eval(<<'.,.,', 'grammar.ra', 694) def _reduce_208(val, _values, result) result = val[1] result end .,., # reduce 209 omitted -module_eval(<<'.,.,', 'grammar.ra', 757) +module_eval(<<'.,.,', 'grammar.ra', 699) def _reduce_210(val, _values, result) result = val[1] result end .,., # reduce 211 omitted # reduce 212 omitted -module_eval(<<'.,.,', 'grammar.ra', 763) +module_eval(<<'.,.,', 'grammar.ra', 705) def _reduce_213(val, _values, result) result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 767) +module_eval(<<'.,.,', 'grammar.ra', 708) def _reduce_214(val, _values, result) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end - + result = val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 774) +module_eval(<<'.,.,', 'grammar.ra', 709) def _reduce_215(val, _values, result) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end - + result = val[1] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 780) +module_eval(<<'.,.,', 'grammar.ra', 710) def _reduce_216(val, _values, result) - result = ast AST::ASTArray - + result = ast AST::ASTArray result end .,., # reduce 217 omitted # reduce 218 omitted # reduce 219 omitted -module_eval(<<'.,.,', 'grammar.ra', 787) +module_eval(<<'.,.,', 'grammar.ra', 716) def _reduce_220(val, _values, result) result = nil result end .,., -module_eval(<<'.,.,', 'grammar.ra', 790) +module_eval(<<'.,.,', 'grammar.ra', 719) def _reduce_221(val, _values, result) result = ast AST::Regex, :value => val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 794) +module_eval(<<'.,.,', 'grammar.ra', 723) def _reduce_222(val, _values, result) if val[1].instance_of?(AST::ASTHash) result = val[1] else result = ast AST::ASTHash, { :value => val[1] } end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 801) +module_eval(<<'.,.,', 'grammar.ra', 730) def _reduce_223(val, _values, result) if val[1].instance_of?(AST::ASTHash) result = val[1] else result = ast AST::ASTHash, { :value => val[1] } end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 807) +module_eval(<<'.,.,', 'grammar.ra', 736) def _reduce_224(val, _values, result) result = ast AST::ASTHash result end .,., # reduce 225 omitted -module_eval(<<'.,.,', 'grammar.ra', 812) +module_eval(<<'.,.,', 'grammar.ra', 741) def _reduce_226(val, _values, result) if val[0].instance_of?(AST::ASTHash) result = val[0].merge(val[2]) else result = ast AST::ASTHash, :value => val[0] result.merge(val[2]) end result end .,., -module_eval(<<'.,.,', 'grammar.ra', 821) +module_eval(<<'.,.,', 'grammar.ra', 750) def _reduce_227(val, _values, result) result = ast AST::ASTHash, { :value => { val[0] => val[2] } } result end .,., -module_eval(<<'.,.,', 'grammar.ra', 824) +module_eval(<<'.,.,', 'grammar.ra', 753) def _reduce_228(val, _values, result) result = val[0][:value] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 825) +module_eval(<<'.,.,', 'grammar.ra', 754) def _reduce_229(val, _values, result) result = val[0] result end .,., -module_eval(<<'.,.,', 'grammar.ra', 828) +module_eval(<<'.,.,', 'grammar.ra', 757) def _reduce_230(val, _values, result) result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] result end .,., # reduce 231 omitted -module_eval(<<'.,.,', 'grammar.ra', 833) +module_eval(<<'.,.,', 'grammar.ra', 762) def _reduce_232(val, _values, result) result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] result end .,., def _reduce_none(val, _values, result) val[0] end end # class Parser end # module Parser end # module Puppet diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index 859897a16..1c4947891 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -1,216 +1,207 @@ # I pulled this into a separate file, because I got # tired of rebuilding the parser.rb file all the time. class Puppet::Parser::Parser require 'puppet/parser/functions' require 'puppet/parser/files' require 'puppet/resource/type_collection' require 'puppet/resource/type_collection_helper' require 'puppet/resource/type' require 'monitor' AST = Puppet::Parser::AST include Puppet::Resource::TypeCollectionHelper attr_reader :version, :environment attr_accessor :files attr_accessor :lexer # Add context to a message; useful for error messages and such. def addcontext(message, obj = nil) obj ||= @lexer message += " on line #{obj.line}" if file = obj.file message += " in file #{file}" end message end - # Create an AST array out of all of the args - def aryfy(*args) - if args[0].instance_of?(AST::ASTArray) - result = args.shift - args.each { |arg| - result.push arg - } - else - result = ast AST::ASTArray, :children => args - end - - result + # Create an AST array containing a single element + def aryfy(arg) + ast AST::ASTArray, :children => [arg] end # Create an AST object, and automatically add the file and line information if # available. def ast(klass, hash = {}) klass.new ast_context(klass.use_docs).merge(hash) end def ast_context(include_docs = false) result = { :line => lexer.line, :file => lexer.file } result[:doc] = lexer.getcomment(result[:line]) if include_docs result end # The fully qualifed name, with the full namespace. def classname(name) [@lexer.namespace, name].join("::").sub(/^::/, '') end def clear initvars end # Raise a Parse error. def error(message) if brace = @lexer.expected message += "; expected '%s'" end except = Puppet::ParseError.new(message) except.line = @lexer.line except.file = @lexer.file if @lexer.file raise except end def file @lexer.file end def file=(file) unless FileTest.exist?(file) unless file =~ /\.pp$/ file = file + ".pp" end raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file) end raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file) watch_file(file) @lexer.file = file end [:hostclass, :definition, :node, :nodes?].each do |method| define_method(method) do |*args| known_resource_types.send(method, *args) end end def find_hostclass(namespace, name) known_resource_types.find_hostclass(namespace, name) end def find_definition(namespace, name) known_resource_types.find_definition(namespace, name) end def import(file) known_resource_types.loader.import_if_possible(file, @lexer.file) end def initialize(env) # The environment is needed to know how to find the resource type collection. @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env initvars end # Initialize or reset all of our variables. def initvars @lexer = Puppet::Parser::Lexer.new end # Split an fq name into a namespace and name def namesplit(fullname) ary = fullname.split("::") n = ary.pop || "" ns = ary.join("::") return ns, n end def on_error(token,value,stack) if token == 0 # denotes end of file value = 'end of file' else value = "'#{value[:value]}'" end error = "Syntax error at #{value}" if brace = @lexer.expected error += "; expected '#{brace}'" end except = Puppet::ParseError.new(error) except.line = @lexer.line except.file = @lexer.file if @lexer.file raise except end # how should I do error handling here? def parse(string = nil) if self.file =~ /\.rb$/ parse_ruby_file main = nil else self.string = string if string begin @yydebug = false main = yyparse(@lexer,:scan) rescue Racc::ParseError => except error = Puppet::ParseError.new(except) error.line = @lexer.line error.file = @lexer.file error.set_backtrace except.backtrace raise error rescue Puppet::ParseError => except except.line ||= @lexer.line except.file ||= @lexer.file raise except rescue Puppet::Error => except # and this is a framework error except.line ||= @lexer.line except.file ||= @lexer.file raise except rescue Puppet::DevError => except except.line ||= @lexer.line except.file ||= @lexer.file raise except rescue => except error = Puppet::DevError.new(except.message) error.line = @lexer.line error.file = @lexer.file error.set_backtrace except.backtrace raise error end end # Store the results as the top-level class. return Puppet::Parser::AST::Hostclass.new('', :code => main) ensure @lexer.clear end def parse_ruby_file require self.file end def string=(string) @lexer.string = string end def version known_resource_types.version end # Add a new file to be checked when we're checking to see if we should be # reparsed. This is basically only used by the TemplateWrapper to let the # parser know about templates that should be parsed. def watch_file(filename) known_resource_types.watch_file(filename) end end diff --git a/spec/unit/parser/ast/astarray_spec.rb b/spec/unit/parser/ast/astarray_spec.rb index f79d6c533..8794848b6 100755 --- a/spec/unit/parser/ast/astarray_spec.rb +++ b/spec/unit/parser/ast/astarray_spec.rb @@ -1,72 +1,55 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::ASTArray do before :each do @scope = Puppet::Parser::Scope.new end it "should have a [] accessor" do array = Puppet::Parser::AST::ASTArray.new :children => [] array.should respond_to(:[]) end it "should evaluate all its children" do item1 = stub "item1", :is_a? => true item2 = stub "item2", :is_a? => true item1.expects(:safeevaluate).with(@scope).returns(123) item2.expects(:safeevaluate).with(@scope).returns(246) operator = Puppet::Parser::AST::ASTArray.new :children => [item1,item2] operator.evaluate(@scope) end - it "should evaluate childrens of type ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields(item1) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] - end - - it "should flatten children coming from children ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] + it "should not flatten children coming from children ASTArray" do + item = Puppet::Parser::AST::String.new :value => 'foo' + inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] + operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] end it "should not flatten the results of children evaluation" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns([123]) + item = Puppet::Parser::AST::String.new :value => 'foo' + item.stubs(:evaluate).returns(['foo']) + operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator.evaluate(@scope).should == [['foo'], ['foo']] + end - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [[123]] + it "should discard nil results from children evaluation" do + item1 = Puppet::Parser::AST::String.new :value => 'foo' + item2 = Puppet::Parser::AST::String.new :value => 'foo' + item2.stubs(:evaluate).returns(nil) + operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] + operator.evaluate(@scope).should == ['foo'] end it "should return a valid string with to_s" do a = stub 'a', :is_a? => true, :to_s => "a" b = stub 'b', :is_a? => true, :to_s => "b" array = Puppet::Parser::AST::ASTArray.new :children => [a,b] array.to_s.should == "[a, b]" end end diff --git a/spec/unit/parser/ast/resource_spec.rb b/spec/unit/parser/ast/resource_spec.rb index 6dbfc1f04..a8e783256 100755 --- a/spec/unit/parser/ast/resource_spec.rb +++ b/spec/unit/parser/ast/resource_spec.rb @@ -1,127 +1,138 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::Resource do ast = Puppet::Parser::AST before :each do @title = Puppet::Parser::AST::String.new(:value => "mytitle") @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) - @resource = ast::Resource.new(:title => @title, :type => "file", :parameters => ast::ASTArray.new(:children => []) ) + @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) + @resource = ast::Resource.new(:type => "file", :instances => ast::ASTArray.new(:children => [@instance])) @resource.stubs(:qualified_type).returns("Resource") end it "should evaluate all its parameters" do param = stub 'param' param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) - @resource.stubs(:parameters).returns [param] + @instance.stubs(:parameters).returns [param] @resource.evaluate(@scope) end it "should evaluate its title" do @resource.evaluate(@scope)[0].title.should == "mytitle" end it "should flatten the titles array" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") end it "should create and return one resource objects per title" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") end + it "should implicitly iterate over instances" do + new_title = Puppet::Parser::AST::String.new(:value => "other_title") + new_instance = ast::ResourceInstance.new(:title => new_title, :parameters => ast::ASTArray.new(:children => [])) + @resource.instances.push(new_instance) + @resource.evaluate(@scope).collect { |r| r.title }.should == ["mytitle", "other_title"] + end + it "should handover resources to the compiler" do titles = [] %w{one two}.each do |title| titles << Puppet::Parser::AST::String.new(:value => title) end array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope) result.each do |res| @compiler.catalog.resource(res.ref).should be_instance_of(Puppet::Parser::Resource) end end it "should generate virtual resources if it is virtual" do @resource.virtual = true result = @resource.evaluate(@scope) result[0].should be_virtual end it "should generate virtual and exported resources if it is exported" do @resource.exported = true result = @resource.evaluate(@scope) result[0].should be_virtual result[0].should be_exported end # Related to #806, make sure resources always look up the full path to the resource. describe "when generating qualified resources" do before do @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) ["one", "one::two", "three"].each do |name| @parser.environment.known_resource_types.add(Puppet::Resource::Type.new(:definition, name, {})) end @twoscope = @scope.newscope(:namespace => "one") @twoscope.resource = @scope.resource end def resource(type, params = nil) params ||= Puppet::Parser::AST::ASTArray.new(:children => []) - Puppet::Parser::AST::Resource.new(:type => type, :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + instance = Puppet::Parser::AST::ResourceInstance.new( + :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + Puppet::Parser::AST::Resource.new(:type => type, + :instances => Puppet::Parser::AST::ASTArray.new(:children => [instance])) end it "should be able to generate resources with fully qualified type information" do resource("two").evaluate(@twoscope)[0].type.should == "One::Two" end it "should be able to generate resources with unqualified type information" do resource("one").evaluate(@twoscope)[0].type.should == "One" end it "should correctly generate resources that can look up builtin types" do resource("file").evaluate(@twoscope)[0].type.should == "File" end it "should correctly generate resources that can look up defined classes by title" do @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) res = resource("class").evaluate(@twoscope)[0] res.type.should == "Class" res.title.should == "Myresource" end it "should fail for resource types that do not exist" do lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) end end end diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 0a61e73de..bf4ef0cf1 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -1,422 +1,421 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Parser do ast = Puppet::Parser::AST before :each do @known_resource_types = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @known_resource_types @true_ast = Puppet::Parser::AST::Boolean.new :value => true end it "should require an environment at initialization" do lambda { Puppet::Parser::Parser.new }.should raise_error(ArgumentError) end it "should set the environment" do env = Puppet::Node::Environment.new Puppet::Parser::Parser.new(env).environment.should == env end it "should convert the environment into an environment instance if a string is provided" do env = Puppet::Node::Environment.new("testing") Puppet::Parser::Parser.new("testing").environment.should == env end it "should be able to look up the environment-specific resource type collection" do rtc = Puppet::Node::Environment.new("development").known_resource_types parser = Puppet::Parser::Parser.new "development" parser.known_resource_types.should equal(rtc) end it "should delegate importing to the known resource type loader" do parser = Puppet::Parser::Parser.new "development" parser.known_resource_types.loader.expects(:import).with("newfile", "current_file") parser.lexer.expects(:file).returns "current_file" parser.import("newfile") end describe "when parsing files" do before do FileTest.stubs(:exist?).returns true File.stubs(:read).returns "" @parser.stubs(:watch_file) end it "should treat files ending in 'rb' as ruby files" do @parser.expects(:parse_ruby_file) @parser.file = "/my/file.rb" @parser.parse end describe "in ruby" do it "should use the ruby interpreter to load the file" do @parser.file = "/my/file.rb" @parser.expects(:require).with "/my/file.rb" @parser.parse_ruby_file end end end describe "when parsing append operator" do it "should not raise syntax errors" do lambda { @parser.parse("$var += something") }.should_not raise_error end it "shouldraise syntax error on incomplete syntax " do lambda { @parser.parse("$var += ") }.should raise_error end it "should create ast::VarDef with append=true" do vardef = @parser.parse("$var += 2").code[0] vardef.should be_a(Puppet::Parser::AST::VarDef) vardef.append.should == true end it "should work with arrays too" do vardef = @parser.parse("$var += ['test']").code[0] vardef.should be_a(Puppet::Parser::AST::VarDef) vardef.append.should == true end end describe "when parsing 'if'" do it "not, it should create the correct ast objects" do ast::Not.expects(:new).with { |h| h[:value].is_a?(ast::Boolean) } @parser.parse("if ! true { $var = 1 }") end it "boolean operation, it should create the correct ast objects" do ast::BooleanOperator.expects(:new).with { |h| h[:rval].is_a?(ast::Boolean) and h[:lval].is_a?(ast::Boolean) and h[:operator]=="or" } @parser.parse("if true or true { $var = 1 }") end it "comparison operation, it should create the correct ast objects" do ast::ComparisonOperator.expects(:new).with { |h| h[:lval].is_a?(ast::Name) and h[:rval].is_a?(ast::Name) and h[:operator]=="<" } @parser.parse("if 1 < 2 { $var = 1 }") end end describe "when parsing if complex expressions" do it "should create a correct ast tree" do aststub = stub_everything 'ast' ast::ComparisonOperator.expects(:new).with { |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]==">" }.returns(aststub) ast::ComparisonOperator.expects(:new).with { |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]=="==" }.returns(aststub) ast::BooleanOperator.expects(:new).with { |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" } @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") end it "should raise an error on incorrect expression" do lambda { @parser.parse("if (1 > 2 > ) or (1 == 2) { $var = 1 }") }.should raise_error end end describe "when parsing resource references" do it "should not raise syntax errors" do lambda { @parser.parse('exec { test: param => File["a"] }') }.should_not raise_error end it "should not raise syntax errors with multiple references" do lambda { @parser.parse('exec { test: param => File["a","b"] }') }.should_not raise_error end it "should create an ast::ResourceReference" do - ast::Resource.stubs(:new) ast::ResourceReference.expects(:new).with { |arg| arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) } @parser.parse('exec { test: command => File["a","b"] }') end end describe "when parsing resource overrides" do it "should not raise syntax errors" do lambda { @parser.parse('Resource["title"] { param => value }') }.should_not raise_error end it "should not raise syntax errors with multiple overrides" do lambda { @parser.parse('Resource["title1","title2"] { param => value }') }.should_not raise_error end it "should create an ast::ResourceOverride" do #ast::ResourceOverride.expects(:new).with { |arg| # arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) #} ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] ro.should be_a(ast::ResourceOverride) ro.line.should == 1 ro.object.should be_a(ast::ResourceReference) ro.parameters[0].should be_a(ast::ResourceParam) end end describe "when parsing if statements" do it "should not raise errors with empty if" do lambda { @parser.parse("if true { }") }.should_not raise_error end it "should not raise errors with empty else" do lambda { @parser.parse("if false { notice('if') } else { }") }.should_not raise_error end it "should not raise errors with empty if and else" do lambda { @parser.parse("if false { } else { }") }.should_not raise_error end it "should create a nop node for empty branch" do ast::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do ast::Nop.expects(:new) @parser.parse("if true { notice('test') } else { }") end it "should build a chain of 'ifs' if there's an 'elsif'" do ast = @parser.parse(<<-PP) if true { notice('test') } elsif true {} else { } PP end end describe "when parsing function calls" do it "should not raise errors with no arguments" do lambda { @parser.parse("tag()") }.should_not raise_error end it "should not raise errors with rvalue function with no args" do lambda { @parser.parse("$a = template()") }.should_not raise_error end it "should not raise errors with arguments" do lambda { @parser.parse("notice(1)") }.should_not raise_error end it "should not raise errors with multiple arguments" do lambda { @parser.parse("notice(1,2)") }.should_not raise_error end it "should not raise errors with multiple arguments and a trailing comma" do lambda { @parser.parse("notice(1,2,)") }.should_not raise_error end end describe "when parsing arrays with trailing comma" do it "should not raise errors with a trailing comma" do lambda { @parser.parse("$a = [1,2,]") }.should_not raise_error end end describe "when providing AST context" do before do @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" @parser.stubs(:lexer).returns @lexer end it "should include the lexer's line" do @parser.ast_context[:line].should == 50 end it "should include the lexer's file" do @parser.ast_context[:file].should == "/foo/bar" end it "should include the docs if directed to do so" do @parser.ast_context(true)[:doc].should == "whev" end it "should not include the docs when told not to" do @parser.ast_context(false)[:doc].should be_nil end it "should not include the docs by default" do @parser.ast_context[:doc].should be_nil end end describe "when building ast nodes" do before do @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" @parser.stubs(:lexer).returns @lexer @class = stub 'class', :use_docs => false end it "should return a new instance of the provided class created with the provided options" do @class.expects(:new).with { |opts| opts[:foo] == "bar" } @parser.ast(@class, :foo => "bar") end it "should merge the ast context into the provided options" do @class.expects(:new).with { |opts| opts[:file] == "/foo" } @parser.expects(:ast_context).returns :file => "/foo" @parser.ast(@class, :foo => "bar") end it "should prefer provided options over AST context" do @class.expects(:new).with { |opts| opts[:file] == "/bar" } @parser.expects(:ast_context).returns :file => "/foo" @parser.ast(@class, :file => "/bar") end it "should include docs when the AST class uses them" do @class.expects(:use_docs).returns true @class.stubs(:new) @parser.expects(:ast_context).with(true).returns({}) @parser.ast(@class, :file => "/bar") end end describe "when retrieving a specific node" do it "should delegate to the known_resource_types node" do @known_resource_types.expects(:node).with("node") @parser.node("node") end end describe "when retrieving a specific class" do it "should delegate to the loaded code" do @known_resource_types.expects(:hostclass).with("class") @parser.hostclass("class") end end describe "when retrieving a specific definitions" do it "should delegate to the loaded code" do @known_resource_types.expects(:definition).with("define") @parser.definition("define") end end describe "when determining the configuration version" do it "should determine it from the resource type collection" do @parser.known_resource_types.expects(:version).returns "foo" @parser.version.should == "foo" end end describe "when looking up definitions" do it "should use the known resource types to check for them by name" do @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:definition).returns(:this_value) @parser.find_definition("namespace","name").should == :this_value end end describe "when looking up hostclasses" do it "should use the known resource types to check for them by name" do @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:hostclass).returns(:this_value) @parser.find_hostclass("namespace","name").should == :this_value end end describe "when parsing classes" do before :each do @krt = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @krt end it "should not create new classes" do @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) @krt.hostclass("foobar").should be_nil end it "should correctly set the parent class when one is provided" do @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" end it "should correctly set the parent class for multiple classes at a time" do statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code statements[0].instantiate('')[0].parent.should == "yayness" statements[1].instantiate('')[0].parent.should == "bar" end it "should define the code when some is provided" do @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil end it "should define parameters when provided" do foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] foobar.arguments.should == {"biz" => nil, "baz" => nil} end end describe "when parsing resources" do before :each do @krt = Puppet::Resource::TypeCollection.new("development") @parser = Puppet::Parser::Parser.new "development" @parser.stubs(:known_resource_types).returns @krt end it "should be able to parse class resources" do @krt.add(Puppet::Resource::Type.new(:hostclass, "foobar", :arguments => {"biz" => nil})) lambda { @parser.parse("class { foobar: biz => stuff }") }.should_not raise_error end it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }").code[0][0].exported.should be_true + @parser.parse("@@file { '/file': }").code[0].exported.should be_true end it "should correctly mark virtual resources as virtual" do - @parser.parse("@file { '/file': }").code[0][0].virtual.should be_true + @parser.parse("@file { '/file': }").code[0].virtual.should be_true end end describe "when parsing nodes" do it "should be able to parse a node with a single name" do node = @parser.parse("node foo { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 1 node.names[0].value.should == "foo" end it "should be able to parse a node with two names" do node = @parser.parse("node foo, bar { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 2 node.names[0].value.should == "foo" node.names[1].value.should == "bar" end it "should be able to parse a node with three names" do node = @parser.parse("node foo, bar, baz { }").code[0] node.should be_a Puppet::Parser::AST::Node node.names.length.should == 3 node.names[0].value.should == "foo" node.names[1].value.should == "bar" node.names[2].value.should == "baz" end end end diff --git a/test/language/parser.rb b/test/language/parser.rb index 6599757f0..6f3d751c2 100755 --- a/test/language/parser.rb +++ b/test/language/parser.rb @@ -1,737 +1,739 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../lib/puppettest' require 'mocha' require 'puppet' require 'puppet/parser/parser' require 'puppettest' require 'puppettest/support/utils' class TestParser < Test::Unit::TestCase include PuppetTest include PuppetTest::ParserTesting include PuppetTest::Support::Utils def setup super Puppet[:parseonly] = true #@lexer = Puppet::Parser::Lexer.new end def teardown super Puppet::Node::Environment.clear end def test_each_file textfiles { |file| Puppet::Node::Environment.clear parser = mkparser Puppet.debug("parsing #{file}") if __FILE__ == $0 assert_nothing_raised { parser.file = file parser.parse } } end def test_failers failers { |file| parser = mkparser Puppet.debug("parsing failer #{file}") if __FILE__ == $0 assert_raise(Puppet::ParseError, Puppet::Error, "Did not fail while parsing #{file}") { Puppet[:manifest] = file config = mkcompiler(parser) config.compile #ast.hostclass("").evaluate config.topscope } } end def test_arrayrvalues parser = mkparser ret = nil file = tempfile assert_nothing_raised { parser.string = "file { \"#{file}\": mode => [755, 640] }" } assert_nothing_raised { ret = parser.parse } end def test_arrayrvalueswithtrailingcomma parser = mkparser ret = nil file = tempfile assert_nothing_raised { parser.string = "file { \"#{file}\": mode => [755, 640,] }" } assert_nothing_raised { ret = parser.parse } end def mkmanifest(file) name = File.join(tmpdir, "file#{rand(100)}") @@tmpfiles << name File.open(file, "w") { |f| f.puts "file { \"%s\": ensure => file, mode => 755 }\n" % name } end def test_importglobbing basedir = File.join(tmpdir, "importesting") @@tmpfiles << basedir Dir.mkdir(basedir) subdir = "subdir" Dir.mkdir(File.join(basedir, subdir)) manifest = File.join(basedir, "manifest") File.open(manifest, "w") { |f| f.puts "import \"%s/*\"" % subdir } 4.times { |i| path = File.join(basedir, subdir, "subfile#{i}.pp") mkmanifest(path) } assert_nothing_raised("Could not parse multiple files") { parser = mkparser parser.file = manifest parser.parse } end def test_nonexistent_import basedir = File.join(tmpdir, "importesting") @@tmpfiles << basedir Dir.mkdir(basedir) manifest = File.join(basedir, "manifest") File.open(manifest, "w") do |f| f.puts "import \" no such file \"" end assert_raise(Puppet::ParseError) { parser = mkparser parser.file = manifest parser.parse } end def test_trailingcomma path = tempfile str = %{file { "#{path}": ensure => file, } } parser = mkparser parser.string = str assert_nothing_raised("Could not parse trailing comma") { parser.parse } end def test_importedclasses imported = tempfile '.pp' importer = tempfile '.pp' made = tempfile File.open(imported, "w") do |f| f.puts %{class foo { file { "#{made}": ensure => file }}} end File.open(importer, "w") do |f| f.puts %{import "#{imported}"\ninclude foo} end parser = mkparser parser.file = importer # Make sure it parses fine assert_nothing_raised { parser.parse } # Now make sure it actually does the work assert_creates(importer, made) end # Make sure fully qualified and unqualified files can be imported def test_fqfilesandlocalfiles dir = tempfile Dir.mkdir(dir) importer = File.join(dir, "site.pp") fullfile = File.join(dir, "full.pp") localfile = File.join(dir, "local.pp") files = [] File.open(importer, "w") do |f| f.puts %{import "#{fullfile}"\ninclude full\nimport "local.pp"\ninclude local} end fullmaker = tempfile files << fullmaker File.open(fullfile, "w") do |f| f.puts %{class full { file { "#{fullmaker}": ensure => file }}} end localmaker = tempfile files << localmaker File.open(localfile, "w") do |f| f.puts %{class local { file { "#{localmaker}": ensure => file }}} end parser = mkparser parser.file = importer # Make sure it parses assert_nothing_raised { parser.parse } # Now make sure it actually does the work assert_creates(importer, *files) end # Make sure the parser adds '.pp' when necessary def test_addingpp dir = tempfile Dir.mkdir(dir) importer = File.join(dir, "site.pp") localfile = File.join(dir, "local.pp") files = [] File.open(importer, "w") do |f| f.puts %{import "local"\ninclude local} end file = tempfile files << file File.open(localfile, "w") do |f| f.puts %{class local { file { "#{file}": ensure => file }}} end parser = mkparser parser.file = importer assert_nothing_raised { parser.parse } end # Make sure that file importing changes file relative names. def test_changingrelativenames dir = tempfile Dir.mkdir(dir) Dir.mkdir(File.join(dir, "subdir")) top = File.join(dir, "site.pp") subone = File.join(dir, "subdir/subone") subtwo = File.join(dir, "subdir/subtwo") files = [] file = tempfile files << file File.open(subone + ".pp", "w") do |f| f.puts %{class one { file { "#{file}": ensure => file }}} end otherfile = tempfile files << otherfile File.open(subtwo + ".pp", "w") do |f| f.puts %{import "subone"\n class two inherits one { file { "#{otherfile}": ensure => file } }} end File.open(top, "w") do |f| f.puts %{import "subdir/subtwo"} end parser = mkparser parser.file = top assert_nothing_raised { parser.parse } end # Defaults are purely syntactical, so it doesn't make sense to be able to # collect them. def test_uncollectabledefaults string = "@Port { protocols => tcp }" assert_raise(Puppet::ParseError) { mkparser.parse(string) } end # Verify that we can parse collections def test_collecting text = "Port <| |>" parser = mkparser parser.string = text ret = nil assert_nothing_raised { ret = parser.parse } ret.code.each do |obj| assert_instance_of(AST::Collection, obj) end end def test_emptyfile file = tempfile File.open(file, "w") do |f| f.puts %{} end parser = mkparser parser.file = file assert_nothing_raised { parser.parse } end def test_multiple_nodes_named file = tempfile other = tempfile File.open(file, "w") do |f| f.puts %{ node nodeA, nodeB { file { "#{other}": ensure => file } } } end parser = mkparser parser.file = file ast = nil assert_nothing_raised { ast = parser.parse } end def test_emptyarrays str = %{$var = []\n} parser = mkparser parser.string = str # Make sure it parses fine assert_nothing_raised { parser.parse } end # Make sure function names aren't reserved words. def test_functionnamecollision str = %{tag yayness tag(rahness) file { "/tmp/yayness": tag => "rahness", ensure => exists } } parser = mkparser parser.string = str # Make sure it parses fine assert_nothing_raised { parser.parse } end def test_metaparams_in_definition_prototypes parser = mkparser assert_raise(Puppet::ParseError) { parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule) {}}), '') } assert_nothing_raised { parser.known_resource_types.import_ast(parser.parse(%{define adef($schedule = false) {}}), '') parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule = daily) {}}), '') } end def test_parsingif parser = mkparser exec = proc do |val| %{exec { "/bin/echo #{val}": logoutput => true }} end str1 = %{if true { #{exec.call("true")} }} ret = nil assert_nothing_raised { ret = parser.parse(str1).code[0] } assert_instance_of(Puppet::Parser::AST::IfStatement, ret) parser = mkparser str2 = %{if true { #{exec.call("true")} } else { #{exec.call("false")} }} ret = parser.parse(str2).code[0] assert_instance_of(Puppet::Parser::AST::IfStatement, ret) assert_instance_of(Puppet::Parser::AST::Else, ret.else) end def test_hostclass parser = mkparser assert_nothing_raised { parser.known_resource_types.import_ast(parser.parse(%{class myclass { class other {} }}), '') } assert(parser.hostclass("myclass"), "Could not find myclass") assert(parser.hostclass("myclass::other"), "Could not find myclass::other") assert_nothing_raised { parser.known_resource_types.import_ast(parser.parse("class base {} class container { class deep::sub inherits base {} }"), '') } sub = parser.hostclass("container::deep::sub") assert(sub, "Could not find sub") # Now try it with a parent class being a fq class assert_nothing_raised { parser.known_resource_types.import_ast(parser.parse("class container::one inherits container::deep::sub {}"), '') } sub = parser.hostclass("container::one") assert(sub, "Could not find one") assert_equal("container::deep::sub", sub.parent) # Finally, try including a qualified class assert_nothing_raised("Could not include fully qualified class") { parser.known_resource_types.import_ast(parser.parse("include container::deep::sub"), '') } end def test_topnamespace parser = mkparser # Make sure we put the top-level code into a class called "" in # the "" namespace parser.initvars assert_nothing_raised do parser.known_resource_types.import_ast(parser.parse("Exec { path => '/usr/bin:/usr/sbin' }"), '') assert_equal("", parser.known_resource_types.hostclass("").name) assert_equal("", parser.known_resource_types.hostclass("").namespace) end end # Make sure virtual and exported resources work appropriately. def test_virtualresources tests = [:virtual] if Puppet.features.rails? catalog_cache_class = Puppet::Resource::Catalog.indirection.cache_class facts_cache_class = Puppet::Node::Facts.indirection.cache_class node_cache_class = Puppet::Node.indirection.cache_class Puppet[:storeconfigs] = true tests << :exported end tests.each do |form| parser = mkparser if form == :virtual at = "@" else at = "@@" end check = proc do |res, msg| if res.is_a?(Puppet::Parser::Resource) txt = res.ref else txt = res.class end # Real resources get marked virtual when exported if form == :virtual or res.is_a?(Puppet::Parser::Resource) assert(res.virtual, "#{msg} #{at}#{txt} is not virtual") end if form == :virtual assert(! res.exported, "#{msg} #{at}#{txt} is exported") else assert(res.exported, "#{msg} #{at}#{txt} is not exported") end end ret = nil assert_nothing_raised do parser.known_resource_types.import_ast(parser.parse("#{at}file { '/tmp/testing': owner => root }"), '') ret = parser.known_resource_types end assert_instance_of(AST::ASTArray, ret.hostclass("").code) - resdef = ret.hostclass("").code[0][0] + resdef = ret.hostclass("").code[0] assert_instance_of(AST::Resource, resdef) - assert_equal("/tmp/testing", resdef.title.value) + assert_instance_of(AST::ASTArray, resdef.instances) + assert_equal(1, resdef.instances.children.length) + assert_equal("/tmp/testing", resdef.instances[0].title.value) # We always get an astarray back, so... check.call(resdef, "simple resource") # Now let's try it with multiple resources in the same spec assert_nothing_raised do parser.known_resource_types.import_ast(parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }"), '') ret = parser.known_resource_types end ret.hostclass("").code[0].each do |res| assert_instance_of(AST::Resource, res) check.call(res, "multiresource") end end ensure if Puppet.features.rails? Puppet[:storeconfigs] = false Puppet::Resource::Catalog.cache_class = catalog_cache_class Puppet::Node::Facts.cache_class = facts_cache_class Puppet::Node.cache_class = node_cache_class end end def test_collections tests = [:virtual] if Puppet.features.rails? catalog_cache_class = Puppet::Resource::Catalog.indirection.cache_class facts_cache_class = Puppet::Node::Facts.indirection.cache_class node_cache_class = Puppet::Node.indirection.cache_class Puppet[:storeconfigs] = true tests << :exported end tests.each do |form| Puppet::Node::Environment.clear parser = mkparser if form == :virtual arrow = "<||>" else arrow = "<<||>>" end ret = nil assert_nothing_raised do ret = parser.parse("File #{arrow}") end coll = ret.code[0] assert_instance_of(AST::Collection, coll) assert_equal(form, coll.form) end ensure if Puppet.features.rails? Puppet[:storeconfigs] = false Puppet::Resource::Catalog.cache_class = catalog_cache_class Puppet::Node::Facts.cache_class = facts_cache_class Puppet::Node.cache_class = node_cache_class end end def test_collectionexpressions %w{== !=}.each do |oper| Puppet::Node::Environment.clear str = "File <| title #{oper} '/tmp/testing' |>" parser = mkparser res = nil assert_nothing_raised do res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) query = res.query assert_instance_of(AST::CollExpr, query) assert_equal(:virtual, query.form) assert_equal("title", query.test1.value) assert_equal("/tmp/testing", query.test2.value) assert_equal(oper, query.oper) end end def test_collectionstatements %w{and or}.each do |joiner| str = "File <| title == '/tmp/testing' #{joiner} owner == root |>" parser = mkparser res = nil assert_nothing_raised do res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) query = res.query assert_instance_of(AST::CollExpr, query) assert_equal(joiner, query.oper) assert_instance_of(AST::CollExpr, query.test1) assert_instance_of(AST::CollExpr, query.test2) end end def test_collectionstatements_with_parens [ "(title == '/tmp/testing' and owner == root) or owner == wheel", "(title == '/tmp/testing')" ].each do |test| str = "File <| #{test} |>" parser = mkparser res = nil assert_nothing_raised("Could not parse '#{test}'") do res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) query = res.query assert_instance_of(AST::CollExpr, query) #assert_equal(joiner, query.oper) #assert_instance_of(AST::CollExpr, query.test1) #assert_instance_of(AST::CollExpr, query.test2) end end def test_fully_qualified_definitions parser = mkparser types = parser.known_resource_types assert_nothing_raised("Could not parse fully-qualified definition") { types.import_ast(parser.parse(%{define one::two { }}), '') } assert(parser.definition("one::two"), "Could not find one::two with no namespace") end # #524 def test_functions_with_no_arguments parser = mkparser assert_nothing_raised("Could not parse statement function with no args") { parser.parse %{tag()} } assert_nothing_raised("Could not parse rvalue function with no args") { parser.parse %{$testing = template()} } end # #774 def test_fully_qualified_collection_statement parser = mkparser assert_nothing_raised("Could not parse fully qualified collection statement") { parser.parse %{Foo::Bar <||>} } end def test_multiple_imports_on_one_line one = tempfile '.pp' two = tempfile '.pp' base = tempfile '.pp' File.open(one, "w") { |f| f.puts "$var = value" } File.open(two, "w") { |f| f.puts "$var = value" } File.open(base, "w") { |f| f.puts "import '#{one}', '#{two}'" } parser = mkparser parser.file = base # Importing is logged at debug time. Puppet::Util::Log.level = :debug assert_nothing_raised("Parser could not import multiple files at once") do parser.parse end [one, two].each do |file| assert(@logs.detect { |l| l.message =~ /importing '#{file}'/}, "did not import #{file}") end end def test_cannot_assign_qualified_variables parser = mkparser assert_raise(Puppet::ParseError, "successfully assigned a qualified variable") do parser.parse("$one::two = yay") end end # #629 - undef keyword def test_undef parser = mkparser result = nil assert_nothing_raised("Could not parse assignment to undef") { result = parser.parse %{$variable = undef} } main = result.code children = main.children assert_instance_of(AST::VarDef, main.children[0]) assert_instance_of(AST::Undef, main.children[0].value) end # Prompted by #729 -- parsing should not modify the interpreter. def test_parse parser = mkparser str = "file { '/tmp/yay': ensure => file }\nclass yay {}\nnode foo {}\ndefine bar {}\n" result = nil assert_nothing_raised("Could not parse") do parser.known_resource_types.import_ast(parser.parse(str), '') result = parser.known_resource_types end assert_instance_of(Puppet::Resource::TypeCollection, result, "Did not get a ASTSet back from parsing") assert_instance_of(Puppet::Resource::Type, result.hostclass("yay"), "Did not create 'yay' class") assert_instance_of(Puppet::Resource::Type, result.hostclass(""), "Did not create main class") assert_instance_of(Puppet::Resource::Type, result.definition("bar"), "Did not create 'bar' definition") assert_instance_of(Puppet::Resource::Type, result.node("foo"), "Did not create 'foo' node") end def test_namesplit parser = mkparser assert_nothing_raised do {"base::sub" => %w{base sub}, "main" => ["", "main"], "one::two::three::four" => ["one::two::three", "four"], }.each do |name, ary| result = parser.namesplit(name) assert_equal(ary, result, "#{name} split to #{result}") end end end # Make sure class, node, and define methods are case-insensitive def test_structure_case_insensitivity parser = mkparser result = nil assert_nothing_raised do parser.known_resource_types.import_ast(parser.parse("class yayness { }"), '') result = parser.known_resource_types.hostclass('yayness') end assert_equal(result, parser.find_hostclass("", "yayNess")) assert_nothing_raised do parser.known_resource_types.import_ast(parser.parse("define funtest { }"), '') result = parser.known_resource_types.definition('funtest') end assert_equal(result, parser.find_definition("", "fUntEst"), "#{"fUntEst"} was not matched") end end diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index bd04c1ec5..411bad37a 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -1,428 +1,425 @@ require 'puppettest' require 'puppet/rails' module PuppetTest::ParserTesting include PuppetTest AST = Puppet::Parser::AST Compiler = Puppet::Parser::Compiler # A fake class that we can use for testing evaluation. class FakeAST attr_writer :evaluate def evaluated? @evaluated end def evaluate(*args) @evaluated = true @evaluate end def initialize(val = nil) @evaluate = val if val end def reset @evaluated = nil end def safeevaluate(*args) evaluate end def evaluate_match(othervalue, scope, options={}) value = evaluate othervalue == value end end def astarray(*args) AST::ASTArray.new( :children => args ) end def mkcompiler(parser = nil) node = mknode Compiler.new(node) end def mknode(name = nil) require 'puppet/node' Puppet::Node.new(name || "nodename") end def mkparser Puppet::Node::Environment.clear Puppet::Parser::Parser.new(Puppet::Node::Environment.new) end def mkscope(hash = {}) parser ||= mkparser compiler ||= mkcompiler compiler.topscope.source = (parser.find_hostclass("", "") || parser.newclass("")) raise "Could not find source for scope" unless compiler.topscope.source # Make the 'main' stuff compiler.send(:evaluate_main) compiler.topscope end def classobj(name, hash = {}) hash[:file] ||= __FILE__ hash[:line] ||= __LINE__ hash[:type] ||= name AST::HostClass.new(hash) end def tagobj(*names) args = {} newnames = names.collect do |name| if name.is_a? AST name else nameobj(name) end end args[:type] = astarray(*newnames) assert_nothing_raised("Could not create tag #{names.inspect}") { return AST::Tag.new(args) } end def resourcedef(type, title, params) title = stringobj(title) unless title.is_a?(AST) + instance = AST::ResourceInstance.new(:title => title, :parameters => resourceparams(params)) assert_nothing_raised("Could not create #{type} #{title}") { return AST::Resource.new( :file => __FILE__, :line => __LINE__, - :title => title, :type => type, - - :parameters => resourceinst(params) + :instances => AST::ASTArray.new(:children => [instance]) ) } end def virt_resourcedef(*args) res = resourcedef(*args) res.virtual = true res end def resourceoverride(type, title, params) assert_nothing_raised("Could not create #{type} #{name}") { return AST::ResourceOverride.new( :file => __FILE__, :line => __LINE__, :object => resourceref(type, title), - - :type => type, - :parameters => resourceinst(params) + :parameters => resourceparams(params) ) } end def resourceref(type, title) assert_nothing_raised("Could not create #{type} #{title}") { return AST::ResourceReference.new( :file => __FILE__, :line => __LINE__, :type => type, :title => stringobj(title) ) } end def fileobj(path, hash = {"owner" => "root"}) assert_nothing_raised("Could not create file #{path}") { return resourcedef("file", path, hash) } end def nameobj(name) assert_nothing_raised("Could not create name #{name}") { return AST::Name.new( :file => tempfile, :line => rand(100), :value => name ) } end def typeobj(name) assert_nothing_raised("Could not create type #{name}") { return AST::Type.new( :file => tempfile, :line => rand(100), :value => name ) } end def nodedef(name) assert_nothing_raised("Could not create node #{name}") { return AST::NodeDef.new( :file => tempfile, :line => rand(100), :names => nameobj(name), :code => AST::ASTArray.new( :children => [ varobj("#{name}var", "#{name}value"), fileobj("/#{name}") ] ) ) } end - def resourceinst(hash) + def resourceparams(hash) assert_nothing_raised("Could not create resource instance") { params = hash.collect { |param, value| resourceparam(param, value) } - return AST::ResourceInstance.new( + return AST::ASTArray.new( :file => tempfile, :line => rand(100), :children => params ) } end def resourceparam(param, value) # Allow them to pass non-strings in value = stringobj(value) if value.is_a?(String) assert_nothing_raised("Could not create param #{param}") { return AST::ResourceParam.new( :file => tempfile, :line => rand(100), :param => param, :value => value ) } end def stringobj(value) AST::String.new( :file => tempfile, :line => rand(100), :value => value ) end def varobj(name, value) value = stringobj(value) unless value.is_a? AST assert_nothing_raised("Could not create #{name} code") { return AST::VarDef.new( :file => tempfile, :line => rand(100), :name => nameobj(name), :value => value ) } end def varref(name) assert_nothing_raised("Could not create #{name} variable") { return AST::Variable.new( :file => __FILE__, :line => __LINE__, :value => name ) } end def argobj(name, value) assert_nothing_raised("Could not create #{name} compargument") { return AST::CompArgument.new( :children => [nameobj(name), stringobj(value)] ) } end def defaultobj(type, params) pary = [] params.each { |p,v| pary << AST::ResourceParam.new( :file => __FILE__, :line => __LINE__, :param => p, :value => stringobj(v) ) } past = AST::ASTArray.new( :file => __FILE__, :line => __LINE__, :children => pary ) assert_nothing_raised("Could not create defaults for #{type}") { return AST::ResourceDefaults.new( :file => __FILE__, :line => __LINE__, :type => type, :parameters => past ) } end def taggedobj(name, ftype = :statement) functionobj("tagged", name, ftype) end def functionobj(function, name, ftype = :statement) func = nil assert_nothing_raised do func = Puppet::Parser::AST::Function.new( :name => function, :ftype => ftype, :arguments => AST::ASTArray.new( :children => [nameobj(name)] ) ) end func end # This assumes no nodes def assert_creates(manifest, *files) oldmanifest = Puppet[:manifest] Puppet[:manifest] = manifest catalog = Puppet::Parser::Compiler.new(mknode).compile.to_ral catalog.apply files.each do |file| assert(FileTest.exists?(file), "Did not create #{file}") end ensure Puppet[:manifest] = oldmanifest end def mk_transobject(file = "/etc/passwd") obj = nil assert_nothing_raised { obj = Puppet::TransObject.new("file", file) obj["owner"] = "root" obj["mode"] = "644" } obj end def mk_transbucket(*resources) bucket = nil assert_nothing_raised { bucket = Puppet::TransBucket.new bucket.name = "yayname" bucket.type = "yaytype" } resources.each { |o| bucket << o } bucket end # Make a tree of resources, yielding if desired def mk_transtree(depth = 4, width = 2) top = nil assert_nothing_raised { top = Puppet::TransBucket.new top.name = "top" top.type = "bucket" } bucket = top file = tempfile depth.times do |i| resources = [] width.times do |j| path = tempfile + i.to_s obj = Puppet::TransObject.new("file", path) obj["owner"] = "root" obj["mode"] = "644" # Yield, if they want yield(obj, i, j) if block_given? resources << obj end newbucket = mk_transbucket(*resources) bucket.push newbucket bucket = newbucket end top end # Take a list of AST resources, evaluate them, and return the results def assert_evaluate(children) top = nil assert_nothing_raised("Could not create top object") { top = AST::ASTArray.new( :children => children ) } trans = nil scope = nil assert_nothing_raised { scope = Puppet::Parser::Scope.new trans = scope.evaluate(:ast => top) } trans end end