From 4da88fb4cd57871f16649d50572240ac3f7420f0 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Fri, 13 Aug 2010 15:43:34 -0700 Subject: [#4496]+[#4521]+[#4522] Add structures to the AST to represent type definitions (classes, definitions, and nodes). Previously, type definitions were not represented directly in the AST. Instead, the parser would instantiate types and insert them into known_resource_types as soon as they were parsed. This made it difficult to distinguish which types had come from the file that was just parsed and which types had been loaded previously, which led to bug 4496. A side-effect of this change is that the user is no longer allowed to define types inside of conditional constructs (such as if/else). This was allowed before but had unexpected semantics (bugs 4521 and 4522). It is still possible, however, to place an "include" statement inside a conditional construct, and have that "include" statement trigger the autoloading of a file that instantiates types. --- spec/unit/parser/parser_spec.rb | 96 +++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 43 deletions(-) (limited to 'spec/unit/parser/parser_spec.rb') diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 0657ab37a..0a61e73de 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -73,14 +73,16 @@ describe Puppet::Parser do lambda { @parser.parse("$var += ") }.should raise_error end - it "should call ast::VarDef with append=true" do - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += 2") + 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 - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += ['test']") + vardef = @parser.parse("$var += ['test']").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true end end @@ -160,10 +162,14 @@ describe Puppet::Parser do end it "should create an ast::ResourceOverride" do - ast::ResourceOverride.expects(:new).with { |arg| - arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) - } - @parser.parse('Resource["title1","title2"] { param => value }') + #ast::ResourceOverride.expects(:new).with { |arg| + # arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) + #} + ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] + ro.should be_a(ast::ResourceOverride) + ro.line.should == 1 + ro.object.should be_a(ast::ResourceReference) + ro.parameters[0].should be_a(ast::ResourceParam) end end @@ -290,24 +296,6 @@ describe Puppet::Parser do end end - describe "when creating a node" do - before :each do - @lexer = stub 'lexer' - @lexer.stubs(:getcomment) - @parser.stubs(:lexer).returns(@lexer) - @node = stub_everything 'node' - @parser.stubs(:ast_context).returns({}) - @parser.stubs(:node).returns(nil) - - @nodename = stub 'nodename', :is_a? => false, :value => "foo" - @nodename.stubs(:is_a?).with(Puppet::Parser::AST::HostName).returns(true) - end - - it "should return an array of nodes" do - @parser.newnode(@nodename).should be_instance_of(Array) - 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") @@ -360,30 +348,28 @@ describe Puppet::Parser do @parser.stubs(:known_resource_types).returns @krt end - it "should create new classes" do - @parser.parse("class foobar {}") - @krt.hostclass("foobar").should be_instance_of(Puppet::Resource::Type) + 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 {}") - @krt.hostclass("foobar").parent.should == "yayness" + @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 - @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}") - @krt.hostclass("foobar").parent.should == "yayness" - @krt.hostclass("boo").parent.should == "bar" + 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 }") - @krt.hostclass("foobar").code.should_not be_nil + @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil end it "should define parameters when provided" do - @parser.parse("class foobar($biz,$baz) {}") - @krt.hostclass("foobar").arguments.should == {"biz" => nil, "baz" => nil} + foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] + foobar.arguments.should == {"biz" => nil, "baz" => nil} end end @@ -400,13 +386,37 @@ describe Puppet::Parser do end it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }") - @krt.hostclass("").code[0].exported.should be_true + @parser.parse("@@file { '/file': }").code[0][0].exported.should be_true end it "should correctly mark virtual resources as virtual" do - @parser.parse("@file { '/file': }") - @krt.hostclass("").code[0].virtual.should be_true + @parser.parse("@file { '/file': }").code[0][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 end -- cgit From df088c9ba16dce50c17a79920c1ac186db67b9e9 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Wed, 25 Aug 2010 11:29:23 -0700 Subject: [4638] Cleanup of plurals and inheritance relationships in AST Changed the grammar so that the following "plural" constructs always parse as an ASTArray: - funcvalues - rvalues - resourceinstances - anyparams - params - caseopts - casevalues And the following "singluar" construct never parses as an ASTArray: - statement The previous behavior was for these constructs to parse as a scalar when they represented a single item and an ASTArray when they contained zero or multiple items. ("Statement" could sometimes represent a single item because a single resource declaration could represent multiple resources). This complicated other grammar rules and caused ambiguous handling of nested arrays. Also made these changes to the AST class hierarchy: - ResourceInstance no longer derives from ASTArray. This relationship was not meaningful because a ResourceInstance is a (title, parameters) pair, not an array, and it produced complications when we wanted to represent an array of ResourceInstance objects. - Resource no longer derives from ResourceReference. No significant functionality was being inherited and the relationship doesn't make sense in an AST context. - ResourceOverride no longer derives from Resource. No significant functionality was being inherited and the relationship doesn't make sense in an AST context. - Resource can now represent a compound resource instance such as "notify { foo: ; bar: }". This saves the parser from having to use represent a statement as an array of objects. - ASTArray's evaluate method never flattens out arrays of arrays. --- spec/unit/parser/parser_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'spec/unit/parser/parser_spec.rb') diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 0a61e73de..bf4ef0cf1 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -143,7 +143,6 @@ describe Puppet::Parser do end it "should create an ast::ResourceReference" do - ast::Resource.stubs(:new) ast::ResourceReference.expects(:new).with { |arg| arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) } @@ -386,11 +385,11 @@ describe Puppet::Parser do end it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }").code[0][0].exported.should be_true + @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][0].virtual.should be_true + @parser.parse("@file { '/file': }").code[0].virtual.should be_true end end -- cgit From f95006148c3a0b4d7e8ee1812b1993b674f050e4 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Fri, 3 Sep 2010 11:17:35 -0700 Subject: [#4716] ResourceTypeAPI exposes implementation details that are likely to change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made the following modifications to ResourceTypeAPI: (1) returned nil from “define”, “hostclass”, and “node”. (2) renamed “mk_resource_type” and “munge_type_arguments” to “__mk_resource_type__” and “__munge_type_arguments__” to discourage customers from calling them. (3) Made ResourceTypeAPI a class rather than a module, and changed the parser to evaluate the contents of pure ruby manifests using a instances of this class. (4) Changed ResourceTypeAPI to insert newly instantiated types into Thread.current[:known_resource_types] rather than the default environment's known_resource_types. This effectively backports the fix for issue #4657 to 2.6.x. Also backported the new spec tests from #4657. --- spec/unit/parser/parser_spec.rb | 9 --------- 1 file changed, 9 deletions(-) (limited to 'spec/unit/parser/parser_spec.rb') diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 0657ab37a..f73e07a5c 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -52,15 +52,6 @@ describe Puppet::Parser do @parser.file = "/my/file.rb" @parser.parse end - - describe "in ruby" do - it "should use the ruby interpreter to load the file" do - @parser.file = "/my/file.rb" - @parser.expects(:require).with "/my/file.rb" - - @parser.parse_ruby_file - end - end end describe "when parsing append operator" do -- cgit From 9604f1c4cd5a368da08c6f3219b44908a9b9921c Mon Sep 17 00:00:00 2001 From: Brice Figureau Date: Thu, 11 Nov 2010 15:51:21 +0100 Subject: Fix #5252 - line number mis-attribution during parsing It is a resurgence of #2366 that appeared because of the commit 8971d8. Before this commit, for associating documentation comments, we were preferring line numbers coming from the parser currently reducing rule, instead of the current lexer line number (which can be in advance of several tokens due to the nature of LALR parsers). We now merge the ast line number before fetching the comment from the lexer. Signed-off-by: Brice Figureau --- spec/unit/parser/parser_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'spec/unit/parser/parser_spec.rb') diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index f73e07a5c..07e2d220b 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -269,16 +269,23 @@ describe Puppet::Parser do it "should prefer provided options over AST context" do @class.expects(:new).with { |opts| opts[:file] == "/bar" } - @parser.expects(:ast_context).returns :file => "/foo" + @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(true).returns({}) + @parser.expects(:ast_context).with{ |a| a[0] == 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 creating a node" do -- cgit From cd8126f4422afd452564e37fae501f9c356a751d Mon Sep 17 00:00:00 2001 From: Nick Lewis Date: Wed, 17 Nov 2010 16:52:21 -0800 Subject: maint: Fix intermittent parser spec failures The variable 'ast' was being used as shorthand for Puppet::Parser::AST, but a test was also trying to use it as a local variable, causing problems. --- spec/unit/parser/parser_spec.rb | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'spec/unit/parser/parser_spec.rb') diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 75f505e66..ab43194e9 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Parser do - ast = Puppet::Parser::AST + Puppet::Parser::AST before :each do @known_resource_types = Puppet::Resource::TypeCollection.new("development") @@ -80,21 +80,21 @@ describe Puppet::Parser do describe "when parsing 'if'" do it "not, it should create the correct ast objects" do - ast::Not.expects(:new).with { |h| h[:value].is_a?(ast::Boolean) } + 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 - ast::BooleanOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Boolean) and h[:lval].is_a?(ast::Boolean) and h[:operator]=="or" + 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 - ast::ComparisonOperator.expects(:new).with { - |h| h[:lval].is_a?(ast::Name) and h[:rval].is_a?(ast::Name) and h[:operator]=="<" + 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 }") @@ -105,13 +105,13 @@ describe Puppet::Parser do describe "when parsing if complex expressions" do it "should create a correct ast tree" do aststub = stub_everything 'ast' - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]==">" + 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) - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]=="==" + 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) - ast::BooleanOperator.expects(:new).with { + 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 }") @@ -134,8 +134,8 @@ describe Puppet::Parser do end it "should create an ast::ResourceReference" do - ast::ResourceReference.expects(:new).with { |arg| - arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) + 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 @@ -152,14 +152,14 @@ describe Puppet::Parser do end it "should create an ast::ResourceOverride" do - #ast::ResourceOverride.expects(:new).with { |arg| - # arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) + #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(ast::ResourceOverride) + ro.should be_a(Puppet::Parser::AST::ResourceOverride) ro.line.should == 1 - ro.object.should be_a(ast::ResourceReference) - ro.parameters[0].should be_a(ast::ResourceParam) + ro.object.should be_a(Puppet::Parser::AST::ResourceReference) + ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) end end @@ -179,17 +179,17 @@ describe Puppet::Parser do end it "should create a nop node for empty branch" do - ast::Nop.expects(:new) + Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do - ast::Nop.expects(:new) + 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 - ast = @parser.parse(<<-PP) + lambda { @parser.parse(<<-PP) }.should_not raise_error if true { notice('test') } elsif true {} else { } PP end -- cgit