The lexer maintains a stack of last seen comments.
On blank lines the lexer flush the comments.
On each opening brace the lexer enters a new stack level.
On each block AST nodes, the stack is popped.
Each AST nodes has a doc property that is filled with the
last seen comments on node creation (in fact only on important node
creation representing statements).
Signed-off-by: Brice Figureau <[EMAIL PROTECTED]>
---
lib/puppet/parser/ast.rb | 16 ++
lib/puppet/parser/ast/casestatement.rb | 2 +
lib/puppet/parser/ast/collection.rb | 2 +
lib/puppet/parser/ast/definition.rb | 2 +
lib/puppet/parser/ast/else.rb | 3 +
lib/puppet/parser/ast/function.rb | 3 +
lib/puppet/parser/ast/hostclass.rb | 3 +
lib/puppet/parser/ast/ifstatement.rb | 3 +
lib/puppet/parser/ast/node.rb | 3 +
lib/puppet/parser/ast/resource.rb | 3 +
lib/puppet/parser/ast/resource_defaults.rb | 2 +
lib/puppet/parser/ast/resource_override.rb | 3 +
lib/puppet/parser/ast/vardef.rb | 3 +
lib/puppet/parser/grammar.ra | 22 +++-
lib/puppet/parser/lexer.rb | 60 +++++++-
lib/puppet/parser/parser.rb | 212 +++++++++++++++-------------
lib/puppet/parser/parser_support.rb | 22 +++-
17 files changed, 253 insertions(+), 111 deletions(-)
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index ddf8852..198f5f4 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -12,8 +12,24 @@ class Puppet::Parser::AST
include Puppet::Util::Errors
include Puppet::Util::MethodHelper
+ include Puppet::Util::Docs
+
attr_accessor :line, :file, :parent, :scope
+ # don't fetch lexer comment by default
+ def use_docs
+ false
+ end
+
+ # allow our subclass to specify they want documentation
+ class << self
+ def associates_doc
+ define_method("use_docs") do
+ true
+ end
+ end
+ end
+
# Does this ast object set something? If so, it gets evaluated first.
def self.settor?
if defined? @settor
diff --git a/lib/puppet/parser/ast/casestatement.rb
b/lib/puppet/parser/ast/casestatement.rb
index aa03090..73fbdcf 100644
--- a/lib/puppet/parser/ast/casestatement.rb
+++ b/lib/puppet/parser/ast/casestatement.rb
@@ -6,6 +6,8 @@ class Puppet::Parser::AST
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)
diff --git a/lib/puppet/parser/ast/collection.rb
b/lib/puppet/parser/ast/collection.rb
index 9e795a3..a51b9b4 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -8,6 +8,8 @@ class Puppet::Parser::AST
class Collection < AST::Branch
attr_accessor :type, :query, :form
+ associates_doc
+
# We return an object that does a late-binding evaluation.
def evaluate(scope)
if self.query
diff --git a/lib/puppet/parser/ast/definition.rb
b/lib/puppet/parser/ast/definition.rb
index 0c65c70..3cd8e79 100644
--- a/lib/puppet/parser/ast/definition.rb
+++ b/lib/puppet/parser/ast/definition.rb
@@ -10,6 +10,8 @@ class Puppet::Parser::AST::Definition <
Puppet::Parser::AST::Branch
attr_accessor :name
end
+ associates_doc
+
# The class name
@name = :definition
diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb
index affac62..70e80b4 100644
--- a/lib/puppet/parser/ast/else.rb
+++ b/lib/puppet/parser/ast/else.rb
@@ -4,6 +4,9 @@ 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
diff --git a/lib/puppet/parser/ast/function.rb
b/lib/puppet/parser/ast/function.rb
index eb36fa9..192940a 100644
--- a/lib/puppet/parser/ast/function.rb
+++ b/lib/puppet/parser/ast/function.rb
@@ -3,6 +3,9 @@ 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
@settor = true
diff --git a/lib/puppet/parser/ast/hostclass.rb
b/lib/puppet/parser/ast/hostclass.rb
index 4f5c479..23d9a00 100644
--- a/lib/puppet/parser/ast/hostclass.rb
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -4,6 +4,9 @@ require 'puppet/parser/ast/definition'
# in that each class is a singleton -- only one will exist for a given
# node.
class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition
+
+ associates_doc
+
@name = :class
# Are we a child of the passed class? Do a recursive search up our
diff --git a/lib/puppet/parser/ast/ifstatement.rb
b/lib/puppet/parser/ast/ifstatement.rb
index afa2cd5..d216b7c 100644
--- a/lib/puppet/parser/ast/ifstatement.rb
+++ b/lib/puppet/parser/ast/ifstatement.rb
@@ -3,6 +3,9 @@ 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
diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb
index 2bf6c18..442518f 100644
--- a/lib/puppet/parser/ast/node.rb
+++ b/lib/puppet/parser/ast/node.rb
@@ -3,6 +3,9 @@ require 'puppet/parser/ast/hostclass'
# The specific code associated with a host. Nodes are annoyingly unlike
# other objects. That's just the way it is, at least for now.
class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass
+
+ associates_doc
+
@name = :node
def initialize(options)
diff --git a/lib/puppet/parser/ast/resource.rb
b/lib/puppet/parser/ast/resource.rb
index 8a60522..1a07fc5 100644
--- a/lib/puppet/parser/ast/resource.rb
+++ b/lib/puppet/parser/ast/resource.rb
@@ -4,6 +4,9 @@ require 'puppet/parser/ast/resource_reference'
# builtin type.
class Puppet::Parser::AST
class Resource < AST::ResourceReference
+
+ associates_doc
+
attr_accessor :title, :type, :exported, :virtual
attr_reader :params
diff --git a/lib/puppet/parser/ast/resource_defaults.rb
b/lib/puppet/parser/ast/resource_defaults.rb
index 4856f05..4919817 100644
--- a/lib/puppet/parser/ast/resource_defaults.rb
+++ b/lib/puppet/parser/ast/resource_defaults.rb
@@ -6,6 +6,8 @@ class Puppet::Parser::AST
class ResourceDefaults < AST::Branch
attr_accessor :type, :params
+ associates_doc
+
# As opposed to ResourceDef, this stores each default for the given
# object type.
def evaluate(scope)
diff --git a/lib/puppet/parser/ast/resource_override.rb
b/lib/puppet/parser/ast/resource_override.rb
index 8380dcd..5c4a241 100644
--- a/lib/puppet/parser/ast/resource_override.rb
+++ b/lib/puppet/parser/ast/resource_override.rb
@@ -4,6 +4,9 @@ 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
+
+ associates_doc
+
attr_accessor :object
attr_reader :params
diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb
index a3094ac..2d5f623 100644
--- a/lib/puppet/parser/ast/vardef.rb
+++ b/lib/puppet/parser/ast/vardef.rb
@@ -3,6 +3,9 @@ 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
@settor = true
diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra
index 23c2934..67303ab 100644
--- a/lib/puppet/parser/grammar.ra
+++ b/lib/puppet/parser/grammar.ra
@@ -130,6 +130,7 @@ namestring: name
}
resource: classname LBRACE resourceinstances endsemi RBRACE {
+ @lexer.commentpop
array = val[2]
if array.instance_of?(AST::ResourceInstance)
array = [array]
@@ -158,6 +159,7 @@ resource: classname LBRACE resourceinstances endsemi
RBRACE {
# Override a value set elsewhere in the configuration.
resourceoverride: resourceref LBRACE anyparams endcomma RBRACE {
+ @lexer.commentpop
result = ast AST::ResourceOverride, :object => val[0], :params => val[2]
}
@@ -198,7 +200,7 @@ collection: classref collectrhand {
Puppet.warning addcontext("Collection names must now be capitalized")
end
type = val[0].downcase
- args = {:type => type}
+ args = {:type => type }
if val[1].is_a?(AST::CollExpr)
args[:query] = val[1]
@@ -410,6 +412,7 @@ resourceref: NAME LBRACK rvalues RBRACK {
}
ifstatement: IF expression LBRACE statements RBRACE else {
+ @lexer.commentpop
args = {
:test => val[1],
:statements => val[3]
@@ -422,6 +425,7 @@ ifstatement: IF expression LBRACE statements RBRACE
else {
result = ast AST::IfStatement, args
}
| IF expression LBRACE RBRACE else {
+ @lexer.commentpop
args = {
:test => val[1],
:statements => ast(AST::Nop)
@@ -436,9 +440,11 @@ ifstatement: IF expression LBRACE statements RBRACE
else {
else: # nothing
| 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)
}
@@ -508,6 +514,7 @@ expression: rvalue
}
casestatement: CASE rvalue LBRACE caseopts RBRACE {
+ @lexer.commentpop
options = val[3]
unless options.instance_of?(AST::ASTArray)
options = ast AST::ASTArray, :children => [val[3]]
@@ -526,8 +533,10 @@ caseopts: caseopt
}
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::ASTArray)
@@ -549,7 +558,10 @@ selector: selectlhand QMARK svalues {
}
svalues: selectval
- | LBRACE sintvalues endcomma RBRACE { result = val[1] }
+ | LBRACE sintvalues endcomma RBRACE {
+ @lexer.commentpop
+ result = val[1]
+}
sintvalues: selectval
| sintvalues comma selectval {
@@ -593,12 +605,14 @@ import: IMPORT qtexts {
# 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
newdefine classname(val[1]), :arguments => val[2], :code => val[4]
@lexer.indefine = false
result = nil
#} | DEFINE NAME argumentlist parent LBRACE RBRACE {
} | DEFINE classname argumentlist LBRACE RBRACE {
+ @lexer.commentpop
newdefine classname(val[1]), :arguments => val[2]
@lexer.indefine = false
result = nil
@@ -606,11 +620,13 @@ definition: DEFINE classname argumentlist LBRACE
statements RBRACE {
#hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE {
hostclass: CLASS classname classparent LBRACE statements RBRACE {
+ @lexer.commentpop
# Our class gets defined in the parent namespace, not our own.
@lexer.namepop
newclass classname(val[1]), :code => val[4], :parent => val[2]
result = nil
} | CLASS classname classparent LBRACE RBRACE {
+ @lexer.commentpop
# Our class gets defined in the parent namespace, not our own.
@lexer.namepop
newclass classname(val[1]), :parent => val[2]
@@ -618,9 +634,11 @@ hostclass: CLASS classname classparent LBRACE statements
RBRACE {
}
nodedef: NODE hostnames nodeparent LBRACE statements RBRACE {
+ @lexer.commentpop
newnode val[1], :parent => val[2], :code => val[4]
result = nil
} | NODE hostnames nodeparent LBRACE RBRACE {
+ @lexer.commentpop
newnode val[1], :parent => val[2]
result = nil
}
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index dd6c29d..69a46d0 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -17,7 +17,7 @@ class Puppet::Parser::Lexer
# Our base token class.
class Token
- attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text
+ attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text,
:accumulate
def initialize(regex, name)
if regex.is_a?(String)
@@ -28,8 +28,10 @@ class Puppet::Parser::Lexer
end
end
- def skip?
- self.skip
+ %w{skip accumulate}.each do |method|
+ define_method(method+"?") do
+ self.send(method)
+ end
end
def to_s
@@ -155,11 +157,16 @@ class Puppet::Parser::Lexer
[string_token, value]
end
- TOKENS.add_token :COMMENT, %r{#.*}, :skip => true
+ TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do
|lexer,value|
+ value.sub!(/# ?/,'')
+ [self, value]
+ end
- TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m do |lexer, value|
+ TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip
=> true do |lexer, value|
lexer.line += value.count("\n")
- [nil,nil]
+ value.sub!(/^\/\* ?/,'')
+ value.sub!(/ ?\*\/$/,'')
+ [self,value]
end
TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true,
:skip_text => true
@@ -325,6 +332,7 @@ class Puppet::Parser::Lexer
@namestack = []
@indefine = false
@expected = []
+ @commentstack = ['']
end
# Make any necessary changes to the token and/or value.
@@ -333,12 +341,18 @@ class Puppet::Parser::Lexer
skip() if token.skip_text
- return if token.skip
+ 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?
+ @commentstack.last << value + "\n"
+ end
+
+ return if token.skip
+
return token, value
end
@@ -389,6 +403,18 @@ class Puppet::Parser::Lexer
raise "Could not match '%s'" % nword
end
+ if matched_token.name == :RETURN
+ # this matches a blank line
+ if @last_return
+ # eat the previously accumulated comments
+ getcomment
+ end
+ # since :RETURN skips, we won't survive to munge_token
+ @last_return = true
+ else
+ @last_return = false
+ end
+
final_token, value = munge_token(matched_token, value)
next unless final_token
@@ -399,6 +425,10 @@ class Puppet::Parser::Lexer
@expected.pop
end
+ if final_token.name == :LBRACE
+ commentpush
+ end
+
yield [final_token.name, value]
if @previous_token
@@ -414,7 +444,6 @@ class Puppet::Parser::Lexer
@indefine = value
end
end
-
@previous_token = final_token
skip()
end
@@ -453,4 +482,19 @@ class Puppet::Parser::Lexer
def string=(string)
@scanner = StringScanner.new(string)
end
+
+ # returns the content of the currently accumulated content cache
+ def commentpop
+ return @commentstack.pop
+ end
+
+ def getcomment
+ comment = @commentstack.pop
+ @commentstack.push('')
+ return comment
+ end
+
+ def commentpush
+ @commentstack.push('')
+ end
end
diff --git a/lib/puppet/parser/parser_support.rb
b/lib/puppet/parser/parser_support.rb
index 1583973..d590937 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -18,6 +18,7 @@ class Puppet::Parser::Parser
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)
@@ -56,7 +57,9 @@ class Puppet::Parser::Parser
end
end
- return klass.new(hash)
+ k = klass.new(hash)
+ k.doc = lexer.getcomment if !k.nil? and k.use_docs and k.doc.empty?
+ return k
end
# The fully qualifed name, with the full namespace.
@@ -272,6 +275,7 @@ class Puppet::Parser::Parser
end
code = options[:code]
parent = options[:parent]
+ doc = options[:doc]
# If the class is already defined, then add code to it.
if other = @astset.classes[name]
@@ -304,6 +308,12 @@ class Puppet::Parser::Parser
other.code ||= code
end
end
+
+ if other.doc and doc
+ other.doc += doc
+ else
+ other.doc ||= doc
+ end
else
# Define it anew.
# Note we're doing something somewhat weird here -- we're setting
@@ -312,6 +322,8 @@ class Puppet::Parser::Parser
args = {:namespace => name, :classname => name, :parser => self}
args[:code] = code if code
args[:parentclass] = parent if parent
+ args[:doc] = doc
+
@astset.classes[name] = ast AST::HostClass, args
end
@@ -336,7 +348,8 @@ class Puppet::Parser::Parser
:arguments => options[:arguments],
:code => options[:code],
:parser => self,
- :classname => name
+ :classname => name,
+ :doc => options[:doc]
}
[:code, :arguments].each do |param|
@@ -350,6 +363,7 @@ class Puppet::Parser::Parser
# table, not according to namespaces.
def newnode(names, options = {})
names = [names] unless names.instance_of?(Array)
+ doc = lexer.getcomment
names.collect do |name|
name = name.to_s.downcase
if other = @astset.nodes[name]
@@ -358,7 +372,8 @@ class Puppet::Parser::Parser
name = name.to_s if name.is_a?(Symbol)
args = {
:name => name,
- :parser => self
+ :parser => self,
+ :doc => doc
}
if options[:code]
args[:code] = options[:code]
@@ -399,6 +414,7 @@ class Puppet::Parser::Parser
self.string = string
end
begin
+ @yydebug = false
main = yyparse(@lexer,:scan)
rescue Racc::ParseError => except
error = Puppet::ParseError.new(except)
--
1.6.0.2
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---