diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-10-04 18:24:24 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-10-04 18:24:24 +0000 |
| commit | 28cee40689440388994a4768bd301ae32c8ecc05 (patch) | |
| tree | c865ab44f4c9247052cf83de16ffc8ebe8b15e54 /lib/puppet/parser/ast | |
| parent | e0e291332bd4676962a28c7b220ae5c5e9651c0a (diff) | |
| download | puppet-28cee40689440388994a4768bd301ae32c8ecc05.tar.gz puppet-28cee40689440388994a4768bd301ae32c8ecc05.tar.xz puppet-28cee40689440388994a4768bd301ae32c8ecc05.zip | |
Merging the changes from the override-refactor branch. This is a significant rewrite of the parser, but it has little affect on the rest of the code tree.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1726 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/parser/ast')
20 files changed, 654 insertions, 1137 deletions
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index c42f658fd..fb0a3f671 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -25,14 +25,10 @@ class Puppet::Parser::AST # 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. - definelist = [ - AST::CompDef, AST::NodeDef, AST::ClassDef - ] setlist = [ - AST::VarDef, AST::TypeDefaults, AST::Function + AST::VarDef, AST::ResourceDefaults, AST::Function ] - definers = [] settors = [] others = [] @@ -53,15 +49,13 @@ class Puppet::Parser::AST # Now sort them all according to the type of action items.each { |child| - if definelist.include?(child.class) - definers << child - elsif setlist.include?(child.class) + if setlist.include?(child.class) settors << child else others << child end } - rets = [definers, settors, others].flatten.collect { |child| + rets = [settors, others].flatten.collect { |child| child.safeevaluate(:scope => scope) } else @@ -107,37 +101,7 @@ class Puppet::Parser::AST # 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 ObjectInst < ASTArray; end - - # Another simple container class to make sure we can correctly arrayfy - # things. - class CompArgument < ASTArray - @@warnings = {} - def initialize(hash) - super - name = @children[0].value - - # If it's not a metaparamer, we're fine. - return unless Puppet::Type.metaparamclass(name) - - if @children[1] - if @children[1].value == false - raise Puppet::ParseError, - "%s is a metaparameter; please choose another name" % - name - else - unless @@warnings[name] - @@warnings[name] = true - Puppet.warning "%s is a metaparam; this value will inherit to all contained elements" % name - end - end - else - raise Puppet::ParseError, - "%s is a metaparameter; please choose another name" % - name - end - end - end + class ResourceInst < ASTArray; end end # $Id$ diff --git a/lib/puppet/parser/ast/classdef.rb b/lib/puppet/parser/ast/classdef.rb deleted file mode 100644 index e09db985f..000000000 --- a/lib/puppet/parser/ast/classdef.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'puppet/parser/ast/compdef' - -class Puppet::Parser::AST - # Define a new class. Syntactically similar to component definitions, - # but classes are always singletons -- only one can exist on a given - # host. - class ClassDef < AST::CompDef - @keyword = "class" - - def self.genclass - AST::HostClass - end - - def each - if @parentclass - #[@type,@args,@parentclass,@code].each { |child| yield child } - [@type,@parentclass,@code].each { |child| yield child } - else - #[@type,@args,@code].each { |child| yield child } - [@type,@code].each { |child| yield child } - end - end - - # Store our parse tree according to type. - def disabled_evaluate(hash) - scope = hash[:scope] - type = @type.safeevaluate(:scope => scope) - #args = @args.safeevaluate(:scope => scope) - - #:args => args, - arghash = { - :type => type, - :code => @code - } - - if @parentclass - arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope) - end - - #Puppet.debug("defining hostclass '%s' with arguments [%s]" % - # [type,args]) - - begin - hclass = HostClass.new(arghash) - hclass.keyword = self.keyword - scope.settype(type, hclass) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error - end - end - - def tree(indent = 0) - #@args.tree(indent + 1), - return [ - @type.tree(indent + 1), - ((@@indline * 4 * indent) + self.typewrap("class")), - @parentclass ? @parentclass.tree(indent + 1) : "", - @code.tree(indent + 1), - ].join("\n") - end - - def to_s - return "class %s(%s) inherits %s {\n%s }" % - [@type, @parentclass, @code] - #[@type, @args, @parentclass, @code] - end - end - -end diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 8e9acce57..fa480b179 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -1,91 +1,30 @@ -require 'puppet/rails' +require 'puppet' +require 'puppet/parser/ast/branch' +require 'puppet/parser/collector' +# An object that collects stored objects from the central cache and returns +# them to the current host, yo. class Puppet::Parser::AST - # An object that collects stored objects from the central cache and returns - # them to the current host, yo. - class Collection < AST::Branch - attr_accessor :type +class Collection < AST::Branch + attr_accessor :type, :query, :form - # We cannot evaluate directly here; instead we need to store a - # CollectType object, which will do the collection. This is - # the only way to find certain exported types in the current - # configuration. - def evaluate(hash) - scope = hash[:scope] + # We return an object that does a late-binding evaluation. + def evaluate(hash) + scope = hash[:scope] - @convertedtype = @type.safeevaluate(:scope => scope) - - scope.newcollection(self) + if self.query + q = self.query.safeevaluate :scope => scope + else + q = nil end - # Now perform the actual collection, yo. - def perform(scope) - # First get everything from the export table. - - # FIXME This will only find objects that are before us in the tree, - # which is a problem. - objects = scope.exported(@convertedtype) - - # We want to return all of these objects, and then whichever objects - # we find in the db. - array = objects.values - - # Mark all of these objects as collected, so that they also get - # returned to the client. We don't store them in our scope - # or anything, which is a little odd, but eh. - array.each do |obj| - obj.collected = true - end - - count = array.length - - # Now we also have to see if there are any exported objects - # in our own scope. - scope.lookupexported(@convertedtype).each do |obj| - objects[obj.name] = obj - obj.collected = true - end - - bucket = Puppet::TransBucket.new - - Puppet::Rails::RailsObject.find_all_by_collectable(true).each do |obj| - # FIXME This should check that the source of the object is the - # host we're running on, else it's a bad conflict. - if objects.include?(obj.name) - scope.debug("%s[%s] is already exported" % [@convertedtype, obj.name]) - next - end - count += 1 - trans = obj.to_trans - bucket.push(trans) + newcoll = Puppet::Parser::Collector.new(scope, @type, q, self.form) - args = { - :name => trans.name, - :type => trans.type, - } + scope.newcollection(newcoll) - [:file, :line].each do |param| - if val = trans.send(param) - args[param] = val - end - end - - args[:arguments] = {} - trans.each do |p,v| args[:arguments][p] = v end - - - # XXX Because the scopes don't expect objects to return values, - # we have to manually add our objects to the scope. This is - # uber-lame. - scope.setobject(args) - end - - scope.debug("Collected %s objects of type %s" % - [count, @convertedtype]) - - return bucket - end + newcoll end end +end # $Id$ diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb new file mode 100644 index 000000000..f69b2e92e --- /dev/null +++ b/lib/puppet/parser/ast/collexpr.rb @@ -0,0 +1,81 @@ +require 'puppet' +require 'puppet/parser/ast/branch' +require 'puppet/parser/collector' + +# An object that collects stored objects from the central cache and returns +# them to the current host, yo. +class Puppet::Parser::AST +class CollExpr < AST::Branch + attr_accessor :test1, :test2, :oper, :form, :type, :parens + + # We return an object that does a late-binding evaluation. + def evaluate(hash) + scope = hash[:scope] + + # Make sure our contained expressions have all the info they need. + [@test1, @test2].each do |t| + if t.is_a?(self.class) + t.form ||= self.form + t.type ||= self.type + end + end + + # The code is only used for virtual lookups + str1, code1 = @test1.safeevaluate :scope => scope + str2, code2 = @test2.safeevaluate :scope => scope + + # First build up the virtual code. + # If we're a conjunction operator, then we're calling code. I did + # some speed comparisons, and it's at least twice as fast doing these + # case statements as doing an eval here. + code = proc do |resource| + case @oper + when "and": code1.call(resource) and code2.call(resource) + when "or": code1.call(resource) or code2.call(resource) + when "==": resource[str1] == str2 + when "!=": resource[str1] != str2 + end + end + + # Now build up the rails conditions code + if self.parens and self.form == :exported + Puppet.warning "Parentheses are ignored in Rails searches" + end + + case @oper + when "and", "or": oper = @oper.upcase + when "==": oper = "=" + else + oper = @oper + end + + if oper == "=" or oper == "!=" + # Add the rails association info where necessary + if str1 == "title" + str = "title #{oper} '#{str2}'" + else + unless self.form == :virtual or str1 == "title" + parsefail "Collection from the database only supports " + + "title matching currently" + end + str = "rails_parameters.name = '#{str1}' and " + + "rails_parameters.value #{oper} '#{str2}'" + end + else + str = [str1, oper, str2].join(" ") + end + + return str, code + end + + def initialize(hash = {}) + super + + unless %w{== != and or}.include?(@oper) + raise ArgumentError, "Invalid operator %s" % @oper + end + end +end +end + +# $Id$ diff --git a/lib/puppet/parser/ast/compdef.rb b/lib/puppet/parser/ast/compdef.rb deleted file mode 100644 index 17ee60181..000000000 --- a/lib/puppet/parser/ast/compdef.rb +++ /dev/null @@ -1,98 +0,0 @@ -class Puppet::Parser::AST - # Define a new component. This basically just stores the - # associated parse tree by name in our current scope. Note that - # there is currently a mismatch in how we look up components -- it - # usually uses scopes, but sometimes uses '@@settypes'. - # FIXME This class should verify that each of its direct children - # has an abstractable name -- i.e., if a file does not include a - # variable in its name, then the user is essentially guaranteed to - # encounter an error if the component is instantiated more than - # once. - class CompDef < AST::Branch - attr_accessor :type, :args, :code, :scope, :parentclass - attr_writer :keyword - - @keyword = "define" - - class << self - attr_reader :keyword - end - - - def self.genclass - AST::Component - end - - def each - [@type,@args,@code].each { |child| yield child } - end - - # Store the parse tree. - def evaluate(hash) - scope = hash[:scope] - arghash = {:code => @code} - arghash[:type] = @type.safeevaluate(:scope => scope) - - if @args - arghash[:args] = @args.safeevaluate(:scope => scope) - end - - if @parentclass - arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope) - end - - - begin - comp = self.class.genclass.new(arghash) - comp.keyword = self.keyword - scope.settype(arghash[:type], comp) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error - end - end - - def initialize(hash) - @parentclass = nil - @args = nil - super - - #if @parentclass - # Puppet.notice "Parent class of %s is %s" % - # [@type.value, @parentclass.value] - #end - - #Puppet.debug "Defining type %s" % @type.value - end - - def keyword - if defined? @keyword - @keyword - else - self.class.keyword - end - end - - def tree(indent = 0) - return [ - @type.tree(indent + 1), - ((@@indline * 4 * indent) + self.typewrap("define")), - @args.tree(indent + 1), - @code.tree(indent + 1), - ].join("\n") - end - - def to_s - return "define %s(%s) {\n%s }" % [@type, @args, @code] - end - end -end - -# $Id$ diff --git a/lib/puppet/parser/ast/component.rb b/lib/puppet/parser/ast/component.rb index ebbf21959..312b11d99 100644 --- a/lib/puppet/parser/ast/component.rb +++ b/lib/puppet/parser/ast/component.rb @@ -1,80 +1,68 @@ +require 'puppet/parser/ast/branch' + class Puppet::Parser::AST # Evaluate the stored parse tree for a given component. This will # receive the arguments passed to the component and also the type and # name of the component. class Component < AST::Branch + include Puppet::Util + include Puppet::Util::Warnings + include Puppet::Util::MethodHelper class << self attr_accessor :name end # The class name - @name = :component + @name = :definition - attr_accessor :type, :args, :code, :scope, :keyword - attr_accessor :collectable, :parentclass + attr_accessor :type, :arguments, :code, :scope, :keyword + attr_accessor :exported, :namespace, :fqname, :interp # These are retrieved when looking up the superclass - attr_accessor :name, :arguments + attr_accessor :name def evaluate(hash) origscope = hash[:scope] objtype = hash[:type] - @name = hash[:name] - @arguments = hash[:arguments] || {} + name = hash[:name] + args = symbolize_options(hash[:arguments] || {}) - @collectable = hash[:collectable] + exported = hash[:exported] pscope = origscope - #pscope = if ! Puppet[:lexical] or hash[:asparent] == false - # origscope - #else - # @scope - #end - scope = pscope.newscope( - :type => @type, - :name => @name, - :keyword => self.keyword - ) - newcontext = hash[:newcontext] + scope = subscope(pscope, name) - if @collectable or origscope.collectable - scope.collectable = true + if exported or origscope.exported? + scope.exported = true end - - unless self.is_a? AST::HostClass and ! newcontext - #scope.warning "Setting context to %s" % self.object_id - scope.context = self.object_id - end - @scope = scope - + scope = scope # Additionally, add a tag for whatever kind of class # we are - scope.tag(@type) + if @type != "" + scope.tag(@type) + end - unless @name.nil? - scope.tag(@name) + unless name.nil? or name =~ /[^\w]/ + scope.tag(name) end # define all of the arguments in our local scope - if self.args + if self.arguments # 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 @arguments.include?(arg) + self.arguments.each { |arg, default| + arg = symbolize(arg) + unless args.include?(arg) if defined? default and ! default.nil? - @arguments[arg] = default + default = default.safeevaluate :scope => scope + args[arg] = default #Puppet.debug "Got default %s for %s in %s" % # [default.inspect, arg.inspect, @name.inspect] else - error = Puppet::ParseError.new( - "Must pass %s to %s of type %s" % - [arg.inspect,@name,@type] - ) - error.line = self.line - error.file = self.file - raise error + parsefail "Must pass %s to %s of type %s" % + [arg,name,@type] end end } @@ -82,54 +70,116 @@ class Puppet::Parser::AST # Set each of the provided arguments as variables in the # component's scope. - @arguments.each { |arg,value| - begin - scope.setvar(arg,@arguments[arg]) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => except - error = Puppet::ParseError.new(except.message) - error.line = self.line - error.file = self.file - error.set_backtrace except.backtrace - raise error + args.each { |arg,value| + unless validattr?(arg) + parsefail "%s does not accept attribute %s" % [@type, arg] + end + + exceptwrap do + scope.setvar(arg.to_s,args[arg]) end } - unless @arguments.include? "name" - scope.setvar("name",@name) + unless args.include? "name" + scope.setvar("name",name) end - # Now just evaluate the code with our new bindings. - #scope.inside(self) do # part of definition inheritance - self.code.safeevaluate(:scope => scope) - #end + if self.code + return self.code.safeevaluate(:scope => scope) + else + return nil + end + end + + def initialize(hash = {}) + @arguments = nil + @parentclass = nil + super + + # Deal with metaparams in the argument list. + if @arguments + @arguments.each do |arg, defvalue| + next unless Puppet::Type.metaparamclass(arg) + if defvalue + warnonce "%s is a metaparam; this value will inherit to all contained elements" % arg + else + raise Puppet::ParseError, + "%s is a metaparameter; please choose another name" % + name + end + end + end + end + + def parentclass + parentobj do |name| + @interp.findclass(namespace, name) + end + end - # If we're being evaluated as a parent class, we want to return the - # scope, so it can be overridden and such, but if not, we want to - # return a TransBucket of our objects. - if hash.include?(:asparent) - return scope + # Set our parent class, with a little check to avoid some potential + # weirdness. + def parentclass=(name) + if name == @type + parsefail "Parent classes must have dissimilar names" + end + + @parentclass = name + end + + # Hunt down our class object. + def parentobj + if @parentclass + # Cache our result, since it should never change. + unless @parentclass.is_a?(AST::HostClass) + unless tmp = yield(@parentclass) + parsefail "Could not find %s %s" % [self.class.name, @parentclass] + end + + if tmp == self + parsefail "Parent classes must have dissimilar names" + end + + @parentclass = tmp + end + @parentclass else - return scope.to_trans + nil end end + # Create a new subscope in which to evaluate our code. + def subscope(scope, name = nil) + args = { + :type => @type, + :keyword => self.keyword, + :namespace => self.namespace + } + + args[:name] = name if name + args[:type] = self.type if self.type + scope = scope.newscope(args) + scope.source = self + + return scope + end + + def to_s + fqname + end + # Check whether a given argument is valid. Searches up through # any parent classes that might exist. - def validarg?(param) + def validattr?(param) + return true if Puppet::Type.metaparam?(param) + + param = param.to_s found = false - unless @args.is_a? Array - @args = [@args] + unless @arguments.is_a? Array + @arguments = [@arguments] end - found = @args.detect { |arg| + found = @arguments.detect { |arg| if arg.is_a? Array arg[0] == param else diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 2c63c8b76..f67531ae3 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -11,7 +11,10 @@ class Puppet::Parser::AST args = @arguments.safeevaluate(:scope => scope) - return scope.send("function_" + @name, args) + #exceptwrap :message => "Failed to execute %s" % @name, + # :type => Puppet::ParseError do + return scope.send("function_" + @name, args) + #end end def initialize(hash) diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb index 44077983d..4a4664f0f 100644 --- a/lib/puppet/parser/ast/hostclass.rb +++ b/lib/puppet/parser/ast/hostclass.rb @@ -1,3 +1,5 @@ +require 'puppet/parser/ast/component' + class Puppet::Parser::AST # The code associated with a class. This is different from components # in that each class is a singleton -- only one will exist for a given @@ -5,152 +7,50 @@ class Puppet::Parser::AST class HostClass < AST::Component @name = :class + # Are we a child of the passed class? Do a recursive search up our + # parentage tree to figure it out. + def child_of?(klass) + return false unless self.parentclass + + if klass == self.parentclass + return true + else + return self.parentclass.child_of?(klass) + end + end + + # Evaluate the code associated with this class. def evaluate(hash) scope = hash[:scope] - objname = hash[:name] args = 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 myscope = scope.lookupclass(self.object_id) + if scope.setclass?(self) Puppet.debug "%s class already evaluated" % @type - - # Not used, but will eventually be used to fix #140. - if myscope.is_a? Puppet::Parser::Scope - unless scope.object_id == myscope.object_id - #scope.parent = myscope - end - end return nil end - # Set the class before we do anything else, so that it's set - # during the evaluation and can be inspected. - scope.setclass(self.object_id, @type) - - origscope = scope - - # Default to creating a new context - newcontext = true - - # If we've got a parent, then we pass it the original scope we - # received. It will get passed all the way up to the top class, - # which will create a subscope and pass that subscope to its - # subclass. - if @parentscope = self.evalparent( - :scope => scope, :arguments => args, :name => objname - ) - if @parentscope.is_a? Puppet::TransBucket - raise Puppet::DevError, "Got a bucket instead of a scope" - end - - # Override our scope binding with the parent scope - # binding. - 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. - result = super( - :scope => scope, - :arguments => args, - :type => @type, - :name => objname, # might be nil - :newcontext => newcontext, - :asparent => hash[:asparent] || false # might be nil - ) - - # Now set the class again, this time using the scope. This way - # we can look up the parent scope of this class later, so we - # can hook the children together. - scope.setscope(self.object_id, result) - - # This is important but painfully difficult. If we're the top-level - # class, that is, we have no parent classes, then the transscope - # is our own scope, but if there are parent classes, then the topmost - # parent's scope is the transscope, since it contains its code and - # all of the subclass's code. - transscope ||= result - - if hash[:asparent] - # If we're a parent class, then return the scope object itself. - return result - else - transscope = nil - if @parentscope - transscope = @parentscope - until transscope.parent.object_id == origscope.object_id - transscope = transscope.parent - end + if @parentclass + if pklass = self.parentclass + pklass.safeevaluate :scope => scope else - transscope = result + parsefail "Could not find class %s" % @parentclass end - - # But if we're the final subclass, translate the whole scope tree - # into TransObjects and TransBuckets. - return transscope.to_trans end - end - # 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(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 + # Set the class before we do anything else, so that it's set + # during the evaluation and can be inspected. + scope.setclass(self) - begin - parentobj = scope.lookuptype(@parentclass) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - raise error - end - unless parentobj - error = Puppet::ParseError.new( - "Could not find parent '%s' of '%s'" % - [@parentclass,@name]) - error.line = self.line - error.file = self.file - raise error - end + unless hash[:nosubscope] + scope = subscope(scope) + end - # Verify that the parent and child are of the same type - unless parentobj.class == self.class - error = Puppet::ParseError.new( - "Class %s has incompatible parent type, %s vs %s" % - [@type, parentobj.class, self.class] - ) - error.file = self.file - error.line = self.line - raise error - end - # We don't need to pass the type, because the parent will just - # use its own type. Specify that it's being evaluated as a parent, - # so that it returns the scope, not a transbucket. - return parentobj.safeevaluate( - :scope => scope, - :arguments => args, - :name => name, - :asparent => true, - :collectable => self.collectable - ) + # Now evaluate our code, yo. + if self.code + return self.code.evaluate(:scope => scope) else - return false + return nil end end @@ -158,7 +58,7 @@ class Puppet::Parser::AST @parentclass = nil super end - end - end + +# $Id$ diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 7b9a283d7..298c0168f 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -28,15 +28,11 @@ class Puppet::Parser::AST def initialize(hash) super - unless @value == 'true' or @value == 'false' + unless @value == true or @value == false raise Puppet::DevError, "'%s' is not a boolean" % @value end - if @value == 'true' - @value = true - else - @value = false - end + @value end end @@ -69,6 +65,9 @@ class Puppet::Parser::AST # Lower-case words. class Name < AST::Leaf; end + # double-colon separated class names + class ClassName < AST::Leaf; end + # Host names, either fully qualified or just the short name class HostName < AST::Leaf def initialize(hash) @@ -87,18 +86,8 @@ class Puppet::Parser::AST # Looks up the value of the object in the scope tree (does # not include syntactical constructs, like '$' and '{}'). def evaluate(hash) - begin + parsewrap do return hash[:scope].lookupvar(@value) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::DevError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error end end end diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb index e4e69bed9..3f508b2bf 100644 --- a/lib/puppet/parser/ast/node.rb +++ b/lib/puppet/parser/ast/node.rb @@ -1,113 +1,70 @@ +require 'puppet/parser/ast/hostclass' + class Puppet::Parser::AST # The specific code associated with a host. Nodes are annoyingly unlike # other objects. That's just the way it is, at least for now. class Node < AST::HostClass @name = :node - attr_accessor :type, :args, :code, :parentclass + attr_accessor :name #def evaluate(scope, facts = {}) def evaluate(hash) - origscope = 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 + scope = hash[:scope] - pscope = origscope #pscope = if ! Puppet[:lexical] or hash[:asparent] # @scope #else # origscope #end - scope = pscope.newscope( - :type => self.type, - :keyword => @keyword - ) - scope.context = self.object_id + Puppet.warning "%s => %s" % [scope.type, self.name] - # Now set all of the facts inside this scope - facts.each { |var, value| - scope.setvar(var, value) - } - - if tmp = self.evalparent(scope) - # Again, override our scope with the parent scope, if - # there is one. - scope = tmp + # We don't have to worry about the declarativeness of node parentage, + # because the entry point is always a single node definition. + if parent = self.parentclass + scope = parent.safeevaluate :scope => scope end + Puppet.notice "%s => %s" % [scope.type, self.name] - #scope.tag(@name) - - # We never pass the facts to the parent class, because they've - # already been defined at this top-level scope. - #super(scope, facts, @name, @name) + scope = scope.newscope( + :type => self.name, + :keyword => @keyword, + :source => self, + :namespace => "" # nodes are always in "" + ) + Puppet.info "%s => %s" % [scope.type, self.name] # Mark our node name as a class, too, but strip it of the domain # name. Make the mark before we evaluate the code, so that it is # marked within the code itself. - scope.setclass(self.object_id, @type.sub(/\..+/, '')) + scope.setclass(self) - # And then evaluate our code. - @code.safeevaluate(:scope => scope) + # And then evaluate our code if we have any + if self.code + @code.safeevaluate(:scope => scope) + end return scope end - # Evaluate our parent class. - def evalparent(scope) - if @parentclass - # This is pretty messed up. I don't know if this will - # work in the long term, but we need to evaluate the node - # in our own scope, even though our parent node has - # a scope associated with it, because otherwise we 1) won't - # get our facts defined, and 2) we won't actually get the - # objects returned, based on how nodes work. - - # We also can't just evaluate the node itself, because - # it would create a node scope within this scope, - # and that would cause mass havoc. - node = nil - - # The 'node' method just returns a hash of the node - # code and name. It's used here, and in 'evalnode'. - unless hash = scope.node(@parentclass) - raise Puppet::ParseError, - "Could not find parent node %s" % - @parentclass - end - - node = hash[:node] - type = nil - if type = node.type - scope.tag(node.type) - end - - begin - code = node.code - code.safeevaluate(:scope => scope, :asparent => true) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - raise error - end + def initialize(hash) + @parentclass = nil + super - if node.parentclass - node.evalparent(scope) - end + # Do some validation on the node name + if @name =~ /[^-\w.]/ + raise Puppet::ParseError, "Invalid node name %s" % @name end end - def initialize(hash) - @parentclass = nil - super + def parentclass + parentobj do |name| + @interp.nodesearch(name) + end + @parentclass end end end + +# $Id$ diff --git a/lib/puppet/parser/ast/nodedef.rb b/lib/puppet/parser/ast/nodedef.rb deleted file mode 100644 index 06b104828..000000000 --- a/lib/puppet/parser/ast/nodedef.rb +++ /dev/null @@ -1,73 +0,0 @@ -class Puppet::Parser::AST - # Define a node. The node definition stores a parse tree for each - # specified node, and this parse tree is only ever looked up when - # a client connects. - class NodeDef < AST::Branch - attr_accessor :names, :code, :parentclass, :keyword, :scope - - def each - [@names,@code].each { |child| yield child } - end - - # Do implicit iteration over each of the names passed. - def evaluate(hash) - scope = hash[:scope] - names = @names.safeevaluate(:scope => scope) - - unless names.is_a?(Array) - names = [names] - end - - names.each { |name| - #Puppet.debug("defining host '%s' in scope %s" % - # [name, scope.object_id]) - # We use 'type' here instead of name, because every component - # type supports both 'type' and 'name', and 'type' is a more - # appropriate description of the syntactic role that this term - # plays. - arghash = { - :type => name, - :code => @code - } - - if @parentclass - arghash[:parentclass] = @parentclass.safeevaluate(:scope => scope) - end - - begin - node = Node.new(arghash) - node.keyword = true - scope.setnode(name, node) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - raise error - end - } - end - - def initialize(hash) - @parentclass = nil - @keyword = "node" - super - end - - def tree(indent = 0) - return [ - @names.tree(indent + 1), - ((@@indline * 4 * indent) + self.typewrap("node")), - @code.tree(indent + 1), - ].join("\n") - end - - def to_s - return "node %s {\n%s }" % [@name, @code] - end - end - -end diff --git a/lib/puppet/parser/ast/objectdef.rb b/lib/puppet/parser/ast/objectdef.rb deleted file mode 100644 index ac5fe3070..000000000 --- a/lib/puppet/parser/ast/objectdef.rb +++ /dev/null @@ -1,353 +0,0 @@ -class Puppet::Parser::AST - # Any normal puppet object declaration. Can result in a class or a - # component, in addition to builtin types. - class ObjectDef < AST::Branch - attr_accessor :name, :type, :collectable - attr_reader :params - - # probably not used at all - def []=(index,obj) - @params[index] = obj - end - - # probably not used at all - def [](index) - return @params[index] - end - - # Iterate across all of our children. - def each - [@type,@name,@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] - @scope = scope - hash = {} - - # Get our type and name. - objtype = @type.safeevaluate(:scope => scope) - - # Disable definition inheritance, for now. 8/27/06, luke - #if objtype == "super" - # objtype = supertype() - # @subtype = true - #else - @subtype = false - #end - - # If the type was a variable, we wouldn't have typechecked yet. - # Do it now, if so. - unless @checked - self.typecheck(objtype) - end - - # See if our object type was defined. If not, we know it's - # builtin because we already typechecked. - begin - object = scope.lookuptype(objtype) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error - end - - hash = {} - # Evaluate all of the specified params. - @params.each { |param| - ary = param.safeevaluate(:scope => scope) - hash[ary[0]] = ary[1] - } - - # Now collect info from our parent. - parentname = nil - if @subtype - parentname = supersetup(hash) - end - - objnames = [nil] - # Determine our name if we have one. - 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 - if parentname - objnames = [parentname] - else - # See if they specified the name as a parameter instead of - # as a normal name (i.e., before the colon). - unless object # we're a builtin - if objclass = Puppet::Type.type(objtype) - namevar = objclass.namevar - - tmp = hash["name"] || hash[namevar.to_s] - - if tmp - objnames = [tmp] - end - else - # this should never happen, because we've already - # typechecked, but it's no real problem if it does - # happen. We just end up with an object with no - # name. - end - end - end - end - - # 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 - objnames.collect { |objname| - # If the object is a class, that means it's a builtin type, so - # we just store it in the scope - begin - #Puppet.debug( - # ("Setting object '%s' " + - # "in scope %s " + - # "with arguments %s") % - # [objname, scope.object_id, hash.inspect] - #) - obj = scope.setobject( - :type => objtype, - :name => objname, - :arguments => hash, - :file => @file, - :line => @line, - :collectable => self.collectable - ) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error - end - }.reject { |obj| obj.nil? } - end - - # Create our ObjectDef. Handles type checking for us. - def initialize(hash) - @checked = false - super - - #self.typecheck(@type.value) - end - - # Verify that all passed parameters are valid - def paramcheck(builtin, objtype) - # This defaults to true - unless Puppet[:paramcheck] - return - end - - @params.each { |param| - if builtin - self.parambuiltincheck(builtin, param) - else - self.paramdefinedcheck(objtype, param) - end - } - - # Mark that we've made it all the way through. - @checked = true - end - - def parambuiltincheck(type, param) - unless param.is_a?(AST::ObjectParam) - raise Puppet::DevError, - "Got something other than param" - end - begin - pname = param.param.value - rescue => detail - raise Puppet::DevError, detail.to_s - end - - return if pname == "name" # always allow these - unless type.validattr?(pname) - error = Puppet::ParseError.new( - "Invalid parameter '%s' for type '%s'" % - [pname, type.name] - ) - error.line = self.line - error.file = self.file - raise error - end - end - - def paramdefinedcheck(objtype, param) - # FIXME We might need to do more here eventually. Metaparams - # behave strangely on containers. - if Puppet::Type.metaparam?(param.param.value.intern) - return - end - - begin - pname = param.param.value - rescue => detail - raise Puppet::DevError, detail.to_s - end - - unless objtype.validarg?(pname) - error = Puppet::ParseError.new( - "Invalid parameter '%s' for type '%s'" % - [pname,objtype.type] - ) - error.line = self.line - error.file = self.file - raise error - end - 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 - - def supercomp - unless defined? @supercomp - if @scope and comp = @scope.inside - @supercomp = comp - else - error = Puppet::ParseError.new( - "'super' is only valid within definitions" - ) - error.line = self.line - error.file = self.file - raise error - end - end - @supercomp - end - - # Take all of the arguments of our parent and add them into our own, - # without overriding anything. - def supersetup(hash) - comp = supercomp() - - # Now check each of the arguments from the parent. - comp.arguments.each do |name, value| - unless hash.has_key? name - hash[name] = value - end - end - - # Return the parent name, so it can be used if appropriate. - return comp.name - end - - # Retrieve our supertype. - def supertype - unless defined? @supertype - if parent = supercomp.parentclass - @supertype = parent - else - error = Puppet::ParseError.new( - "%s does not have a parent class" % comp.type - ) - error.line = self.line - error.file = self.file - raise error - end - end - @supertype - end - - # Print this object out. - def tree(indent = 0) - return [ - @type.tree(indent + 1), - @name.tree(indent + 1), - ((@@indline * indent) + self.typewrap(self.pin)), - @params.collect { |param| - begin - param.tree(indent + 1) - rescue NoMethodError => detail - Puppet.err @params.inspect - error = Puppet::DevError.new( - "failed to tree a %s" % self.class - ) - error.set_backtrace detail.backtrace - raise error - end - }.join("\n") - ].join("\n") - end - - # Verify that the type is valid. This throws an error if there's - # a problem, so the return value doesn't matter - def typecheck(objtype) - # This will basically always be on, but I wanted to make it at - # least simple to turn off if it came to that - unless Puppet[:typecheck] - return - end - - builtin = false - begin - builtin = Puppet::Type.type(objtype) - rescue TypeError - # nothing; we've already set builtin to false - end - - typeobj = nil - if builtin - self.paramcheck(builtin, objtype) - else - # If there's no set scope, then we're in initialize, not - # evaluate, so we can't test defined types. - return true unless defined? @scope and @scope - - # Unless we can look up the type, throw an error - unless typeobj = @scope.lookuptype(objtype) - error = Puppet::ParseError.new( - "Unknown type '%s'" % objtype - ) - error.line = self.line - error.file = self.file - raise error - end - - # Now that we have the type, verify all of the parameters. - # Note that we're now passing an AST Class object or whatever - # as the type, not a simple string. - self.paramcheck(builtin, typeobj) - end - end - - def to_s - return "%s => { %s }" % [@name, - @params.collect { |param| - param.to_s - }.join("\n") - ] - end - end -end diff --git a/lib/puppet/parser/ast/objectref.rb b/lib/puppet/parser/ast/objectref.rb deleted file mode 100644 index f9a63e222..000000000 --- a/lib/puppet/parser/ast/objectref.rb +++ /dev/null @@ -1,77 +0,0 @@ -class Puppet::Parser::AST - # A reference to an object. Only valid as an rvalue. - class ObjectRef < AST::Branch - attr_accessor :name, :type - - def each - [@type,@name].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] - 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) - objnames = [objnames] - end - - # See if we can look the object up in our scope tree. - begin - object = scope.lookuptype(objtype) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error - end - - # If the type isn't defined, verify that it's builtin - unless object or Puppet::Type.type(objtype) - error = Puppet::ParseError.new("Could not find type %s" % - objtype.inspect) - error.line = self.line - error.file = self.file - raise error - end - - # should we implicitly iterate here? - # yes, i believe that we essentially have to... - ret = objnames.collect { |objname| - if object.is_a?(AST::Component) - objname = "%s[%s]" % [objtype,objname] - objtype = "component" - end - [objtype,objname] - }.reject { |obj| obj.nil? } - - # Return a flattened array, since we know that we've created an - # array - return *ret - end - - def tree(indent = 0) - return [ - @type.tree(indent + 1), - @name.tree(indent + 1), - ((@@indline * indent) + self.typewrap(self.pin)) - ].join("\n") - end - - def to_s - return "%s[%s]" % [@name,@type] - end - end - -end diff --git a/lib/puppet/parser/ast/resourcedef.rb b/lib/puppet/parser/ast/resourcedef.rb new file mode 100644 index 000000000..1c9333030 --- /dev/null +++ b/lib/puppet/parser/ast/resourcedef.rb @@ -0,0 +1,215 @@ +require 'puppet/parser/ast/branch' + +# Any normal puppet object declaration. Can result in a class or a +# component, in addition to builtin types. +class Puppet::Parser::AST +class ResourceDef < AST::Branch + attr_accessor :title, :type, :exported, :virtual + attr_reader :params + + # probably not used at all + def []=(index,obj) + @params[index] = obj + end + + # probably not used at all + def [](index) + return @params[index] + end + + # Iterate across all of our children. + def each + [@type,@title,@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] + @scope = scope + hash = {} + + # Get our type and name. + objtype = @type + + # Disable definition inheritance, for now. 8/27/06, luke + #if objtype == "super" + # objtype = supertype() + # @subtype = true + #else + @subtype = false + #end + + # Evaluate all of the specified params. + paramobjects = @params.collect { |param| + param.safeevaluate(:scope => scope) + } + + # Now collect info from our parent. + parentname = nil + if @subtype + parentname = supersetup(hash) + end + + objtitles = nil + # Determine our name if we have one. + if self.title + 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 + else + if parentname + objtitles = [parentname] + else + # See if they specified the name as a parameter instead of + # as a normal name (i.e., before the colon). + unless object # we're a builtin + if objclass = Puppet::Type.type(objtype) + namevar = objclass.namevar + + tmp = hash["name"] || hash[namevar.to_s] + + if tmp + objtitles = [tmp] + end + else + # This isn't grammatically legal. + raise Puppet::ParseError, "Got a resource with no title" + end + end + end + end + + # 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 + obj = Puppet::Parser::Resource.new( + :type => objtype, + :title => objtitle, + :params => paramobjects, + :file => @file, + :line => @line, + :exported => self.exported || scope.exported, + :virtual => self.virtual, + :source => scope.source, + :scope => scope + ) + + # And then store the resource in the scope. + # XXX At some point, we need to switch all of this to return + # objects instead of storing them like this. + scope.setresource(obj) + obj + end + }.reject { |obj| obj.nil? } + end + + # Create our ResourceDef. Handles type checking for us. + def initialize(hash) + @checked = false + super + + #self.typecheck(@type.value) + 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 + + def supercomp + unless defined? @supercomp + if @scope and comp = @scope.inside + @supercomp = comp + else + error = Puppet::ParseError.new( + "'super' is only valid within definitions" + ) + error.line = self.line + error.file = self.file + raise error + end + end + @supercomp + end + + # Take all of the arguments of our parent and add them into our own, + # without overriding anything. + def supersetup(hash) + comp = supercomp() + + # Now check each of the arguments from the parent. + comp.arguments.each do |name, value| + unless hash.has_key? name + hash[name] = value + end + end + + # Return the parent name, so it can be used if appropriate. + return comp.name + end + + # Retrieve our supertype. + def supertype + unless defined? @supertype + if parent = supercomp.parentclass + @supertype = parent + else + error = Puppet::ParseError.new( + "%s does not have a parent class" % comp.type + ) + error.line = self.line + error.file = self.file + raise error + end + end + @supertype + end + + # Print this object out. + def tree(indent = 0) + return [ + @type.tree(indent + 1), + @title.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)), + @params.collect { |param| + begin + param.tree(indent + 1) + rescue NoMethodError => detail + Puppet.err @params.inspect + error = Puppet::DevError.new( + "failed to tree a %s" % self.class + ) + error.set_backtrace detail.backtrace + raise error + end + }.join("\n") + ].join("\n") + end + + def to_s + return "%s => { %s }" % [@title, + @params.collect { |param| + param.to_s + }.join("\n") + ] + end +end +end + +# $Id$ diff --git a/lib/puppet/parser/ast/typedefaults.rb b/lib/puppet/parser/ast/resourcedefaults.rb index 2e11a1b94..44db4d465 100644 --- a/lib/puppet/parser/ast/typedefaults.rb +++ b/lib/puppet/parser/ast/resourcedefaults.rb @@ -1,32 +1,22 @@ class Puppet::Parser::AST - # A statement syntactically similar to an ObjectDef, but uses a + # A statement syntactically similar to an ResourceDef, but uses a # capitalized object type and cannot have a name. - class TypeDefaults < AST::Branch + class ResourceDefaults < AST::Branch attr_accessor :type, :params def each [@type,@params].each { |child| yield child } end - # As opposed to ObjectDef, this stores each default for the given + # As opposed to ResourceDef, this stores each default for the given # object type. def evaluate(hash) scope = hash[:scope] - type = @type.safeevaluate(:scope => scope) + type = @type.downcase params = @params.safeevaluate(:scope => scope) - begin - scope.setdefaults(type.downcase,params) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error + parsewrap do + scope.setdefaults(type, params) end end @@ -44,3 +34,5 @@ class Puppet::Parser::AST end end + +# $Id$ diff --git a/lib/puppet/parser/ast/resourceoverride.rb b/lib/puppet/parser/ast/resourceoverride.rb new file mode 100644 index 000000000..26d69ae97 --- /dev/null +++ b/lib/puppet/parser/ast/resourceoverride.rb @@ -0,0 +1,62 @@ +require 'puppet/parser/ast/resourcedef' + +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 + 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.setoverride(obj) + + obj + end + + # Create our ResourceDef. Handles type checking for us. + def initialize(hash) + @checked = false + super + + #self.typecheck(@type.value) + end + end +end + +# $Id$ diff --git a/lib/puppet/parser/ast/objectparam.rb b/lib/puppet/parser/ast/resourceparam.rb index 87c3e5e8e..248e91b32 100644 --- a/lib/puppet/parser/ast/objectparam.rb +++ b/lib/puppet/parser/ast/resourceparam.rb @@ -1,6 +1,8 @@ +require 'puppet/parser/ast/branch' + class Puppet::Parser::AST - # The AST object for the parameters inside ObjectDefs and Selectors. - class ObjectParam < AST::Branch + # The AST object for the parameters inside ResourceDefs and Selectors. + class ResourceParam < AST::Branch attr_accessor :value, :param def each @@ -10,9 +12,17 @@ class Puppet::Parser::AST # Return the parameter and the value. def evaluate(hash) scope = hash[:scope] - param = @param.safeevaluate(:scope => scope) + param = @param value = @value.safeevaluate(:scope => scope) - return [param, value] + + args = {:name => param, :value => value, :source => scope.source} + [:line, :file].each do |p| + if v = self.send(p) + args[p] = v + end + end + + return Puppet::Parser::Resource::Param.new(args) end def tree(indent = 0) @@ -27,5 +37,6 @@ class Puppet::Parser::AST return "%s => %s" % [@param,@value] end end - end + +# $Id$ diff --git a/lib/puppet/parser/ast/resourceref.rb b/lib/puppet/parser/ast/resourceref.rb new file mode 100644 index 000000000..b0fe5f6d7 --- /dev/null +++ b/lib/puppet/parser/ast/resourceref.rb @@ -0,0 +1,44 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + # A reference to an object. Only valid as an rvalue. + class ResourceRef < AST::Branch + attr_accessor :title, :type + + 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] + + # We want a lower-case type. + objtype = @type.downcase + + title = @title.safeevaluate(:scope => scope) + + return Puppet::Parser::Resource::Reference.new( + :type => objtype, :title => title + ) + end + + def tree(indent = 0) + return [ + @type.tree(indent + 1), + @title.tree(indent + 1), + ((@@indline * indent) + self.typewrap(self.pin)) + ].join("\n") + end + + def to_s + return "%s[%s]" % [@type,@title] + end + end +end + +# $Id$ diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb index 5d1c41494..fe3fe9eaf 100644 --- a/lib/puppet/parser/ast/selector.rb +++ b/lib/puppet/parser/ast/selector.rb @@ -42,12 +42,8 @@ class Puppet::Parser::AST if default retvalue = default.value.safeevaluate(:scope => scope) else - error = Puppet::ParseError.new( + self.fail Puppet::ParseError, "No value for selector param '%s'" % paramvalue - ) - error.line = self.line - error.file = self.file - raise error end end diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb index 79129f31a..30eef204a 100644 --- a/lib/puppet/parser/ast/vardef.rb +++ b/lib/puppet/parser/ast/vardef.rb @@ -10,18 +10,8 @@ class Puppet::Parser::AST name = @name.safeevaluate(:scope => scope) value = @value.safeevaluate(:scope => scope) - begin + parsewrap do scope.setvar(name,value) - rescue Puppet::ParseError => except - except.line = self.line - except.file = self.file - raise except - rescue => detail - error = Puppet::ParseError.new(detail) - error.line = self.line - error.file = self.file - error.set_backtrace detail.backtrace - raise error end end @@ -43,3 +33,5 @@ class Puppet::Parser::AST end end + +# $Id$ |
