diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 2a8f4d4c1..9a2dc286c 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -1,75 +1,75 @@ 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 # Return a child by index. Probably never used. def [](index) @children[index] end # Evaluate our children. def evaluate(hash) scope = hash[:scope] rets = nil # We basically always operate declaratively, and when we # do we need to evaluate the settor-like statements first. This # is basically variable and type-default declarations. # This is such a stupid hack. I've no real idea how to make a # "real" declarative language, so I hack it so it looks like # one, yay. settors = [] others = [] # 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| if ac.class.settor? settors << ac else others << ac end end else if child.class.settor? settors << child else others << child end end } rets = [settors, others].flatten.collect { |child| child.safeevaluate(:scope => scope) } return rets.reject { |o| o.nil? } 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) } return self 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 ResourceInst < ASTArray; end + class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/resourcedef.rb b/lib/puppet/parser/ast/resource.rb similarity index 96% rename from lib/puppet/parser/ast/resourcedef.rb rename to lib/puppet/parser/ast/resource.rb index a432268f1..c53ab0a68 100644 --- a/lib/puppet/parser/ast/resourcedef.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -1,75 +1,75 @@ -require 'puppet/parser/ast/resourceref' +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 ResourceDef < AST::ResourceRef +class Resource < AST::ResourceReference attr_accessor :title, :type, :exported, :virtual attr_reader :params # Does not actually return an object; instead sets an object # in the current scope. def evaluate(options) scope = options[:scope] # Evaluate all of the specified params. paramobjects = @params.collect { |param| param.safeevaluate(:scope => scope) } objtitles = @title.safeevaluate(:scope => scope) # it's easier to always use an array, even for only one name unless objtitles.is_a?(Array) objtitles = [objtitles] end objtype = qualified_type(scope) # 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. objtitles.collect { |objtitle| exceptwrap :type => Puppet::ParseError do exp = self.exported || scope.resource.exported? # 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 || scope.resource.virtual? || exp obj = Puppet::Parser::Resource.new( :type => objtype, :title => objtitle, :params => paramobjects, :file => self.file, :line => self.line, :exported => exp, :virtual => virt, :source => scope.source, :scope => scope ) # And then store the resource in the compile. # At some point, we need to switch all of this to return # objects instead of storing them like this. scope.compile.store_resource(scope, obj) obj end }.reject { |obj| obj.nil? } end # Set the parameters for our object. def params=(params) if params.is_a?(AST::ASTArray) @params = params else @params = AST::ASTArray.new( :line => params.line, :file => params.file, :children => [params] ) end end end end diff --git a/lib/puppet/parser/ast/resourcedefaults.rb b/lib/puppet/parser/ast/resource_defaults.rb similarity index 100% rename from lib/puppet/parser/ast/resourcedefaults.rb rename to lib/puppet/parser/ast/resource_defaults.rb diff --git a/lib/puppet/parser/ast/resourceoverride.rb b/lib/puppet/parser/ast/resource_override.rb similarity index 95% rename from lib/puppet/parser/ast/resourceoverride.rb rename to lib/puppet/parser/ast/resource_override.rb index 4232737fc..46c930902 100644 --- a/lib/puppet/parser/ast/resourceoverride.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -1,60 +1,60 @@ -require 'puppet/parser/ast/resourcedef' +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 < ResourceDef + class ResourceOverride < Resource attr_accessor :object attr_reader :params # Iterate across all of our children. def each [@object,@params].flatten.each { |param| #Puppet.debug("yielding param %s" % param) yield param } end # Does not actually return an object; instead sets an object # in the current scope. def evaluate(hash) scope = hash[:scope] # Get our object reference. object = @object.safeevaluate(:scope => scope) hash = {} # Evaluate all of the specified params. params = @params.collect { |param| param.safeevaluate(:scope => scope) } # Now we just create a normal resource, but we call a very different # method on the scope. obj = Puppet::Parser::Resource.new( :type => object.type, :title => object.title, :params => 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.compile.store_override(obj) obj 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/ast/resourceref.rb b/lib/puppet/parser/ast/resource_reference.rb similarity index 97% rename from lib/puppet/parser/ast/resourceref.rb rename to lib/puppet/parser/ast/resource_reference.rb index 02a19d88d..b8edff8f1 100644 --- a/lib/puppet/parser/ast/resourceref.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -1,66 +1,66 @@ require 'puppet/parser/ast/branch' class Puppet::Parser::AST # A reference to an object. Only valid as an rvalue. - class ResourceRef < AST::Branch + class ResourceReference < AST::Branch attr_accessor :title, :type # Is the type a builtin type? def builtintype?(type) if typeklass = Puppet::Type.type(type) return typeklass else return false end end def each [@type,@title].flatten.each { |param| #Puppet.debug("yielding param %s" % param) yield param } end # Evaluate our object, but just return a simple array of the type # and name. def evaluate(hash) scope = hash[:scope] title = @title.safeevaluate(:scope => scope) if @type == "class" objtype = @type title = qualified_class(scope, title) else objtype = qualified_type(scope) end return Puppet::Parser::Resource::Reference.new( :type => objtype, :title => title ) end # Look up a fully qualified class name. def qualified_class(scope, title) # Look up the full path to the class if classobj = scope.findclass(title) title = classobj.classname else raise Puppet::ParseError, "Could not find class %s" % title end end # Look up a fully-qualified type. This method is # also used in AST::Resource. def qualified_type(scope, title = nil) # We want a lower-case type. For some reason. objtype = @type.downcase unless builtintype?(objtype) if dtype = scope.finddefine(objtype) objtype = dtype.classname else raise Puppet::ParseError, "Could not find resource type %s" % objtype end end return objtype end end end diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index c7216186a..26cb42217 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -1,650 +1,650 @@ # vim: syntax=ruby # the parser class Puppet::Parser::Parser token LBRACK DQTEXT SQTEXT RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE token FALSE EQUALS LESSEQUAL NOTEQUAL DOT COLON TYPE 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 rule program: statements { if val[0] # Make sure we always return an array. if val[0].is_a?(AST::ASTArray) if val[0].children.empty? result = nil else result = val[0] end else result = aryfy(val[0]) end else result = nil end } | nil statements: statement | statements statement { if val[0] and val[1] 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 elsif obj = (val[0] || val[1]) result = obj else result = nil end } # The main list of valid statements statement: resource | virtualresource | collection | assignment | casestatement | ifstatement | import | fstatement | definition | hostclass | nodedef | resourceoverride fstatement: NAME LPAREN funcvalues RPAREN { args = aryfy(val[2]) result = ast AST::Function, :name => val[0], :arguments => args, :ftype => :statement } | NAME LPAREN RPAREN { result = ast AST::Function, :name => val[0], :arguments => AST::ASTArray.new({}), :ftype => :statement } | NAME funcvalues { args = aryfy(val[1]) result = ast AST::Function, :name => val[0], :arguments => args, :ftype => :statement } funcvalues: namestrings | resourcerefs namestrings: namestring | namestrings COMMA namestring { result = aryfy(val[0], val[2]) result.line = @lexer.line result.file = @lexer.file } # 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 | CLASSNAME { result = ast AST::Name, :value => val[0] } resourcerefs: resourceref | resourcerefs COMMA resourceref { unless val[0].is_a?(AST::ASTArray) val[0] = aryfy(val[0]) end val[0].push(val[2]) result = val[0] } resource: classname LBRACE resourceinstances endsemi RBRACE { array = val[2] - if array.instance_of?(AST::ResourceInst) + if array.instance_of?(AST::ResourceInstance) array = [array] end result = ast AST::ASTArray # this iterates across each specified resourceinstance array.each { |instance| - unless instance.instance_of?(AST::ResourceInst) + unless instance.instance_of?(AST::ResourceInstance) raise Puppet::Dev, "Got something that isn't an instance" end # now, i need to somehow differentiate between those things with # arrays in their names, and normal things - result.push ast(AST::ResourceDef, + result.push ast(AST::Resource, :type => val[0], :title => instance[0], :params => instance[1]) } } | 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 result = ast(AST::ResourceDefaults, :type => val[0], :params => val[2]) } # Override a value set elsewhere in the configuration. resourceoverride: resourceref LBRACE anyparams endcomma RBRACE { result = ast AST::ResourceOverride, :object => val[0], :params => 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] error "You cannot collect without storeconfigs being set" end if val[1].is_a? AST::ResourceDefaults error "Defaults are not virtualizable" end 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 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: collectname 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] error "You cannot collect exported resources without storeconfigs being set" end result = ast AST::Collection, args } collectname: TYPE | NAME 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 | OR collexpr: colllval ISEQUAL simplervalue { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] #result = ast AST::CollExpr #result.push *val } | colllval NOTEQUAL simplervalue { result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] #result = ast AST::CollExpr #result.push *val } colllval: variable | name resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInst, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :children => [val[0],val[2]] } resourceinstances: resourceinst | resourceinstances SEMIC resourceinst { - if val[0].instance_of?(AST::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] } type: TYPE { result = ast AST::Type, :value => val[0] } resourcename: quotedtext | name | type | selector | variable | array assignment: VARIABLE EQUALS rvalue { if val[0] =~ /::/ raise Puppet::ParseError, "Cannot assign to variables in other namespaces" end # this is distinct from referencing a variable variable = ast AST::Name, :value => val[0] result = ast AST::VarDef, :name => variable, :value => val[2] } params: # nothing { result = ast AST::ASTArray } | param { result = 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 => val[2] } addparam: NAME PARROW rvalue { result = ast AST::ResourceParam, :param => val[0], :value => val[2], :add => true } anyparam: param | addparam anyparams: # nothing { result = ast AST::ASTArray } | anyparam { result = 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 } simplervalue: quotedtext | name | type | boolean | selector | variable rvalue: quotedtext | name | type | boolean | selector | variable | array | 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], :arguments => args, :ftype => :rvalue } | NAME LPAREN RPAREN { result = ast AST::Function, :name => val[0], :arguments => AST::ASTArray.new({}), :ftype => :rvalue } quotedtext: DQTEXT { result = ast AST::String, :value => val[0] } | SQTEXT { result = ast AST::FlatString, :value => val[0] } boolean: BOOLEAN { result = ast AST::Boolean, :value => val[0] } resourceref: NAME LBRACK rvalue RBRACK { Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceRef, :type => val[0], :title => val[2] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] } | classref LBRACK rvalue RBRACK { - result = ast AST::ResourceRef, :type => val[0], :title => val[2] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] } ifstatement: IF iftest LBRACE statements RBRACE else { args = { :test => val[1], :statements => val[3] } if val[5] args[:else] = val[5] end result = ast AST::IfStatement, args } else: # nothing | ELSE LBRACE statements RBRACE { result = ast AST::Else, :statements => val[2] } # Currently we only support a single value, but eventually one assumes # we'll support operators and such. iftest: rvalue casestatement: CASE rvalue LBRACE caseopts RBRACE { options = val[3] unless options.instance_of?(AST::ASTArray) options = ast AST::ASTArray, :children => [val[3]] end result = ast AST::CaseStatement, :test => val[1], :options => options } caseopts: caseopt | 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 { result = ast AST::CaseOpt, :value => val[0], :statements => val[3] } | casevalues COLON LBRACE RBRACE { result = ast(AST::CaseOpt, :value => val[0], :statements => ast(AST::ASTArray) ) } casevalues: selectlhand | 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 { 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] } # These are only used for importing, and we don't interpolate there. qtexts: quotedtext { result = [val[0].value] } | qtexts COMMA quotedtext { results = val[0] << val[2].value } import: IMPORT qtexts { val[1].each do |file| import(file) end result = AST::ASTArray.new(:children => []) } # Disable definition inheritance for now. 8/27/06, luke #definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { definition: DEFINE classname argumentlist LBRACE statements RBRACE { newdefine classname(val[1]), :arguments => val[2], :code => val[4] @lexer.indefine = false result = nil #} | DEFINE NAME argumentlist parent LBRACE RBRACE { } | DEFINE classname argumentlist LBRACE RBRACE { newdefine classname(val[1]), :arguments => val[2] @lexer.indefine = false result = nil } #hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { hostclass: CLASS classname classparent LBRACE statements RBRACE { # Our class gets defined in the parent namespace, not our own. @lexer.namepop newclass classname(val[1]), :code => val[4], :parent => val[2] result = nil } | CLASS classname classparent LBRACE RBRACE { # Our class gets defined in the parent namespace, not our own. @lexer.namepop newclass classname(val[1]), :parent => val[2] result = nil } nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { newnode val[1], :parent => val[2], :code => val[4] result = nil } | NODE hostnames nodeparent LBRACE RBRACE { newnode val[1], :parent => val[2] result = nil } classref: TYPE | CLASSREF classname: NAME | CLASSNAME # Multiple hostnames, as used for node names. These are all literal # strings, not AST objects. hostnames: hostname | hostnames COMMA hostname { result = val[0] result = [result] unless result.is_a?(Array) result << val[2] } hostname: NAME | SQTEXT | DQTEXT | DEFAULT 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], val[2]] } | NAME { Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0]] } | VARIABLE EQUALS rvalue { result = [val[0], val[2]] } | VARIABLE { result = [val[0]] } 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] } array: LBRACK rvalues 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 } comma: FARROW | COMMA endcomma: # nothing | COMMA { result = nil } end ---- header ---- require 'puppet' require 'puppet/util/loadedfile' require 'puppet/parser/lexer' require 'puppet/parser/ast' #require 'puppet/parser/interpreter' module Puppet class ParseError < Puppet::Error; end class ImportError < Racc::ParseError; end class AlreadyImportedError < ImportError; end end Puppet[:typecheck] = true Puppet[:paramcheck] = true ---- 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 aaffa816e..907bddc0a 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -1,1748 +1,1748 @@ # # DO NOT MODIFY!!!! # This file is automatically generated by racc 1.4.5 # from racc grammer file "grammar.ra". # require 'racc/parser' require 'puppet' require 'puppet/util/loadedfile' require 'puppet/parser/lexer' require 'puppet/parser/ast' #require 'puppet/parser/interpreter' module Puppet class ParseError < Puppet::Error; end class ImportError < Racc::ParseError; end class AlreadyImportedError < ImportError; end end Puppet[:typecheck] = true Puppet[:paramcheck] = true module Puppet module Parser class Parser < Racc::Parser -module_eval <<'..end grammar.ra modeval..idc3bb85ed76', 'grammar.ra', 640 +module_eval <<'..end grammar.ra modeval..id8b4fcf8e20', 'grammar.ra', 640 # 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 modeval..idc3bb85ed76 +..end grammar.ra modeval..id8b4fcf8e20 ##### racc 1.4.5 generates ### racc_reduce_table = [ 0, 0, :racc_error, 1, 53, :_reduce_1, 1, 53, :_reduce_none, 1, 54, :_reduce_none, 2, 54, :_reduce_4, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 1, 56, :_reduce_none, 4, 64, :_reduce_17, 3, 64, :_reduce_18, 2, 64, :_reduce_19, 1, 69, :_reduce_none, 1, 69, :_reduce_none, 1, 70, :_reduce_none, 3, 70, :_reduce_23, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_none, 1, 72, :_reduce_31, 1, 71, :_reduce_none, 3, 71, :_reduce_33, 5, 57, :_reduce_34, 5, 57, :_reduce_35, 5, 57, :_reduce_36, 5, 68, :_reduce_37, 2, 58, :_reduce_38, 1, 88, :_reduce_39, 2, 88, :_reduce_40, 2, 59, :_reduce_41, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 3, 90, :_reduce_44, 3, 90, :_reduce_45, 1, 91, :_reduce_none, 1, 91, :_reduce_none, 3, 91, :_reduce_48, 1, 92, :_reduce_none, 3, 92, :_reduce_50, 1, 93, :_reduce_none, 1, 93, :_reduce_none, 3, 94, :_reduce_53, 3, 94, :_reduce_54, 1, 95, :_reduce_none, 1, 95, :_reduce_none, 4, 97, :_reduce_57, 1, 82, :_reduce_none, 3, 82, :_reduce_59, 0, 83, :_reduce_none, 1, 83, :_reduce_none, 1, 99, :_reduce_62, 1, 73, :_reduce_63, 1, 75, :_reduce_64, 1, 98, :_reduce_none, 1, 98, :_reduce_none, 1, 98, :_reduce_none, 1, 98, :_reduce_none, 1, 98, :_reduce_none, 1, 98, :_reduce_none, 3, 60, :_reduce_71, 0, 84, :_reduce_72, 1, 84, :_reduce_73, 3, 84, :_reduce_74, 3, 102, :_reduce_75, 3, 103, :_reduce_76, 1, 104, :_reduce_none, 1, 104, :_reduce_none, 0, 87, :_reduce_79, 1, 87, :_reduce_80, 3, 87, :_reduce_81, 1, 105, :_reduce_none, 3, 105, :_reduce_83, 1, 96, :_reduce_none, 1, 96, :_reduce_none, 1, 96, :_reduce_none, 1, 96, :_reduce_none, 1, 96, :_reduce_none, 1, 96, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 1, 101, :_reduce_none, 4, 77, :_reduce_100, 3, 77, :_reduce_101, 1, 79, :_reduce_102, 1, 79, :_reduce_103, 1, 76, :_reduce_104, 4, 80, :_reduce_105, 4, 80, :_reduce_106, 6, 62, :_reduce_107, 0, 108, :_reduce_none, 4, 108, :_reduce_109, 1, 107, :_reduce_none, 5, 61, :_reduce_111, 1, 109, :_reduce_none, 2, 109, :_reduce_113, 5, 110, :_reduce_114, 4, 110, :_reduce_115, 1, 111, :_reduce_none, 3, 111, :_reduce_117, 3, 78, :_reduce_118, 1, 113, :_reduce_none, 4, 113, :_reduce_120, 1, 115, :_reduce_none, 3, 115, :_reduce_122, 3, 114, :_reduce_123, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_none, 1, 112, :_reduce_131, 1, 116, :_reduce_132, 3, 116, :_reduce_133, 2, 63, :_reduce_134, 6, 65, :_reduce_135, 5, 65, :_reduce_136, 6, 66, :_reduce_137, 5, 66, :_reduce_138, 6, 67, :_reduce_139, 5, 67, :_reduce_140, 1, 86, :_reduce_none, 1, 86, :_reduce_none, 1, 81, :_reduce_none, 1, 81, :_reduce_none, 1, 119, :_reduce_none, 3, 119, :_reduce_146, 1, 121, :_reduce_none, 1, 121, :_reduce_none, 1, 121, :_reduce_none, 1, 121, :_reduce_none, 0, 55, :_reduce_151, 0, 122, :_reduce_152, 1, 117, :_reduce_none, 3, 117, :_reduce_154, 3, 117, :_reduce_155, 1, 123, :_reduce_none, 3, 123, :_reduce_157, 3, 124, :_reduce_158, 1, 124, :_reduce_159, 3, 124, :_reduce_160, 1, 124, :_reduce_161, 1, 120, :_reduce_none, 2, 120, :_reduce_163, 1, 118, :_reduce_none, 2, 118, :_reduce_165, 1, 125, :_reduce_none, 1, 125, :_reduce_none, 1, 74, :_reduce_168, 3, 100, :_reduce_169, 2, 100, :_reduce_170, 1, 106, :_reduce_none, 1, 106, :_reduce_none, 0, 85, :_reduce_none, 1, 85, :_reduce_174 ] racc_reduce_n = 175 racc_shift_n = 279 racc_action_table = [ 81, 60, 64, 103, 173, 165, 81, 60, 64, 145, 37, 167, 58, -141, 51, 97, 70, -141, 115, 107, 166, -125, 70, 41, 81, 60, 64, 44, 45, 37, 196, 51, 142, 162, 163, 63, 66, 51, 10, 72, 130, 63, 66, 114, 10, 72, 172, 42, 68, 36, 10, 81, 60, 64, 68, 51, 5, 10, 217, 63, 127, 173, 46, 72, 180, 47, 251, 70, 207, 81, 60, 64, 68, 211, 142, 81, 60, 64, 103, 250, 44, 45, 51, 162, 163, 70, 63, 66, 197, 51, 72, 70, 199, 200, 107, 10, 81, 60, 64, 68, 51, 181, 245, 95, 63, 66, 51, 96, 72, 244, 63, 66, 70, 10, 72, 46, -130, 68, 47, 10, 81, 60, 64, 68, 199, 262, 36, 51, 191, 159, 36, 63, 66, 5, -129, 72, 70, 5, -125, 36, 10, 58, 60, 64, 68, -143, 5, 81, 60, 64, 95, 51, 44, 45, 179, 63, 66, 70, 103, 72, -127, 54, -124, 70, 10, 81, 60, 64, 68, 51, 207, -124, 51, 176, 107, 211, 63, 66, 51, 212, 72, 70, 63, 66, 55, 10, 72, 46, 213, 68, 47, 10, 81, 60, 64, 68, 51, 60, 64, 173, 63, 66, 168, 103, 72, 179, 162, 163, 70, 10, 81, 60, 64, 68, 51, -141, 81, 60, 64, 107, 60, 64, -126, 51, 175, 143, 70, 63, 66, -128, 141, 72, 70, -126, 139, 231, 10, 81, 60, 64, 68, 51, 120, -128, 234, 63, 66, 51, 235, 72, 154, 63, 66, 130, 10, 72, 60, 64, 68, 154, 10, 238, 60, 64, 68, 142, 120, 241, 51, 171, -126, 130, 63, 186, -124, 147, 72, 130, 60, 64, 60, 64, 101, 248, 249, 68, 51, 160, 252, 96, 63, 186, 51, 130, 72, 130, 63, 186, 255, -127, 72, -126, -124, 68, 60, 64, 60, 64, 51, 68, 51, -127, 63, 186, 63, 186, 72, -125, 72, 70, -129, 130, 60, 64, 193, 68, 247, 68, 60, 64, -125, 187, 179, 94, 51, 156, 51, 130, 63, 66, 63, 186, 72, 130, 72, 263, 55, 10, 265, 154, -127, 68, 51, 68, 150, 149, 63, 186, 51, 50, 72, 49, 63, 186, 60, 64, 72, 272, -174, 68, 60, 64, 273, 148, -129, 68, 34, 58, nil, 70, 60, 64, nil, nil, 137, 130, nil, nil, nil, nil, nil, nil, nil, nil, 51, 130, nil, nil, 63, 66, 51, nil, 72, nil, 63, 186, 55, 10, 72, 278, 51, 68, nil, nil, 63, 186, nil, 68, 72, nil, 23, nil, 55, nil, nil, nil, nil, 68, 243, nil, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, 253, 1, 6, nil, 13, nil, 18, nil, 22, nil, 28, 23, nil, 5, 10, nil, nil, nil, nil, 274, nil, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, 227, 1, 6, nil, 13, nil, 18, nil, 22, nil, 28, 23, nil, 5, 10, nil, nil, nil, nil, 256, nil, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, 257, 1, 6, nil, 13, nil, 18, nil, 22, nil, 28, 23, nil, 5, 10, nil, nil, nil, nil, 277, nil, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, 270, 1, 6, nil, 13, nil, 18, nil, 22, nil, 28, 23, nil, 5, 10, nil, nil, nil, nil, 215, nil, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, nil, 1, 6, nil, 13, 23, 18, nil, 22, nil, 28, nil, nil, 5, 10, 20, nil, 25, 27, nil, 1, 6, nil, 13, nil, 18, nil, 22, nil, 28, nil, nil, 5, 10 ] racc_action_check = [ 95, 95, 95, 41, 120, 105, 81, 81, 81, 81, 143, 110, 66, 23, 41, 31, 95, 23, 48, 41, 110, 133, 81, 7, 50, 50, 50, 115, 115, 2, 143, 95, 66, 105, 105, 95, 95, 81, 143, 95, 50, 81, 81, 48, 95, 81, 120, 7, 95, 2, 81, 198, 198, 198, 81, 50, 2, 2, 161, 50, 50, 127, 115, 50, 136, 115, 209, 198, 251, 173, 173, 173, 50, 251, 127, 58, 58, 58, 42, 209, 13, 13, 198, 161, 161, 173, 198, 198, 146, 42, 198, 58, 146, 146, 42, 198, 34, 34, 34, 198, 173, 138, 203, 29, 173, 173, 58, 29, 173, 203, 58, 58, 34, 173, 58, 13, 77, 173, 13, 58, 172, 172, 172, 58, 240, 240, 101, 34, 140, 101, 6, 34, 34, 101, 76, 34, 172, 6, 75, 27, 34, 18, 18, 18, 34, 18, 27, 20, 20, 20, 74, 172, 114, 114, 131, 172, 172, 18, 164, 172, 73, 18, 71, 20, 172, 22, 22, 22, 172, 164, 150, 129, 18, 128, 164, 150, 18, 18, 20, 152, 18, 22, 20, 20, 18, 18, 20, 114, 153, 18, 114, 20, 252, 252, 252, 20, 22, 149, 149, 154, 22, 22, 112, 103, 22, 155, 112, 112, 252, 22, 248, 248, 248, 22, 103, 70, 238, 238, 238, 103, 25, 25, 125, 252, 121, 67, 248, 252, 252, 78, 65, 252, 238, 59, 57, 174, 252, 176, 176, 176, 252, 248, 175, 53, 177, 248, 248, 238, 178, 248, 179, 238, 238, 176, 248, 238, 166, 166, 248, 180, 238, 183, 167, 167, 238, 186, 49, 194, 176, 116, 83, 166, 176, 176, 85, 86, 176, 167, 148, 148, 260, 260, 39, 207, 208, 176, 166, 102, 211, 38, 166, 166, 167, 148, 166, 260, 167, 167, 214, 132, 167, 220, 221, 166, 142, 142, 245, 245, 148, 167, 260, 222, 148, 148, 260, 260, 148, 224, 260, 142, 225, 245, 205, 205, 142, 148, 205, 260, 139, 139, 88, 139, 237, 28, 142, 97, 245, 205, 142, 142, 245, 245, 142, 139, 245, 243, 142, 142, 244, 96, 87, 142, 205, 245, 93, 92, 205, 205, 139, 16, 205, 14, 139, 139, 54, 54, 139, 261, 262, 205, 187, 187, 263, 90, 89, 139, 1, 196, nil, 54, 141, 141, nil, nil, 54, 187, nil, nil, nil, nil, nil, nil, nil, nil, 54, 141, nil, nil, 54, 54, 187, nil, 54, nil, 187, 187, 54, 54, 187, 276, 141, 54, nil, nil, 141, 141, nil, 187, 141, nil, 276, nil, 141, nil, nil, nil, nil, 141, 201, nil, 276, nil, 276, 276, nil, 276, 276, nil, 276, 201, 276, nil, 276, nil, 276, nil, nil, 276, 276, 201, nil, 201, 201, 212, 201, 201, nil, 201, nil, 201, nil, 201, nil, 201, 212, nil, 201, 201, nil, nil, nil, nil, 265, nil, 212, nil, 212, 212, nil, 212, 212, nil, 212, 265, 212, nil, 212, nil, 212, nil, nil, 212, 212, 265, nil, 265, 265, 171, 265, 265, nil, 265, nil, 265, nil, 265, nil, 265, 171, nil, 265, 265, nil, nil, nil, nil, 216, nil, 171, nil, 171, 171, nil, 171, 171, nil, 171, 216, 171, nil, 171, nil, 171, nil, nil, 171, 171, 216, nil, 216, 216, 228, 216, 216, nil, 216, nil, 216, nil, 216, nil, 216, 228, nil, 216, 216, nil, nil, nil, nil, 275, nil, 228, nil, 228, 228, nil, 228, 228, nil, 228, 275, 228, nil, 228, nil, 228, nil, nil, 228, 228, 275, nil, 275, 275, 254, 275, 275, nil, 275, nil, 275, nil, 275, nil, 275, 254, nil, 275, 275, nil, nil, nil, nil, 160, nil, 254, nil, 254, 254, nil, 254, 254, nil, 254, 160, 254, nil, 254, nil, 254, nil, nil, 254, 254, 160, nil, 160, 160, nil, 160, 160, nil, 160, 273, 160, nil, 160, nil, 160, nil, nil, 160, 160, 273, nil, 273, 273, nil, 273, 273, nil, 273, 147, 273, nil, 273, nil, 273, nil, nil, 273, 273, 147, nil, 147, 147, nil, 147, 147, nil, 147, 33, 147, nil, 147, nil, 147, nil, nil, 147, 147, 33, nil, 33, 33, nil, 33, 33, nil, 33, 0, 33, nil, 33, nil, 33, nil, nil, 33, 33, 0, nil, 0, 0, nil, 0, 0, nil, 0, nil, 0, nil, 0, nil, 0, nil, nil, 0, 0 ] racc_action_pointer = [ 673, 363, 11, nil, nil, nil, 92, 4, nil, nil, nil, nil, nil, 77, 355, nil, 353, nil, 139, nil, 145, nil, 163, 11, nil, 217, nil, 101, 291, 101, nil, 15, nil, 654, 94, nil, nil, nil, 283, 247, nil, -19, 56, nil, nil, nil, nil, nil, 8, 228, 22, nil, nil, 222, 361, nil, nil, 213, 73, 212, nil, nil, nil, nil, nil, 220, 10, 215, nil, nil, 213, 141, nil, 139, 148, 117, 113, 95, 208, nil, nil, 4, nil, 249, nil, 253, 269, 329, 309, 353, 367, nil, 345, 332, nil, -2, 311, 335, nil, nil, nil, 88, 281, 181, nil, -15, nil, nil, nil, nil, -4, nil, 158, nil, 149, 24, 263, nil, nil, nil, -5, 214, nil, nil, nil, 201, nil, 52, 134, 150, nil, 144, 278, 0, nil, nil, 47, nil, 78, 325, 123, 377, 301, -8, nil, nil, 83, 635, 275, 194, 137, nil, 173, 183, 190, 195, nil, nil, nil, nil, 597, 35, nil, nil, 136, nil, 253, 259, nil, nil, nil, 490, 118, 67, 228, 204, 235, 237, 241, 212, 221, nil, nil, 252, nil, nil, 243, 367, nil, nil, nil, nil, nil, nil, 244, nil, 375, nil, 49, nil, nil, 421, nil, 92, nil, 319, nil, 270, 261, 56, nil, 275, 446, nil, 291, nil, 509, nil, nil, nil, 280, 281, 290, nil, 296, 299, nil, nil, 534, nil, nil, nil, nil, nil, nil, nil, nil, 322, 214, nil, 115, nil, nil, 316, 342, 303, nil, nil, 208, nil, nil, 35, 190, nil, 578, nil, nil, nil, nil, nil, 277, 360, 361, 366, nil, 465, nil, nil, nil, nil, nil, nil, nil, 616, nil, 553, 402, nil, nil ] racc_action_default = [ -151, -175, -175, -14, -2, -144, -175, -175, -15, -3, -142, -16, -5, -175, -175, -6, -175, -7, -43, -8, -175, -9, -175, -42, -10, -175, -11, -175, -39, -175, -12, -175, -13, -1, -175, -38, -143, -141, -175, -151, -41, -151, -151, -145, -149, -148, -147, -150, -151, -79, -72, -168, -130, -28, -175, -31, -29, -175, -175, -30, -102, -32, -19, -104, -103, -20, -63, -21, -62, -22, -64, -24, -131, -25, -175, -26, -27, -99, -98, -96, -94, -175, -110, -90, -97, -91, -175, -95, -92, -93, -175, -132, -134, -151, -40, -175, -72, -175, -4, -71, -164, -175, -175, -151, -46, -175, -47, -63, -49, -56, -175, -55, -175, -162, -175, -175, -175, -77, -78, -80, -175, -173, -128, -70, -68, -65, -73, -63, -60, -66, -64, -173, -69, -67, -58, -129, -175, -18, -175, -175, -175, -175, -175, -175, -82, -170, -175, -175, -175, -175, -152, -153, -175, -175, -175, -173, 279, -166, -165, -167, -175, -175, -52, -51, -175, -45, -175, -175, -44, -163, -146, -175, -175, -175, -175, -174, -61, -175, -175, -174, -72, -17, -126, -175, -118, -119, -63, -175, -124, -127, -125, -105, -23, -101, -175, -33, -175, -169, -175, -171, -172, -175, -112, -175, -116, -175, -133, -161, -175, -175, -156, -159, -175, -106, -175, -138, -175, -50, -48, -88, -84, -85, -89, -53, -86, -87, -54, -140, -175, -76, -75, -37, -81, -59, -34, -35, -74, -173, -175, -121, -173, -100, -83, -108, -175, -175, -113, -111, -175, -154, -155, -175, -175, -136, -175, -36, -137, -139, -57, -123, -175, -175, -172, -175, -107, -175, -117, -160, -157, -158, -135, -122, -120, -175, -115, -175, -175, -114, -109 ] racc_goto_table = [ 29, 33, 38, 131, 185, 98, 117, 53, 123, 119, 174, 43, 134, 31, 210, 62, 39, 105, 112, 202, 178, 218, 198, 223, 226, 4, 146, 40, 86, 264, 205, 121, 77, 29, 77, 177, 184, 93, 128, 122, 240, 92, 152, 53, 214, 102, 77, 48, 183, 155, 116, 138, 239, 192, 208, 209, 59, 204, 35, 158, nil, nil, nil, 91, 100, nil, nil, nil, nil, 76, 77, nil, nil, 113, nil, nil, 246, nil, nil, 161, nil, nil, nil, nil, 82, nil, 90, nil, 125, nil, nil, nil, 59, 77, nil, nil, 183, nil, 99, nil, nil, 135, nil, nil, nil, 76, nil, 77, nil, nil, nil, 157, 169, 170, 204, 268, 260, nil, 151, nil, nil, 75, 140, nil, nil, 271, 258, nil, 122, 261, 53, 53, 117, 237, 123, 232, 236, 122, 233, 194, nil, nil, nil, nil, nil, 144, nil, 29, 201, nil, nil, nil, nil, 133, 266, 122, 122, 75, nil, 153, 29, 216, nil, nil, nil, 122, nil, nil, nil, 183, nil, 29, 228, 98, nil, nil, 122, 182, nil, 59, 59, nil, nil, 71, 77, 77, 182, 206, 98, nil, 135, nil, 76, 76, 122, nil, nil, 73, nil, 135, 98, 29, nil, nil, 220, 220, 109, 109, nil, nil, 77, nil, 29, 254, 125, 129, 29, 225, 225, 71, 111, 111, nil, nil, nil, 182, 98, 135, 29, 132, nil, nil, nil, 73, 122, nil, 229, 230, 135, nil, nil, nil, 190, 182, 75, 75, nil, 98, 98, 122, 77, 190, nil, 56, 29, nil, 135, nil, nil, nil, 77, nil, 242, nil, 77, 29, 275, nil, 109, 224, 224, nil, nil, 29, 276, 29, 29, nil, nil, 133, nil, nil, 111, 182, nil, 124, nil, nil, nil, 56, 190, nil, nil, nil, nil, nil, 135, nil, 182, nil, nil, nil, 259, nil, 188, nil, 71, 71, 190, nil, nil, 135, 267, 188, nil, nil, 269, nil, 189, nil, 73, 73, 61, nil, 84, nil, 84, 189, nil, 109, nil, 221, 221, nil, nil, nil, nil, nil, 84, nil, nil, 129, nil, 111, nil, 222, 222, nil, 190, nil, nil, nil, 188, nil, nil, 132, nil, nil, 61, nil, nil, nil, 84, 190, nil, nil, 189, nil, nil, nil, 188, nil, nil, nil, nil, nil, 56, 56, nil, nil, nil, nil, nil, nil, 189, 84, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 84, nil, 219, 219, nil, nil, nil, nil, nil, nil, nil, 188, 124, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 189, 188, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 189, nil, nil, nil, nil, nil, nil, 61, 195, 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, 84, 84, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 84, 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, 84, nil, nil, nil, nil, nil, nil, nil, nil, nil, 84, nil, nil, nil, 84 ] racc_goto_check = [ 34, 2, 34, 32, 62, 4, 50, 25, 48, 52, 33, 69, 45, 1, 72, 17, 29, 39, 39, 58, 33, 40, 54, 44, 44, 3, 53, 38, 55, 56, 57, 35, 47, 34, 47, 31, 61, 29, 30, 25, 63, 64, 65, 25, 33, 66, 47, 67, 60, 32, 68, 17, 62, 20, 70, 71, 27, 60, 5, 73, nil, nil, nil, 27, 3, nil, nil, nil, nil, 24, 47, nil, nil, 3, nil, nil, 58, nil, nil, 39, nil, nil, nil, nil, 49, nil, 49, nil, 27, nil, nil, nil, 27, 47, nil, nil, 60, nil, 49, nil, nil, 24, nil, nil, nil, 24, nil, 47, nil, nil, nil, 29, 69, 69, 60, 72, 54, nil, 3, nil, nil, 23, 49, nil, nil, 62, 33, nil, 25, 33, 25, 25, 50, 32, 48, 52, 50, 25, 45, 17, nil, nil, nil, nil, nil, 49, nil, 34, 2, nil, nil, nil, nil, 23, 60, 25, 25, 23, nil, 49, 34, 2, nil, nil, nil, 25, nil, nil, nil, 60, nil, 34, 2, 4, nil, nil, 25, 27, nil, 27, 27, nil, nil, 21, 47, 47, 27, 27, 4, nil, 24, nil, 24, 24, 25, nil, nil, 22, nil, 24, 4, 34, nil, nil, 27, 27, 21, 21, nil, nil, 47, nil, 34, 2, 27, 21, 34, 24, 24, 21, 22, 22, nil, nil, nil, 27, 4, 24, 34, 22, nil, nil, nil, 22, 25, nil, 49, 49, 24, nil, nil, nil, 23, 27, 23, 23, nil, 4, 4, 25, 47, 23, nil, 26, 34, nil, 24, nil, nil, nil, 47, nil, 49, nil, 47, 34, 2, nil, 21, 23, 23, nil, nil, 34, 2, 34, 34, nil, nil, 23, nil, nil, 22, 27, nil, 26, nil, nil, nil, 26, 23, nil, nil, nil, nil, nil, 24, nil, 27, nil, nil, nil, 49, nil, 21, nil, 21, 21, 23, nil, nil, 24, 49, 21, nil, nil, 49, nil, 22, nil, 22, 22, 28, nil, 28, nil, 28, 22, nil, 21, nil, 21, 21, nil, nil, nil, nil, nil, 28, nil, nil, 21, nil, 22, nil, 22, 22, nil, 23, nil, nil, nil, 21, nil, nil, 22, nil, nil, 28, nil, nil, nil, 28, 23, nil, nil, 22, nil, nil, nil, 21, nil, nil, nil, nil, nil, 26, 26, nil, nil, nil, nil, nil, nil, 22, 28, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 28, nil, 26, 26, nil, nil, nil, nil, nil, nil, nil, 21, 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 22, 21, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 22, nil, nil, nil, nil, nil, nil, 28, 28, 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, 28, 28, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 28, 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, 28, nil, nil, nil, nil, nil, nil, nil, nil, nil, 28, nil, nil, nil, 28 ] racc_goto_pointer = [ nil, 13, 1, 25, -28, 56, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, -3, nil, nil, -88, 165, 179, 103, 51, -11, 235, 38, 304, 10, -12, -93, -47, -111, 0, -18, nil, nil, 20, -24, -143, nil, nil, nil, -143, -38, nil, 12, -42, 64, -43, nil, -40, -55, -124, 8, -214, -118, -129, nil, -91, -103, -135, -147, 16, -51, 6, 34, 2, -2, -96, -95, -136, -42 ] racc_goto_default = [ nil, nil, nil, 104, 9, 12, 15, 17, 19, 21, 24, 26, 30, 32, 3, 8, 11, nil, 65, 67, 69, 85, 87, 88, 89, 78, 80, 83, 14, 16, nil, nil, nil, nil, 74, nil, 2, 7, nil, nil, 106, 164, 108, 110, nil, nil, 136, 52, 79, nil, 126, 118, nil, nil, nil, nil, nil, nil, nil, 203, 57, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ] racc_token_table = { false => 0, Object.new => 1, :LBRACK => 2, :DQTEXT => 3, :SQTEXT => 4, :RBRACK => 5, :LBRACE => 6, :RBRACE => 7, :SYMBOL => 8, :FARROW => 9, :COMMA => 10, :TRUE => 11, :FALSE => 12, :EQUALS => 13, :LESSEQUAL => 14, :NOTEQUAL => 15, :DOT => 16, :COLON => 17, :TYPE => 18, :LLCOLLECT => 19, :RRCOLLECT => 20, :QMARK => 21, :LPAREN => 22, :RPAREN => 23, :ISEQUAL => 24, :GREATEREQUAL => 25, :GREATERTHAN => 26, :LESSTHAN => 27, :IF => 28, :ELSE => 29, :IMPORT => 30, :DEFINE => 31, :ELSIF => 32, :VARIABLE => 33, :CLASS => 34, :INHERITS => 35, :NODE => 36, :BOOLEAN => 37, :NAME => 38, :SEMIC => 39, :CASE => 40, :DEFAULT => 41, :AT => 42, :LCOLLECT => 43, :RCOLLECT => 44, :CLASSNAME => 45, :CLASSREF => 46, :NOT => 47, :OR => 48, :AND => 49, :UNDEF => 50, :PARROW => 51 } racc_use_result_var = true racc_nt_base = 52 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', 'LBRACK', 'DQTEXT', 'SQTEXT', 'RBRACK', 'LBRACE', 'RBRACE', 'SYMBOL', 'FARROW', 'COMMA', 'TRUE', 'FALSE', 'EQUALS', 'LESSEQUAL', 'NOTEQUAL', 'DOT', 'COLON', 'TYPE', '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', '$start', 'program', 'statements', 'nil', 'statement', 'resource', 'virtualresource', 'collection', 'assignment', 'casestatement', 'ifstatement', 'import', 'fstatement', 'definition', 'hostclass', 'nodedef', 'resourceoverride', 'funcvalues', 'namestrings', 'resourcerefs', 'namestring', 'name', 'variable', 'type', 'boolean', 'funcrvalue', 'selector', 'quotedtext', 'resourceref', 'classname', 'resourceinstances', 'endsemi', 'params', 'endcomma', 'classref', 'anyparams', 'at', 'collectname', 'collectrhand', 'collstatements', 'collstatement', 'colljoin', 'collexpr', 'colllval', 'simplervalue', 'resourceinst', 'resourcename', 'undef', 'array', 'rvalue', 'param', 'addparam', 'anyparam', 'rvalues', 'comma', 'iftest', 'else', 'caseopts', 'caseopt', 'casevalues', 'selectlhand', 'svalues', 'selectval', 'sintvalues', 'qtexts', 'argumentlist', 'classparent', 'hostnames', 'nodeparent', 'hostname', 'nothing', 'arguments', 'argument', 'classnameordefault'] Racc_debug_parser = false ##### racc system variables end ##### # reduce 0 omitted module_eval <<'.,.,', 'grammar.ra', 30 def _reduce_1( val, _values, result ) if val[0] # Make sure we always return an array. if val[0].is_a?(AST::ASTArray) if val[0].children.empty? result = nil else result = val[0] end else result = aryfy(val[0]) end else result = nil end result end .,., # reduce 2 omitted # reduce 3 omitted module_eval <<'.,.,', 'grammar.ra', 46 def _reduce_4( val, _values, result ) if val[0] and val[1] 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 elsif obj = (val[0] || val[1]) result = obj else result = nil end 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 module_eval <<'.,.,', 'grammar.ra', 68 def _reduce_17( val, _values, result ) args = aryfy(val[2]) result = ast AST::Function, :name => val[0], :arguments => args, :ftype => :statement result end .,., module_eval <<'.,.,', 'grammar.ra', 74 def _reduce_18( val, _values, result ) result = ast AST::Function, :name => val[0], :arguments => AST::ASTArray.new({}), :ftype => :statement result end .,., module_eval <<'.,.,', 'grammar.ra', 81 def _reduce_19( val, _values, result ) args = aryfy(val[1]) result = ast AST::Function, :name => val[0], :arguments => args, :ftype => :statement result end .,., # reduce 20 omitted # reduce 21 omitted # reduce 22 omitted module_eval <<'.,.,', 'grammar.ra', 91 def _reduce_23( val, _values, result ) result = aryfy(val[0], val[2]) result.line = @lexer.line result.file = @lexer.file result end .,., # reduce 24 omitted # reduce 25 omitted # reduce 26 omitted # reduce 27 omitted # reduce 28 omitted # reduce 29 omitted # reduce 30 omitted module_eval <<'.,.,', 'grammar.ra', 104 def _reduce_31( val, _values, result ) result = ast AST::Name, :value => val[0] result end .,., # reduce 32 omitted module_eval <<'.,.,', 'grammar.ra', 115 def _reduce_33( val, _values, result ) unless val[0].is_a?(AST::ASTArray) val[0] = aryfy(val[0]) end val[0].push(val[2]) result = val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 136 def _reduce_34( val, _values, result ) array = val[2] - if array.instance_of?(AST::ResourceInst) + if array.instance_of?(AST::ResourceInstance) array = [array] end result = ast AST::ASTArray # this iterates across each specified resourceinstance array.each { |instance| - unless instance.instance_of?(AST::ResourceInst) + unless instance.instance_of?(AST::ResourceInstance) raise Puppet::Dev, "Got something that isn't an instance" end # now, i need to somehow differentiate between those things with # arrays in their names, and normal things - result.push ast(AST::ResourceDef, + result.push ast(AST::Resource, :type => val[0], :title => instance[0], :params => instance[1]) } result end .,., module_eval <<'.,.,', 'grammar.ra', 139 def _reduce_35( val, _values, result ) # This is a deprecated syntax. error "All resource specifications require names" result end .,., module_eval <<'.,.,', 'grammar.ra', 142 def _reduce_36( val, _values, result ) # a defaults setting for a type result = ast(AST::ResourceDefaults, :type => val[0], :params => val[2]) result end .,., module_eval <<'.,.,', 'grammar.ra', 147 def _reduce_37( val, _values, result ) result = ast AST::ResourceOverride, :object => val[0], :params => val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 174 def _reduce_38( val, _values, result ) type = val[0] if type == :exported and ! Puppet[:storeconfigs] error "You cannot collect without storeconfigs being set" end if val[1].is_a? AST::ResourceDefaults error "Defaults are not virtualizable" end 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 result = val[1] result end .,., module_eval <<'.,.,', 'grammar.ra', 175 def _reduce_39( val, _values, result ) result = :virtual result end .,., module_eval <<'.,.,', 'grammar.ra', 176 def _reduce_40( val, _values, result ) result = :exported result end .,., module_eval <<'.,.,', 'grammar.ra', 199 def _reduce_41( 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] error "You cannot collect exported resources without storeconfigs being set" end result = ast AST::Collection, args result end .,., # reduce 42 omitted # reduce 43 omitted module_eval <<'.,.,', 'grammar.ra', 210 def _reduce_44( val, _values, result ) if val[1] result = val[1] result.form = :virtual else result = :virtual end result end .,., module_eval <<'.,.,', 'grammar.ra', 218 def _reduce_45( val, _values, result ) if val[1] result = val[1] result.form = :exported else result = :exported end result end .,., # reduce 46 omitted # reduce 47 omitted module_eval <<'.,.,', 'grammar.ra', 226 def _reduce_48( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] result end .,., # reduce 49 omitted module_eval <<'.,.,', 'grammar.ra', 232 def _reduce_50( val, _values, result ) result = val[1] result.parens = true result end .,., # reduce 51 omitted # reduce 52 omitted module_eval <<'.,.,', 'grammar.ra', 240 def _reduce_53( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] #result = ast AST::CollExpr #result.push *val result end .,., module_eval <<'.,.,', 'grammar.ra', 245 def _reduce_54( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] #result = ast AST::CollExpr #result.push *val result end .,., # reduce 55 omitted # reduce 56 omitted module_eval <<'.,.,', 'grammar.ra', 252 def _reduce_57( val, _values, result ) - result = ast AST::ResourceInst, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :children => [val[0],val[2]] result end .,., # reduce 58 omitted module_eval <<'.,.,', 'grammar.ra', 262 def _reduce_59( val, _values, result ) - if val[0].instance_of?(AST::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 result end .,., # reduce 60 omitted # reduce 61 omitted module_eval <<'.,.,', 'grammar.ra', 269 def _reduce_62( val, _values, result ) result = ast AST::Undef, :value => :undef result end .,., module_eval <<'.,.,', 'grammar.ra', 273 def _reduce_63( val, _values, result ) result = ast AST::Name, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 277 def _reduce_64( val, _values, result ) result = ast AST::Type, :value => val[0] result end .,., # reduce 65 omitted # reduce 66 omitted # reduce 67 omitted # reduce 68 omitted # reduce 69 omitted # reduce 70 omitted module_eval <<'.,.,', 'grammar.ra', 293 def _reduce_71( val, _values, result ) if val[0] =~ /::/ raise Puppet::ParseError, "Cannot assign to variables in other namespaces" end # this is distinct from referencing a variable variable = ast AST::Name, :value => val[0] result = ast AST::VarDef, :name => variable, :value => val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 298 def _reduce_72( val, _values, result ) result = ast AST::ASTArray result end .,., module_eval <<'.,.,', 'grammar.ra', 298 def _reduce_73( val, _values, result ) result = val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 307 def _reduce_74( 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', 311 def _reduce_75( val, _values, result ) result = ast AST::ResourceParam, :param => val[0], :value => val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 316 def _reduce_76( val, _values, result ) result = ast AST::ResourceParam, :param => val[0], :value => val[2], :add => true result end .,., # reduce 77 omitted # reduce 78 omitted module_eval <<'.,.,', 'grammar.ra', 324 def _reduce_79( val, _values, result ) result = ast AST::ASTArray result end .,., module_eval <<'.,.,', 'grammar.ra', 324 def _reduce_80( val, _values, result ) result = val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 333 def _reduce_81( 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 .,., # reduce 82 omitted module_eval <<'.,.,', 'grammar.ra', 342 def _reduce_83( 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]] end result end .,., # reduce 84 omitted # reduce 85 omitted # reduce 86 omitted # reduce 87 omitted # reduce 88 omitted # reduce 89 omitted # reduce 90 omitted # reduce 91 omitted # reduce 92 omitted # reduce 93 omitted # reduce 94 omitted # reduce 95 omitted # reduce 96 omitted # reduce 97 omitted # reduce 98 omitted # reduce 99 omitted module_eval <<'.,.,', 'grammar.ra', 369 def _reduce_100( val, _values, result ) args = aryfy(val[2]) result = ast AST::Function, :name => val[0], :arguments => args, :ftype => :rvalue result end .,., module_eval <<'.,.,', 'grammar.ra', 374 def _reduce_101( val, _values, result ) result = ast AST::Function, :name => val[0], :arguments => AST::ASTArray.new({}), :ftype => :rvalue result end .,., module_eval <<'.,.,', 'grammar.ra', 378 def _reduce_102( val, _values, result ) result = ast AST::String, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 380 def _reduce_103( val, _values, result ) result = ast AST::FlatString, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 384 def _reduce_104( val, _values, result ) result = ast AST::Boolean, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 389 def _reduce_105( val, _values, result ) Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceRef, :type => val[0], :title => val[2] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 391 def _reduce_106( val, _values, result ) - result = ast AST::ResourceRef, :type => val[0], :title => val[2] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 404 def _reduce_107( val, _values, result ) args = { :test => val[1], :statements => val[3] } if val[5] args[:else] = val[5] end result = ast AST::IfStatement, args result end .,., # reduce 108 omitted module_eval <<'.,.,', 'grammar.ra', 409 def _reduce_109( val, _values, result ) result = ast AST::Else, :statements => val[2] result end .,., # reduce 110 omitted module_eval <<'.,.,', 'grammar.ra', 421 def _reduce_111( val, _values, result ) options = val[3] unless options.instance_of?(AST::ASTArray) options = ast AST::ASTArray, :children => [val[3]] end result = ast AST::CaseStatement, :test => val[1], :options => options result end .,., # reduce 112 omitted module_eval <<'.,.,', 'grammar.ra', 431 def _reduce_113( val, _values, result ) 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 result end .,., module_eval <<'.,.,', 'grammar.ra', 435 def _reduce_114( val, _values, result ) result = ast AST::CaseOpt, :value => val[0], :statements => val[3] result end .,., module_eval <<'.,.,', 'grammar.ra', 440 def _reduce_115( val, _values, result ) result = ast(AST::CaseOpt, :value => val[0], :statements => ast(AST::ASTArray) ) result end .,., # reduce 116 omitted module_eval <<'.,.,', 'grammar.ra', 450 def _reduce_117( 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', 454 def _reduce_118( val, _values, result ) result = ast AST::Selector, :param => val[0], :values => val[2] result end .,., # reduce 119 omitted module_eval <<'.,.,', 'grammar.ra', 456 def _reduce_120( val, _values, result ) result = val[1] result end .,., # reduce 121 omitted module_eval <<'.,.,', 'grammar.ra', 467 def _reduce_122( 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', 471 def _reduce_123( val, _values, result ) result = ast AST::ResourceParam, :param => val[0], :value => val[2] result end .,., # reduce 124 omitted # reduce 125 omitted # reduce 126 omitted # reduce 127 omitted # reduce 128 omitted # reduce 129 omitted # reduce 130 omitted module_eval <<'.,.,', 'grammar.ra', 482 def _reduce_131( val, _values, result ) result = ast AST::Default, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 484 def _reduce_132( val, _values, result ) result = [val[0].value] result end .,., module_eval <<'.,.,', 'grammar.ra', 488 def _reduce_133( val, _values, result ) results = val[0] << val[2].value result end .,., module_eval <<'.,.,', 'grammar.ra', 496 def _reduce_134( val, _values, result ) val[1].each do |file| import(file) end result = AST::ASTArray.new(:children => []) result end .,., module_eval <<'.,.,', 'grammar.ra', 506 def _reduce_135( val, _values, result ) newdefine classname(val[1]), :arguments => val[2], :code => val[4] @lexer.indefine = false result = nil #} | DEFINE NAME argumentlist parent LBRACE RBRACE { result end .,., module_eval <<'.,.,', 'grammar.ra', 510 def _reduce_136( val, _values, result ) newdefine classname(val[1]), :arguments => val[2] @lexer.indefine = false result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 518 def _reduce_137( val, _values, result ) # Our class gets defined in the parent namespace, not our own. @lexer.namepop newclass classname(val[1]), :code => val[4], :parent => val[2] result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 523 def _reduce_138( val, _values, result ) # Our class gets defined in the parent namespace, not our own. @lexer.namepop newclass classname(val[1]), :parent => val[2] result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 528 def _reduce_139( val, _values, result ) newnode val[1], :parent => val[2], :code => val[4] result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 531 def _reduce_140( val, _values, result ) newnode val[1], :parent => val[2] result = nil result end .,., # reduce 141 omitted # reduce 142 omitted # reduce 143 omitted # reduce 144 omitted # reduce 145 omitted module_eval <<'.,.,', 'grammar.ra', 546 def _reduce_146( val, _values, result ) result = val[0] result = [result] unless result.is_a?(Array) result << val[2] result end .,., # reduce 147 omitted # reduce 148 omitted # reduce 149 omitted # reduce 150 omitted module_eval <<'.,.,', 'grammar.ra', 555 def _reduce_151( val, _values, result ) result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 559 def _reduce_152( val, _values, result ) result = ast AST::ASTArray, :children => [] result end .,., # reduce 153 omitted module_eval <<'.,.,', 'grammar.ra', 564 def _reduce_154( val, _values, result ) result = nil result end .,., module_eval <<'.,.,', 'grammar.ra', 568 def _reduce_155( val, _values, result ) result = val[1] result = [result] unless result[0].is_a?(Array) result end .,., # reduce 156 omitted module_eval <<'.,.,', 'grammar.ra', 575 def _reduce_157( val, _values, result ) result = val[0] result = [result] unless result[0].is_a?(Array) result << val[2] result end .,., module_eval <<'.,.,', 'grammar.ra', 580 def _reduce_158( val, _values, result ) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0], val[2]] result end .,., module_eval <<'.,.,', 'grammar.ra', 584 def _reduce_159( val, _values, result ) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0]] result end .,., module_eval <<'.,.,', 'grammar.ra', 586 def _reduce_160( val, _values, result ) result = [val[0], val[2]] result end .,., module_eval <<'.,.,', 'grammar.ra', 588 def _reduce_161( val, _values, result ) result = [val[0]] result end .,., # reduce 162 omitted module_eval <<'.,.,', 'grammar.ra', 593 def _reduce_163( val, _values, result ) result = val[1] result end .,., # reduce 164 omitted module_eval <<'.,.,', 'grammar.ra', 598 def _reduce_165( val, _values, result ) result = val[1] result end .,., # reduce 166 omitted # reduce 167 omitted module_eval <<'.,.,', 'grammar.ra', 604 def _reduce_168( val, _values, result ) result = ast AST::Variable, :value => val[0] result end .,., module_eval <<'.,.,', 'grammar.ra', 612 def _reduce_169( val, _values, result ) if val[1].instance_of?(AST::ASTArray) result = val[1] else result = ast AST::ASTArray, :children => [val[1]] end result end .,., module_eval <<'.,.,', 'grammar.ra', 614 def _reduce_170( val, _values, result ) result = ast AST::ASTArray result end .,., # reduce 171 omitted # reduce 172 omitted # reduce 173 omitted module_eval <<'.,.,', 'grammar.ra', 619 def _reduce_174( val, _values, result ) result = nil result end .,., def _reduce_none( val, _values, result ) result end end # class Parser end # module Parser end # module Puppet diff --git a/test/language/ast/resourcedef.rb b/test/language/ast/resource.rb similarity index 92% rename from test/language/ast/resourcedef.rb rename to test/language/ast/resource.rb index d79a02cfa..9ef5181af 100755 --- a/test/language/ast/resourcedef.rb +++ b/test/language/ast/resource.rb @@ -1,59 +1,59 @@ #!/usr/bin/env ruby # # Created by Luke A. Kanies on 2007-07-8. # Copyright (c) 2007. All rights reserved. $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppettest' require 'puppettest/parsertesting' -class TestASTResourceDef < Test::Unit::TestCase +class TestASTResource< Test::Unit::TestCase include PuppetTest include PuppetTest::ParserTesting AST = Puppet::Parser::AST def setup super @scope = mkscope @parser = @scope.compile.parser @scope.compile.send(:evaluate_main) end def newdef(type, title, params = nil) params ||= AST::ASTArray.new(:children => []) - AST::ResourceDef.new(:type => type, :title => AST::String.new(:value => title), :params => params) + AST::Resource.new(:type => type, :title => AST::String.new(:value => title), :params => params) end # Related to #806, make sure resources always look up the full path to the resource. def test_scoped_types @parser.newdefine "one" @parser.newdefine "one::two" @parser.newdefine "three" twoscope = @scope.newscope(:namespace => "one") twoscope.resource = @scope.resource assert(twoscope.finddefine("two"), "Could not find 'two' definition") title = "title" # First try a qualified type assert_equal("one::two", newdef("two", title).evaluate(:scope => twoscope)[0].type, "Defined type was not made fully qualified") # Then try a type that does not need to be qualified assert_equal("one", newdef("one", title).evaluate(:scope => twoscope)[0].type, "Unqualified defined type was not handled correctly") # Then an unqualified type from within the one namespace assert_equal("three", newdef("three", title).evaluate(:scope => twoscope)[0].type, "Defined type was not made fully qualified") # Then a builtin type assert_equal("file", newdef("file", title).evaluate(:scope => twoscope)[0].type, "Builtin type was not handled correctly") # Now try a type that does not exist, which should throw an error. assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do newdef("nosuchtype", title).evaluate(:scope => twoscope) end end end diff --git a/test/language/ast/resourceref.rb b/test/language/ast/resource_reference.rb similarity index 95% rename from test/language/ast/resourceref.rb rename to test/language/ast/resource_reference.rb index 33a80ad40..e8883afb9 100755 --- a/test/language/ast/resourceref.rb +++ b/test/language/ast/resource_reference.rb @@ -1,93 +1,93 @@ #!/usr/bin/env ruby # # Created by Luke A. Kanies on 2007-07-8. # Copyright (c) 2007. All rights reserved. $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'puppettest' require 'puppettest/parsertesting' -class TestASTResourceRef < Test::Unit::TestCase +class TestASTResourceReference < Test::Unit::TestCase include PuppetTest include PuppetTest::ParserTesting AST = Puppet::Parser::AST def newref(type, title) - AST::ResourceRef.new(:type => type, :title => AST::String.new(:value => title)) + AST::ResourceReference.new(:type => type, :title => AST::String.new(:value => title)) end def setup super @scope = mkscope @parser = @scope.compile.parser end def test_evaluate @parser.newdefine "one::two" @parser.newdefine "one-two" [%w{file /tmp/yay}, %w{one::two three}, %w{one-two three}].each do |type, title| ref = newref(type, title) evaled = nil assert_nothing_raised("Could not evaluate resource ref") do evaled = ref.evaluate(:scope => @scope) end assert_equal(type, evaled.type, "Type did not translate correctly") assert_equal(title, evaled.title, "Title did not translate correctly") end end # Related to #706, make sure resource references correctly translate to qualified types. def test_scoped_references @parser.newdefine "one" @parser.newdefine "one::two" @parser.newdefine "three" twoscope = @scope.newscope(:namespace => "one") assert(twoscope.finddefine("two"), "Could not find 'two' definition") title = "title" # First try a qualified type assert_equal("one::two", newref("two", title).evaluate(:scope => twoscope).type, "Defined type was not made fully qualified") # Then try a type that does not need to be qualified assert_equal("one", newref("one", title).evaluate(:scope => twoscope).type, "Unqualified defined type was not handled correctly") # Then an unqualified type from within the one namespace assert_equal("three", newref("three", title).evaluate(:scope => twoscope).type, "Defined type was not made fully qualified") # Then a builtin type assert_equal("file", newref("file", title).evaluate(:scope => twoscope).type, "Builtin type was not handled correctly") # Now try a type that does not exist, which should throw an error. assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do newref("nosuchtype", title).evaluate(:scope => twoscope) end # Now run the same tests, but with the classes @parser.newclass "four" @parser.newclass "one::five" # First try an unqualified type assert_equal("four", newref("class", "four").evaluate(:scope => twoscope).title, "Unqualified class was not found") # Then a qualified class assert_equal("one::five", newref("class", "five").evaluate(:scope => twoscope).title, "Class was not made fully qualified") # Then try a type that does not need to be qualified assert_equal("four", newref("class", "four").evaluate(:scope => twoscope).title, "Unqualified class was not handled correctly") # Now try a type that does not exist, which should throw an error. assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do newref("class", "nosuchclass").evaluate(:scope => twoscope) end end end diff --git a/test/language/parser.rb b/test/language/parser.rb index ddf35e3e3..d50bdfe5a 100755 --- a/test/language/parser.rb +++ b/test/language/parser.rb @@ -1,1197 +1,1197 @@ #!/usr/bin/env ruby $:.unshift("../lib").unshift("../../lib") if __FILE__ =~ /\.rb$/ require 'mocha' require 'puppet' require 'puppet/parser/parser' require 'puppettest' class TestParser < Test::Unit::TestCase include PuppetTest::ParserTesting def setup super Puppet[:parseonly] = true #@lexer = Puppet::Parser::Lexer.new() end def test_each_file textfiles { |file| parser = mkparser Puppet.debug("parsing %s" % file) if __FILE__ == $0 assert_nothing_raised() { parser.file = file parser.parse } Puppet::Type.eachtype { |type| type.each { |obj| assert(obj.file, "File is not set on %s" % obj.ref) assert(obj.name, "Name is not set on %s" % obj.ref) assert(obj.line, "Line is not set on %s" % obj.ref) } } Puppet::Type.allclear } end def test_failers failers { |file| parser = mkparser Puppet.debug("parsing failer %s" % file) if __FILE__ == $0 assert_raise(Puppet::ParseError, "Did not fail while parsing %s" % file) { parser.file = file ast = parser.parse config = mkconfig(parser) config.compile #ast.classes[""].evaluate :scope => config.topscope } Puppet::Type.allclear } 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 mkmanifest(file) name = File.join(tmpdir, "file%s" % 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%s" % i) 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() importer = tempfile() 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.classes[""].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.parse %{define mydef($schedule) {}} } assert_nothing_raised { parser.parse %{define adef($schedule = false) {}} 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).classes[""].code[0] } assert_instance_of(Puppet::Parser::AST::IfStatement, ret) parser = mkparser str2 = %{if true { #{exec.call("true")} } else { #{exec.call("false")} }} assert_nothing_raised { ret = parser.parse(str2).classes[""].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.parse %{class myclass { class other {} }} } assert(parser.classes["myclass"], "Could not find myclass") assert(parser.classes["myclass::other"], "Could not find myclass::other") assert_nothing_raised { parser.parse "class base {} class container { class deep::sub inherits base {} }" } sub = parser.classes["container::deep::sub"] assert(sub, "Could not find sub") # Now try it with a parent class being a fq class assert_nothing_raised { parser.parse "class container::one inherits container::deep::sub {}" } sub = parser.classes["container::one"] assert(sub, "Could not find one") assert_equal("container::deep::sub", sub.parentclass) # Finally, try including a qualified class assert_nothing_raised("Could not include fully qualified class") { 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 assert_nothing_raised do out = parser.parse "" assert_instance_of(Puppet::Parser::Parser::ASTSet, out) assert_nil(parser.classes[""], "Got a 'main' class when we had no code") end # Now try something a touch more complicated parser.initvars assert_nothing_raised do out = parser.parse "Exec { path => '/usr/bin:/usr/sbin' }" assert_instance_of(Puppet::Parser::Parser::ASTSet, out) assert_equal("", parser.classes[""].classname) assert_equal("", parser.classes[""].namespace) end end # Make sure virtual and exported resources work appropriately. def test_virtualresources tests = [:virtual] if Puppet.features.rails? 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 ret = parser.parse("#{at}file { '/tmp/testing': owner => root }") end assert_instance_of(AST::ASTArray, ret.classes[""].code) resdef = ret.classes[""].code[0] - assert_instance_of(AST::ResourceDef, resdef) + assert_instance_of(AST::Resource, resdef) assert_equal("/tmp/testing", resdef.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 ret = parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }") end ret.classes[""].each do |res| - assert_instance_of(AST::ResourceDef, res) + assert_instance_of(AST::Resource, res) check.call(res, "multiresource") end # Now evaluate these scope = mkscope klass = parser.newclass "" scope.source = klass assert_nothing_raised do ret.classes[""].evaluate :scope => scope, :resource => Puppet::Parser::Resource.new(:type => "mydefine", :title => 'whatever', :scope => scope, :source => scope.source) end # Make sure we can find both of them %w{/tmp/1 /tmp/2}.each do |title| res = scope.findresource("File[#{title}]") assert(res, "Could not find %s" % title) check.call(res, "found multiresource") end end end def test_collections tests = [:virtual] if Puppet.features.rails? Puppet[:storeconfigs] = true tests << :exported end tests.each do |form| parser = mkparser if form == :virtual arrow = "<||>" else arrow = "<<||>>" end ret = nil assert_nothing_raised do ret = parser.parse("File #{arrow}") end coll = ret.classes[""].code[0] assert_instance_of(AST::Collection, coll) assert_equal(form, coll.form) end end def test_collectionexpressions %w{== !=}.each do |oper| str = "File <| title #{oper} '/tmp/testing' |>" parser = mkparser res = nil assert_nothing_raised do res = parser.parse(str).classes[""].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).classes[""].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).classes[""].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 # We've had problems with files other than site.pp importing into main. def test_importing_into_main top = tempfile() other = tempfile() File.open(top, "w") do |f| f.puts "import '#{other}'" end file = tempfile() File.open(other, "w") do |f| f.puts "file { '#{file}': ensure => present }" end interp = mkinterp :Manifest => top, :UseNodes => false code = nil assert_nothing_raised do code = interp.compile(mknode).extract.flatten end assert(code.length == 1, "Did not get the file") assert_instance_of(Puppet::TransObject, code[0]) end def test_fully_qualified_definitions parser = mkparser assert_nothing_raised("Could not parse fully-qualified definition") { parser.parse %{define one::two { }} } assert(parser.definitions["one::two"], "Could not find one::two with no namespace") # Now try using the definition assert_nothing_raised("Could not parse fully-qualified definition usage") { parser.parse %{one::two { yayness: }} } 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 def test_module_import basedir = File.join(tmpdir(), "module-import") @@tmpfiles << basedir Dir.mkdir(basedir) modfiles = [ "init.pp", "mani1.pp", "mani2.pp", "sub/smani1.pp", "sub/smani2.pp" ] modpath = File.join(basedir, "modules") Puppet[:modulepath] = modpath modname = "amod" manipath = File::join(modpath, modname, Puppet::Module::MANIFESTS) FileUtils::mkdir_p(File::join(manipath, "sub")) targets = [] modfiles.each do |fname| target = File::join(basedir, File::basename(fname, '.pp')) targets << target txt = %[ file { '#{target}': content => "#{fname}" } ] if fname == "init.pp" txt = %[import 'mani1' \nimport '#{modname}/mani2'\nimport '#{modname}/sub/*.pp'\n ] + txt end File::open(File::join(manipath, fname), "w") do |f| f.puts txt end end manifest_texts = [ "import '#{modname}'", "import '#{modname}/init'", "import '#{modname}/init.pp'" ] manifest = File.join(modpath, "manifest.pp") manifest_texts.each do |txt| File.open(manifest, "w") { |f| f.puts txt } assert_nothing_raised { parser = mkparser parser.file = manifest parser.parse } assert_creates(manifest, *targets) end end # #544 def test_ignoreimports parser = mkparser assert(! Puppet[:ignoreimport], ":ignoreimport defaulted to true") assert_raise(Puppet::ParseError, "Did not fail on missing import") do parser.parse("import 'nosuchfile'") end assert_nothing_raised("could not set :ignoreimport") do Puppet[:ignoreimport] = true end assert_nothing_raised("Parser did not follow :ignoreimports") do parser.parse("import 'nosuchfile'") end end def test_multiple_imports_on_one_line one = tempfile two = tempfile base = tempfile 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 %s" % 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 # #588 def test_globbing_with_directories dir = tempfile Dir.mkdir(dir) subdir = File.join(dir, "subdir") Dir.mkdir(subdir) file = File.join(dir, "file.pp") maker = tempfile File.open(file, "w") { |f| f.puts "file { '#{maker}': ensure => file }" } parser = mkparser assert_nothing_raised("Globbing failed when it matched a directory") do parser.import("%s/*" % dir) 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.classes[""].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 result = parser.parse(str) end assert_instance_of(Puppet::Parser::Parser::ASTSet, result, "Did not get a ASTSet back from parsing") assert_instance_of(AST::HostClass, result.classes["yay"], "Did not create 'yay' class") assert_instance_of(AST::HostClass, result.classes[""], "Did not create main class") assert_instance_of(AST::Definition, result.definitions["bar"], "Did not create 'bar' definition") assert_instance_of(AST::Node, result.nodes["foo"], "Did not create 'foo' node") end # Make sure our node gets added to the node table. def test_newnode parser = mkparser # First just try calling it directly assert_nothing_raised { parser.newnode("mynode", :code => :yay) } assert_equal(:yay, parser.nodes["mynode"].code) # Now make sure that trying to redefine it throws an error. assert_raise(Puppet::ParseError) { parser.newnode("mynode", {}) } # Now try one with no code assert_nothing_raised { parser.newnode("simplenode", :parent => :foo) } # Now define the parent node parser.newnode(:foo) # And make sure we get things back correctly assert_equal(:foo, parser.nodes["simplenode"].parentclass) assert_nil(parser.nodes["simplenode"].code) # Now make sure that trying to redefine it throws an error. assert_raise(Puppet::ParseError) { parser.newnode("mynode", {}) } # Test multiple names names = ["one", "two", "three"] assert_nothing_raised { parser.newnode(names, {:code => :yay, :parent => :foo}) } names.each do |name| assert_equal(:yay, parser.nodes[name].code) assert_equal(:foo, parser.nodes[name].parentclass) # Now make sure that trying to redefine it throws an error. assert_raise(Puppet::ParseError) { parser.newnode(name, {}) } end end def test_newdefine parser = mkparser assert_nothing_raised { parser.newdefine("mydefine", :code => :yay, :arguments => ["a", stringobj("b")]) } mydefine = parser.definitions["mydefine"] assert(mydefine, "Could not find definition") assert_equal("", mydefine.namespace) assert_equal("mydefine", mydefine.classname) assert_raise(Puppet::ParseError) do parser.newdefine("mydefine", :code => :yay, :arguments => ["a", stringobj("b")]) end # Now define the same thing in a different scope assert_nothing_raised { parser.newdefine("other::mydefine", :code => :other, :arguments => ["a", stringobj("b")]) } other = parser.definitions["other::mydefine"] assert(other, "Could not find definition") assert(parser.definitions["other::mydefine"], "Could not find other::mydefine") assert_equal(:other, other.code) assert_equal("other", other.namespace) assert_equal("other::mydefine", other.classname) end def test_newclass scope = mkscope parser = scope.compile.parser mkcode = proc do |ary| classes = ary.collect do |string| AST::FlatString.new(:value => string) end AST::ASTArray.new(:children => classes) end # First make sure that code is being appended code = mkcode.call(%w{original code}) klass = nil assert_nothing_raised { klass = parser.newclass("myclass", :code => code) } assert(klass, "Did not return class") assert(parser.classes["myclass"], "Could not find definition") assert_equal("myclass", parser.classes["myclass"].classname) assert_equal(%w{original code}, parser.classes["myclass"].code.evaluate(:scope => scope)) # Newclass behaves differently than the others -- it just appends # the code to the existing class. code = mkcode.call(%w{something new}) assert_nothing_raised do klass = parser.newclass("myclass", :code => code) end assert(klass, "Did not return class when appending") assert_equal(%w{original code something new}, parser.classes["myclass"].code.evaluate(:scope => scope)) # Now create the same class name in a different scope assert_nothing_raised { klass = parser.newclass("other::myclass", :code => mkcode.call(%w{something diff})) } assert(klass, "Did not return class") other = parser.classes["other::myclass"] assert(other, "Could not find class") assert_equal("other::myclass", other.classname) assert_equal("other::myclass", other.namespace) assert_equal(%w{something diff}, other.code.evaluate(:scope => scope)) # Make sure newclass deals correctly with nodes with no code klass = parser.newclass("nocode") assert(klass, "Did not return class") assert_nothing_raised do klass = parser.newclass("nocode", :code => mkcode.call(%w{yay test})) end assert(klass, "Did not return class with no code") assert_equal(%w{yay test}, parser.classes["nocode"].code.evaluate(:scope => scope)) # Then try merging something into nothing parser.newclass("nocode2", :code => mkcode.call(%w{foo test})) assert(klass, "Did not return class with no code") assert_nothing_raised do klass = parser.newclass("nocode2") end assert(klass, "Did not return class with no code") assert_equal(%w{foo test}, parser.classes["nocode2"].code.evaluate(:scope => scope)) # And lastly, nothing and nothing klass = parser.newclass("nocode3") assert(klass, "Did not return class with no code") assert_nothing_raised do klass = parser.newclass("nocode3") end assert(klass, "Did not return class with no code") assert_nil(parser.classes["nocode3"].code) end # Make sure you can't have classes and defines with the same name in the # same scope. def test_classes_beat_defines parser = mkparser assert_nothing_raised { parser.newclass("yay::funtest") } assert_raise(Puppet::ParseError) do parser.newdefine("yay::funtest") end assert_nothing_raised { parser.newdefine("yay::yaytest") } assert_raise(Puppet::ParseError) do parser.newclass("yay::yaytest") end 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, "%s split to %s" % [name, result]) end end end # Now make sure we get appropriate behaviour with parent class conflicts. def test_newclass_parentage parser = mkparser parser.newclass("base1") parser.newclass("one::two::three") # First create it with no parentclass. assert_nothing_raised { parser.newclass("sub") } assert(parser.classes["sub"], "Could not find definition") assert_nil(parser.classes["sub"].parentclass) # Make sure we can't set the parent class to ourself. assert_raise(Puppet::ParseError) { parser.newclass("sub", :parent => "sub") } # Now create another one, with a parentclass. assert_nothing_raised { parser.newclass("sub", :parent => "base1") } # Make sure we get the right parent class, and make sure it's not an object. assert_equal("base1", parser.classes["sub"].parentclass) # Now make sure we get a failure if we try to conflict. assert_raise(Puppet::ParseError) { parser.newclass("sub", :parent => "one::two::three") } # Make sure that failure didn't screw us up in any way. assert_equal("base1", parser.classes["sub"].parentclass) # But make sure we can create a class with a fq parent assert_nothing_raised { parser.newclass("another", :parent => "one::two::three") } assert_equal("one::two::three", parser.classes["another"].parentclass) end def test_fqfind parser = mkparser table = {} # Define a bunch of things. %w{a c a::b a::b::c a::c a::b::c::d a::b::c::d::e::f c::d}.each do |string| table[string] = string end check = proc do |namespace, hash| hash.each do |thing, result| assert_equal(result, parser.fqfind(namespace, thing, table), "Could not find %s in %s" % [thing, namespace]) end end # Now let's do some test lookups. # First do something really simple check.call "a", "b" => "a::b", "b::c" => "a::b::c", "d" => nil, "::c" => "c" check.call "a::b", "c" => "a::b::c", "b" => "a::b", "a" => "a" check.call "a::b::c::d::e", "c" => "a::b::c", "::c" => "c", "c::d" => "a::b::c::d", "::c::d" => "c::d" check.call "", "a" => "a", "a::c" => "a::c" end # Setup a module. def mk_module(name, files = {}) mdir = File.join(@dir, name) mandir = File.join(mdir, "manifests") FileUtils.mkdir_p mandir if defs = files[:define] files.delete(:define) end Dir.chdir(mandir) do files.each do |file, classes| File.open("%s.pp" % file, "w") do |f| classes.each { |klass| if defs f.puts "define %s {}" % klass else f.puts "class %s {}" % klass end } end end end end # #596 - make sure classes and definitions load automatically if they're in modules, so we don't have to manually load each one. def test_module_autoloading @dir = tempfile Puppet[:modulepath] = @dir FileUtils.mkdir_p @dir parser = mkparser # Make sure we fail like normal for actually missing classes assert_nil(parser.findclass("", "nosuchclass"), "Did not return nil on missing classes") # test the simple case -- the module class itself name = "simple" mk_module(name, :init => [name]) # Try to load the module automatically now klass = parser.findclass("", name) assert_instance_of(AST::HostClass, klass, "Did not autoload class from module init file") assert_equal(name, klass.classname, "Incorrect class was returned") # Try loading the simple module when we're in something other than the base namespace. parser = mkparser klass = parser.findclass("something::else", name) assert_instance_of(AST::HostClass, klass, "Did not autoload class from module init file") assert_equal(name, klass.classname, "Incorrect class was returned") # Now try it with a definition as the base file name = "simpdef" mk_module(name, :define => true, :init => [name]) klass = parser.finddefine("", name) assert_instance_of(AST::Definition, klass, "Did not autoload class from module init file") assert_equal(name, klass.classname, "Incorrect class was returned") # Now try it with namespace classes where both classes are in the init file parser = mkparser modname = "both" name = "sub" mk_module(modname, :init => %w{both both::sub}) # First try it with a namespace klass = parser.findclass("both", name) assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from module init file with a namespace") assert_equal("both::sub", klass.classname, "Incorrect class was returned") # Now try it using the fully qualified name parser = mkparser klass = parser.findclass("", "both::sub") assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from module init file with no namespace") assert_equal("both::sub", klass.classname, "Incorrect class was returned") # Now try it with the class in a different file parser = mkparser modname = "separate" name = "sub" mk_module(modname, :init => %w{separate}, :sub => %w{separate::sub}) # First try it with a namespace klass = parser.findclass("separate", name) assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from separate file with a namespace") assert_equal("separate::sub", klass.classname, "Incorrect class was returned") # Now try it using the fully qualified name parser = mkparser klass = parser.findclass("", "separate::sub") assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from separate file with no namespace") assert_equal("separate::sub", klass.classname, "Incorrect class was returned") # Now make sure we don't get a failure when there's no module file parser = mkparser modname = "alone" name = "sub" mk_module(modname, :sub => %w{alone::sub}) # First try it with a namespace assert_nothing_raised("Could not autoload file when module file is missing") do klass = parser.findclass("alone", name) end assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from alone file with a namespace") assert_equal("alone::sub", klass.classname, "Incorrect class was returned") # Now try it using the fully qualified name parser = mkparser klass = parser.findclass("", "alone::sub") assert_instance_of(AST::HostClass, klass, "Did not autoload sub class from alone file with no namespace") assert_equal("alone::sub", klass.classname, "Incorrect class was returned") end # Make sure class, node, and define methods are case-insensitive def test_structure_case_insensitivity parser = mkparser result = nil assert_nothing_raised do result = parser.newclass "Yayness" end assert_equal(result, parser.findclass("", "yayNess")) assert_nothing_raised do result = parser.newdefine "FunTest" end assert_equal(result, parser.finddefine("", "fUntEst"), "%s was not matched" % "fUntEst") end end # $Id$ diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index b8fd8bd83..c71508803 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -1,408 +1,408 @@ require 'puppettest' require 'puppet/rails' module PuppetTest::ParserTesting include PuppetTest AST = Puppet::Parser::AST Compile = Puppet::Parser::Compile # A fake class that we can use for testing evaluation. class FakeAST attr_writer :evaluate def evaluated? defined? @evaluated and @evaluated end def evaluate(*args) @evaluated = true return @evaluate end def initialize(val = nil) if val @evaluate = val end end def reset @evaluated = nil end def safeevaluate(*args) evaluate() end end def astarray(*args) AST::ASTArray.new( :children => args ) end def mkconfig(parser = nil) require 'puppet/network/handler/node' parser ||= mkparser node = mknode return Compile.new(node, parser) end def mknode(name = nil) require 'puppet/node' name ||= "nodename" Puppet::Network::Handler.handler(:node) Puppet::Node.new(name) end def mkinterp(args = {}) args[:Code] ||= "" unless args.include?(:Manifest) args[:Local] ||= true Puppet::Parser::Interpreter.new(args) end def mkparser Puppet::Parser::Parser.new() end def mkscope(hash = {}) hash[:parser] ||= mkparser config ||= mkconfig(hash[:parser]) config.topscope.source = (hash[:parser].findclass("", "") || hash[:parser].newclass("")) unless config.topscope.source raise "Could not find source for scope" end # Make the 'main' stuff config.send(:evaluate_main) config.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 %s" % names.inspect) { return AST::Tag.new(args) } end def resourcedef(type, title, params) unless title.is_a?(AST) title = stringobj(title) end assert_nothing_raised("Could not create %s %s" % [type, title]) { - return AST::ResourceDef.new( + return AST::Resource.new( :file => __FILE__, :line => __LINE__, :title => title, :type => type, :params => resourceinst(params) ) } end def virt_resourcedef(*args) res = resourcedef(*args) res.virtual = true res end def resourceoverride(type, title, params) assert_nothing_raised("Could not create %s %s" % [type, name]) { return AST::ResourceOverride.new( :file => __FILE__, :line => __LINE__, :object => resourceref(type, title), :type => type, :params => resourceinst(params) ) } end def resourceref(type, title) assert_nothing_raised("Could not create %s %s" % [type, title]) { - return AST::ResourceRef.new( + 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 %s" % path) { return resourcedef("file", path, hash) } end def nameobj(name) assert_nothing_raised("Could not create name %s" % name) { return AST::Name.new( :file => tempfile(), :line => rand(100), :value => name ) } end def typeobj(name) assert_nothing_raised("Could not create type %s" % name) { return AST::Type.new( :file => tempfile(), :line => rand(100), :value => name ) } end def nodedef(name) assert_nothing_raised("Could not create node %s" % name) { return AST::NodeDef.new( :file => tempfile(), :line => rand(100), :names => nameobj(name), :code => AST::ASTArray.new( :children => [ varobj("%svar" % name, "%svalue" % name), fileobj("/%s" % name) ] ) ) } end def resourceinst(hash) assert_nothing_raised("Could not create resource instance") { params = hash.collect { |param, value| resourceparam(param, value) } - return AST::ResourceInst.new( + return AST::ResourceInstance.new( :file => tempfile(), :line => rand(100), :children => params ) } end def resourceparam(param, value) # Allow them to pass non-strings in if value.is_a?(String) value = stringobj(value) end assert_nothing_raised("Could not create param %s" % 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) unless value.is_a? AST value = stringobj(value) end assert_nothing_raised("Could not create %s code" % name) { return AST::VarDef.new( :file => tempfile(), :line => rand(100), :name => nameobj(name), :value => value ) } end def varref(name) assert_nothing_raised("Could not create %s variable" % name) { return AST::Variable.new( :file => __FILE__, :line => __LINE__, :value => name ) } end def argobj(name, value) assert_nothing_raised("Could not create %s compargument" % name) { 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 %s" % type) { return AST::ResourceDefaults.new( :file => __FILE__, :line => __LINE__, :type => type, :params => 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 return func end # This assumes no nodes def assert_creates(manifest, *files) interp = nil assert_nothing_raised { interp = Puppet::Parser::Interpreter.new( :Manifest => manifest, :UseNodes => false ) } config = nil assert_nothing_raised { config = interp.compile(mknode) } comp = nil assert_nothing_raised { comp = config.extract.to_type } assert_apply(comp) files.each do |file| assert(FileTest.exists?(file), "Did not create %s" % file) end end def mk_transobject(file = "/etc/passwd") obj = nil assert_nothing_raised { obj = Puppet::TransObject.new("file", file) obj["owner"] = "root" obj["mode"] = "644" } return 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 } return 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 if block_given? yield(obj, i, j) end resources << obj end newbucket = mk_transbucket(*resources) bucket.push newbucket bucket = newbucket end return 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) } return trans end end