Class: Puppet::Pops::Parser::Parser

Inherits:
Racc::Parser
  • Object
show all
Includes:
Resource::TypeCollectionHelper
Defined in:
lib/puppet/pops/parser/parser_support.rb,
lib/puppet/pops/parser/eparser.rb

Overview

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.

Constant Summary collapse

Racc_arg =
[
racc_action_table,
racc_action_check,
racc_action_default,
racc_action_pointer,
racc_goto_table,
racc_goto_check,
racc_goto_default,
racc_goto_pointer,
racc_nt_base,
racc_reduce_table,
racc_token_table,
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
Racc_token_to_s_table =
[
"$end",
"error",
"STRING",
"DQPRE",
"DQMID",
"DQPOST",
"LBRACK",
"RBRACK",
"LBRACE",
"RBRACE",
"SYMBOL",
"FARROW",
"COMMA",
"TRUE",
"FALSE",
"EQUALS",
"APPENDS",
"LESSEQUAL",
"NOTEQUAL",
"DOT",
"COLON",
"LLCOLLECT",
"RRCOLLECT",
"QMARK",
"LPAREN",
"RPAREN",
"ISEQUAL",
"GREATEREQUAL",
"GREATERTHAN",
"LESSTHAN",
"IF",
"ELSE",
"DEFINE",
"ELSIF",
"VARIABLE",
"CLASS",
"INHERITS",
"NODE",
"BOOLEAN",
"NAME",
"SEMIC",
"CASE",
"DEFAULT",
"AT",
"LCOLLECT",
"RCOLLECT",
"CLASSREF",
"NOT",
"OR",
"AND",
"UNDEF",
"PARROW",
"PLUS",
"MINUS",
"TIMES",
"DIV",
"LSHIFT",
"RSHIFT",
"UMINUS",
"MATCH",
"NOMATCH",
"REGEX",
"IN_EDGE",
"OUT_EDGE",
"IN_EDGE_SUB",
"OUT_EDGE_SUB",
"IN",
"UNLESS",
"PIPE",
"SELBRACE",
"LOW",
"HIGH",
"CALL",
"MODULO",
"TITLE_COLON",
"CASE_COLON",
"$start",
"program",
"statements",
"nil",
"syntactic_statements",
"syntactic_statement",
"any_expression",
"relationship_expression",
"resource_expression",
"expression",
"higher_precedence",
"expressions",
"match_rvalue",
"selector_entries",
"call_function_expression",
"primary_expression",
"literal_expression",
"variable",
"call_method_with_lambda_expression",
"collection_expression",
"case_expression",
"if_expression",
"unless_expression",
"definition_expression",
"hostclass_expression",
"node_definition_expression",
"array",
"boolean",
"default",
"hash",
"regex",
"text_or_name",
"type",
"undef",
"name",
"quotedtext",
"endcomma",
"lambda",
"call_method_expression",
"named_access",
"lambda_parameter_list",
"lambda_rest",
"parameters",
"if_part",
"else",
"unless_else",
"case_options",
"case_option",
"case_colon",
"selector_entry",
"selector_entry_list",
"at",
"resourceinstances",
"endsemi",
"attribute_operations",
"resourceinst",
"title_colon",
"collect_query",
"optional_query",
"attribute_operation",
"attribute_name",
"keyword",
"classname",
"parameter_list",
"classparent",
"classnameordefault",
"hostnames",
"nodeparent",
"hostname",
"parameter",
"hashpairs",
"hashpair",
"string",
"dq_string",
"dqpre",
"dqrval",
"dqpost",
"dqmid",
"text_expression",
"dqtail" ]
Racc_debug_parser =
false
Factory =

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.

Puppet::Pops::Model::Factory
Model =
Puppet::Pops::Model

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Resource::TypeCollectionHelper

#known_resource_types

Constructor Details

#initializeParser

Returns a new instance of Parser.



75
76
77
78
79
80
81
# File 'lib/puppet/pops/parser/parser_support.rb', line 75

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).
  #
  initvars
end

Instance Attribute Details

#lexerObject



26
27
28
# File 'lib/puppet/pops/parser/parser_support.rb', line 26

def lexer
  @lexer
end

Instance Method Details

#_parseObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/puppet/pops/parser/parser_support.rb', line 183

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
  main.record_origin(@lexer.file) if main
  return main
ensure
  @lexer.clear
end

#_reduce_none(val, _values, result) ⇒ Object



2249
2250
2251
# File 'lib/puppet/pops/parser/eparser.rb', line 2249

