1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
require_relative '../../../puppet/concurrent/thread_local_singleton'
module Puppet::Pops
module Parser
# Does not support "import" and parsing ruby files
#
class EvaluatingParser
extend Puppet::Concurrent::ThreadLocalSingleton
attr_reader :parser
def initialize()
@parser = Parser.new()
end
def parse_string(s, file_source = nil)
clear()
# Handling of syntax error can be much improved (in general), now it bails out of the parser
# and does not have as rich information (when parsing a string), need to update it with the file source
# (ideally, a syntax error should be entered as an issue, and not just thrown - but that is a general problem
# and an improvement that can be made in the eparser (rather than here).
# Also a possible improvement (if the YAML parser returns positions) is to provide correct output of position.
#
begin
assert_and_report(parser.parse_string(s, file_source), file_source).model
rescue Puppet::ParseErrorWithIssue => e
raise e
rescue Puppet::ParseError => e
# TODO: This is not quite right, why does not the exception have the correct file?
e.file = file_source unless e.file.is_a?(String) && !e.file.empty?
raise e
end
end
def parse_file(file)
clear()
assert_and_report(parser.parse_file(file), file).model
end
def evaluate_string(scope, s, file_source = nil)
evaluate(scope, parse_string(s, file_source))
end
def evaluate_file(scope, file)
evaluate(scope, parse_file(file))
end
def clear()
@acceptor = nil
end
# Create a closure that can be called in the given scope
def closure(model, scope)
Evaluator::Closure::Dynamic.new(evaluator, model, scope)
end
def evaluate(scope, model)
return nil unless model
evaluator.evaluate(model, scope)
end
# Evaluates the given expression in a local scope with the given variable bindings
# set in this local scope, returns what the expression returns.
#
def evaluate_expression_with_bindings(scope, variable_bindings, expression)
evaluator.evaluate_block_with_bindings(scope, variable_bindings, expression)
end
def evaluator
# Do not use the cached evaluator if this is a migration run
if (Puppet.lookup(:migration_checker) { nil })
return Evaluator::EvaluatorImpl.new()
end
@@evaluator ||= Evaluator::EvaluatorImpl.new()
@@evaluator
end
def convert_to_3x(object, scope)
evaluator.convert(object, scope, nil)
end
def validate(parse_result)
resulting_acceptor = acceptor()
validator(resulting_acceptor).validate(parse_result)
resulting_acceptor
end
def acceptor()
Validation::Acceptor.new
end
def validator(acceptor)
Validation::ValidatorFactory_4_0.new().validator(acceptor)
end
def assert_and_report(parse_result, file_source)
return nil unless parse_result
if parse_result['source_ref'].nil? || parse_result['source_ref'] == ''
parse_result['source_ref'] = file_source
end
validation_result = validate(parse_result.model)
IssueReporter.assert_and_report(validation_result,
:emit_warnings => true)
parse_result
end
def quote(x)
self.class.quote(x)
end
# Translates an already parsed string that contains control characters, quotes
# and backslashes into a quoted string where all such constructs have been escaped.
# Parsing the return value of this method using the puppet parser should yield
# exactly the same string as the argument passed to this method
#
# The method makes an exception for the two character sequences \$ and \s. They
# will not be escaped since they have a special meaning in puppet syntax.
#
# TODO: Handle \uXXXX characters ??
#
# @param x [String] The string to quote and "unparse"
# @return [String] The quoted string
#
def self.quote(x)
escaped = '"'
p = nil
x.each_char do |c|
case p
when nil
# do nothing
when "\t"
escaped << '\\t'
when "\n"
escaped << '\\n'
when "\f"
escaped << '\\f'
# TODO: \cx is a range of characters - skip for now
# when "\c"
# escaped << '\\c'
when '"'
escaped << '\\"'
when '\\'
escaped << if c == '$' || c == 's'; p; else '\\\\'; end # don't escape \ when followed by s or $
else
escaped << p
end
p = c
end
escaped << p unless p.nil?
escaped << '"'
end
class EvaluatingEppParser < EvaluatingParser
def initialize()
@parser = EppParser.new()
end
end
end
end
end
|