| Server IP : 77.68.64.21 / Your IP : 216.73.217.59 Web Server : Apache System : Linux hp3-wp-1011352.hostingp3.local 3.10.0-1160.144.1.el7.tuxcare.els9.x86_64 #1 SMP Fri Jul 10 17:06:31 UTC 2026 x86_64 User : csh2516497 ( 2094697) PHP Version : 8.3.30 Disable Function : shell_exec,exec,system,popen,set_time_limit MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /usr/share/ruby/vendor_ruby/puppet/pops/parser/ |
Upload File : |
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'
# Supporting logic for the parser.
# This supporting logic has slightly different responsibilities compared to the original Puppet::Parser::Parser.
# It is only concerned with parsing.
#
class Puppet::Pops::Parser::Parser
# Note that the name of the contained class and the file name (currently parser_support.rb)
# needs to be different as the class is generated by Racc, and this file (parser_support.rb) is included as a mix in
#
# Simplify access to the Model factory
# Note that the parser/parser support does not have direct knowledge about the Model.
# All model construction/manipulation is made by the Factory.
#
Factory = Puppet::Pops::Model::Factory
Model = Puppet::Pops::Model
include Puppet::Resource::TypeCollectionHelper
attr_accessor :lexer
attr_reader :definitions
# Returns the token text of the given lexer token, or nil, if token is nil
def token_text t
return t if t.nil?
t = t.current if t.respond_to?(:current)
return t.value if t.is_a? Model::QualifiedName
# else it is a lexer token
t[:value]
end
# Produces the fully qualified name, with the full (current) namespace for a given name.
#
# This is needed because class bodies are lazily evaluated and an inner class' container(s) may not
# have been evaluated before some external reference is made to the inner class; its must therefore know its complete name
# before evaluation-time.
#
def classname(name)
[namespace, name].join("::").sub(/^::/, '')
end
# # Reinitializes variables (i.e. creates a new lexer instance
# #
# def clear
# initvars
# end
# Raises a Parse error.
def error(value, message, options = {})
except = Puppet::ParseError.new(message)
except.line = options[:line] || value[:line]
except.file = options[:file] || value[:file] # @lexer.file
except.pos = options[:pos] || value[:pos] # @lexer.pos
raise except
end
# Parses a file expected to contain pp DSL logic.
def parse_file(file)
unless Puppet::FileSystem.exist?(file)
unless file =~ /\.pp$/
file = file + ".pp"
end
end
@lexer.file = file
_parse()
end
def initialize()
# Since the parser is not responsible for importing (removed), and does not perform linking,
# and there is no syntax that requires knowing if something referenced exists, it is safe
# to assume that no environment is needed when parsing. (All that comes later).
#
@lexer = Puppet::Pops::Parser::Lexer2.new
@namestack = []
@definitions = []
end
# # Initializes the parser support by creating a new instance of {Puppet::Pops::Parser::Lexer}
# # @return [void]
# #
# def initvars
# end
# This is a callback from the generated grammar (when an error occurs while parsing)
# TODO Picks up origin information from the lexer, probably needs this from the caller instead
# (for code strings, and when start line is not line 1 in a code string (or file), etc.)
#
def on_error(token,value,stack)
if token == 0 # denotes end of file
value_at = 'end of file'
else
value_at = "'#{value[:value]}'"
end
error = "Syntax error at #{value_at}"
# The 'expected' is only of value at end of input, otherwise any parse error involving a
# start of a pair will be reported as expecting the close of the pair - e.g. "$x.each |$x {|", would
# report that "seeing the '{', the '}' is expected. That would be wrong.
# Real "expected" tokens are very difficult to compute (would require parsing of racc output data). Output of the stack
# could help, but can require extensive backtracking and produce many options.
#
# The lexer should handle the "expected instead of end of file for strings, and interpolation", other expectancies
# must be handled by the grammar. The lexer may have enqueued tokens far ahead - the lexer's opinion about this
# is not trustworthy.
#
# if token == 0 && brace = @lexer.expected
# error += "; expected '#{brace}'"
# end
except = Puppet::ParseError.new(error)
if token != 0
path = value[:file]
except.line = value[:line]
except.pos = value[:pos]
else
# At end of input, use what the lexer thinks is the source file
path = lexer.file
end
except.file = path if path.is_a?(String) && !path.empty?
raise except
end
# Parses a String of pp DSL code.
# @todo make it possible to pass a given origin
#
def parse_string(code)
@lexer.string = code
_parse()
end
# Mark the factory wrapped model object with location information
# @todo the lexer produces :line for token, but no offset or length
# @return [Puppet::Pops::Model::Factory] the given factory
# @api private
#
def loc(factory, start_locateable, end_locateable = nil)
factory.record_position(start_locateable, end_locateable)
end
def heredoc_loc(factory, start_locateabke, end_locateable = nil)
factory.record_heredoc_position(start_locatable, end_locatable)
end
# Associate documentation with the factory wrapped model object.
# @return [Puppet::Pops::Model::Factory] the given factory
# @api private
def doc factory, doc_string
factory.doc = doc_string
end
def aryfy(o)
o = [o] unless o.is_a?(Array)
o
end
def namespace
@namestack.join('::')
end
def namestack(name)
@namestack << name
end
def namepop()
@namestack.pop
end
def add_definition(definition)
@definitions << definition.current
definition
end
# Transforms an array of expressions containing literal name expressions to calls if followed by an
# expression, or expression list
#
def transform_calls(expressions)
Factory.transform_calls(expressions)
end
# Transforms a LEFT followed by the result of attribute_operations, this may be a call or an invalid sequence
def transform_resource_wo_title(left, resource)
Factory.transform_resource_wo_title(left, resource)
end
# If there are definitions that require initialization a Program is produced, else the body
def create_program(body)
locator = @lexer.locator
Factory.PROGRAM(body, definitions, locator)
end
# Performs the parsing and returns the resulting model.
# The lexer holds state, and this is setup with {#parse_string}, or {#parse_file}.
#
# TODO: Drop support for parsing a ruby file this way (should be done where it is decided
# which file to load/run (i.e. loaders), and initial file to run
# TODO: deal with options containing origin (i.e. parsing a string from externally known location).
# TODO: should return the model, not a Hostclass
#
# @api private
#
def _parse()
begin
@yydebug = false
main = yyparse(@lexer,:scan)
# #Commented out now because this hides problems in the racc grammar while developing
# # TODO include this when test coverage is good enough.
# 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, @lexer.pos, except)
end
return main
ensure
@lexer.clear
@namestack = []
@definitions = []
end
end