def _reduce_none(val, _values, result)
  val[0]
end

#aryfy(o) ⇒ Object



161
162
163
164
# File 'lib/puppet/pops/parser/parser_support.rb', line 161

def aryfy(o)
  o = [o] unless o.is_a?(Array)
  o
end

#classname(name) ⇒ Object

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.



44
45
46
# File 'lib/puppet/pops/parser/parser_support.rb', line 44

def classname(name)
  [@lexer.namespace, name].join("::").sub(/^::/, '')
end

#clearObject

Reinitializes variables (i.e. creates a new lexer instance



50
51
52
# File 'lib/puppet/pops/parser/parser_support.rb', line 50

def clear
  initvars
end

#doc(factory, doc_string) ⇒ Puppet::Pops::Model::Factory

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Associate documentation with the factory wrapped model object.

Returns:



140
141
142
# File 'lib/puppet/pops/parser/parser_support.rb', line 140

def doc factory, doc_string
  factory.doc = doc_string
end

#error(message, options = {}) ⇒ Object

Raises a Parse error.



55
56
57
58
59
60
61
62
# File 'lib/puppet/pops/parser/parser_support.rb', line 55

def error(message, options = {})
  except = Puppet::ParseError.new(message)
  except.line = options[:line] || @lexer.line
  except.file = options[:file] || @lexer.file
  except.pos = options[:pos]   || @lexer.pos

  raise except
end

#initvarsvoid

This method returns an undefined value.

Initializes the parser support by creating a new instance of Lexer



86
87
88
# File 'lib/puppet/pops/parser/parser_support.rb', line 86

def initvars
  @lexer = Puppet::Pops::Parser::Lexer.new
end

#loc(factory, start_token, end_token = nil) ⇒ Puppet::Pops::Model::Factory

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

TODO:

the lexer produces :line for token, but no offset or length

Mark the factory wrapped model object with location information

Returns:



133
134
135
# File 'lib/puppet/pops/parser/parser_support.rb', line 133

def loc(factory, start_token, end_token = nil)
  factory.record_position(sourcepos(start_token), sourcepos(end_token))
end

#on_error(token, value, stack) ⇒ Object

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.)


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/puppet/pops/parser/parser_support.rb', line 94

def on_error(token,value,stack)
  if token == 0 # denotes end of file
    value = 'end of file'
  else
    value = "'#{value[:value]}'"
  end
  error = "Syntax error at #{value}"

  # 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.
  #
  if token == 0 && brace = @lexer.expected
    error += "; expected '#{brace}'"
  end

  except = Puppet::ParseError.new(error)
  except.line = @lexer.line
  except.file = @lexer.file if @lexer.file
  except.pos  = @lexer.pos

  raise except
end

#parse_file(file) ⇒ Object

Parses a file expected to contain pp DSL logic.



65
66
67
68
69
70
71
72
73
# File 'lib/puppet/pops/parser/parser_support.rb', line 65

def parse_file(file)
  unless Puppet::FileSystem::File.exist?(file)
    unless file =~ /\.pp$/
      file = file + ".pp"
    end
  end
  @lexer.file = file
  _parse()
end

#parse_string(code) ⇒ Object

TODO:

make it possible to pass a given origin

Parses a String of pp DSL code.



123
124
125
126
# File 'lib/puppet/pops/parser/parser_support.rb', line 123

def parse_string(code)
  @lexer.string = code
  _parse()
end

#sourcepos(o) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/puppet/pops/parser/parser_support.rb', line 144

def sourcepos(o)
  if !o
    Puppet::Pops::Adapters::SourcePosAdapter.new
  elsif o.is_a? Puppet::Pops::Model::Factory
    # It is a built model element with loc set returns start at pos 0
    o.loc
  else
    loc = Puppet::Pops::Adapters::SourcePosAdapter.new
    # It must be a token
    loc.line = o[:line]
    loc.pos = o[:pos]
    loc.offset = o[:offset]
    loc.length = o[:length]
    loc
  end
end

#token_text(t) ⇒ Object

Returns the token text of the given lexer token, or nil, if token is nil



29
30
31
32
33
34
35
36
# File 'lib/puppet/pops/parser/parser_support.rb', line 29

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

#transform_calls(expressions) ⇒ Object

Transforms an array of expressions containing literal name expressions to calls if followed by an expression, or expression list



169
170
171
# File 'lib/puppet/pops/parser/parser_support.rb', line 169

def transform_calls(expressions)
  Factory.transform_calls(expressions)
end