(PDOC-63) Implement the Puppet parser.
This commit implements the Puppet language parser that future handlers will use to generate YARD code objects for classes, defined types, and functions written in Puppet.
This commit is contained in:
parent
d4bab8a5ab
commit
f2e41a9c23
|
@ -12,6 +12,9 @@ module PuppetStrings::Yard
|
|||
def self.setup!
|
||||
# Register the template path
|
||||
YARD::Templates::Engine.register_template_path(File.join(File.dirname(__FILE__), 'yard', 'templates'))
|
||||
|
||||
# Register the Puppet parser
|
||||
YARD::Parser::SourceParser.register_parser_type(:puppet, PuppetStrings::Yard::Parsers::Puppet::Parser, ['pp'])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# The module for custom YARD parsers.
|
||||
module PuppetStrings::Yard::Parsers
|
||||
# The module for custom YARD parsers for the Puppet language.
|
||||
module Puppet
|
||||
require 'puppet-strings/yard/parsers/puppet/parser'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
require 'puppet'
|
||||
require 'puppet/pops'
|
||||
require 'puppet-strings/yard/parsers/puppet/statement'
|
||||
|
||||
# Implements the Puppet language parser.
|
||||
class PuppetStrings::Yard::Parsers::Puppet::Parser < YARD::Parser::Base
|
||||
attr_reader :file, :source
|
||||
|
||||
# Initializes the parser.
|
||||
# @param [String] source The source being parsed.
|
||||
# @param [String] filename The file name of the file being parsed.
|
||||
# @return [void]
|
||||
def initialize(source, filename)
|
||||
@source = source
|
||||
@file = filename
|
||||
@visitor = ::Puppet::Pops::Visitor.new(self, 'transform')
|
||||
end
|
||||
|
||||
# Parses the source.
|
||||
# @return [void]
|
||||
def parse
|
||||
begin
|
||||
@statements ||= (@visitor.visit(::Puppet::Pops::Parser::Parser.new.parse_string(source)) || []).compact
|
||||
rescue ::Puppet::ParseError => ex
|
||||
log.error "Failed to parse #{@file}: #{ex.message}"
|
||||
@statements = []
|
||||
end
|
||||
@statements.freeze
|
||||
self
|
||||
end
|
||||
|
||||
# Gets an enumerator for the statements that were parsed.
|
||||
# @return Returns an enumerator for the statements that were parsed.
|
||||
def enumerator
|
||||
@statements
|
||||
end
|
||||
|
||||
private
|
||||
def transform_Program(o)
|
||||
# Cache the lines of the source text; we'll use this to locate comments
|
||||
@lines = o.source_text.lines.to_a
|
||||
o.definitions.map { |d| @visitor.visit(d) }
|
||||
end
|
||||
|
||||
def transform_Factory(o)
|
||||
@visitor.visit(o.current)
|
||||
end
|
||||
|
||||
def transform_HostClassDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::ClassStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_ResourceTypeDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::DefinedTypeStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_FunctionDefinition(o)
|
||||
statement = PuppetStrings::Yard::Parsers::Puppet::FunctionStatement.new(o, @file)
|
||||
statement.extract_docstring(@lines)
|
||||
statement
|
||||
end
|
||||
|
||||
def transform_Object(o)
|
||||
# Ignore anything else (will be compacted out of the resulting array)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,146 @@
|
|||
require 'puppet'
|
||||
require 'puppet/pops'
|
||||
|
||||
module PuppetStrings::Yard::Parsers::Puppet
|
||||
# Represents the base Puppet language statement.
|
||||
class Statement
|
||||
# The pattern for parsing docstring comments.
|
||||
COMMENT_REGEX = /^\s*#+\s?/
|
||||
|
||||
attr_reader :source
|
||||
attr_reader :file
|
||||
attr_reader :line
|
||||
attr_reader :docstring
|
||||
attr_reader :comments_range
|
||||
|
||||
# Initializes the Puppet language statement.
|
||||
# @param object The Puppet parser model object for the statement.
|
||||
# @param [String] file The file name of the file containing the statement.
|
||||
def initialize(object, file)
|
||||
@file = file
|
||||
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(object)
|
||||
@source = adapter.extract_text
|
||||
@line = adapter.line
|
||||
@comments_range = nil
|
||||
end
|
||||
|
||||
# Extracts the docstring for the statement given the source lines.
|
||||
# @param [Array<String>] lines The source lines for the file containing the statement.
|
||||
# @return [void]
|
||||
def extract_docstring(lines)
|
||||
comment = []
|
||||
(0..@line-2).reverse_each do |index|
|
||||
break unless index <= lines.count
|
||||
line = lines[index].strip
|
||||
count = line.size
|
||||
line.gsub!(COMMENT_REGEX, '')
|
||||
# Break out if nothing was removed (wasn't a comment line)
|
||||
break unless line.size < count
|
||||
comment << line
|
||||
end
|
||||
@comments_range = (@line - comment.size - 1..@line - 1)
|
||||
@docstring = YARD::Docstring.new(comment.reverse.join("\n"))
|
||||
end
|
||||
|
||||
# Shows the first line context for the statement.
|
||||
# @return [String] Returns the first line context for the statement.
|
||||
def show
|
||||
"\t#{@line}: #{first_line}"
|
||||
end
|
||||
|
||||
# Gets the full comments of the statement.
|
||||
# @return [String] Returns the full comments of the statement.
|
||||
def comments
|
||||
@docstring.all
|
||||
end
|
||||
|
||||
# Determines if the comments have hash flag.
|
||||
# @return [Boolean] Returns true if the comments have a hash flag or false if not.
|
||||
def comments_hash_flag
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
def first_line
|
||||
@source.split(/\r?\n/).first.strip
|
||||
end
|
||||
end
|
||||
|
||||
# Implements a parameterized statement (a statement that takes parameters).
|
||||
class ParameterizedStatement < Statement
|
||||
# Implements a parameter for a parameterized statement.
|
||||
class Parameter
|
||||
attr_reader :name
|
||||
attr_reader :type
|
||||
attr_reader :value
|
||||
|
||||
# Initializes the parameter.
|
||||
# @param [Puppet::Pops::Model::Parameter] parameter The parameter model object.
|
||||
def initialize(parameter)
|
||||
@name = parameter.name
|
||||
# Take the exact text for the type expression
|
||||
if parameter.type_expr
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(parameter.type_expr)
|
||||
@type = adapter.extract_text
|
||||
end
|
||||
# Take the exact text for the default value expression
|
||||
if parameter.value
|
||||
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(parameter.value)
|
||||
@value = adapter.extract_text
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :parameters
|
||||
|
||||
# Initializes the parameterized statement.
|
||||
# @param object The Puppet parser model object that has parameters.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@parameters = object.parameters.map { |parameter| Parameter.new(parameter) }
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet class statement.
|
||||
class ClassStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
attr_reader :parent_class
|
||||
|
||||
# Initializes the Puppet class statement.
|
||||
# @param [Puppet::Pops::Model::HostClassDefinition] object The model object for the class statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
@parent_class = object.parent_class
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet defined type statement.
|
||||
class DefinedTypeStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
|
||||
# Initializes the Puppet defined type statement.
|
||||
# @param [Puppet::Pops::Model::ResourceTypeDefinition] object The model object for the defined type statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
end
|
||||
end
|
||||
|
||||
# Implements the Puppet function statement.
|
||||
class FunctionStatement < ParameterizedStatement
|
||||
attr_reader :name
|
||||
|
||||
# Initializes the Puppet function statement.
|
||||
# @param [Puppet::Pops::Model::FunctionDefinition] object The model object for the function statement.
|
||||
# @param [String] file The file containing the statement.
|
||||
def initialize(object, file)
|
||||
super(object, file)
|
||||
@name = object.name
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue