diff --git a/lib/puppet/parser.rb b/lib/puppet/parser.rb index e01ca1f9f..d41f77126 100644 --- a/lib/puppet/parser.rb +++ b/lib/puppet/parser.rb @@ -1,7 +1,17 @@ -# @api public +# is only needed to create the name space module Puppet::Parser; end -require 'puppet/parser/parser' +require 'puppet/parser/ast' require 'puppet/parser/compiler' require 'puppet/resource/type_collection' +require 'puppet/parser/functions' +require 'puppet/parser/files' +require 'puppet/parser/relationship' + +require 'puppet/resource/type_collection_helper' +require 'puppet/resource/type' +require 'monitor' + +# PUP-3274 This should probably go someplace else +class Puppet::LexError < RuntimeError; end diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index ed2c66bba..2e2cb5370 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -1,129 +1,103 @@ # the parent class for all of our syntactical objects require 'puppet' require 'puppet/util/autoload' # The base class for all of the objects that make up the parse trees. # Handles things like file name, line #, and also does the initialization # for all of the parameters of all of the child objects. class Puppet::Parser::AST # Do this so I don't have to type the full path in all of the subclasses AST = Puppet::Parser::AST include Puppet::Util::Errors include Puppet::Util::MethodHelper include Puppet::Util::Docs attr_accessor :parent, :scope, :file, :line, :pos def inspect "( #{self.class} #{self.to_s} #{@children.inspect} )" end # don't fetch lexer comment by default def use_docs self.class.use_docs end # allow our subclass to specify they want documentation class << self attr_accessor :use_docs def associates_doc self.use_docs = true end end # Evaluate the current object. Just a stub method, since the subclass # should override this method. def evaluate(*options) end # Throw a parse error. def parsefail(message) self.fail(Puppet::ParseError, message) end # Wrap a statemp in a reusable way so we always throw a parse error. def parsewrap exceptwrap :type => Puppet::ParseError do yield end end # The version of the evaluate method that should be called, because it # correctly handles errors. It is critical to use this method because # it can enable you to catch the error where it happens, rather than # much higher up the stack. def safeevaluate(*options) # We duplicate code here, rather than using exceptwrap, because this # is called so many times during parsing. begin return self.evaluate(*options) rescue Puppet::Error => detail raise adderrorcontext(detail) rescue => detail error = Puppet::ParseError.new(detail.to_s, nil, nil, detail) # We can't use self.fail here because it always expects strings, # not exceptions. raise adderrorcontext(error, detail) end end # Initialize the object. Requires a hash as the argument, and # takes each of the parameters of the hash and calls the settor # method for them. This is probably pretty inefficient and should # likely be changed at some point. def initialize(args) set_options(args) end # evaluate ourselves, and match def evaluate_match(value, scope) obj = self.safeevaluate(scope) obj = obj.downcase if obj.respond_to?(:downcase) value = value.downcase if value.respond_to?(:downcase) obj = Puppet::Parser::Scope.number?(obj) || obj value = Puppet::Parser::Scope.number?(value) || value # "" == undef for case/selector/if obj == value or (obj == "" and value == :undef) or (obj == :undef and value == "") end end # And include all of the AST subclasses. -require 'puppet/parser/ast/arithmetic_operator' require 'puppet/parser/ast/astarray' -require 'puppet/parser/ast/asthash' -require 'puppet/parser/ast/boolean_operator' -require 'puppet/parser/ast/branch' -require 'puppet/parser/ast/caseopt' -require 'puppet/parser/ast/casestatement' -require 'puppet/parser/ast/collection' -require 'puppet/parser/ast/collexpr' -require 'puppet/parser/ast/comparison_operator' -require 'puppet/parser/ast/definition' -require 'puppet/parser/ast/else' -require 'puppet/parser/ast/function' -require 'puppet/parser/ast/hostclass' -require 'puppet/parser/ast/ifstatement' -require 'puppet/parser/ast/in_operator' -require 'puppet/parser/ast/lambda' +require 'puppet/parser/ast/block_expression' +require 'puppet/parser/ast/hostclass' # PUP-3274 cannot remove until environment uses a different representation require 'puppet/parser/ast/leaf' -require 'puppet/parser/ast/match_operator' -require 'puppet/parser/ast/method_call' -require 'puppet/parser/ast/minus' require 'puppet/parser/ast/node' -require 'puppet/parser/ast/nop' -require 'puppet/parser/ast/not' -require 'puppet/parser/ast/relationship' require 'puppet/parser/ast/resource' -require 'puppet/parser/ast/resource_defaults' require 'puppet/parser/ast/resource_instance' -require 'puppet/parser/ast/resource_override' -require 'puppet/parser/ast/resource_reference' require 'puppet/parser/ast/resourceparam' -require 'puppet/parser/ast/selector' -require 'puppet/parser/ast/vardef' -require 'puppet/parser/code_merger' diff --git a/lib/puppet/parser/ast/arithmetic_operator.rb b/lib/puppet/parser/ast/arithmetic_operator.rb deleted file mode 100644 index 162d263a7..000000000 --- a/lib/puppet/parser/ast/arithmetic_operator.rb +++ /dev/null @@ -1,91 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - class ArithmeticOperator < AST::Branch - - attr_accessor :operator, :lval, :rval - - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end - - # Produces an object which is the result of the applying the operator to the of lval and rval operands. - # * Supports +, -, *, /, %, and <<, >> on numeric strings. - # * Supports + on arrays (concatenate), and hashes (merge) - # * Supports << on arrays (append) - # - def evaluate(scope) - # evaluate the operands, should return a boolean value - left = @lval.safeevaluate(scope) - right = @rval.safeevaluate(scope) - - if left.is_a?(Array) || right.is_a?(Array) - eval_array(left, right) - elsif left.is_a?(Hash) || right.is_a?(Hash) - eval_hash(left, right) - else - eval_numeric(left, right) - end - end - - # Concatenates (+) two arrays, or appends (<<) any object to a newly created array. - # - def eval_array(left, right) - assert_concatenation_supported() - - raise ArgumentError, "operator #{@operator} is not applicable when one of the operands is an Array." unless %w{+ <<}.include?(@operator) - raise ArgumentError, "left operand of #{@operator} must be an Array" unless left.is_a?(Array) - if @operator == '+' - raise ArgumentError, "right operand of #{@operator} must be an Array when left is an Array." unless right.is_a?(Array) - return left + right - end - # only append case remains, left asserted to be an array, and right may be any object - # wrapping right in an array and adding it ensures a new copy (operator << mutates). - # - left + [right] - end - - # Merges two hashes. - # - def eval_hash(left, right) - assert_concatenation_supported() - - raise ArgumentError, "operator #{@operator} is not applicable when one of the operands is an Hash." unless @operator == '+' - raise ArgumentError, "left operand of #{@operator} must be an Hash" unless left.is_a?(Hash) - raise ArgumentError, "right operand of #{@operator} must be an Hash" unless right.is_a?(Hash) - # merge produces a merged copy - left.merge(right) - end - - def eval_numeric(left, right) - left = Puppet::Parser::Scope.number?(left) - right = Puppet::Parser::Scope.number?(right) - raise ArgumentError, "left operand of #{@operator} is not a number" unless left != nil - raise ArgumentError, "right operand of #{@operator} is not a number" unless right != nil - - # compute result - left.send(@operator, right) - end - - def assert_concatenation_supported - return if Puppet[:parser] == 'future' - raise ParseError.new("Unsupported Operation: Array concatenation available with '--parser future' setting only.") - end - - def initialize(hash) - super - - raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / % << >>}.include?(@operator) - end - end - - # Used by future parser instead of ArithmeticOperator to enable concatenation - class ArithmeticOperator2 < ArithmeticOperator - # Overrides the arithmetic operator to allow concatenation - def assert_concatenation_supported - end - end - -end diff --git a/lib/puppet/parser/ast/asthash.rb b/lib/puppet/parser/ast/asthash.rb deleted file mode 100644 index ae81d35dd..000000000 --- a/lib/puppet/parser/ast/asthash.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'puppet/parser/ast/leaf' - -class Puppet::Parser::AST - class ASTHash < Leaf - include Enumerable - - # Evaluate our children. - def evaluate(scope) - items = {} - - @value.each_pair do |k,v| - key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k - items.merge!({ key => v.safeevaluate(scope) }) - end - - items - end - - def merge(hash) - case hash - when ASTHash - @value = @value.merge(hash.value) - when Hash - @value = @value.merge(hash) - end - end - - def to_s - "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}" - end - - def initialize(args) - super(args) - @value ||= {} - end - end -end diff --git a/lib/puppet/parser/ast/boolean_operator.rb b/lib/puppet/parser/ast/boolean_operator.rb deleted file mode 100644 index 8481e4f8d..000000000 --- a/lib/puppet/parser/ast/boolean_operator.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - class BooleanOperator < AST::Branch - - attr_accessor :operator, :lval, :rval - - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end - - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - # evaluate the first operand, should return a boolean value - lval = @lval.safeevaluate(scope) - - # return result - # lazy evaluate right operand - case @operator - when "and" - if Puppet::Parser::Scope.true?(lval) - rval = @rval.safeevaluate(scope) - Puppet::Parser::Scope.true?(rval) - else # false and false == false - false - end - when "or" - if Puppet::Parser::Scope.true?(lval) - true - else - rval = @rval.safeevaluate(scope) - Puppet::Parser::Scope.true?(rval) - end - end - end - - def initialize(hash) - super - - raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator) - end - end -end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb deleted file mode 100644 index db4c2b024..000000000 --- a/lib/puppet/parser/ast/caseopt.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # Each individual option in a case statement. - class CaseOpt < AST::Branch - attr_accessor :value, :statements - - # CaseOpt is a bit special -- we just want the value first, - # so that CaseStatement can compare, and then it will selectively - # decide whether to fully evaluate this option - - def each - [@value,@statements].each { |child| yield child } - end - - # Are we the default option? - def default? - # Cache the @default value. - return @default if defined?(@default) - - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - - @default ||= false - - @default - end - - # You can specify a list of values; return each in turn. - def eachvalue(scope) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - end - - def eachopt - @value.each { |subval| - yield subval - } - end - - # Evaluate the actual statements; this only gets called if - # our option matched. - def evaluate(scope) - @statements.safeevaluate(scope) - end - end -end diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb deleted file mode 100644 index 67510ca72..000000000 --- a/lib/puppet/parser/ast/casestatement.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # The basic logical structure in Puppet. Supports a list of - # tests and statement arrays. - class CaseStatement < AST::Branch - attr_accessor :test, :options, :default - - associates_doc - - # 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) - - # Iterate across the options looking for a match. - default = nil - @options.each do |option| - option.eachopt do |opt| - return option.safeevaluate(scope) if opt.evaluate_match(value, scope) - end - - default = option if option.default? - end - - # Unless we found something, look for the default. - return default.safeevaluate(scope) if default - - Puppet.debug "No true answers and no default" - return nil - ensure - scope.unset_ephemeral_var(level) - end - - def each - [@test,@options].each { |child| yield child } - end - end -end diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb deleted file mode 100644 index 0f4b17500..000000000 --- a/lib/puppet/parser/ast/collection.rb +++ /dev/null @@ -1,53 +0,0 @@ -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 Collection < AST::Branch - attr_accessor :type, :query, :form - attr_reader :override - - associates_doc - - # We return an object that does a late-binding evaluation. - def evaluate(scope) - match, code = query && query.safeevaluate(scope) - - if @type == 'class' - fail "Classes cannot be collected" - end - - resource_type = scope.find_resource_type(@type) - fail "Resource type #{@type} doesn't exist" unless resource_type - newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, match, code, self.form) - - scope.compiler.add_collection(newcoll) - - # overrides if any - # Evaluate all of the specified params. - if @override - params = @override.collect { |param| param.safeevaluate(scope) } - newcoll.add_override( - :parameters => params, - :file => @file, - :line => @line, - :source => scope.source, - :scope => scope - ) - end - - newcoll - end - - # Handle our parameter ourselves - def override=(override) - @override = if override.is_a?(AST::ASTArray) - override - else - AST::ASTArray.new(:line => override.line,:file => override.file,:children => [override]) - end - end - end -end diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb deleted file mode 100644 index 92f9cc10f..000000000 --- a/lib/puppet/parser/ast/collexpr.rb +++ /dev/null @@ -1,109 +0,0 @@ -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 - - def evaluate(scope) - if Puppet[:parser] == 'future' - evaluate4x(scope) - else - evaluate3x(scope) - end - end - - # We return an object that does a late-binding evaluation. - def evaluate3x(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 - match1, code1 = @test1.safeevaluate scope - match2, code2 = @test2.safeevaluate 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 "==" - if match1 == "tag" - resource.tagged?(match2) - else - if resource[match1].is_a?(Array) - resource[match1].include?(match2) - else - resource[match1] == match2 - end - end - when "!="; resource[match1] != match2 - end - end - - match = [match1, @oper, match2] - return match, code - end - - # Late binding evaluation of a collect expression (as done in 3x), but with proper Puppet Language - # semantics for equals and include - # - def evaluate4x(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 - match1, code1 = @test1.safeevaluate scope - match2, code2 = @test2.safeevaluate 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 "==" - if match1 == "tag" - resource.tagged?(match2) - else - if resource[match1].is_a?(Array) - @@compare_operator.include?(resource[match1], match2, scope) - else - @@compare_operator.equals(resource[match1], match2) - end - end - when "!="; ! @@compare_operator.equals(resource[match1], match2) - end - end - - match = [match1, @oper, match2] - return match, code - end - - def initialize(hash = {}) - super - if Puppet[:parser] == "future" - @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new - end - raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper) - end -end -end diff --git a/lib/puppet/parser/ast/comparison_operator.rb b/lib/puppet/parser/ast/comparison_operator.rb deleted file mode 100644 index 039c81df8..000000000 --- a/lib/puppet/parser/ast/comparison_operator.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - class ComparisonOperator < AST::Branch - - attr_accessor :operator, :lval, :rval - - # Iterate across all of our children. - def each - [@lval,@rval,@operator].each { |child| yield child } - end - - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - # evaluate the operands, should return a boolean value - lval = @lval.safeevaluate(scope) - - case @operator - when "==","!=" - @rval.evaluate_match(lval, scope) ? @operator == '==' : @operator == '!=' - else - rval = @rval.safeevaluate(scope) - rval = Puppet::Parser::Scope.number?(rval) || rval - lval = Puppet::Parser::Scope.number?(lval) || lval - - lval.send(@operator,rval) - end - end - - def initialize(hash) - super - - raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator) - end - end -end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb deleted file mode 100644 index 0a81d46fe..000000000 --- a/lib/puppet/parser/ast/definition.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'puppet/parser/ast/top_level_construct' - -class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct - attr_accessor :context - - def initialize(name, context = {}) - @name = name - @context = context - end - - def instantiate(modname) - new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname)) - [new_definition] - end -end diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb deleted file mode 100644 index 172149116..000000000 --- a/lib/puppet/parser/ast/else.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # A separate ElseIf statement; can function as an 'else' if there's no - # test. - class Else < AST::Branch - - associates_doc - - attr_accessor :statements - - def each - yield @statements - end - - # Evaluate the actual statements; this only gets called if - # our test was true matched. - def evaluate(scope) - @statements.safeevaluate(scope) - end - end -end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb deleted file mode 100644 index 5d2dc6f3d..000000000 --- a/lib/puppet/parser/ast/function.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # An AST object to call a function. - class Function < AST::Branch - - associates_doc - - attr_accessor :name, :arguments, :pblock - - def evaluate(scope) - # Make sure it's a defined function - raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) - - # Now check that it's been used correctly - case @ftype - when :rvalue - raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name) - - when :statement - # It is harmless to produce an ignored rvalue, the alternative is to mark functions - # as appropriate for both rvalue and statements - # Keeping the old behavior when a pblock is not present. This since it is not known - # if the lambda contains a statement or not (at least not without a costly search). - # The purpose of the check is to protect a user for producing a meaningless rvalue where the - # operation has no side effects. - # - if !pblock && Puppet::Parser::Functions.rvalue?(@name) - raise Puppet::ParseError, - "Function '#{@name}' must be the value of a statement" - end - else - raise Puppet::DevError, "Invalid function type #{@ftype.inspect}" - end - - # We don't need to evaluate the name, because it's plaintext - args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } - - # append a puppet lambda (unevaluated) if it is defined - args << pblock if pblock - - scope.send("function_#{@name}", args) - end - - def initialize(hash) - @ftype = hash[:ftype] || :rvalue - hash.delete(:ftype) if hash.include? :ftype - - super(hash) - - # Lastly, check the parity - end - - def to_s - args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments - "#{name}(#{args})" - end - end -end diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb deleted file mode 100644 index 7fd8a576a..000000000 --- a/lib/puppet/parser/ast/ifstatement.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # A basic 'if/elsif/else' statement. - class IfStatement < AST::Branch - - associates_doc - - attr_accessor :test, :else, :statements - - def each - [@test,@else,@statements].each { |child| yield child } - end - - # Short-curcuit evaluation. If we're true, evaluate our statements, - # 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 - begin - if Puppet::Parser::Scope.true?(value) - return @statements.safeevaluate(scope) - else - return defined?(@else) ? @else.safeevaluate(scope) : nil - end - ensure - scope.unset_ephemeral_var(level) - end - end - end -end diff --git a/lib/puppet/parser/ast/in_operator.rb b/lib/puppet/parser/ast/in_operator.rb deleted file mode 100644 index 2a163e726..000000000 --- a/lib/puppet/parser/ast/in_operator.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - class InOperator < AST::Branch - - attr_accessor :lval, :rval - - # Returns a boolean which is the result of the 'in' operation - # of lval and rval operands - def evaluate(scope) - - # evaluate the operands, should return a boolean value - lval = @lval.safeevaluate(scope) - raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String) - - rval = @rval.safeevaluate(scope) - unless rval.respond_to?(:include?) - raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)" - end - rval.include?(lval) - end - end -end diff --git a/lib/puppet/parser/ast/lambda.rb b/lib/puppet/parser/ast/lambda.rb deleted file mode 100644 index 64d78d49b..000000000 --- a/lib/puppet/parser/ast/lambda.rb +++ /dev/null @@ -1,135 +0,0 @@ -require 'puppet/parser/ast/block_expression' - -class Puppet::Parser::AST - # A block of statements/expressions with additional parameters - # Requires scope to contain the values for the defined parameters when evaluated - # If evaluated without a prepared scope, the lambda will behave like its super class. - # - class Lambda < AST::BlockExpression - - # The lambda parameters. - # These are encoded as an array where each entry is an array of one or two object. The first - # is the parameter name, and the optional second object is the value expression (that will - # be evaluated when bound to a scope). - # The value expression is the default value for the parameter. All default values must be - # at the end of the parameter list. - # - # @return [Array>] list of parameter names with optional value expression - attr_accessor :parameters - # Evaluates each expression/statement and produce the last expression evaluation result - # @return [Object] what the last expression evaluated to - def evaluate(scope) - if @children.is_a? Puppet::Parser::AST::ASTArray - result = nil - @children.each {|expr| result = expr.evaluate(scope) } - result - else - @children.evaluate(scope) - end - end - - # Calls the lambda. - # Assigns argument values in a nested local scope that should be used to evaluate the lambda - # and then evaluates the lambda. - # @param scope [Puppet::Scope] the calling scope - # @return [Object] the result of evaluating the expression(s) in the lambda - # - def call(scope, *args) - raise Puppet::ParseError, "Too many arguments: #{args.size} for #{parameters.size}" unless args.size <= parameters.size - - # associate values with parameters - merged = parameters.zip(args) - # calculate missing arguments - missing = parameters.slice(args.size, parameters.size - args.size).select {|e| e.size == 1} - unless missing.empty? - optional = parameters.count { |p| p.size == 2 } - raise Puppet::ParseError, "Too few arguments; #{args.size} for #{optional > 0 ? ' min ' : ''}#{parameters.size - optional}" - end - - evaluated = merged.collect do |m| - # m can be one of - # m = [["name"], "given"] - # | [["name", default_expr], "given"] - # - # "given" is always an optional entry. If a parameter was provided then - # the entry will be in the array, otherwise the m array will be a - # single element. - given_argument = m[1] - argument_name = m[0][0] - default_expression = m[0][1] - - value = if m.size == 1 - default_expression.safeevaluate(scope) - else - given_argument - end - [argument_name, value] - end - - # Store the evaluated name => value associations in a new inner/local/ephemeral scope - # (This is made complicated due to the fact that the implementation of scope is overloaded with - # functionality and an inner ephemeral scope must be used (as opposed to just pushing a local scope - # on a scope "stack"). - - # Ensure variable exists with nil value if error occurs. - # Some ruby implementations does not like creating variable on return - result = nil - begin - elevel = scope.ephemeral_level - scope.ephemeral_from(Hash[evaluated], file, line) - result = safeevaluate(scope) - ensure - scope.unset_ephemeral_var(elevel) - end - result - end - - # Validates the lambda. - # Validation checks if parameters with default values are at the end of the list. (It is illegal - # to have a parameter with default value followed by one without). - # - # @raise [Puppet::ParseError] if a parameter with a default comes before a parameter without default value - # - def validate - params = parameters || [] - defaults = params.drop_while {|p| p.size < 2 } - trailing = defaults.drop_while {|p| p.size == 2 } - raise Puppet::ParseError, "Lambda parameters with default values must be placed last" unless trailing.empty? - end - - # Returns the number of parameters (required and optional) - # @return [Integer] the total number of accepted parameters - def parameter_count - @parameters.size - end - - # Returns the number of optional parameters. - # @return [Integer] the number of optional accepted parameters - def optional_parameter_count - @parameters.count {|p| p.size == 2 } - end - - def initialize(options) - super(options) - # ensure there is an empty parameters structure if not given by creator - @parameters = [] unless options[:parameters] - validate - end - - def to_s - result = ["{|"] - result += @parameters.collect {|p| "#{p[0]}" + (p.size == 2 && p[1]) ? p[1].to_s() : '' }.join(', ') - result << "| ... }" - result.join('') - end - - # marker method checked with respond_to :puppet_lambda - def puppet_lambda() - true - end - - def parameter_names - @parameters.collect {|p| p[0] } - end - end -end diff --git a/lib/puppet/parser/ast/match_operator.rb b/lib/puppet/parser/ast/match_operator.rb deleted file mode 100644 index 6207a8c2c..000000000 --- a/lib/puppet/parser/ast/match_operator.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - class MatchOperator < AST::Branch - - attr_accessor :lval, :rval, :operator - - # Iterate across all of our children. - def each - [@lval,@rval].each { |child| yield child } - end - - # Returns a boolean which is the result of the boolean operation - # of lval and rval operands - def evaluate(scope) - lval = @lval.safeevaluate(scope) - - return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~") - end - - def initialize(hash) - super - - raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator) - end - end -end diff --git a/lib/puppet/parser/ast/method_call.rb b/lib/puppet/parser/ast/method_call.rb deleted file mode 100644 index d613674ad..000000000 --- a/lib/puppet/parser/ast/method_call.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'puppet/parser/ast/branch' -require 'puppet/parser/methods' - -class Puppet::Parser::AST - # An AST object to call a method - class MethodCall < AST::Branch - - associates_doc - - # An AST that evaluates to the object the method is applied to - # @return [Puppet::Parser::AST] - attr_accessor :receiver - - # The name of the method - # @return [String] - attr_accessor :name - - # The arguments to evaluate as arguments to the method. - # @return [Array] - attr_accessor :arguments - - # An optional lambda/block that will be yielded to by the called method (if it supports this) - # @return [Puppet::Parser::AST::Lambda] - attr_accessor :lambda - - # Evaluates the method call and returns what the called method/function returns. - # The evaluation evaluates all arguments in the calling scope and then delegates - # to a "method" instance produced by Puppet::Parser::Methods for this method call. - # @see Puppet::Parser::Methods - # @return [Object] what the called method/function returns - def evaluate(scope) - # Make sure it's a defined method for the receiver - r = @receiver.evaluate(scope) - raise Puppet::ParseError, "No object to apply method #{@name} to" unless r - m = Puppet::Parser::Methods.find_method(scope, r, @name) - raise Puppet::ParseError, "Unknown method #{@name} for #{r}" unless m - - # Now check if rvalue is required (in expressions) - case @ftype - when :rvalue - raise Puppet::ParseError, "Method '#{@name}' does not return a value" unless m.is_rvalue? - when :statement - # When used as a statement, ignore if it produces a rvalue (it is simply not used) - else - raise Puppet::DevError, "Invalid method type #{@ftype.inspect}" - end - - # Evaluate arguments - args = @arguments ? @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } : [] - - # There is no need to evaluate the name, since it is a literal ruby string - - # call the method (it is already bound to the receiver and name) - m.invoke(scope, args, @lambda) - end - - def initialize(hash) - @ftype = hash[:ftype] || :rvalue - hash.delete(:ftype) if hash.include? :ftype - - super(hash) - - # Lastly, check the parity - end - - # Sets this method call in statement mode where a produced rvalue is ignored. - # @return [void] - def ignore_rvalue - @ftype = :statement - end - - def to_s - args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments - "#{@receiver.to_s}.#{name} (#{args})" + (@lambda ? " #{@lambda.to_s}" : '') - end - end -end diff --git a/lib/puppet/parser/ast/minus.rb b/lib/puppet/parser/ast/minus.rb deleted file mode 100644 index d7a362aa1..000000000 --- a/lib/puppet/parser/ast/minus.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -# An object that returns a boolean which is the boolean not -# of the given value. -class Puppet::Parser::AST - class Minus < AST::Branch - attr_accessor :value - - def each - yield @value - end - - def evaluate(scope) - val = @value.safeevaluate(scope) - val = Puppet::Parser::Scope.number?(val) - if val == nil - raise ArgumentError, "minus operand #{val} is not a number" - end - -val - end - end -end diff --git a/lib/puppet/parser/ast/nop.rb b/lib/puppet/parser/ast/nop.rb deleted file mode 100644 index 15383aa1f..000000000 --- a/lib/puppet/parser/ast/nop.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # This class is a no-op, it doesn't produce anything - # when evaluated, hence its name :-) - class Nop < AST::Leaf - def evaluate(scope) - # nothing to do - end - end -end diff --git a/lib/puppet/parser/ast/not.rb b/lib/puppet/parser/ast/not.rb deleted file mode 100644 index 30fa6d503..000000000 --- a/lib/puppet/parser/ast/not.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'puppet' -require 'puppet/parser/ast/branch' - -# An object that returns a boolean which is the boolean not -# of the given value. -class Puppet::Parser::AST - class Not < AST::Branch - attr_accessor :value - - def each - yield @value - end - - def evaluate(scope) - val = @value.safeevaluate(scope) - ! Puppet::Parser::Scope.true?(val) - end - end -end diff --git a/lib/puppet/parser/ast/relationship.rb b/lib/puppet/parser/ast/relationship.rb deleted file mode 100644 index 37ead311f..000000000 --- a/lib/puppet/parser/ast/relationship.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'puppet/parser/ast' -require 'puppet/parser/ast/branch' -require 'puppet/parser/relationship' - -class Puppet::Parser::AST::Relationship < Puppet::Parser::AST::Branch - RELATIONSHIP_TYPES = %w{-> <- ~> <~} - - attr_accessor :left, :right, :arrow, :type - - # Evaluate our object, but just return a simple array of the type - # and name. - def evaluate(scope) - real_left = left.safeevaluate(scope) - real_right = right.safeevaluate(scope) - - source, target = sides2edge(real_left, real_right) - scope.compiler.add_relationship Puppet::Parser::Relationship.new(source, target, type) - - real_right - end - - def initialize(left, right, arrow, args = {}) - super(args) - unless RELATIONSHIP_TYPES.include?(arrow) - raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}" - end - @left, @right, @arrow = left, right, arrow - end - - def type - subscription? ? :subscription : :relationship - end - - def sides2edge(left, right) - out_edge? ? [left, right] : [right, left] - end - - private - - def out_edge? - ["->", "~>"].include?(arrow) - end - - def subscription? - ["~>", "<~"].include?(arrow) - end -end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 5f5f1ab06..8401ba484 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -1,67 +1,65 @@ -require 'puppet/parser/ast/resource_reference' - # Any normal puppet resource declaration. Can point to a definition or a # builtin type. class Puppet::Parser::AST class Resource < AST::Branch associates_doc attr_accessor :type, :instances, :exported, :virtual # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) # We want virtual to be true if exported is true. We can't # just set :virtual => self.virtual in the initialization, # because sometimes the :virtual attribute is set *after* # :exported, in which case it clobbers :exported if :exported # is true. Argh, this was a very tough one to track down. virt = self.virtual || self.exported # First level of implicit iteration: build a resource for each # instance. This handles things like: # file { '/foo': owner => blah; '/bar': owner => blah } @instances.collect { |instance| # Evaluate all of the specified params. paramobjects = instance.parameters.collect { |param| param.safeevaluate(scope) } resource_titles = instance.title.safeevaluate(scope) # it's easier to always use an array, even for only one name resource_titles = [resource_titles] unless resource_titles.is_a?(Array) fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) # Second level of implicit iteration; build a resource for each # title. This handles things like: # file { ['/foo', '/bar']: owner => blah } resource_titles.flatten.collect { |resource_title| exceptwrap :type => Puppet::ParseError do resource = Puppet::Parser::Resource.new( fully_qualified_type, resource_title, :parameters => paramobjects, :file => self.file, :line => self.line, :exported => self.exported, :virtual => virt, :source => scope.source, :scope => scope, :strict => true ) if resource.resource_type.is_a? Puppet::Resource::Type resource.resource_type.instantiate_resource(scope, resource) end scope.compiler.add_resource(scope, resource) scope.compiler.evaluate_classes([resource_title], scope, false, true) if fully_qualified_type == 'class' resource end } }.flatten.reject { |resource| resource.nil? } end end end diff --git a/lib/puppet/parser/ast/resource_defaults.rb b/lib/puppet/parser/ast/resource_defaults.rb deleted file mode 100644 index 9dfed28a0..000000000 --- a/lib/puppet/parser/ast/resource_defaults.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # A statement syntactically similar to an ResourceDef, but uses a - # capitalized object type and cannot have a name. - class ResourceDefaults < AST::Branch - attr_accessor :type, :parameters - - associates_doc - - # As opposed to ResourceDef, this stores each default for the given - # object type. - def evaluate(scope) - # Use a resource reference to canonize the type - ref = Puppet::Resource.new(@type, "whatever") - type = ref.type - params = @parameters.safeevaluate(scope) - - parsewrap do - scope.define_settings(type, params) - end - end - end -end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb deleted file mode 100644 index 78fe74171..000000000 --- a/lib/puppet/parser/ast/resource_override.rb +++ /dev/null @@ -1,62 +0,0 @@ -require 'puppet/parser/ast/resource' - -class Puppet::Parser::AST - # Set a parameter on a resource specification created somewhere else in the - # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < AST::Branch - - associates_doc - - attr_accessor :object, :parameters - - # Iterate across all of our children. - def each - [@object,@parameters].flatten.each { |param| - #Puppet.debug("yielding param #{param}") - yield param - } - end - - # Does not actually return an object; instead sets an object - # in the current scope. - def evaluate(scope) - # Get our object reference. - resource = @object.safeevaluate(scope) - - # Evaluate all of the specified params. - params = @parameters.collect { |param| - param.safeevaluate(scope) - } - - # Now we just create a normal resource, but we call a very different - # method on the scope. - resource = [resource] unless resource.is_a?(Array) - - resource = resource.collect do |r| - - res = Puppet::Parser::Resource.new( - r.type, r.title, - :parameters => params, - :file => file, - :line => line, - :source => scope.source, - :scope => scope - ) - - # Now we tell the scope that it's an override, and it behaves as - # necessary. - scope.compiler.add_override(res) - - res - end - # decapsulate array in case of only one item - return(resource.length == 1 ? resource.pop : resource) - end - - # Create our ResourceDef. Handles type checking for us. - def initialize(hash) - @checked = false - super - end - end -end diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb deleted file mode 100644 index 256a99d75..000000000 --- a/lib/puppet/parser/ast/resource_reference.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'puppet/parser/ast' -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch - attr_accessor :title, :type - - # Evaluate our object, but just return a simple array of the type - # and name. - def evaluate(scope) - titles = Array(title.safeevaluate(scope)).flatten - - a_type, titles = scope.resolve_type_and_titles(type, titles) - - resources = titles.collect{ |a_title| - Puppet::Resource.new(a_type, a_title) - } - - return(resources.length == 1 ? resources.pop : resources) - end - - def to_s - if title.is_a?(Puppet::Parser::AST::ASTArray) - "#{type.to_s.capitalize}#{title}" - else - "#{type.to_s.capitalize}[#{title}]" - end - end -end diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb deleted file mode 100644 index 04f0b1873..000000000 --- a/lib/puppet/parser/ast/selector.rb +++ /dev/null @@ -1,50 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # The inline conditional operator. Unlike CaseStatement, which executes - # code, we just return a value. - class Selector < AST::Branch - attr_accessor :param, :values - - def each - [@param,@values].each { |child| yield child } - end - - # Find the value that corresponds with the test. - def evaluate(scope) - level = scope.ephemeral_level - # Get our parameter. - paramvalue = @param.safeevaluate(scope) - - default = nil - - @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array - - # Then look for a match in the options. - @values.each do |obj| - # short circuit asap if we have a match - return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope) - - # Store the default, in case it's necessary. - default = obj if obj.param.is_a?(Default) - end - - # Unless we found something, look for the default. - return default.value.safeevaluate(scope) if default - - self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'" - ensure - scope.unset_ephemeral_var(level) - end - - def to_s - if @values.instance_of? AST::ASTArray or @values.instance_of? Array - v = @values - else - v = [@values] - end - - param.to_s + " ? { " + v.collect { |v| v.to_s }.join(', ') + " }" - end - end -end diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb deleted file mode 100644 index 07999f316..000000000 --- a/lib/puppet/parser/ast/vardef.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'puppet/parser/ast/branch' - -class Puppet::Parser::AST - # Define a variable. Stores the value in the current scope. - class VarDef < AST::Branch - - associates_doc - - attr_accessor :name, :value, :append - - # Look up our name and value, and store them appropriately. The - # lexer strips off the syntax stuff like '$'. - def evaluate(scope) - value = @value.safeevaluate(scope) - if name.is_a?(HashOrArrayAccess) - name.assign(scope, value) - else - name = @name.safeevaluate(scope) - - parsewrap do - scope.setvar(name,value, :file => file, :line => line, :append => @append) - end - end - if @append - # Produce resulting value from append operation - scope[name] - else - # Produce assigned value - value - end - end - - def each - [@name,@value].each { |child| yield child } - end - end - -end diff --git a/lib/puppet/parser/code_merger.rb b/lib/puppet/parser/code_merger.rb deleted file mode 100644 index e8913b88b..000000000 --- a/lib/puppet/parser/code_merger.rb +++ /dev/null @@ -1,13 +0,0 @@ - -class Puppet::Parser::CodeMerger - - # Concatenates the logic in the array of parse results into one parse result - # @return Puppet::Parser::AST::BlockExpression - # - def concatenate(parse_results) - children = parse_results.select {|x| !x.nil? && x.code}.reduce([]) do |memo, parsed_class| - memo + parsed_class.code.children - end - Puppet::Parser::AST::BlockExpression.new(:children => children) - end -end diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb deleted file mode 100644 index 7a15bfb21..000000000 --- a/lib/puppet/parser/collector.rb +++ /dev/null @@ -1,177 +0,0 @@ -# An object that collects stored objects from the central cache and returns -# them to the current host, yo. -class Puppet::Parser::Collector - attr_accessor :type, :scope, :vquery, :equery, :form - attr_accessor :resources, :overrides, :collected - - # Call the collection method, mark all of the returned objects as - # non-virtual, optionally applying parameter overrides. The collector can - # also delete himself from the compiler if there is no more resources to - # collect (valid only for resource fixed-set collector which get their - # resources from +collect_resources+ and not from the catalog) - def evaluate - # Shortcut if we're not using storeconfigs and they're trying to collect - # exported resources. - if form == :exported and Puppet[:storeconfigs] != true - Puppet.warning "Not collecting exported resources without storeconfigs" - return false - end - - if self.resources - unless objects = collect_resources and ! objects.empty? - return false - end - else - method = "collect_#{@form.to_s}" - objects = send(method).each do |obj| - obj.virtual = false - end - return false if objects.empty? - end - - # we have an override for the collected resources - if @overrides and !objects.empty? - # force the resource to be always child of any other resource - overrides[:source].meta_def(:child_of?) do |klass| - true - end - - # tell the compiler we have some override for him unless we already - # overrided those resources - objects.each do |res| - unless @collected.include?(res.ref) - newres = Puppet::Parser::Resource. - new(res.type, res.title, - :parameters => overrides[:parameters], - :file => overrides[:file], - :line => overrides[:line], - :source => overrides[:source], - :scope => overrides[:scope]) - - scope.compiler.add_override(newres) - end - end - end - - # filter out object that this collector has previously found. - objects.reject! { |o| @collected.include?(o.ref) } - - return false if objects.empty? - - # keep an eye on the resources we have collected - objects.inject(@collected) { |c,o| c[o.ref]=o; c } - - # return our newly collected resources - objects - end - - def initialize(scope, type, equery, vquery, form) - @scope = scope - @vquery = vquery - @equery = equery - - # initialisation - @collected = {} - - # Canonize the type - @type = Puppet::Resource.new(type, "whatever").type - - unless [:exported, :virtual].include?(form) - raise ArgumentError, "Invalid query form #{form}" - end - @form = form - end - - # add a resource override to the soon to be exported/realized resources - def add_override(hash) - raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters] - - # schedule an override for an upcoming collection - @overrides = hash - end - - private - - # Collect exported objects. - def collect_exported - resources = [] - - time = Puppet::Util.thinmark do - # First get everything from the export table. Just reuse our - # collect_virtual method but tell it to use 'exported? for the test. - resources = collect_virtual(true).reject { |r| ! r.virtual? } - - # key is '#{type}/#{name}', and host and filter. - found = Puppet::Resource.indirection. - search(@type, :host => @scope.compiler.node.name, :filter => @equery, :scope => @scope) - - found_resources = found.map {|x| x.is_a?(Puppet::Parser::Resource) ? x : x.to_resource(@scope)} - - found_resources.each do |item| - if existing = @scope.findresource(item.type, item.title) - unless existing.collector_id == item.collector_id - # unless this is the one we've already collected - raise Puppet::ParseError, - "A duplicate resource was found while collecting exported resources, with the type and title #{item.ref}" - end - else - item.exported = false - @scope.compiler.add_resource(@scope, item) - resources << item - end - end - end - - scope.debug("Collected %s %s resource%s in %.2f seconds" % - [resources.length, @type, resources.length == 1 ? "" : "s", time]) - - resources - end - - def collect_resources - @resources = [@resources] unless @resources.is_a?(Array) - method = "collect_#{form.to_s}_resources" - send(method) - end - - def collect_exported_resources - raise Puppet::ParseError, "realize() is not yet implemented for exported resources" - end - - # Collect resources directly; this is the result of using 'realize', - # which specifies resources, rather than using a normal collection. - def collect_virtual_resources - return [] unless defined?(@resources) and ! @resources.empty? - result = @resources.dup.collect do |ref| - if res = @scope.findresource(ref.to_s) - @resources.delete(ref) - res - end - end.reject { |r| r.nil? }.each do |res| - res.virtual = false - end - - # If there are no more resources to find, delete this from the list - # of collections. - @scope.compiler.delete_collection(self) if @resources.empty? - - result - end - - # Collect just virtual objects, from our local compiler. - def collect_virtual(exported = false) - scope.compiler.resources.find_all do |resource| - resource.type == @type and (exported ? resource.exported? : true) and match?(resource) - end - end - - # Does the resource match our tests? We don't yet support tests, - # so it's always true at the moment. - def match?(resource) - if self.vquery - return self.vquery.call(resource) - else - return true - end - end -end diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index 2b8d3eaa6..17ff299e7 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -1,19 +1,13 @@ # This is just syntactic sugar for a collection, although it will generally # be a good bit faster. Puppet::Parser::Functions::newfunction(:realize, :arity => -2, :doc => "Make a virtual object real. This is useful when you want to know the name of the virtual object and don't want to bother with a full collection. It is slightly faster than a collection, and, of course, is a bit shorter. You must pass the object using a reference; e.g.: `realize User[luke]`." ) do |vals| vals = [vals] unless vals.is_a?(Array) - if Puppet[:parser] == 'future' - coll = Puppet::Pops::Evaluator::Collectors::FixedSetCollector.new(self, vals.flatten) - else - coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) - coll.resources = vals.flatten - end - + coll = Puppet::Pops::Evaluator::Collectors::FixedSetCollector.new(self, vals.flatten) compiler.add_collection(coll) end diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra deleted file mode 100644 index c7b83fe6b..000000000 --- a/lib/puppet/parser/grammar.ra +++ /dev/null @@ -1,806 +0,0 @@ -# vim: syntax=ruby - -# the parser - -class Puppet::Parser::Parser - -token STRING DQPRE DQMID DQPOST -token LBRACK RBRACK LBRACE RBRACE SYMBOL FARROW COMMA TRUE -token FALSE EQUALS APPENDS LESSEQUAL NOTEQUAL DOT COLON LLCOLLECT RRCOLLECT -token QMARK LPAREN RPAREN ISEQUAL GREATEREQUAL GREATERTHAN LESSTHAN -token IF ELSE IMPORT DEFINE ELSIF VARIABLE CLASS INHERITS NODE BOOLEAN -token NAME SEMIC CASE DEFAULT AT LCOLLECT RCOLLECT CLASSREF -token NOT OR AND UNDEF PARROW PLUS MINUS TIMES DIV LSHIFT RSHIFT UMINUS -token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB -token IN UNLESS MODULO - -prechigh - right NOT - nonassoc UMINUS - left IN MATCH NOMATCH - left TIMES DIV MODULO - left MINUS PLUS - left LSHIFT RSHIFT - left NOTEQUAL ISEQUAL - left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL - left AND - left OR -preclow - -rule -program: statements_and_declarations - | nil - - statements_and_declarations: statement_or_declaration { - result = ast AST::BlockExpression, :children => (val[0] ? [val[0]] : []) - } - | statements_and_declarations statement_or_declaration { - if val[1] - val[0].push(val[1]) - end - result = val[0] - } - -# statements is like statements_and_declarations, but it doesn't allow -# nested definitions, classes, or nodes. -statements: statements_and_declarations { - val[0].each do |stmt| - if stmt.is_a?(AST::TopLevelConstruct) - error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ - :line => stmt.context[:line], :file => stmt.context[:file] - end - end - result = val[0] -} - -# The main list of valid statements -statement_or_declaration: resource - | virtualresource - | collection - | assignment - | casestatement - | ifstatement_begin - | unlessstatement - | import - | fstatement - | definition - | hostclass - | nodedef - | resourceoverride - | append - | relationship - -keyword: AND - | CASE - | CLASS - | DEFAULT - | DEFINE - | ELSE - | ELSIF - | IF - | IN - | IMPORT - | INHERITS - | NODE - | OR - | UNDEF - | UNLESS - -relationship: relationship_side edge relationship_side { - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) -} - | relationship edge relationship_side { - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) -} - -relationship_side: resource - | resourceref - | collection - | variable - | quotedtext - | selector - | casestatement - | hasharrayaccesses - -edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB - -fstatement: NAME LPAREN expressions RPAREN { - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[2], - :ftype => :statement -} -| NAME LPAREN expressions COMMA RPAREN { - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[2], - :ftype => :statement -} | NAME LPAREN RPAREN { - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :statement -} - | NAME funcvalues { - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[1], - :ftype => :statement -} - -funcvalues: rvalue { result = aryfy(val[0]) } -# This rvalue could be an expression - | funcvalues COMMA rvalue { - val[0].push(val[2]) - result = val[0] -} - -expressions: expression { result = aryfy(val[0]) } - | expressions comma expression { result = val[0].push(val[2]) } - -rvalue: quotedtext - | name - | type - | boolean - | selector - | variable - | array - | hasharrayaccesses - | resourceref - | funcrvalue - | undef - -resource: classname LBRACE resourceinstances endsemi RBRACE { - @lexer.commentpop - result = ast(AST::Resource, :type => val[0], :instances => val[2]) -} | classname LBRACE params endcomma RBRACE { - # This is a deprecated syntax. - error "All resource specifications require names" -} | type LBRACE params endcomma RBRACE { - # a defaults setting for a type - @lexer.commentpop - result = ast(AST::ResourceDefaults, :type => val[0].value, :parameters => val[2]) -} - -# Override a value set elsewhere in the configuration. -resourceoverride: resourceref LBRACE anyparams endcomma RBRACE { - @lexer.commentpop - result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] -} - -# Exported and virtual resources; these don't get sent to the client -# unless they get collected elsewhere in the db. -virtualresource: at resource { - type = val[0] - - if (type == :exported and ! Puppet[:storeconfigs]) - Puppet.warning addcontext("You cannot collect without storeconfigs being set") - end - - error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults - - method = type.to_s + "=" - - # Just mark our resource as exported and pass it through. - val[1].send(method, true) - - result = val[1] -} - -at: AT { result = :virtual } - | AT AT { result = :exported } - -# A collection statement. Currently supports no arguments at all, but eventually -# will, I assume. -collection: type collectrhand LBRACE anyparams endcomma RBRACE { - @lexer.commentpop - type = val[0].value.downcase - args = {:type => type} - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - args[:override] = val[3] - result = ast AST::Collection, args -} - | type collectrhand { - type = val[0].value.downcase - args = {:type => type } - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - result = ast AST::Collection, args -} - - -collectrhand: LCOLLECT collstatements RCOLLECT { - if val[1] - result = val[1] - result.form = :virtual - else - result = :virtual - end -} - | LLCOLLECT collstatements RRCOLLECT { - if val[1] - result = val[1] - result.form = :exported - else - result = :exported - end -} - -# A mini-language for handling collection comparisons. This is organized -# to avoid the need for precedence indications. -collstatements: nil - | collstatement - | collstatements colljoin collstatement { - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] -} - -collstatement: collexpr - | LPAREN collstatements RPAREN { - result = val[1] - result.parens = true -} - -colljoin: AND { result=val[0][:value] } - | OR { result=val[0][:value] } - -collexpr: colllval ISEQUAL expression { - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val -} - | colllval NOTEQUAL expression { - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val -} - -colllval: variable - | name - -resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] -} - -resourceinstances: resourceinst { result = aryfy(val[0]) } - | resourceinstances SEMIC resourceinst { - val[0].push val[2] - result = val[0] -} - -endsemi: # nothing - | SEMIC - -undef: UNDEF { - result = ast AST::Undef, :value => :undef -} - -name: NAME { - result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] -} - -type: CLASSREF { - result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] -} - -resourcename: quotedtext - | name - | type - | selector - | variable - | array - | hasharrayaccesses - -assignment: VARIABLE EQUALS expression { - raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ - # this is distinct from referencing a variable - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] -} - | hasharrayaccess EQUALS expression { - result = ast AST::VarDef, :name => val[0], :value => val[2] -} - -append: VARIABLE APPENDS expression { - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] -} - -params: # nothing -{ - result = ast AST::ASTArray -} - | param { result = aryfy(val[0]) } - | params COMMA param { - val[0].push(val[2]) - result = val[0] -} - -param_name: NAME - | keyword - | BOOLEAN - -param: param_name FARROW expression { - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] -} - -addparam: NAME PARROW expression { - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], - :add => true -} - -anyparam: param - | addparam - -anyparams: # nothing -{ - result = ast AST::ASTArray -} - | anyparam { result = aryfy(val[0]) } - | anyparams COMMA anyparam { - val[0].push(val[2]) - result = val[0] -} - -# We currently require arguments in these functions. -funcrvalue: NAME LPAREN expressions RPAREN { - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => val[2], - :ftype => :rvalue -} | NAME LPAREN RPAREN { - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :rvalue -} - -quotedtext: STRING { result = ast AST::String, :value => val[0][:value], :line => val[0][:line] } - | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] } - -dqrval: expression dqtail { result = [val[0]] + val[1] } - -dqtail: DQPOST { result = [ast(AST::String,val[0])] } - | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] } - -boolean: BOOLEAN { - result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] -} - -resourceref: NAME LBRACK expressions RBRACK { - Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] -} | type LBRACK expressions RBRACK { - result = ast AST::ResourceReference, :type => val[0].value, :title => val[2] -} - -unlessstatement: UNLESS expression LBRACE statements RBRACE { - @lexer.commentpop - args = { - :test => ast(AST::Not, :value => val[1]), - :statements => val[3] - } - - result = ast AST::IfStatement, args -} - | UNLESS expression LBRACE RBRACE { - @lexer.commentpop - args = { - :test => ast(AST::Not, :value => val[1]), - :statements => ast(AST::Nop) - } - result = ast AST::IfStatement, args -} - -ifstatement_begin: IF ifstatement { - result = val[1] -} - -ifstatement: expression LBRACE statements RBRACE else { - @lexer.commentpop - args = { - :test => val[0], - :statements => val[2] - } - - args[:else] = val[4] if val[4] - - result = ast AST::IfStatement, args -} - | expression LBRACE RBRACE else { - @lexer.commentpop - args = { - :test => val[0], - :statements => ast(AST::Nop) - } - - args[:else] = val[3] if val[3] - - result = ast AST::IfStatement, args -} - -else: # nothing - | ELSIF ifstatement { - result = ast AST::Else, :statements => val[1] -} - | ELSE LBRACE statements RBRACE { - @lexer.commentpop - result = ast AST::Else, :statements => val[2] -} - | ELSE LBRACE RBRACE { - @lexer.commentpop - result = ast AST::Else, :statements => ast(AST::Nop) -} - -# Unlike yacc/bison, it seems racc -# gives tons of shift/reduce warnings -# with the following syntax: -# -# expression: ... -# | expression arithop expressio { ... } -# -# arithop: PLUS | MINUS | DIVIDE | TIMES ... -# -# So I had to develop the expression by adding one rule -# per operator :-( - -expression: rvalue - | hash - | expression IN expression { - result = ast AST::InOperator, :lval => val[0], :rval => val[2] -} - | expression MATCH regex { - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression NOMATCH regex { - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression PLUS expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression MINUS expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression DIV expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression TIMES expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression MODULO expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression LSHIFT expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression RSHIFT expression { - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | MINUS expression =UMINUS { - result = ast AST::Minus, :value => val[1] -} - | expression NOTEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression ISEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression GREATERTHAN expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression GREATEREQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression LESSTHAN expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression LESSEQUAL expression { - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | NOT expression { - result = ast AST::Not, :value => val[1] -} - | expression AND expression { - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | expression OR expression { - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] -} - | LPAREN expression RPAREN { - result = val[1] -} - -casestatement: CASE expression LBRACE caseopts RBRACE { - @lexer.commentpop - result = ast AST::CaseStatement, :test => val[1], :options => val[3] -} - -caseopts: caseopt { result = aryfy(val[0]) } - | caseopts caseopt { - val[0].push val[1] - result = val[0] -} - -caseopt: casevalues COLON LBRACE statements RBRACE { - @lexer.commentpop - result = ast AST::CaseOpt, :value => val[0], :statements => val[3] -} | casevalues COLON LBRACE RBRACE { - @lexer.commentpop - - result = ast( - AST::CaseOpt, - :value => val[0], - - :statements => ast(AST::BlockExpression) - ) -} - -casevalues: selectlhand { result = aryfy(val[0]) } - | casevalues COMMA selectlhand { - val[0].push(val[2]) - result = val[0] -} - -selector: selectlhand QMARK svalues { - result = ast AST::Selector, :param => val[0], :values => val[2] -} - -svalues: selectval - | LBRACE sintvalues endcomma RBRACE { - @lexer.commentpop - result = val[1] -} - -sintvalues: selectval - | sintvalues comma selectval { - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end -} - -selectval: selectlhand FARROW rvalue { - result = ast AST::ResourceParam, :param => val[0], :value => val[2] -} - -selectlhand: name - | type - | quotedtext - | variable - | funcrvalue - | boolean - | undef - | hasharrayaccess - | DEFAULT { - result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] -} - | regex - -# These are only used for importing, and we don't interpolate there. -string: STRING { result = [val[0][:value]] } -strings: string - | strings COMMA string { result = val[0] += val[2] } - -import: IMPORT strings { - val[1].each do |file| - import(file) - end - - result = nil -} - -# Disable definition inheritance for now. 8/27/06, luke -#definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { -definition: DEFINE classname argumentlist LBRACE statements RBRACE { - @lexer.commentpop - result = Puppet::Parser::AST::Definition.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :code => val[4], - :line => val[0][:line])) - @lexer.indefine = false - -#} | DEFINE NAME argumentlist parent LBRACE RBRACE { -} | DEFINE classname argumentlist LBRACE RBRACE { - @lexer.commentpop - result = Puppet::Parser::AST::Definition.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) - @lexer.indefine = false -} - -#hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { -hostclass: CLASS classname argumentlist classparent LBRACE statements_and_declarations RBRACE { - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :parent => val[3], - :code => val[5], :line => val[0][:line])) -} | CLASS classname argumentlist classparent LBRACE RBRACE { - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :parent => val[3], - :line => val[0][:line])) -} - -nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { - @lexer.commentpop - result = Puppet::Parser::AST::Node.new(val[1], - ast_context(true).merge(:parent => val[2], :code => val[4], - :line => val[0][:line])) -} | NODE hostnames nodeparent LBRACE RBRACE { - @lexer.commentpop - result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) -} - -classname: NAME { result = val[0][:value] } - | CLASS { result = "class" } - -# Multiple hostnames, as used for node names. These are all literal -# strings, not AST objects. -hostnames: nodename { - result = [result] -} - | hostnames COMMA nodename { - result = val[0] - result << val[2] -} - -nodename: hostname { - result = ast AST::HostName, :value => val[0] -} - -hostname: NAME { result = val[0][:value] } - | STRING { result = val[0][:value] } - | DEFAULT { result = val[0][:value] } - | regex - -nil: { - result = nil -} - -nothing: { - result = ast AST::ASTArray, :children => [] -} - -argumentlist: nil - | LPAREN nothing RPAREN { - result = nil -} - | LPAREN arguments endcomma RPAREN { - result = val[1] - result = [result] unless result[0].is_a?(Array) -} - -arguments: argument - | arguments COMMA argument { - result = val[0] - result = [result] unless result[0].is_a?(Array) - result << val[2] -} - -argument: - VARIABLE EQUALS expression { result = [val[0][:value], val[2]] } -| VARIABLE { result = [val[0][:value]] } - -nodeparent: nil - | INHERITS hostname { - result = val[1] -} - -classparent: nil - | INHERITS classnameordefault { - result = val[1] -} - -classnameordefault: classname | DEFAULT - -variable: VARIABLE { - result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] -} - -array: LBRACK expressions RBRACK { result = val[1] } - | LBRACK expressions COMMA RBRACK { result = val[1] } - | LBRACK RBRACK { result = ast AST::ASTArray } - -comma: FARROW - | COMMA - -endcomma: # nothing - | COMMA { result = nil } - -regex: REGEX { - result = ast AST::Regex, :value => val[0][:value] -} - -hash: LBRACE hashpairs RBRACE { - @lexer.commentpop - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end -} - | LBRACE hashpairs COMMA RBRACE { - @lexer.commentpop - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end -} | LBRACE RBRACE { - @lexer.commentpop - result = ast AST::ASTHash -} - -hashpairs: hashpair - | hashpairs COMMA hashpair { - if val[0].instance_of?(AST::ASTHash) - result = val[0].merge(val[2]) - else - result = ast AST::ASTHash, :value => val[0] - result.merge(val[2]) - end -} - -hashpair: key FARROW expression { - result = ast AST::ASTHash, { :value => { val[0] => val[2] } } -} - -key: NAME { result = val[0][:value] } - | quotedtext { result = val[0] } - -hasharrayaccess: VARIABLE LBRACK expression RBRACK { - result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] -} - -hasharrayaccesses: hasharrayaccess - | hasharrayaccesses LBRACK expression RBRACK { - result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] -} - -end ----- header ---- -require 'puppet' -require 'puppet/parser/lexer' -require 'puppet/parser/ast' - -module Puppet - class ParseError < Puppet::Error; end - class ImportError < Racc::ParseError; end - class AlreadyImportedError < ImportError; end -end - ----- inner ---- - -# It got too annoying having code in a file that needs to be compiled. -require 'puppet/parser/parser_support' - -# Make emacs happy -# Local Variables: -# mode: ruby -# End: diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb deleted file mode 100644 index de1249991..000000000 --- a/lib/puppet/parser/lexer.rb +++ /dev/null @@ -1,608 +0,0 @@ -# the scanner/lexer - -require 'forwardable' -require 'strscan' -require 'puppet' -require 'puppet/util/methodhelper' - - -module Puppet - class LexError < RuntimeError; end -end - -module Puppet::Parser; end - -class Puppet::Parser::Lexer - extend Forwardable - - attr_reader :last, :file, :lexing_context, :token_queue - - attr_accessor :line, :indefine - alias :indefine? :indefine - - # Returns the position on the line. - # This implementation always returns nil. It is here for API reasons in Puppet::Error - # which needs to support both --parser current, and --parser future. - # - def pos - # Make the lexer comply with newer API. It does not produce a pos... - nil - end - - def lex_error msg - raise Puppet::LexError.new(msg) - end - - class Token - ALWAYS_ACCEPTABLE = Proc.new { |context| true } - - include Puppet::Util::MethodHelper - - attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate - alias skip? skip - alias accumulate? accumulate - - def initialize(string_or_regex, name, options = {}) - if string_or_regex.is_a?(String) - @name, @string = name, string_or_regex - @regex = Regexp.new(Regexp.escape(string_or_regex)) - else - @name, @regex = name, string_or_regex - end - - set_options(options) - @acceptable_when = ALWAYS_ACCEPTABLE - end - - def to_s - string or @name.to_s - end - - def acceptable?(context={}) - @acceptable_when.call(context) - end - - # Define when the token is able to match. - # This provides context that cannot be expressed otherwise, such as feature flags. - # - # @param block [Proc] a proc that given a context returns a boolean - def acceptable_when(block) - @acceptable_when = block - end - end - - # Maintain a list of tokens. - class TokenList - extend Forwardable - - attr_reader :regex_tokens, :string_tokens - def_delegator :@tokens, :[] - - # Create a new token. - def add_token(name, regex, options = {}, &block) - raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name) - token = Token.new(regex, name, options) - @tokens[token.name] = token - if token.string - @string_tokens << token - @tokens_by_string[token.string] = token - else - @regex_tokens << token - end - - token.meta_def(:convert, &block) if block_given? - - token - end - - def initialize - @tokens = {} - @regex_tokens = [] - @string_tokens = [] - @tokens_by_string = {} - end - - # Look up a token by its value, rather than name. - def lookup(string) - @tokens_by_string[string] - end - - # Define more tokens. - def add_tokens(hash) - hash.each do |regex, name| - add_token(name, regex) - end - end - - # Sort our tokens by length, so we know once we match, we're done. - # This helps us avoid the O(n^2) nature of token matching. - def sort_tokens - @string_tokens.sort! { |a, b| b.string.length <=> a.string.length } - end - - # Yield each token name and value in turn. - def each - @tokens.each {|name, value| yield name, value } - end - end - - TOKENS = TokenList.new - TOKENS.add_tokens( - '[' => :LBRACK, - ']' => :RBRACK, - '{' => :LBRACE, - '}' => :RBRACE, - '(' => :LPAREN, - ')' => :RPAREN, - '=' => :EQUALS, - '+=' => :APPENDS, - '==' => :ISEQUAL, - '>=' => :GREATEREQUAL, - '>' => :GREATERTHAN, - '<' => :LESSTHAN, - '<=' => :LESSEQUAL, - '!=' => :NOTEQUAL, - '!' => :NOT, - ',' => :COMMA, - '.' => :DOT, - ':' => :COLON, - '@' => :AT, - '<<|' => :LLCOLLECT, - '|>>' => :RRCOLLECT, - '->' => :IN_EDGE, - '<-' => :OUT_EDGE, - '~>' => :IN_EDGE_SUB, - '<~' => :OUT_EDGE_SUB, - '<|' => :LCOLLECT, - '|>' => :RCOLLECT, - ';' => :SEMIC, - '?' => :QMARK, - '\\' => :BACKSLASH, - '=>' => :FARROW, - '+>' => :PARROW, - '+' => :PLUS, - '-' => :MINUS, - '/' => :DIV, - '*' => :TIMES, - '%' => :MODULO, - '<<' => :LSHIFT, - '>>' => :RSHIFT, - '=~' => :MATCH, - '!~' => :NOMATCH, - %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF, - "" => :STRING, - "" => :DQPRE, - "" => :DQMID, - "" => :DQPOST, - "" => :BOOLEAN - ) - - module Contextual - QUOTE_TOKENS = [:DQPRE,:DQMID] - REGEX_INTRODUCING_TOKENS = [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA] - - NOT_INSIDE_QUOTES = Proc.new do |context| - !QUOTE_TOKENS.include? context[:after] - end - - INSIDE_QUOTES = Proc.new do |context| - QUOTE_TOKENS.include? context[:after] - end - - IN_REGEX_POSITION = Proc.new do |context| - REGEX_INTRODUCING_TOKENS.include? context[:after] - end - - IN_STRING_INTERPOLATION = Proc.new do |context| - context[:string_interpolation_depth] > 0 - end - - DASHED_VARIABLES_ALLOWED = Proc.new do |context| - Puppet[:allow_variables_with_dashes] - end - - VARIABLE_AND_DASHES_ALLOWED = Proc.new do |context| - Contextual::DASHED_VARIABLES_ALLOWED.call(context) and TOKENS[:VARIABLE].acceptable?(context) - end - end - - # Numbers are treated separately from names, so that they may contain dots. - TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value| - [TOKENS[:NAME], value] - end - TOKENS[:NUMBER].acceptable_when Contextual::NOT_INSIDE_QUOTES - - TOKENS.add_token :NAME, %r{((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*} do |lexer, value| - string_token = self - # we're looking for keywords here - if tmp = KEYWORDS.lookup(value) - string_token = tmp - if [:TRUE, :FALSE].include?(string_token.name) - value = eval(value) - string_token = TOKENS[:BOOLEAN] - end - end - [string_token, value] - end - [:NAME, :CLASSREF].each do |name_token| - TOKENS[name_token].acceptable_when Contextual::NOT_INSIDE_QUOTES - end - - TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value| - value.sub!(/# ?/,'') - [self, value] - end - - TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value| - lexer.line += value.count("\n") - value.sub!(/^\/\* ?/,'') - value.sub!(/ ?\*\/$/,'') - [self,value] - end - - TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value| - # Make sure we haven't matched an escaped / - while value[-2..-2] == '\\' - other = lexer.scan_until(%r{/}) - value += other - end - regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/") - [self, Regexp.new(regex)] - end - TOKENS[:REGEX].acceptable_when Contextual::IN_REGEX_POSITION - - TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true - - TOKENS.add_token :SQUOTE, "'" do |lexer, value| - [TOKENS[:STRING], lexer.slurpstring(value,["'"],:ignore_invalid_escapes).first ] - end - - DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING} - DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST} - - TOKENS.add_token :DQUOTE, /"/ do |lexer, value| - lexer.tokenize_interpolated_string(DQ_initial_token_types) - end - - TOKENS.add_token :DQCONT, /\}/ do |lexer, value| - lexer.tokenize_interpolated_string(DQ_continuation_token_types) - end - TOKENS[:DQCONT].acceptable_when Contextual::IN_STRING_INTERPOLATION - - TOKENS.add_token :DOLLAR_VAR_WITH_DASH, %r{\$(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value| - lexer.warn_if_variable_has_hyphen(value) - - [TOKENS[:VARIABLE], value[1..-1]] - end - TOKENS[:DOLLAR_VAR_WITH_DASH].acceptable_when Contextual::DASHED_VARIABLES_ALLOWED - - TOKENS.add_token :DOLLAR_VAR, %r{\$(::)?(\w+::)*\w+} do |lexer, value| - [TOKENS[:VARIABLE],value[1..-1]] - end - - TOKENS.add_token :VARIABLE_WITH_DASH, %r{(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value| - lexer.warn_if_variable_has_hyphen(value) - - [TOKENS[:VARIABLE], value] - end - TOKENS[:VARIABLE_WITH_DASH].acceptable_when Contextual::VARIABLE_AND_DASHES_ALLOWED - - TOKENS.add_token :VARIABLE, %r{(::)?(\w+::)*\w+} - TOKENS[:VARIABLE].acceptable_when Contextual::INSIDE_QUOTES - - TOKENS.sort_tokens - - @@pairs = { - "{" => "}", - "(" => ")", - "[" => "]", - "<|" => "|>", - "<<|" => "|>>" - } - - KEYWORDS = TokenList.new - KEYWORDS.add_tokens( - "case" => :CASE, - "class" => :CLASS, - "default" => :DEFAULT, - "define" => :DEFINE, - "import" => :IMPORT, - "if" => :IF, - "elsif" => :ELSIF, - "else" => :ELSE, - "inherits" => :INHERITS, - "node" => :NODE, - "and" => :AND, - "or" => :OR, - "undef" => :UNDEF, - "false" => :FALSE, - "true" => :TRUE, - "in" => :IN, - "unless" => :UNLESS - ) - - def clear - initvars - end - - def expected - return nil if @expected.empty? - name = @expected[-1] - TOKENS.lookup(name) or lex_error "Could not find expected token #{name}" - end - - # scan the whole file - # basically just used for testing - def fullscan - array = [] - - self.scan { |token, str| - # Ignore any definition nesting problems - @indefine = false - array.push([token,str]) - } - array - end - - def file=(file) - @file = file - @line = 1 - contents = Puppet::FileSystem.exist?(file) ? Puppet::FileSystem.read(file) : "" - @scanner = StringScanner.new(contents) - end - - def_delegator :@token_queue, :shift, :shift_token - - def find_string_token - # We know our longest string token is three chars, so try each size in turn - # until we either match or run out of chars. This way our worst-case is three - # tries, where it is otherwise the number of string token we have. Also, - # the lookups are optimized hash lookups, instead of regex scans. - # - s = @scanner.peek(3) - token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1]) - [ token, token && @scanner.scan(token.regex) ] - end - - # Find the next token that matches a regex. We look for these first. - def find_regex_token - best_token = nil - best_length = 0 - - # I tried optimizing based on the first char, but it had - # a slightly negative affect and was a good bit more complicated. - TOKENS.regex_tokens.each do |token| - if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context) - # We've found a longer match - if length > best_length - best_length = length - best_token = token - end - end - end - - return best_token, @scanner.scan(best_token.regex) if best_token - end - - # Find the next token, returning the string and the token. - def find_token - shift_token || find_regex_token || find_string_token - end - - def initialize - initvars - end - - def initvars - @line = 1 - @previous_token = nil - @scanner = nil - @file = nil - # AAARRGGGG! okay, regexes in ruby are bloody annoying - # no one else has "\n" =~ /\s/ - @skip = %r{[ \t\r]+} - - @namestack = [] - @token_queue = [] - @indefine = false - @expected = [] - @commentstack = [ ['', @line] ] - @lexing_context = { - :after => nil, - :start_of_line => true, - :string_interpolation_depth => 0 - } - end - - # Make any necessary changes to the token and/or value. - def munge_token(token, value) - @line += 1 if token.incr_line - - skip if token.skip_text - - return if token.skip and not token.accumulate? - - token, value = token.convert(self, value) if token.respond_to?(:convert) - - return unless token - - if token.accumulate? - comment = @commentstack.pop - comment[0] << value + "\n" - @commentstack.push(comment) - end - - return if token.skip - - return token, { :value => value, :line => @line } - end - - # Handling the namespace stack - def_delegator :@namestack, :pop, :namepop - # This value might have :: in it, but we don't care -- it'll be handled - # normally when joining, and when popping we want to pop this full value, - # however long the namespace is. - def_delegator :@namestack, :<<, :namestack - - # Collect the current namespace. - def namespace - @namestack.join("::") - end - - def_delegator :@scanner, :rest - - # this is the heart of the lexer - def scan - #Puppet.debug("entering scan") - lex_error "Invalid or empty string" unless @scanner - - # Skip any initial whitespace. - skip - - until token_queue.empty? and @scanner.eos? do - matched_token, value = find_token - - # error out if we didn't match anything at all - lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token - - newline = matched_token.name == :RETURN - - # this matches a blank line; eat the previously accumulated comments - getcomment if lexing_context[:start_of_line] and newline - lexing_context[:start_of_line] = newline - - final_token, token_value = munge_token(matched_token, value) - - unless final_token - skip - next - end - - final_token_name = final_token.name - lexing_context[:after] = final_token_name unless newline - lexing_context[:string_interpolation_depth] += 1 if final_token_name == :DQPRE - lexing_context[:string_interpolation_depth] -= 1 if final_token_name == :DQPOST - - value = token_value[:value] - - if match = @@pairs[value] and final_token_name != :DQUOTE and final_token_name != :SQUOTE - @expected << match - elsif exp = @expected[-1] and exp == value and final_token_name != :DQUOTE and final_token_name != :SQUOTE - @expected.pop - end - - if final_token_name == :LBRACE or final_token_name == :LPAREN - commentpush - end - if final_token_name == :RPAREN - commentpop - end - - yield [final_token_name, token_value] - - if @previous_token - namestack(value) if @previous_token.name == :CLASS and value != '{' - - if @previous_token.name == :DEFINE - if indefine? - msg = "Cannot nest definition #{value} inside #{@indefine}" - self.indefine = false - raise Puppet::ParseError, msg - end - - @indefine = value - end - end - @previous_token = final_token - skip - end - @scanner = nil - - # This indicates that we're done parsing. - yield [false,false] - end - - # Skip any skipchars in our remaining string. - def skip - @scanner.skip(@skip) - end - - # Provide some limited access to the scanner, for those - # tokens that need it. - def_delegator :@scanner, :scan_until - - # we've encountered the start of a string... - # slurp in the rest of the string and return it - def slurpstring(terminators,escapes=%w{ \\ $ ' " r n t s }+["\n"],ignore_invalid_escapes=false) - # we search for the next quote that isn't preceded by a - # backslash; the caret is there to match empty strings - str = @scanner.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" - @line += str.count("\n") # literal carriage returns add to the line count. - str.gsub!(/\\(.)/m) { - ch = $1 - if escapes.include? ch - case ch - when 'r'; "\r" - when 'n'; "\n" - when 't'; "\t" - when 's'; " " - when "\n"; '' - else ch - end - else - Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" unless ignore_invalid_escapes - "\\#{ch}" - end - } - [ str[0..-2],str[-1,1] ] - end - - def tokenize_interpolated_string(token_type,preamble='') - value,terminator = slurpstring('"$') - token_queue << [TOKENS[token_type[terminator]],preamble+value] - variable_regex = if Puppet[:allow_variables_with_dashes] - TOKENS[:VARIABLE_WITH_DASH].regex - else - TOKENS[:VARIABLE].regex - end - if terminator != '$' or @scanner.scan(/\{/) - token_queue.shift - elsif var_name = @scanner.scan(variable_regex) - warn_if_variable_has_hyphen(var_name) - token_queue << [TOKENS[:VARIABLE],var_name] - tokenize_interpolated_string(DQ_continuation_token_types) - else - tokenize_interpolated_string(token_type,token_queue.pop.last + terminator) - end - end - - # just parse a string, not a whole file - def string=(string) - @scanner = StringScanner.new(string) - end - - # returns the content of the currently accumulated content cache - def commentpop - @commentstack.pop[0] - end - - def getcomment(line = nil) - comment = @commentstack.last - if line.nil? or comment[1] <= line - @commentstack.pop - @commentstack.push(['', @line]) - return comment[0] - end - '' - end - - def commentpush - @commentstack.push(['', @line]) - end - - def warn_if_variable_has_hyphen(var_name) - if var_name.include?('-') - Puppet.deprecation_warning("Using `-` in variable names is deprecated at #{file || ''}:#{line}. See http://links.puppetlabs.com/puppet-hyphenated-variable-deprecation") - end - end -end diff --git a/lib/puppet/parser/makefile b/lib/puppet/parser/makefile deleted file mode 100644 index c4911d097..000000000 --- a/lib/puppet/parser/makefile +++ /dev/null @@ -1,8 +0,0 @@ -#parser.rb: grammar.ry -# ryacc --output parser grammar - -parser.rb: grammar.ra - racc -o$@ grammar.ra - -grammar.output: grammar.ra - racc -v -o$@ grammar.ra diff --git a/lib/puppet/parser/methods.rb b/lib/puppet/parser/methods.rb deleted file mode 100644 index af19b2a03..000000000 --- a/lib/puppet/parser/methods.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'puppet/util/autoload' -require 'puppet/parser/scope' -require 'puppet/parser/functions' -require 'monitor' - -# A module for handling finding and invoking methods (functions invokable as a method). -# A method call on the form: -# -# $a.meth(1,2,3] {|...| ...} -# -# will lookup a function called 'meth' and call it with the arguments ($a, 1, 2, 3, ) -# -# @see Puppet::Parser::AST::Lambda -# @see Puppet::Parser::AST::MethodCall -# -# @api public -# @since 3.2 -# -module Puppet::Parser::Methods - Environment = Puppet::Node::Environment - # Represents an invokable method configured to be invoked for a given object. - # - class Method - def initialize(receiver, obj, method_name, rvalue) - @receiver = receiver - @o = obj - @method_name = method_name - @rvalue = rvalue - end - - # Invoke this method's function in the given scope with the given arguments and parameterized block. - # A method call on the form: - # - # $a.meth(1,2,3) {|...| ...} - # - # results in the equivalent: - # - # meth($a, 1, 2, 3, {|...| ... }) - # - # @param scope [Puppet::Parser::Scope] the scope the call takes place in - # @param args [Array] arguments 1..n to pass to the function - # @param pblock [Puppet::Parser::AST::Lambda] optional parameterized block to pass as the last argument - # to the called function - # - def invoke(scope, args=[], pblock=nil) - arguments = [@o] + args - arguments << pblock if pblock - @receiver.send(@method_name, arguments) - end - - # @return [Boolean] whether the method function produces an rvalue or not. - def is_rvalue? - @rvalue - end - end - - class << self - include Puppet::Util - end - - # Finds a function and returns an instance of Method configured to perform invocation. - # @return [Method, nil] configured method or nil if method not found - def self.find_method(scope, receiver, name) - fname = Puppet::Parser::Functions.function(name) - rvalue = Puppet::Parser::Functions.rvalue?(name) - return Method.new(scope, receiver, fname, rvalue) if fname - nil - end -end diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb deleted file mode 100644 index 16872ee34..000000000 --- a/lib/puppet/parser/parser.rb +++ /dev/null @@ -1,2559 +0,0 @@ -# -# DO NOT MODIFY!!!! -# This file is automatically generated by Racc 1.4.9 -# from Racc grammer file "". -# - -require 'racc/parser.rb' - -require 'puppet' -require 'puppet/parser/lexer' -require 'puppet/parser/ast' - -module Puppet - class ParseError < Puppet::Error; end - class ImportError < Racc::ParseError; end - class AlreadyImportedError < ImportError; end -end - -module Puppet - module Parser - class Parser < Racc::Parser - -module_eval(<<'...end grammar.ra/module_eval...', 'grammar.ra', 799) - -# It got too annoying having code in a file that needs to be compiled. -require 'puppet/parser/parser_support' - -# Make emacs happy -# Local Variables: -# mode: ruby -# End: -...end grammar.ra/module_eval... -##### State transition tables begin ### - -clist = [ -'35,36,199,198,246,159,-130,86,-112,82,277,357,361,379,356,215,210,159', -'276,-197,360,158,85,158,211,213,212,214,39,248,48,49,267,33,50,158,51', -'37,26,-129,40,46,30,35,36,32,84,217,216,31,398,203,204,206,205,208,209', -'-122,201,202,52,-130,-130,-130,-130,200,38,207,35,36,278,39,86,48,49', -'350,33,50,90,51,37,26,89,40,46,30,35,36,32,-178,94,253,31,257,280,257', -'364,274,273,92,93,215,210,52,257,255,226,336,62,38,211,213,212,214,39', -'338,48,49,254,33,50,339,51,37,26,347,40,46,30,35,36,32,-180,217,216', -'31,310,203,204,206,205,208,209,341,201,202,52,35,36,274,273,200,38,207', -'223,303,-178,39,304,48,49,-177,33,50,185,51,37,26,95,40,46,30,35,36', -'32,190,-184,281,31,397,189,344,90,201,202,226,89,215,210,52,200,357', -'250,32,356,38,211,213,212,214,39,-179,48,49,268,33,50,90,51,37,26,89', -'40,46,30,35,36,32,185,217,216,31,395,203,204,206,205,208,209,190,201', -'202,52,119,189,201,202,200,38,207,201,202,200,39,119,48,49,200,33,50', -'185,51,37,26,267,40,46,30,35,36,32,190,185,90,31,392,189,89,119,265', -'375,118,337,190,120,52,257,280,189,302,-96,38,118,257,263,120,39,-185', -'48,49,52,33,50,52,51,37,26,-123,40,46,30,35,36,32,52,103,118,31,252', -'120,279,206,205,251,257,280,201,202,52,250,243,243,262,200,38,207,257', -'263,52,137,135,139,134,136,80,132,140,141,177,168,240,131,162,35,36', -'82,32,180,142,130,163,271,94,-184,274,273,203,204,206,205,-183,52,-181', -'201,202,62,138,144,-180,353,200,39,207,48,49,354,33,50,330,51,37,26', -'-182,40,46,30,35,36,32,-177,52,-179,31,367,203,204,206,205,157,368,370', -'201,202,52,35,36,371,372,200,38,207,122,327,326,39,110,48,49,109,33', -'50,267,51,37,26,334,40,46,30,35,36,32,91,81,62,31,377,80,90,323,-179', -'37,128,382,40,46,52,35,36,32,383,-180,38,31,385,61,-228,39,387,48,49', -'388,33,50,52,51,37,26,323,40,46,30,35,36,32,319,110,393,31,308,80,90', -'317,305,37,128,158,40,46,52,53,399,32,400,,38,31,,,,39,,48,49,,33,50', -'52,51,37,26,,40,46,30,230,,32,,,,31,,,215,210,56,57,58,59,,,52,211,213', -'212,214,,38,203,204,206,205,208,209,,201,202,56,57,58,59,,200,,207,217', -'216,210,,203,204,206,205,208,209,211,201,202,228,-38,-38,-38,-38,200', -',207,,215,210,-44,-44,-44,-44,,,,211,213,212,214,,,203,204,206,205,208', -'209,,201,202,-40,-40,-40,-40,,200,,207,217,216,,,203,204,206,205,208', -'209,,201,202,229,,,,,200,,207,,215,210,206,205,,,,201,202,211,213,212', -'214,,200,,207,,,,35,36,,,103,,104,,,,,,217,216,,,203,204,206,205,208', -'209,102,201,202,35,36,,,103,200,104,207,80,,,,37,77,,,46,,,,32,101,102', -',31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36', -'100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,', -'104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52', -',37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46', -',,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101', -'102,,31,35,36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35', -'36,100,,103,,104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103', -',104,,80,,52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,', -'52,,37,77,,,46,,,,32,101,102,,31,35,36,100,,103,,104,,80,,52,,37,77', -',,46,35,36,,32,101,102,155,31,,,100,,,35,36,,80,103,52,,37,77,,,46,', -',,32,101,35,36,31,80,103,100,104,37,231,,,46,,52,,32,80,,,31,37,77,102', -',46,35,36,,32,103,52,104,31,80,,35,36,37,77,,,46,358,52,,32,101,102', -',31,,,100,35,36,,,,80,,52,,37,77,,,46,,80,,32,101,37,231,31,,46,100', -',,32,,,,31,52,80,,,,37,231,,,46,52,,,32,35,36,,31,103,,104,,,,,,,,52', -',,35,36,,,103,102,104,,,,,,,,,,80,,,,37,77,102,,46,,,,32,101,,,31,80', -',100,,37,77,,,46,,52,,32,101,35,36,31,,103,100,104,,,,35,36,,52,103', -',104,,,,35,36,102,,103,161,104,,,,,,102,80,,,,37,77,,,46,102,80,,32', -'101,37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101,35,36,31', -'52,103,100,104,,,,35,36,,52,103,,104,,,,35,36,102,,103,,104,,,,,,102', -'80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31', -'52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,78,,-197,,,', -'35,36,102,,103,,104,,,,,,63,80,,,,37,77,,,46,102,80,,32,101,37,77,31', -',46,100,80,,32,,37,77,31,52,46,,,,32,101,35,36,31,52,103,100,104,,,', -'35,36,,52,103,,104,,,,35,36,102,,103,,104,,,,,,102,80,,,,37,77,,,46', -'102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101', -'35,36,31,52,103,100,104,,,,35,36,,52,103,,104,,,,35,36,102,,103,,104', -',,,,,102,80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101', -'37,77,31,52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,103', -',104,,,,35,36,102,,103,,104,,,,,,102,80,,,,37,77,,,46,102,80,,32,101', -'37,77,31,,46,100,80,,32,101,37,77,31,52,46,100,,,32,101,35,36,31,52', -'103,100,104,,,,35,36,,52,103,161,104,,,,35,36,102,,103,,104,,,,,,102', -'80,,,,37,77,,,46,102,80,,32,101,37,77,31,,46,100,80,,32,101,37,77,31', -'52,46,100,,,32,101,35,36,31,52,103,100,104,,,,35,36,,52,,,,,,,35,36', -'102,,,,234,,,,35,36,,80,103,,,37,77,,,46,,80,,32,101,37,231,31,,46,100', -'80,,32,,37,231,31,52,46,,80,,32,,37,231,31,52,46,35,36,,32,103,,104', -'31,52,,35,36,,,103,,104,,52,,35,36,102,,,,,,,,,,102,80,,,,37,77,,,46', -',80,,32,101,37,77,31,,46,100,80,,32,101,37,231,31,52,46,100,,,32,,35', -'36,31,52,103,,104,,,,,,,52,,,,35,36,,,103,102,104,,,,,,,,,,80,,,,37', -'77,102,260,46,,35,36,32,101,103,,31,80,,100,,37,77,,,46,,52,,32,101', -'35,36,31,,103,100,104,,,,,,80,52,,,37,77,,,46,,102,,32,,210,,31,,,,', -'80,211,,,37,77,52,,46,,,,32,101,215,210,31,,,100,,,,211,213,212,214', -'52,203,204,206,205,208,209,,201,202,210,,,,,200,,207,211,217,216,,,203', -'204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,203', -'204,206,205,208,209,,201,202,,210,,,,200,,207,,211,217,216,,,203,204', -'206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,203,204', -'206,205,208,209,,201,202,,,,,,200,,207,,,217,216,,,203,204,206,205,208', -'209,,201,202,215,210,,,,200,,207,,211,213,212,214,203,204,206,205,208', -'209,,201,202,,,,,,200,,207,,,217,216,,,203,204,206,205,208,209,,201', -'202,215,210,,,,200,,207,301,211,213,212,214,,,,,215,210,,,,,,,,211,213', -'212,214,,,217,216,,,203,204,206,205,208,209,,201,202,,,,,,200,,207,203', -'204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,,', -',,,,,,215,210,,,,,,,,211,213,212,214,,,203,204,206,205,208,209,,201', -'202,,,,,,200,,207,217,216,,,203,204,206,205,208,209,,201,202,215,210', -',,,200,,207,,211,213,212,214,,,,,,,,,,,,,,,,,,,,,216,,,203,204,206,205', -'208,209,,201,202,215,210,,,,200,,207,,211,213,212,214,,,,,,,,,,,,,,', -',,,,,217,216,,,203,204,206,205,208,209,,201,202,215,210,,,,200,,207', -',211,213,212,214,,,,,215,210,,,,,,,,211,213,212,214,,,217,216,,,203', -'204,206,205,208,209,,201,202,,,,,,200,,207,203,204,206,205,208,209,', -'201,202,215,210,,,,200,,207,,211,213,212,214,,,,,,,,,,,,,,,,,,,,217', -'216,,,203,204,206,205,208,209,,201,202,215,210,,,,200,,207,,211,213', -'212,214,,,,,,,,,,,,,,,,,,,,217,216,,,203,204,206,205,208,209,,201,202', -',,,,,200,,207,137,135,139,134,136,,132,140,141,148,179,,131,133,,,,', -',142,130,143,137,135,139,134,136,,132,140,141,148,146,,131,133,,138', -'144,,,142,130,143,137,135,139,134,136,,132,140,141,148,146,,131,133', -',138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148,179,,131', -'133,,138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148,179', -',131,133,,138,144,,,142,130,143,137,135,139,134,136,,132,140,141,148', -'146,,131,133,,138,144,,,142,130,143,,,,,,,,,,,,,,,,138,144' ] - racc_action_table = arr = ::Array.new(2588, nil) - idx = 0 - clist.each do |str| - str.split(',', -1).each do |i| - arr[idx] = i.to_i unless i.empty? - idx += 1 - end - end - -clist = [ -'0,0,97,97,115,77,262,28,168,28,186,354,313,345,354,97,97,128,186,128', -'313,168,28,77,97,97,97,97,0,115,0,0,178,0,0,128,0,0,0,177,0,0,0,391', -'391,0,28,97,97,0,391,97,97,97,97,97,97,254,97,97,0,262,262,262,262,97', -'0,97,304,304,191,391,68,391,391,304,391,391,49,391,391,391,49,391,391', -'391,2,2,391,68,33,153,391,259,259,315,315,191,191,33,33,153,153,391', -'154,154,304,259,175,391,153,153,153,153,2,263,2,2,154,2,2,264,2,2,2', -'275,2,2,2,229,229,2,173,153,153,2,229,153,153,153,153,153,153,266,153', -'153,2,104,104,275,275,153,2,153,104,222,171,229,222,229,229,170,229', -'229,84,229,229,229,34,229,229,229,383,383,229,84,34,195,229,383,84,269', -'29,288,288,104,29,195,195,229,288,310,270,29,310,229,195,195,195,195', -'383,169,383,383,166,383,383,50,383,383,383,50,383,383,383,382,382,383', -'185,195,195,383,382,195,195,195,195,195,195,185,195,195,383,51,185,290', -'290,195,383,195,289,289,290,382,248,382,382,289,382,382,272,382,382', -'382,165,382,382,382,372,372,382,272,85,326,382,372,272,326,246,164,326', -'51,261,85,51,382,261,261,85,221,163,382,248,221,221,248,372,162,372', -'372,201,372,372,51,372,372,372,155,372,372,372,81,81,372,248,81,246', -'372,149,246,192,287,287,146,192,192,287,287,372,145,114,113,160,287', -'372,287,160,160,246,81,81,81,81,81,81,81,81,81,81,81,112,81,81,306,306', -'87,81,83,81,81,81,181,80,79,181,181,292,292,292,292,76,81,75,292,292', -'73,81,81,71,307,292,306,292,306,306,309,306,306,249,306,306,306,69,306', -'306,306,319,319,306,67,202,66,306,319,291,291,291,291,64,320,321,291', -'291,306,55,55,323,324,291,306,291,53,245,244,319,48,319,319,41,319,319', -'343,319,319,319,255,319,319,319,327,327,319,30,27,25,319,327,55,55,243', -'23,55,55,357,55,55,319,60,60,55,360,22,319,55,362,21,364,327,366,327', -'327,369,327,327,55,327,327,327,370,327,327,327,228,228,327,241,240,376', -'327,228,60,60,235,225,60,60,231,60,60,327,1,394,60,396,,327,60,,,,228', -',228,228,,228,228,60,228,228,228,,228,228,228,108,,228,,,,228,,,108', -'108,20,20,20,20,,,228,108,108,108,108,,228,294,294,294,294,294,294,', -'294,294,19,19,19,19,,294,,294,108,108,296,,108,108,108,108,108,108,296', -'108,108,105,5,5,5,5,108,,108,,105,105,9,9,9,9,,,,105,105,105,105,,,296', -'296,296,296,296,296,,296,296,7,7,7,7,,296,,296,105,105,,,105,105,105', -'105,105,105,,105,105,107,,,,,105,,105,,107,107,286,286,,,,286,286,107', -'107,107,107,,286,,286,,,,204,204,,,204,,204,,,,,,107,107,,,107,107,107', -'107,107,107,204,107,107,36,36,,,36,107,36,107,204,,,,204,204,,,204,', -',,204,204,36,,204,38,38,204,,38,,38,,36,,204,,36,36,,,36,,,,36,36,38', -',36,39,39,36,,39,,39,,38,,36,,38,38,,,38,,,,38,38,39,,38,40,40,38,,40', -',40,,39,,38,,39,39,,,39,,,,39,39,40,,39,214,214,39,,214,,214,,40,,39', -',40,40,,,40,,,,40,40,214,,40,213,213,40,,213,,213,,214,,40,,214,214', -',,214,,,,214,214,213,,214,212,212,214,,212,,212,,213,,214,,213,213,', -',213,,,,213,213,212,,213,211,211,213,,211,,211,,212,,213,,212,212,,', -'212,,,,212,212,211,,212,210,210,212,,210,,210,,211,,212,,211,211,,,211', -',,,211,211,210,,211,209,209,211,,209,,209,,210,,211,,210,210,,,210,', -',,210,210,209,,210,356,356,210,,356,,356,,209,,210,,209,209,,,209,,', -',209,209,356,,209,63,63,209,,63,,63,,356,,209,,356,356,,,356,361,361', -',356,356,63,63,356,,,356,,,317,317,,63,317,356,,63,63,,,63,,,,63,63', -'208,208,63,361,208,63,208,361,361,,,361,,63,,361,317,,,361,317,317,208', -',317,207,207,,317,207,361,207,317,208,,311,311,208,208,,,208,311,317', -',208,208,207,,208,,,208,363,363,,,,207,,208,,207,207,,,207,,311,,207', -'207,311,311,207,,311,207,,,311,,,,311,207,363,,,,363,363,,,363,311,', -',363,305,305,,363,305,,305,,,,,,,,363,,,206,206,,,206,305,206,,,,,,', -',,,305,,,,305,305,206,,305,,,,305,305,,,305,206,,305,,206,206,,,206', -',305,,206,206,205,205,206,,205,206,205,,,,215,215,,206,215,,215,,,,78', -'78,205,,78,78,78,,,,,,215,205,,,,205,205,,,205,78,215,,205,205,215,215', -'205,,215,205,78,,215,215,78,78,215,205,78,215,,,78,78,203,203,78,215', -'203,78,203,,,,371,371,,78,371,,371,,,,200,200,203,,200,,200,,,,,,371', -'203,,,,203,203,,,203,200,371,,203,203,371,371,203,,371,203,200,,371', -'371,200,200,371,203,200,371,,,200,200,199,199,200,371,199,200,199,,', -',26,26,,200,26,,26,,,,251,251,199,,251,,251,,,,,,26,199,,,,199,199,', -',199,251,26,,199,199,26,26,199,,26,199,251,,26,,251,251,26,199,251,', -',,251,251,86,86,251,26,86,251,86,,,,252,252,,251,252,,252,,,,92,92,86', -',92,,92,,,,,,252,86,,,,86,86,,,86,92,252,,86,86,252,252,86,,252,86,92', -',252,252,92,92,252,86,92,252,,,92,92,93,93,92,252,93,92,93,,,,94,94', -',92,94,,94,,,,95,95,93,,95,,95,,,,,,94,93,,,,93,93,,,93,95,94,,93,93', -'94,94,93,,94,93,95,,94,94,95,95,94,93,95,94,,,95,95,216,216,95,94,216', -'95,216,,,,100,100,,95,100,,100,,,,101,101,216,,101,,101,,,,,,100,216', -',,,216,216,,,216,101,100,,216,216,100,100,216,,100,216,101,,100,100', -'101,101,100,216,101,100,,,101,101,102,102,101,100,102,101,102,,,,103', -'103,,101,103,103,103,,,,256,256,102,,256,,256,,,,,,103,102,,,,102,102', -',,102,256,103,,102,102,103,103,102,,103,102,256,,103,103,256,256,103', -'102,256,103,,,256,256,217,217,256,103,217,256,217,,,,234,234,,256,,', -',,,,109,109,217,,,,109,,,,265,265,,217,265,,,217,217,,,217,,234,,217', -'217,234,234,217,,234,217,109,,234,,109,109,234,217,109,,265,,109,,265', -'265,109,234,265,276,276,,265,276,,276,265,109,,277,277,,,277,,277,,265', -',230,230,276,,,,,,,,,,277,276,,,,276,276,,,276,,277,,276,276,277,277', -'276,,277,276,230,,277,277,230,230,277,276,230,277,,,230,,159,159,230', -'277,159,,159,,,,,,,230,,,,158,158,,,158,159,158,,,,,,,,,,159,,,,159', -'159,158,158,159,,157,157,159,159,157,,159,158,,159,,158,158,,,158,,159', -',158,158,62,62,158,,62,158,62,,,,,,157,158,,,157,157,,,157,,62,,157', -',298,,157,,,,,62,298,,,62,62,157,,62,,,,62,62,335,335,62,,,62,,,,335', -'335,335,335,62,298,298,298,298,298,298,,298,298,295,,,,,298,,298,295', -'335,335,,,335,335,335,335,335,335,,335,335,390,390,,,,335,,335,,390', -'390,390,390,295,295,295,295,295,295,,295,295,,297,,,,295,,295,,297,390', -'390,,,390,390,390,390,390,390,,390,390,156,156,,,,390,,390,,156,156', -'156,156,297,297,297,297,297,297,,297,297,,,,,,297,,297,,,156,156,,,156', -'156,156,156,156,156,,156,156,194,194,,,,156,,156,,194,194,194,194,293', -'293,293,293,293,293,,293,293,,,,,,293,,293,,,194,194,,,194,194,194,194', -'194,194,,194,194,220,220,,,,194,,194,220,220,220,220,220,,,,,348,348', -',,,,,,,348,348,348,348,,,220,220,,,220,220,220,220,220,220,,220,220', -',,,,,220,,220,348,348,348,348,348,348,,348,348,349,349,,,,348,,348,', -'349,349,349,349,,,,,,,,,333,333,,,,,,,,333,333,333,333,,,349,349,349', -'349,349,349,,349,349,,,,,,349,,349,333,333,,,333,333,333,333,333,333', -',333,333,300,300,,,,333,,333,,300,300,300,300,,,,,,,,,,,,,,,,,,,,,300', -',,300,300,300,300,300,300,,300,300,352,352,,,,300,,300,,352,352,352', -'352,,,,,,,,,,,,,,,,,,,,352,352,,,352,352,352,352,352,352,,352,352,196', -'196,,,,352,,352,,196,196,196,196,,,,,299,299,,,,,,,,299,299,299,299', -',,196,196,,,196,196,196,196,196,196,,196,196,,,,,,196,,196,299,299,299', -'299,299,299,,299,299,193,193,,,,299,,299,,193,193,193,193,,,,,,,,,,', -',,,,,,,,,193,193,,,193,193,193,193,193,193,,193,193,332,332,,,,193,', -'193,,332,332,332,332,,,,,,,,,,,,,,,,,,,,332,332,,,332,332,332,332,332', -'332,,332,332,,,,,,332,,332,268,268,268,268,268,,268,268,268,268,268', -',268,268,,,,,,268,268,268,180,180,180,180,180,,180,180,180,180,180,', -'180,180,,268,268,,,180,180,180,61,61,61,61,61,,61,61,61,61,61,,61,61', -',180,180,,,61,61,61,267,267,267,267,267,,267,267,267,267,267,,267,267', -',61,61,,,267,267,267,82,82,82,82,82,,82,82,82,82,82,,82,82,,267,267', -',,82,82,82,250,250,250,250,250,,250,250,250,250,250,,250,250,,82,82', -',,250,250,250,,,,,,,,,,,,,,,,250,250' ] - racc_action_check = arr = ::Array.new(2588, nil) - idx = 0 - clist.each do |str| - str.split(',', -1).each do |i| - arr[idx] = i.to_i unless i.empty? - idx += 1 - end - end - -racc_action_pointer = [ - -2, 490, 84, nil, nil, 507, nil, 539, nil, 517, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 485, - 463, 447, 428, 417, nil, 428, 1304, 425, 1, 146, - 388, nil, nil, 84, 153, nil, 675, nil, 700, 725, - 750, 395, nil, nil, nil, nil, nil, nil, 413, 42, - 171, 231, nil, 411, nil, 402, nil, nil, nil, nil, - 445, 2453, 1832, 950, 386, nil, 368, 366, 66, 359, - nil, 345, nil, 359, nil, 339, 337, -1, 1180, 330, - 346, 299, 2497, 339, 140, 238, 1361, 337, nil, nil, - nil, nil, 1381, 1428, 1438, 1448, nil, -2, nil, nil, - 1505, 1515, 1562, 1572, 145, 561, nil, 615, 507, 1649, - nil, nil, 328, 297, 296, -8, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 11, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 307, 261, nil, nil, 297, - nil, nil, nil, 84, 93, 274, 1954, 1811, 1785, 1768, - 315, nil, 264, 257, 228, 242, 184, nil, -3, 178, - 138, 133, nil, 109, nil, 102, nil, 16, 20, nil, - 2431, 305, nil, nil, nil, 194, -8, nil, nil, nil, - nil, 48, 303, 2324, 1999, 170, 2262, nil, nil, 1294, - 1247, 228, 328, 1227, 650, 1160, 1113, 1022, 997, 900, - 875, 850, 825, 800, 775, 1170, 1495, 1629, nil, nil, - 2044, 272, 146, nil, nil, 472, nil, nil, 470, 127, - 1721, 462, nil, nil, 1639, 471, nil, nil, nil, nil, - 474, 467, nil, 404, 376, 404, 266, nil, 242, 369, - 2519, 1314, 1371, nil, 34, 400, 1582, nil, nil, 82, - nil, 265, -2, 108, 112, 1659, 134, 2475, 2409, 172, - 180, nil, 226, nil, nil, 100, 1701, 1711, nil, nil, - nil, nil, nil, nil, nil, nil, 579, 256, 123, 180, - 175, 341, 303, 1976, 486, 1886, 540, 1931, 1842, 2279, - 2172, nil, nil, nil, 66, 1096, 341, 360, nil, 366, - 160, 1032, nil, 0, nil, 84, nil, 980, nil, 384, - 374, 388, nil, 391, 399, nil, 227, 427, nil, nil, - nil, nil, 2369, 2127, nil, 1864, nil, nil, nil, nil, - nil, nil, nil, 409, nil, 4, nil, nil, 2061, 2106, - nil, nil, 2217, nil, -20, nil, 925, 435, nil, nil, - 442, 967, 445, 1050, 447, nil, 449, nil, nil, 436, - 433, 1237, 256, nil, nil, nil, 468, nil, nil, nil, - nil, nil, 213, 170, nil, nil, nil, nil, nil, nil, - 1909, 41, nil, nil, 482, nil, 484, nil, nil, nil, - nil ] - -racc_action_default = [ - -206, -241, -1, -2, -3, -6, -7, -8, -9, -10, - -11, -12, -13, -14, -15, -16, -17, -18, -19, -20, - -241, -39, -41, -42, -43, -45, -97, -241, -178, -241, - -74, -96, -98, -221, -239, -124, -241, -129, -241, -241, - -241, -241, -177, -181, -182, -183, -185, -186, -241, -241, - -198, -241, -229, -241, -4, -241, -46, -47, -48, -49, - -241, -119, -241, -241, -53, -54, -58, -59, -60, -61, - -62, -63, -64, -65, -66, -67, -68, -97, -241, -239, - -221, -109, -109, -77, -206, -206, -241, -241, -73, -197, - -198, -75, -241, -241, -241, -241, -125, -241, -141, -142, - -241, -241, -241, -241, -241, -241, -134, -241, -241, -241, - -187, -188, -190, -206, -206, -206, -199, -201, -202, -203, - -204, -205, 401, -37, -38, -39, -40, -44, -97, -36, - -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, - -31, -32, -33, -34, -35, -227, -112, -113, -114, -241, - -117, -118, -120, -241, -241, -52, -56, -241, -241, -241, - -241, -224, -24, -34, -94, -227, -241, -92, -97, -99, - -100, -101, -102, -103, -104, -105, -110, -114, -227, -112, - -119, -241, -80, -81, -83, -206, -241, -89, -90, -97, - -221, -241, -241, -106, -108, -241, -107, -126, -127, -241, - -241, -241, -241, -241, -241, -241, -241, -241, -241, -241, - -241, -241, -241, -241, -241, -241, -241, -241, -153, -160, - -241, -241, -241, -232, -233, -241, -236, -237, -241, -241, - -241, -97, -171, -172, -241, -241, -178, -179, -180, -184, - -241, -241, -208, -207, -206, -241, -241, -215, -241, -241, - -228, -241, -241, -240, -50, -226, -241, -225, -55, -241, - -123, -241, -222, -226, -241, -95, -241, -228, -109, -241, - -227, -78, -241, -85, -86, -241, -241, -241, -79, -131, - -226, -238, -128, -143, -144, -145, -146, -147, -148, -149, - -150, -151, -152, -154, -155, -156, -157, -158, -159, -161, - -162, -163, -222, -230, -241, -241, -5, -241, -133, -241, - -137, -241, -165, -241, -169, -227, -174, -241, -189, -241, - -241, -227, -211, -214, -241, -217, -241, -241, -200, -216, - -72, -121, -116, -115, -51, -57, -122, -130, -223, -69, - -93, -70, -111, -227, -71, -241, -82, -84, -87, -88, - -231, -234, -235, -132, -137, -136, -241, -241, -164, -166, - -241, -241, -241, -241, -226, -176, -241, -192, -209, -241, - -228, -241, -241, -218, -219, -220, -241, -196, -91, -76, - -135, -138, -241, -241, -170, -173, -175, -191, -210, -212, - -213, -241, -194, -195, -241, -140, -241, -168, -193, -139, - -167 ] - -racc_goto_table = [ - 28, 2, 28, 42, 224, 42, 54, 65, 106, 233, - 113, 114, 235, 121, 116, 44, 174, 44, 43, 111, - 43, 249, 167, 96, 307, 309, 3, 322, 145, 87, - 25, 88, 25, 165, 178, 176, 176, 83, 312, 355, - 123, 266, 181, 191, 311, 129, 127, 331, 126, 154, - 24, 127, 24, 126, 269, 28, 346, 124, 42, 232, - 28, 197, 124, 42, 160, 55, 60, 241, 244, 315, - 44, 264, 192, 43, 112, 44, 164, 324, 43, 115, - 245, 171, 363, 380, 170, 25, 329, 188, 188, 221, - 25, 320, 321, 64, 373, 222, 44, 1, nil, 43, - nil, nil, nil, nil, nil, 24, nil, nil, nil, 236, - 24, 175, 42, nil, nil, 366, nil, nil, 34, 359, - 34, nil, nil, 376, 44, nil, nil, 43, nil, nil, - nil, 172, nil, 314, 316, nil, nil, 235, 258, 242, - 242, 247, nil, 275, 259, 261, 345, 270, nil, nil, - nil, nil, nil, nil, 389, nil, nil, nil, nil, nil, - nil, nil, nil, 284, 285, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 394, 396, - nil, nil, nil, nil, nil, nil, 282, nil, 188, nil, - nil, 362, nil, nil, nil, nil, nil, 369, nil, nil, - 174, nil, nil, nil, 351, nil, 340, nil, 121, 328, - 121, 318, nil, nil, 314, nil, nil, nil, nil, 378, - 343, 342, 176, nil, nil, nil, nil, 239, 28, 28, - 236, 42, 42, 42, 236, nil, nil, 42, nil, nil, - nil, nil, nil, 44, 44, 44, 43, 43, 43, 44, - nil, nil, 43, nil, nil, nil, nil, nil, 25, 25, - nil, nil, nil, 386, 384, 171, 235, nil, 170, nil, - 325, nil, nil, nil, nil, 188, nil, nil, 24, 24, - 44, nil, nil, 43, 23, nil, 23, 374, nil, nil, - nil, nil, nil, nil, nil, 175, nil, nil, 365, 45, - nil, 45, nil, nil, nil, nil, 28, nil, nil, 42, - 54, 236, nil, nil, 42, 172, nil, nil, nil, 28, - nil, 44, 42, nil, 43, 381, 44, 28, nil, 43, - 42, nil, nil, nil, 44, nil, 25, 43, nil, 23, - nil, nil, 44, nil, 23, 43, 34, 34, 239, 25, - nil, nil, 239, nil, 45, nil, 24, 25, nil, 45, - nil, 236, nil, 236, 42, 169, 42, nil, 22, 24, - 22, nil, 28, 391, nil, 42, 44, 24, 44, 43, - 45, 43, 28, 28, nil, 42, 42, 44, 227, nil, - 43, 28, nil, 237, 42, 54, nil, 44, 44, nil, - 43, 43, 25, 21, nil, 21, 44, nil, 45, 43, - nil, nil, 25, 25, nil, nil, nil, nil, nil, nil, - nil, 25, 24, 22, 34, nil, nil, nil, 22, 239, - nil, nil, 24, 24, nil, nil, nil, 34, nil, nil, - nil, 24, nil, nil, nil, 34, nil, nil, nil, 173, - nil, nil, 187, 187, nil, nil, nil, nil, 125, nil, - nil, nil, nil, 125, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 238, nil, 239, - nil, 239, nil, nil, nil, nil, nil, nil, nil, nil, - 34, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 34, 34, nil, nil, nil, nil, nil, nil, nil, 34, - nil, nil, 23, 23, 237, nil, nil, nil, 237, nil, - nil, nil, nil, nil, nil, nil, nil, 45, 45, 45, - nil, nil, nil, 45, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 169, - nil, nil, nil, 187, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 45, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 227, nil, - 23, nil, nil, nil, nil, 237, 22, 22, 238, nil, - nil, nil, 238, 23, nil, 45, nil, nil, nil, nil, - 45, 23, nil, nil, nil, nil, nil, nil, 45, nil, - nil, nil, nil, nil, nil, nil, 45, nil, nil, nil, - nil, 21, 21, 173, nil, 97, nil, 105, 107, 108, - 187, nil, nil, nil, nil, 237, nil, 237, nil, nil, - nil, nil, nil, nil, nil, nil, 23, nil, nil, nil, - 45, 153, 45, nil, nil, nil, 23, 23, nil, nil, - nil, 45, nil, nil, 22, 23, nil, nil, nil, 238, - nil, 45, 45, nil, nil, nil, nil, 22, nil, nil, - 45, 193, 194, 195, 196, 22, nil, nil, nil, 218, - 219, 220, nil, nil, nil, nil, nil, nil, nil, 21, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 21, nil, nil, nil, nil, nil, nil, 238, - 21, 238, nil, nil, nil, nil, nil, nil, nil, nil, - 22, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 22, 22, nil, nil, nil, nil, nil, nil, nil, 22, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 21, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 21, 21, nil, nil, nil, - nil, nil, nil, nil, 21, nil, nil, nil, 97, 283, - nil, nil, 286, 287, 288, 289, 290, 291, 292, 293, - 294, 295, 296, 297, 298, 299, 300, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 332, 333, nil, nil, nil, 335, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 348, 349, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 352, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 107, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 390 ] - -racc_goto_check = [ - 35, 2, 35, 34, 86, 34, 4, 31, 62, 71, - 40, 40, 69, 65, 79, 36, 37, 36, 38, 73, - 38, 44, 53, 60, 5, 5, 3, 83, 45, 35, - 28, 6, 28, 43, 43, 56, 56, 47, 67, 63, - 22, 44, 48, 48, 66, 22, 10, 59, 8, 29, - 27, 10, 27, 8, 44, 35, 49, 6, 34, 70, - 35, 61, 6, 34, 29, 23, 23, 75, 75, 72, - 36, 42, 29, 38, 74, 36, 41, 76, 38, 77, - 78, 35, 33, 63, 34, 28, 80, 34, 34, 29, - 28, 81, 82, 30, 84, 85, 36, 1, nil, 38, - nil, nil, nil, nil, nil, 27, nil, nil, nil, 35, - 27, 28, 34, nil, nil, 5, nil, nil, 55, 67, - 55, nil, nil, 5, 36, nil, nil, 38, nil, nil, - nil, 27, nil, 69, 71, nil, nil, 69, 31, 3, - 3, 3, nil, 48, 29, 29, 44, 45, nil, nil, - nil, nil, nil, nil, 83, nil, nil, nil, nil, nil, - nil, nil, nil, 65, 65, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 5, 5, - nil, nil, nil, nil, nil, nil, 60, nil, 34, nil, - nil, 44, nil, nil, nil, nil, nil, 44, nil, nil, - 37, nil, nil, nil, 86, nil, 53, nil, 65, 79, - 65, 73, nil, nil, 69, nil, nil, nil, nil, 44, - 43, 56, 56, nil, nil, nil, nil, 55, 35, 35, - 35, 34, 34, 34, 35, nil, nil, 34, nil, nil, - nil, nil, nil, 36, 36, 36, 38, 38, 38, 36, - nil, nil, 38, nil, nil, nil, nil, nil, 28, 28, - nil, nil, nil, 71, 69, 35, 69, nil, 34, nil, - 3, nil, nil, nil, nil, 34, nil, nil, 27, 27, - 36, nil, nil, 38, 26, nil, 26, 40, nil, nil, - nil, nil, nil, nil, nil, 28, nil, nil, 31, 39, - nil, 39, nil, nil, nil, nil, 35, nil, nil, 34, - 4, 35, nil, nil, 34, 27, nil, nil, nil, 35, - nil, 36, 34, nil, 38, 62, 36, 35, nil, 38, - 34, nil, nil, nil, 36, nil, 28, 38, nil, 26, - nil, nil, 36, nil, 26, 38, 55, 55, 55, 28, - nil, nil, 55, nil, 39, nil, 27, 28, nil, 39, - nil, 35, nil, 35, 34, 26, 34, nil, 25, 27, - 25, nil, 35, 2, nil, 34, 36, 27, 36, 38, - 39, 38, 35, 35, nil, 34, 34, 36, 26, nil, - 38, 35, nil, 26, 34, 4, nil, 36, 36, nil, - 38, 38, 28, 24, nil, 24, 36, nil, 39, 38, - nil, nil, 28, 28, nil, nil, nil, nil, nil, nil, - nil, 28, 27, 25, 55, nil, nil, nil, 25, 55, - nil, nil, 27, 27, nil, nil, nil, 55, nil, nil, - nil, 27, nil, nil, nil, 55, nil, nil, nil, 25, - nil, nil, 25, 25, nil, nil, nil, nil, 24, nil, - nil, nil, nil, 24, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 25, nil, 55, - nil, 55, nil, nil, nil, nil, nil, nil, nil, nil, - 55, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 55, 55, nil, nil, nil, nil, nil, nil, nil, 55, - nil, nil, 26, 26, 26, nil, nil, nil, 26, nil, - nil, nil, nil, nil, nil, nil, nil, 39, 39, 39, - nil, nil, nil, 39, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 26, - nil, nil, nil, 25, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 39, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, 26, nil, - 26, nil, nil, nil, nil, 26, 25, 25, 25, nil, - nil, nil, 25, 26, nil, 39, nil, nil, nil, nil, - 39, 26, nil, nil, nil, nil, nil, nil, 39, nil, - nil, nil, nil, nil, nil, nil, 39, nil, nil, nil, - nil, 24, 24, 25, nil, 32, nil, 32, 32, 32, - 25, nil, nil, nil, nil, 26, nil, 26, nil, nil, - nil, nil, nil, nil, nil, nil, 26, nil, nil, nil, - 39, 32, 39, nil, nil, nil, 26, 26, nil, nil, - nil, 39, nil, nil, 25, 26, nil, nil, nil, 25, - nil, 39, 39, nil, nil, nil, nil, 25, nil, nil, - 39, 32, 32, 32, 32, 25, nil, nil, nil, 32, - 32, 32, nil, nil, nil, nil, nil, nil, nil, 24, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 24, nil, nil, nil, nil, nil, nil, 25, - 24, 25, nil, nil, nil, nil, nil, nil, nil, nil, - 25, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 25, 25, nil, nil, nil, nil, nil, nil, nil, 25, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 24, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 24, 24, nil, nil, nil, - nil, nil, nil, nil, 24, nil, nil, nil, 32, 32, - nil, nil, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 32, 32, nil, nil, nil, 32, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 32, 32, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 32, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 32, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 32 ] - -racc_goto_pointer = [ - nil, 97, 1, 26, 4, -204, 2, nil, -7, nil, - -9, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, -15, 46, 403, 368, 284, 50, 30, -14, - 67, -19, 599, -233, 3, 0, 15, -65, 18, 299, - -39, -5, -93, -48, -124, -33, nil, 9, -42, -216, - nil, nil, nil, -59, nil, 118, -46, nil, nil, -203, - -13, -36, -31, -271, nil, -38, -186, -192, nil, -97, - -50, -100, -165, -29, 26, -46, -167, 28, -35, -37, - -162, -152, -151, -216, -232, -9, -100, nil ] - -racc_goto_default = [ - nil, nil, 306, 182, 4, nil, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 147, 20, nil, 74, 71, 66, 70, 73, nil, - nil, 98, 156, 256, 67, 68, 69, 72, 75, 76, - 27, nil, nil, nil, nil, nil, 29, nil, nil, 183, - 272, 184, 186, nil, 166, 79, 150, 149, 151, 152, - nil, nil, nil, nil, 99, 47, nil, nil, 313, 41, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 117, nil, nil, nil, nil, nil, nil, 225 ] - -racc_reduce_table = [ - 0, 0, :racc_error, - 1, 71, :_reduce_none, - 1, 71, :_reduce_none, - 1, 72, :_reduce_3, - 2, 72, :_reduce_4, - 1, 75, :_reduce_5, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 74, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 3, 90, :_reduce_36, - 3, 90, :_reduce_37, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 93, :_reduce_none, - 1, 93, :_reduce_none, - 1, 93, :_reduce_none, - 1, 93, :_reduce_none, - 4, 84, :_reduce_50, - 5, 84, :_reduce_51, - 3, 84, :_reduce_52, - 2, 84, :_reduce_53, - 1, 100, :_reduce_54, - 3, 100, :_reduce_55, - 1, 99, :_reduce_56, - 3, 99, :_reduce_57, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 1, 101, :_reduce_none, - 5, 76, :_reduce_69, - 5, 76, :_reduce_70, - 5, 76, :_reduce_71, - 5, 88, :_reduce_72, - 2, 77, :_reduce_73, - 1, 116, :_reduce_74, - 2, 116, :_reduce_75, - 6, 78, :_reduce_76, - 2, 78, :_reduce_77, - 3, 117, :_reduce_78, - 3, 117, :_reduce_79, - 1, 118, :_reduce_none, - 1, 118, :_reduce_none, - 3, 118, :_reduce_82, - 1, 119, :_reduce_none, - 3, 119, :_reduce_84, - 1, 120, :_reduce_85, - 1, 120, :_reduce_86, - 3, 121, :_reduce_87, - 3, 121, :_reduce_88, - 1, 122, :_reduce_none, - 1, 122, :_reduce_none, - 4, 123, :_reduce_91, - 1, 111, :_reduce_92, - 3, 111, :_reduce_93, - 0, 112, :_reduce_none, - 1, 112, :_reduce_none, - 1, 109, :_reduce_96, - 1, 104, :_reduce_97, - 1, 105, :_reduce_98, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 1, 124, :_reduce_none, - 3, 79, :_reduce_106, - 3, 79, :_reduce_107, - 3, 89, :_reduce_108, - 0, 113, :_reduce_109, - 1, 113, :_reduce_110, - 3, 113, :_reduce_111, - 1, 127, :_reduce_none, - 1, 127, :_reduce_none, - 1, 127, :_reduce_none, - 3, 126, :_reduce_115, - 3, 128, :_reduce_116, - 1, 129, :_reduce_none, - 1, 129, :_reduce_none, - 0, 115, :_reduce_119, - 1, 115, :_reduce_120, - 3, 115, :_reduce_121, - 4, 108, :_reduce_122, - 3, 108, :_reduce_123, - 1, 96, :_reduce_124, - 2, 96, :_reduce_125, - 2, 130, :_reduce_126, - 1, 131, :_reduce_127, - 2, 131, :_reduce_128, - 1, 106, :_reduce_129, - 4, 94, :_reduce_130, - 4, 94, :_reduce_131, - 5, 82, :_reduce_132, - 4, 82, :_reduce_133, - 2, 81, :_reduce_134, - 5, 132, :_reduce_135, - 4, 132, :_reduce_136, - 0, 133, :_reduce_none, - 2, 133, :_reduce_138, - 4, 133, :_reduce_139, - 3, 133, :_reduce_140, - 1, 102, :_reduce_none, - 1, 102, :_reduce_none, - 3, 102, :_reduce_143, - 3, 102, :_reduce_144, - 3, 102, :_reduce_145, - 3, 102, :_reduce_146, - 3, 102, :_reduce_147, - 3, 102, :_reduce_148, - 3, 102, :_reduce_149, - 3, 102, :_reduce_150, - 3, 102, :_reduce_151, - 3, 102, :_reduce_152, - 2, 102, :_reduce_153, - 3, 102, :_reduce_154, - 3, 102, :_reduce_155, - 3, 102, :_reduce_156, - 3, 102, :_reduce_157, - 3, 102, :_reduce_158, - 3, 102, :_reduce_159, - 2, 102, :_reduce_160, - 3, 102, :_reduce_161, - 3, 102, :_reduce_162, - 3, 102, :_reduce_163, - 5, 80, :_reduce_164, - 1, 136, :_reduce_165, - 2, 136, :_reduce_166, - 5, 137, :_reduce_167, - 4, 137, :_reduce_168, - 1, 138, :_reduce_169, - 3, 138, :_reduce_170, - 3, 97, :_reduce_171, - 1, 140, :_reduce_none, - 4, 140, :_reduce_173, - 1, 142, :_reduce_none, - 3, 142, :_reduce_175, - 3, 141, :_reduce_176, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_none, - 1, 139, :_reduce_185, - 1, 139, :_reduce_none, - 1, 143, :_reduce_187, - 1, 144, :_reduce_none, - 3, 144, :_reduce_189, - 2, 83, :_reduce_190, - 6, 85, :_reduce_191, - 5, 85, :_reduce_192, - 7, 86, :_reduce_193, - 6, 86, :_reduce_194, - 6, 87, :_reduce_195, - 5, 87, :_reduce_196, - 1, 110, :_reduce_197, - 1, 110, :_reduce_198, - 1, 147, :_reduce_199, - 3, 147, :_reduce_200, - 1, 149, :_reduce_201, - 1, 150, :_reduce_202, - 1, 150, :_reduce_203, - 1, 150, :_reduce_204, - 1, 150, :_reduce_none, - 0, 73, :_reduce_206, - 0, 151, :_reduce_207, - 1, 145, :_reduce_none, - 3, 145, :_reduce_209, - 4, 145, :_reduce_210, - 1, 152, :_reduce_none, - 3, 152, :_reduce_212, - 3, 153, :_reduce_213, - 1, 153, :_reduce_214, - 1, 148, :_reduce_none, - 2, 148, :_reduce_216, - 1, 146, :_reduce_none, - 2, 146, :_reduce_218, - 1, 154, :_reduce_none, - 1, 154, :_reduce_none, - 1, 95, :_reduce_221, - 3, 107, :_reduce_222, - 4, 107, :_reduce_223, - 2, 107, :_reduce_224, - 1, 103, :_reduce_none, - 1, 103, :_reduce_none, - 0, 114, :_reduce_none, - 1, 114, :_reduce_228, - 1, 135, :_reduce_229, - 3, 134, :_reduce_230, - 4, 134, :_reduce_231, - 2, 134, :_reduce_232, - 1, 155, :_reduce_none, - 3, 155, :_reduce_234, - 3, 156, :_reduce_235, - 1, 157, :_reduce_236, - 1, 157, :_reduce_237, - 4, 125, :_reduce_238, - 1, 98, :_reduce_none, - 4, 98, :_reduce_240 ] - -racc_reduce_n = 241 - -racc_shift_n = 401 - -racc_token_table = { - false => 0, - :error => 1, - :STRING => 2, - :DQPRE => 3, - :DQMID => 4, - :DQPOST => 5, - :LBRACK => 6, - :RBRACK => 7, - :LBRACE => 8, - :RBRACE => 9, - :SYMBOL => 10, - :FARROW => 11, - :COMMA => 12, - :TRUE => 13, - :FALSE => 14, - :EQUALS => 15, - :APPENDS => 16, - :LESSEQUAL => 17, - :NOTEQUAL => 18, - :DOT => 19, - :COLON => 20, - :LLCOLLECT => 21, - :RRCOLLECT => 22, - :QMARK => 23, - :LPAREN => 24, - :RPAREN => 25, - :ISEQUAL => 26, - :GREATEREQUAL => 27, - :GREATERTHAN => 28, - :LESSTHAN => 29, - :IF => 30, - :ELSE => 31, - :IMPORT => 32, - :DEFINE => 33, - :ELSIF => 34, - :VARIABLE => 35, - :CLASS => 36, - :INHERITS => 37, - :NODE => 38, - :BOOLEAN => 39, - :NAME => 40, - :SEMIC => 41, - :CASE => 42, - :DEFAULT => 43, - :AT => 44, - :LCOLLECT => 45, - :RCOLLECT => 46, - :CLASSREF => 47, - :NOT => 48, - :OR => 49, - :AND => 50, - :UNDEF => 51, - :PARROW => 52, - :PLUS => 53, - :MINUS => 54, - :TIMES => 55, - :DIV => 56, - :LSHIFT => 57, - :RSHIFT => 58, - :UMINUS => 59, - :MATCH => 60, - :NOMATCH => 61, - :REGEX => 62, - :IN_EDGE => 63, - :OUT_EDGE => 64, - :IN_EDGE_SUB => 65, - :OUT_EDGE_SUB => 66, - :IN => 67, - :UNLESS => 68, - :MODULO => 69 } - -racc_nt_base = 70 - -racc_use_result_var = true - -Racc_arg = [ - racc_action_table, - racc_action_check, - racc_action_default, - racc_action_pointer, - racc_goto_table, - racc_goto_check, - racc_goto_default, - racc_goto_pointer, - racc_nt_base, - racc_reduce_table, - racc_token_table, - racc_shift_n, - racc_reduce_n, - racc_use_result_var ] - -Racc_token_to_s_table = [ - "$end", - "error", - "STRING", - "DQPRE", - "DQMID", - "DQPOST", - "LBRACK", - "RBRACK", - "LBRACE", - "RBRACE", - "SYMBOL", - "FARROW", - "COMMA", - "TRUE", - "FALSE", - "EQUALS", - "APPENDS", - "LESSEQUAL", - "NOTEQUAL", - "DOT", - "COLON", - "LLCOLLECT", - "RRCOLLECT", - "QMARK", - "LPAREN", - "RPAREN", - "ISEQUAL", - "GREATEREQUAL", - "GREATERTHAN", - "LESSTHAN", - "IF", - "ELSE", - "IMPORT", - "DEFINE", - "ELSIF", - "VARIABLE", - "CLASS", - "INHERITS", - "NODE", - "BOOLEAN", - "NAME", - "SEMIC", - "CASE", - "DEFAULT", - "AT", - "LCOLLECT", - "RCOLLECT", - "CLASSREF", - "NOT", - "OR", - "AND", - "UNDEF", - "PARROW", - "PLUS", - "MINUS", - "TIMES", - "DIV", - "LSHIFT", - "RSHIFT", - "UMINUS", - "MATCH", - "NOMATCH", - "REGEX", - "IN_EDGE", - "OUT_EDGE", - "IN_EDGE_SUB", - "OUT_EDGE_SUB", - "IN", - "UNLESS", - "MODULO", - "$start", - "program", - "statements_and_declarations", - "nil", - "statement_or_declaration", - "statements", - "resource", - "virtualresource", - "collection", - "assignment", - "casestatement", - "ifstatement_begin", - "unlessstatement", - "import", - "fstatement", - "definition", - "hostclass", - "nodedef", - "resourceoverride", - "append", - "relationship", - "keyword", - "relationship_side", - "edge", - "resourceref", - "variable", - "quotedtext", - "selector", - "hasharrayaccesses", - "expressions", - "funcvalues", - "rvalue", - "expression", - "comma", - "name", - "type", - "boolean", - "array", - "funcrvalue", - "undef", - "classname", - "resourceinstances", - "endsemi", - "params", - "endcomma", - "anyparams", - "at", - "collectrhand", - "collstatements", - "collstatement", - "colljoin", - "collexpr", - "colllval", - "resourceinst", - "resourcename", - "hasharrayaccess", - "param", - "param_name", - "addparam", - "anyparam", - "dqrval", - "dqtail", - "ifstatement", - "else", - "hash", - "regex", - "caseopts", - "caseopt", - "casevalues", - "selectlhand", - "svalues", - "selectval", - "sintvalues", - "string", - "strings", - "argumentlist", - "classparent", - "hostnames", - "nodeparent", - "nodename", - "hostname", - "nothing", - "arguments", - "argument", - "classnameordefault", - "hashpairs", - "hashpair", - "key" ] - -Racc_debug_parser = false - -##### State transition tables end ##### - -# reduce 0 omitted - -# reduce 1 omitted - -# reduce 2 omitted - -module_eval(<<'.,.,', 'grammar.ra', 34) - def _reduce_3(val, _values, result) - result = ast AST::BlockExpression, :children => (val[0] ? [val[0]] : []) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 37) - def _reduce_4(val, _values, result) - if val[1] - val[0].push(val[1]) - end - result = val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 46) - def _reduce_5(val, _values, result) - val[0].each do |stmt| - if stmt.is_a?(AST::TopLevelConstruct) - error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ - :line => stmt.context[:line], :file => stmt.context[:file] - end - end - result = val[0] - - result - end -.,., - -# reduce 6 omitted - -# reduce 7 omitted - -# reduce 8 omitted - -# reduce 9 omitted - -# reduce 10 omitted - -# reduce 11 omitted - -# reduce 12 omitted - -# reduce 13 omitted - -# reduce 14 omitted - -# reduce 15 omitted - -# reduce 16 omitted - -# reduce 17 omitted - -# reduce 18 omitted - -# reduce 19 omitted - -# reduce 20 omitted - -# reduce 21 omitted - -# reduce 22 omitted - -# reduce 23 omitted - -# reduce 24 omitted - -# reduce 25 omitted - -# reduce 26 omitted - -# reduce 27 omitted - -# reduce 28 omitted - -# reduce 29 omitted - -# reduce 30 omitted - -# reduce 31 omitted - -# reduce 32 omitted - -# reduce 33 omitted - -# reduce 34 omitted - -# reduce 35 omitted - -module_eval(<<'.,.,', 'grammar.ra', 89) - def _reduce_36(val, _values, result) - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 92) - def _reduce_37(val, _values, result) - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) - - result - end -.,., - -# reduce 38 omitted - -# reduce 39 omitted - -# reduce 40 omitted - -# reduce 41 omitted - -# reduce 42 omitted - -# reduce 43 omitted - -# reduce 44 omitted - -# reduce 45 omitted - -# reduce 46 omitted - -# reduce 47 omitted - -# reduce 48 omitted - -# reduce 49 omitted - -module_eval(<<'.,.,', 'grammar.ra', 107) - def _reduce_50(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[2], - :ftype => :statement - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 114) - def _reduce_51(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[2], - :ftype => :statement - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 120) - def _reduce_52(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :statement - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 127) - def _reduce_53(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => val[1], - :ftype => :statement - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 134) - def _reduce_54(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 137) - def _reduce_55(val, _values, result) - val[0].push(val[2]) - result = val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 141) - def _reduce_56(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 142) - def _reduce_57(val, _values, result) - result = val[0].push(val[2]) - result - end -.,., - -# reduce 58 omitted - -# reduce 59 omitted - -# reduce 60 omitted - -# reduce 61 omitted - -# reduce 62 omitted - -# reduce 63 omitted - -# reduce 64 omitted - -# reduce 65 omitted - -# reduce 66 omitted - -# reduce 67 omitted - -# reduce 68 omitted - -module_eval(<<'.,.,', 'grammar.ra', 157) - def _reduce_69(val, _values, result) - @lexer.commentpop - result = ast(AST::Resource, :type => val[0], :instances => val[2]) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 160) - def _reduce_70(val, _values, result) - # This is a deprecated syntax. - error "All resource specifications require names" - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 163) - def _reduce_71(val, _values, result) - # a defaults setting for a type - @lexer.commentpop - result = ast(AST::ResourceDefaults, :type => val[0].value, :parameters => val[2]) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 170) - def _reduce_72(val, _values, result) - @lexer.commentpop - result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 177) - def _reduce_73(val, _values, result) - type = val[0] - - if (type == :exported and ! Puppet[:storeconfigs]) - Puppet.warning addcontext("You cannot collect without storeconfigs being set") - end - - error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults - - method = type.to_s + "=" - - # Just mark our resource as exported and pass it through. - val[1].send(method, true) - - result = val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 193) - def _reduce_74(val, _values, result) - result = :virtual - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 194) - def _reduce_75(val, _values, result) - result = :exported - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 199) - def _reduce_76(val, _values, result) - @lexer.commentpop - type = val[0].value.downcase - args = {:type => type} - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - args[:override] = val[3] - result = ast AST::Collection, args - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 217) - def _reduce_77(val, _values, result) - type = val[0].value.downcase - args = {:type => type } - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - result = ast AST::Collection, args - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 235) - def _reduce_78(val, _values, result) - if val[1] - result = val[1] - result.form = :virtual - else - result = :virtual - end - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 243) - def _reduce_79(val, _values, result) - if val[1] - result = val[1] - result.form = :exported - else - result = :exported - end - - result - end -.,., - -# reduce 80 omitted - -# reduce 81 omitted - -module_eval(<<'.,.,', 'grammar.ra', 256) - def _reduce_82(val, _values, result) - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] - - result - end -.,., - -# reduce 83 omitted - -module_eval(<<'.,.,', 'grammar.ra', 261) - def _reduce_84(val, _values, result) - result = val[1] - result.parens = true - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 265) - def _reduce_85(val, _values, result) - result=val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 266) - def _reduce_86(val, _values, result) - result=val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 269) - def _reduce_87(val, _values, result) - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 274) - def _reduce_88(val, _values, result) - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val - - result - end -.,., - -# reduce 89 omitted - -# reduce 90 omitted - -module_eval(<<'.,.,', 'grammar.ra', 283) - def _reduce_91(val, _values, result) - result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 286) - def _reduce_92(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 288) - def _reduce_93(val, _values, result) - val[0].push val[2] - result = val[0] - - result - end -.,., - -# reduce 94 omitted - -# reduce 95 omitted - -module_eval(<<'.,.,', 'grammar.ra', 296) - def _reduce_96(val, _values, result) - result = ast AST::Undef, :value => :undef - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 300) - def _reduce_97(val, _values, result) - result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 304) - def _reduce_98(val, _values, result) - result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] - - result - end -.,., - -# reduce 99 omitted - -# reduce 100 omitted - -# reduce 101 omitted - -# reduce 102 omitted - -# reduce 103 omitted - -# reduce 104 omitted - -# reduce 105 omitted - -module_eval(<<'.,.,', 'grammar.ra', 316) - def _reduce_106(val, _values, result) - raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ - # this is distinct from referencing a variable - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 322) - def _reduce_107(val, _values, result) - result = ast AST::VarDef, :name => val[0], :value => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 326) - def _reduce_108(val, _values, result) - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 332) - def _reduce_109(val, _values, result) - result = ast AST::ASTArray - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 334) - def _reduce_110(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 336) - def _reduce_111(val, _values, result) - val[0].push(val[2]) - result = val[0] - - result - end -.,., - -# reduce 112 omitted - -# reduce 113 omitted - -# reduce 114 omitted - -module_eval(<<'.,.,', 'grammar.ra', 345) - def _reduce_115(val, _values, result) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 349) - def _reduce_116(val, _values, result) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], - :add => true - - result - end -.,., - -# reduce 117 omitted - -# reduce 118 omitted - -module_eval(<<'.,.,', 'grammar.ra', 358) - def _reduce_119(val, _values, result) - result = ast AST::ASTArray - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 360) - def _reduce_120(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 362) - def _reduce_121(val, _values, result) - val[0].push(val[2]) - result = val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 368) - def _reduce_122(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => val[2], - :ftype => :rvalue - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 373) - def _reduce_123(val, _values, result) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :rvalue - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 379) - def _reduce_124(val, _values, result) - result = ast AST::String, :value => val[0][:value], :line => val[0][:line] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 380) - def _reduce_125(val, _values, result) - result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 382) - def _reduce_126(val, _values, result) - result = [val[0]] + val[1] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 384) - def _reduce_127(val, _values, result) - result = [ast(AST::String,val[0])] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 385) - def _reduce_128(val, _values, result) - result = [ast(AST::String,val[0])] + val[1] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 388) - def _reduce_129(val, _values, result) - result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 392) - def _reduce_130(val, _values, result) - Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 395) - def _reduce_131(val, _values, result) - result = ast AST::ResourceReference, :type => val[0].value, :title => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 399) - def _reduce_132(val, _values, result) - @lexer.commentpop - args = { - :test => ast(AST::Not, :value => val[1]), - :statements => val[3] - } - - result = ast AST::IfStatement, args - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 408) - def _reduce_133(val, _values, result) - @lexer.commentpop - args = { - :test => ast(AST::Not, :value => val[1]), - :statements => ast(AST::Nop) - } - result = ast AST::IfStatement, args - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 417) - def _reduce_134(val, _values, result) - result = val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 421) - def _reduce_135(val, _values, result) - @lexer.commentpop - args = { - :test => val[0], - :statements => val[2] - } - - args[:else] = val[4] if val[4] - - result = ast AST::IfStatement, args - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 432) - def _reduce_136(val, _values, result) - @lexer.commentpop - args = { - :test => val[0], - :statements => ast(AST::Nop) - } - - args[:else] = val[3] if val[3] - - result = ast AST::IfStatement, args - - result - end -.,., - -# reduce 137 omitted - -module_eval(<<'.,.,', 'grammar.ra', 445) - def _reduce_138(val, _values, result) - result = ast AST::Else, :statements => val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 448) - def _reduce_139(val, _values, result) - @lexer.commentpop - result = ast AST::Else, :statements => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 452) - def _reduce_140(val, _values, result) - @lexer.commentpop - result = ast AST::Else, :statements => ast(AST::Nop) - - result - end -.,., - -# reduce 141 omitted - -# reduce 142 omitted - -module_eval(<<'.,.,', 'grammar.ra', 471) - def _reduce_143(val, _values, result) - result = ast AST::InOperator, :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 474) - def _reduce_144(val, _values, result) - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 477) - def _reduce_145(val, _values, result) - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 480) - def _reduce_146(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 483) - def _reduce_147(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 486) - def _reduce_148(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 489) - def _reduce_149(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 492) - def _reduce_150(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 495) - def _reduce_151(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 498) - def _reduce_152(val, _values, result) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 501) - def _reduce_153(val, _values, result) - result = ast AST::Minus, :value => val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 504) - def _reduce_154(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 507) - def _reduce_155(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 510) - def _reduce_156(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 513) - def _reduce_157(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 516) - def _reduce_158(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 519) - def _reduce_159(val, _values, result) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 522) - def _reduce_160(val, _values, result) - result = ast AST::Not, :value => val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 525) - def _reduce_161(val, _values, result) - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 528) - def _reduce_162(val, _values, result) - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 531) - def _reduce_163(val, _values, result) - result = val[1] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 535) - def _reduce_164(val, _values, result) - @lexer.commentpop - result = ast AST::CaseStatement, :test => val[1], :options => val[3] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 539) - def _reduce_165(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 541) - def _reduce_166(val, _values, result) - val[0].push val[1] - result = val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 546) - def _reduce_167(val, _values, result) - @lexer.commentpop - result = ast AST::CaseOpt, :value => val[0], :statements => val[3] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 549) - def _reduce_168(val, _values, result) - @lexer.commentpop - - result = ast( - AST::CaseOpt, - :value => val[0], - - :statements => ast(AST::BlockExpression) - ) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 559) - def _reduce_169(val, _values, result) - result = aryfy(val[0]) - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 561) - def _reduce_170(val, _values, result) - val[0].push(val[2]) - result = val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 566) - def _reduce_171(val, _values, result) - result = ast AST::Selector, :param => val[0], :values => val[2] - - result - end -.,., - -# reduce 172 omitted - -module_eval(<<'.,.,', 'grammar.ra', 571) - def _reduce_173(val, _values, result) - @lexer.commentpop - result = val[1] - - result - end -.,., - -# reduce 174 omitted - -module_eval(<<'.,.,', 'grammar.ra', 577) - def _reduce_175(val, _values, result) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 586) - def _reduce_176(val, _values, result) - result = ast AST::ResourceParam, :param => val[0], :value => val[2] - - result - end -.,., - -# reduce 177 omitted - -# reduce 178 omitted - -# reduce 179 omitted - -# reduce 180 omitted - -# reduce 181 omitted - -# reduce 182 omitted - -# reduce 183 omitted - -# reduce 184 omitted - -module_eval(<<'.,.,', 'grammar.ra', 598) - def _reduce_185(val, _values, result) - result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] - - result - end -.,., - -# reduce 186 omitted - -module_eval(<<'.,.,', 'grammar.ra', 603) - def _reduce_187(val, _values, result) - result = [val[0][:value]] - result - end -.,., - -# reduce 188 omitted - -module_eval(<<'.,.,', 'grammar.ra', 605) - def _reduce_189(val, _values, result) - result = val[0] += val[2] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 608) - def _reduce_190(val, _values, result) - val[1].each do |file| - import(file) - end - - result = nil - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 618) - def _reduce_191(val, _values, result) - @lexer.commentpop - result = Puppet::Parser::AST::Definition.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :code => val[4], - :line => val[0][:line])) - @lexer.indefine = false - -#} | DEFINE NAME argumentlist parent LBRACE RBRACE { - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 626) - def _reduce_192(val, _values, result) - @lexer.commentpop - result = Puppet::Parser::AST::Definition.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) - @lexer.indefine = false - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 634) - def _reduce_193(val, _values, result) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :parent => val[3], - :code => val[5], :line => val[0][:line])) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 641) - def _reduce_194(val, _values, result) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), - ast_context(true).merge(:arguments => val[2], :parent => val[3], - :line => val[0][:line])) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 650) - def _reduce_195(val, _values, result) - @lexer.commentpop - result = Puppet::Parser::AST::Node.new(val[1], - ast_context(true).merge(:parent => val[2], :code => val[4], - :line => val[0][:line])) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 655) - def _reduce_196(val, _values, result) - @lexer.commentpop - result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 659) - def _reduce_197(val, _values, result) - result = val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 660) - def _reduce_198(val, _values, result) - result = "class" - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 665) - def _reduce_199(val, _values, result) - result = [result] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 668) - def _reduce_200(val, _values, result) - result = val[0] - result << val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 673) - def _reduce_201(val, _values, result) - result = ast AST::HostName, :value => val[0] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 676) - def _reduce_202(val, _values, result) - result = val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 677) - def _reduce_203(val, _values, result) - result = val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 678) - def _reduce_204(val, _values, result) - result = val[0][:value] - result - end -.,., - -# reduce 205 omitted - -module_eval(<<'.,.,', 'grammar.ra', 682) - def _reduce_206(val, _values, result) - result = nil - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 686) - def _reduce_207(val, _values, result) - result = ast AST::ASTArray, :children => [] - - result - end -.,., - -# reduce 208 omitted - -module_eval(<<'.,.,', 'grammar.ra', 691) - def _reduce_209(val, _values, result) - result = nil - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 694) - def _reduce_210(val, _values, result) - result = val[1] - result = [result] unless result[0].is_a?(Array) - - result - end -.,., - -# reduce 211 omitted - -module_eval(<<'.,.,', 'grammar.ra', 700) - def _reduce_212(val, _values, result) - result = val[0] - result = [result] unless result[0].is_a?(Array) - result << val[2] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 706) - def _reduce_213(val, _values, result) - result = [val[0][:value], val[2]] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 707) - def _reduce_214(val, _values, result) - result = [val[0][:value]] - result - end -.,., - -# reduce 215 omitted - -module_eval(<<'.,.,', 'grammar.ra', 711) - def _reduce_216(val, _values, result) - result = val[1] - - result - end -.,., - -# reduce 217 omitted - -module_eval(<<'.,.,', 'grammar.ra', 716) - def _reduce_218(val, _values, result) - result = val[1] - - result - end -.,., - -# reduce 219 omitted - -# reduce 220 omitted - -module_eval(<<'.,.,', 'grammar.ra', 722) - def _reduce_221(val, _values, result) - result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 725) - def _reduce_222(val, _values, result) - result = val[1] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 726) - def _reduce_223(val, _values, result) - result = val[1] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 727) - def _reduce_224(val, _values, result) - result = ast AST::ASTArray - result - end -.,., - -# reduce 225 omitted - -# reduce 226 omitted - -# reduce 227 omitted - -module_eval(<<'.,.,', 'grammar.ra', 733) - def _reduce_228(val, _values, result) - result = nil - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 736) - def _reduce_229(val, _values, result) - result = ast AST::Regex, :value => val[0][:value] - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 740) - def _reduce_230(val, _values, result) - @lexer.commentpop - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 748) - def _reduce_231(val, _values, result) - @lexer.commentpop - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 755) - def _reduce_232(val, _values, result) - @lexer.commentpop - result = ast AST::ASTHash - - result - end -.,., - -# reduce 233 omitted - -module_eval(<<'.,.,', 'grammar.ra', 761) - def _reduce_234(val, _values, result) - if val[0].instance_of?(AST::ASTHash) - result = val[0].merge(val[2]) - else - result = ast AST::ASTHash, :value => val[0] - result.merge(val[2]) - end - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 770) - def _reduce_235(val, _values, result) - result = ast AST::ASTHash, { :value => { val[0] => val[2] } } - - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 773) - def _reduce_236(val, _values, result) - result = val[0][:value] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 774) - def _reduce_237(val, _values, result) - result = val[0] - result - end -.,., - -module_eval(<<'.,.,', 'grammar.ra', 777) - def _reduce_238(val, _values, result) - result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] - - result - end -.,., - -# reduce 239 omitted - -module_eval(<<'.,.,', 'grammar.ra', 782) - def _reduce_240(val, _values, result) - result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] - - result - end -.,., - -def _reduce_none(val, _values, result) - val[0] -end - - end # class Parser - end # module Parser - end # module Puppet diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb deleted file mode 100644 index a34b213d0..000000000 --- a/lib/puppet/parser/parser_support.rb +++ /dev/null @@ -1,179 +0,0 @@ -# I pulled this into a separate file, because I got -# tired of rebuilding the parser.rb file all the time. -require 'forwardable' - -class Puppet::Parser::Parser - extend Forwardable - - require 'puppet/parser/functions' - require 'puppet/parser/files' - require 'puppet/resource/type_collection' - require 'puppet/resource/type_collection_helper' - require 'puppet/resource/type' - require 'monitor' - - AST = Puppet::Parser::AST - - include Puppet::Resource::TypeCollectionHelper - - attr_reader :version, :environment - attr_accessor :files - - attr_accessor :lexer - - # Add context to a message; useful for error messages and such. - def addcontext(message, obj = nil) - obj ||= @lexer - - message += " on line #{obj.line}" - if file = obj.file - message += " in file #{file}" - end - - message - end - - # Create an AST array containing a single element - def aryfy(arg) - ast AST::ASTArray, :children => [arg] - end - - # Create an AST block containing a single element - def block(arg) - ast AST::BlockExpression, :children => [arg] - end - - # Create an AST object, and automatically add the file and line information if - # available. - def ast(klass, hash = {}) - klass.new ast_context(klass.use_docs, hash[:line]).merge(hash) - end - - def ast_context(include_docs = false, ast_line = nil) - result = { - :line => ast_line || lexer.line, - :file => lexer.file - } - result[:doc] = lexer.getcomment(result[:line]) if include_docs - result - end - - # The fully qualifed name, with the full namespace. - def classname(name) - [@lexer.namespace, name].join("::").sub(/^::/, '') - end - - def clear - initvars - end - - # Raise a Parse error. - def error(message, options = {}) - if @lexer.expected - message += "; expected '%s'" - end - except = Puppet::ParseError.new(message) - except.line = options[:line] || @lexer.line - except.file = options[:file] || @lexer.file - - raise except - end - - def_delegators :@lexer, :file, :string= - - def file=(file) - unless Puppet::FileSystem.exist?(file) - unless file =~ /\.pp$/ - file = file + ".pp" - end - end - raise Puppet::AlreadyImportedError, "Import loop detected for #{file}" if known_resource_types.watching_file?(file) - - watch_file(file) - @lexer.file = file - end - - def_delegators :known_resource_types, :hostclass, :definition, :node, :nodes? - def_delegators :known_resource_types, :find_hostclass, :find_definition - def_delegators :known_resource_types, :watch_file, :version - - def import(file) - deprecation_location_text = - if @lexer.file && @lexer.line - " at #{@lexer.file}:#{@lexer.line}" - elsif @lexer.file - " in file #{@lexer.file}" - elsif @lexer.line - " at #{@lexer.line}" - end - - Puppet.deprecation_warning("The use of 'import' is deprecated#{deprecation_location_text}. See http://links.puppetlabs.com/puppet-import-deprecation") - if @lexer.file - # use a path relative to the file doing the importing - dir = File.dirname(@lexer.file) - else - # otherwise assume that everything needs to be from where the user is - # executing this command. Normally, this would be in a "puppet apply -e" - dir = Dir.pwd - end - - known_resource_types.loader.import(file, dir) - end - - def initialize(env) - @environment = env - initvars - end - - # Initialize or reset all of our variables. - def initvars - @lexer = Puppet::Parser::Lexer.new - end - - # Split an fq name into a namespace and name - def namesplit(fullname) - ary = fullname.split("::") - n = ary.pop || "" - ns = ary.join("::") - return ns, n - end - - def on_error(token,value,stack) - if token == 0 # denotes end of file - value = 'end of file' - else - value = "'#{value[:value]}'" - end - error = "Syntax error at #{value}" - - if brace = @lexer.expected - error += "; expected '#{brace}'" - end - - except = Puppet::ParseError.new(error) - except.line = @lexer.line - except.file = @lexer.file if @lexer.file - - raise except - end - - # how should I do error handling here? - def parse(string = nil) - self.string = string if string - begin - @yydebug = false - main = yyparse(@lexer,:scan) - rescue Puppet::ParseError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - except.pos ||= @lexer.pos - raise except - rescue => except - raise Puppet::ParseError.new(except.message, @lexer.file, @lexer.line, nil, except) - end - # Store the results as the top-level class. - return Puppet::Parser::AST::Hostclass.new('', :code => main) - ensure - @lexer.clear - end -end diff --git a/lib/puppet/parser/relationship.rb b/lib/puppet/parser/relationship.rb index a32d0ae90..cbc1b4d1b 100644 --- a/lib/puppet/parser/relationship.rb +++ b/lib/puppet/parser/relationship.rb @@ -1,77 +1,62 @@ class Puppet::Parser::Relationship attr_accessor :source, :target, :type PARAM_MAP = {:relationship => :before, :subscription => :notify} def arrayify(resources) - # This if statement is needed because the 3x parser cannot load - # Puppet::Pops. This logic can be removed for 4.0 when the 3x AST - # is removed (when Pops is always used). - if !(Puppet[:parser] == 'future') - case resources - when Puppet::Parser::Collector - resources.collected.values - when Array - resources - else - [resources] - end + case resources + when Puppet::Pops::Evaluator::Collectors::AbstractCollector + resources.collected.values + when Array + resources else - require 'puppet/pops' - case resources - when Puppet::Pops::Evaluator::Collectors::AbstractCollector - resources.collected.values - when Array - resources - else - [resources] - end + [resources] end end def evaluate(catalog) arrayify(source).each do |s| arrayify(target).each do |t| mk_relationship(s, t, catalog) end end end def initialize(source, target, type) @source, @target, @type = source, target, type end def param_name PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}") end def mk_relationship(source, target, catalog) # REVISIT: In Ruby 1.8 we applied `to_s` to source and target, rather than # `join` without an argument. In 1.9 the behaviour of Array#to_s changed, # and it gives a different representation than just concat the stringified # elements. # # This restores the behaviour, but doesn't address the underlying question # of what would happen when more than one item was passed in that array. # (Hint: this will not end well.) # # See http://projects.puppetlabs.com/issues/12076 for the ticket tracking # the fact that we should dig out the sane version of this behaviour, then # implement it - where we don't risk breaking a stable release series. # --daniel 2012-01-21 source = source.is_a?(Array) ? source.join : source.to_s target = target.is_a?(Array) ? target.join : target.to_s unless source_resource = catalog.resource(source) raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'" end unless catalog.resource(target) raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'" end Puppet.debug "Adding relationship from #{source} to #{target} with '#{param_name}'" if source_resource[param_name].class != Array source_resource[param_name] = [source_resource[param_name]].compact end source_resource[param_name] << target end end diff --git a/lib/puppet/pops.rb b/lib/puppet/pops.rb index 97568e257..6ed6696aa 100644 --- a/lib/puppet/pops.rb +++ b/lib/puppet/pops.rb @@ -1,126 +1,125 @@ module Puppet # The Pops language system. This includes the parser, evaluator, AST model, and # Binder. # # @todo Explain how a user should use this to parse and evaluate the puppet # language. # # @note Warning: Pops is still considered experimental, as such the API may # change at any time. # # @api public module Pops require 'puppet/pops/patterns' require 'puppet/pops/utils' require 'puppet/pops/adaptable' require 'puppet/pops/adapters' require 'puppet/pops/visitable' require 'puppet/pops/visitor' require 'puppet/pops/containment' require 'puppet/pops/issues' require 'puppet/pops/semantic_error' require 'puppet/pops/label_provider' require 'puppet/pops/validation' require 'puppet/pops/issue_reporter' require 'puppet/pops/model/model' # (the Types module initializes itself) require 'puppet/pops/types/types' require 'puppet/pops/types/type_calculator' require 'puppet/pops/types/type_factory' require 'puppet/pops/types/type_parser' require 'puppet/pops/types/class_loader' require 'puppet/pops/types/enumeration' module Model require 'puppet/pops/model/tree_dumper' require 'puppet/pops/model/ast_transformer' - require 'puppet/pops/model/ast_tree_dumper' require 'puppet/pops/model/factory' require 'puppet/pops/model/model_tree_dumper' require 'puppet/pops/model/model_label_provider' end module Binder module SchemeHandler # the handlers are auto loaded via bindings end module Producers require 'puppet/pops/binder/producers' end require 'puppet/pops/binder/binder' require 'puppet/pops/binder/bindings_model' require 'puppet/pops/binder/binder_issues' require 'puppet/pops/binder/bindings_checker' require 'puppet/pops/binder/bindings_factory' require 'puppet/pops/binder/bindings_label_provider' require 'puppet/pops/binder/bindings_validator_factory' require 'puppet/pops/binder/injector_entry' require 'puppet/pops/binder/key_factory' require 'puppet/pops/binder/injector' require 'puppet/pops/binder/bindings_composer' require 'puppet/pops/binder/bindings_model_dumper' require 'puppet/pops/binder/system_bindings' require 'puppet/pops/binder/bindings_loader' require 'puppet/pops/binder/lookup' module Config require 'puppet/pops/binder/config/binder_config' require 'puppet/pops/binder/config/binder_config_checker' require 'puppet/pops/binder/config/issues' require 'puppet/pops/binder/config/diagnostic_producer' end end module Parser require 'puppet/pops/parser/eparser' require 'puppet/pops/parser/parser_support' require 'puppet/pops/parser/locator' require 'puppet/pops/parser/locatable' require 'puppet/pops/parser/lexer2' require 'puppet/pops/parser/evaluating_parser' require 'puppet/pops/parser/epp_parser' require 'puppet/pops/parser/code_merger' end module Validation require 'puppet/pops/validation/checker4_0' require 'puppet/pops/validation/validator_factory_4_0' end module Evaluator require 'puppet/pops/evaluator/callable_signature' require 'puppet/pops/evaluator/runtime3_support' require 'puppet/pops/evaluator/evaluator_impl' require 'puppet/pops/evaluator/epp_evaluator' require 'puppet/pops/evaluator/callable_mismatch_describer' require 'puppet/pops/evaluator/collector_transformer' module Collectors require 'puppet/pops/evaluator/collectors/abstract_collector' require 'puppet/pops/evaluator/collectors/fixed_set_collector' require 'puppet/pops/evaluator/collectors/catalog_collector' require 'puppet/pops/evaluator/collectors/exported_collector' end end # Subsystem for puppet functions defined in ruby. # # @api public module Functions require 'puppet/pops/functions/function' require 'puppet/pops/functions/dispatch' require 'puppet/pops/functions/dispatcher' end end require 'puppet/parser/ast/pops_bridge' require 'puppet/bindings' require 'puppet/functions' end diff --git a/lib/puppet/pops/evaluator/closure.rb b/lib/puppet/pops/evaluator/closure.rb index 0aca525c1..12f4df503 100644 --- a/lib/puppet/pops/evaluator/closure.rb +++ b/lib/puppet/pops/evaluator/closure.rb @@ -1,228 +1,229 @@ # A Closure represents logic bound to a particular scope. # As long as the runtime (basically the scope implementation) has the behaviour of Puppet 3x it is not # safe to use this closure when the scope given to it when initialized goes "out of scope". # # Note that the implementation is backwards compatible in that the call method accepts a scope, but this # scope is not used. # # Note that this class is a CallableSignature, and the methods defined there should be used # as the API for obtaining information in a callable implementation agnostic way. # class Puppet::Pops::Evaluator::Closure < Puppet::Pops::Evaluator::CallableSignature attr_reader :evaluator attr_reader :model attr_reader :enclosing_scope def initialize(evaluator, model, scope) @evaluator = evaluator @model = model @enclosing_scope = scope end # marker method checked with respond_to :puppet_lambda # @api private # @deprecated Use the type system to query if an object is of Callable type, then use its signatures method for info def puppet_lambda() true end + # TODO-3274 does not have to be compatible? the scope is not used since lambdas are evaluated in their closure # compatible with 3x AST::Lambda # @api public def call(scope, *args) variable_bindings = combine_values_with_parameters(args) tc = Puppet::Pops::Types::TypeCalculator final_args = tc.infer_set(parameters.inject([]) do |final_args, param| if param.captures_rest final_args.concat(variable_bindings[param.name]) else final_args << variable_bindings[param.name] end end) if tc.callable?(type, final_args) @evaluator.evaluate_block_with_bindings(@enclosing_scope, variable_bindings, @model.body) else raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}" end end # Call closure with argument assignment by name def call_by_name(scope, args_hash, enforce_parameters) if enforce_parameters if args_hash.size > parameters.size raise ArgumentError, "Too many arguments: #{args_hash.size} for #{parameters.size}" end # associate values with parameters scope_hash = {} parameters.each do |p| name = p.name if (arg_value = args_hash[name]).nil? # only set result of default expr if it is defined (it is otherwise not possible to differentiate # between explicit undef and no default expression unless p.value.nil? scope_hash[name] = @evaluator.evaluate(p.value, @enclosing_scope) end else scope_hash[name] = arg_value end end missing = parameters.select { |p| !scope_hash.include?(p.name) } if missing.any? raise ArgumentError, "Too few arguments; no value given for required parameters #{missing.collect(&:name).join(" ,")}" end tc = Puppet::Pops::Types::TypeCalculator final_args = tc.infer_set(parameter_names.collect { |param| scope_hash[param] }) if !tc.callable?(type, final_args) raise ArgumentError, "lambda called with mis-matched arguments\n#{Puppet::Pops::Evaluator::CallableMismatchDescriber.diff_string('lambda', final_args, [self])}" end else scope_hash = args_hash end @evaluator.evaluate_block_with_bindings(@enclosing_scope, scope_hash, @model.body) end def parameters @model.parameters end # Returns the number of parameters (required and optional) # @return [Integer] the total number of accepted parameters def parameter_count # yes, this is duplication of code, but it saves a method call @model.parameters.size end # @api public def parameter_names @model.parameters.collect(&:name) end # @api public def type @callable ||= create_callable_type end # @api public def last_captures_rest? last = @model.parameters[-1] last && last.captures_rest end # @api public def block_name # TODO: Lambda's does not support blocks yet. This is a placeholder 'unsupported_block' end private def combine_values_with_parameters(args) variable_bindings = {} parameters.each_with_index do |parameter, index| param_captures = parameter.captures_rest default_expression = parameter.value if index >= args.size if default_expression # not given, has default value = @evaluator.evaluate(default_expression, @enclosing_scope) if param_captures && !value.is_a?(Array) # correct non array default value value = [value] end else # not given, does not have default if param_captures # default for captures rest is an empty array value = [] else @evaluator.fail(Puppet::Pops::Issues::MISSING_REQUIRED_PARAMETER, parameter, { :param_name => parameter.name }) end end else given_argument = args[index] if param_captures # get excess arguments value = args[(parameter_count-1)..-1] # If the input was a single nil, or undef, and there is a default, use the default # This supports :undef in case it was used in a 3x data structure and it is passed as an arg # if value.size == 1 && (given_argument.nil? || given_argument == :undef) && default_expression value = @evaluator.evaluate(default_expression, scope) # and ensure it is an array value = [value] unless value.is_a?(Array) end else value = given_argument end end variable_bindings[parameter.name] = value end variable_bindings end def create_callable_type() types = [] range = [0, 0] in_optional_parameters = false parameters.each do |param| type = if param.type_expr @evaluator.evaluate(param.type_expr, @enclosing_scope) else Puppet::Pops::Types::TypeFactory.any() end if param.captures_rest && type.is_a?(Puppet::Pops::Types::PArrayType) # An array on a slurp parameter is how a size range is defined for a # slurp (Array[Integer, 1, 3] *$param). However, the callable that is # created can't have the array in that position or else type checking # will require the parameters to be arrays, which isn't what is # intended. The array type contains the intended information and needs # to be unpacked. param_range = type.size_range type = type.element_type elsif param.captures_rest && !type.is_a?(Puppet::Pops::Types::PArrayType) param_range = ANY_NUMBER_RANGE elsif param.value param_range = OPTIONAL_SINGLE_RANGE else param_range = REQUIRED_SINGLE_RANGE end types << type if param_range[0] == 0 in_optional_parameters = true elsif param_range[0] != 0 && in_optional_parameters @evaluator.fail(Puppet::Pops::Issues::REQUIRED_PARAMETER_AFTER_OPTIONAL, param, { :param_name => param.name }) end range[0] += param_range[0] range[1] += param_range[1] end if range[1] == Puppet::Pops::Types::INFINITY range[1] = :default end Puppet::Pops::Types::TypeFactory.callable(*(types + range)) end # Produces information about parameters compatible with a 4x Function (which can have multiple signatures) def signatures [ self ] end ANY_NUMBER_RANGE = [0, Puppet::Pops::Types::INFINITY] OPTIONAL_SINGLE_RANGE = [0, 1] REQUIRED_SINGLE_RANGE = [1, 1] end diff --git a/lib/puppet/pops/evaluator/runtime3_support.rb b/lib/puppet/pops/evaluator/runtime3_support.rb index 50b021212..690f70926 100644 --- a/lib/puppet/pops/evaluator/runtime3_support.rb +++ b/lib/puppet/pops/evaluator/runtime3_support.rb @@ -1,601 +1,601 @@ # A module with bindings between the new evaluator and the 3x runtime. # The intention is to separate all calls into scope, compiler, resource, etc. in this module # to make it easier to later refactor the evaluator for better implementations of the 3x classes. # # @api private module Puppet::Pops::Evaluator::Runtime3Support NAME_SPACE_SEPARATOR = '::'.freeze # Fails the evaluation of _semantic_ with a given issue. # # @param issue [Puppet::Pops::Issue] the issue to report # @param semantic [Puppet::Pops::ModelPopsObject] the object for which evaluation failed in some way. Used to determine origin. # @param options [Hash] hash of optional named data elements for the given issue # @return [!] this method does not return # @raise [Puppet::ParseError] an evaluation error initialized from the arguments (TODO: Change to EvaluationError?) # def fail(issue, semantic, options={}, except=nil) optionally_fail(issue, semantic, options, except) # an error should have been raised since fail always fails raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception" end # Optionally (based on severity) Fails the evaluation of _semantic_ with a given issue # If the given issue is configured to be of severity < :error it is only reported, and the function returns. # # @param issue [Puppet::Pops::Issue] the issue to report # @param semantic [Puppet::Pops::ModelPopsObject] the object for which evaluation failed in some way. Used to determine origin. # @param options [Hash] hash of optional named data elements for the given issue # @return [!] this method does not return # @raise [Puppet::ParseError] an evaluation error initialized from the arguments (TODO: Change to EvaluationError?) # def optionally_fail(issue, semantic, options={}, except=nil) if except.nil? # Want a stacktrace, and it must be passed as an exception begin raise EvaluationError.new() rescue EvaluationError => e except = e end end diagnostic_producer.accept(issue, semantic, options, except) end # Binds the given variable name to the given value in the given scope. # The reference object `o` is intended to be used for origin information - the 3x scope implementation # only makes use of location when there is an error. This is now handled by other mechanisms; first a check # is made if a variable exists and an error is raised if attempting to change an immutable value. Errors # in name, numeric variable assignment etc. have also been validated prior to this call. In the event the # scope.setvar still raises an error, the general exception handling for evaluation of the assignment # expression knows about its location. Because of this, there is no need to extract the location for each # setting (extraction is somewhat expensive since 3x requires line instead of offset). # def set_variable(name, value, o, scope) # Scope also checks this but requires that location information are passed as options. # Those are expensive to calculate and a test is instead made here to enable failing with better information. # The error is not specific enough to allow catching it - need to check the actual message text. # TODO: Improve the messy implementation in Scope. # if scope.bound?(name) if Puppet::Parser::Scope::RESERVED_VARIABLE_NAMES.include?(name) fail(Puppet::Pops::Issues::ILLEGAL_RESERVED_ASSIGNMENT, o, {:name => name} ) else fail(Puppet::Pops::Issues::ILLEGAL_REASSIGNMENT, o, {:name => name} ) end end scope.setvar(name, value) end # Returns the value of the variable (nil is returned if variable has no value, or if variable does not exist) # def get_variable_value(name, o, scope) # Puppet 3x stores all variables as strings (then converts them back to numeric with a regexp... to see if it is a match variable) # Not ideal, scope should support numeric lookup directly instead. # TODO: consider fixing scope catch(:undefined_variable) { x = scope.lookupvar(name.to_s) # Must convert :undef back to nil - this can happen when an undefined variable is used in a # parameter's default value expression - there nil must be :undef to work with the rest of 3x. # Now that the value comes back to 4x it is changed to nil. return (x == :undef) ? nil : x } # It is always ok to reference numeric variables even if they are not assigned. They are always undef # if not set by a match expression. # unless name =~ Puppet::Pops::Patterns::NUMERIC_VAR_NAME fail(Puppet::Pops::Issues::UNKNOWN_VARIABLE, o, {:name => name}) end end # Returns true if the variable of the given name is set in the given most nested scope. True is returned even if # variable is bound to nil. # def variable_bound?(name, scope) scope.bound?(name.to_s) end # Returns true if the variable is bound to a value or nil, in the scope or it's parent scopes. # def variable_exists?(name, scope) scope.exist?(name.to_s) end def set_match_data(match_data, scope) # See set_variable for rationale for not passing file and line to ephemeral_from. # NOTE: The 3x scope adds one ephemeral(match) to its internal stack per match that succeeds ! It never # clears anything. Thus a context that performs many matches will get very deep (there simply is no way to # clear the match variables without rolling back the ephemeral stack.) # This implementation does not attempt to fix this, it behaves the same bad way. unless match_data.nil? scope.ephemeral_from(match_data) end end # Creates a local scope with vairalbes set from a hash of variable name to value # def create_local_scope_from(hash, scope) # two dummy values are needed since the scope tries to give an error message (can not happen in this # case - it is just wrong, the error should be reported by the caller who knows in more detail where it # is in the source. # raise ArgumentError, "Internal error - attempt to create a local scope without a hash" unless hash.is_a?(Hash) scope.ephemeral_from(hash) end # Creates a nested match scope def create_match_scope_from(scope) # Create a transparent match scope (for future matches) scope.new_match_scope(nil) end def get_scope_nesting_level(scope) scope.ephemeral_level end def set_scope_nesting_level(scope, level) # Yup, 3x uses this method to reset the level, it also supports passing :all to destroy all # ephemeral/local scopes - which is a sure way to create havoc. # scope.unset_ephemeral_var(level) end # Adds a relationship between the given `source` and `target` of the given `relationship_type` # @param source [Puppet:Pops::Types::PCatalogEntryType] the source end of the relationship (from) # @param target [Puppet:Pops::Types::PCatalogEntryType] the target end of the relationship (to) # @param relationship_type [:relationship, :subscription] the type of the relationship # def add_relationship(source, target, relationship_type, scope) # The 3x way is to record a Puppet::Parser::Relationship that is evaluated at the end of the compilation. # This means it is not possible to detect any duplicates at this point (and signal where an attempt is made to # add a duplicate. There is also no location information to signal the original place in the logic. The user will have # to go fish. # The 3.x implementation is based on Strings :-o, so the source and target must be transformed. The resolution is # done by Catalog#resource(type, title). To do that, it creates a Puppet::Resource since it is responsible for # translating the name/type/title and create index-keys used by the catalog. The Puppet::Resource has bizarre parsing of # the type and title (scan for [] that is interpreted as type/title (but it gets it wrong). # Moreover if the type is "" or "component", the type is Class, and if the type is :main, it is :main, all other cases # undergo capitalization of name-segments (foo::bar becomes Foo::Bar). (This was earlier done in the reverse by the parser). # Further, the title undergoes the same munging !!! # # That bug infested nest of messy logic needs serious Exorcism! # # Unfortunately it is not easy to simply call more intelligent methods at a lower level as the compiler evaluates the recorded # Relationship object at a much later point, and it is responsible for invoking all the messy logic. # # TODO: Revisit the below logic when there is a sane implementation of the catalog, compiler and resource. For now # concentrate on transforming the type references to what is expected by the wacky logic. # # HOWEVER, the Compiler only records the Relationships, and the only method it calls is @relationships.each{|x| x.evaluate(catalog) } # Which means a smarter Relationship class could do this right. Instead of obtaining the resource from the catalog using # the borked resource(type, title) which creates a resource for the purpose of looking it up, it needs to instead # scan the catalog's resources # # GAAAH, it is even worse! # It starts in the parser, which parses "File['foo']" into an AST::ResourceReference with type = File, and title = foo # This AST is evaluated by looking up the type/title in the scope - causing it to be loaded if it exists, and if not, the given # type name/title is used. It does not search for resource instances, only classes and types. It returns symbolic information # [type, [title, title]]. From this, instances of Puppet::Resource are created and returned. These only have type/title information # filled out. One or an array of resources are returned. # This set of evaluated (empty reference) Resource instances are then passed to the relationship operator. It creates a # Puppet::Parser::Relationship giving it a source and a target that are (empty reference) Resource instances. These are then remembered # until the relationship is evaluated by the compiler (at the end). When evaluation takes place, the (empty reference) Resource instances # are converted to String (!?! WTF) on the simple format "#{type}[#{title}]", and the catalog is told to find a resource, by giving # it this string. If it cannot find the resource it fails, else the before/notify parameter is appended with the target. # The search for the resource begin with (you guessed it) again creating an (empty reference) resource from type and title (WTF?!?!). # The catalog now uses the reference resource to compute a key [r.type, r.title.to_s] and also gets a uniqueness key from the # resource (This is only a reference type created from title and type). If it cannot find it with the first key, it uses the # uniqueness key to lookup. # # This is probably done to allow a resource type to munge/translate the title in some way (but it is quite unclear from the long # and convoluted path of evaluation. # In order to do this in a way that is similar to 3.x two resources are created to be used as keys. # # And if that is not enough, a source/target may be a Collector (a baked query that will be evaluated by the # compiler - it is simply passed through here for processing by the compiler at the right time). # - if source.is_a?(Puppet::Parser::Collector) || source.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector) + if source.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector) # use verbatim - behavior defined by 3x source_resource = source else # transform into the wonderful String representation in 3x type, title = catalog_type_to_split_type_title(source) source_resource = Puppet::Resource.new(type, title) end - if target.is_a?(Puppet::Parser::Collector) || target.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector) + if target.is_a?(Puppet::Pops::Evaluator::Collectors::AbstractCollector) # use verbatim - behavior defined by 3x target_resource = target else # transform into the wonderful String representation in 3x type, title = catalog_type_to_split_type_title(target) target_resource = Puppet::Resource.new(type, title) end # Add the relationship to the compiler for later evaluation. scope.compiler.add_relationship(Puppet::Parser::Relationship.new(source_resource, target_resource, relationship_type)) end # Coerce value `v` to numeric or fails. # The given value `v` is coerced to Numeric, and if that fails the operation # calls {#fail}. # @param v [Object] the value to convert # @param o [Object] originating instruction # @param scope [Object] the (runtime specific) scope where evaluation of o takes place # @return [Numeric] value `v` converted to Numeric. # def coerce_numeric(v, o, scope) unless n = Puppet::Pops::Utils.to_n(v) fail(Puppet::Pops::Issues::NOT_NUMERIC, o, {:value => v}) end n end def call_function(name, args, o, scope) Puppet::Util::Profiler.profile("Called #{name}", [:functions, name]) do # Call via 4x API if the function exists there loaders = scope.compiler.loaders # find the loader that loaded the code, or use the private_environment_loader (sees env + all modules) adapter = Puppet::Pops::Utils.find_adapter(o, Puppet::Pops::Adapters::LoaderAdapter) loader = adapter.nil? ? loaders.private_environment_loader : adapter.loader if loader && func = loader.load(:function, name) return func.call(scope, *args) end # Call via 3x API if function exists there fail(Puppet::Pops::Issues::UNKNOWN_FUNCTION, o, {:name => name}) unless Puppet::Parser::Functions.function(name) # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x. # NOTE: Passing an empty string last converts nil/:undef to empty string mapped_args = args.map {|a| convert(a, scope, '') } result = scope.send("function_#{name}", mapped_args) # Prevent non r-value functions from leaking their result (they are not written to care about this) Puppet::Parser::Functions.rvalue?(name) ? result : nil end end # The o is used for source reference def create_resource_parameter(o, scope, name, value, operator) file, line = extract_file_line(o) Puppet::Parser::Resource::Param.new( :name => name, :value => convert(value, scope, nil), # converted to 3x since 4x supports additional objects / types :source => scope.source, :line => line, :file => file, :add => operator == :'+>' ) end CLASS_STRING = 'class'.freeze def create_resources(o, scope, virtual, exported, type_name, resource_titles, evaluated_parameters) # TODO: Unknown resource causes creation of Resource to fail with ArgumentError, should give # a proper Issue. Now the result is "Error while evaluating a Resource Statement" with the message # from the raised exception. (It may be good enough). # resolve in scope. fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type_name, resource_titles) # Not 100% accurate as this is the resource expression location and each title is processed separately # The titles are however the result of evaluation and they have no location at this point (an array # of positions for the source expressions are required for this to work). # TODO: Revisit and possible improve the accuracy. # file, line = extract_file_line(o) # Build a resource for each title resource_titles.map do |resource_title| resource = Puppet::Parser::Resource.new( fully_qualified_type, resource_title, :parameters => evaluated_parameters, :file => file, :line => line, :exported => exported, :virtual => virtual, # WTF is this? Which source is this? The file? The name of the context ? :source => scope.source, :scope => scope, :strict => true ) if resource.resource_type.is_a? Puppet::Resource::Type resource.resource_type.instantiate_resource(scope, resource) end scope.compiler.add_resource(scope, resource) scope.compiler.evaluate_classes([resource_title], scope, false, true) if fully_qualified_type == CLASS_STRING # Turn the resource into a PType (a reference to a resource type) # weed out nil's resource_to_ptype(resource) end end # Defines default parameters for a type with the given name. # def create_resource_defaults(o, scope, type_name, evaluated_parameters) # Note that name must be capitalized in this 3x call # The 3x impl creates a Resource instance with a bogus title and then asks the created resource # for the type of the name. # Note, locations are available per parameter. # scope.define_settings(capitalize_qualified_name(type_name), evaluated_parameters) end # Capitalizes each segment of a qualified name # def capitalize_qualified_name(name) name.split(/::/).map(&:capitalize).join(NAME_SPACE_SEPARATOR) end # Creates resource overrides for all resource type objects in evaluated_resources. The same set of # evaluated parameters are applied to all. # def create_resource_overrides(o, scope, evaluated_resources, evaluated_parameters) # Not 100% accurate as this is the resource expression location and each title is processed separately # The titles are however the result of evaluation and they have no location at this point (an array # of positions for the source expressions are required for this to work. # TODO: Revisit and possible improve the accuracy. # file, line = extract_file_line(o) evaluated_resources.each do |r| unless r.is_a?(Puppet::Pops::Types::PResourceType) && r.type_name != 'class' fail(Puppet::Pops::Issues::ILLEGAL_OVERRIDEN_TYPE, o, {:actual => r} ) end resource = Puppet::Parser::Resource.new( r.type_name, r.title, :parameters => evaluated_parameters, :file => file, :line => line, # WTF is this? Which source is this? The file? The name of the context ? :source => scope.source, :scope => scope ) scope.compiler.add_override(resource) end end # Finds a resource given a type and a title. # def find_resource(scope, type_name, title) scope.compiler.findresource(type_name, title) end # Returns the value of a resource's parameter by first looking up the parameter in the resource # and then in the defaults for the resource. Since the resource exists (it must in order to look up its # parameters, any overrides have already been applied). Defaults are not applied to a resource until it # has been finished (which typically has not taken place when this is evaluated; hence the dual lookup). # def get_resource_parameter_value(scope, resource, parameter_name) # This gets the parameter value, or nil (for both valid parameters and parameters that do not exist). val = resource[parameter_name] # Sometimes the resource is a Puppet::Parser::Resource and sometimes it is # a Puppet::Resource. The Puppet::Resource case occurs when puppet language # is evaluated against an already completed catalog (where all instances of # Puppet::Parser::Resource are converted to Puppet::Resource instances). # Evaluating against an already completed catalog is really only found in # the language specification tests, where the puppet language is used to # test itself. if resource.is_a?(Puppet::Parser::Resource) # The defaults must be looked up in the scope where the resource was created (not in the given # scope where the lookup takes place. resource_scope = resource.scope if val.nil? && resource_scope && defaults = resource_scope.lookupdefaults(resource.type) # NOTE: 3x resource keeps defaults as hash using symbol for name as key to Parameter which (again) holds # name and value. # NOTE: meta parameters that are unset ends up here, and there are no defaults for those encoded # in the defaults, they may receive hardcoded defaults later (e.g. 'tag'). param = defaults[parameter_name.to_sym] # Some parameters (meta parameters like 'tag') does not return a param from which the value can be obtained # at all times. Instead, they return a nil param until a value has been set. val = param.nil? ? nil : param.value end end val end # Returns true, if the given name is the name of a resource parameter. # def is_parameter_of_resource?(scope, resource, name) return false unless name.is_a?(String) resource.valid_parameter?(name) end def resource_to_ptype(resource) nil if resource.nil? # inference returns the meta type since the 3x Resource is an alternate way to describe a type type_calculator.infer(resource).type end # This is the same type of "truth" as used in the current Puppet DSL. # def is_true? o # Is the value true? This allows us to control the definition of truth # in one place. case o # Support :undef since it may come from a 3x structure when :undef false else !!o end end # Utility method for TrueClass || FalseClass # @param x [Object] the object to test if it is instance of TrueClass or FalseClass def is_boolean? x x.is_a?(TrueClass) || x.is_a?(FalseClass) end def initialize @@convert_visitor ||= Puppet::Pops::Visitor.new(self, "convert", 2, 2) @@convert2_visitor ||= Puppet::Pops::Visitor.new(self, "convert2", 2, 2) end # Converts 4x supported values to 3x values. This is required because # resources and other objects do not know about the new type system, and does not support # regular expressions. Unfortunately this has to be done for array and hash as well. # A complication is that catalog types needs to be resolved against the scope. # def convert(o, scope, undef_value) @@convert_visitor.visit_this_2(self, o, scope, undef_value) end # Converts nested 4x supported values to 3x values. This is required because # resources and other objects do not know about the new type system, and does not support # regular expressions. Unfortunately this has to be done for array and hash as well. # A complication is that catalog types needs to be resolved against the scope. # def convert2(o, scope, undef_value) @@convert2_visitor.visit_this_2(self, o, scope, undef_value) end def convert_NilClass(o, scope, undef_value) undef_value end def convert2_NilClass(o, scope, undef_value) :undef end def convert_String(o, scope, undef_value) # although wasteful, needed because user code may mutate these strings in Resources o.frozen? ? o.dup : o end alias convert2_String :convert_String def convert_Object(o, scope, undef_value) o end alias :convert2_Object :convert_Object def convert_Array(o, scope, undef_value) o.map {|x| convert2(x, scope, undef_value) } end alias :convert2_Array :convert_Array def convert_Hash(o, scope, undef_value) result = {} o.each {|k,v| result[convert2(k, scope, undef_value)] = convert2(v, scope, undef_value) } result end alias :convert2_Hash :convert_Hash def convert_Regexp(o, scope, undef_value) # Puppet 3x cannot handle parameter values that are reqular expressions. Turn into regexp string in # source form o.inspect end alias :convert2_Regexp :convert_Regexp def convert_Symbol(o, scope, undef_value) case o # Support :undef since it may come from a 3x structure when :undef undef_value # 3x wants undef as either empty string or :undef else o # :default, and all others are verbatim since they are new in future evaluator end end # The :undef symbol should not be converted when nested in arrays or hashes def convert2_Symbol(o, scope, undef_value) o end def convert_PAnyType(o, scope, undef_value) o end alias :convert2_PAnyType :convert_PAnyType def convert_PCatalogEntryType(o, scope, undef_value) # Since 4x does not support dynamic scoping, all names are absolute and can be # used as is (with some check/transformation/mangling between absolute/relative form # due to Puppet::Resource's idiosyncratic behavior where some references must be # absolute and others cannot be. # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup. Puppet::Resource.new(*catalog_type_to_split_type_title(o)) end alias :convert2_PCatalogEntryType :convert_PCatalogEntryType private # Produces an array with [type, title] from a PCatalogEntryType # This method is used to produce the arguments for creation of reference resource instances # (used when 3x is operating on a resource). # Ensures that resources are *not* absolute. # def catalog_type_to_split_type_title(catalog_type) split_type = catalog_type.is_a?(Puppet::Pops::Types::PType) ? catalog_type.type : catalog_type case split_type when Puppet::Pops::Types::PHostClassType class_name = split_type.class_name ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')] when Puppet::Pops::Types::PResourceType type_name = split_type.type_name title = split_type.title if type_name =~ /^(::)?[Cc]lass/ ['class', title.nil? ? nil : title.sub(/^::/, '')] else # Ensure that title is '' if nil # Resources with absolute name always results in error because tagging does not support leading :: [type_name.nil? ? nil : type_name.sub(/^::/, ''), title.nil? ? '' : title] end else raise ArgumentError, "Cannot split the type #{catalog_type.class}, it represents neither a PHostClassType, nor a PResourceType." end end def extract_file_line(o) source_pos = Puppet::Pops::Utils.find_closest_positioned(o) return [nil, -1] unless source_pos [source_pos.locator.file, source_pos.line] end def find_closest_positioned(o) return nil if o.nil? || o.is_a?(Puppet::Pops::Model::Program) o.offset.nil? ? find_closest_positioned(o.eContainer) : Puppet::Pops::Adapters::SourcePosAdapter.adapt(o) end # Creates a diagnostic producer def diagnostic_producer Puppet::Pops::Validation::DiagnosticProducer.new( ExceptionRaisingAcceptor.new(), # Raises exception on all issues SeverityProducer.new(), # All issues are errors Puppet::Pops::Model::ModelLabelProvider.new()) end # Configure the severity of failures class SeverityProducer < Puppet::Pops::Validation::SeverityProducer Issues = Puppet::Pops::Issues def initialize super p = self # Issues triggering warning only if --debug is on if Puppet[:debug] p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :warning else p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore end # Store config issues, ignore or warning p[Issues::RT_NO_STORECONFIGS_EXPORT] = Puppet[:storeconfigs] ? :ignore : :warning p[Issues::RT_NO_STORECONFIGS] = Puppet[:storeconfigs] ? :ignore : :warning end end # An acceptor of diagnostics that immediately raises an exception. class ExceptionRaisingAcceptor < Puppet::Pops::Validation::Acceptor def accept(diagnostic) super Puppet::Pops::IssueReporter.assert_and_report(self, {:message => "Evaluation Error:", :emit_warnings => true }) if errors? raise ArgumentError, "Internal Error: Configuration of runtime error handling wrong: should have raised exception" end end end class EvaluationError < StandardError end end diff --git a/lib/puppet/pops/model/ast_transformer.rb b/lib/puppet/pops/model/ast_transformer.rb index 2898534dd..c032d55b5 100644 --- a/lib/puppet/pops/model/ast_transformer.rb +++ b/lib/puppet/pops/model/ast_transformer.rb @@ -1,643 +1,125 @@ require 'puppet/parser/ast' # The receiver of `import(file)` calls; once per imported file, or nil if imports are ignored # # Transforms a Pops::Model to classic Puppet AST. # TODO: Documentation is currently skipped completely (it is only used for Rdoc) # class Puppet::Pops::Model::AstTransformer AST = Puppet::Parser::AST Model = Puppet::Pops::Model attr_reader :importer def initialize(source_file = "unknown-file", importer=nil) @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform",0,0) @@query_transform_visitor ||= Puppet::Pops::Visitor.new(nil,"query",0,0) @@hostname_transform_visitor ||= Puppet::Pops::Visitor.new(nil,"hostname",0,0) @importer = importer @source_file = source_file end # Initialize klass from o (location) and hash (options to created instance). # The object o is used to compute a source location. It may be nil. Source position is merged into # the given options (non surgically). If o is non-nil, the first found source position going up # the containment hierarchy is set. I.e. callers should pass nil if a source position is not wanted # or known to be unobtainable for the object. # # @param o [Object, nil] object from which source position / location is obtained, may be nil # @param klass [Class] the ast class to create an instance of # @param hash [Hash] hash with options for the class to create # def ast(o, klass, hash={}) # create and pass hash with file and line information + # PUP-3274 - still needed since hostname transformation requires AST::HostName, and AST::Regexp klass.new(merge_location(hash, o)) end # THIS IS AN EXPENSIVE OPERATION # The 3x AST requires line, pos etc. to be recorded directly in the AST nodes and this information # must be computed. # (Newer implementation only computes the information that is actually needed; typically when raising an # exception). # def merge_location(hash, o) if o pos = {} source_pos = Puppet::Pops::Utils.find_closest_positioned(o) if source_pos pos[:line] = source_pos.line pos[:pos] = source_pos.pos end pos[:file] = @source_file if @source_file hash = hash.merge(pos) end hash end # Transforms pops expressions into AST 3.1 statements/expressions def transform(o) begin @@transform_visitor.visit_this(self,o) rescue StandardError => e loc_data = {} merge_location(loc_data, o) raise Puppet::ParseError.new("Error while transforming to Puppet 3 AST: #{e.message}", loc_data[:file], loc_data[:line], loc_data[:pos], e) end end # Transforms pops expressions into AST 3.1 query expressions def query(o) @@query_transform_visitor.visit_this(self, o) end # Transforms pops expressions into AST 3.1 hostnames def hostname(o) @@hostname_transform_visitor.visit_this(self, o) end - def transform_LiteralFloat(o) - # Numbers are Names in the AST !! (Name a.k.a BareWord) - ast o, AST::Name, :value => o.value.to_s - end - - def transform_LiteralInteger(o) - s = case o.radix - when 10 - o.value.to_s - when 8 - "0%o" % o.value - when 16 - "0x%X" % o.value - else - "bad radix:" + o.value.to_s - end - - # Numbers are Names in the AST !! (Name a.k.a BareWord) - ast o, AST::Name, :value => s - end - - # Transforms all literal values to string (override for those that should not be AST::String) - # - def transform_LiteralValue(o) - ast o, AST::String, :value => o.value.to_s - end - - def transform_LiteralBoolean(o) - ast o, AST::Boolean, :value => o.value - end - - def transform_Factory(o) - transform(o.current) - end - - def transform_ArithmeticExpression(o) - ast o, AST::ArithmeticOperator2, :lval => transform(o.left_expr), :rval=>transform(o.right_expr), - :operator => o.operator.to_s - end - - def transform_Array(o) - ast nil, AST::ASTArray, :children => o.collect {|x| transform(x) } - end - - # Puppet AST only allows: - # * variable[expression] => Hasharray Access - # * NAME [expressions] => Resource Reference(s) - # * type [epxressions] => Resource Reference(s) - # * HashArrayAccesses[expression] => HasharrayAccesses - # - # i.e. it is not possible to do `func()[3]`, `[1,2,3][$x]`, `{foo=>10, bar=>20}[$x]` etc. since - # LHS is not an expression - # - # Validation for 3.x semantics should validate the illegal cases. This transformation may fail, - # or ignore excess information if the expressions are not correct. - # This means that the transformation does not have to evaluate the lhs to detect the target expression. - # - # Hm, this seems to have changed, the LHS (variable) is evaluated if evaluateable, else it is used as is. - # - def transform_AccessExpression(o) - case o.left_expr - when Model::QualifiedName - ast o, AST::ResourceReference, :type => o.left_expr.value, :title => transform(o.keys) - - when Model::QualifiedReference - ast o, AST::ResourceReference, :type => o.left_expr.value, :title => transform(o.keys) - - when Model::VariableExpression - ast o, AST::HashOrArrayAccess, :variable => transform(o.left_expr), :key => transform(o.keys()[0]) - - else - ast o, AST::HashOrArrayAccess, :variable => transform(o.left_expr), :key => transform(o.keys()[0]) - end - end - - # Puppet AST has a complicated structure - # LHS can not be an expression, it must be a type (which is downcased). - # type = a downcased QualifiedName - # - def transform_CollectExpression(o) - raise "LHS is not a type" unless o.type_expr.is_a? Model::QualifiedReference - type = o.type_expr.value().downcase() - args = { :type => type } - - # This somewhat peculiar encoding is used by the 3.1 AST. - query = transform(o.query) - if query.is_a? Symbol - args[:form] = query - else - args[:form] = query.form - args[:query] = query - query.type = type - end - - if o.operations.size > 0 - args[:override] = transform(o.operations) - end - ast o, AST::Collection, args - end - - def transform_EppExpression(o) - # TODO: Not supported in 3x TODO_EPP - parameters = o.parameters.collect {|p| transform(p) } - args = { :parameters => parameters } - args[:children] = transform(o.body) unless is_nop?(o.body) - Puppet::Parser::AST::Epp.new(merge_location(args, o)) - end - - def transform_ExportedQuery(o) - if is_nop?(o.expr) - result = :exported - else - result = query(o.expr) - result.form = :exported - end - result - end - - def transform_VirtualQuery(o) - if is_nop?(o.expr) - result = :virtual - else - result = query(o.expr) - result.form = :virtual - end - result - end # Ensures transformation fails if a 3.1 non supported object is encountered in a query expression # def query_Object(o) raise "Not a valid expression in a collection query: "+o.class.name end - # Puppet AST only allows == and !=, and left expr is restricted, but right value is an expression - # - def query_ComparisonExpression(o) - if [:'==', :'!='].include? o.operator - ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => o.operator.to_s, :test2 => transform(o.right_expr) - else - raise "Not a valid comparison operator in a collection query: " + o.operator.to_s - end - end - - def query_AndExpression(o) - ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => 'and', :test2 => query(o.right_expr) - end - - def query_OrExpression(o) - ast o, AST::CollExpr, :test1 => query(o.left_expr), :oper => 'or', :test2 => query(o.right_expr) - end - - def query_ParenthesizedExpression(o) - result = query(o.expr) # produces CollExpr - result.parens = true - result - end - - def query_VariableExpression(o) - transform(o) - end - - def query_QualifiedName(o) - transform(o) - end - - def query_LiteralNumber(o) - transform(o) # number to string in correct radix - end - - def query_LiteralString(o) - transform(o) - end - - def query_LiteralBoolean(o) - transform(o) - end - - def transform_QualifiedName(o) - ast o, AST::Name, :value => o.value - end - - def transform_QualifiedReference(o) - ast o, AST::Type, :value => o.value - end - - def transform_ComparisonExpression(o) - ast o, AST::ComparisonOperator, :operator => o.operator.to_s, :lval => transform(o.left_expr), :rval => transform(o.right_expr) - end - - def transform_AndExpression(o) - ast o, AST::BooleanOperator, :operator => 'and', :lval => transform(o.left_expr), :rval => transform(o.right_expr) - end - - def transform_OrExpression(o) - ast o, AST::BooleanOperator, :operator => 'or', :lval => transform(o.left_expr), :rval => transform(o.right_expr) - end - - def transform_InExpression(o) - ast o, AST::InOperator, :lval => transform(o.left_expr), :rval => transform(o.right_expr) - end - - # Assignment in AST 3.1 is to variable or hasharray accesses !!! See Bug #16116 - def transform_AssignmentExpression(o) - args = {:value => transform(o.right_expr) } - case o.operator - when :'+=' - args[:append] = true - when :'=' - else - raise "The operator #{o.operator} is not supported by Puppet 3." - end - - args[:name] = case o.left_expr - when Model::VariableExpression - ast o, AST::Name, {:value => o.left_expr.expr.value } - when Model::AccessExpression - transform(o.left_expr) - else - raise "LHS is not an expression that can be assigned to" - end - ast o, AST::VarDef, args - end - - # Produces (name => expr) or (name +> expr) - def transform_AttributeOperation(o) - args = { :value => transform(o.value_expr) } - args[:add] = true if o.operator == :'+>' - args[:param] = o.attribute_name - ast o, AST::ResourceParam, args - end - - def transform_LiteralList(o) - # Uses default transform of Ruby Array to ASTArray - transform(o.values) - end - - # Literal hash has strange behavior in Puppet 3.1. See Bug #19426, and this implementation is bug - # compatible - def transform_LiteralHash(o) - if o.entries.size == 0 - ast o, AST::ASTHash, {:value=> {}} - else - value = {} - o.entries.each {|x| value.merge! transform(x) } - ast o, AST::ASTHash, {:value=> value} - end - end - - # Transforms entry into a hash (they are later merged with strange effects: Bug #19426). - # Puppet 3.x only allows: - # * NAME - # * quotedtext - # As keys (quoted text can be an interpolated string which is compared as a key in a less than satisfactory way). - # - def transform_KeyedEntry(o) - value = transform(o.value) - key = case o.key - when Model::QualifiedName - o.key.value - when Model::LiteralString - transform o.key - when Model::LiteralNumber - transform o.key - when Model::ConcatenatedString - transform o.key - else - raise "Illegal hash key expression of type (#{o.key.class})" - end - {key => value} - end - - def transform_MatchExpression(o) - ast o, AST::MatchOperator, :operator => o.operator.to_s, :lval => transform(o.left_expr), :rval => transform(o.right_expr) - end - - def transform_LiteralString(o) - ast o, AST::String, :value => o.value - end - - def transform_LambdaExpression(o) - astargs = { :parameters => o.parameters.collect {|p| transform(p) } } - astargs.merge!({ :children => transform(o.body) }) if o.body # do not want children if it is nil/nop - ast o, AST::Lambda, astargs - end - - def transform_LiteralDefault(o) - ast o, AST::Default, :value => :default - end - - def transform_LiteralUndef(o) - ast o, AST::Undef, :value => :undef - end - - def transform_LiteralRegularExpression(o) - ast o, AST::Regex, :value => o.value - end - - def transform_Nop(o) - ast o, AST::Nop - end - - # In the 3.1. grammar this is a hash that is merged with other elements to form a method call - # Also in 3.1. grammar there are restrictions on the LHS (that are only there for grammar issues). - # - def transform_NamedAccessExpression(o) - receiver = transform(o.left_expr) - name = o.right_expr - raise "Unacceptable function/method name" unless name.is_a? Model::QualifiedName - {:receiver => receiver, :name => name.value} - end - - def transform_NilClass(o) - ast o, AST::Nop, {} - end - - def transform_NotExpression(o) - ast o, AST::Not, :value => transform(o.expr) - end - - def transform_VariableExpression(o) - # assumes the expression is a QualifiedName - ast o, AST::Variable, :value => o.expr.value - end - - # In Puppet 3.1, the ConcatenatedString is responsible for the evaluation and stringification of - # expression segments. Expressions and Strings are kept in an array. - def transform_TextExpression(o) - transform(o.expr) - end - - def transform_UnaryMinusExpression(o) - ast o, AST::Minus, :value => transform(o.expr) - end - - # Puppet 3.1 representation of a BlockExpression is an AST::Array - this makes it impossible to differentiate - # between a LiteralArray and a Sequence. (Should it return the collected array, or the last expression?) - # (A BlockExpression has now been introduced in the AST to solve this). - # - def transform_BlockExpression(o) - children = [] - # remove nops resulting from import - o.statements.each {|s| r = transform(s); children << r unless is_nop?(r) } - ast o, AST::BlockExpression, :children => children # o.statements.collect {|s| transform(s) } - end - - # Interpolated strings are kept in an array of AST (string or other expression). - def transform_ConcatenatedString(o) - ast o, AST::Concat, :value => o.segments.collect {|x| transform(x)} - end - - def transform_HostClassDefinition(o) - parameters = o.parameters.collect {|p| transform(p) } - args = { - :arguments => parameters, - :parent => o.parent_class, - } - args[:code] = transform(o.body) unless is_nop?(o.body) - Puppet::Parser::AST::Hostclass.new(o.name, merge_location(args, o)) - end - - def transform_HeredocExpression(o) - # TODO_HEREDOC Not supported in 3x - args = {:syntax=> o.syntax(), :expr => transform(o.text_expr()) } - Puppet::Parser::AST::Heredoc.new(merge_location(args, o)) - end - - def transform_NodeDefinition(o) - # o.host_matches are expressions, and 3.1 AST requires special object AST::HostName - # where a HostName is one of NAME, STRING, DEFAULT or Regexp - all of these are strings except regexp - # - args = { - :code => transform(o.body) - } - args[:parent] = hostname(o.parent) unless is_nop?(o.parent) - if(args[:parent].is_a?(Array)) - raise "Illegal expression - unacceptable as a node parent" - end - Puppet::Parser::AST::Node.new(hostname(o.host_matches), merge_location(args, o)) - end - # Transforms Array of host matching expressions into a (Ruby) array of AST::HostName def hostname_Array(o) o.collect {|x| ast x, AST::HostName, :value => hostname(x) } end def hostname_LiteralValue(o) return o.value end def hostname_QualifiedName(o) return o.value end def hostname_LiteralNumber(o) transform(o) # Number to string with correct radix end def hostname_LiteralDefault(o) return 'default' end def hostname_LiteralRegularExpression(o) ast o, AST::Regex, :value => o.value end def hostname_Object(o) raise "Illegal expression - unacceptable as a node name" end - def transform_RelationshipExpression(o) - Puppet::Parser::AST::Relationship.new(transform(o.left_expr), transform(o.right_expr), o.operator.to_s, merge_location({}, o)) - end - - def transform_RenderStringExpression(o) - # TODO_EPP Not supported in 3x - ast o, AST::RenderString, :value => o.value - end - - def transform_RenderExpression(o) - # TODO_EPP Not supported in 3x - ast o, AST::RenderExpression, :value => transform(o.expr) - end - - def transform_ResourceTypeDefinition(o) - parameters = o.parameters.collect {|p| transform(p) } - args = { :arguments => parameters } - args[:code] = transform(o.body) unless is_nop?(o.body) - - Puppet::Parser::AST::Definition.new(o.name, merge_location(args, o)) - end - - # Transformation of ResourceOverrideExpression is slightly more involved than a straight forward - # transformation. - # A ResourceOverrideExppression has "resources" which should be an AccessExpression - # on the form QualifiedName[expressions], or QualifiedReference[expressions] to be valid. - # It also has a set of attribute operations. - # - # The AST equivalence is an AST::ResourceOverride with a ResourceReference as its LHS, and - # a set of Parameters. - # ResourceReference has type as a string, and the expressions representing - # the "titles" to be an ASTArray. - # - def transform_ResourceOverrideExpression(o) - raise "Unsupported transformation - use the new evaluator" - end - - # Parameter is a parameter in a definition of some kind. - # It is transformed to an array on the form `[name]´, or `[name, value]´. - def transform_Parameter(o) - if o.value - [o.name, transform(o.value)] - else - [o.name] - end - end - - # For non query expressions, parentheses can be dropped in the resulting AST. - def transform_ParenthesizedExpression(o) - transform(o.expr) - end - - def transform_Program(o) - transform(o.body) - end - - def transform_IfExpression(o) - args = { :test => transform(o.test), :statements => transform(o.then_expr) } - args[:else] = transform(o.else_expr) # Tests say Nop should be there (unless is_nop? o.else_expr), probably not needed - ast o, AST::IfStatement, args - end - - # Unless is not an AST object, instead an AST::IfStatement is used with an AST::Not around the test - # - def transform_UnlessExpression(o) - args = { :test => ast(o, AST::Not, :value => transform(o.test)), - :statements => transform(o.then_expr) } - # AST 3.1 does not allow else on unless in the grammar, but it is ok since unless is encoded as an if !x - args.merge!({:else => transform(o.else_expr)}) unless is_nop?(o.else_expr) - ast o, AST::IfStatement, args - end - - # Puppet 3.1 AST only supports calling a function by name (it is not possible to produce a function - # that is then called). - # rval_required (for an expression) - # functor_expr (lhs - the "name" expression) - # arguments - list of arguments - # - def transform_CallNamedFunctionExpression(o) - name = o.functor_expr - raise "Unacceptable expression for name of function" unless name.is_a? Model::QualifiedName - args = { - :name => name.value, - :arguments => transform(o.arguments), - :ftype => o.rval_required ? :rvalue : :statement - } - args[:pblock] = transform(o.lambda) if o.lambda - ast o, AST::Function, args - end - - # Transformation of CallMethodExpression handles a NamedAccessExpression functor and - # turns this into a 3.1 AST::MethodCall. - # - def transform_CallMethodExpression(o) - name = o.functor_expr - raise "Unacceptable expression for name of function" unless name.is_a? Model::NamedAccessExpression - # transform of NamedAccess produces a hash, add arguments to it - astargs = transform(name).merge(:arguments => transform(o.arguments)) - astargs.merge!(:lambda => transform(o.lambda)) if o.lambda # do not want a Nop as the lambda - ast o, AST::MethodCall, astargs - - end - - def transform_CaseExpression(o) - # Expects expression, AST::ASTArray of AST - ast o, AST::CaseStatement, :test => transform(o.test), :options => transform(o.options) - end - - def transform_CaseOption(o) - ast o, AST::CaseOpt, :value => transform(o.values), :statements => transform(o.then_expr) - end - - def transform_ResourceBody(o) - raise "Unsupported transformation - use the new evaluator" - end - - def transform_ResourceDefaultsExpression(o) - raise "Unsupported transformation - use the new evaluator" - end - - # Transformation of ResourceExpression requires calling a method on the resulting - # AST::Resource if it is virtual or exported - # - def transform_ResourceExpression(o) - raise "Unsupported transformation - use the new evaluator" - end - - # Transformation of SelectorExpression is limited to certain types of expressions. - # This is probably due to constraints in the old grammar rather than any real concerns. - def transform_SelectorExpression(o) - case o.left_expr - when Model::CallNamedFunctionExpression - when Model::AccessExpression - when Model::VariableExpression - when Model::ConcatenatedString - else - raise "Unacceptable select expression" unless o.left_expr.kind_of? Model::Literal - end - ast o, AST::Selector, :param => transform(o.left_expr), :values => transform(o.selectors) - end - - def transform_SelectorEntry(o) - ast o, AST::ResourceParam, :param => transform(o.matching_expr), :value => transform(o.value_expr) - end - def transform_Object(o) raise "Unacceptable transform - found an Object without a rule: #{o.class}" end # Nil, nop # Bee bopp a luh-lah, a bop bop boom. # def is_nop?(o) o.nil? || o.is_a?(Model::Nop) end end diff --git a/lib/puppet/pops/model/ast_tree_dumper.rb b/lib/puppet/pops/model/ast_tree_dumper.rb deleted file mode 100644 index 9008b1ccd..000000000 --- a/lib/puppet/pops/model/ast_tree_dumper.rb +++ /dev/null @@ -1,386 +0,0 @@ -require 'puppet/parser/ast' - -# Dumps a Pops::Model in reverse polish notation; i.e. LISP style -# The intention is to use this for debugging output -# TODO: BAD NAME - A DUMP is a Ruby Serialization -# -class Puppet::Pops::Model::AstTreeDumper < Puppet::Pops::Model::TreeDumper - AST = Puppet::Parser::AST - Model = Puppet::Pops::Model - - def dump_LiteralFloat o - o.value.to_s - end - - def dump_LiteralInteger o - case o.radix - when 10 - o.value.to_s - when 8 - "0%o" % o.value - when 16 - "0x%X" % o.value - else - "bad radix:" + o.value.to_s - end - end - - def dump_Expression(o) - "(pops-expression #{Puppet::Pops::Model::ModelTreeDumper.new().dump(o.value)})" - end - - def dump_Factory o - do_dump(o.current) - end - - def dump_ArithmeticOperator o - [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)] - end - def dump_Relationship o - [o.arrow.to_s, do_dump(o.left), do_dump(o.right)] - end - - # Hostname is tricky, it is either a bare word, a string, or default, or regular expression - # Least evil, all strings except default are quoted - def dump_HostName o - result = do_dump o.value - unless o.value.is_a? AST::Regex - result = result == "default" ? ":default" : "'#{result}'" - end - result - end - - # x[y] prints as (slice x y) - def dump_HashOrArrayAccess o - var = o.variable.is_a?(String) ? "$#{o.variable}" : do_dump(o.variable) - ["slice", var, do_dump(o.key)] - end - - # The AST Collection knows about exported or virtual query, not the query. - def dump_Collection o - result = ["collect", do_dump(o.type), :indent, :break] - if o.form == :virtual - q = ["<| |>"] - else - q = ["<<| |>>"] - end - q << do_dump(o.query) unless is_nop?(o.query) - q << :indent - result << q - o.override do |ao| - result << :break << do_dump(ao) - end - result += [:dedent, :dedent ] - result - end - - def dump_CollExpr o - operator = case o.oper - when 'and' - '&&' - when 'or' - '||' - else - o.oper - end - [operator, do_dump(o.test1), do_dump(o.test2)] - end - - def dump_ComparisonOperator o - [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)] - end - - def dump_Boolean o - o.to_s - end - - def dump_BooleanOperator o - operator = o.operator == 'and' ? '&&' : '||' - [operator, do_dump(o.lval), do_dump(o.rval)] - end - - def dump_InOperator o - ["in", do_dump(o.lval), do_dump(o.rval)] - end - - # $x = ... - # $x += ... - # - def dump_VarDef o - operator = o.append ? "+=" : "=" - [operator, '$' + do_dump(o.name), do_dump(o.value)] - end - - # Produces (name => expr) or (name +> expr) - def dump_ResourceParam o - operator = o.add ? "+>" : "=>" - [do_dump(o.param), operator, do_dump(o.value)] - end - - def dump_Array o - o.collect {|e| do_dump(e) } - end - - def dump_ASTArray o - ["[]"] + o.children.collect {|x| do_dump(x)} - end - - def dump_ASTHash o - ["{}"] + o.value.sort_by{|k,v| k.to_s}.collect {|x| [do_dump(x[0]), do_dump(x[1])]} -# ["{}"] + o.value.collect {|x| [do_dump(x[0]), do_dump(x[1])]} - end - - def dump_MatchOperator o - [o.operator.to_s, do_dump(o.lval), do_dump(o.rval)] - end - - # Dump a Ruby String in single quotes unless it is a number. - def dump_String o - - if o.is_a? String - o # A Ruby String, not quoted - elsif Puppet::Pops::Utils.to_n(o.value) - o.value # AST::String that is a number without quotes - else - "'#{o.value}'" # AST::String that is not a number - end - end - - def dump_Lambda o - result = ["lambda"] - result << ["parameters"] + o.parameters.collect {|p| _dump_ParameterArray(p) } if o.parameters.size() > 0 - if o.children == [] - result << [] # does not have a lambda body - else - result << do_dump(o.children) - end - result - end - - def dump_Default o - ":default" - end - - def dump_Undef o - ":undef" - end - - # Note this is Regex (the AST kind), not Ruby Regexp - def dump_Regex o - "/#{o.value.source}/" - end - - def dump_Nop o - ":nop" - end - - def dump_NilClass o - "()" - end - - def dump_Not o - ['!', dump(o.value)] - end - - def dump_Variable o - "$#{dump(o.value)}" - end - - def dump_Minus o - ['-', do_dump(o.value)] - end - - def dump_BlockExpression o - ["block"] + o.children.collect {|x| do_dump(x) } - end - - # Interpolated strings are shown as (cat seg0 seg1 ... segN) - def dump_Concat o - ["cat"] + o.value.collect {|x| x.is_a?(AST::String) ? " "+do_dump(x) : ["str", do_dump(x)]} - end - - def dump_Hostclass o - # ok, this is kind of crazy stuff in the AST, information in a context instead of in AST, and - # parameters are in a Ruby Array with each parameter being an Array... - # - context = o.context - args = context[:arguments] - parent = context[:parent] - result = ["class", o.name] - result << ["inherits", parent] if parent - result << ["parameters"] + args.collect {|p| _dump_ParameterArray(p) } if args && args.size() > 0 - if is_nop?(o.code) - result << [] - else - result << do_dump(o.code) - end - result - end - - def dump_Name o - o.value - end - - def dump_Node o - context = o.context - parent = context[:parent] - code = context[:code] - - result = ["node"] - result << ["matches"] + o.names.collect {|m| do_dump(m) } - result << ["parent", do_dump(parent)] if !is_nop?(parent) - if is_nop?(code) - result << [] - else - result << do_dump(code) - end - result - end - - def dump_Definition o - # ok, this is even crazier that Hostclass. The name of the define does not have an accessor - # and some things are in the context (but not the name). Parameters are called arguments and they - # are in a Ruby Array where each parameter is an array of 1 or 2 elements. - # - context = o.context - name = o.instance_variable_get("@name") - args = context[:arguments] - code = context[:code] - result = ["define", name] - result << ["parameters"] + args.collect {|p| _dump_ParameterArray(p) } if args && args.size() > 0 - if is_nop?(code) - result << [] - else - result << do_dump(code) - end - result - end - - def dump_ResourceReference o - result = ["slice", do_dump(o.type)] - if o.title.children.size == 1 - result << do_dump(o.title[0]) - else - result << do_dump(o.title.children) - end - result - end - - def dump_ResourceOverride o - result = ["override", do_dump(o.object), :indent] - o.parameters.each do |p| - result << :break << do_dump(p) - end - result << :dedent - result - end - - # Puppet AST encodes a parameter as a one or two slot Array. - # This is not a polymorph dump method. - # - def _dump_ParameterArray o - if o.size == 2 - ["=", o[0], do_dump(o[1])] - else - o[0] - end - end - - def dump_IfStatement o - result = ["if", do_dump(o.test), :indent, :break, - ["then", :indent, do_dump(o.statements), :dedent]] - result += - [:break, - ["else", :indent, do_dump(o.else), :dedent], - :dedent] unless is_nop? o.else - result - end - - # Produces (invoke name args...) when not required to produce an rvalue, and - # (call name args ... ) otherwise. - # - def dump_Function o - # somewhat ugly as Function hides its "ftype" instance variable - result = [o.instance_variable_get("@ftype") == :rvalue ? "call" : "invoke", do_dump(o.name)] - o.arguments.collect {|a| result << do_dump(a) } - result << do_dump(o.pblock) if o.pblock - result - end - - def dump_MethodCall o - # somewhat ugly as Method call (does the same as function) and hides its "ftype" instance variable - result = [o.instance_variable_get("@ftype") == :rvalue ? "call-method" : "invoke-method", - [".", do_dump(o.receiver), do_dump(o.name)]] - o.arguments.collect {|a| result << do_dump(a) } - result << do_dump(o.lambda) if o.lambda - result - end - - def dump_CaseStatement o - result = ["case", do_dump(o.test), :indent] - o.options.each do |s| - result << :break << do_dump(s) - end - result << :dedent - end - - def dump_CaseOpt o - result = ["when"] - result << o.value.collect {|x| do_dump(x) } - # A bit of trickery to get it into the same shape as Pops output - if is_nop?(o.statements) - result << ["then", []] # Puppet AST has a nop if there is no body - else - result << ["then", do_dump(o.statements) ] - end - result - end - - def dump_ResourceInstance o - result = [do_dump(o.title), :indent] - o.parameters.each do |p| - result << :break << do_dump(p) - end - result << :dedent - result - end - - def dump_ResourceDefaults o - result = ["resource-defaults", do_dump(o.type), :indent] - o.parameters.each do |p| - result << :break << do_dump(p) - end - result << :dedent - result - end - - def dump_Resource o - if o.exported - form = 'exported-' - elsif o.virtual - form = 'virtual-' - else - form = '' - end - result = [form+"resource", do_dump(o.type), :indent] - o.instances.each do |b| - result << :break << do_dump(b) - end - result << :dedent - result - end - - def dump_Selector o - values = o.values - values = [values] unless values.instance_of?(AST::ASTArray) || values.instance_of?(Array) - ["?", do_dump(o.param)] + values.collect {|x| do_dump(x) } - end - - def dump_Object o - ['dev-error-no-polymorph-dump-for:', o.class.to_s, o.to_s] - end - - def is_nop? o - o.nil? || o.is_a?(Model::Nop) || o.is_a?(AST::Nop) - end -end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index 999177dd3..66b960dba 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -1,399 +1,397 @@ require 'puppet/parser' require 'puppet/util/warnings' require 'puppet/util/errors' require 'puppet/util/inline_docs' require 'puppet/parser/ast/leaf' -require 'puppet/parser/ast/block_expression' # Puppet::Resource::Type represents nodes, classes and defined types. # # It has a standard format for external consumption, usable from the # resource_type indirection via rest and the resource_type face. See the # {file:api_docs/http_resource_type.md#Schema resource type schema # description}. # # @api public class Puppet::Resource::Type Puppet::ResourceType = self include Puppet::Util::InlineDocs include Puppet::Util::Warnings include Puppet::Util::Errors RESOURCE_KINDS = [:hostclass, :node, :definition] # Map the names used in our documentation to the names used internally RESOURCE_KINDS_TO_EXTERNAL_NAMES = { :hostclass => "class", :node => "node", :definition => "defined_type", } RESOURCE_EXTERNAL_NAMES_TO_KINDS = RESOURCE_KINDS_TO_EXTERNAL_NAMES.invert attr_accessor :file, :line, :doc, :code, :parent, :resource_type_collection attr_reader :namespace, :arguments, :behaves_like, :module_name # Map from argument (aka parameter) names to Puppet Type # @return [Hash :parser def self.from_data_hash(data) name = data.delete('name') or raise ArgumentError, "Resource Type names must be specified" kind = data.delete('kind') || "definition" unless type = RESOURCE_EXTERNAL_NAMES_TO_KINDS[kind] raise ArgumentError, "Unsupported resource kind '#{kind}'" end data = data.inject({}) { |result, ary| result[ary[0].intern] = ary[1]; result } # External documentation uses "parameters" but the internal name # is "arguments" data[:arguments] = data.delete(:parameters) new(type, name, data) end def to_data_hash data = [:doc, :line, :file, :parent].inject({}) do |hash, param| next hash unless (value = self.send(param)) and (value != "") hash[param.to_s] = value hash end # External documentation uses "parameters" but the internal name # is "arguments" data['parameters'] = arguments.dup unless arguments.empty? data['name'] = name unless RESOURCE_KINDS_TO_EXTERNAL_NAMES.has_key?(type) raise ArgumentError, "Unsupported resource kind '#{type}'" end data['kind'] = RESOURCE_KINDS_TO_EXTERNAL_NAMES[type] data end # 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 parent return(klass == parent_type ? true : parent_type.child_of?(klass)) end # Now evaluate the code associated with this class or definition. def evaluate_code(resource) static_parent = evaluate_parent_type(resource) scope = static_parent || resource.scope scope = scope.newscope(:namespace => namespace, :source => self, :resource => resource) unless resource.title == :main scope.compiler.add_class(name) unless definition? set_resource_parameters(resource, scope) resource.add_edge_to_stage if code if @match # Only bother setting up the ephemeral scope if there are match variables to add into it begin elevel = scope.ephemeral_level scope.ephemeral_from(@match, file, line) code.safeevaluate(scope) ensure scope.unset_ephemeral_var(elevel) end else code.safeevaluate(scope) end end end def initialize(type, name, options = {}) @type = type.to_s.downcase.to_sym raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_KINDS.include?(@type) name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName) set_name_and_namespace(name) [:code, :doc, :line, :file, :parent].each do |param| next unless value = options[param] send(param.to_s + "=", value) end set_arguments(options[:arguments]) set_argument_types(options[:argument_types]) @match = nil @module_name = options[:module_name] end # This is only used for node names, and really only when the node name # is a regexp. def match(string) return string.to_s.downcase == name unless name_is_regex? @match = @name.match(string) end # Add code from a new instance to our code. def merge(other) fail "#{name} is not a class; cannot add code to it" unless type == :hostclass fail "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass fail "Cannot have code outside of a class/node/define because 'freeze_main' is enabled" if name == "" and Puppet.settings[:freeze_main] if parent and other.parent and parent != other.parent fail "Cannot merge classes with different parent classes (#{name} => #{parent} vs. #{other.name} => #{other.parent})" end # We know they're either equal or only one is set, so keep whichever parent is specified. self.parent ||= other.parent if other.doc self.doc ||= "" self.doc += other.doc end # This might just be an empty, stub class. return unless other.code unless self.code self.code = other.code return end self.code = Puppet::Parser::ParserFactory.code_merger.concatenate([self, other]) -# self.code = self.code.sequence_with(other.code) end # Make an instance of the resource type, and place it in the catalog # if it isn't in the catalog already. This is only possible for # classes and nodes. No parameters are be supplied--if this is a # parameterized class, then all parameters take on their default # values. def ensure_in_catalog(scope, parameters=nil) type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" resource_type = type == :hostclass ? :class : :node # Do nothing if the resource already exists; this makes sure we don't # get multiple copies of the class resource, which helps provide the # singleton nature of classes. # we should not do this for classes with parameters # if parameters are passed, we should still try to create the resource # even if it exists so that we can fail # this prevents us from being able to combine param classes with include if resource = scope.catalog.resource(resource_type, name) and !parameters return resource end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) assign_parameter_values(parameters, resource) instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) resource end def instantiate_resource(scope, resource) # Make sure our parent class has been evaluated, if we have one. if parent && !scope.catalog.resource(resource.type, parent) parent_type(scope).ensure_in_catalog(scope) end if ['Class', 'Node'].include? resource.type scope.catalog.tag(*resource.tags) end end def name return @name unless @name.is_a?(Regexp) @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') end def name_is_regex? @name.is_a?(Regexp) end def assign_parameter_values(parameters, resource) return unless parameters # It'd be nice to assign default parameter values here, # but we can't because they often rely on local variables # created during set_resource_parameters. parameters.each do |name, value| resource.set_parameter name, value end end # MQR TODO: # # The change(s) introduced by the fix for #4270 are mostly silly & should be # removed, though we didn't realize it at the time. If it can be established/ # ensured that nodes never call parent_type and that resource_types are always # (as they should be) members of exactly one resource_type_collection the # following method could / should be replaced with: # # def parent_type # @parent_type ||= parent && ( # resource_type_collection.find_or_load([name],parent,type.to_sym) || # fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{resource_type_collection.environment}" # ) # end # # ...and then the rest of the changes around passing in scope reverted. # def parent_type(scope = nil) return nil unless parent unless @parent_type raise "Must pass scope to parent_type when called first time" unless scope unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", [name], parent) fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{scope.environment}" end end @parent_type end # Set any arguments passed by the resource as variables in the scope. def set_resource_parameters(resource, scope) set = {} resource.to_hash.each do |param, value| param = param.to_sym fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param) exceptwrap { scope[param.to_s] = value } set[param] = true end if @type == :hostclass scope["title"] = resource.title.to_s.downcase unless set.include? :title scope["name"] = resource.name.to_s.downcase unless set.include? :name else scope["title"] = resource.title unless set.include? :title scope["name"] = resource.name unless set.include? :name end scope["module_name"] = module_name if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? # Evaluate the default parameters, now that all other variables are set default_params = resource.set_default_parameters(scope) default_params.each { |param| scope[param] = resource[param] } # This has to come after the above parameters so that default values # can use their values resource.validate_complete end # Check whether a given argument is valid. def valid_parameter?(param) param = param.to_s return true if param == "name" return true if Puppet::Type.metaparam?(param) return false unless defined?(@arguments) return(arguments.include?(param) ? true : false) end def set_arguments(arguments) @arguments = {} return if arguments.nil? arguments.each do |arg, default| arg = arg.to_s warn_if_metaparam(arg, default) @arguments[arg] = default end end # Sets the argument name to Puppet Type hash used for type checking. # Names must correspond to available arguments (they must be defined first). # Arguments not mentioned will not be type-checked. Only supported when parser == "future" # def set_argument_types(name_to_type_hash) @argument_types = {} return unless name_to_type_hash name_to_type_hash.each do |name, t| # catch internal errors unless @arguments.include?(name) raise Puppet::DevError, "Parameter '#{name}' is given a type, but is not a valid parameter." end unless t.is_a? Puppet::Pops::Types::PAnyType raise Puppet::DevError, "Parameter '#{name}' is given a type that is not a Puppet Type, got #{t.class}" end @argument_types[name] = t end end private def convert_from_ast(name) value = name.value if value.is_a?(Puppet::Parser::AST::Regex) name = value.value else name = value end end def evaluate_parent_type(resource) return unless klass = parent_type(resource.scope) and parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name) parent_resource.evaluate unless parent_resource.evaluated? parent_scope(resource.scope, klass) end # Split an fq name into a namespace and name def namesplit(fullname) ary = fullname.split("::") n = ary.pop || "" ns = ary.join("::") return ns, n end def parent_scope(scope, klass) scope.class_scope(klass) || raise(Puppet::DevError, "Could not find scope for #{klass.name}") end def set_name_and_namespace(name) if name.is_a?(Regexp) @name = name @namespace = "" else @name = name.to_s.downcase # Note we're doing something somewhat weird here -- we're setting # the class's namespace to its fully qualified name. This means # anything inside that class starts looking in that namespace first. @namespace, ignored_shortname = @type == :hostclass ? [@name, ''] : namesplit(@name) end end def warn_if_metaparam(param, default) return unless Puppet::Type.metaparamclass(param) if default warnonce "#{param} is a metaparam; this value will inherit to all contained resources in the #{self.name} definition" else raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition" end end end diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collection_spec.rb similarity index 99% rename from spec/integration/parser/collector_spec.rb rename to spec/integration/parser/collection_spec.rb index 31ed0bf2f..a8460f972 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collection_spec.rb @@ -1,273 +1,271 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet_spec/compiler' -require 'puppet/parser/collector' - -describe Puppet::Parser::Collector do +describe 'collectors' do include PuppetSpec::Compiler def expect_the_message_to_be(expected_messages, code, node = Puppet::Node.new('the node')) catalog = compile_to_catalog(code, node) messages = catalog.resources.find_all { |resource| resource.type == 'Notify' }. collect { |notify| notify[:message] } messages.should include(*expected_messages) end context "virtual resource collection" do it "matches everything when no query given" do expect_the_message_to_be(["the other message", "the message"], <<-MANIFEST) @notify { "testing": message => "the message" } @notify { "other": message => "the other message" } Notify <| |> MANIFEST end it "matches regular resources " do expect_the_message_to_be(["changed", "changed"], <<-MANIFEST) notify { "testing": message => "the message" } notify { "other": message => "the other message" } Notify <| |> { message => "changed" } MANIFEST end it "matches on tags" do expect_the_message_to_be(["wanted"], <<-MANIFEST) @notify { "testing": tag => ["one"], message => "wanted" } @notify { "other": tag => ["two"], message => "unwanted" } Notify <| tag == one |> MANIFEST end it "matches on title" do expect_the_message_to_be(["the message"], <<-MANIFEST) @notify { "testing": message => "the message" } Notify <| title == "testing" |> MANIFEST end it "matches on other parameters" do expect_the_message_to_be(["the message"], <<-MANIFEST) @notify { "testing": message => "the message" } @notify { "other testing": message => "the wrong message" } Notify <| message == "the message" |> MANIFEST end it "matches against elements of an array valued parameter" do expect_the_message_to_be([["the", "message"]], <<-MANIFEST) @notify { "testing": message => ["the", "message"] } @notify { "other testing": message => ["not", "here"] } Notify <| message == "message" |> MANIFEST end it "allows criteria to be combined with 'and'" do expect_the_message_to_be(["the message"], <<-MANIFEST) @notify { "testing": message => "the message" } @notify { "other": message => "the message" } Notify <| title == "testing" and message == "the message" |> MANIFEST end it "allows criteria to be combined with 'or'" do expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) @notify { "testing": message => "the message" } @notify { "other": message => "other message" } @notify { "yet another": message => "different message" } Notify <| title == "testing" or message == "other message" |> MANIFEST end it "allows criteria to be combined with 'or'" do expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) @notify { "testing": message => "the message" } @notify { "other": message => "other message" } @notify { "yet another": message => "different message" } Notify <| title == "testing" or message == "other message" |> MANIFEST end it "allows criteria to be grouped with parens" do expect_the_message_to_be(["the message", "different message"], <<-MANIFEST) @notify { "testing": message => "different message", withpath => true } @notify { "other": message => "the message" } @notify { "yet another": message => "the message", withpath => true } Notify <| (title == "testing" or message == "the message") and withpath == true |> MANIFEST end it "does not do anything if nothing matches" do expect_the_message_to_be([], <<-MANIFEST) @notify { "testing": message => "different message" } Notify <| title == "does not exist" |> MANIFEST end it "excludes items with inequalities" do expect_the_message_to_be(["good message"], <<-MANIFEST) @notify { "testing": message => "good message" } @notify { "the wrong one": message => "bad message" } Notify <| title != "the wrong one" |> MANIFEST end it "does not exclude resources with unequal arrays" do expect_the_message_to_be(["message", ["not this message", "or this one"]], <<-MANIFEST) @notify { "testing": message => "message" } @notify { "the wrong one": message => ["not this message", "or this one"] } Notify <| message != "not this message" |> MANIFEST end it "does not exclude tags with inequalities" do expect_the_message_to_be(["wanted message", "the way it works"], <<-MANIFEST) @notify { "testing": tag => ["wanted"], message => "wanted message" } @notify { "other": tag => ["why"], message => "the way it works" } Notify <| tag != "why" |> MANIFEST end it "does not collect classes" do node = Puppet::Node.new('the node') expect do catalog = compile_to_catalog(<<-MANIFEST, node) class theclass { @notify { "testing": message => "good message" } } Class <| |> MANIFEST end.to raise_error(/Classes cannot be collected/) end it "does not collect resources that don't exist" do node = Puppet::Node.new('the node') expect do catalog = compile_to_catalog(<<-MANIFEST, node) class theclass { @notify { "testing": message => "good message" } } SomeResource <| |> MANIFEST end.to raise_error(/Resource type someresource doesn't exist/) end context "overrides" do it "modifies an existing array" do expect_the_message_to_be([["original message", "extra message"]], <<-MANIFEST) @notify { "testing": message => ["original message"] } Notify <| |> { message +> "extra message" } MANIFEST end it "converts a scalar to an array" do expect_the_message_to_be([["original message", "extra message"]], <<-MANIFEST) @notify { "testing": message => "original message" } Notify <| |> { message +> "extra message" } MANIFEST end it "collects with override when inside a class (#10963)" do expect_the_message_to_be(["overridden message"], <<-MANIFEST) @notify { "testing": message => "original message" } include collector_test class collector_test { Notify <| |> { message => "overridden message" } } MANIFEST end it "collects with override when inside a define (#10963)" do expect_the_message_to_be(["overridden message"], <<-MANIFEST) @notify { "testing": message => "original message" } collector_test { testing: } define collector_test() { Notify <| |> { message => "overridden message" } } MANIFEST end # Catches regression in implemented behavior, this is not to be taken as this is the wanted behavior # but it has been this way for a long time. it "collects and overrides user defined resources immediately (before queue is evaluated)" do expect_the_message_to_be(["overridden"], <<-MANIFEST) define foo($message) { notify { "testing": message => $message } } foo { test: message => 'given' } Foo <| |> { message => 'overridden' } MANIFEST end # Catches regression in implemented behavior, this is not to be taken as this is the wanted behavior # but it has been this way for a long time. it "collects and overrides user defined resources immediately (virtual resources not queued)" do expect_the_message_to_be(["overridden"], <<-MANIFEST) define foo($message) { @notify { "testing": message => $message } } foo { test: message => 'given' } Notify <| |> # must be collected or the assertion does not find it Foo <| |> { message => 'overridden' } MANIFEST end # Catches regression in implemented behavior, this is not to be taken as this is the wanted behavior # but it has been this way for a long time. # Note difference from none +> case where the override takes effect it "collects and overrides user defined resources with +>" do expect_the_message_to_be([["given", "overridden"]], <<-MANIFEST) define foo($message) { notify { "$name": message => $message } } foo { test: message => ['given'] } Notify <| |> { message +> ['overridden'] } MANIFEST end it "collects and overrides virtual resources multiple times using multiple collects" do expect_the_message_to_be(["overridden2"], <<-MANIFEST) @notify { "testing": message => "original" } Notify <| |> { message => 'overridden1' } Notify <| |> { message => 'overridden2' } MANIFEST end it "collects and overrides non virtual resources multiple times using multiple collects" do expect_the_message_to_be(["overridden2"], <<-MANIFEST) notify { "testing": message => "original" } Notify <| |> { message => 'overridden1' } Notify <| |> { message => 'overridden2' } MANIFEST end end end end diff --git a/spec/unit/parser/ast/arithmetic_operator_spec.rb b/spec/unit/parser/ast/arithmetic_operator_spec.rb deleted file mode 100755 index cdd01e375..000000000 --- a/spec/unit/parser/ast/arithmetic_operator_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ArithmeticOperator do - - ast = Puppet::Parser::AST - - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - @one = stub 'lval', :safeevaluate => 1 - @two = stub 'rval', :safeevaluate => 2 - end - - it "should evaluate both branches" do - lval = stub "lval" - lval.expects(:safeevaluate).with(@scope).returns(1) - rval = stub "rval" - rval.expects(:safeevaluate).with(@scope).returns(2) - - operator = ast::ArithmeticOperator.new :rval => rval, :operator => "+", :lval => lval - operator.evaluate(@scope) - end - - it "should fail for an unknown operator" do - lambda { operator = ast::ArithmeticOperator.new :lval => @one, :operator => "^", :rval => @two }.should raise_error - end - - it "should call Puppet::Parser::Scope.number?" do - Puppet::Parser::Scope.expects(:number?).with(1).returns(1) - Puppet::Parser::Scope.expects(:number?).with(2).returns(2) - - ast::ArithmeticOperator.new(:lval => @one, :operator => "+", :rval => @two).evaluate(@scope) - end - - - %w{ + - * / % << >>}.each do |op| - it "should call ruby Numeric '#{op}'" do - one = stub 'one' - two = stub 'two' - operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two - Puppet::Parser::Scope.stubs(:number?).with(1).returns(one) - Puppet::Parser::Scope.stubs(:number?).with(2).returns(two) - one.expects(:send).with(op,two) - operator.evaluate(@scope) - end - end - - it "should work even with numbers embedded in strings" do - two = stub 'two', :safeevaluate => "2" - one = stub 'one', :safeevaluate => "1" - operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one - operator.evaluate(@scope).should == 3 - end - - it "should work even with floats" do - two = stub 'two', :safeevaluate => 2.53 - one = stub 'one', :safeevaluate => 1.80 - operator = ast::ArithmeticOperator.new :lval => two, :operator => "+", :rval => one - operator.evaluate(@scope).should == 4.33 - end - - context "when applied to array" do - before :each do - Puppet[:parser] = 'future' - end - - it "+ should concatenate an array" do - one = stub 'one', :safeevaluate => [1,2,3] - two = stub 'two', :safeevaluate => [4,5] - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - operator.evaluate(@scope).should == [1,2,3,4,5] - end - - it "<< should append array to an array" do - one = stub 'one', :safeevaluate => [1,2,3] - two = stub 'two', :safeevaluate => [4,5] - operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two - operator.evaluate(@scope).should == [1,2,3, [4,5]] - end - - it "<< should append object to an array" do - one = stub 'one', :safeevaluate => [1,2,3] - two = stub 'two', :safeevaluate => 'a b c' - operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two - operator.evaluate(@scope).should == [1,2,3, 'a b c'] - end - - context "and input is invalid" do - it "should raise error for + if left is not an array" do - one = stub 'one', :safeevaluate => 4 - two = stub 'two', :safeevaluate => [4,5] - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) - end - - it "should raise error for << if left is not an array" do - one = stub 'one', :safeevaluate => 4 - two = stub 'two', :safeevaluate => [4,5] - operator = ast::ArithmeticOperator.new :lval => one, :operator => "<<", :rval => two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) - end - - it "should raise error for + if right is not an array" do - one = stub 'one', :safeevaluate => [1,2] - two = stub 'two', :safeevaluate => 45 - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/right/) - end - - %w{ - * / % >>}.each do |op| - it "should raise error for '#{op}'" do - one = stub 'one', :safeevaluate => [1,2,3] - two = stub 'two', :safeevaluate => [4,5] - operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error - end - end - end - - context "when applied to hash" do - before :each do - Puppet[:parser] = 'future' - end - - it "+ should merge two hashes" do - one = stub 'one', :safeevaluate => {'a' => 1, 'b' => 2} - two = stub 'two', :safeevaluate => {'c' => 3 } - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - operator.evaluate(@scope).should == {'a' => 1, 'b' => 2, 'c' => 3} - end - - context "and input is invalid" do - it "should raise error for + if left is not a hash" do - one = stub 'one', :safeevaluate => 4 - two = stub 'two', :safeevaluate => {'a' => 1} - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error(/left/) - end - - it "should raise error for + if right is not a hash" do - one = stub 'one', :safeevaluate => {'a' => 1} - two = stub 'two', :safeevaluate => 1 - operator = ast::ArithmeticOperator.new :lval => one, :operator => "+", :rval => two - lambda { operator.evaluate(@scope).should == {'a'=>1, 1=>nil} }.should raise_error(/right/) - end - - %w{ - * / % << >>}.each do |op| - it "should raise error for '#{op}'" do - one = stub 'one', :safeevaluate => {'a' => 1, 'b' => 2} - two = stub 'two', :safeevaluate => {'c' => 3 } - operator = ast::ArithmeticOperator.new :lval => @one, :operator => op, :rval => @two - lambda { operator.evaluate(@scope).should == [1,2,3,4,5] }.should raise_error - end - end - end - end - end -end diff --git a/spec/unit/parser/ast/astarray_spec.rb b/spec/unit/parser/ast/astarray_spec.rb index 7c6463844..901c71081 100755 --- a/spec/unit/parser/ast/astarray_spec.rb +++ b/spec/unit/parser/ast/astarray_spec.rb @@ -1,56 +1,56 @@ #! /usr/bin/env ruby require 'spec_helper' -describe Puppet::Parser::AST::ASTArray do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - it "should have a [] accessor" do - array = Puppet::Parser::AST::ASTArray.new :children => [] - array.should respond_to(:[]) - end - - it "should evaluate all its children" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2", :is_a? => true - - item1.expects(:safeevaluate).with(@scope).returns(123) - item2.expects(:safeevaluate).with(@scope).returns(246) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item1,item2] - operator.evaluate(@scope) - end - - it "should not flatten children coming from children ASTArray" do - item = Puppet::Parser::AST::String.new :value => 'foo' - inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] - operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] - operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] - end - - it "should not flatten the results of children evaluation" do - item = Puppet::Parser::AST::String.new :value => 'foo' - item.stubs(:evaluate).returns(['foo']) - operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] - operator.evaluate(@scope).should == [['foo'], ['foo']] - end - - it "should discard nil results from children evaluation" do - item1 = Puppet::Parser::AST::String.new :value => 'foo' - item2 = Puppet::Parser::AST::String.new :value => 'foo' - item2.stubs(:evaluate).returns(nil) - operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] - operator.evaluate(@scope).should == ['foo'] - end - - it "should return a valid string with to_s" do - a = stub 'a', :is_a? => true, :to_s => "a" - b = stub 'b', :is_a? => true, :to_s => "b" - array = Puppet::Parser::AST::ASTArray.new :children => [a,b] - - array.to_s.should == "[a, b]" - end +describe 'Puppet::Parser::AST::ASTArray' do +# before :each do +# node = Puppet::Node.new('localhost') +# compiler = Puppet::Parser::Compiler.new(node) +# @scope = Puppet::Parser::Scope.new(compiler) +# end +# +# it "should have a [] accessor" do +# array = Puppet::Parser::AST::ASTArray.new :children => [] +# array.should respond_to(:[]) +# end +# +# it "should evaluate all its children" do +# item1 = stub "item1", :is_a? => true +# item2 = stub "item2", :is_a? => true +# +# item1.expects(:safeevaluate).with(@scope).returns(123) +# item2.expects(:safeevaluate).with(@scope).returns(246) +# +# operator = Puppet::Parser::AST::ASTArray.new :children => [item1,item2] +# operator.evaluate(@scope) +# end +# +# it "should not flatten children coming from children ASTArray" do +# item = Puppet::Parser::AST::String.new :value => 'foo' +# inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] +# operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] +# operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] +# end +# +# it "should not flatten the results of children evaluation" do +# item = Puppet::Parser::AST::String.new :value => 'foo' +# item.stubs(:evaluate).returns(['foo']) +# operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] +# operator.evaluate(@scope).should == [['foo'], ['foo']] +# end +# +# it "should discard nil results from children evaluation" do +# item1 = Puppet::Parser::AST::String.new :value => 'foo' +# item2 = Puppet::Parser::AST::String.new :value => 'foo' +# item2.stubs(:evaluate).returns(nil) +# operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] +# operator.evaluate(@scope).should == ['foo'] +# end +# +# it "should return a valid string with to_s" do +# a = stub 'a', :is_a? => true, :to_s => "a" +# b = stub 'b', :is_a? => true, :to_s => "b" +# array = Puppet::Parser::AST::ASTArray.new :children => [a,b] +# +# array.to_s.should == "[a, b]" +# end end diff --git a/spec/unit/parser/ast/asthash_spec.rb b/spec/unit/parser/ast/asthash_spec.rb index a4b4f8e29..14fc823a8 100755 --- a/spec/unit/parser/ast/asthash_spec.rb +++ b/spec/unit/parser/ast/asthash_spec.rb @@ -1,98 +1,98 @@ #! /usr/bin/env ruby require 'spec_helper' -describe Puppet::Parser::AST::ASTHash do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - it "should have a merge functionality" do - hash = Puppet::Parser::AST::ASTHash.new(:value => {}) - hash.should respond_to(:merge) - end - - it "should be able to merge 2 AST hashes" do - hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) - - hash.merge(Puppet::Parser::AST::ASTHash.new(:value => {"c" => "d"})) - - hash.value.should == { "a" => "b", "c" => "d" } - end - - it "should be able to merge with a ruby Hash" do - hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) - - hash.merge({"c" => "d"}) - - hash.value.should == { "a" => "b", "c" => "d" } - end - - it "should evaluate each hash value" do - key1 = stub "key1" - value1 = stub "value1" - key2 = stub "key2" - value2 = stub "value2" - - value1.expects(:safeevaluate).with(@scope).returns("b") - value2.expects(:safeevaluate).with(@scope).returns("d") - - operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) - operator.evaluate(@scope) - end - - it "should evaluate the hash keys if they are AST instances" do - key1 = stub "key1" - value1 = stub "value1", :safeevaluate => "one" - key2 = stub "key2" - value2 = stub "value2", :safeevaluate => "two" - - key1.expects(:safeevaluate).with(@scope).returns("1") - key2.expects(:safeevaluate).with(@scope).returns("2") - - operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) - hash = operator.evaluate(@scope) - hash["1"].should == "one" - hash["2"].should == "two" - end - - it "should evaluate the hash keys if they are not AST instances" do - key1 = "1" - value1 = stub "value1", :safeevaluate => "one" - key2 = "2" - value2 = stub "value2", :safeevaluate => "two" - - operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) - hash = operator.evaluate(@scope) - hash["1"].should == "one" - hash["2"].should == "two" - end - - it "should return an evaluated hash" do - key1 = stub "key1" - value1 = stub "value1", :safeevaluate => "b" - key2 = stub "key2" - value2 = stub "value2", :safeevaluate => "d" - - operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) - operator.evaluate(@scope).should == { key1 => "b", key2 => "d" } - end - - describe "when being initialized without arguments" do - it "should evaluate to an empty hash" do - hash = Puppet::Parser::AST::ASTHash.new({}) - hash.evaluate(@scope).should == {} - end - - it "should support merging" do - hash = Puppet::Parser::AST::ASTHash.new({}) - hash.merge({"a" => "b"}).should == {"a" => "b"} - end - end - - it "should return a valid string with to_s" do - hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b", "c" => "d" }) - ["{a => b, c => d}", "{c => d, a => b}"].should be_include hash.to_s - end +describe 'Puppet::Parser::AST::ASTHash' do +# before :each do +# node = Puppet::Node.new('localhost') +# compiler = Puppet::Parser::Compiler.new(node) +# @scope = Puppet::Parser::Scope.new(compiler) +# end +# +# it "should have a merge functionality" do +# hash = Puppet::Parser::AST::ASTHash.new(:value => {}) +# hash.should respond_to(:merge) +# end +# +# it "should be able to merge 2 AST hashes" do +# hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) +# +# hash.merge(Puppet::Parser::AST::ASTHash.new(:value => {"c" => "d"})) +# +# hash.value.should == { "a" => "b", "c" => "d" } +# end +# +# it "should be able to merge with a ruby Hash" do +# hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) +# +# hash.merge({"c" => "d"}) +# +# hash.value.should == { "a" => "b", "c" => "d" } +# end +# +# it "should evaluate each hash value" do +# key1 = stub "key1" +# value1 = stub "value1" +# key2 = stub "key2" +# value2 = stub "value2" +# +# value1.expects(:safeevaluate).with(@scope).returns("b") +# value2.expects(:safeevaluate).with(@scope).returns("d") +# +# operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) +# operator.evaluate(@scope) +# end +# +# it "should evaluate the hash keys if they are AST instances" do +# key1 = stub "key1" +# value1 = stub "value1", :safeevaluate => "one" +# key2 = stub "key2" +# value2 = stub "value2", :safeevaluate => "two" +# +# key1.expects(:safeevaluate).with(@scope).returns("1") +# key2.expects(:safeevaluate).with(@scope).returns("2") +# +# operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) +# hash = operator.evaluate(@scope) +# hash["1"].should == "one" +# hash["2"].should == "two" +# end +# +# it "should evaluate the hash keys if they are not AST instances" do +# key1 = "1" +# value1 = stub "value1", :safeevaluate => "one" +# key2 = "2" +# value2 = stub "value2", :safeevaluate => "two" +# +# operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) +# hash = operator.evaluate(@scope) +# hash["1"].should == "one" +# hash["2"].should == "two" +# end +# +# it "should return an evaluated hash" do +# key1 = stub "key1" +# value1 = stub "value1", :safeevaluate => "b" +# key2 = stub "key2" +# value2 = stub "value2", :safeevaluate => "d" +# +# operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) +# operator.evaluate(@scope).should == { key1 => "b", key2 => "d" } +# end +# +# describe "when being initialized without arguments" do +# it "should evaluate to an empty hash" do +# hash = Puppet::Parser::AST::ASTHash.new({}) +# hash.evaluate(@scope).should == {} +# end +# +# it "should support merging" do +# hash = Puppet::Parser::AST::ASTHash.new({}) +# hash.merge({"a" => "b"}).should == {"a" => "b"} +# end +# end +# +# it "should return a valid string with to_s" do +# hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b", "c" => "d" }) +# ["{a => b, c => d}", "{c => d, a => b}"].should be_include hash.to_s +# end end diff --git a/spec/unit/parser/ast/block_expression_spec.rb b/spec/unit/parser/ast/block_expression_spec.rb index daf3e9dbe..8440fb669 100644 --- a/spec/unit/parser/ast/block_expression_spec.rb +++ b/spec/unit/parser/ast/block_expression_spec.rb @@ -1,67 +1,68 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'puppet/parser/ast/block_expression' -describe Puppet::Parser::AST::BlockExpression do +describe 'Puppet::Parser::AST::BlockExpression' do class StackDepthAST < Puppet::Parser::AST attr_reader :call_depth def evaluate(*options) @call_depth = caller.length end end NO_SCOPE = nil def depth_probe StackDepthAST.new({}) end def sequence_probe(name, sequence) probe = mock("Sequence Probe #{name}") probe.expects(:safeevaluate).in_sequence(sequence) probe end def block_of(children) Puppet::Parser::AST::BlockExpression.new(:children => children) end def assert_all_at_same_depth(*probes) depth0 = probes[0].call_depth probes.drop(1).each do |p| p.call_depth.should == depth0 end end it "evaluates all its children at the same stack depth" do depth_probes = [depth_probe, depth_probe] expr = block_of(depth_probes) expr.evaluate(NO_SCOPE) assert_all_at_same_depth(*depth_probes) end it "evaluates sequenced children at the same stack depth" do depth1 = depth_probe depth2 = depth_probe depth3 = depth_probe expr1 = block_of([depth1]) expr2 = block_of([depth2]) expr3 = block_of([depth3]) expr1.sequence_with(expr2).sequence_with(expr3).evaluate(NO_SCOPE) assert_all_at_same_depth(depth1, depth2, depth3) end it "evaluates sequenced children in order" do evaluation_order = sequence("Child evaluation order") expr1 = block_of([sequence_probe("Step 1", evaluation_order)]) expr2 = block_of([sequence_probe("Step 2", evaluation_order)]) expr3 = block_of([sequence_probe("Step 3", evaluation_order)]) expr1.sequence_with(expr2).sequence_with(expr3).evaluate(NO_SCOPE) end end diff --git a/spec/unit/parser/ast/boolean_operator_spec.rb b/spec/unit/parser/ast/boolean_operator_spec.rb deleted file mode 100755 index 4d25245b4..000000000 --- a/spec/unit/parser/ast/boolean_operator_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::BooleanOperator do - - ast = Puppet::Parser::AST - - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - @true_ast = ast::Boolean.new( :value => true) - @false_ast = ast::Boolean.new( :value => false) - end - - it "should evaluate left operand inconditionally" do - lval = stub "lval" - lval.expects(:safeevaluate).with(@scope).returns("true") - rval = stub "rval", :safeevaluate => false - rval.expects(:safeevaluate).never - - operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval - operator.evaluate(@scope) - end - - it "should evaluate right 'and' operand only if left operand is true" do - lval = stub "lval", :safeevaluate => true - rval = stub "rval", :safeevaluate => false - rval.expects(:safeevaluate).with(@scope).returns(false) - operator = ast::BooleanOperator.new :rval => rval, :operator => "and", :lval => lval - operator.evaluate(@scope) - end - - it "should evaluate right 'or' operand only if left operand is false" do - lval = stub "lval", :safeevaluate => false - rval = stub "rval", :safeevaluate => false - rval.expects(:safeevaluate).with(@scope).returns(false) - operator = ast::BooleanOperator.new :rval => rval, :operator => "or", :lval => lval - operator.evaluate(@scope) - end - - it "should return true for false OR true" do - ast::BooleanOperator.new(:rval => @true_ast, :operator => "or", :lval => @false_ast).evaluate(@scope).should be_true - end - - it "should return false for true AND false" do - ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @false_ast ).evaluate(@scope).should be_false - end - - it "should return true for true AND true" do - ast::BooleanOperator.new(:rval => @true_ast, :operator => "and", :lval => @true_ast ).evaluate(@scope).should be_true - end - -end diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb deleted file mode 100755 index d20872e06..000000000 --- a/spec/unit/parser/ast/casestatement_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::CaseStatement do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - describe "when evaluating" do - - before :each do - @test = stub 'test' - @test.stubs(:safeevaluate).with(@scope).returns("value") - - @option1 = Puppet::Parser::AST::CaseOpt.new({}) - @option1.stubs(:eachopt) - @option1.stubs(:default?).returns false - @option2 = Puppet::Parser::AST::CaseOpt.new({}) - @option2.stubs(:eachopt) - @option2.stubs(:default?).returns false - - @options = Puppet::Parser::AST::ASTArray.new(:children => [@option1, @option2]) - - @casestmt = Puppet::Parser::AST::CaseStatement.new :test => @test, :options => @options - end - - it "should evaluate test" do - @test.expects(:safeevaluate).with(@scope) - - @casestmt.evaluate(@scope) - end - - it "should scan each option" do - @casestmt.evaluate(@scope) - end - - describe "when scanning options" do - before :each do - @opval1 = stub_everything 'opval1' - @option1.stubs(:eachopt).yields(@opval1) - - @opval2 = stub_everything 'opval2' - @option2.stubs(:eachopt).yields(@opval2) - end - - it "should evaluate each sub-option" do - @option1.expects(:eachopt) - @option2.expects(:eachopt) - - @casestmt.evaluate(@scope) - end - - it "should evaluate first matching option" do - @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) - @option2.expects(:safeevaluate).with(@scope) - - @casestmt.evaluate(@scope) - end - - it "should return the first matching evaluated option" do - @opval2.stubs(:evaluate_match).with { |*arg| arg[0] == "value" }.returns(true) - @option2.stubs(:safeevaluate).with(@scope).returns(:result) - - @casestmt.evaluate(@scope).should == :result - end - - it "should evaluate the default option if none matched" do - @option1.stubs(:default?).returns(true) - @option1.expects(:safeevaluate).with(@scope) - - @casestmt.evaluate(@scope) - end - - it "should return the default evaluated option if none matched" do - @option1.stubs(:default?).returns(true) - @option1.stubs(:safeevaluate).with(@scope).returns(:result) - - @casestmt.evaluate(@scope).should == :result - end - - it "should return nil if nothing matched" do - @casestmt.evaluate(@scope).should be_nil - end - - it "should match and set scope ephemeral variables" do - @opval1.expects(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope } - - @casestmt.evaluate(@scope) - end - - it "should evaluate this regex option if it matches" do - @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) - - @option1.expects(:safeevaluate).with(@scope) - - @casestmt.evaluate(@scope) - end - - it "should return this evaluated regex option if it matches" do - @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) - @option1.stubs(:safeevaluate).with(@scope).returns(:result) - - @casestmt.evaluate(@scope).should == :result - end - - it "should unset scope ephemeral variables after option evaluation" do - @scope.stubs(:ephemeral_level).returns(:level) - @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) - @option1.stubs(:safeevaluate).with(@scope).returns(:result) - - @scope.expects(:unset_ephemeral_var).with(:level) - - @casestmt.evaluate(@scope) - end - - it "should not leak ephemeral variables even if evaluation fails" do - @scope.stubs(:ephemeral_level).returns(:level) - @opval1.stubs(:evaluate_match).with { |*arg| arg[0] == "value" and arg[1] == @scope }.returns(true) - @option1.stubs(:safeevaluate).with(@scope).raises - - @scope.expects(:unset_ephemeral_var).with(:level) - - lambda { @casestmt.evaluate(@scope) }.should raise_error - end - end - - end - - it "should match if any of the provided options evaluate as true" do - ast = nil - AST = Puppet::Parser::AST - - tests = { - "one" => %w{a b c}, - "two" => %w{e f g} - } - options = tests.collect do |result, values| - values = values.collect { |v| AST::Leaf.new :value => v } - - AST::CaseOpt.new( - :value => AST::ASTArray.new(:children => values), - :statements => AST::Leaf.new(:value => result) - ) - end - options << AST::CaseOpt.new( - :value => AST::Default.new(:value => "default"), - :statements => AST::Leaf.new(:value => "default") - ) - - ast = nil - param = AST::Variable.new(:value => "testparam") - ast = AST::CaseStatement.new(:test => param, :options => options) - - tests.each do |should, values| - values.each do |value| - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - scope = Puppet::Parser::Scope.new(compiler) - scope['testparam'] = value - result = ast.evaluate(scope) - - result.should == should - end - end - end -end diff --git a/spec/unit/parser/ast/collection_spec.rb b/spec/unit/parser/ast/collection_spec.rb deleted file mode 100755 index 3e1dbfaa5..000000000 --- a/spec/unit/parser/ast/collection_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Collection do - before :each do - @mytype = Puppet::Resource::Type.new(:definition, "mytype") - @environment = Puppet::Node::Environment.create(:testing, []) - @environment.known_resource_types.add @mytype - - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode", :environment => @environment)) - @scope = Puppet::Parser::Scope.new(@compiler) - - @overrides = stub_everything 'overrides' - @overrides.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - end - - it "should evaluate its query" do - query = mock 'query' - collection = Puppet::Parser::AST::Collection.new :query => query, :form => :virtual - collection.type = 'mytype' - - query.expects(:safeevaluate).with(@scope) - - collection.evaluate(@scope) - end - - it "should instantiate a Collector for this type" do - collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test" - @test_type = Puppet::Resource::Type.new(:definition, "test") - @environment.known_resource_types.add @test_type - - Puppet::Parser::Collector.expects(:new).with(@scope, "test", nil, nil, :virtual) - - collection.evaluate(@scope) - end - - it "should tell the compiler about this collector" do - collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype" - Puppet::Parser::Collector.stubs(:new).returns("whatever") - - @compiler.expects(:add_collection).with("whatever") - - collection.evaluate(@scope) - end - - it "should evaluate overriden parameters" do - collector = stub_everything 'collector' - collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype", :override => @overrides - Puppet::Parser::Collector.stubs(:new).returns(collector) - - @overrides.expects(:safeevaluate).with(@scope) - - collection.evaluate(@scope) - end - - it "should tell the collector about overrides" do - collector = mock 'collector' - collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "mytype", :override => @overrides - Puppet::Parser::Collector.stubs(:new).returns(collector) - - collector.expects(:add_override) - - collection.evaluate(@scope) - end - - it "should fail when evaluating undefined resource types" do - collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "bogus" - lambda { collection.evaluate(@scope) }.should raise_error "Resource type bogus doesn't exist" - end -end diff --git a/spec/unit/parser/ast/collexpr_spec.rb b/spec/unit/parser/ast/collexpr_spec.rb deleted file mode 100755 index 479d5de3b..000000000 --- a/spec/unit/parser/ast/collexpr_spec.rb +++ /dev/null @@ -1,120 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::CollExpr do - - ast = Puppet::Parser::AST - - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - describe "when evaluating with two operands" do - before :each do - @test1 = mock 'test1' - @test1.expects(:safeevaluate).with(@scope).returns("test1") - @test2 = mock 'test2' - @test2.expects(:safeevaluate).with(@scope).returns("test2") - end - - it "should evaluate both" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") - collexpr.evaluate(@scope) - end - - it "should produce a data and code representation of the expression" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") - result = collexpr.evaluate(@scope) - result[0].should == ["test1", "==", "test2"] - result[1].should be_an_instance_of(Proc) - end - - it "should propagate expression type and form to child if expression themselves" do - [@test1, @test2].each do |t| - t.expects(:is_a?).returns(true) - t.expects(:form).returns(false) - t.expects(:type).returns(false) - t.expects(:type=) - t.expects(:form=) - end - - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper=>"==", :form => true, :type => true) - result = collexpr.evaluate(@scope) - end - - describe "and when evaluating the produced code" do - before :each do - @resource = mock 'resource' - @resource.expects(:[]).with("test1").at_least(1).returns("test2") - end - - it "should evaluate like the original expression for ==" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "==") - collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] == "test2") - end - - it "should evaluate like the original expression for !=" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, :oper => "!=") - collexpr.evaluate(@scope)[1].call(@resource).should === (@resource["test1"] != "test2") - end - end - - it "should work if this is an exported collection containing parenthesis" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, - :oper => "==", :parens => true, :form => :exported) - match, code = collexpr.evaluate(@scope) - match.should == ["test1", "==", "test2"] - @logs.should be_empty # no warnings emitted - end - - %w{and or}.each do |op| - it "should parse / eval if this is an exported collection with #{op} operator" do - collexpr = ast::CollExpr.new(:test1 => @test1, :test2 => @test2, - :oper => op, :form => :exported) - match, code = collexpr.evaluate(@scope) - match.should == ["test1", op, "test2"] - end - end - end - - describe "when evaluating with tags" do - before :each do - @tag = stub 'tag', :safeevaluate => 'tag' - @value = stub 'value', :safeevaluate => 'value' - - @resource = stub 'resource' - @resource.stubs(:tagged?).with("value").returns(true) - end - - it "should produce a data representation of the expression" do - collexpr = ast::CollExpr.new(:test1 => @tag, :test2 => @value, :oper=>"==") - result = collexpr.evaluate(@scope) - result[0].should == ["tag", "==", "value"] - end - - it "should inspect resource tags if the query term is on tags" do - collexpr = ast::CollExpr.new(:test1 => @tag, :test2 => @value, :oper => "==") - collexpr.evaluate(@scope)[1].call(@resource).should be_true - end - end - - [:exported,:virtual].each do |mode| - it "should check for array member equality if resource parameter is an array for == in mode #{mode}" do - array = mock 'array', :safeevaluate => "array" - test1 = mock 'test1' - test1.expects(:safeevaluate).with(@scope).returns("test1") - - resource = mock 'resource' - resource.expects(:[]).with("array").at_least(1).returns(["test1","test2","test3"]) - collexpr = ast::CollExpr.new(:test1 => array, :test2 => test1, :oper => "==", :form => mode) - collexpr.evaluate(@scope)[1].call(resource).should be_true - end - end - - it "should raise an error for invalid operator" do - lambda { collexpr = ast::CollExpr.new(:oper=>">") }.should raise_error - end - -end diff --git a/spec/unit/parser/ast/comparison_operator_spec.rb b/spec/unit/parser/ast/comparison_operator_spec.rb deleted file mode 100755 index 7c7dfa0a0..000000000 --- a/spec/unit/parser/ast/comparison_operator_spec.rb +++ /dev/null @@ -1,118 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ComparisonOperator do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - - @one = Puppet::Parser::AST::Leaf.new(:value => "1") - @two = Puppet::Parser::AST::Leaf.new(:value => "2") - - @lval = Puppet::Parser::AST::Leaf.new(:value => "one") - @rval = Puppet::Parser::AST::Leaf.new(:value => "two") - end - - it "should evaluate both values" do - @lval.expects(:safeevaluate).with(@scope) - @rval.expects(:safeevaluate).with(@scope) - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval - operator.evaluate(@scope) - end - - it "should convert the arguments to numbers if they are numbers in string" do - Puppet::Parser::Scope.expects(:number?).with("1").returns(1) - Puppet::Parser::Scope.expects(:number?).with("2").returns(2) - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "==", :rval => @two - operator.evaluate(@scope) - end - - %w{< > <= >=}.each do |oper| - it "should use string comparison #{oper} if operands are strings" do - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => oper, :rval => @rval - operator.evaluate(@scope).should == "one".send(oper,"two") - end - end - - describe "with string comparison" do - it "should use matching" do - @rval.expects(:evaluate_match).with("one", @scope) - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval - operator.evaluate(@scope) - end - - it "should return true for :undef to '' equality" do - astundef = Puppet::Parser::AST::Leaf.new(:value => :undef) - empty = Puppet::Parser::AST::Leaf.new(:value => '') - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => astundef, :operator => "==", :rval => empty - operator.evaluate(@scope).should be_true - end - - [true, false].each do |result| - it "should return #{(result).inspect} with '==' when matching return #{result.inspect}" do - @rval.expects(:evaluate_match).with("one", @scope).returns result - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "==", :rval => @rval - operator.evaluate(@scope).should == result - end - - it "should return #{(!result).inspect} with '!=' when matching return #{result.inspect}" do - @rval.expects(:evaluate_match).with("one", @scope).returns result - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @lval, :operator => "!=", :rval => @rval - operator.evaluate(@scope).should == !result - end - end - end - - it "should fail with arguments of different types" do - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => ">", :rval => @rval - lambda { operator.evaluate(@scope) }.should raise_error(ArgumentError) - end - - it "should fail for an unknown operator" do - lambda { operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => "or", :rval => @two }.should raise_error - end - - %w{< > <= >= ==}.each do |oper| - it "should return the result of using '#{oper}' to compare the left and right sides" do - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => oper, :rval => @two - - operator.evaluate(@scope).should == 1.send(oper,2) - end - end - - it "should return the result of using '!=' to compare the left and right sides" do - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => @one, :operator => '!=', :rval => @two - - operator.evaluate(@scope).should == true - end - - it "should work for variables too" do - one = Puppet::Parser::AST::Variable.new( :value => "one" ) - two = Puppet::Parser::AST::Variable.new( :value => "two" ) - - one.expects(:safeevaluate).with(@scope).returns(1) - two.expects(:safeevaluate).with(@scope).returns(2) - - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => one, :operator => "<", :rval => two - operator.evaluate(@scope).should == true - end - - # see ticket #1759 - %w{< > <= >=}.each do |oper| - it "should return the correct result of using '#{oper}' to compare 10 and 9" do - ten = Puppet::Parser::AST::Leaf.new(:value => "10") - nine = Puppet::Parser::AST::Leaf.new(:value => "9") - operator = Puppet::Parser::AST::ComparisonOperator.new :lval => ten, :operator => oper, :rval => nine - - operator.evaluate(@scope).should == 10.send(oper,9) - end - end - -end diff --git a/spec/unit/parser/ast/definition_spec.rb b/spec/unit/parser/ast/definition_spec.rb deleted file mode 100755 index afc8e0e54..000000000 --- a/spec/unit/parser/ast/definition_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Definition do - it "should make its context available through an accessor" do - definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) - definition.context.should == {:line => 5} - end - - describe "when instantiated" do - it "should create a definition with the proper type, name, context, and module name" do - definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) - instantiated_definitions = definition.instantiate('modname') - instantiated_definitions.length.should == 1 - instantiated_definitions[0].type.should == :definition - instantiated_definitions[0].name.should == 'foo' - instantiated_definitions[0].line.should == 5 - instantiated_definitions[0].module_name.should == 'modname' - end - end -end diff --git a/spec/unit/parser/ast/function_spec.rb b/spec/unit/parser/ast/function_spec.rb deleted file mode 100755 index 6115ad1d2..000000000 --- a/spec/unit/parser/ast/function_spec.rb +++ /dev/null @@ -1,92 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Function do - before :each do - @scope = mock 'scope' - end - - describe "when initializing" do - it "should not fail if the function doesn't exist" do - Puppet::Parser::Functions.stubs(:function).returns(false) - - expect{ Puppet::Parser::AST::Function.new :name => "dontexist" }.to_not raise_error - - end - end - - it "should return its representation with to_s" do - args = stub 'args', :is_a? => true, :to_s => "[a, b]" - - Puppet::Parser::AST::Function.new(:name => "func", :arguments => args).to_s.should == "func(a, b)" - end - - describe "when evaluating" do - - it "should fail if the function doesn't exist" do - Puppet::Parser::Functions.stubs(:function).returns(false) - func = Puppet::Parser::AST::Function.new :name => "dontexist" - - expect{ func.evaluate(@scope) }.to raise_error(Puppet::ParseError) - end - - it "should fail if the function is a statement used as rvalue" do - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(false) - - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :rvalue - - expect{ func.evaluate(@scope) }.to raise_error(Puppet::ParseError, "Function 'exist' does not return a value") - end - - it "should fail if the function is an rvalue used as statement" do - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - Puppet::Parser::Functions.stubs(:rvalue?).with("exist").returns(true) - - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement - - expect{ func.evaluate(@scope) }.to raise_error(Puppet::ParseError,"Function 'exist' must be the value of a statement") - end - - it "should evaluate its arguments" do - argument = stub 'arg' - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - @scope.stubs(:function_exist) - - argument.expects(:safeevaluate).with(@scope).returns(["argument"]) - - func.evaluate(@scope) - end - - it "should call the underlying ruby function" do - argument = stub 'arg', :safeevaluate => ["nothing"] - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - - @scope.expects(:function_exist).with(["nothing"]) - - func.evaluate(@scope) - end - - it "should convert :undef to '' in arguments" do - argument = stub 'arg', :safeevaluate => ["foo", :undef, "bar"] - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - - @scope.expects(:function_exist).with(["foo", "", "bar"]) - - func.evaluate(@scope) - end - - it "should return the ruby function return for rvalue functions" do - argument = stub 'arg', :safeevaluate => ["nothing"] - Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) - func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - @scope.stubs(:function_exist).with(["nothing"]).returns("returning") - - func.evaluate(@scope).should == "returning" - end - - end -end diff --git a/spec/unit/parser/ast/hostclass_spec.rb b/spec/unit/parser/ast/hostclass_spec.rb deleted file mode 100755 index ae9d9a996..000000000 --- a/spec/unit/parser/ast/hostclass_spec.rb +++ /dev/null @@ -1,72 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Hostclass do - def ast - Puppet::Parser::AST - end - - def newarray(*elems) - ast::ASTArray.new({}).push(*elems) - end - - it "should make its name and context available through accessors" do - hostclass = ast::Hostclass.new('foo', :line => 5) - hostclass.name.should == 'foo' - hostclass.context.should == {:line => 5} - end - - it "should make its code available through an accessor" do - code = newarray - hostclass = ast::Hostclass.new('foo', :code => code) - hostclass.code.should be_equal(code) - end - - describe "when instantiated" do - it "should create a class with the proper type, code, name, context, and module name" do - code = newarray - hostclass = ast::Hostclass.new('foo', :code => code, :line => 5) - instantiated_class = hostclass.instantiate('modname')[0] - instantiated_class.type.should == :hostclass - instantiated_class.name.should == 'foo' - instantiated_class.code.should be_equal(code) - instantiated_class.line.should == 5 - instantiated_class.module_name.should == 'modname' - end - - it "should instantiate all nested classes, defines, and nodes with the same module name." do - nested_objects = newarray(ast::Hostclass.new('foo::child1'), - ast::Definition.new('foo::child2'), - ast::Definition.new('child3')) - hostclass = ast::Hostclass.new('foo', :code => nested_objects) - instantiated_classes = hostclass.instantiate('modname') - instantiated_classes.length.should == 4 - instantiated_classes[0].name.should == 'foo' - instantiated_classes[1].name.should == 'foo::child1' - instantiated_classes[2].name.should == 'foo::child2' - instantiated_classes[3].name.should == 'child3' - instantiated_classes.each { |cls| cls.module_name.should == 'modname' } - end - - it "should handle a nested class that contains its own nested classes." do - foo_bar_baz = ast::Hostclass.new('foo::bar::baz') - foo_bar = ast::Hostclass.new('foo::bar', :code => newarray(foo_bar_baz)) - foo = ast::Hostclass.new('foo', :code => newarray(foo_bar)) - instantiated_classes = foo.instantiate('') - instantiated_classes.length.should == 3 - instantiated_classes[0].name.should == 'foo' - instantiated_classes[1].name.should == 'foo::bar' - instantiated_classes[2].name.should == 'foo::bar::baz' - end - - it "should skip nested elements that are not classes, definitions, or nodes." do - func = ast::Function.new(:name => 'biz', :arguments => newarray(ast::Name.new(:value => 'baz'))) - foo = ast::Hostclass.new('foo', :code => newarray(func)) - instantiated_classes = foo.instantiate('') - instantiated_classes.length.should == 1 - instantiated_classes[0].should be_a(Puppet::Resource::Type) - instantiated_classes[0].name.should == 'foo' - end - end -end - diff --git a/spec/unit/parser/ast/ifstatement_spec.rb b/spec/unit/parser/ast/ifstatement_spec.rb deleted file mode 100755 index d17403bf4..000000000 --- a/spec/unit/parser/ast/ifstatement_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::IfStatement do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - describe "when evaluating" do - - before :each do - @test = stub 'test' - @test.stubs(:safeevaluate).with(@scope) - - @stmt = stub 'stmt' - @stmt.stubs(:safeevaluate).with(@scope) - - @else = stub 'else' - @else.stubs(:safeevaluate).with(@scope) - - @ifstmt = Puppet::Parser::AST::IfStatement.new :test => @test, :statements => @stmt - @ifelsestmt = Puppet::Parser::AST::IfStatement.new :test => @test, :statements => @stmt, :else => @else - end - - it "should evaluate test" do - Puppet::Parser::Scope.stubs(:true?).returns(false) - - @test.expects(:safeevaluate).with(@scope) - - @ifstmt.evaluate(@scope) - end - - it "should evaluate if statements if test is true" do - Puppet::Parser::Scope.stubs(:true?).returns(true) - - @stmt.expects(:safeevaluate).with(@scope) - - @ifstmt.evaluate(@scope) - end - - it "should not evaluate if statements if test is false" do - Puppet::Parser::Scope.stubs(:true?).returns(false) - - @stmt.expects(:safeevaluate).with(@scope).never - - @ifstmt.evaluate(@scope) - end - - it "should evaluate the else branch if test is false" do - Puppet::Parser::Scope.stubs(:true?).returns(false) - - @else.expects(:safeevaluate).with(@scope) - - @ifelsestmt.evaluate(@scope) - end - - it "should not evaluate the else branch if test is true" do - Puppet::Parser::Scope.stubs(:true?).returns(true) - - @else.expects(:safeevaluate).with(@scope).never - - @ifelsestmt.evaluate(@scope) - end - - it "should reset ephemeral statements after evaluation" do - @scope.expects(:ephemeral_level).returns(:level) - Puppet::Parser::Scope.stubs(:true?).returns(true) - - @stmt.expects(:safeevaluate).with(@scope) - @scope.expects(:unset_ephemeral_var).with(:level) - - @ifstmt.evaluate(@scope) - end - end -end diff --git a/spec/unit/parser/ast/in_operator_spec.rb b/spec/unit/parser/ast/in_operator_spec.rb deleted file mode 100755 index c79c55101..000000000 --- a/spec/unit/parser/ast/in_operator_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -require 'puppet/parser/ast/in_operator' - -describe Puppet::Parser::AST::InOperator do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - - @lval = stub 'lval' - @lval.stubs(:safeevaluate).with(@scope).returns("left") - - @rval = stub 'rval' - @rval.stubs(:safeevaluate).with(@scope).returns("right") - - @operator = Puppet::Parser::AST::InOperator.new :lval => @lval, :rval => @rval - end - - it "should evaluate the left operand" do - @lval.expects(:safeevaluate).with(@scope).returns("string") - - @operator.evaluate(@scope) - end - - it "should evaluate the right operand" do - @rval.expects(:safeevaluate).with(@scope).returns("string") - - @operator.evaluate(@scope) - end - - it "should raise an argument error if lval is not a string" do - @lval.expects(:safeevaluate).with(@scope).returns([12,13]) - - lambda { @operator.evaluate(@scope) }.should raise_error - end - - it "should raise an argument error if rval doesn't support the include? method" do - @rval.expects(:safeevaluate).with(@scope).returns(stub('value')) - - lambda { @operator.evaluate(@scope) }.should raise_error - end - - it "should not raise an argument error if rval supports the include? method" do - @rval.expects(:safeevaluate).with(@scope).returns(stub('value', :include? => true)) - - lambda { @operator.evaluate(@scope) }.should_not raise_error - end - - it "should return rval.include?(lval)" do - lval = stub 'lvalue', :is_a? => true - @lval.stubs(:safeevaluate).with(@scope).returns(lval) - - rval = stub 'rvalue' - @rval.stubs(:safeevaluate).with(@scope).returns(rval) - rval.expects(:include?).with(lval).returns(:result) - - @operator.evaluate(@scope).should == :result - end -end diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb index f2466b5da..5630b3877 100755 --- a/spec/unit/parser/ast/leaf_spec.rb +++ b/spec/unit/parser/ast/leaf_spec.rb @@ -1,511 +1,191 @@ #! /usr/bin/env ruby require 'spec_helper' describe Puppet::Parser::AST::Leaf do before :each do node = Puppet::Node.new('localhost') compiler = Puppet::Parser::Compiler.new(node) @scope = Puppet::Parser::Scope.new(compiler) @value = stub 'value' @leaf = Puppet::Parser::AST::Leaf.new(:value => @value) end it "should have an evaluate_match method" do Puppet::Parser::AST::Leaf.new(:value => "value").should respond_to(:evaluate_match) end describe "when converting to string" do it "should transform its value to string" do value = stub 'value', :is_a? => true value.expects(:to_s) Puppet::Parser::AST::Leaf.new( :value => value ).to_s end end it "should have a match method" do @leaf.should respond_to(:match) end it "should delegate match to ==" do @value.expects(:==).with("value") @leaf.match("value") end end -describe Puppet::Parser::AST::FlatString do - describe "when converting to string" do - it "should transform its value to a quoted string" do - Puppet::Parser::AST::FlatString.new(:value => 'ab').to_s.should == "\"ab\"" - end - - it "should escape embedded double-quotes" do - value = Puppet::Parser::AST::FlatString.new(:value => 'hello "friend"') - value.to_s.should == "\"hello \\\"friend\\\"\"" - end - end -end - -describe Puppet::Parser::AST::String do - describe "when converting to string" do - it "should transform its value to a quoted string" do - Puppet::Parser::AST::String.new(:value => 'ab').to_s.should == "\"ab\"" - end - - it "should escape embedded double-quotes" do - value = Puppet::Parser::AST::String.new(:value => 'hello "friend"') - value.to_s.should == "\"hello \\\"friend\\\"\"" - end - - it "should return a dup of its value" do - value = "" - Puppet::Parser::AST::String.new( :value => value ).evaluate(stub('scope')).should_not be_equal(value) - end - end -end - -describe Puppet::Parser::AST::Concat do - describe "when evaluating" do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - it "should interpolate variables and concatenate their values" do - one = Puppet::Parser::AST::String.new(:value => "one") - one.stubs(:evaluate).returns("one ") - two = Puppet::Parser::AST::String.new(:value => "two") - two.stubs(:evaluate).returns(" two ") - three = Puppet::Parser::AST::String.new(:value => "three") - three.stubs(:evaluate).returns(" three") - var = Puppet::Parser::AST::Variable.new(:value => "myvar") - var.stubs(:evaluate).returns("foo") - array = Puppet::Parser::AST::Variable.new(:value => "array") - array.stubs(:evaluate).returns(["bar","baz"]) - concat = Puppet::Parser::AST::Concat.new(:value => [one,var,two,array,three]) - - concat.evaluate(@scope).should == 'one foo two barbaz three' - end - - it "should transform undef variables to empty string" do - var = Puppet::Parser::AST::Variable.new(:value => "myvar") - var.stubs(:evaluate).returns(:undef) - concat = Puppet::Parser::AST::Concat.new(:value => [var]) - - concat.evaluate(@scope).should == '' - end - end -end - -describe Puppet::Parser::AST::Undef do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - @undef = Puppet::Parser::AST::Undef.new(:value => :undef) - end - - it "should match undef with undef" do - @undef.evaluate_match(:undef, @scope).should be_true - end - - it "should not match undef with an empty string" do - @undef.evaluate_match("", @scope).should be_true - end -end - -describe Puppet::Parser::AST::HashOrArrayAccess do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - describe "when evaluating" do - it "should evaluate the variable part if necessary" do - @scope["a"] = ["b"] - - variable = stub 'variable', :evaluate => "a" - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 ) - - variable.expects(:safeevaluate).with(@scope).returns("a") - - access.evaluate(@scope).should == "b" - end - - it "should evaluate the access key part if necessary" do - @scope["a"] = ["b"] - - index = stub 'index', :evaluate => 0 - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index ) - - index.expects(:safeevaluate).with(@scope).returns(0) - - access.evaluate(@scope).should == "b" - end - - it "should be able to return an array member" do - @scope["a"] = %w{val1 val2 val3} - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) - - access.evaluate(@scope).should == "val2" - end - - it "should be able to return an array member when index is a stringified number" do - @scope["a"] = %w{val1 val2 val3} - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" ) - - access.evaluate(@scope).should == "val2" - end - - it "should raise an error when accessing an array with a key" do - @scope["a"] = ["val1", "val2", "val3"] - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) - - lambda { access.evaluate(@scope) }.should raise_error - end - - it "should be able to return :undef for an unknown array index" do - @scope["a"] = ["val1", "val2", "val3"] - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 6 ) - - access.evaluate(@scope).should == :undef - end - - it "should be able to return a hash value" do - @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" } - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) - - access.evaluate(@scope).should == "val2" - end - - it "should be able to return :undef for unknown hash keys" do - @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" } - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key12" ) - - access.evaluate(@scope).should == :undef - end - - it "should be able to return a hash value with a numerical key" do - @scope["a"] = { "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" } - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" ) - - access.evaluate(@scope).should == "45" - end - - it "should raise an error if the variable lookup didn't return a hash or an array" do - @scope["a"] = "I'm a string" - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) - - lambda { access.evaluate(@scope) }.should raise_error - end - - it "should raise an error if the variable wasn't in the scope" do - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) - - lambda { access.evaluate(@scope) }.should raise_error - end - - it "should return a correct string representation" do - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) - access.to_s.should == '$a[key2]' - end - - it "should work with recursive hash access" do - @scope["a"] = { "key" => { "subkey" => "b" }} - - access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") - access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") - - access2.evaluate(@scope).should == 'b' - end - - it "should work with interleaved array and hash access" do - @scope['a'] = { "key" => [ "a" , "b" ]} - - access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") - access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1) - - access2.evaluate(@scope).should == 'b' - end - - it "should raise a useful error for hash access on undef" do - @scope["a"] = :undef - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") - - expect { - access.evaluate(@scope) - }.to raise_error(Puppet::ParseError, /not a hash or array/) - end - - it "should raise a useful error for hash access on TrueClass" do - @scope["a"] = true - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") - - expect { - access.evaluate(@scope) - }.to raise_error(Puppet::ParseError, /not a hash or array/) - end - - it "should raise a useful error for recursive undef hash access" do - @scope["a"] = { "key" => "val" } - - access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "nonexistent") - access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") - - expect { - access2.evaluate(@scope) - }.to raise_error(Puppet::ParseError, /not a hash or array/) - end - - it "should produce boolean values when value is a boolean" do - @scope["a"] = [true, false] - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 0 ) - expect(access.evaluate(@scope)).to be == true - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) - expect(access.evaluate(@scope)).to be == false - end - end - - describe "when assigning" do - it "should add a new key and value" do - Puppet.expects(:warning).once - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - scope = Puppet::Parser::Scope.new(compiler) - - scope['a'] = { 'a' => 'b' } - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "b") - access.assign(scope, "c" ) - - scope['a'].should be_include("b") - end - - it "should raise an error when assigning an array element with a key" do - @scope['a'] = [] - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) - - lambda { access.assign(@scope, "test") }.should raise_error - end - - it "should be able to return an array member when index is a stringified number" do - Puppet.expects(:warning).once - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - scope = Puppet::Parser::Scope.new(compiler) - - scope['a'] = [] - - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" ) - - access.assign(scope, "val2") - scope['a'].should == ["val2"] - end - - it "should raise an error when trying to overwrite a hash value" do - @scope['a'] = { "key" => [ "a" , "b" ]} - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") - - lambda { access.assign(@scope, "test") }.should raise_error - end - end -end describe Puppet::Parser::AST::Regex do before :each do node = Puppet::Node.new('localhost') compiler = Puppet::Parser::Compiler.new(node) @scope = Puppet::Parser::Scope.new(compiler) end describe "when initializing" do it "should create a Regexp with its content when value is not a Regexp" do Regexp.expects(:new).with("/ab/") Puppet::Parser::AST::Regex.new :value => "/ab/" end it "should not create a Regexp with its content when value is a Regexp" do value = Regexp.new("/ab/") Regexp.expects(:new).with("/ab/").never Puppet::Parser::AST::Regex.new :value => value end end describe "when evaluating" do it "should return self" do val = Puppet::Parser::AST::Regex.new :value => "/ab/" val.evaluate(@scope).should === val end end describe "when evaluate_match" do before :each do @value = stub 'regex' @value.stubs(:match).with("value").returns(true) Regexp.stubs(:new).returns(@value) @regex = Puppet::Parser::AST::Regex.new :value => "/ab/" end it "should issue the regexp match" do @value.expects(:match).with("value") @regex.evaluate_match("value", @scope) end it "should not downcase the parameter value" do @value.expects(:match).with("VaLuE") @regex.evaluate_match("VaLuE", @scope) end it "should set ephemeral scope vars if there is a match" do @scope.expects(:ephemeral_from).with(true, nil, nil) @regex.evaluate_match("value", @scope) end it "should return the match to the caller" do @value.stubs(:match).with("value").returns(:match) @scope.stubs(:ephemeral_from) @regex.evaluate_match("value", @scope) end end it "should match undef to the empty string" do regex = Puppet::Parser::AST::Regex.new(:value => "^$") regex.evaluate_match(:undef, @scope).should be_true end it "should not match undef to a non-empty string" do regex = Puppet::Parser::AST::Regex.new(:value => '\w') regex.evaluate_match(:undef, @scope).should be_false end it "should match a string against a string" do regex = Puppet::Parser::AST::Regex.new(:value => '\w') regex.evaluate_match('foo', @scope).should be_true end it "should return the regex source with to_s" do regex = stub 'regex' Regexp.stubs(:new).returns(regex) val = Puppet::Parser::AST::Regex.new :value => "/ab/" regex.expects(:source) val.to_s end it "should delegate match to the underlying regexp match method" do regex = Regexp.new("/ab/") val = Puppet::Parser::AST::Regex.new :value => regex regex.expects(:match).with("value") val.match("value") end end -describe Puppet::Parser::AST::Variable do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - @var = Puppet::Parser::AST::Variable.new(:value => "myvar", :file => 'my.pp', :line => 222) - end - - it "should lookup the variable in scope" do - @scope["myvar"] = :myvalue - @var.safeevaluate(@scope).should == :myvalue - end - - it "should pass the source location to lookupvar" do - @scope.setvar("myvar", :myvalue, :file => 'my.pp', :line => 222 ) - @var.safeevaluate(@scope).should == :myvalue - end - - it "should return undef if the variable wasn't set" do - @var.safeevaluate(@scope).should == :undef - end - - describe "when converting to string" do - it "should transform its value to a variable" do - value = stub 'value', :is_a? => true, :to_s => "myvar" - Puppet::Parser::AST::Variable.new( :value => value ).to_s.should == "\$myvar" - end - end -end - describe Puppet::Parser::AST::HostName do before :each do node = Puppet::Node.new('localhost') compiler = Puppet::Parser::Compiler.new(node) @scope = Puppet::Parser::Scope.new(compiler) @value = 'value' @value.stubs(:to_s).returns(@value) @value.stubs(:downcase).returns(@value) @host = Puppet::Parser::AST::HostName.new(:value => @value) end it "should raise an error if hostname is not valid" do lambda { Puppet::Parser::AST::HostName.new( :value => "not a hostname!" ) }.should raise_error end it "should not raise an error if hostname is a regex" do lambda { Puppet::Parser::AST::HostName.new( :value => Puppet::Parser::AST::Regex.new(:value => "/test/") ) }.should_not raise_error end it "should stringify the value" do value = stub 'value', :=~ => false value.expects(:to_s).returns("test") Puppet::Parser::AST::HostName.new(:value => value) end it "should downcase the value" do value = stub 'value', :=~ => false value.stubs(:to_s).returns("UPCASED") host = Puppet::Parser::AST::HostName.new(:value => value) host.value == "upcased" end it "should evaluate to its value" do @host.evaluate(@scope).should == @value end it "should delegate eql? to the underlying value if it is an HostName" do @value.expects(:eql?).with("value") @host.eql?("value") end it "should delegate eql? to the underlying value if it is not an HostName" do value = stub 'compared', :is_a? => true, :value => "value" @value.expects(:eql?).with("value") @host.eql?(value) end it "should delegate hash to the underlying value" do @value.expects(:hash) @host.hash end end diff --git a/spec/unit/parser/ast/match_operator_spec.rb b/spec/unit/parser/ast/match_operator_spec.rb deleted file mode 100755 index 2a9fad3d1..000000000 --- a/spec/unit/parser/ast/match_operator_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::MatchOperator do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - - @lval = stub 'lval' - @lval.stubs(:safeevaluate).with(@scope).returns("this is a string") - - @rval = stub 'rval' - @rval.stubs(:evaluate_match) - - @operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => "=~" - end - - it "should evaluate the left operand" do - @lval.expects(:safeevaluate).with(@scope) - - @operator.evaluate(@scope) - end - - it "should fail for an unknown operator" do - lambda { operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :operator => "unknown", :rval => @rval }.should raise_error - end - - it "should evaluate_match the left operand" do - @rval.expects(:evaluate_match).with("this is a string", @scope).returns(:match) - - @operator.evaluate(@scope) - end - - { "=~" => true, "!~" => false }.each do |op, res| - it "should return #{res} if the regexp matches with #{op}" do - match = stub 'match' - @rval.stubs(:evaluate_match).with("this is a string", @scope).returns(match) - - operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => op - operator.evaluate(@scope).should == res - end - - it "should return #{!res} if the regexp doesn't match" do - @rval.stubs(:evaluate_match).with("this is a string", @scope).returns(nil) - - operator = Puppet::Parser::AST::MatchOperator.new :lval => @lval, :rval => @rval, :operator => op - operator.evaluate(@scope).should == !res - end - end -end diff --git a/spec/unit/parser/ast/minus_spec.rb b/spec/unit/parser/ast/minus_spec.rb deleted file mode 100755 index f866e780d..000000000 --- a/spec/unit/parser/ast/minus_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Minus do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - it "should evaluate its argument" do - value = stub "value" - value.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::Minus.new :value => value - operator.evaluate(@scope) - end - - it "should fail if argument is not a string or integer" do - array_ast = stub 'array_ast', :safeevaluate => [2] - operator = Puppet::Parser::AST::Minus.new :value => array_ast - lambda { operator.evaluate(@scope) }.should raise_error - end - - it "should work with integer as string" do - string = stub 'string', :safeevaluate => "123" - operator = Puppet::Parser::AST::Minus.new :value => string - operator.evaluate(@scope).should == -123 - end - - it "should work with integers" do - int = stub 'int', :safeevaluate => 123 - operator = Puppet::Parser::AST::Minus.new :value => int - operator.evaluate(@scope).should == -123 - end - -end diff --git a/spec/unit/parser/ast/node_spec.rb b/spec/unit/parser/ast/node_spec.rb deleted file mode 100755 index 0cb80061c..000000000 --- a/spec/unit/parser/ast/node_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Node do - describe "when instantiated" do - it "should make its names and context available through accessors" do - node = Puppet::Parser::AST::Node.new(['foo', 'bar'], :line => 5) - node.names.should == ['foo', 'bar'] - node.context.should == {:line => 5} - end - - it "should create a node with the proper type, name, context, and module name" do - node = Puppet::Parser::AST::Node.new(['foo'], :line => 5) - instantiated_nodes = node.instantiate('modname') - instantiated_nodes.length.should == 1 - instantiated_nodes[0].type.should == :node - instantiated_nodes[0].name.should == 'foo' - instantiated_nodes[0].line.should == 5 - instantiated_nodes[0].module_name.should == 'modname' - end - - it "should handle multiple names" do - node = Puppet::Parser::AST::Node.new(['foo', 'bar']) - instantiated_nodes = node.instantiate('modname') - instantiated_nodes.length.should == 2 - instantiated_nodes[0].name.should == 'foo' - instantiated_nodes[1].name.should == 'bar' - end - end -end diff --git a/spec/unit/parser/ast/nop_spec.rb b/spec/unit/parser/ast/nop_spec.rb deleted file mode 100755 index 5b21fe88c..000000000 --- a/spec/unit/parser/ast/nop_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Nop do - - before do - @scope = mock 'scope' - end - - it "should do nothing on evaluation" do - Puppet::Parser::AST.expects(:safeevaluate).never - Puppet::Parser::AST::Nop.new({}).evaluate(@scope) - end - - it "should not return anything" do - Puppet::Parser::AST::Nop.new({}).evaluate(@scope).should be_nil - end - -end diff --git a/spec/unit/parser/ast/not_spec.rb b/spec/unit/parser/ast/not_spec.rb deleted file mode 100755 index b5af3f98f..000000000 --- a/spec/unit/parser/ast/not_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Not do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - @true_ast = Puppet::Parser::AST::Boolean.new( :value => true) - @false_ast = Puppet::Parser::AST::Boolean.new( :value => false) - end - - it "should evaluate its child expression" do - val = stub "val" - val.expects(:safeevaluate).with(@scope) - - operator = Puppet::Parser::AST::Not.new :value => val - operator.evaluate(@scope) - end - - it "should return true for ! false" do - operator = Puppet::Parser::AST::Not.new :value => @false_ast - operator.evaluate(@scope).should == true - end - - it "should return false for ! true" do - operator = Puppet::Parser::AST::Not.new :value => @true_ast - operator.evaluate(@scope).should == false - end - -end diff --git a/spec/unit/parser/ast/relationship_spec.rb b/spec/unit/parser/ast/relationship_spec.rb deleted file mode 100755 index afd506a02..000000000 --- a/spec/unit/parser/ast/relationship_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Relationship do - before do - @class = Puppet::Parser::AST::Relationship - end - - it "should set its 'left' and 'right' arguments accordingly" do - dep = @class.new(:left, :right, '->') - dep.left.should == :left - dep.right.should == :right - end - - it "should set its arrow to whatever arrow is passed" do - @class.new(:left, :right, '->').arrow.should == '->' - end - - it "should set its type to :relationship if the relationship type is '<-'" do - @class.new(:left, :right, '<-').type.should == :relationship - end - - it "should set its type to :relationship if the relationship type is '->'" do - @class.new(:left, :right, '->').type.should == :relationship - end - - it "should set its type to :subscription if the relationship type is '~>'" do - @class.new(:left, :right, '~>').type.should == :subscription - end - - it "should set its type to :subscription if the relationship type is '<~'" do - @class.new(:left, :right, '<~').type.should == :subscription - end - - it "should set its line and file if provided" do - dep = @class.new(:left, :right, '->', :line => 50, :file => "/foo") - dep.line.should == 50 - dep.file.should == "/foo" - end - - describe "when evaluating" do - before do - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) - @scope = Puppet::Parser::Scope.new(@compiler) - end - - it "should create a relationship with the evaluated source and target and add it to the scope" do - source = stub 'source', :safeevaluate => :left - target = stub 'target', :safeevaluate => :right - @class.new(source, target, '->').evaluate(@scope) - @compiler.relationships[0].source.should == :left - @compiler.relationships[0].target.should == :right - end - - describe "a chained relationship" do - before do - @left = stub 'left', :safeevaluate => :left - @middle = stub 'middle', :safeevaluate => :middle - @right = stub 'right', :safeevaluate => :right - @first = @class.new(@left, @middle, '->') - @second = @class.new(@first, @right, '->') - end - - it "should evaluate the relationship to the left" do - @first.expects(:evaluate).with(@scope).returns Puppet::Parser::Relationship.new(:left, :right, :relationship) - - @second.evaluate(@scope) - end - - it "should use the right side of the left relationship as its source" do - @second.evaluate(@scope) - - @compiler.relationships[0].source.should == :left - @compiler.relationships[0].target.should == :middle - @compiler.relationships[1].source.should == :middle - @compiler.relationships[1].target.should == :right - end - - it "should only evaluate a given AST node once" do - @left.expects(:safeevaluate).once.returns :left - @middle.expects(:safeevaluate).once.returns :middle - @right.expects(:safeevaluate).once.returns :right - @second.evaluate(@scope) - end - end - end -end diff --git a/spec/unit/parser/ast/resource_defaults_spec.rb b/spec/unit/parser/ast/resource_defaults_spec.rb deleted file mode 100755 index 6904bee3b..000000000 --- a/spec/unit/parser/ast/resource_defaults_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ResourceDefaults do - - ast = Puppet::Parser::AST - - before :each do - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(@compiler) - @params = Puppet::Parser::AST::ASTArray.new({}) - @compiler.stubs(:add_override) - end - - it "should add defaults when evaluated" do - default = Puppet::Parser::AST::ResourceDefaults.new :type => "file", :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) - default.evaluate @scope - - @scope.lookupdefaults("file").should_not be_nil - end -end diff --git a/spec/unit/parser/ast/resource_override_spec.rb b/spec/unit/parser/ast/resource_override_spec.rb deleted file mode 100755 index 7989cf0e5..000000000 --- a/spec/unit/parser/ast/resource_override_spec.rb +++ /dev/null @@ -1,50 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ResourceOverride do - - ast = Puppet::Parser::AST - - before :each do - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(@compiler) - @params = ast::ASTArray.new({}) - @compiler.stubs(:add_override) - end - - it "should evaluate the overriden object" do - klass = stub 'klass', :title => "title", :type => "type" - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns(klass) - ast::ResourceOverride.new(:object => object, :parameters => @params ).evaluate(@scope) - end - - it "should tell the compiler to override the resource with our own" do - @compiler.expects(:add_override) - - klass = stub 'klass', :title => "title", :type => "one" - object = mock 'object', :safeevaluate => klass - ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) - end - - it "should return the overriden resource directly when called with one item" do - klass = stub 'klass', :title => "title", :type => "one" - object = mock 'object', :safeevaluate => klass - override = ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) - override.should be_an_instance_of(Puppet::Parser::Resource) - override.title.should == "title" - override.type.should == "One" - end - - it "should return an array of overriden resources when called with an array of titles" do - klass1 = stub 'klass1', :title => "title1", :type => "one" - klass2 = stub 'klass2', :title => "title2", :type => "one" - - object = mock 'object', :safeevaluate => [klass1,klass2] - - override = ast::ResourceOverride.new(:object => object , :parameters => @params).evaluate(@scope) - override.should have(2).elements - override.each {|o| o.should be_an_instance_of(Puppet::Parser::Resource) } - end - -end diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb deleted file mode 100755 index cd5a5923c..000000000 --- a/spec/unit/parser/ast/resource_reference_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ResourceReference do - - ast = Puppet::Parser::AST - - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - def ast_name(value) - Puppet::Parser::AST::Name.new(:value => value) - end - - def newref(type, title) - title_array = Puppet::Parser::AST::ASTArray.new(:children => [title]) - ref = Puppet::Parser::AST::ResourceReference.new(:type => type, :title => title_array) - end - - it "should correctly produce reference strings" do - newref("File", ast_name("/tmp/yay")).evaluate(@scope).to_s.should == "File[/tmp/yay]" - end - - it "should produce a single resource when the title evaluates to a string" do - newref("File", ast_name("/tmp/yay")).evaluate(@scope).should == Puppet::Resource.new("file", "/tmp/yay") - end - - it "should return an array of resources if given an array of titles" do - titles = Puppet::Parser::AST::ASTArray.new(:children => [ast_name("title1"), ast_name("title2")]) - ref = ast::ResourceReference.new( :title => titles, :type => "File" ) - ref.evaluate(@scope).should == [ - Puppet::Resource.new("file", "title1"), - Puppet::Resource.new("file", "title2") - ] - end - - it "should return an array of resources if given a variable containing an array of titles" do - @scope["my_files"] = ["foo", "bar"] - titles = Puppet::Parser::AST::Variable.new(:value => "my_files") - ref = newref('File', titles) - ref.evaluate(@scope).should == [ - Puppet::Resource.new("file", "foo"), - Puppet::Resource.new("file", "bar") - ] - end - - it "should return a correct representation when converting to string" do - type = stub 'type', :is_a? => true, :to_s => "file" - title = stub 'title', :is_a? => true, :to_s => "[/tmp/a, /tmp/b]" - - ast::ResourceReference.new( :type => type, :title => title ).to_s.should == "File[/tmp/a, /tmp/b]" - end -end diff --git a/spec/unit/parser/ast/resource_spec.rb b/spec/unit/parser/ast/resource_spec.rb deleted file mode 100755 index 00aa263ff..000000000 --- a/spec/unit/parser/ast/resource_spec.rb +++ /dev/null @@ -1,183 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Resource do - ast = Puppet::Parser::AST - - describe "for builtin types" do - before :each do - @title = Puppet::Parser::AST::String.new(:value => "mytitle") - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(@compiler) - @scope.stubs(:resource).returns(stub_everything) - @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) - @resource = ast::Resource.new(:type => "file", :instances => ast::ASTArray.new(:children => [@instance])) - @resource.stubs(:qualified_type).returns("Resource") - end - - it "should evaluate all its parameters" do - param = stub 'param' - param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) - @instance.stubs(:parameters).returns [param] - - @resource.evaluate(@scope) - end - - it "should evaluate its title" do - @resource.evaluate(@scope)[0].title.should == "mytitle" - end - - it "should flatten the titles array" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) - end - - array = Puppet::Parser::AST::ASTArray.new(:children => titles) - - @instance.title = array - result = @resource.evaluate(@scope).collect { |r| r.title } - result.should be_include("one") - result.should be_include("two") - end - - it "should create and return one resource objects per title" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) - end - - array = Puppet::Parser::AST::ASTArray.new(:children => titles) - - @instance.title = array - result = @resource.evaluate(@scope).collect { |r| r.title } - result.should be_include("one") - result.should be_include("two") - end - - it "should implicitly iterate over instances" do - new_title = Puppet::Parser::AST::String.new(:value => "other_title") - new_instance = ast::ResourceInstance.new(:title => new_title, :parameters => ast::ASTArray.new(:children => [])) - @resource.instances.push(new_instance) - @resource.evaluate(@scope).collect { |r| r.title }.should == ["mytitle", "other_title"] - end - - it "should handover resources to the compiler" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) - end - - array = Puppet::Parser::AST::ASTArray.new(:children => titles) - - @instance.title = array - result = @resource.evaluate(@scope) - - result.each do |res| - @compiler.catalog.resource(res.ref).should be_instance_of(Puppet::Parser::Resource) - end - end - - it "should generate virtual resources if it is virtual" do - @resource.virtual = true - - result = @resource.evaluate(@scope) - result[0].should be_virtual - end - - it "should generate virtual and exported resources if it is exported" do - @resource.exported = true - - result = @resource.evaluate(@scope) - result[0].should be_virtual - result[0].should be_exported - end - - # Related to #806, make sure resources always look up the full path to the resource. - describe "when generating qualified resources" do - before do - @scope = Puppet::Parser::Scope.new Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @parser = Puppet::Parser::Parser.new(@scope.environment) - ["one", "one::two", "three"].each do |name| - @parser.environment.known_resource_types.add(Puppet::Resource::Type.new(:definition, name, {})) - end - @twoscope = @scope.newscope(:namespace => "one") - @twoscope.resource = @scope.resource - end - - def resource(type, params = nil) - params ||= Puppet::Parser::AST::ASTArray.new(:children => []) - instance = Puppet::Parser::AST::ResourceInstance.new( - :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) - Puppet::Parser::AST::Resource.new(:type => type, - :instances => Puppet::Parser::AST::ASTArray.new(:children => [instance])) - end - - it "should be able to generate resources with fully qualified type information" do - resource("two").evaluate(@twoscope)[0].type.should == "One::Two" - end - - it "should be able to generate resources with unqualified type information" do - resource("one").evaluate(@twoscope)[0].type.should == "One" - end - - it "should correctly generate resources that can look up builtin types" do - resource("file").evaluate(@twoscope)[0].type.should == "File" - end - - it "should correctly generate resources that can look up defined classes by title" do - @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) - @scope.compiler.stubs(:evaluate_classes) - res = resource("class").evaluate(@twoscope)[0] - res.type.should == "Class" - res.title.should == "Myresource" - end - - it "should evaluate parameterized classes when they are instantiated" do - @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) - @scope.compiler.expects(:evaluate_classes).with(['myresource'],@twoscope,false,true) - resource("class").evaluate(@twoscope)[0] - end - - it "should fail for resource types that do not exist" do - lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) - end - end - end - - describe "for class resources" do - before do - @title = Puppet::Parser::AST::String.new(:value => "classname") - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(@compiler) - @scope.stubs(:resource).returns(stub_everything) - @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) - @resource = ast::Resource.new(:type => "Class", :instances => ast::ASTArray.new(:children => [@instance])) - @resource.stubs(:qualified_type).returns("Resource") - @type = Puppet::Resource::Type.new(:hostclass, "classname") - @compiler.known_resource_types.add(@type) - end - - it "should instantiate the class" do - @compiler.stubs(:evaluate_classes) - result = @resource.evaluate(@scope) - result.length.should == 1 - result.first.ref.should == "Class[Classname]" - @compiler.catalog.resource("Class[Classname]").should equal(result.first) - end - - it "should cause its parent to be evaluated" do - parent_type = Puppet::Resource::Type.new(:hostclass, "parentname") - @compiler.stubs(:evaluate_classes) - @compiler.known_resource_types.add(parent_type) - @type.parent = "parentname" - result = @resource.evaluate(@scope) - result.length.should == 1 - result.first.ref.should == "Class[Classname]" - @compiler.catalog.resource("Class[Classname]").should equal(result.first) - @compiler.catalog.resource("Class[Parentname]").should be_instance_of(Puppet::Parser::Resource) - end - - end - -end diff --git a/spec/unit/parser/ast/resourceparam_spec.rb b/spec/unit/parser/ast/resourceparam_spec.rb deleted file mode 100644 index 818f146d3..000000000 --- a/spec/unit/parser/ast/resourceparam_spec.rb +++ /dev/null @@ -1,51 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::ResourceParam do - - ast = Puppet::Parser::AST - - before :each do - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(@compiler) - @params = ast::ASTArray.new({}) - @compiler.stubs(:add_override) - end - - it "should evaluate the parameter value" do - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns('value') - ast::ResourceParam.new(:param => 'myparam', :value => object).evaluate(@scope) - end - - it "should return a Puppet::Parser::Resource::Param on evaluation" do - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns('value') - evaled = ast::ResourceParam.new(:param => 'myparam', :value => object).evaluate(@scope) - evaled.should be_a(Puppet::Parser::Resource::Param) - evaled.name.to_s.should == 'myparam' - evaled.value.to_s.should == 'value' - end - - it "should copy line numbers to Puppet::Parser::Resource::Param" do - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns('value') - evaled = ast::ResourceParam.new(:param => 'myparam', :value => object, :line => 42).evaluate(@scope) - evaled.line.should == 42 - end - - it "should copy source file to Puppet::Parser::Resource::Param" do - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns('value') - evaled = ast::ResourceParam.new(:param => 'myparam', :value => object, :file => 'foo.pp').evaluate(@scope) - evaled.file.should == 'foo.pp' - end - - it "should change nil parameter values to undef" do - object = mock 'object' - object.expects(:safeevaluate).with(@scope).returns(nil) - evaled = ast::ResourceParam.new(:param => 'myparam', :value => object).evaluate(@scope) - evaled.should be_a(Puppet::Parser::Resource::Param) - evaled.value.should == :undef - end -end diff --git a/spec/unit/parser/ast/selector_spec.rb b/spec/unit/parser/ast/selector_spec.rb deleted file mode 100755 index ef1168918..000000000 --- a/spec/unit/parser/ast/selector_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::Selector do - let :node do Puppet::Node.new('localhost') end - let :compiler do Puppet::Parser::Compiler.new(node) end - let :scope do Puppet::Parser::Scope.new(compiler) end - - # Take a code expression containing a selector, and return that portion of - # the AST. This does the magic required to make that legal and all. - def parse(selector) - Puppet::Parser::Parser.new(scope.environment). - parse("$foo = #{selector}"). - code[0].value # extract only the selector - end - - describe "when evaluating" do - it "should evaluate param" do - selector = parse 'value ? { default => result }' - selector.param.expects(:safeevaluate) - selector.evaluate(scope) - end - - it "should try to match each option in sequence" do - selector = parse '"a" ? { "a" => "a", "b" => "b", default => "default" }' - - order = sequence('evaluation of matching options') - selector.values.each do |slot| - slot.param.expects(:evaluate_match).in_sequence(order).returns(false) - end - - selector.evaluate(scope) - end - - describe "when scanning values" do - it "should evaluate and return first matching option" do - selector = parse '"b" ? { "a" => "=a", "b" => "=b", "c" => "=c" }' - selector.evaluate(scope).should == '=b' - end - - it "should evaluate the default option if none matched" do - selector = parse '"a" ? { "b" => "=b", default => "=default" }' - selector.evaluate(scope).should == "=default" - end - - it "should return the default even if that isn't the last option" do - selector = parse '"a" ? { "b" => "=b", default => "=default", "c" => "=c" }' - selector.evaluate(scope).should == "=default" - end - - it "should raise ParseError if nothing matched, and no default" do - selector = parse '"a" ? { "b" => "=b" }' - msg = /No matching value for selector param/ - expect { selector.evaluate(scope) }.to raise_error Puppet::ParseError, msg - end - - it "should unset scope ephemeral variables after option evaluation" do - selector = parse '"a" ? { "a" => "=a" }' - scope.expects(:unset_ephemeral_var).with(scope.ephemeral_level) - selector.evaluate(scope) - end - - it "should not leak ephemeral variables even if evaluation fails" do - selector = parse '"a" ? { "b" => "=b" }' - scope.expects(:unset_ephemeral_var).with(scope.ephemeral_level) - expect { selector.evaluate(scope) }.to raise_error - end - end - end - - describe "when converting to string" do - it "should work with a single match" do - parse('$input ? { "a" => "a+" }').to_s.should == '$input ? { "a" => "a+" }' - end - - it "should work with multiple matches" do - parse('$input ? { "a" => "a+", "b" => "b+" }').to_s. - should == '$input ? { "a" => "a+", "b" => "b+" }' - end - - it "should preserve order of inputs" do - match = ('a' .. 'z').map {|x| "#{x} => #{x}" }.join(', ') - selector = parse "$input ? { #{match} }" - - selector.to_s.should == "$input ? { #{match} }" - end - end -end diff --git a/spec/unit/parser/ast/vardef_spec.rb b/spec/unit/parser/ast/vardef_spec.rb deleted file mode 100755 index 0e123bde6..000000000 --- a/spec/unit/parser/ast/vardef_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser::AST::VarDef do - before :each do - node = Puppet::Node.new('localhost') - compiler = Puppet::Parser::Compiler.new(node) - @scope = Puppet::Parser::Scope.new(compiler) - end - - describe "when evaluating" do - - it "should evaluate arguments" do - name = Puppet::Parser::AST::String.new :value => 'name' - value = Puppet::Parser::AST::String.new :value => 'value' - - name.expects(:safeevaluate).with(@scope).returns('name') - value.expects(:safeevaluate).with(@scope).returns('value') - - vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil - vardef.evaluate(@scope) - end - - it "should be in append=false mode if called without append" do - name = stub 'name', :safeevaluate => "var" - value = stub 'value', :safeevaluate => "1" - - @scope.expects(:setvar).with { |name,value,options| options[:append] == nil } - - vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil - vardef.evaluate(@scope) - end - - it "should call scope in append mode if append is true" do - name = stub 'name', :safeevaluate => "var" - value = stub 'value', :safeevaluate => "1" - - @scope.expects(:setvar).with { |name,value,options| options[:append] == true } - - vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => nil, :line => nil, :append => true - vardef.evaluate(@scope) - end - - it "should call pass the source location to setvar" do - name = stub 'name', :safeevaluate => "var" - value = stub 'value', :safeevaluate => "1" - - @scope.expects(:setvar).with { |name,value,options| options[:file] == 'setvar.pp' and options[:line] == 917 } - - vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => value, :file => 'setvar.pp', :line => 917 - vardef.evaluate(@scope) - end - - describe "when dealing with hash" do - it "should delegate to the HashOrArrayAccess assign" do - access = stub 'name' - access.stubs(:is_a?).with(Puppet::Parser::AST::HashOrArrayAccess).returns(true) - value = stub 'value', :safeevaluate => "1" - vardef = Puppet::Parser::AST::VarDef.new :name => access, :value => value, :file => nil, :line => nil - - access.expects(:assign).with(@scope, '1') - - vardef.evaluate(@scope) - end - end - - end -end diff --git a/spec/unit/parser/ast_spec.rb b/spec/unit/parser/ast_spec.rb deleted file mode 100755 index 0437b503c..000000000 --- a/spec/unit/parser/ast_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -require 'puppet/parser/ast' - -describe Puppet::Parser::AST do - it "should have a doc accessor" do - ast = Puppet::Parser::AST.new({}) - ast.should respond_to(:doc) - end - - it "should have a use_docs accessor to indicate it wants documentation" do - ast = Puppet::Parser::AST.new({}) - ast.should respond_to(:use_docs) - end - - [ Puppet::Parser::AST::Collection, Puppet::Parser::AST::Else, - Puppet::Parser::AST::Function, Puppet::Parser::AST::IfStatement, - Puppet::Parser::AST::Resource, Puppet::Parser::AST::ResourceDefaults, - Puppet::Parser::AST::ResourceOverride, Puppet::Parser::AST::VarDef - ].each do |k| - it "#{k}.use_docs should return true" do - ast = k.new({}) - ast.use_docs.should be_true - end - end - - describe "when initializing" do - it "should store the doc argument if passed" do - ast = Puppet::Parser::AST.new(:doc => "documentation") - ast.doc.should == "documentation" - end - end - -end - -describe 'AST Generic Child' do - let(:scope) { stub 'scope' } - - class Evaluateable < Puppet::Parser::AST - attr_accessor :value - def safeevaluate(*options) - return value - end - end - - def ast_node_of(value) - Evaluateable.new(:value => value) - end - - describe "when evaluate_match is called" do - it "matches when the values are equal" do - ast_node_of('value').evaluate_match('value', scope).should be_true - end - - it "matches in a case insensitive manner" do - ast_node_of('vALue').evaluate_match('vALuE', scope).should be_true - end - - it "matches strings that represent numbers" do - ast_node_of("23").evaluate_match(23, scope).should be_true - end - - it "matches numbers against strings that represent numbers" do - ast_node_of(23).evaluate_match("23", scope).should be_true - end - - it "matches undef if value is an empty string" do - ast_node_of('').evaluate_match(:undef, scope).should be_true - end - - it "matches '' if value is undef" do - ast_node_of(:undef).evaluate_match('', scope).should be_true - end - end -end diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb deleted file mode 100755 index 5042f5937..000000000 --- a/spec/unit/parser/collector_spec.rb +++ /dev/null @@ -1,438 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' -require 'puppet/rails' -require 'puppet/parser/collector' - -describe Puppet::Parser::Collector, "when initializing" do - before do - @scope = mock 'scope' - @resource_type = 'resource_type' - @form = :exported - @vquery = mock 'vquery' - @equery = mock 'equery' - - @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @equery, @vquery, @form) - end - - it "should require a scope" do - @collector.scope.should equal(@scope) - end - - it "should require a resource type" do - @collector.type.should == 'Resource_type' - end - - it "should only accept :virtual or :exported as the collector form" do - expect { @collector = Puppet::Parser::Collector.new(@scope, @resource_type, @vquery, @equery, :other) }.to raise_error(ArgumentError) - end - - it "should accept an optional virtual query" do - @collector.vquery.should equal(@vquery) - end - - it "should accept an optional exported query" do - @collector.equery.should equal(@equery) - end - - it "should canonicalize the type name" do - @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) - @collector.type.should == "Resource::Type" - end - - it "should accept an optional resource override" do - @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) - override = { :parameters => "whatever" } - @collector.add_override(override) - @collector.overrides.should equal(override) - end - -end - -describe Puppet::Parser::Collector, "when collecting specific virtual resources" do - before do - @scope = mock 'scope' - @vquery = mock 'vquery' - @equery = mock 'equery' - @compiler = mock 'compiler' - - @collector = Puppet::Parser::Collector.new(@scope, "resource_type", @equery, @vquery, :virtual) - end - - it "should not fail when it does not find any resources to collect" do - @collector.resources = ["File[virtual1]", "File[virtual2]"] - @scope.stubs(:findresource).returns(false) - expect { @collector.evaluate }.to_not raise_error - end - - it "should mark matched resources as non-virtual" do - @collector.resources = ["File[virtual1]", "File[virtual2]"] - one = stub_everything 'one' - one.expects(:virtual=).with(false) - - @scope.stubs(:findresource).with("File[virtual1]").returns(one) - @scope.stubs(:findresource).with("File[virtual2]").returns(nil) - @collector.evaluate - end - - it "should return matched resources" do - @collector.resources = ["File[virtual1]", "File[virtual2]"] - one = stub_everything 'one' - @scope.stubs(:findresource).with("File[virtual1]").returns(one) - @scope.stubs(:findresource).with("File[virtual2]").returns(nil) - @collector.evaluate.should == [one] - end - - it "should delete itself from the compile's collection list if it has found all of its resources" do - @collector.resources = ["File[virtual1]"] - one = stub_everything 'one' - @compiler.expects(:delete_collection).with(@collector) - @scope.expects(:compiler).returns(@compiler) - @scope.stubs(:findresource).with("File[virtual1]").returns(one) - @collector.evaluate - end - - it "should not delete itself from the compile's collection list if it has unfound resources" do - @collector.resources = ["File[virtual1]"] - one = stub_everything 'one' - @compiler.expects(:delete_collection).never - @scope.stubs(:findresource).with("File[virtual1]").returns(nil) - @collector.evaluate - end -end - -describe Puppet::Parser::Collector, "when collecting virtual and catalog resources" do - before do - @scope = mock 'scope' - @compiler = mock 'compile' - @scope.stubs(:compiler).returns(@compiler) - @resource_type = "Mytype" - @vquery = proc { |res| true } - - @collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, @vquery, :virtual) - end - - it "should find all virtual resources matching the vquery" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true - two = stub_everything 'two', :type => "Mytype", :virtual? => true - - @compiler.expects(:resources).returns([one, two]) - - @collector.evaluate.should == [one, two] - end - - it "should find all non-virtual resources matching the vquery" do - one = stub_everything 'one', :type => "Mytype", :virtual? => false - two = stub_everything 'two', :type => "Mytype", :virtual? => false - - @compiler.expects(:resources).returns([one, two]) - - @collector.evaluate.should == [one, two] - end - - it "should mark all matched resources as non-virtual" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true - - one.expects(:virtual=).with(false) - - @compiler.expects(:resources).returns([one]) - - @collector.evaluate - end - - it "should return matched resources" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true - two = stub_everything 'two', :type => "Mytype", :virtual? => true - - @compiler.expects(:resources).returns([one, two]) - - @collector.evaluate.should == [one, two] - end - - it "should return all resources of the correct type if there is no virtual query" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true - two = stub_everything 'two', :type => "Mytype", :virtual? => true - - one.expects(:virtual=).with(false) - two.expects(:virtual=).with(false) - - @compiler.expects(:resources).returns([one, two]) - - @collector = Puppet::Parser::Collector.new(@scope, @resource_type, nil, nil, :virtual) - - @collector.evaluate.should == [one, two] - end - - it "should not return or mark resources of a different type" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true - two = stub_everything 'two', :type => :other, :virtual? => true - - one.expects(:virtual=).with(false) - two.expects(:virtual=).never - - @compiler.expects(:resources).returns([one, two]) - - @collector.evaluate.should == [one] - end - - it "should create a resource with overridden parameters" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" - param = stub 'param' - @compiler.stubs(:add_override) - - @compiler.expects(:resources).returns([one]) - - @collector.add_override(:parameters => param ) - Puppet::Parser::Resource.expects(:new).with { |type, title, h| - h[:parameters] == param - } - - @collector.evaluate - end - - it "should define a new allow all child_of? on overriden resource" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" - param = stub 'param' - source = stub 'source' - @compiler.stubs(:add_override) - - @compiler.expects(:resources).returns([one]) - - @collector.add_override(:parameters => param, :source => source ) - Puppet::Parser::Resource.stubs(:new) - - source.expects(:meta_def).with { |name,block| name == :child_of? } - - @collector.evaluate - end - - - it "should not override already overriden resources for this same collection in a previous run" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" - param = stub 'param' - @compiler.stubs(:add_override) - - @compiler.expects(:resources).at_least(2).returns([one]) - - @collector.add_override(:parameters => param ) - Puppet::Parser::Resource.expects(:new).once.with { |type, title, h| - h[:parameters] == param - } - - @collector.evaluate - - @collector.evaluate - end - - it "should not return resources that were collected in a previous run of this collector" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" - @compiler.stubs(:resources).returns([one]) - - @collector.evaluate - - @collector.evaluate.should be_false - end - - - it "should tell the compiler about the overriden resources" do - one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" - param = stub 'param' - - one.expects(:virtual=).with(false) - @compiler.expects(:resources).returns([one]) - @collector.add_override(:parameters => param ) - Puppet::Parser::Resource.stubs(:new).returns("whatever") - - @compiler.expects(:add_override).with("whatever") - - @collector.evaluate - end - - it "should not return or mark non-matching resources" do - @collector.vquery = proc { |res| res.name == :one } - - one = stub_everything 'one', :name => :one, :type => "Mytype", :virtual? => true - two = stub_everything 'two', :name => :two, :type => "Mytype", :virtual? => true - - one.expects(:virtual=).with(false) - two.expects(:virtual=).never - - @compiler.expects(:resources).returns([one, two]) - - @collector.evaluate.should == [one] - end -end - -describe Puppet::Parser::Collector, "when collecting exported resources", :if => can_use_scratch_database? do - include PuppetSpec::Files - - before do - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new @compiler - @resource_type = "notify" - @equery = ["title", "!=", ""] - @vquery = proc { |r| true } - @collector = Puppet::Parser::Collector.new(@scope, @resource_type, - @equery, @vquery, :exported) - end - - it "should just return false if :storeconfigs is not enabled" do - Puppet[:storeconfigs] = false - @collector.evaluate.should be_false - end - - context "with storeconfigs enabled" do - before :each do - setup_scratch_database - Puppet[:storeconfigs] = true - Puppet[:environment] = "production" - Puppet[:storeconfigs_backend] = "active_record" - end - - after :each do - Puppet::Rails.teardown - end - - it "should return all matching resources from the current compile and mark them non-virtual and non-exported" do - one = Puppet::Parser::Resource.new('notify', 'one', - :virtual => true, - :exported => true, - :scope => @scope) - two = Puppet::Parser::Resource.new('notify', 'two', - :virtual => true, - :exported => true, - :scope => @scope) - - @compiler.resources << one - @compiler.resources << two - - @collector.evaluate.should == [one, two] - one.should_not be_virtual - two.should_not be_virtual - end - - it "should mark all returned resources as not virtual" do - one = Puppet::Parser::Resource.new('notify', 'one', - :virtual => true, - :exported => true, - :scope => @scope) - - @compiler.resources << one - - @collector.evaluate.should == [one] - one.should_not be_virtual - end - - it "should convert all found resources into parser resources if necessary" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - - result = @collector.evaluate - result.length.should == 1 - result.first.should be_an_instance_of Puppet::Parser::Resource - result.first.type.should == 'Notify' - result.first.title.should == 'whammo' - end - - it "should leave parser resources alone" do - resource = Puppet::Parser::Resource.new(:file, "/tmp/foo", :scope => @scope) - resource2 = Puppet::Parser::Resource.new(:file, "/tmp/bar", :scope => @scope) - resource.expects(:to_resource).never - resource2.expects(:to_resource).never - - resources = [resource, resource2] - - Puppet::Resource.indirection.stubs(:search).returns resources - - @collector.evaluate.should == resources - end - - it "should override all exported collected resources if collector has an override" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - - param = Puppet::Parser::Resource::Param. - new(:name => 'message', :value => 'howdy') - @collector.add_override(:parameters => [param], :scope => @scope) - - got = @collector.evaluate - got.first[:message].should == param.value - end - - it "should store converted resources in the compile's resource list" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - - @compiler.expects(:add_resource).with do |scope, resource| - scope.should be_an_instance_of Puppet::Parser::Scope - resource.type.should == 'Notify' - resource.title.should == 'whammo' - true - end - - @collector.evaluate - end - - # This way one host doesn't store another host's resources as exported. - it "should mark resources collected from the database as not exported" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - - got = @collector.evaluate - got.length.should == 1 - got.first.type.should == "Notify" - got.first.title.should == "whammo" - got.first.should_not be_exported - end - - it "should fail if an equivalent resource already exists in the compile" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - - local = Puppet::Parser::Resource.new('notify', 'whammo', :scope => @scope) - @compiler.add_resource(@scope, local) - - expect { @collector.evaluate }. - to raise_error Puppet::ParseError, /A duplicate resource was found while collecting exported resources/ - end - - it "should ignore exported resources that match already-collected resources" do - host = Puppet::Rails::Host.create!(:name => 'one.local') - # One that we already collected... - db = Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'whammo', - :exported => true) - # ...and one we didn't. - Puppet::Rails::Resource. - create!(:host => host, - :restype => 'Notify', :title => 'boingy-boingy', - :exported => true) - - local = Puppet::Parser::Resource.new('notify', 'whammo', - :scope => @scope, - :collector_id => db.id) - @compiler.add_resource(@scope, local) - - got = nil - expect { got = @collector.evaluate }.not_to raise_error - got.length.should == 1 - got.first.type.should == "Notify" - got.first.title.should == "boingy-boingy" - end - end -end diff --git a/spec/unit/parser/lexer_spec.rb b/spec/unit/parser/lexer_spec.rb deleted file mode 100755 index 8d44a960e..000000000 --- a/spec/unit/parser/lexer_spec.rb +++ /dev/null @@ -1,877 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -require 'puppet/parser/lexer' - -# This is a special matcher to match easily lexer output -RSpec::Matchers.define :be_like do |*expected| - match do |actual| - expected.zip(actual).all? { |e,a| !e or a[0] == e or (e.is_a? Array and a[0] == e[0] and (a[1] == e[1] or (a[1].is_a?(Hash) and a[1][:value] == e[1]))) } - end -end -__ = nil - -def tokens_scanned_from(s) - lexer = Puppet::Parser::Lexer.new - lexer.string = s - lexer.fullscan[0..-2] -end - - -describe Puppet::Parser::Lexer do - describe "when reading strings" do - before { @lexer = Puppet::Parser::Lexer.new } - it "should increment the line count for every carriage return in the string" do - @lexer.line = 10 - @lexer.string = "this\nis\natest'" - @lexer.slurpstring("'") - - @lexer.line.should == 12 - end - - it "should not increment the line count for escapes in the string" do - @lexer.line = 10 - @lexer.string = "this\\nis\\natest'" - @lexer.slurpstring("'") - - @lexer.line.should == 10 - end - - it "should not think the terminator is escaped, when preceded by an even number of backslashes" do - @lexer.line = 10 - @lexer.string = "here\nis\nthe\nstring\\\\'with\nextra\njunk" - @lexer.slurpstring("'") - - @lexer.line.should == 13 - end - - { - 'r' => "\r", - 'n' => "\n", - 't' => "\t", - 's' => " " - }.each do |esc, expected_result| - it "should recognize \\#{esc} sequence" do - @lexer.string = "\\#{esc}'" - @lexer.slurpstring("'")[0].should == expected_result - end - end - end -end - -describe Puppet::Parser::Lexer::Token do - before do - @token = Puppet::Parser::Lexer::Token.new(%r{something}, :NAME) - end - - [:regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate].each do |param| - it "should have a #{param.to_s} reader" do - @token.should be_respond_to(param) - end - - it "should have a #{param.to_s} writer" do - @token.should be_respond_to(param.to_s + "=") - end - end -end - -describe Puppet::Parser::Lexer::Token, "when initializing" do - it "should create a regex if the first argument is a string" do - Puppet::Parser::Lexer::Token.new("something", :NAME).regex.should == %r{something} - end - - it "should set the string if the first argument is one" do - Puppet::Parser::Lexer::Token.new("something", :NAME).string.should == "something" - end - - it "should set the regex if the first argument is one" do - Puppet::Parser::Lexer::Token.new(%r{something}, :NAME).regex.should == %r{something} - end -end - -describe Puppet::Parser::Lexer::TokenList do - before do - @list = Puppet::Parser::Lexer::TokenList.new - end - - it "should have a method for retrieving tokens by the name" do - token = @list.add_token :name, "whatever" - @list[:name].should equal(token) - end - - it "should have a method for retrieving string tokens by the string" do - token = @list.add_token :name, "whatever" - @list.lookup("whatever").should equal(token) - end - - it "should add tokens to the list when directed" do - token = @list.add_token :name, "whatever" - @list[:name].should equal(token) - end - - it "should have a method for adding multiple tokens at once" do - @list.add_tokens "whatever" => :name, "foo" => :bar - @list[:name].should_not be_nil - @list[:bar].should_not be_nil - end - - it "should fail to add tokens sharing a name with an existing token" do - @list.add_token :name, "whatever" - expect { @list.add_token :name, "whatever" }.to raise_error(ArgumentError) - end - - it "should set provided options on tokens being added" do - token = @list.add_token :name, "whatever", :skip_text => true - token.skip_text.should == true - end - - it "should define any provided blocks as a :convert method" do - token = @list.add_token(:name, "whatever") do "foo" end - token.convert.should == "foo" - end - - it "should store all string tokens in the :string_tokens list" do - one = @list.add_token(:name, "1") - @list.string_tokens.should be_include(one) - end - - it "should store all regex tokens in the :regex_tokens list" do - one = @list.add_token(:name, %r{one}) - @list.regex_tokens.should be_include(one) - end - - it "should not store string tokens in the :regex_tokens list" do - one = @list.add_token(:name, "1") - @list.regex_tokens.should_not be_include(one) - end - - it "should not store regex tokens in the :string_tokens list" do - one = @list.add_token(:name, %r{one}) - @list.string_tokens.should_not be_include(one) - end - - it "should sort the string tokens inversely by length when asked" do - one = @list.add_token(:name, "1") - two = @list.add_token(:other, "12") - @list.sort_tokens - @list.string_tokens.should == [two, one] - end -end - -describe Puppet::Parser::Lexer::TOKENS do - before do - @lexer = Puppet::Parser::Lexer.new - end - - { - :LBRACK => '[', - :RBRACK => ']', - :LBRACE => '{', - :RBRACE => '}', - :LPAREN => '(', - :RPAREN => ')', - :EQUALS => '=', - :ISEQUAL => '==', - :GREATEREQUAL => '>=', - :GREATERTHAN => '>', - :LESSTHAN => '<', - :LESSEQUAL => '<=', - :NOTEQUAL => '!=', - :NOT => '!', - :COMMA => ',', - :DOT => '.', - :COLON => ':', - :AT => '@', - :LLCOLLECT => '<<|', - :RRCOLLECT => '|>>', - :LCOLLECT => '<|', - :RCOLLECT => '|>', - :SEMIC => ';', - :QMARK => '?', - :BACKSLASH => '\\', - :FARROW => '=>', - :PARROW => '+>', - :APPENDS => '+=', - :PLUS => '+', - :MINUS => '-', - :DIV => '/', - :TIMES => '*', - :LSHIFT => '<<', - :RSHIFT => '>>', - :MATCH => '=~', - :NOMATCH => '!~', - :IN_EDGE => '->', - :OUT_EDGE => '<-', - :IN_EDGE_SUB => '~>', - :OUT_EDGE_SUB => '<~', - }.each do |name, string| - it "should have a token named #{name.to_s}" do - Puppet::Parser::Lexer::TOKENS[name].should_not be_nil - end - - it "should match '#{string}' for the token #{name.to_s}" do - Puppet::Parser::Lexer::TOKENS[name].string.should == string - end - end - - { - "case" => :CASE, - "class" => :CLASS, - "default" => :DEFAULT, - "define" => :DEFINE, - "import" => :IMPORT, - "if" => :IF, - "elsif" => :ELSIF, - "else" => :ELSE, - "inherits" => :INHERITS, - "node" => :NODE, - "and" => :AND, - "or" => :OR, - "undef" => :UNDEF, - "false" => :FALSE, - "true" => :TRUE, - "in" => :IN, - "unless" => :UNLESS, - }.each do |string, name| - it "should have a keyword named #{name.to_s}" do - Puppet::Parser::Lexer::KEYWORDS[name].should_not be_nil - end - - it "should have the keyword for #{name.to_s} set to #{string}" do - Puppet::Parser::Lexer::KEYWORDS[name].string.should == string - end - end - - # These tokens' strings don't matter, just that the tokens exist. - [:STRING, :DQPRE, :DQMID, :DQPOST, :BOOLEAN, :NAME, :NUMBER, :COMMENT, :MLCOMMENT, :RETURN, :SQUOTE, :DQUOTE, :VARIABLE].each do |name| - it "should have a token named #{name.to_s}" do - Puppet::Parser::Lexer::TOKENS[name].should_not be_nil - end - end -end - -describe Puppet::Parser::Lexer::TOKENS[:CLASSREF] do - before { @token = Puppet::Parser::Lexer::TOKENS[:CLASSREF] } - - it "should match against single upper-case alpha-numeric terms" do - @token.regex.should =~ "One" - end - - it "should match against upper-case alpha-numeric terms separated by double colons" do - @token.regex.should =~ "One::Two" - end - - it "should match against many upper-case alpha-numeric terms separated by double colons" do - @token.regex.should =~ "One::Two::Three::Four::Five" - end - - it "should match against upper-case alpha-numeric terms prefixed by double colons" do - @token.regex.should =~ "::One" - end -end - -describe Puppet::Parser::Lexer::TOKENS[:NAME] do - before { @token = Puppet::Parser::Lexer::TOKENS[:NAME] } - - it "should match against lower-case alpha-numeric terms" do - @token.regex.should =~ "one-two" - end - - it "should return itself and the value if the matched term is not a keyword" do - Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(nil) - lexer = stub("lexer") - @token.convert(lexer, "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] - end - - it "should return the keyword token and the value if the matched term is a keyword" do - keyword = stub 'keyword', :name => :testing - Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) - @token.convert(stub("lexer"), "myval").should == [keyword, "myval"] - end - - it "should return the BOOLEAN token and 'true' if the matched term is the string 'true'" do - keyword = stub 'keyword', :name => :TRUE - Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) - @token.convert(stub('lexer'), "true").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], true] - end - - it "should return the BOOLEAN token and 'false' if the matched term is the string 'false'" do - keyword = stub 'keyword', :name => :FALSE - Puppet::Parser::Lexer::KEYWORDS.expects(:lookup).returns(keyword) - @token.convert(stub('lexer'), "false").should == [Puppet::Parser::Lexer::TOKENS[:BOOLEAN], false] - end - - it "should match against lower-case alpha-numeric terms separated by double colons" do - @token.regex.should =~ "one::two" - end - - it "should match against many lower-case alpha-numeric terms separated by double colons" do - @token.regex.should =~ "one::two::three::four::five" - end - - it "should match against lower-case alpha-numeric terms prefixed by double colons" do - @token.regex.should =~ "::one" - end - - it "should match against nested terms starting with numbers" do - @token.regex.should =~ "::1one::2two::3three" - end -end - -describe Puppet::Parser::Lexer::TOKENS[:NUMBER] do - before do - @token = Puppet::Parser::Lexer::TOKENS[:NUMBER] - @regex = @token.regex - end - - it "should match against numeric terms" do - @regex.should =~ "2982383139" - end - - it "should match against float terms" do - @regex.should =~ "29823.235" - end - - it "should match against hexadecimal terms" do - @regex.should =~ "0xBEEF0023" - end - - it "should match against float with exponent terms" do - @regex.should =~ "10e23" - end - - it "should match against float terms with negative exponents" do - @regex.should =~ "10e-23" - end - - it "should match against float terms with fractional parts and exponent" do - @regex.should =~ "1.234e23" - end - - it "should return the NAME token and the value" do - @token.convert(stub("lexer"), "myval").should == [Puppet::Parser::Lexer::TOKENS[:NAME], "myval"] - end -end - -describe Puppet::Parser::Lexer::TOKENS[:COMMENT] do - before { @token = Puppet::Parser::Lexer::TOKENS[:COMMENT] } - - it "should match against lines starting with '#'" do - @token.regex.should =~ "# this is a comment" - end - - it "should be marked to get skipped" do - @token.skip?.should be_true - end - - it "should be marked to accumulate" do - @token.accumulate?.should be_true - end - - it "'s block should return the comment without the #" do - @token.convert(@lexer,"# this is a comment")[1].should == "this is a comment" - end -end - -describe Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] do - before do - @token = Puppet::Parser::Lexer::TOKENS[:MLCOMMENT] - @lexer = stub 'lexer', :line => 0 - end - - it "should match against lines enclosed with '/*' and '*/'" do - @token.regex.should =~ "/* this is a comment */" - end - - it "should match multiple lines enclosed with '/*' and '*/'" do - @token.regex.should =~ """/* - this is a comment - */""" - end - - it "should increase the lexer current line number by the amount of lines spanned by the comment" do - @lexer.expects(:line=).with(2) - @token.convert(@lexer, "1\n2\n3") - end - - it "should not greedily match comments" do - match = @token.regex.match("/* first */ word /* second */") - match[1].should == " first " - end - - it "should be marked to accumulate" do - @token.accumulate?.should be_true - end - - it "'s block should return the comment without the comment marks" do - @lexer.stubs(:line=).with(0) - - @token.convert(@lexer,"/* this is a comment */")[1].should == "this is a comment" - end - -end - -describe Puppet::Parser::Lexer::TOKENS[:RETURN] do - before { @token = Puppet::Parser::Lexer::TOKENS[:RETURN] } - - it "should match against carriage returns" do - @token.regex.should =~ "\n" - end - - it "should be marked to initiate text skipping" do - @token.skip_text.should be_true - end - - it "should be marked to increment the line" do - @token.incr_line.should be_true - end -end - - -shared_examples_for "handling `-` in standard variable names" do |prefix| - # Watch out - a regex might match a *prefix* on these, not just the whole - # word, so make sure you don't have false positive or negative results based - # on that. - legal = %w{f foo f::b foo::b f::bar foo::bar 3 foo3 3foo} - illegal = %w{f- f-o -f f::-o f::o- f::o-o} - - ["", "::"].each do |global_scope| - legal.each do |name| - var = prefix + global_scope + name - it "should accept #{var.inspect} as a valid variable name" do - (subject.regex.match(var) || [])[0].should == var - end - end - - illegal.each do |name| - var = prefix + global_scope + name - it "when `variable_with_dash` is disabled it should NOT accept #{var.inspect} as a valid variable name" do - Puppet[:allow_variables_with_dashes] = false - (subject.regex.match(var) || [])[0].should_not == var - end - - it "when `variable_with_dash` is enabled it should NOT accept #{var.inspect} as a valid variable name" do - Puppet[:allow_variables_with_dashes] = true - (subject.regex.match(var) || [])[0].should_not == var - end - end - end -end - -describe Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR] do - its(:skip_text) { should be_false } - its(:incr_line) { should be_false } - - it_should_behave_like "handling `-` in standard variable names", '$' -end - -describe Puppet::Parser::Lexer::TOKENS[:VARIABLE] do - its(:skip_text) { should be_false } - its(:incr_line) { should be_false } - - it_should_behave_like "handling `-` in standard variable names", '' -end - -describe "the horrible deprecation / compatibility variables with dashes" do - NamesWithDashes = %w{f- f-o -f f::-o f::o- f::o-o} - - { Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR_WITH_DASH] => '$', - Puppet::Parser::Lexer::TOKENS[:VARIABLE_WITH_DASH] => '' - }.each do |token, prefix| - describe token do - its(:skip_text) { should be_false } - its(:incr_line) { should be_false } - - context "when compatibly is disabled" do - before :each do Puppet[:allow_variables_with_dashes] = false end - Puppet::Parser::Lexer::TOKENS.each do |name, value| - it "should be unacceptable after #{name}" do - token.acceptable?(:after => name).should be_false - end - end - - # Yes, this should still *match*, just not be acceptable. - NamesWithDashes.each do |name| - ["", "::"].each do |global_scope| - var = prefix + global_scope + name - it "should match #{var.inspect}" do - subject.regex.match(var).to_a.should == [var] - end - end - end - end - - context "when compatibility is enabled" do - before :each do Puppet[:allow_variables_with_dashes] = true end - it "should be acceptable after DQPRE" do - token.acceptable?(:after => :DQPRE).should be_true - end - - NamesWithDashes.each do |name| - ["", "::"].each do |global_scope| - var = prefix + global_scope + name - it "should match #{var.inspect}" do - subject.regex.match(var).to_a.should == [var] - end - end - end - end - end - end - - context "deprecation warnings" do - before :each do Puppet[:allow_variables_with_dashes] = true end - - it "should match a top level variable" do - Puppet.expects(:deprecation_warning).once - - tokens_scanned_from('$foo-bar').should == [ - [:VARIABLE, { :value => 'foo-bar', :line => 1 }] - ] - end - - it "does not warn about a variable without a dash" do - Puppet.expects(:deprecation_warning).never - - tokens_scanned_from('$c').should == [ - [:VARIABLE, { :value => "c", :line => 1 }] - ] - end - - it "does not warn about referencing a class name that contains a dash" do - Puppet.expects(:deprecation_warning).never - - tokens_scanned_from('foo-bar').should == [ - [:NAME, { :value => "foo-bar", :line => 1 }] - ] - end - - it "warns about reference to variable" do - Puppet.expects(:deprecation_warning).once - - tokens_scanned_from('$::foo-bar::baz-quux').should == [ - [:VARIABLE, { :value => "::foo-bar::baz-quux", :line => 1 }] - ] - end - - it "warns about reference to variable interpolated in a string" do - Puppet.expects(:deprecation_warning).once - - tokens_scanned_from('"$::foo-bar::baz-quux"').should == [ - [:DQPRE, { :value => "", :line => 1 }], - [:VARIABLE, { :value => "::foo-bar::baz-quux", :line => 1 }], - [:DQPOST, { :value => "", :line => 1 }], - ] - end - - it "warns about reference to variable interpolated in a string as an expression" do - Puppet.expects(:deprecation_warning).once - - tokens_scanned_from('"${::foo-bar::baz-quux}"').should == [ - [:DQPRE, { :value => "", :line => 1 }], - [:VARIABLE, { :value => "::foo-bar::baz-quux", :line => 1 }], - [:DQPOST, { :value => "", :line => 1 }], - ] - end - end -end - -describe Puppet::Parser::Lexer,"when lexing strings" do - { - %q{'single quoted string')} => [[:STRING,'single quoted string']], - %q{"double quoted string"} => [[:STRING,'double quoted string']], - %q{'single quoted string with an escaped "\\'"'} => [[:STRING,'single quoted string with an escaped "\'"']], - %q{'single quoted string with an escaped "\$"'} => [[:STRING,'single quoted string with an escaped "\$"']], - %q{'single quoted string with an escaped "\."'} => [[:STRING,'single quoted string with an escaped "\."']], - %q{'single quoted string with an escaped "\r\n"'} => [[:STRING,'single quoted string with an escaped "\r\n"']], - %q{'single quoted string with an escaped "\n"'} => [[:STRING,'single quoted string with an escaped "\n"']], - %q{'single quoted string with an escaped "\\\\"'} => [[:STRING,'single quoted string with an escaped "\\\\"']], - %q{"string with an escaped '\\"'"} => [[:STRING,"string with an escaped '\"'"]], - %q{"string with an escaped '\\$'"} => [[:STRING,"string with an escaped '$'"]], - %Q{"string with a line ending with a backslash: \\\nfoo"} => [[:STRING,"string with a line ending with a backslash: foo"]], - %q{"string with $v (but no braces)"} => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' (but no braces)']], - %q["string with ${v} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' in braces']], - %q["string with ${qualified::var} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'qualified::var'],[:DQPOST,' in braces']], - %q{"string with $v and $v (but no braces)"} => [[:DQPRE,"string with "],[:VARIABLE,"v"],[:DQMID," and "],[:VARIABLE,"v"],[:DQPOST," (but no braces)"]], - %q["string with ${v} and ${v} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,"v"],[:DQMID," and "],[:VARIABLE,"v"],[:DQPOST," in braces"]], - %q["string with ${'a nested single quoted string'} inside it."] => [[:DQPRE,"string with "],[:STRING,'a nested single quoted string'],[:DQPOST,' inside it.']], - %q["string with ${['an array ',$v2]} in it."] => [[:DQPRE,"string with "],:LBRACK,[:STRING,"an array "],:COMMA,[:VARIABLE,"v2"],:RBRACK,[:DQPOST," in it."]], - %q{a simple "scanner" test} => [[:NAME,"a"],[:NAME,"simple"], [:STRING,"scanner"],[:NAME,"test"]], - %q{a simple 'single quote scanner' test} => [[:NAME,"a"],[:NAME,"simple"], [:STRING,"single quote scanner"],[:NAME,"test"]], - %q{a harder 'a $b \c"'} => [[:NAME,"a"],[:NAME,"harder"], [:STRING,'a $b \c"']], - %q{a harder "scanner test"} => [[:NAME,"a"],[:NAME,"harder"], [:STRING,"scanner test"]], - %q{a hardest "scanner \"test\""} => [[:NAME,"a"],[:NAME,"hardest"],[:STRING,'scanner "test"']], - %Q{a hardestest "scanner \\"test\\"\n"} => [[:NAME,"a"],[:NAME,"hardestest"],[:STRING,%Q{scanner "test"\n}]], - %q{function("call")} => [[:NAME,"function"],[:LPAREN,"("],[:STRING,'call'],[:RPAREN,")"]], - %q["string with ${(3+5)/4} nested math."] => [[:DQPRE,"string with "],:LPAREN,[:NAME,"3"],:PLUS,[:NAME,"5"],:RPAREN,:DIV,[:NAME,"4"],[:DQPOST," nested math."]], - %q["$$$$"] => [[:STRING,"$$$$"]], - %q["$variable"] => [[:DQPRE,""],[:VARIABLE,"variable"],[:DQPOST,""]], - %q["$var$other"] => [[:DQPRE,""],[:VARIABLE,"var"],[:DQMID,""],[:VARIABLE,"other"],[:DQPOST,""]], - %q["foo$bar$"] => [[:DQPRE,"foo"],[:VARIABLE,"bar"],[:DQPOST,"$"]], - %q["foo$$bar"] => [[:DQPRE,"foo$"],[:VARIABLE,"bar"],[:DQPOST,""]], - %q[""] => [[:STRING,""]], - %q["123 456 789 0"] => [[:STRING,"123 456 789 0"]], - %q["${123} 456 $0"] => [[:DQPRE,""],[:VARIABLE,"123"],[:DQMID," 456 "],[:VARIABLE,"0"],[:DQPOST,""]], - %q["$foo::::bar"] => [[:DQPRE,""],[:VARIABLE,"foo"],[:DQPOST,"::::bar"]] - }.each { |src,expected_result| - it "should handle #{src} correctly" do - tokens_scanned_from(src).should be_like(*expected_result) - end - } -end - -describe Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR] do - before { @token = Puppet::Parser::Lexer::TOKENS[:DOLLAR_VAR] } - - it "should match against alpha words prefixed with '$'" do - @token.regex.should =~ '$this_var' - end - - it "should return the VARIABLE token and the variable name stripped of the '$'" do - @token.convert(stub("lexer"), "$myval").should == [Puppet::Parser::Lexer::TOKENS[:VARIABLE], "myval"] - end -end - -describe Puppet::Parser::Lexer::TOKENS[:REGEX] do - before { @token = Puppet::Parser::Lexer::TOKENS[:REGEX] } - - it "should match against any expression enclosed in //" do - @token.regex.should =~ '/this is a regex/' - end - - it 'should not match if there is \n in the regex' do - @token.regex.should_not =~ "/this is \n a regex/" - end - - describe "when scanning" do - it "should not consider escaped slashes to be the end of a regex" do - tokens_scanned_from("$x =~ /this \\/ foo/").should be_like(__,__,[:REGEX,%r{this / foo}]) - end - - it "should not lex chained division as a regex" do - tokens_scanned_from("$x = $a/$b/$c").collect { |name, data| name }.should_not be_include( :REGEX ) - end - - it "should accept a regular expression after NODE" do - tokens_scanned_from("node /www.*\.mysite\.org/").should be_like(__,[:REGEX,Regexp.new("www.*\.mysite\.org")]) - end - - it "should accept regular expressions in a CASE" do - s = %q{case $variable { - "something": {$othervar = 4096 / 2} - /regex/: {notice("this notably sucks")} - } - } - tokens_scanned_from(s).should be_like( - :CASE,:VARIABLE,:LBRACE,:STRING,:COLON,:LBRACE,:VARIABLE,:EQUALS,:NAME,:DIV,:NAME,:RBRACE,[:REGEX,/regex/],:COLON,:LBRACE,:NAME,:LPAREN,:STRING,:RPAREN,:RBRACE,:RBRACE - ) - end - - end - - - it "should return the REGEX token and a Regexp" do - @token.convert(stub("lexer"), "/myregex/").should == [Puppet::Parser::Lexer::TOKENS[:REGEX], Regexp.new(/myregex/)] - end -end - -describe Puppet::Parser::Lexer, "when lexing comments" do - before { @lexer = Puppet::Parser::Lexer.new } - - it "should accumulate token in munge_token" do - token = stub 'token', :skip => true, :accumulate? => true, :incr_line => nil, :skip_text => false - - token.stubs(:convert).with(@lexer, "# this is a comment").returns([token, " this is a comment"]) - @lexer.munge_token(token, "# this is a comment") - @lexer.munge_token(token, "# this is a comment") - - @lexer.getcomment.should == " this is a comment\n this is a comment\n" - end - - it "should add a new comment stack level on LBRACE" do - @lexer.string = "{" - - @lexer.expects(:commentpush) - - @lexer.fullscan - end - - it "should add a new comment stack level on LPAREN" do - @lexer.string = "(" - - @lexer.expects(:commentpush) - - @lexer.fullscan - end - - it "should pop the current comment on RPAREN" do - @lexer.string = ")" - - @lexer.expects(:commentpop) - - @lexer.fullscan - end - - it "should return the current comments on getcomment" do - @lexer.string = "# comment" - @lexer.fullscan - - @lexer.getcomment.should == "comment\n" - end - - it "should discard the previous comments on blank line" do - @lexer.string = "# 1\n\n# 2" - @lexer.fullscan - - @lexer.getcomment.should == "2\n" - end - - it "should skip whitespace before lexing the next token after a non-token" do - tokens_scanned_from("/* 1\n\n */ \ntest").should be_like([:NAME, "test"]) - end - - it "should not return comments seen after the current line" do - @lexer.string = "# 1\n\n# 2" - @lexer.fullscan - - @lexer.getcomment(1).should == "" - end - - it "should return a comment seen before the current line" do - @lexer.string = "# 1\n# 2" - @lexer.fullscan - - @lexer.getcomment(2).should == "1\n2\n" - end -end - -# FIXME: We need to rewrite all of these tests, but I just don't want to take the time right now. -describe "Puppet::Parser::Lexer in the old tests" do - before { @lexer = Puppet::Parser::Lexer.new } - - it "should do simple lexing" do - { - %q{\\} => [[:BACKSLASH,"\\"]], - %q{simplest scanner test} => [[:NAME,"simplest"],[:NAME,"scanner"],[:NAME,"test"]], - %Q{returned scanner test\n} => [[:NAME,"returned"],[:NAME,"scanner"],[:NAME,"test"]] - }.each { |source,expected| - tokens_scanned_from(source).should be_like(*expected) - } - end - - it "should fail usefully" do - expect { tokens_scanned_from('^') }.to raise_error(RuntimeError) - end - - it "should fail if the string is not set" do - expect { @lexer.fullscan }.to raise_error(Puppet::LexError) - end - - it "should correctly identify keywords" do - tokens_scanned_from("case").should be_like([:CASE, "case"]) - end - - it "should correctly parse class references" do - %w{Many Different Words A Word}.each { |t| tokens_scanned_from(t).should be_like([:CLASSREF,t])} - end - - # #774 - it "should correctly parse namespaced class refernces token" do - %w{Foo ::Foo Foo::Bar ::Foo::Bar}.each { |t| tokens_scanned_from(t).should be_like([:CLASSREF, t]) } - end - - it "should correctly parse names" do - %w{this is a bunch of names}.each { |t| tokens_scanned_from(t).should be_like([:NAME,t]) } - end - - it "should correctly parse names with numerals" do - %w{1name name1 11names names11}.each { |t| tokens_scanned_from(t).should be_like([:NAME,t]) } - end - - it "should correctly parse empty strings" do - expect { tokens_scanned_from('$var = ""') }.to_not raise_error - end - - it "should correctly parse virtual resources" do - tokens_scanned_from("@type {").should be_like([:AT, "@"], [:NAME, "type"], [:LBRACE, "{"]) - end - - it "should correctly deal with namespaces" do - @lexer.string = %{class myclass} - @lexer.fullscan - @lexer.namespace.should == "myclass" - - @lexer.namepop - @lexer.namespace.should == "" - - @lexer.string = "class base { class sub { class more" - @lexer.fullscan - @lexer.namespace.should == "base::sub::more" - - @lexer.namepop - @lexer.namespace.should == "base::sub" - end - - it "should not put class instantiation on the namespace" do - @lexer.string = "class base { class sub { class { mode" - @lexer.fullscan - @lexer.namespace.should == "base::sub" - end - - it "should correctly handle fully qualified names" do - @lexer.string = "class base { class sub::more {" - @lexer.fullscan - @lexer.namespace.should == "base::sub::more" - - @lexer.namepop - @lexer.namespace.should == "base" - end - - it "should correctly lex variables" do - ["$variable", "$::variable", "$qualified::variable", "$further::qualified::variable"].each do |string| - tokens_scanned_from(string).should be_like([:VARIABLE,string.sub(/^\$/,'')]) - end - end - - it "should end variables at `-`" do - tokens_scanned_from('$hyphenated-variable'). - should be_like [:VARIABLE, "hyphenated"], [:MINUS, '-'], [:NAME, 'variable'] - end - - it "should not include whitespace in a variable" do - tokens_scanned_from("$foo bar").should_not be_like([:VARIABLE, "foo bar"]) - end - it "should not include excess colons in a variable" do - tokens_scanned_from("$foo::::bar").should_not be_like([:VARIABLE, "foo::::bar"]) - end -end - -describe 'Puppet::Parser::Lexer handles reserved words' do - ['function', 'private', 'attr', 'type'].each do |reserved_bare_word| - it "by delivering '#{reserved_bare_word}' as a bare word" do - expect(tokens_scanned_from(reserved_bare_word)).to eq([[:NAME, {:value=>reserved_bare_word, :line => 1}]]) - end - end -end - -describe "Puppet::Parser::Lexer in the old tests when lexing example files" do - my_fixtures('*.pp') do |file| - it "should correctly lex #{file}" do - lexer = Puppet::Parser::Lexer.new - lexer.file = file - expect { lexer.fullscan }.to_not raise_error - end - end -end - -describe "when trying to lex a non-existent file" do - include PuppetSpec::Files - - it "should return an empty list of tokens" do - lexer = Puppet::Parser::Lexer.new - lexer.file = nofile = tmpfile('lexer') - Puppet::FileSystem.exist?(nofile).should == false - - lexer.fullscan.should == [[false,false]] - end -end diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb deleted file mode 100755 index 71e682563..000000000 --- a/spec/unit/parser/parser_spec.rb +++ /dev/null @@ -1,521 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe Puppet::Parser do - - Puppet::Parser::AST - - before :each do - @known_resource_types = Puppet::Resource::TypeCollection.new("development") - @parser = Puppet::Parser::Parser.new "development" - @parser.stubs(:known_resource_types).returns @known_resource_types - @true_ast = Puppet::Parser::AST::Boolean.new :value => true - end - - it "should require an environment at initialization" do - expect { - Puppet::Parser::Parser.new - }.to raise_error(ArgumentError, /wrong number of arguments/) - end - - it "should set the environment" do - env = Puppet::Node::Environment.create(:testing, []) - Puppet::Parser::Parser.new(env).environment.should == env - end - - it "should be able to look up the environment-specific resource type collection" do - env = Puppet::Node::Environment.create(:development, []) - rtc = env.known_resource_types - parser = Puppet::Parser::Parser.new env - parser.known_resource_types.should equal(rtc) - end - - context "when importing" do - it "uses the directory of the currently parsed file" do - @parser.lexer.stubs(:file).returns "/tmp/current_file" - - @parser.known_resource_types.loader.expects(:import).with("newfile", "/tmp") - - @parser.import("newfile") - end - - it "uses the current working directory, when there is no file being parsed" do - @parser.known_resource_types.loader.expects(:import).with('one', Dir.pwd) - @parser.known_resource_types.loader.expects(:import).with('two', Dir.pwd) - - @parser.parse("import 'one', 'two'") - end - end - - describe "when parsing append operator" do - - it "should not raise syntax errors" do - expect { @parser.parse("$var += something") }.to_not raise_error - end - - it "should raise syntax error on incomplete syntax " do - expect { - @parser.parse("$var += ") - }.to raise_error(Puppet::ParseError, /Syntax error at end of file/) - end - - it "should create ast::VarDef with append=true" do - vardef = @parser.parse("$var += 2").code[0] - vardef.should be_a(Puppet::Parser::AST::VarDef) - vardef.append.should == true - end - - it "should work with arrays too" do - vardef = @parser.parse("$var += ['test']").code[0] - vardef.should be_a(Puppet::Parser::AST::VarDef) - vardef.append.should == true - end - - end - - describe "when parsing selector" do - it "should support hash access on the left hand side" do - expect { @parser.parse("$h = { 'a' => 'b' } $a = $h['a'] ? { 'b' => 'd', default => undef }") }.to_not raise_error - end - end - - describe "parsing 'unless'" do - it "should create the correct ast objects" do - Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } - @parser.parse("unless false { $var = 1 }") - end - - it "should not raise an error with empty statements" do - expect { @parser.parse("unless false { }") }.to_not raise_error - end - - #test for bug #13296 - it "should not override 'unless' as a parameter inside resources" do - lambda { @parser.parse("exec {'/bin/echo foo': unless => '/usr/bin/false',}") }.should_not raise_error - end - end - - describe "when parsing parameter names" do - Puppet::Parser::Lexer::KEYWORDS.sort_tokens.each do |keyword| - it "should allow #{keyword} as a keyword" do - lambda { @parser.parse("exec {'/bin/echo foo': #{keyword} => '/usr/bin/false',}") }.should_not raise_error - end - end - end - - describe "when parsing 'if'" do - it "not, it should create the correct ast objects" do - Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } - @parser.parse("if ! true { $var = 1 }") - end - - it "boolean operation, it should create the correct ast objects" do - Puppet::Parser::AST::BooleanOperator.expects(:new).with { - |h| h[:rval].is_a?(Puppet::Parser::AST::Boolean) and h[:lval].is_a?(Puppet::Parser::AST::Boolean) and h[:operator]=="or" - } - @parser.parse("if true or true { $var = 1 }") - - end - - it "comparison operation, it should create the correct ast objects" do - Puppet::Parser::AST::ComparisonOperator.expects(:new).with { - |h| h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="<" - } - @parser.parse("if 1 < 2 { $var = 1 }") - - end - - end - - describe "when parsing if complex expressions" do - it "should create a correct ast tree" do - aststub = stub_everything 'ast' - Puppet::Parser::AST::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]==">" - }.returns(aststub) - Puppet::Parser::AST::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="==" - }.returns(aststub) - Puppet::Parser::AST::BooleanOperator.expects(:new).with { - |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" - } - @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") - end - - it "should raise an error on incorrect expression" do - expect { - @parser.parse("if (1 > 2 > ) or (1 == 2) { $var = 1 }") - }.to raise_error(Puppet::ParseError, /Syntax error at '\)'/) - end - - end - - describe "when parsing resource references" do - - it "should not raise syntax errors" do - expect { @parser.parse('exec { test: param => File["a"] }') }.to_not raise_error - end - - it "should not raise syntax errors with multiple references" do - expect { @parser.parse('exec { test: param => File["a","b"] }') }.to_not raise_error - end - - it "should create an ast::ResourceReference" do - Puppet::Parser::AST::ResourceReference.expects(:new).with { |arg| - arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(Puppet::Parser::AST::ASTArray) - } - @parser.parse('exec { test: command => File["a","b"] }') - end - end - - describe "when parsing resource overrides" do - - it "should not raise syntax errors" do - expect { @parser.parse('Resource["title"] { param => value }') }.to_not raise_error - end - - it "should not raise syntax errors with multiple overrides" do - expect { @parser.parse('Resource["title1","title2"] { param => value }') }.to_not raise_error - end - - it "should create an ast::ResourceOverride" do - #Puppet::Parser::AST::ResourceOverride.expects(:new).with { |arg| - # arg[:line]==1 and arg[:object].is_a?(Puppet::Parser::AST::ResourceReference) and arg[:parameters].is_a?(Puppet::Parser::AST::ResourceParam) - #} - ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] - ro.should be_a(Puppet::Parser::AST::ResourceOverride) - ro.line.should == 1 - ro.object.should be_a(Puppet::Parser::AST::ResourceReference) - ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) - end - - end - - describe "when parsing if statements" do - - it "should not raise errors with empty if" do - expect { @parser.parse("if true { }") }.to_not raise_error - end - - it "should not raise errors with empty else" do - expect { @parser.parse("if false { notice('if') } else { }") }.to_not raise_error - end - - it "should not raise errors with empty if and else" do - expect { @parser.parse("if false { } else { }") }.to_not raise_error - end - - it "should create a nop node for empty branch" do - Puppet::Parser::AST::Nop.expects(:new) - @parser.parse("if true { }") - end - - it "should create a nop node for empty else branch" do - Puppet::Parser::AST::Nop.expects(:new) - @parser.parse("if true { notice('test') } else { }") - end - - it "should build a chain of 'ifs' if there's an 'elsif'" do - expect { @parser.parse(<<-PP) }.to_not raise_error - if true { notice('test') } elsif true {} else { } - PP - end - - end - - describe "when parsing function calls" do - it "should not raise errors with no arguments" do - expect { @parser.parse("tag()") }.to_not raise_error - end - - it "should not raise errors with rvalue function with no args" do - expect { @parser.parse("$a = template()") }.to_not raise_error - end - - it "should not raise errors with arguments" do - expect { @parser.parse("notice(1)") }.to_not raise_error - end - - it "should not raise errors with multiple arguments" do - expect { @parser.parse("notice(1,2)") }.to_not raise_error - end - - it "should not raise errors with multiple arguments and a trailing comma" do - expect { @parser.parse("notice(1,2,)") }.to_not raise_error - end - - end - - describe "when parsing arrays" do - it "should parse an array" do - expect { @parser.parse("$a = [1,2]") }.to_not raise_error - end - - it "should not raise errors with a trailing comma" do - expect { @parser.parse("$a = [1,2,]") }.to_not raise_error - end - - it "should accept an empty array" do - expect { @parser.parse("$var = []\n") }.to_not raise_error - end - end - - describe "when providing AST context" do - before do - @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" - @parser.stubs(:lexer).returns @lexer - end - - it "should include the lexer's line" do - @parser.ast_context[:line].should == 50 - end - - it "should include the lexer's file" do - @parser.ast_context[:file].should == "/foo/bar" - end - - it "should include the docs if directed to do so" do - @parser.ast_context(true)[:doc].should == "whev" - end - - it "should not include the docs when told not to" do - @parser.ast_context(false)[:doc].should be_nil - end - - it "should not include the docs by default" do - @parser.ast_context[:doc].should be_nil - end - end - - describe "when building ast nodes" do - before do - @lexer = stub 'lexer', :line => 50, :file => "/foo/bar", :getcomment => "whev" - @parser.stubs(:lexer).returns @lexer - @class = Puppet::Resource::Type.new(:hostclass, "myclass", :use_docs => false) - end - - it "should return a new instance of the provided class created with the provided options" do - @class.expects(:new).with { |opts| opts[:foo] == "bar" } - @parser.ast(@class, :foo => "bar") - end - - it "should merge the ast context into the provided options" do - @class.expects(:new).with { |opts| opts[:file] == "/foo" } - @parser.expects(:ast_context).returns :file => "/foo" - @parser.ast(@class, :foo => "bar") - end - - it "should prefer provided options over AST context" do - @class.expects(:new).with { |opts| opts[:file] == "/bar" } - @lexer.expects(:file).returns "/foo" - @parser.ast(@class, :file => "/bar") - end - - it "should include docs when the AST class uses them" do - @class.expects(:use_docs).returns true - @class.stubs(:new) - @parser.expects(:ast_context).with{ |docs, line| docs == true }.returns({}) - @parser.ast(@class, :file => "/bar") - end - - it "should get docs from lexer using the correct AST line number" do - @class.expects(:use_docs).returns true - @class.stubs(:new).with{ |a| a[:doc] == "doc" } - @lexer.expects(:getcomment).with(12).returns "doc" - @parser.ast(@class, :file => "/bar", :line => 12) - end - end - - describe "when retrieving a specific node" do - it "should delegate to the known_resource_types node" do - @known_resource_types.expects(:node).with("node") - - @parser.node("node") - end - end - - describe "when retrieving a specific class" do - it "should delegate to the loaded code" do - @known_resource_types.expects(:hostclass).with("class") - - @parser.hostclass("class") - end - end - - describe "when retrieving a specific definitions" do - it "should delegate to the loaded code" do - @known_resource_types.expects(:definition).with("define") - - @parser.definition("define") - end - end - - describe "when determining the configuration version" do - it "should determine it from the resource type collection" do - @parser.known_resource_types.expects(:version).returns "foo" - @parser.version.should == "foo" - end - end - - describe "when looking up definitions" do - it "should use the known resource types to check for them by name" do - @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:definition).returns(:this_value) - @parser.find_definition("namespace","name").should == :this_value - end - end - - describe "when looking up hostclasses" do - it "should use the known resource types to check for them by name" do - @parser.known_resource_types.stubs(:find_or_load).with("namespace","name",:hostclass,{}).returns(:this_value) - @parser.find_hostclass("namespace","name").should == :this_value - end - end - - describe "when parsing classes" do - before :each do - @krt = Puppet::Resource::TypeCollection.new("development") - @parser = Puppet::Parser::Parser.new "development" - @parser.stubs(:known_resource_types).returns @krt - end - - it "should not create new classes" do - @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) - @krt.hostclass("foobar").should be_nil - end - - it "should correctly set the parent class when one is provided" do - @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" - end - - it "should correctly set the parent class for multiple classes at a time" do - statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code - statements[0].instantiate('')[0].parent.should == "yayness" - statements[1].instantiate('')[0].parent.should == "bar" - end - - it "should define the code when some is provided" do - @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil - end - - it "should accept parameters with trailing comma" do - @parser.parse("file { '/example': ensure => file, }").should be - end - - it "should accept parametrized classes with trailing comma" do - @parser.parse("class foobar ($var1 = 0,) { $var = val }").code[0].code.should_not be_nil - end - - it "should define parameters when provided" do - foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] - foobar.arguments.should == {"biz" => nil, "baz" => nil} - end - end - - describe "when parsing resources" do - before :each do - @krt = Puppet::Resource::TypeCollection.new("development") - @parser = Puppet::Parser::Parser.new "development" - @parser.stubs(:known_resource_types).returns @krt - end - - it "should be able to parse class resources" do - @krt.add(Puppet::Resource::Type.new(:hostclass, "foobar", :arguments => {"biz" => nil})) - expect { @parser.parse("class { foobar: biz => stuff }") }.to_not raise_error - end - - it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }").code[0].exported.should be_true - end - - it "should correctly mark virtual resources as virtual" do - @parser.parse("@file { '/file': }").code[0].virtual.should be_true - end - end - - describe "when parsing nodes" do - it "should be able to parse a node with a single name" do - node = @parser.parse("node foo { }").code[0] - node.should be_a Puppet::Parser::AST::Node - node.names.length.should == 1 - node.names[0].value.should == "foo" - end - - it "should be able to parse a node with two names" do - node = @parser.parse("node foo, bar { }").code[0] - node.should be_a Puppet::Parser::AST::Node - node.names.length.should == 2 - node.names[0].value.should == "foo" - node.names[1].value.should == "bar" - end - - it "should be able to parse a node with three names" do - node = @parser.parse("node foo, bar, baz { }").code[0] - node.should be_a Puppet::Parser::AST::Node - node.names.length.should == 3 - node.names[0].value.should == "foo" - node.names[1].value.should == "bar" - node.names[2].value.should == "baz" - end - end - - it "should fail if trying to collect defaults" do - expect { - @parser.parse("@Port { protocols => tcp }") - }.to raise_error(Puppet::ParseError, /Defaults are not virtualizable/) - end - - context "when parsing collections" do - it "should parse basic collections" do - @parser.parse("Port <| |>").code. - should be_all {|x| x.is_a? Puppet::Parser::AST::Collection } - end - - it "should parse fully qualified collections" do - @parser.parse("Port::Range <| |>").code. - should be_all {|x| x.is_a? Puppet::Parser::AST::Collection } - end - end - - it "should not assign to a fully qualified variable" do - expect { - @parser.parse("$one::two = yay") - }.to raise_error(Puppet::ParseError, /Cannot assign to variables in other namespaces/) - end - - it "should parse assignment of undef" do - tree = @parser.parse("$var = undef") - tree.code.children[0].should be_an_instance_of Puppet::Parser::AST::VarDef - tree.code.children[0].value.should be_an_instance_of Puppet::Parser::AST::Undef - end - - context "#namesplit" do - { "base::sub" => %w{base sub}, - "main" => ["", "main"], - "one::two::three::four" => ["one::two::three", "four"], - }.each do |input, output| - it "should split #{input.inspect} to #{output.inspect}" do - @parser.namesplit(input).should == output - end - end - end - - it "should treat classes as case insensitive" do - @parser.known_resource_types.import_ast(@parser.parse("class yayness {}"), '') - @parser.known_resource_types.hostclass('yayness'). - should == @parser.find_hostclass("", "YayNess") - end - - it "should treat defines as case insensitive" do - @parser.known_resource_types.import_ast(@parser.parse("define funtest {}"), '') - @parser.known_resource_types.hostclass('funtest'). - should == @parser.find_hostclass("", "fUntEst") - end - - context "deprecations" do - it "should flag use of import as deprecated" do - Puppet.expects(:deprecation_warning).once - @parser.known_resource_types.loader.expects(:import).with('foo', Dir.pwd) - @parser.parse("import 'foo'") - end - end -end diff --git a/spec/unit/parser/relationship_spec.rb b/spec/unit/parser/relationship_spec.rb index aaf229198..890b35e21 100755 --- a/spec/unit/parser/relationship_spec.rb +++ b/spec/unit/parser/relationship_spec.rb @@ -1,93 +1,75 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/parser/relationship' describe Puppet::Parser::Relationship do before do @source = Puppet::Resource.new(:mytype, "source") @target = Puppet::Resource.new(:mytype, "target") @extra_resource = Puppet::Resource.new(:mytype, "extra") @extra_resource2 = Puppet::Resource.new(:mytype, "extra2") @dep = Puppet::Parser::Relationship.new(@source, @target, :relationship) end describe "when evaluating" do before do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource(@source) @catalog.add_resource(@target) @catalog.add_resource(@extra_resource) @catalog.add_resource(@extra_resource2) end it "should fail if the source resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @target lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should fail if the target resource cannot be found" do @catalog = Puppet::Resource::Catalog.new @catalog.add_resource @source lambda { @dep.evaluate(@catalog) }.should raise_error(ArgumentError) end it "should add the target as a 'before' value if the type is 'relationship'" do @dep.type = :relationship @dep.evaluate(@catalog) @source[:before].should be_include("Mytype[target]") end it "should add the target as a 'notify' value if the type is 'subscription'" do @dep.type = :subscription @dep.evaluate(@catalog) @source[:notify].should be_include("Mytype[target]") end it "should supplement rather than clobber existing relationship values" do @source[:before] = "File[/bar]" @dep.evaluate(@catalog) # this test did not work before. It was appending the resources # together as a string (@source[:before].class == Array).should be_true @source[:before].should be_include("Mytype[target]") @source[:before].should be_include("File[/bar]") end it "should supplement rather than clobber existing resource relationships" do @source[:before] = @extra_resource @dep.evaluate(@catalog) (@source[:before].class == Array).should be_true @source[:before].should be_include("Mytype[target]") @source[:before].should be_include(@extra_resource) end it "should supplement rather than clobber multiple existing resource relationships" do @source[:before] = [@extra_resource, @extra_resource2] @dep.evaluate(@catalog) (@source[:before].class == Array).should be_true @source[:before].should be_include("Mytype[target]") @source[:before].should be_include(@extra_resource) @source[:before].should be_include(@extra_resource2) end - - it "should use the collected retargets if the target is a Collector" do - orig_target = @target - @target = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) - @target.collected[:foo] = @target - @dep.evaluate(@catalog) - - @source[:before].should be_include("Mytype[target]") - end - - it "should use the collected resources if the source is a Collector" do - orig_source = @source - @source = Puppet::Parser::Collector.new(stub("scope"), :file, "equery", "vquery", :virtual) - @source.collected[:foo] = @source - @dep.evaluate(@catalog) - - orig_source[:before].should be_include("Mytype[target]") - end end end diff --git a/spec/unit/pops/model/ast_transformer_spec.rb b/spec/unit/pops/model/ast_transformer_spec.rb deleted file mode 100644 index d62d2eaec..000000000 --- a/spec/unit/pops/model/ast_transformer_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'spec_helper' - -require File.join(File.dirname(__FILE__), '/../factory_rspec_helper') -require 'puppet/pops' - -describe Puppet::Pops::Model::AstTransformer do - include FactoryRspecHelper - - let(:filename) { "the-file.pp" } - let(:transformer) { Puppet::Pops::Model::AstTransformer.new(filename) } - - context "literal numbers" do - it "converts a decimal number to a string Name" do - ast = transform(QNAME_OR_NUMBER("10")) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "10" - end - - it "converts a 0 to a decimal 0" do - ast = transform(QNAME_OR_NUMBER("0")) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "0" - end - - it "converts a 00 to an octal 00" do - ast = transform(QNAME_OR_NUMBER("0")) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "0" - end - - it "converts an octal number to a string Name" do - ast = transform(QNAME_OR_NUMBER("020")) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "020" - end - - it "converts a hex number to a string Name" do - ast = transform(QNAME_OR_NUMBER("0x20")) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "0x20" - end - - it "converts an unknown radix to an error string" do - ast = transform(Puppet::Pops::Model::Factory.new(Puppet::Pops::Model::LiteralInteger, 3, 2)) - - ast.should be_kind_of(Puppet::Parser::AST::Name) - ast.value.should == "bad radix:3" - end - end - - it "preserves the file location" do - model = literal(1) - adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(model.current) - adapter.locator = Puppet::Pops::Parser::Locator.locator("\n\n1",filename) - model.record_position(location(2, 1), nil) - - ast = transform(model) - - ast.file.should == filename - ast.line.should == 3 - ast.pos.should == 1 - end - - def transform(model) - transformer.transform(model) - end - - def location(offset, length) - Puppet::Pops::Parser::Locatable::Fixed.new(offset, length) - end -end diff --git a/spec/unit/pops/transformer/transform_basic_expressions_spec.rb b/spec/unit/pops/transformer/transform_basic_expressions_spec.rb deleted file mode 100644 index dda35002c..000000000 --- a/spec/unit/pops/transformer/transform_basic_expressions_spec.rb +++ /dev/null @@ -1,243 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' -require 'puppet/pops' - -# relative to this spec file (./) does not work as this file is loaded by rspec -require File.join(File.dirname(__FILE__), '/transformer_rspec_helper') - -describe "transformation to Puppet AST for basic expressions" do - include TransformerRspecHelper - - context "When transforming arithmetic" do - context "with Integers" do - it "$a = 2 + 2" do; astdump(parse("$a = 2 + 2")).should == "(= $a (+ 2 2))" ; end - it "$a = 7 - 3" do; astdump(parse("$a = 7 - 3")).should == "(= $a (- 7 3))" ; end - it "$a = 6 * 3" do; astdump(parse("$a = 6 * 3")).should == "(= $a (* 6 3))" ; end - it "$a = 6 / 3" do; astdump(parse("$a = 6 / 3")).should == "(= $a (/ 6 3))" ; end - it "$a = 6 % 3" do; astdump(parse("$a = 6 % 3")).should == "(= $a (% 6 3))" ; end - it "$a = -(6/3)" do; astdump(parse("$a = -(6/3)")).should == "(= $a (- (/ 6 3)))" ; end - it "$a = -6/3" do; astdump(parse("$a = -6/3")).should == "(= $a (/ (- 6) 3))" ; end - it "$a = 8 >> 1 " do; astdump(parse("$a = 8 >> 1")).should == "(= $a (>> 8 1))" ; end - it "$a = 8 << 1 " do; astdump(parse("$a = 8 << 1")).should == "(= $a (<< 8 1))" ; end - end - - context "with Floats" do - it "$a = 2.2 + 2.2" do; astdump(parse("$a = 2.2 + 2.2")).should == "(= $a (+ 2.2 2.2))" ; end - it "$a = 7.7 - 3.3" do; astdump(parse("$a = 7.7 - 3.3")).should == "(= $a (- 7.7 3.3))" ; end - it "$a = 6.1 * 3.1" do; astdump(parse("$a = 6.1 - 3.1")).should == "(= $a (- 6.1 3.1))" ; end - it "$a = 6.6 / 3.3" do; astdump(parse("$a = 6.6 / 3.3")).should == "(= $a (/ 6.6 3.3))" ; end - it "$a = -(6.0/3.0)" do; astdump(parse("$a = -(6.0/3.0)")).should == "(= $a (- (/ 6.0 3.0)))" ; end - it "$a = -6.0/3.0" do; astdump(parse("$a = -6.0/3.0")).should == "(= $a (/ (- 6.0) 3.0))" ; end - it "$a = 3.14 << 2" do; astdump(parse("$a = 3.14 << 2")).should == "(= $a (<< 3.14 2))" ; end - it "$a = 3.14 >> 2" do; astdump(parse("$a = 3.14 >> 2")).should == "(= $a (>> 3.14 2))" ; end - end - - context "with hex and octal Integer values" do - it "$a = 0xAB + 0xCD" do; astdump(parse("$a = 0xAB + 0xCD")).should == "(= $a (+ 0xAB 0xCD))" ; end - it "$a = 0777 - 0333" do; astdump(parse("$a = 0777 - 0333")).should == "(= $a (- 0777 0333))" ; end - end - - context "with strings requiring boxing to Numeric" do - # In AST, there is no difference, the ast dumper prints all numbers without quotes - they are still - # strings - it "$a = '2' + '2'" do; astdump(parse("$a = '2' + '2'")).should == "(= $a (+ 2 2))" ; end - it "$a = '2.2' + '0.2'" do; astdump(parse("$a = '2.2' + '0.2'")).should == "(= $a (+ 2.2 0.2))" ; end - it "$a = '0xab' + '0xcd'" do; astdump(parse("$a = '0xab' + '0xcd'")).should == "(= $a (+ 0xab 0xcd))" ; end - it "$a = '0777' + '0333'" do; astdump(parse("$a = '0777' + '0333'")).should == "(= $a (+ 0777 0333))" ; end - end - - context "precedence should be correct" do - it "$a = 1 + 2 * 3" do; astdump(parse("$a = 1 + 2 * 3")).should == "(= $a (+ 1 (* 2 3)))"; end - it "$a = 1 + 2 % 3" do; astdump(parse("$a = 1 + 2 % 3")).should == "(= $a (+ 1 (% 2 3)))"; end - it "$a = 1 + 2 / 3" do; astdump(parse("$a = 1 + 2 / 3")).should == "(= $a (+ 1 (/ 2 3)))"; end - it "$a = 1 + 2 << 3" do; astdump(parse("$a = 1 + 2 << 3")).should == "(= $a (<< (+ 1 2) 3))"; end - it "$a = 1 + 2 >> 3" do; astdump(parse("$a = 1 + 2 >> 3")).should == "(= $a (>> (+ 1 2) 3))"; end - end - - context "parentheses alter precedence" do - it "$a = (1 + 2) * 3" do; astdump(parse("$a = (1 + 2) * 3")).should == "(= $a (* (+ 1 2) 3))"; end - it "$a = (1 + 2) / 3" do; astdump(parse("$a = (1 + 2) / 3")).should == "(= $a (/ (+ 1 2) 3))"; end - end - end - - context "When transforming boolean operations" do - context "using operators AND OR NOT" do - it "$a = true and true" do; astdump(parse("$a = true and true")).should == "(= $a (&& true true))"; end - it "$a = true or true" do; astdump(parse("$a = true or true")).should == "(= $a (|| true true))" ; end - it "$a = !true" do; astdump(parse("$a = !true")).should == "(= $a (! true))" ; end - end - - context "precedence should be correct" do - it "$a = false or true and true" do - astdump(parse("$a = false or true and true")).should == "(= $a (|| false (&& true true)))" - end - - it "$a = (false or true) and true" do - astdump(parse("$a = (false or true) and true")).should == "(= $a (&& (|| false true) true))" - end - - it "$a = !true or true and true" do - astdump(parse("$a = !false or true and true")).should == "(= $a (|| (! false) (&& true true)))" - end - end - - # Possibly change to check of literal expressions - context "on values requiring boxing to Boolean" do - it "'x' == true" do - astdump(parse("! 'x'")).should == "(! 'x')" - end - - it "'' == false" do - astdump(parse("! ''")).should == "(! '')" - end - - it ":undef == false" do - astdump(parse("! undef")).should == "(! :undef)" - end - end - end - - context "When transforming comparisons" do - context "of string values" do - it "$a = 'a' == 'a'" do; astdump(parse("$a = 'a' == 'a'")).should == "(= $a (== 'a' 'a'))" ; end - it "$a = 'a' != 'a'" do; astdump(parse("$a = 'a' != 'a'")).should == "(= $a (!= 'a' 'a'))" ; end - it "$a = 'a' < 'b'" do; astdump(parse("$a = 'a' < 'b'")).should == "(= $a (< 'a' 'b'))" ; end - it "$a = 'a' > 'b'" do; astdump(parse("$a = 'a' > 'b'")).should == "(= $a (> 'a' 'b'))" ; end - it "$a = 'a' <= 'b'" do; astdump(parse("$a = 'a' <= 'b'")).should == "(= $a (<= 'a' 'b'))" ; end - it "$a = 'a' >= 'b'" do; astdump(parse("$a = 'a' >= 'b'")).should == "(= $a (>= 'a' 'b'))" ; end - end - - context "of integer values" do - it "$a = 1 == 1" do; astdump(parse("$a = 1 == 1")).should == "(= $a (== 1 1))" ; end - it "$a = 1 != 1" do; astdump(parse("$a = 1 != 1")).should == "(= $a (!= 1 1))" ; end - it "$a = 1 < 2" do; astdump(parse("$a = 1 < 2")).should == "(= $a (< 1 2))" ; end - it "$a = 1 > 2" do; astdump(parse("$a = 1 > 2")).should == "(= $a (> 1 2))" ; end - it "$a = 1 <= 2" do; astdump(parse("$a = 1 <= 2")).should == "(= $a (<= 1 2))" ; end - it "$a = 1 >= 2" do; astdump(parse("$a = 1 >= 2")).should == "(= $a (>= 1 2))" ; end - end - - context "of regular expressions (parse errors)" do - # Not supported in concrete syntax (until Lexer2) - it "$a = /.*/ == /.*/" do - astdump(parse("$a = /.*/ == /.*/")).should == "(= $a (== /.*/ /.*/))" - end - - it "$a = /.*/ != /a.*/" do - astdump(parse("$a = /.*/ != /.*/")).should == "(= $a (!= /.*/ /.*/))" - end - end - end - - context "When transforming Regular Expression matching" do - it "$a = 'a' =~ /.*/" do; astdump(parse("$a = 'a' =~ /.*/")).should == "(= $a (=~ 'a' /.*/))" ; end - it "$a = 'a' =~ '.*'" do; astdump(parse("$a = 'a' =~ '.*'")).should == "(= $a (=~ 'a' '.*'))" ; end - it "$a = 'a' !~ /b.*/" do; astdump(parse("$a = 'a' !~ /b.*/")).should == "(= $a (!~ 'a' /b.*/))" ; end - it "$a = 'a' !~ 'b.*'" do; astdump(parse("$a = 'a' !~ 'b.*'")).should == "(= $a (!~ 'a' 'b.*'))" ; end - end - - context "When transforming Lists" do - it "$a = []" do - astdump(parse("$a = []")).should == "(= $a ([]))" - end - - it "$a = [1]" do - astdump(parse("$a = [1]")).should == "(= $a ([] 1))" - end - - it "$a = [1,2,3]" do - astdump(parse("$a = [1,2,3]")).should == "(= $a ([] 1 2 3))" - end - - it "[...[...[]]] should create nested arrays without trouble" do - astdump(parse("$a = [1,[2.0, 2.1, [2.2]],[3.0, 3.1]]")).should == "(= $a ([] 1 ([] 2.0 2.1 ([] 2.2)) ([] 3.0 3.1)))" - end - - it "$a = [2 + 2]" do - astdump(parse("$a = [2+2]")).should == "(= $a ([] (+ 2 2)))" - end - - it "$a [1,2,3] == [1,2,3]" do - astdump(parse("$a = [1,2,3] == [1,2,3]")).should == "(= $a (== ([] 1 2 3) ([] 1 2 3)))" - end - end - - context "When transforming indexed access" do - it "$a = $b[2]" do - astdump(parse("$a = $b[2]")).should == "(= $a (slice $b 2))" - end - - it "$a = [1, 2, 3][2]" do - astdump(parse("$a = [1,2,3][2]")).should == "(= $a (slice ([] 1 2 3) 2))" - end - - it "$a = {'a' => 1, 'b' => 2}['b']" do - astdump(parse("$a = {'a'=>1,'b' =>2}[b]")).should == "(= $a (slice ({} ('a' 1) ('b' 2)) b))" - end - end - - context "When transforming Hashes" do - it "should create a Hash when evaluating a LiteralHash" do - astdump(parse("$a = {'a'=>1,'b'=>2}")).should == "(= $a ({} ('a' 1) ('b' 2)))" - end - - it "$a = {...{...{}}} should create nested hashes without trouble" do - astdump(parse("$a = {'a'=>1,'b'=>{'x'=>2.1,'y'=>2.2}}")).should == "(= $a ({} ('a' 1) ('b' ({} ('x' 2.1) ('y' 2.2)))))" - end - - it "$a = {'a'=> 2 + 2} should evaluate values in entries" do - astdump(parse("$a = {'a'=>2+2}")).should == "(= $a ({} ('a' (+ 2 2))))" - end - - it "$a = {'a'=> 1, 'b'=>2} == {'a'=> 1, 'b'=>2}" do - astdump(parse("$a = {'a'=>1,'b'=>2} == {'a'=>1,'b'=>2}")).should == "(= $a (== ({} ('a' 1) ('b' 2)) ({} ('a' 1) ('b' 2))))" - end - - it "$a = {'a'=> 1, 'b'=>2} != {'x'=> 1, 'y'=>3}" do - astdump(parse("$a = {'a'=>1,'b'=>2} != {'a'=>1,'b'=>2}")).should == "(= $a (!= ({} ('a' 1) ('b' 2)) ({} ('a' 1) ('b' 2))))" - end - end - - context "When transforming the 'in' operator" do - it "with integer in a list" do - astdump(parse("$a = 1 in [1,2,3]")).should == "(= $a (in 1 ([] 1 2 3)))" - end - - it "with string key in a hash" do - astdump(parse("$a = 'a' in {'x'=>1, 'a'=>2, 'y'=> 3}")).should == "(= $a (in 'a' ({} ('a' 2) ('x' 1) ('y' 3))))" - end - - it "with substrings of a string" do - astdump(parse("$a = 'ana' in 'bananas'")).should == "(= $a (in 'ana' 'bananas'))" - end - - it "with sublist in a list" do - astdump(parse("$a = [2,3] in [1,2,3]")).should == "(= $a (in ([] 2 3) ([] 1 2 3)))" - end - end - - context "When transforming string interpolation" do - it "should interpolate a bare word as a variable name, \"${var}\"" do - astdump(parse("$a = \"$var\"")).should == "(= $a (cat '' (str $var) ''))" - end - - it "should interpolate a variable in a text expression, \"${$var}\"" do - astdump(parse("$a = \"${$var}\"")).should == "(= $a (cat '' (str $var) ''))" - end - - it "should interpolate two variables in a text expression" do - astdump(parse(%q{$a = "xxx $x and $y end"})).should == "(= $a (cat 'xxx ' (str $x) ' and ' (str $y) ' end'))" - end - - it "should interpolate one variables followed by parentheses" do - astdump(parse(%q{$a = "xxx ${x} (yay)"})).should == "(= $a (cat 'xxx ' (str $x) ' (yay)'))" - end - - it "should interpolate a variable, \"yo${var}yo\"" do - astdump(parse("$a = \"yo${var}yo\"")).should == "(= $a (cat 'yo' (str $var) 'yo'))" - end - - it "should interpolate any expression in a text expression, \"${var*2}\"" do - astdump(parse("$a = \"yo${$var+2}yo\"")).should == "(= $a (cat 'yo' (str (+ $var 2)) 'yo'))" - end - end -end diff --git a/spec/unit/pops/transformer/transform_calls_spec.rb b/spec/unit/pops/transformer/transform_calls_spec.rb deleted file mode 100644 index dba0d560f..000000000 --- a/spec/unit/pops/transformer/transform_calls_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' -require 'puppet/pops' - -# relative to this spec file (./) does not work as this file is loaded by rspec -require File.join(File.dirname(__FILE__), '/transformer_rspec_helper') - -describe "transformation to Puppet AST for function calls" do - include TransformerRspecHelper - - context "When transforming calls as statements" do - context "in top level scope" do - it "foo()" do - astdump(parse("foo()")).should == "(invoke foo)" - end - - it "notice bar" do - astdump(parse("notice bar")).should == "(invoke notice bar)" - end - end - - context "in nested scopes" do - it "if true { foo() }" do - astdump(parse("if true {foo()}")).should == "(if true\n (then (invoke foo)))" - end - - it "if true { notice bar}" do - astdump(parse("if true {notice bar}")).should == "(if true\n (then (invoke notice bar)))" - end - end - context "in general" do - { - "require bar" => '(invoke require bar)', - "realize bar" => '(invoke realize bar)', - "contain bar" => '(invoke contain bar)', - "include bar" => '(invoke include bar)', - "tag bar" => '(invoke tag bar)', - - "info bar" => '(invoke info bar)', - "notice bar" => '(invoke notice bar)', - "error bar" => '(invoke error bar)', - "warning bar" => '(invoke warning bar)', - "debug bar" => '(invoke debug bar)', - - "fail bar" => '(invoke fail bar)', - - "notice {a => 1}" => "(invoke notice ({} ('a' 1)))", - "notice 1,2,3" => "(invoke notice 1 2 3)", - "notice(1,2,3)" => "(invoke notice 1 2 3)", - }.each do |source, result| - it "should transform #{source} to #{result}" do - astdump(parse(source)).should == result - end - end - - { - "foo bar" => '(block foo bar)', - "tag" => 'tag', - }.each do |source, result| - it "should not transform #{source}, and instead produce #{result}" do - astdump(parse(source)).should == result - end - end - - end - end - - context "When transforming calls as expressions" do - it "$a = foo()" do - astdump(parse("$a = foo()")).should == "(= $a (call foo))" - end - - it "$a = foo(bar)" do - astdump(parse("$a = foo()")).should == "(= $a (call foo))" - end - - # For egrammar where a bare word can be a "statement" - it "$a = foo bar # assignment followed by bare word is ok in egrammar" do - astdump(parse("$a = foo bar")).should == "(block (= $a foo) bar)" - end - - context "in nested scopes" do - it "if true { $a = foo() }" do - astdump(parse("if true { $a = foo()}")).should == "(if true\n (then (= $a (call foo))))" - end - - it "if true { $a= foo(bar)}" do - astdump(parse("if true {$a = foo(bar)}")).should == "(if true\n (then (= $a (call foo bar))))" - end - end - end - - context "When transforming method calls" do - it "$a.foo" do - astdump(parse("$a.foo")).should == "(call-method (. $a foo))" - end - - it "$a.foo || { }" do - astdump(parse("$a.foo || { }")).should == "(call-method (. $a foo) (lambda ()))" - end - - it "$a.foo ||{[]} # check transformation to block with empty array" do - astdump(parse("$a.foo || {[]}")).should == "(call-method (. $a foo) (lambda (block ([]))))" - end - - it "$a.foo |$x| { }" do - astdump(parse("$a.foo |$x| { }")).should == "(call-method (. $a foo) (lambda (parameters x) ()))" - end - - it "$a.foo |$x| { $b = $x}" do - astdump(parse("$a.foo |$x| { $b = $x}")).should == - "(call-method (. $a foo) (lambda (parameters x) (block (= $b $x))))" - end - end -end diff --git a/spec/unit/pops/transformer/transform_conditionals_spec.rb b/spec/unit/pops/transformer/transform_conditionals_spec.rb deleted file mode 100644 index 02b0de4a8..000000000 --- a/spec/unit/pops/transformer/transform_conditionals_spec.rb +++ /dev/null @@ -1,123 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' -require 'puppet/pops' - -# relative to this spec file (./) does not work as this file is loaded by rspec -require File.join(File.dirname(__FILE__), '/transformer_rspec_helper') - -describe "transformation to Puppet AST for conditionals" do - include TransformerRspecHelper - - context "When transforming if statements" do - it "if true { $a = 10 }" do - astdump(parse("if true { $a = 10 }")).should == "(if true\n (then (= $a 10)))" - end - - it "if true { $a = 10 } else {$a = 20}" do - astdump(parse("if true { $a = 10 } else {$a = 20}")).should == - ["(if true", - " (then (= $a 10))", - " (else (= $a 20)))"].join("\n") - end - - it "if true { $a = 10 } elsif false { $a = 15} else {$a = 20}" do - astdump(parse("if true { $a = 10 } elsif false { $a = 15} else {$a = 20}")).should == - ["(if true", - " (then (= $a 10))", - " (else (if false", - " (then (= $a 15))", - " (else (= $a 20)))))"].join("\n") - end - - it "if true { $a = 10 $b = 10 } else {$a = 20}" do - astdump(parse("if true { $a = 10 $b = 20} else {$a = 20}")).should == - ["(if true", - " (then (block (= $a 10) (= $b 20)))", - " (else (= $a 20)))"].join("\n") - end - end - - context "When transforming unless statements" do - # Note that Puppet 3.1 does not have an "unless x", it is encoded as "if !x" - it "unless true { $a = 10 }" do - astdump(parse("unless true { $a = 10 }")).should == "(if (! true)\n (then (= $a 10)))" - end - - it "unless true { $a = 10 } else {$a = 20}" do - astdump(parse("unless true { $a = 10 } else {$a = 20}")).should == - ["(if (! true)", - " (then (= $a 10))", - " (else (= $a 20)))"].join("\n") - end - - it "unless true { $a = 10 } elsif false { $a = 15} else {$a = 20} # is illegal" do - expect { parse("unless true { $a = 10 } elsif false { $a = 15} else {$a = 20}")}.to raise_error(Puppet::ParseError) - end - end - - context "When transforming selector expressions" do - it "$a = $b ? banana => fruit " do - astdump(parse("$a = $b ? banana => fruit")).should == - "(= $a (? $b (banana => fruit)))" - end - - it "$a = $b ? { banana => fruit}" do - astdump(parse("$a = $b ? { banana => fruit }")).should == - "(= $a (? $b (banana => fruit)))" - end - - it "$a = $b ? { banana => fruit, grape => berry }" do - astdump(parse("$a = $b ? {banana => fruit, grape => berry}")).should == - "(= $a (? $b (banana => fruit) (grape => berry)))" - end - - it "$a = $b ? { banana => fruit, grape => berry, default => wat }" do - astdump(parse("$a = $b ? {banana => fruit, grape => berry, default => wat}")).should == - "(= $a (? $b (banana => fruit) (grape => berry) (:default => wat)))" - end - - it "$a = $b ? { default => wat, banana => fruit, grape => berry, }" do - astdump(parse("$a = $b ? {default => wat, banana => fruit, grape => berry}")).should == - "(= $a (? $b (:default => wat) (banana => fruit) (grape => berry)))" - end - end - - context "When transforming case statements" do - it "case $a { a : {}}" do - astdump(parse("case $a { a : {}}")).should == - ["(case $a", - " (when (a) (then ())))" - ].join("\n") - end - - it "case $a { /.*/ : {}}" do - astdump(parse("case $a { /.*/ : {}}")).should == - ["(case $a", - " (when (/.*/) (then ())))" - ].join("\n") - end - - it "case $a { a, b : {}}" do - astdump(parse("case $a { a, b : {}}")).should == - ["(case $a", - " (when (a b) (then ())))" - ].join("\n") - end - - it "case $a { a, b : {} default : {}}" do - astdump(parse("case $a { a, b : {} default : {}}")).should == - ["(case $a", - " (when (a b) (then ()))", - " (when (:default) (then ())))" - ].join("\n") - end - - it "case $a { a : {$b = 10 $c = 20}}" do - astdump(parse("case $a { a : {$b = 10 $c = 20}}")).should == - ["(case $a", - " (when (a) (then (block (= $b 10) (= $c 20)))))" - ].join("\n") - end - end - -end diff --git a/spec/unit/pops/transformer/transform_containers_spec.rb b/spec/unit/pops/transformer/transform_containers_spec.rb deleted file mode 100644 index c57998eed..000000000 --- a/spec/unit/pops/transformer/transform_containers_spec.rb +++ /dev/null @@ -1,190 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' -require 'puppet/pops' - -# relative to this spec file (./) does not work as this file is loaded by rspec -require File.join(File.dirname(__FILE__), '/transformer_rspec_helper') - -describe "transformation to Puppet AST for containers" do - include TransformerRspecHelper - - context "When transforming file scope" do - it "$a = 10 $b = 20" do - astdump(parse("$a = 10 $b = 20")).should == "(block (= $a 10) (= $b 20))" - end - - it "$a = 10" do - astdump(parse("$a = 10")).should == "(= $a 10)" - end - end - - context "When transforming class" do - it "class foo {}" do - astdump(parse("class foo {}")).should == "(class foo ())" - end - - it "class foo::bar {}" do - astdump(parse("class foo::bar {}")).should == "(class foo::bar ())" - end - - it "class foo inherits bar {}" do - astdump(parse("class foo inherits bar {}")).should == "(class foo (inherits bar) ())" - end - - it "class foo($a) {}" do - astdump(parse("class foo($a) {}")).should == "(class foo (parameters a) ())" - end - - it "class foo($a, $b) {}" do - astdump(parse("class foo($a, $b) {}")).should == "(class foo (parameters a b) ())" - end - - it "class foo($a, $b=10) {}" do - astdump(parse("class foo($a, $b=10) {}")).should == "(class foo (parameters a (= b 10)) ())" - end - - it "class foo($a, $b) inherits belgo::bar {}" do - astdump(parse("class foo($a, $b) inherits belgo::bar{}")).should == "(class foo (inherits belgo::bar) (parameters a b) ())" - end - - it "class foo {$a = 10 $b = 20}" do - astdump(parse("class foo {$a = 10 $b = 20}")).should == "(class foo (block (= $a 10) (= $b 20)))" - end - - context "it should handle '3x weirdness'" do - it "class class {} # a class named 'class'" do - # Not as much weird as confusing that it is possible to name a class 'class'. Can have - # a very confusing effect when resolving relative names, getting the global hardwired "Class" - # instead of some foo::class etc. - # This is allowed in 3.x. - expect { - astdump(parse("class class {}")).should == "(class class ())" - }.to raise_error(/is not a valid classname/) - end - - it "class default {} # a class named 'default'" do - # The weirdness here is that a class can inherit 'default' but not declare a class called default. - # (It will work with relative names i.e. foo::default though). The whole idea with keywords as - # names is flawed to begin with - it generally just a very bad idea. - expect { dump(parse("class default {}")).should == "(class default ())" }.to raise_error(Puppet::ParseError) - end - - it "class foo::default {} # a nested name 'default'" do - astdump(parse("class foo::default {}")).should == "(class foo::default ())" - end - - it "class class inherits default {} # inherits default", :broken => true do - astdump(parse("class class inherits default {}")).should == "(class class (inherits default) ())" - end - - it "class class inherits default {} # inherits default" do - # TODO: See previous test marked as :broken=>true, it is actually this test (result) that is wacky, - # this because a class is named at parse time (since class evaluation is lazy, the model must have the - # full class name for nested classes - only, it gets this wrong when a class is named "class" - or at least - # I think it is wrong.) - # - expect { - astdump(parse("class class inherits default {}")).should == "(class class::class (inherits default) ())" - }.to raise_error(/is not a valid classname/) - end - - it "class foo inherits class" do - expect { - astdump(parse("class foo inherits class {}")).should == "(class foo (inherits class) ())" - }.to raise_error(/is not a valid classname/) - end - end - end - - context "When transforming define" do - it "define foo {}" do - astdump(parse("define foo {}")).should == "(define foo ())" - end - - it "define foo::bar {}" do - astdump(parse("define foo::bar {}")).should == "(define foo::bar ())" - end - - it "define foo($a) {}" do - astdump(parse("define foo($a) {}")).should == "(define foo (parameters a) ())" - end - - it "define foo($a, $b) {}" do - astdump(parse("define foo($a, $b) {}")).should == "(define foo (parameters a b) ())" - end - - it "define foo($a, $b=10) {}" do - astdump(parse("define foo($a, $b=10) {}")).should == "(define foo (parameters a (= b 10)) ())" - end - - it "define foo {$a = 10 $b = 20}" do - astdump(parse("define foo {$a = 10 $b = 20}")).should == "(define foo (block (= $a 10) (= $b 20)))" - end - - context "it should handle '3x weirdness'" do - it "define class {} # a define named 'class'" do - # This is weird because Class already exists, and instantiating this define will probably not - # work - expect { - astdump(parse("define class {}")).should == "(define class ())" - }.to raise_error(/is not a valid classname/) - end - - it "define default {} # a define named 'default'" do - # Check unwanted ability to define 'default'. - # The expression below is not allowed (which is good). - # - expect { dump(parse("define default {}")).should == "(define default ())"}.to raise_error(Puppet::ParseError) - end - end - end - - context "When transforming node" do - it "node foo {}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo {}")).should == "(node (matches 'foo') ())" - end - - it "node foo, x.bar, default {}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo, x_bar, default {}")).should == "(node (matches 'foo' 'x_bar' :default) ())" - end - - it "node 'foo' {}" do - # AST can not differentiate between bare word and string - astdump(parse("node 'foo' {}")).should == "(node (matches 'foo') ())" - end - - it "node foo inherits x::bar {}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo inherits x_bar {}")).should == "(node (matches 'foo') (parent x_bar) ())" - end - - it "node foo inherits 'bar' {}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo inherits 'bar' {}")).should == "(node (matches 'foo') (parent bar) ())" - end - - it "node foo inherits default {}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo inherits default {}")).should == "(node (matches 'foo') (parent default) ())" - end - - it "node /web.*/ {}" do - astdump(parse("node /web.*/ {}")).should == "(node (matches /web.*/) ())" - end - - it "node /web.*/, /do\.wop.*/, and.so.on {}" do - astdump(parse("node /web.*/, /do\.wop.*/, 'and.so.on' {}")).should == "(node (matches /web.*/ /do\.wop.*/ 'and.so.on') ())" - end - - it "node wat inherits /apache.*/ {}" do - astdump(parse("node wat inherits /apache.*/ {}")).should == "(node (matches 'wat') (parent /apache.*/) ())" - end - - it "node foo inherits bar {$a = 10 $b = 20}" do - # AST can not differentiate between bare word and string - astdump(parse("node foo inherits bar {$a = 10 $b = 20}")).should == "(node (matches 'foo') (parent bar) (block (= $a 10) (= $b 20)))" - end - end -end diff --git a/spec/unit/pops/transformer/transformer_rspec_helper.rb b/spec/unit/pops/transformer/transformer_rspec_helper.rb deleted file mode 100644 index 94c3f02c1..000000000 --- a/spec/unit/pops/transformer/transformer_rspec_helper.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'puppet/pops' -require 'puppet/parser/ast' - -require File.join(File.dirname(__FILE__), '/../factory_rspec_helper') - -module TransformerRspecHelper - include FactoryRspecHelper - # Dumps the AST to string form - # - def astdump(ast) - ast = transform(ast) unless ast.kind_of?(Puppet::Parser::AST) - Puppet::Pops::Model::AstTreeDumper.new.dump(ast) - end - - # Transforms the Pops model to an AST model - # - def transform(model) - Puppet::Pops::Model::AstTransformer.new.transform(model) - end - - # Parses the string code to a Pops model - # - def parse(code) - parser = Puppet::Pops::Parser::Parser.new() - parser.parse_string(code) - end -end