diff options
Diffstat (limited to 'lib/puppet/parser')
-rw-r--r-- | lib/puppet/parser/ast.rb | 4 | ||||
-rw-r--r-- | lib/puppet/parser/ast/astarray.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/caseopt.rb | 5 | ||||
-rw-r--r-- | lib/puppet/parser/ast/casestatement.rb | 9 | ||||
-rw-r--r-- | lib/puppet/parser/ast/classdef.rb | 31 | ||||
-rw-r--r-- | lib/puppet/parser/ast/compdef.rb | 26 | ||||
-rw-r--r-- | lib/puppet/parser/ast/component.rb | 51 | ||||
-rw-r--r-- | lib/puppet/parser/ast/hostclass.rb | 49 | ||||
-rw-r--r-- | lib/puppet/parser/ast/leaf.rb | 12 | ||||
-rw-r--r-- | lib/puppet/parser/ast/node.rb | 35 | ||||
-rw-r--r-- | lib/puppet/parser/ast/nodedef.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/objectdef.rb | 49 | ||||
-rw-r--r-- | lib/puppet/parser/ast/objectparam.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/objectref.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/selector.rb | 11 | ||||
-rw-r--r-- | lib/puppet/parser/ast/typedefaults.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/ast/vardef.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/grammar.ra | 8 | ||||
-rw-r--r-- | lib/puppet/parser/interpreter.rb | 18 | ||||
-rw-r--r-- | lib/puppet/parser/parser.rb | 16 | ||||
-rw-r--r-- | lib/puppet/parser/scope.rb | 126 |
21 files changed, 330 insertions, 162 deletions
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index d690ff1a8..7aedfb1cc 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -44,10 +44,10 @@ module Puppet # Evaluate the current object. Basically just iterates across all # of the contained children and evaluates them in turn, returning a # list of all of the collected values, rejecting nil values - def evaluate(scope) + def evaluate(args) #Puppet.debug("Evaluating ast %s" % @name) value = self.collect { |obj| - obj.safeevaluate(scope) + obj.safeevaluate(args) }.reject { |obj| obj.nil? } diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 1e7bdb81c..356258a96 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -15,7 +15,8 @@ class Puppet::Parser::AST end # Evaluate our children. - def evaluate(scope) + 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 @@ -35,12 +36,12 @@ class Puppet::Parser::AST end } rets = [settors,others].flatten.collect { |child| - child.safeevaluate(scope) + child.safeevaluate(:scope => scope) } else # If we're not declarative, just do everything in order. rets = @children.collect { |item| - item.safeevaluate(scope) + item.safeevaluate(:scope => scope) } end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 258f5081a..366b6e939 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -50,8 +50,9 @@ class Puppet::Parser::AST # Evaluate the actual statements; this only gets called if # our option matched. - def evaluate(scope) - return @statements.safeevaluate(scope.newscope) + def evaluate(hash) + scope = hash[:scope] + return @statements.safeevaluate(:scope => scope.newscope) end def tree(indent = 0) diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb index cd87cfd08..e51cc7522 100644 --- a/lib/puppet/parser/ast/casestatement.rb +++ b/lib/puppet/parser/ast/casestatement.rb @@ -6,8 +6,9 @@ class Puppet::Parser::AST # Short-curcuit evaluation. Return the value of the statements for # the first option that matches. - def evaluate(scope) - value = @test.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + value = @test.safeevaluate(:scope => scope) retvalue = nil found = false @@ -16,7 +17,7 @@ class Puppet::Parser::AST @options.each { |option| if option.eachvalue { |opval| break true if opval == value } # we found a matching option - retvalue = option.safeevaluate(scope) + retvalue = option.safeevaluate(:scope => scope) found = true break end @@ -25,7 +26,7 @@ class Puppet::Parser::AST # Unless we found something, look for the default. unless found if defined? @default - retvalue = @default.safeevaluate(scope) + retvalue = @default.safeevaluate(:scope => scope) else Puppet.debug "No true answers and no default" end diff --git a/lib/puppet/parser/ast/classdef.rb b/lib/puppet/parser/ast/classdef.rb index 147ab88e5..0a6a86816 100644 --- a/lib/puppet/parser/ast/classdef.rb +++ b/lib/puppet/parser/ast/classdef.rb @@ -9,36 +9,37 @@ class Puppet::Parser::AST def each if @parentclass - #[@name,@args,@parentclass,@code].each { |child| yield child } - [@name,@parentclass,@code].each { |child| yield child } + #[@type,@args,@parentclass,@code].each { |child| yield child } + [@type,@parentclass,@code].each { |child| yield child } else - #[@name,@args,@code].each { |child| yield child } - [@name,@code].each { |child| yield child } + #[@type,@args,@code].each { |child| yield child } + [@type,@code].each { |child| yield child } end end - # Store our parse tree according to name. - def evaluate(scope) - name = @name.safeevaluate(scope) - #args = @args.safeevaluate(scope) + # Store our parse tree according to type. + def evaluate(hash) + scope = hash[:scope] + type = @type.safeevaluate(:scope => scope) + #args = @args.safeevaluate(:scope => scope) #:args => args, arghash = { - :name => name, + :type => type, :code => @code } if @parentclass - arghash[:parentclass] = @parentclass.safeevaluate(scope) + arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope) end #Puppet.debug("defining hostclass '%s' with arguments [%s]" % - # [name,args]) + # [type,args]) begin hclass = HostClass.new(arghash) hclass.keyword = self.keyword - scope.settype(name, hclass) + scope.settype(type, hclass) rescue Puppet::ParseError => except except.line = self.line except.file = self.file @@ -61,7 +62,7 @@ class Puppet::Parser::AST def tree(indent = 0) #@args.tree(indent + 1), return [ - @name.tree(indent + 1), + @type.tree(indent + 1), ((@@indline * 4 * indent) + self.typewrap("class")), @parentclass ? @parentclass.tree(indent + 1) : "", @code.tree(indent + 1), @@ -70,8 +71,8 @@ class Puppet::Parser::AST def to_s return "class %s(%s) inherits %s {\n%s }" % - [@name, @parentclass, @code] - #[@name, @args, @parentclass, @code] + [@type, @parentclass, @code] + #[@type, @args, @parentclass, @code] end end diff --git a/lib/puppet/parser/ast/compdef.rb b/lib/puppet/parser/ast/compdef.rb index 07eda339e..f1b947ec4 100644 --- a/lib/puppet/parser/ast/compdef.rb +++ b/lib/puppet/parser/ast/compdef.rb @@ -9,25 +9,26 @@ class Puppet::Parser::AST # encounter an error if the component is instantiated more than # once. class CompDef < AST::Branch - attr_accessor :name, :args, :code, :keyword + attr_accessor :type, :args, :code, :keyword def each - [@name,@args,@code].each { |child| yield child } + [@type,@args,@code].each { |child| yield child } end # Store the parse tree. - def evaluate(scope) - name = @name.safeevaluate(scope) - args = @args.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + type = @type.safeevaluate(:scope => scope) + args = @args.safeevaluate(:scope => scope) begin comp = AST::Component.new( - :name => name, + :type => type, :args => args, :code => @code ) comp.keyword = self.keyword - scope.settype(name, comp) + scope.settype(type, comp) rescue Puppet::ParseError => except except.line = self.line except.file = self.file @@ -48,12 +49,17 @@ class Puppet::Parser::AST @keyword = "define" super - #Puppet.debug "Defining type %s" % @name.value + #if @parentclass + # Puppet.notice "Parent class of %s is %s" % + # [@type.value, @parentclass.value] + #end + + #Puppet.debug "Defining type %s" % @type.value end def tree(indent = 0) return [ - @name.tree(indent + 1), + @type.tree(indent + 1), ((@@indline * 4 * indent) + self.typewrap("define")), @args.tree(indent + 1), @code.tree(indent + 1), @@ -61,7 +67,7 @@ class Puppet::Parser::AST end def to_s - return "define %s(%s) {\n%s }" % [@name, @args, @code] + return "define %s(%s) {\n%s }" % [@type, @args, @code] end end end diff --git a/lib/puppet/parser/ast/component.rb b/lib/puppet/parser/ast/component.rb index 858ef86f6..aa29624fd 100644 --- a/lib/puppet/parser/ast/component.rb +++ b/lib/puppet/parser/ast/component.rb @@ -10,20 +10,35 @@ class Puppet::Parser::AST # The class name @name = :component - attr_accessor :name, :args, :code, :scope, :autoname, :keyword - - def evaluate(scope,hash,objtype,objname) - scope = scope.newscope + attr_accessor :type, :args, :code, :scope, :autoname, :keyword + + #def evaluate(scope,hash,objtype,objname) + def evaluate(hash) + scope = hash[:scope] + objtype = hash[:type] + objname = hash[:name] + arguments = hash[:arguments] || {} + + scope = scope.newscope( + :type => @type, + :name => objname, + :keyword => self.keyword, + :autoname => self.autoname + ) + if hash[:newcontext] + #scope.warning "Setting context to %s" % self.object_id + scope.context = self.object_id + end @scope = scope # The type is the component or class name - scope.type = objtype + #scope.type = objtype # The name is the name the user has chosen or that has # been dynamically generated. This is almost never used - scope.name = objname + #scope.name = objname - scope.keyword = self.keyword + #scope.keyword = self.keyword # Retain the fact that we were autonamed, if so if self.autoname @@ -36,9 +51,10 @@ class Puppet::Parser::AST # Additionally, add a tag for whatever kind of class # we are - scope.tag(objtype) + scope.tag(@type) - unless objname =~ /-\d+/ # it was generated + unless objname.nil? + #Puppet.info "tagging with %s" % objname.inspect scope.tag(objname) end #scope.base = self.class.name @@ -46,21 +62,20 @@ class Puppet::Parser::AST # define all of the arguments in our local scope if self.args - # Verify that all required arguments are either present or # have been provided with defaults. # FIXME This should probably also require each parent # class's arguments... self.args.each { |arg, default| - unless hash.include?(arg) + unless arguments.include?(arg) if defined? default and ! default.nil? - hash[arg] = default + arguments[arg] = default #Puppet.debug "Got default %s for %s in %s" % # [default.inspect, arg.inspect, objname.inspect] else error = Puppet::ParseError.new( "Must pass %s to %s of type %s" % - [arg.inspect,name,objtype] + [arg.inspect,objname,@type] ) error.line = self.line error.file = self.file @@ -72,10 +87,10 @@ class Puppet::Parser::AST # Set each of the provided arguments as variables in the # component's scope. - hash["name"] = objname - hash.each { |arg,value| + arguments["name"] = objname + arguments.each { |arg,value| begin - scope.setvar(arg,hash[arg]) + scope.setvar(arg,arguments[arg]) rescue Puppet::ParseError => except except.line = self.line except.file = self.file @@ -94,7 +109,7 @@ class Puppet::Parser::AST } # Now just evaluate the code with our new bindings. - self.code.safeevaluate(scope) + self.code.safeevaluate(:scope => scope) # We return the scope, so that our children can make their scopes # under ours. This allows them to find our definitions. @@ -120,7 +135,7 @@ class Puppet::Parser::AST if found # It's a valid arg for us return true - elsif @parentclass + elsif defined? @parentclass and @parentclass # Else, check any existing parent parent = @scope.lookuptype(@parentclass) if parent and parent != [] diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index d6b323fb7..3952cd4dc 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -6,26 +6,45 @@ class Puppet::Parser::AST @name = :class attr_accessor :parentclass - def evaluate(scope,hash,objtype,objname) + #def evaluate(scope,hash,objtype,objname) + def evaluate(hash) + scope = hash[:scope] + objtype = hash[:type] + objname = hash[:name] + hash = hash[:arguments] # Verify that we haven't already been evaluated # FIXME The second subclass won't evaluate the parent class # code at all, and any overrides will throw an error. if scope.lookupclass(self.object_id) - Puppet.debug "%s class already evaluated" % @name + Puppet.debug "%s class already evaluated" % @type return nil end - if tmp = self.evalparent(scope, hash, objname) + # Default to creating a new context + newcontext = true + if parentscope = self.evalparent( + :scope => scope, :arguments => hash, :name => objname + ) # Override our scope binding with the parent scope # binding. This is quite hackish, but I can't think # of another way to make sure our scopes end up under # our parent scopes. - scope = tmp + scope = parentscope + + # But don't create a new context if our parent created one + newcontext = false end # just use the Component evaluate method, but change the type # to our own type - retval = super(scope,hash,@name,objname) + #retval = super(scope,hash,@name,objname) + retval = super( + :scope => scope, + :arguments => hash, + :type => @type, + :name => objname, + :newcontext => newcontext + ) # Set the mark after we evaluate, so we don't record it but # then encounter an error @@ -36,8 +55,14 @@ class Puppet::Parser::AST # Evaluate our parent class. Parent classes are evaluated in the # exact same scope as the children. This is maybe not a good idea # but, eh. - def evalparent(scope, args, name) + #def evalparent(scope, args, name) + def evalparent(hash) + scope = hash[:scope] + args = hash[:arguments] + name = hash[:name] if @parentclass + #scope.warning "parent class of %s is %s" % + # [@type, @parentclass.inspect] parentobj = nil begin @@ -65,13 +90,21 @@ class Puppet::Parser::AST unless parentobj.class == self.class error = Puppet::ParseError.new( "Class %s has incompatible parent type, %s vs %s" % - [@name, parentobj.class, self.class] + [@type, parentobj.class, self.class] ) error.file = self.file error.line = self.line raise error end - return parentobj.safeevaluate(scope,args,@parentclass,name) + # We don't need to pass the type, because the parent will just + # use its own type + return parentobj.safeevaluate( + :scope => scope, + :arguments => args, + :name => name + ) + else + return false end end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 5d70460ae..b0f9cca04 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -6,7 +6,7 @@ class Puppet::Parser::AST attr_accessor :value, :type # Return our value. - def evaluate(scope) + def evaluate(hash) return @value end @@ -44,8 +44,8 @@ class Puppet::Parser::AST class String < AST::Leaf # Interpolate the string looking for variables, and then return # the result. - def evaluate(scope) - return scope.strinterp(@value) + def evaluate(hash) + return hash[:scope].strinterp(@value) end end @@ -53,7 +53,7 @@ class Puppet::Parser::AST class FlatString < AST::Leaf # Interpolate the string looking for variables, and then return # the result. - def evaluate(scope) + def evaluate(hash) return @value end end @@ -74,9 +74,9 @@ class Puppet::Parser::AST class Variable < Name # Looks up the value of the object in the scope tree (does # not include syntactical constructs, like '$' and '{}'). - def evaluate(scope) + def evaluate(hash) begin - return scope.lookupvar(@value) + return hash[:scope].lookupvar(@value) rescue Puppet::ParseError => except except.line = self.line except.file = self.file diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index 2e33eb672..e8f4c5d87 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -5,18 +5,19 @@ class Puppet::Parser::AST @name = :node attr_accessor :name, :args, :code, :parentclass - def evaluate(scope, facts = {}) - scope = scope.newscope - + #def evaluate(scope, facts = {}) + def evaluate(hash) + scope = hash[:scope] + facts = hash[:facts] || {} # nodes are never instantiated like a normal object, # but we need the type to be the name users would use for # instantiation, otherwise tags don't work out - - # The name has already been evaluated, so it's a normal - # string. - scope.type = @name - scope.name = @name - scope.keyword = @keyword + scope = scope.newscope( + :type => @name, + :name => @name, + :keyword => @keyword + ) + scope.context = self.object_id # Mark this scope as a nodescope, so that classes will be # singletons within it @@ -40,7 +41,7 @@ class Puppet::Parser::AST #super(scope, facts, @name, @name) # And then evaluate our code. - @code.safeevaluate(scope) + @code.safeevaluate(:scope => scope) return scope end @@ -69,14 +70,18 @@ class Puppet::Parser::AST end node = hash[:node] - # Tag the scope with the parent's name/type. - name = node.name - #Puppet.info "Tagging with parent node %s" % name - scope.tag(name) + type = nil + if type = node.type + scope.tag(node.type) + end + + if name = node.name + scope.tag(node.name) unless name == type + end begin code = node.code - code.safeevaluate(scope) + code.safeevaluate(:scope => scope) rescue Puppet::ParseError => except except.line = self.line except.file = self.file diff --git a/lib/puppet/parser/ast/nodedef.rb b/lib/puppet/parser/ast/nodedef.rb index da93069b2..d41eeecde 100644 --- a/lib/puppet/parser/ast/nodedef.rb +++ b/lib/puppet/parser/ast/nodedef.rb @@ -10,8 +10,9 @@ class Puppet::Parser::AST end # Do implicit iteration over each of the names passed. - def evaluate(scope) - names = @names.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + names = @names.safeevaluate(:scope => scope) unless names.is_a?(Array) names = [names] @@ -26,7 +27,7 @@ class Puppet::Parser::AST } if @parentclass - arghash[:parentclass] = @parentclass.safeevaluate(scope) + arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope) end begin diff --git a/lib/puppet/parser/ast/objectdef.rb b/lib/puppet/parser/ast/objectdef.rb index e75b07ccb..4ed48d3a4 100644 --- a/lib/puppet/parser/ast/objectdef.rb +++ b/lib/puppet/parser/ast/objectdef.rb @@ -40,12 +40,13 @@ class Puppet::Parser::AST # Does not actually return an object; instead sets an object # in the current scope. - def evaluate(scope) + def evaluate(hash) + scope = hash[:scope] @scope = scope hash = {} # Get our type and name. - objtype = @type.safeevaluate(scope) + objtype = @type.safeevaluate(:scope => scope) # If the type was a variable, we wouldn't have typechecked yet. # Do it now, if so. @@ -70,17 +71,18 @@ class Puppet::Parser::AST end autonamed = false + objnames = [nil] # Autogenerate the name if one was not passed. - if defined? @name - objnames = @name.safeevaluate(scope) - else - objnames = self.autoname(objtype, object) - autonamed = true - end + if self.name + objnames = @name.safeevaluate(:scope => scope) + # it's easier to always use an array, even for only one name + unless objnames.is_a?(Array) + objnames = [objnames] + end + #else + # objnames = self.autoname(objtype, object) + # autonamed = true - # it's easier to always use an array, even for only one name - unless objnames.is_a?(Array) - objnames = [objnames] end # Retrieve the defaults for our type @@ -88,7 +90,7 @@ class Puppet::Parser::AST # then set all of the specified params @params.each { |param| - ary = param.safeevaluate(scope) + ary = param.safeevaluate(:scope => scope) hash[ary[0]] = ary[1] } @@ -99,6 +101,11 @@ class Puppet::Parser::AST # If the object is a class, that means it's a builtin type, so # we just store it in the scope unless object + unless objname + raise Puppet::ParseError, + "Object of type %s created with no name" % objtype + end + begin #Puppet.debug( # ("Setting object '%s' " + @@ -107,11 +114,11 @@ class Puppet::Parser::AST # [objname, scope.object_id, hash.inspect] #) obj = scope.setobject( - objtype, - objname, - hash, - @file, - @line + :type => objtype, + :name => objname, + :arguments => hash, + :file => @file, + :line => @line ) rescue Puppet::ParseError => except except.line = self.line @@ -129,7 +136,13 @@ class Puppet::Parser::AST # one of those, evaluate that with our arguments #Puppet.debug("Calling object '%s' with arguments %s" % # [object.name, hash.inspect]) - obj = object.safeevaluate(scope,hash,objtype,objname) + #obj = object.safeevaluate(scope,hash,objtype,objname) + obj = object.safeevaluate( + :scope => scope, + :arguments => hash, + :type => objtype, + :name => objname + ) # Retain any name generation stuff obj.autoname = autonamed diff --git a/lib/puppet/parser/ast/objectparam.rb b/lib/puppet/parser/ast/objectparam.rb index 41cd050ef..87c3e5e8e 100644 --- a/lib/puppet/parser/ast/objectparam.rb +++ b/lib/puppet/parser/ast/objectparam.rb @@ -8,9 +8,10 @@ class Puppet::Parser::AST end # Return the parameter and the value. - def evaluate(scope) - param = @param.safeevaluate(scope) - value = @value.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + param = @param.safeevaluate(:scope => scope) + value = @value.safeevaluate(:scope => scope) return [param, value] end diff --git a/lib/puppet/parser/ast/objectref.rb b/lib/puppet/parser/ast/objectref.rb index 6418c14fb..12e36360f 100644 --- a/lib/puppet/parser/ast/objectref.rb +++ b/lib/puppet/parser/ast/objectref.rb @@ -12,9 +12,10 @@ class Puppet::Parser::AST # Evaluate our object, but just return a simple array of the type # and name. - def evaluate(scope) - objtype = @type.safeevaluate(scope) - objnames = @name.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + objtype = @type.safeevaluate(:scope => scope) + objnames = @name.safeevaluate(:scope => scope) # it's easier to always use an array, even for only one name unless objnames.is_a?(Array) diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb index 51d880ed9..299473fda 100644 --- a/lib/puppet/parser/ast/selector.rb +++ b/lib/puppet/parser/ast/selector.rb @@ -9,21 +9,22 @@ class Puppet::Parser::AST end # Find the value that corresponds with the test. - def evaluate(scope) + def evaluate(hash) + scope = hash[:scope] retvalue = nil found = nil # Get our parameter. - paramvalue = @param.safeevaluate(scope) + paramvalue = @param.safeevaluate(:scope => scope) default = nil # Then look for a match in the options. @values.each { |obj| - param = obj.param.safeevaluate(scope) + param = obj.param.safeevaluate(:scope => scope) if param == paramvalue # we found a matching option - retvalue = obj.value.safeevaluate(scope) + retvalue = obj.value.safeevaluate(:scope => scope) found = true break elsif obj.param.is_a?(Default) @@ -34,7 +35,7 @@ class Puppet::Parser::AST # Unless we found something, look for the default. unless found if default - retvalue = default.value.safeevaluate(scope) + retvalue = default.value.safeevaluate(:scope => scope) else error = Puppet::ParseError.new( "No value for selector param '%s'" % paramvalue diff --git a/lib/puppet/parser/ast/typedefaults.rb b/lib/puppet/parser/ast/typedefaults.rb index c1f8cce52..e6ffe7080 100644 --- a/lib/puppet/parser/ast/typedefaults.rb +++ b/lib/puppet/parser/ast/typedefaults.rb @@ -10,9 +10,10 @@ class Puppet::Parser::AST # As opposed to ObjectDef, this stores each default for the given # object type. - def evaluate(scope) - type = @type.safeevaluate(scope) - params = @params.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + type = @type.safeevaluate(:scope => scope) + params = @params.safeevaluate(:scope => scope) begin scope.setdefaults(type.downcase,params) diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb index 52548a42c..4b1eb90d2 100644 --- a/lib/puppet/parser/ast/vardef.rb +++ b/lib/puppet/parser/ast/vardef.rb @@ -5,9 +5,10 @@ class Puppet::Parser::AST # Look up our name and value, and store them appropriately. The # lexer strips off the syntax stuff like '$'. - def evaluate(scope) - name = @name.safeevaluate(scope) - value = @value.safeevaluate(scope) + def evaluate(hash) + scope = hash[:scope] + name = @name.safeevaluate(:scope => scope) + value = @value.safeevaluate(:scope => scope) begin scope.setvar(name,value) diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 6e2a98aea..715adf064 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -494,7 +494,7 @@ import: IMPORT quotedtext { definition: DEFINE NAME argumentlist LBRACE statements RBRACE { result = AST::CompDef.new( - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :args => val[2], :file => @lexer.file, :line => @lexer.line, @@ -503,7 +503,7 @@ definition: DEFINE NAME argumentlist LBRACE statements RBRACE { ) } | DEFINE NAME argumentlist LBRACE RBRACE { result = AST::CompDef.new( - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :args => val[2], :file => @lexer.file, :line => @lexer.line, @@ -520,7 +520,7 @@ definition: DEFINE NAME argumentlist LBRACE statements RBRACE { hostclass: CLASS NAME parent LBRACE statements RBRACE { #:args => val[2], args = { - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :file => @lexer.file, :line => @lexer.line, :keyword => val[0], @@ -533,7 +533,7 @@ hostclass: CLASS NAME parent LBRACE statements RBRACE { result = AST::ClassDef.new(args) } | CLASS NAME parent LBRACE RBRACE { args = { - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :file => @lexer.file, :line => @lexer.line, :keyword => val[0], diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb index 1ad039f06..f9ee81f8c 100644 --- a/lib/puppet/parser/interpreter.rb +++ b/lib/puppet/parser/interpreter.rb @@ -195,14 +195,25 @@ module Puppet end # We've already evaluated the AST, in this case - return @scope.evalnode(names, facts, classes, parent) + #return @scope.evalnode(names, facts, classes, parent) + return @scope.evalnode( + :name => names, + :facts => facts, + :classes => classes, + :parent => parent + ) else # We've already evaluated the AST, in this case @scope = Puppet::Parser::Scope.new() # no parent scope @scope.interp = self @scope.type = "puppet" @scope.name = "top" - return @scope.evaluate(@ast, facts, @classes) + #return @scope.evaluate(@ast, facts, @classes) + return @scope.evaluate( + :ast => @ast, + :facts => facts, + :classes => @classes + ) end #@ast.evaluate(@scope) rescue Puppet::DevError, Puppet::Error, Puppet::ParseError => except @@ -233,7 +244,6 @@ module Puppet # this doesn't actually do anything, because we have to evaluate the # entire configuration each time we get a connect. def evaluate - # FIXME When this produces errors, it should specify which # node caused those errors. if @usenodes @@ -242,7 +252,7 @@ module Puppet @scope.type = "puppet" @scope.interp = self Puppet.debug "Nodes defined" - @ast.safeevaluate(@scope) + @ast.safeevaluate(:scope => @scope) else Puppet.debug "No nodes defined" return diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index f87c0d808..3030ea3fc 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -1,6 +1,6 @@ # # DO NOT MODIFY!!!! -# This file is automatically generated by racc 1.4.5 +# This file is automatically generated by racc 1.4.4 # from racc grammer file "grammar.ra". # @@ -29,7 +29,7 @@ module Puppet class Parser < Racc::Parser -module_eval <<'..end grammar.ra modeval..id352a7e96a4', 'grammar.ra', 718 +module_eval <<'..end grammar.ra modeval..id427de77f6a', 'grammar.ra', 718 attr_reader :file attr_accessor :files @@ -144,9 +144,9 @@ def string=(string) end # $Id$ -..end grammar.ra modeval..id352a7e96a4 +..end grammar.ra modeval..id427de77f6a -##### racc 1.4.5 generates ### +##### racc 1.4.4 generates ### racc_reduce_table = [ 0, 0, :racc_error, @@ -1195,7 +1195,7 @@ module_eval <<'.,.,', 'grammar.ra', 493 module_eval <<'.,.,', 'grammar.ra', 504 def _reduce_72( val, _values, result ) result = AST::CompDef.new( - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :args => val[2], :file => @lexer.file, :line => @lexer.line, @@ -1209,7 +1209,7 @@ module_eval <<'.,.,', 'grammar.ra', 504 module_eval <<'.,.,', 'grammar.ra', 517 def _reduce_73( val, _values, result ) result = AST::CompDef.new( - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :args => val[2], :file => @lexer.file, :line => @lexer.line, @@ -1228,7 +1228,7 @@ module_eval <<'.,.,', 'grammar.ra', 534 def _reduce_74( val, _values, result ) #:args => val[2], args = { - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :file => @lexer.file, :line => @lexer.line, :keyword => val[0], @@ -1246,7 +1246,7 @@ module_eval <<'.,.,', 'grammar.ra', 534 module_eval <<'.,.,', 'grammar.ra', 551 def _reduce_75( val, _values, result ) args = { - :name => AST::Name.new(:value => val[1], :line => @lexer.line), + :type => AST::Name.new(:value => val[1], :line => @lexer.line), :file => @lexer.file, :line => @lexer.line, :keyword => val[0], diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 3d1d690f5..b1b2b6b81 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -6,11 +6,13 @@ require 'puppet/transportable' module Puppet module Parser class Scope + Puppet::Util.logmethods(self) + include Enumerable attr_accessor :parent, :level, :interp attr_accessor :name, :type, :topscope, :base, :keyword, :autoname - attr_accessor :top + attr_accessor :top, :context # This is probably not all that good of an idea, but... # This way a parent can share its tables with all of its children. @@ -40,7 +42,7 @@ module Puppet obj.tags.each { |tag| unless list.include?(tag) if tag.nil? or tag == "" - Puppet.warning "Got tag %s from %s(%s)" % + Puppet.debug "Got tag %s from %s(%s)" % [tag.inspect, obj.type, obj.name] else list << tag @@ -49,6 +51,14 @@ module Puppet } end + def declarative=(val) + self.class.declarative = val + end + + def declarative + self.class.declarative + end + # Log the existing tags. At some point this should be in a better # place, but eh. def logtags @@ -169,7 +179,12 @@ module Puppet # Evaluate a specific node's code. This method will normally be called # on the top-level scope, but it actually evaluates the node at the # appropriate scope. - def evalnode(names, facts, classes = nil, parent = nil) + #def evalnode(names, facts, classes = nil, parent = nil) + def evalnode(hash) + names = hash[:name] + facts = hash[:facts] + classes = hash[:classes] + parent = hash[:parent] # First make sure there aren't any other node scopes lying around self.nodeclean @@ -203,7 +218,7 @@ module Puppet # Note that we evaluate the node code with its containing # scope, not with the top scope. We also retrieve the created # nodescope so that we can get any classes set within it - nodescope = code.safeevaluate(scope, facts) + nodescope = code.safeevaluate(:scope => scope, :facts => facts) # We don't need to worry about removing the Node code because # it will be removed during translation. @@ -246,12 +261,17 @@ module Puppet # Now evaluate it, which evaluates the parent but doesn't really # do anything else but does return the nodescope - scope = node.safeevaluate(self) + scope = node.safeevaluate(:scope => self) # And now evaluate each set klass within the nodescope. classes.each { |klass| if code = scope.lookuptype(klass) - code.safeevaluate(scope, {}, klass, klass) + #code.safeevaluate(scope, {}, klass, klass) + code.safeevaluate( + :scope => scope, + :facts => {}, + :type => klass + ) end } @@ -288,18 +308,26 @@ module Puppet # silly method, in that it just calls evaluate on the passed-in # objects, and then calls to_trans on itself. It just conceals # a paltry amount of info from whomever's using the scope object. - def evaluate(objects, facts = {}, classes = []) + #def evaluate(objects, facts = {}, classes = []) + def evaluate(hash) + objects = hash[:ast] + facts = hash[:facts] || {} + classes = hash[:classes] || [] facts.each { |var, value| self.setvar(var, value) } - objects.safeevaluate(self) + objects.safeevaluate(:scope => self) # These classes would be passed in manually, via something like # a cfengine module classes.each { |klass| if code = self.lookuptype(klass) - code.safeevaluate(self, {}, klass, klass) + code.safeevaluate( + :scope => self, + :facts => {}, + :type => klass + ) end } @@ -316,8 +344,20 @@ module Puppet # Initialize our new scope. Defaults to having no parent and to # being declarative. - def initialize(parent = nil, declarative = true) - @parent = parent + #def initialize(parent = nil, declarative = true) + def initialize(hash = {}) + @parent = nil + @type = nil + @name = nil + hash.each { |name, val| + method = name.to_s + "=" + if self.respond_to? method + self.send(method, val) + else + raise Puppet::DevError, "Invalid scope argument %s" % name + end + } + #@parent = hash[:parent] @nodescope = false @tags = [] @@ -326,12 +366,14 @@ module Puppet # the level is mostly used for debugging @level = 1 - @@declarative = declarative - # The table for storing class singletons. This will only actually # be used by top scopes and node scopes. @classtable = Hash.new(nil) + unless hash.include? :declarative + self.class.declarative = true + end + # The table for all defined objects. This will only be # used in the top scope if we don't have any nodescopes. @definedtable = Hash.new { |types, type| @@ -356,11 +398,14 @@ module Puppet names[name] = [] } } + + @context = nil else @parent.child = self @level = @parent.level + 1 @interp = @parent.interp @topscope = @parent.topscope + @context = @parent.context end # Our child scopes @@ -408,7 +453,7 @@ module Puppet # This method abstracts recursive searching. It accepts the type # of search being done and then either a literal key to search for or # a Proc instance to do the searching. - def lookup(type,sub) + def lookup(type,sub, usecontext = false) table = @map[type] if table.nil? error = Puppet::ParseError.new( @@ -423,7 +468,13 @@ module Puppet elsif table.include?(sub) return table[sub] elsif ! @parent.nil? - return @parent.lookup(type,sub) + #self.notice "Context is %s, parent %s is %s" % + # [self.context, @parent.type, @parent.context] + if usecontext and self.context != @parent.context + return :undefined + else + return @parent.lookup(type,sub, usecontext) + end else return :undefined end @@ -488,7 +539,8 @@ module Puppet end end - # Look up an object by name and type. + # Look up an object by name and type. This should only look up objects + # within a class structure, not within the entire scope structure. def lookupobject(name,type) #Puppet.debug "Looking up object %s of type %s in level %s" % # [name, type, @level] @@ -501,7 +553,7 @@ module Puppet nil end } - value = self.lookup("object",sub) + value = self.lookup("object",sub, true) if value == :undefined return nil else @@ -525,9 +577,10 @@ module Puppet end # Create a new scope. - def newscope + def newscope(hash = {}) + hash[:parent] = self #Puppet.debug "Creating new scope, level %s" % [self.level + 1] - return Puppet::Parser::Scope.new(self) + return Puppet::Parser::Scope.new(hash) end # Store the fact that we've evaluated a given class. We use a hash @@ -601,13 +654,21 @@ module Puppet # This method will fail if the named object is already defined anywhere # in the scope tree, which is what provides some minimal closure-like # behaviour. - def setobject(type, name, params, file, line) + #def setobject(type, name, params, file, line) + def setobject(hash) # FIXME This objectlookup stuff should be looking up using both # the name and the namevar. # First see if we can look the object up using normal scope # rules, i.e., one of our parent classes has defined the # object or something + + name = hash[:name] + type = hash[:type] + params = hash[:arguments] + file = hash[:file] + line = hash[:line] + obj = self.lookupobject(name,type) # If we can't find it... @@ -632,6 +693,7 @@ module Puppet end # And if it's not, then create it anew + #self.info "Adding %s[%s] to table" % [type, name] obj = @objectable[type][name] # only set these if we've created the object, which is the @@ -674,7 +736,8 @@ module Puppet def tag(*ary) ary.each { |tag| if tag.nil? or tag == "" - Puppet.warning "got told to tag with %s" % tag.inspect + Puppet.debug "got told to tag with %s" % tag.inspect + next end unless @tags.include?(tag) #Puppet.info "Tagging scope %s with %s" % [self.object_id, tag] @@ -693,7 +756,8 @@ module Puppet if @parent @parent.tags.each { |tag| if tag.nil? or tag == "" - Puppet.warning "parent returned tag %s" % tag.inspect + Puppet.debug "parent returned tag %s" % tag.inspect + next end unless tmp.include?(tag) tmp << tag @@ -703,6 +767,15 @@ module Puppet return tmp end + # Used mainly for logging + def to_s + if @name + return "%s[%s]" % [@type, @name] + else + return @type.to_s + end + end + # Convert our scope to a list of Transportable objects. def to_trans #Puppet.debug "Translating scope %s at level %s" % @@ -765,10 +838,13 @@ module Puppet # If we have a name and type, then make a TransBucket, which # becomes a component. # Else, just stack all of the objects into the current bucket. - if defined? @name + if @type bucket = TransBucket.new - bucket.name = @name - bucket.autoname = self.autoname + + if defined? @name and @name + bucket.name = @name + bucket.autoname = self.autoname + end # it'd be nice not to have to do this... results.each { |result| |