summaryrefslogtreecommitdiffstats
path: root/lib/puppet/parser/ast
diff options
context:
space:
mode:
authorDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
committerDominic Cleal <dcleal@redhat.com>2010-11-27 13:36:04 +0000
commitafe2d014feb2210a8666c93465d11e9c9d555f8b (patch)
tree208f5ac82b2c29610d2021821c8fca9b079e638b /lib/puppet/parser/ast
parent143fc744a839affd328234fca26246d49d15d3d8 (diff)
parent4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff)
Merge branch 'master' of github.com:domcleal/puppet into master-old
Diffstat (limited to 'lib/puppet/parser/ast')
-rw-r--r--lib/puppet/parser/ast/astarray.rb35
-rw-r--r--lib/puppet/parser/ast/caseopt.rb36
-rw-r--r--lib/puppet/parser/ast/collection.rb85
-rw-r--r--lib/puppet/parser/ast/definition.rb17
-rw-r--r--lib/puppet/parser/ast/function.rb3
-rw-r--r--lib/puppet/parser/ast/hostclass.rb29
-rw-r--r--lib/puppet/parser/ast/leaf.rb14
-rw-r--r--lib/puppet/parser/ast/node.rb20
-rw-r--r--lib/puppet/parser/ast/resource.rb92
-rw-r--r--lib/puppet/parser/ast/resource_instance.rb9
-rw-r--r--lib/puppet/parser/ast/resource_override.rb5
-rw-r--r--lib/puppet/parser/ast/resource_reference.rb11
-rw-r--r--lib/puppet/parser/ast/top_level_construct.rb4
13 files changed, 201 insertions, 159 deletions
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb
index 529998e3c..7283a1f6c 100644
--- a/lib/puppet/parser/ast/astarray.rb
+++ b/lib/puppet/parser/ast/astarray.rb
@@ -16,25 +16,20 @@ class Puppet::Parser::AST
# Evaluate our children.
def evaluate(scope)
- # Make a new array, so we don't have to deal with the details of
- # flattening and such
- items = []
-
- # First clean out any AST::ASTArrays
- @children.each { |child|
- if child.instance_of?(AST::ASTArray)
- child.each do |ac|
- items << ac
+ result = []
+ @children.each do |child|
+ # Skip things that respond to :instantiate (classes, nodes,
+ # and definitions), because they have already been
+ # instantiated.
+ if !child.respond_to?(:instantiate)
+ item = child.safeevaluate(scope)
+ if !item.nil?
+ # nil values are implicitly removed.
+ result.push(item)
end
- else
- items << child
end
- }
-
- rets = items.flatten.collect { |child|
- child.safeevaluate(scope)
- }
- rets.reject { |o| o.nil? }
+ end
+ result
end
def push(*ary)
@@ -52,10 +47,4 @@ class Puppet::Parser::AST
"[" + @children.collect { |c| c.to_s }.join(', ') + "]"
end
end
-
- # A simple container class, containing the parameters for an object.
- # Used for abstracting the grammar declarations. Basically unnecessary
- # except that I kept finding bugs because I had too many arrays that
- # meant completely different things.
- class ResourceInstance < ASTArray; end
end
diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb
index 4e296e82f..db4c2b024 100644
--- a/lib/puppet/parser/ast/caseopt.rb
+++ b/lib/puppet/parser/ast/caseopt.rb
@@ -18,16 +18,12 @@ class Puppet::Parser::AST
# Cache the @default value.
return @default if defined?(@default)
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- if subval.is_a?(AST::Default)
- @default = true
- break
- end
- }
- else
- @default = true if @value.is_a?(AST::Default)
- end
+ @value.each { |subval|
+ if subval.is_a?(AST::Default)
+ @default = true
+ break
+ end
+ }
@default ||= false
@@ -36,23 +32,15 @@ class Puppet::Parser::AST
# You can specify a list of values; return each in turn.
def eachvalue(scope)
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- yield subval.safeevaluate(scope)
- }
- else
- yield @value.safeevaluate(scope)
- end
+ @value.each { |subval|
+ yield subval.safeevaluate(scope)
+ }
end
def eachopt
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- yield subval
- }
- else
- yield @value
- end
+ @value.each { |subval|
+ yield subval
+ }
end
# Evaluate the actual statements; this only gets called if
diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb
index 09d5b4eb3..ef36b7143 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -5,61 +5,44 @@ 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)
- if self.query
- str, code = self.query.safeevaluate scope
- else
- str = code = nil
- end
-
- newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form)
-
- scope.compiler.add_collection(newcoll)
-
- # overrides if any
- # Evaluate all of the specified params.
- if @override
- params = @override.collect do |param|
- param.safeevaluate(scope)
+ 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)
+ str, code = query && query.safeevaluate(scope)
+
+ resource_type = scope.find_resource_type(@type)
+ newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, str, 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.add_override(
-
- :parameters => params,
- :file => @file,
- :line => @line,
- :source => scope.source,
-
- :scope => scope
- )
+ newcoll
end
- newcoll
- end
-
- # Handle our parameter ourselves
- def override=(override)
- if override.is_a?(AST::ASTArray)
- @override = override
- else
-
- @override = AST::ASTArray.new(
-
- :line => override.line,
- :file => override.file,
-
- :children => [override]
- )
+ # 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
end
diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb
new file mode 100644
index 000000000..c43422f82
--- /dev/null
+++ b/lib/puppet/parser/ast/definition.rb
@@ -0,0 +1,17 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct
+ attr_accessor :context
+
+ def initialize(name, context = {}, &ruby_code)
+ @name = name
+ @context = context
+ @ruby_code = ruby_code
+ end
+
+ def instantiate(modname)
+ new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname))
+ new_definition.ruby_code = @ruby_code if @ruby_code
+ [new_definition]
+ end
+end
diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb
index 602016c75..80e6e6512 100644
--- a/lib/puppet/parser/ast/function.rb
+++ b/lib/puppet/parser/ast/function.rb
@@ -11,7 +11,6 @@ class Puppet::Parser::AST
@settor = true
def evaluate(scope)
-
# Make sure it's a defined function
raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name)
@@ -29,7 +28,7 @@ class Puppet::Parser::AST
end
# We don't need to evaluate the name, because it's plaintext
- args = @arguments.safeevaluate(scope)
+ args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x }
scope.send("function_#{@name}", args)
end
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb
new file mode 100644
index 000000000..cab5e4a24
--- /dev/null
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -0,0 +1,29 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct
+ attr_accessor :name, :context
+
+ def initialize(name, context = {}, &ruby_code)
+ @context = context
+ @name = name
+ @ruby_code = ruby_code
+ end
+
+ def instantiate(modname)
+ new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname))
+ new_class.ruby_code = @ruby_code if @ruby_code
+ all_types = [new_class]
+ if code
+ code.each do |nested_ast_node|
+ if nested_ast_node.respond_to? :instantiate
+ all_types += nested_ast_node.instantiate(modname)
+ end
+ end
+ end
+ return all_types
+ end
+
+ def code()
+ @context[:code]
+ end
+end
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index 49cde63ca..fcdd219d7 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -42,7 +42,7 @@ class Puppet::Parser::AST
# The base string class.
class String < AST::Leaf
def evaluate(scope)
- @value
+ @value.dup
end
def to_s
@@ -148,12 +148,20 @@ class Puppet::Parser::AST
key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key
end
+ def array_index_or_key(object, key)
+ if object.is_a?(Array)
+ raise Puppet::ParserError, "#{key} is not an integer, but is used as an index of an array" unless key = Puppet::Parser::Scope.number?(key)
+ end
+ key
+ end
+
def evaluate(scope)
object = evaluate_container(scope)
+ accesskey = evaluate_key(scope)
raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array)
- object[evaluate_key(scope)]
+ object[array_index_or_key(object, accesskey)]
end
# Assign value to this hashkey or array index
@@ -166,7 +174,7 @@ class Puppet::Parser::AST
end
# assign to hash or array
- object[accesskey] = value
+ object[array_index_or_key(object, accesskey)] = value
end
def to_s
diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb
new file mode 100644
index 000000000..b69a5c4e0
--- /dev/null
+++ b/lib/puppet/parser/ast/node.rb
@@ -0,0 +1,20 @@
+require 'puppet/parser/ast/top_level_construct'
+
+class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct
+ attr_accessor :names, :context
+
+ def initialize(names, context = {}, &ruby_code)
+ raise ArgumentError, "names should be an array" unless names.is_a? Array
+ @names = names
+ @context = context
+ @ruby_code = ruby_code
+ end
+
+ def instantiate(modname)
+ @names.collect do |name|
+ new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname))
+ new_node.ruby_code = @ruby_code if @ruby_code
+ new_node
+ end
+ end
+end
diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb
index 1b063c984..ce3c499c5 100644
--- a/lib/puppet/parser/ast/resource.rb
+++ b/lib/puppet/parser/ast/resource.rb
@@ -3,26 +3,15 @@ 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::ResourceReference
+class Resource < AST::Branch
associates_doc
- attr_accessor :title, :type, :exported, :virtual
- attr_reader :parameters
+ attr_accessor :type, :instances, :exported, :virtual
# Does not actually return an object; instead sets an object
# in the current scope.
def evaluate(scope)
- # Evaluate all of the specified params.
- paramobjects = parameters.collect { |param|
- param.safeevaluate(scope)
- }
-
- resource_titles = @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)
-
# 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*
@@ -30,48 +19,49 @@ class Resource < AST::ResourceReference
# is true. Argh, this was a very tough one to track down.
virt = self.virtual || self.exported
- # This is where our implicit iteration takes place; if someone
- # passed an array as the name, then we act just like the called us
- # many times.
- resource_titles.flatten.collect { |resource_title|
- exceptwrap :type => Puppet::ParseError do
+ # 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|
- resource = Puppet::Parser::Resource.new(
- type, resource_title,
- :parameters => paramobjects,
- :file => self.file,
- :line => self.line,
- :exported => self.exported,
- :virtual => virt,
- :source => scope.source,
- :scope => scope,
-
- :strict => true
- )
+ # Evaluate all of the specified params.
+ paramobjects = instance.parameters.collect { |param|
+ param.safeevaluate(scope)
+ }
- # And then store the resource in the compiler.
- # At some point, we need to switch all of this to return
- # resources instead of storing them like this.
- scope.compiler.add_resource(scope, resource)
- resource
- end
- }.reject { |resource| resource.nil? }
- end
+ 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)
- # Set the parameters for our object.
- def parameters=(params)
- if params.is_a?(AST::ASTArray)
- @parameters = params
- else
+ # 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
+ )
- @parameters = AST::ASTArray.new(
-
- :line => params.line,
- :file => params.file,
-
- :children => [params]
- )
- end
+ 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) if fully_qualified_type == 'class'
+ resource
+ end
+ }
+ }.flatten.reject { |resource| resource.nil? }
end
end
end
diff --git a/lib/puppet/parser/ast/resource_instance.rb b/lib/puppet/parser/ast/resource_instance.rb
new file mode 100644
index 000000000..ebfb17bf1
--- /dev/null
+++ b/lib/puppet/parser/ast/resource_instance.rb
@@ -0,0 +1,9 @@
+require 'puppet/parser/ast/branch'
+
+class Puppet::Parser::AST
+ class ResourceInstance < Branch
+ # A simple container for a parameter for an object. Consists of a
+ # title and a set of parameters.
+ attr_accessor :title, :parameters
+ end
+end
diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb
index e0be889ff..d638202ab 100644
--- a/lib/puppet/parser/ast/resource_override.rb
+++ b/lib/puppet/parser/ast/resource_override.rb
@@ -3,12 +3,11 @@ 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 < Resource
+ class ResourceOverride < AST::Branch
associates_doc
- attr_accessor :object
- attr_reader :parameters
+ attr_accessor :object, :parameters
# Iterate across all of our children.
def each
diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb
index 5d8334335..0f8e655bf 100644
--- a/lib/puppet/parser/ast/resource_reference.rb
+++ b/lib/puppet/parser/ast/resource_reference.rb
@@ -7,8 +7,15 @@ class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch
# Evaluate our object, but just return a simple array of the type
# and name.
def evaluate(scope)
- titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) }
- return(titles.length == 1 ? titles.pop : titles)
+ titles = Array(title.safeevaluate(scope))
+
+ 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
diff --git a/lib/puppet/parser/ast/top_level_construct.rb b/lib/puppet/parser/ast/top_level_construct.rb
new file mode 100644
index 000000000..901a939c2
--- /dev/null
+++ b/lib/puppet/parser/ast/top_level_construct.rb
@@ -0,0 +1,4 @@
+# The base class for AST nodes representing top level things:
+# hostclasses, definitions, and nodes.
+class Puppet::Parser::AST::TopLevelConstruct < Puppet::Parser::AST
+end