diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/puppet/parser/ast/casestatement.rb | 4 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/ifstatement.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/parser/ast/selector.rb | 3 | ||||
| -rw-r--r-- | lib/puppet/parser/scope.rb | 70 |
4 files changed, 68 insertions, 12 deletions
diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb index 64298cac3..ed1bb8aa3 100644 --- a/lib/puppet/parser/ast/casestatement.rb +++ b/lib/puppet/parser/ast/casestatement.rb @@ -11,6 +11,8 @@ class Puppet::Parser::AST # Short-curcuit evaluation. Return the value of the statements for # the first option that matches. def evaluate(scope) + level = scope.ephemeral_level + value = @test.safeevaluate(scope) retvalue = nil @@ -32,7 +34,7 @@ class Puppet::Parser::AST Puppet.debug "No true answers and no default" return nil ensure - scope.unset_ephemeral_var + scope.unset_ephemeral_var(level) end def each diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb index 9d52123b6..d84445bbd 100644 --- a/lib/puppet/parser/ast/ifstatement.rb +++ b/lib/puppet/parser/ast/ifstatement.rb @@ -16,6 +16,7 @@ class Puppet::Parser::AST # else if there's an 'else' setting, evaluate it. # the first option that matches. def evaluate(scope) + level = scope.ephemeral_level value = @test.safeevaluate(scope) # let's emulate a new scope for each branches @@ -30,7 +31,7 @@ class Puppet::Parser::AST end end ensure - scope.unset_ephemeral_var + scope.unset_ephemeral_var(level) end end end diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb index ce834b63b..cc468a536 100644 --- a/lib/puppet/parser/ast/selector.rb +++ b/lib/puppet/parser/ast/selector.rb @@ -12,6 +12,7 @@ class Puppet::Parser::AST # Find the value that corresponds with the test. def evaluate(scope) + level = scope.ephemeral_level # Get our parameter. paramvalue = @param.safeevaluate(scope) @@ -37,7 +38,7 @@ class Puppet::Parser::AST self.fail Puppet::ParseError, "No matching value for selector param '%s'" % paramvalue ensure - scope.unset_ephemeral_var + scope.unset_ephemeral_var(level) end def to_s diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index d6d663041..3623f40e2 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -20,6 +20,30 @@ class Puppet::Parser::Scope attr_accessor :top, :translated, :compiler attr_writer :parent + # thin wrapper around an ephemeral + # symbol table. + # when a symbol + class Ephemeral + def initialize(parent=nil) + @symbols = {} + @parent = parent + end + + [:include?, :delete, :[]=].each do |m| + define_method(m) do |*args| + @symbols.send(m, *args) + end + end + + def [](name) + unless @symbols.include?(name) or @parent.nil? + @parent[name] + else + @symbols[name] + end + end + end + # A demeterific shortcut to the catalog. def catalog compiler.catalog @@ -131,7 +155,9 @@ class Puppet::Parser::Scope # the ephemeral symbol tables # those should not persist long, and are used for the moment only # for $0..$xy capture variables of regexes - @ephemeral = {} + # this is actually implemented as a stack, with each ephemeral scope + # shadowing the previous one + @ephemeral = [ Ephemeral.new ] # All of the defaults set for types. It's a hash of hashes, # with the first key being the type, then the second key being @@ -194,13 +220,13 @@ class Puppet::Parser::Scope # Look up a variable. The simplest value search we do. Default to returning # an empty string for missing values, but support returning a constant. def lookupvar(name, usestring = true) - table = ephemeral?(name) ? @ephemeral : @symtable + table = ephemeral?(name) ? @ephemeral.last : @symtable # If the variable is qualified, then find the specified scope and look the variable up there instead. if name =~ /::/ return lookup_qualified_var(name, usestring) end # We can't use "if table[name]" here because the value might be false - if table.include?(name) + if ephemeral_include?(name) or table.include?(name) if usestring and table[name] == :undef return "" else @@ -293,7 +319,7 @@ class Puppet::Parser::Scope # in scopes above, but will not allow variables in the current scope # to be reassigned. def setvar(name,value, options = {}) - table = options[:ephemeral] ? @ephemeral : @symtable + table = options[:ephemeral] ? @ephemeral.last : @symtable #Puppet.debug "Setting %s to '%s' at level %s mode append %s" % # [name.inspect,value,self.level, append] if table.include?(name) @@ -338,7 +364,7 @@ class Puppet::Parser::Scope else # look the variable up # make sure $0-$9 are lookupable only if ephemeral var = ss[1] || ss[3] || ss[4] - if var and var =~ /^[0-9]+$/ and not ephemeral?(var) + if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var) next end out << lookupvar(var).to_s || "" @@ -403,23 +429,49 @@ class Puppet::Parser::Scope # Undefine a variable; only used for testing. def unsetvar(var) - table = ephemeral?(var) ? @ephemeral : @symtable + table = ephemeral?(var) ? @ephemeral.last : @symtable if table.include?(var) table.delete(var) end end - def unset_ephemeral_var - @ephemeral = {} + # remove ephemeral scope up to level + def unset_ephemeral_var(level=:all) + if level == :all + @ephemeral = [ Ephemeral.new ] + else + (@ephemeral.size - level).times do + @ephemeral.pop + end + end + end + + # check if name exists in one of the ephemeral scope. + def ephemeral_include?(name) + @ephemeral.reverse.each do |eph| + return true if eph.include?(name) + end + false end + # is name an ephemeral variable? def ephemeral?(name) - @ephemeral.include?(name) + name =~ /^\d+$/ + end + + def ephemeral_level + @ephemeral.size + end + + def new_ephemeral + @ephemeral.push(Ephemeral.new(@ephemeral.last)) end def ephemeral_from(match, file = nil, line = nil) raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData) + new_ephemeral + setvar("0", match[0], :file => file, :line => line, :ephemeral => true) match.captures.each_with_index do |m,i| setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => true) |
