puppet 3.7.5-x64-mingw32 → 3.8.1-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/ext/build_defaults.yaml +5 -5
- data/lib/hiera/puppet_function.rb +15 -4
- data/lib/puppet.rb +5 -2
- data/lib/puppet/application/agent.rb +5 -0
- data/lib/puppet/application/apply.rb +5 -0
- data/lib/puppet/application/device.rb +8 -3
- data/lib/puppet/application/master.rb +5 -0
- data/lib/puppet/defaults.rb +8 -0
- data/lib/puppet/error.rb +27 -1
- data/lib/puppet/file_system.rb +13 -0
- data/lib/puppet/file_system/file19windows.rb +8 -0
- data/lib/puppet/file_system/file_impl.rb +4 -0
- data/lib/puppet/file_system/memory_impl.rb +4 -0
- data/lib/puppet/functions.rb +25 -3
- data/lib/puppet/functions/defined.rb +130 -0
- data/lib/puppet/functions/hiera_include.rb +1 -1
- data/lib/puppet/node/environment.rb +4 -0
- data/lib/puppet/parser/compiler.rb +5 -2
- data/lib/puppet/parser/functions/defined.rb +26 -1
- data/lib/puppet/parser/functions/file.rb +3 -1
- data/lib/puppet/parser/templatewrapper.rb +2 -1
- data/lib/puppet/pops.rb +5 -0
- data/lib/puppet/pops/evaluator/access_operator.rb +25 -5
- data/lib/puppet/pops/evaluator/collector_transformer.rb +1 -11
- data/lib/puppet/pops/evaluator/compare_operator.rb +43 -0
- data/lib/puppet/pops/evaluator/evaluator_impl.rb +43 -28
- data/lib/puppet/pops/evaluator/runtime3_support.rb +9 -5
- data/lib/puppet/pops/functions/dispatch.rb +6 -1
- data/lib/puppet/pops/issue_reporter.rb +42 -16
- data/lib/puppet/pops/issues.rb +96 -0
- data/lib/puppet/pops/loader/module_loaders.rb +3 -1
- data/lib/puppet/pops/loaders.rb +6 -4
- data/lib/puppet/pops/migration/migration_checker.rb +45 -0
- data/lib/puppet/pops/model/factory.rb +1 -1
- data/lib/puppet/pops/model/model_meta.rb +1 -1
- data/lib/puppet/pops/parser/egrammar.ra +1 -1
- data/lib/puppet/pops/parser/eparser.rb +1 -1
- data/lib/puppet/pops/parser/epp_support.rb +18 -9
- data/lib/puppet/pops/parser/evaluating_parser.rb +7 -1
- data/lib/puppet/pops/parser/heredoc_support.rb +12 -11
- data/lib/puppet/pops/parser/interpolation_support.rb +7 -1
- data/lib/puppet/pops/parser/lexer2.rb +8 -8
- data/lib/puppet/pops/parser/lexer_support.rb +46 -20
- data/lib/puppet/pops/parser/parser_support.rb +11 -14
- data/lib/puppet/pops/parser/slurp_support.rb +22 -6
- data/lib/puppet/pops/types/type_calculator.rb +156 -55
- data/lib/puppet/pops/types/type_factory.rb +67 -14
- data/lib/puppet/pops/types/type_parser.rb +22 -13
- data/lib/puppet/pops/types/types.rb +21 -3
- data/lib/puppet/pops/types/types_meta.rb +13 -2
- data/lib/puppet/pops/validation.rb +25 -2
- data/lib/puppet/pops/validation/checker4_0.rb +25 -5
- data/lib/puppet/provider/group/windows_adsi.rb +18 -6
- data/lib/puppet/provider/mount/parsed.rb +145 -2
- data/lib/puppet/provider/package/pip.rb +4 -5
- data/lib/puppet/provider/package/zypper.rb +17 -7
- data/lib/puppet/provider/scheduled_task/win32_taskscheduler.rb +35 -10
- data/lib/puppet/provider/service/init.rb +7 -0
- data/lib/puppet/provider/user/windows_adsi.rb +8 -1
- data/lib/puppet/provider/zpool/zpool.rb +7 -2
- data/lib/puppet/resource.rb +1 -1
- data/lib/puppet/type/group.rb +1 -1
- data/lib/puppet/type/mount.rb +14 -3
- data/lib/puppet/type/scheduled_task.rb +21 -6
- data/lib/puppet/util/log.rb +50 -8
- data/lib/puppet/util/log/destinations.rb +23 -2
- data/lib/puppet/util/logging.rb +37 -1
- data/lib/puppet/util/windows/adsi.rb +36 -11
- data/lib/puppet/version.rb +1 -1
- data/spec/fixtures/unit/provider/mount/parsed/aix.filesystems +93 -85
- data/spec/fixtures/unit/provider/mount/parsed/aix.mount +11 -7
- data/spec/integration/parser/collector_spec.rb +7 -0
- data/spec/integration/parser/future_compiler_spec.rb +9 -0
- data/spec/integration/parser/resource_expressions_spec.rb +3 -0
- data/spec/unit/file_system_spec.rb +38 -0
- data/spec/unit/functions/defined_spec.rb +291 -0
- data/spec/unit/functions/hiera_spec.rb +8 -6
- data/spec/unit/functions4_spec.rb +97 -2
- data/spec/unit/parser/functions/file_spec.rb +8 -2
- data/spec/unit/parser/functions/template_spec.rb +1 -1
- data/spec/unit/parser/templatewrapper_spec.rb +1 -1
- data/spec/unit/pops/evaluator/access_ops_spec.rb +19 -0
- data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +61 -8
- data/spec/unit/pops/issues_spec.rb +16 -16
- data/spec/unit/pops/loaders/module_loaders_spec.rb +5 -0
- data/spec/unit/pops/migration_spec.rb +180 -0
- data/spec/unit/pops/parser/lexer2_spec.rb +152 -1
- data/spec/unit/pops/parser/parse_heredoc_spec.rb +26 -0
- data/spec/unit/pops/transformer/transform_calls_spec.rb +1 -1
- data/spec/unit/pops/types/type_calculator_spec.rb +204 -11
- data/spec/unit/pops/validation_spec.rb +66 -0
- data/spec/unit/provider/group/windows_adsi_spec.rb +65 -1
- data/spec/unit/provider/mount/parsed_spec.rb +31 -5
- data/spec/unit/provider/package/pip_spec.rb +19 -7
- data/spec/unit/provider/package/zypper_spec.rb +25 -14
- data/spec/unit/provider/scheduled_task/win32_taskscheduler_spec.rb +312 -70
- data/spec/unit/provider/service/base_spec.rb +42 -31
- data/spec/unit/provider/service/freebsd_spec.rb +1 -0
- data/spec/unit/provider/service/gentoo_spec.rb +1 -0
- data/spec/unit/provider/service/init_spec.rb +18 -0
- data/spec/unit/provider/service/openbsd_spec.rb +1 -0
- data/spec/unit/provider/service/redhat_spec.rb +1 -0
- data/spec/unit/provider/user/windows_adsi_spec.rb +21 -0
- data/spec/unit/provider/zpool/zpool_spec.rb +47 -10
- data/spec/unit/util/log_spec.rb +113 -0
- data/spec/unit/util/windows/adsi_spec.rb +106 -26
- metadata +10 -2
@@ -20,6 +20,8 @@ class Puppet::Pops::Parser::EvaluatingParser
|
|
20
20
|
#
|
21
21
|
begin
|
22
22
|
assert_and_report(parser.parse_string(s))
|
23
|
+
rescue Puppet::ParseErrorWithIssue => e
|
24
|
+
raise e
|
23
25
|
rescue Puppet::ParseError => e
|
24
26
|
# TODO: This is not quite right, why does not the exception have the correct file?
|
25
27
|
e.file = @file_source unless e.file.is_a?(String) && !e.file.empty?
|
@@ -56,12 +58,16 @@ class Puppet::Pops::Parser::EvaluatingParser
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def evaluator
|
61
|
+
# Do not use the cached evaluator if this is a migration run
|
62
|
+
if (Puppet.lookup(:migration_checker) { nil })
|
63
|
+
return Puppet::Pops::Evaluator::EvaluatorImpl.new()
|
64
|
+
end
|
59
65
|
@@evaluator ||= Puppet::Pops::Evaluator::EvaluatorImpl.new()
|
60
66
|
@@evaluator
|
61
67
|
end
|
62
68
|
|
63
69
|
def convert_to_3x(object, scope)
|
64
|
-
val =
|
70
|
+
val = evaluator.convert(object, scope, nil)
|
65
71
|
end
|
66
72
|
|
67
73
|
def validate(parse_result)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module Puppet::Pops::Parser::HeredocSupport
|
2
|
+
include Puppet::Pops::Parser::LexerSupport
|
2
3
|
|
3
4
|
# Pattern for heredoc `@(endtag[:syntax][/escapes])
|
4
5
|
# Produces groups for endtag (group 1), syntax (group 2), and escapes (group 3)
|
@@ -14,13 +15,12 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
14
15
|
|
15
16
|
# scanner is at position before @(
|
16
17
|
# find end of the heredoc spec
|
17
|
-
str = scn.scan_until(/\)/) ||
|
18
|
+
str = scn.scan_until(/\)/) || lex_error(Puppet::Pops::Issues::HEREDOC_UNCLOSED_PARENTHESIS, :followed_by => followed_by)
|
18
19
|
pos_after_heredoc = scn.pos
|
19
20
|
|
20
21
|
# Note: allows '+' as separator in syntax, but this needs validation as empty segments are not allowed
|
21
|
-
|
22
|
-
|
23
|
-
end
|
22
|
+
md = str.match(PATTERN_HEREDOC)
|
23
|
+
lex_error(Puppet::Pops::Issues::HEREDOC_INVALID_SYNTAX) unless md
|
24
24
|
endtag = md[1]
|
25
25
|
syntax = md[2] || ''
|
26
26
|
escapes = md[3]
|
@@ -33,7 +33,7 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
33
33
|
endtag = $1.strip
|
34
34
|
end
|
35
35
|
|
36
|
-
|
36
|
+
lex_error(Puppet::Pops::Issues::HEREDOC_MISSING_ENDTAG) unless endtag.length >= 1
|
37
37
|
|
38
38
|
resulting_escapes = []
|
39
39
|
if escapes
|
@@ -41,7 +41,7 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
41
41
|
|
42
42
|
escapes = escapes.split('')
|
43
43
|
unless escapes.length == escapes.uniq.length
|
44
|
-
lex_error(
|
44
|
+
lex_error(Puppet::Pops::Issues::HEREDOC_MULTIPLE_AT_ESCAPES, :escapes => escapes)
|
45
45
|
end
|
46
46
|
resulting_escapes = ["\\"]
|
47
47
|
escapes.each do |e|
|
@@ -51,7 +51,7 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
51
51
|
when "L"
|
52
52
|
resulting_escapes += ["\n", "\r\n"]
|
53
53
|
else
|
54
|
-
lex_error(
|
54
|
+
lex_error(Puppet::Pops::Issues::HEREDOC_INVALID_ESCAPE, :actual => e)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -66,14 +66,14 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
66
66
|
if ctx[:newline_jump]
|
67
67
|
scn.pos = ctx[:newline_jump]
|
68
68
|
else
|
69
|
-
scn.scan_until(/\n/) || lex_error(
|
69
|
+
scn.scan_until(/\n/) || lex_error(Puppet::Pops::Issues::HEREDOC_WITHOUT_TEXT)
|
70
70
|
end
|
71
71
|
# offset 0 for the heredoc, and its line number
|
72
72
|
heredoc_offset = scn.pos
|
73
73
|
heredoc_line = locator.line_for_offset(heredoc_offset)-1
|
74
74
|
|
75
75
|
# Compute message to emit if there is no end (to make it refer to the opening heredoc position).
|
76
|
-
|
76
|
+
eof_error = create_lex_error(Puppet::Pops::Issues::HEREDOC_WITHOUT_END_TAGGED_LINE)
|
77
77
|
|
78
78
|
# Text from this position (+ lexing contexts offset for any preceding heredoc) is heredoc until a line
|
79
79
|
# that terminates the heredoc is found.
|
@@ -82,7 +82,8 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
82
82
|
endline_pattern = /([[:blank:]]*)(?:([|])[[:blank:]]*)?(?:(\-)[[:blank:]]*)?#{Regexp.escape(endtag)}[[:blank:]]*\r?(?:\n|\z)/
|
83
83
|
lines = []
|
84
84
|
while !scn.eos? do
|
85
|
-
one_line = scn.scan_until(/(?:\n|\z)/)
|
85
|
+
one_line = scn.scan_until(/(?:\n|\z)/)
|
86
|
+
raise eof_error unless one_line
|
86
87
|
if md = one_line.match(endline_pattern)
|
87
88
|
leading = md[1]
|
88
89
|
has_margin = md[2] == '|'
|
@@ -116,7 +117,7 @@ module Puppet::Pops::Parser::HeredocSupport
|
|
116
117
|
lines << one_line
|
117
118
|
end
|
118
119
|
end
|
119
|
-
|
120
|
+
raise eof_error
|
120
121
|
end
|
121
122
|
|
122
123
|
# Produces the heredoc text string given the individual (unprocessed) lines as an array.
|
@@ -193,9 +193,15 @@ module Puppet::Pops::Parser::InterpolationSupport
|
|
193
193
|
token_name = token[0]
|
194
194
|
ctx[:after] = token_name
|
195
195
|
if token_name == :RBRACE && ctx[:brace_count] == brace_count
|
196
|
-
|
196
|
+
qlength = queue.size - queue_size
|
197
|
+
if qlength == 1
|
197
198
|
# Single token is subject to replacement
|
198
199
|
queue[-1] = transform_to_variable(queue[-1])
|
200
|
+
elsif qlength > 1 && [:DOT, :LBRACK].include?(queue[queue_size + 1][0])
|
201
|
+
# A first word, number of name token followed by '[' or '.' is subject to replacement
|
202
|
+
# But not for other operators such as ?, +, - etc. where user must use a $ before the name
|
203
|
+
# to get a variable
|
204
|
+
queue[queue_size] = transform_to_variable(queue[queue_size])
|
199
205
|
end
|
200
206
|
return
|
201
207
|
end
|
@@ -213,7 +213,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
213
213
|
@scanner = StringScanner.new(string)
|
214
214
|
@locator = locator || Puppet::Pops::Parser::Locator.locator(string, '')
|
215
215
|
@lexing_context[:escapes] = escapes || UQ_ESCAPES
|
216
|
-
@lexing_context[:uq_slurp_pattern] =
|
216
|
+
@lexing_context[:uq_slurp_pattern] = interpolate ? (escapes.include?('$') ? SLURP_UQ_PATTERN : SLURP_UQNE_PATTERN) : SLURP_ALL_PATTERN
|
217
217
|
end
|
218
218
|
|
219
219
|
# Convenience method, and for compatibility with older lexer. Use the lex_file instead.
|
@@ -274,7 +274,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
274
274
|
ctx = @lexing_context
|
275
275
|
queue = @token_queue
|
276
276
|
|
277
|
-
lex_error_without_pos(
|
277
|
+
lex_error_without_pos(Puppet::Pops::Issues::NO_INPUT_TO_LEXER) unless scn
|
278
278
|
|
279
279
|
scn.skip(PATTERN_WS)
|
280
280
|
|
@@ -533,7 +533,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
533
533
|
else
|
534
534
|
# move to faulty position ('::<uc-letter>' was ok)
|
535
535
|
scn.pos = scn.pos + 3
|
536
|
-
lex_error(
|
536
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_CLASS_REFERENCE)
|
537
537
|
end
|
538
538
|
else
|
539
539
|
value = scn.scan(PATTERN_BARE_WORD)
|
@@ -546,7 +546,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
546
546
|
else
|
547
547
|
# move to faulty position ('::' was ok)
|
548
548
|
scn.pos = scn.pos + 2
|
549
|
-
lex_error(
|
549
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_NAME)
|
550
550
|
end
|
551
551
|
end
|
552
552
|
else
|
@@ -578,7 +578,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
578
578
|
else
|
579
579
|
# move to faulty position ([0-9] was ok)
|
580
580
|
scn.pos = scn.pos + 1
|
581
|
-
lex_error(
|
581
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_NUMBER)
|
582
582
|
end
|
583
583
|
|
584
584
|
when 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
@@ -594,9 +594,9 @@ class Puppet::Pops::Parser::Lexer2
|
|
594
594
|
scn.pos = scn.pos + 1
|
595
595
|
fully_qualified = scn.match?(/::/)
|
596
596
|
if fully_qualified
|
597
|
-
lex_error(
|
597
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_FULLY_QUALIFIED_NAME)
|
598
598
|
else
|
599
|
-
lex_error(
|
599
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_NAME_OR_BARE_WORD)
|
600
600
|
end
|
601
601
|
end
|
602
602
|
|
@@ -608,7 +608,7 @@ class Puppet::Pops::Parser::Lexer2
|
|
608
608
|
else
|
609
609
|
# move to faulty position ([A-Z] was ok)
|
610
610
|
scn.pos = scn.pos + 1
|
611
|
-
lex_error(
|
611
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_CLASS_REFERENCE)
|
612
612
|
end
|
613
613
|
|
614
614
|
when "\n"
|
@@ -3,18 +3,6 @@
|
|
3
3
|
#
|
4
4
|
module Puppet::Pops::Parser::LexerSupport
|
5
5
|
|
6
|
-
# Formats given message by appending file, line and position if available.
|
7
|
-
def positioned_message(msg, pos = nil)
|
8
|
-
result = [msg]
|
9
|
-
file = @locator.file
|
10
|
-
line = @locator.line_for_offset(pos || @scanner.pos)
|
11
|
-
pos = @locator.pos_on_line(pos || @scanner.pos)
|
12
|
-
|
13
|
-
result << "in file #{file}" if file && file.is_a?(String) && !file.empty?
|
14
|
-
result << "at line #{line}:#{pos}"
|
15
|
-
result.join(" ")
|
16
|
-
end
|
17
|
-
|
18
6
|
# Returns "<eof>" if at end of input, else the following 5 characters with \n \r \t escaped
|
19
7
|
def followed_by
|
20
8
|
return "<eof>" if @scanner.eos?
|
@@ -35,13 +23,51 @@ module Puppet::Pops::Parser::LexerSupport
|
|
35
23
|
end
|
36
24
|
|
37
25
|
# Raises a Puppet::LexError with the given message
|
38
|
-
def lex_error_without_pos
|
39
|
-
raise Puppet::
|
26
|
+
def lex_error_without_pos(issue, args = {})
|
27
|
+
raise Puppet::ParseErrorWithIssue.new(issue.format(args), nil, nil, nil, nil, issue.issue_code)
|
40
28
|
end
|
41
29
|
|
42
|
-
# Raises a Puppet::
|
43
|
-
def lex_error(
|
44
|
-
raise
|
30
|
+
# Raises a Puppet::ParserErrorWithIssue with the given issue and arguments
|
31
|
+
def lex_error(issue, args = {}, pos=nil)
|
32
|
+
raise create_lex_error(issue, args, pos)
|
33
|
+
end
|
34
|
+
|
35
|
+
def filename
|
36
|
+
file = @locator.file
|
37
|
+
file.is_a?(String) && !file.empty? ? file : nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def line(pos)
|
41
|
+
@locator.line_for_offset(pos || @scanner.pos)
|
42
|
+
end
|
43
|
+
|
44
|
+
def position(pos)
|
45
|
+
@locator.pos_on_line(pos || @scanner.pos)
|
46
|
+
end
|
47
|
+
|
48
|
+
def lex_warning(issue, args = {}, pos=nil)
|
49
|
+
Puppet::Util::Log.create({
|
50
|
+
:level => :warning,
|
51
|
+
:message => issue.format(args),
|
52
|
+
:issue_code => issue.issue_code,
|
53
|
+
:file => filename,
|
54
|
+
:line => line(pos),
|
55
|
+
:pos => position(pos),
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param issue [Puppet::Pops::Issues::Issue] the issue
|
60
|
+
# @param args [Hash<Symbol,String>] Issue arguments
|
61
|
+
# @param pos [Integer]
|
62
|
+
# @return [Puppet::ParseErrorWithIssue] the created error
|
63
|
+
def create_lex_error(issue, args = {}, pos = nil)
|
64
|
+
Puppet::ParseErrorWithIssue.new(
|
65
|
+
issue.format(args),
|
66
|
+
filename,
|
67
|
+
line(pos),
|
68
|
+
position(pos),
|
69
|
+
nil,
|
70
|
+
issue.issue_code)
|
45
71
|
end
|
46
72
|
|
47
73
|
# Asserts that the given string value is a float, or an integer in decimal, octal or hex form.
|
@@ -49,13 +75,13 @@ module Puppet::Pops::Parser::LexerSupport
|
|
49
75
|
#
|
50
76
|
def assert_numeric(value, length)
|
51
77
|
if value =~ /^0[xX].*$/
|
52
|
-
lex_error(
|
78
|
+
lex_error(Puppet::Pops::Issues::INVALID_HEX_NUMBER, {:value => value}, length) unless value =~ /^0[xX][0-9A-Fa-f]+$/
|
53
79
|
|
54
80
|
elsif value =~ /^0[^.].*$/
|
55
|
-
lex_error(
|
81
|
+
lex_error(Puppet::Pops::Issues::INVALID_OCTAL_NUMBER, {:value => value}, length) unless value =~ /^0[0-7]+$/
|
56
82
|
|
57
83
|
else
|
58
|
-
lex_error(
|
84
|
+
lex_error(Puppet::Pops::Issues::INVALID_DECIMAL_NUMBER, {:value => value}, length) unless value =~ /0?\d+(?:\.\d+)?(?:[eE]-?\d+)?/
|
59
85
|
end
|
60
86
|
end
|
61
87
|
|
@@ -93,11 +93,8 @@ class Puppet::Pops::Parser::Parser
|
|
93
93
|
else
|
94
94
|
value_at = "'#{value[:value]}'"
|
95
95
|
end
|
96
|
-
|
97
|
-
|
98
|
-
else
|
99
|
-
error = "Syntax error at #{value_at}"
|
100
|
-
end
|
96
|
+
error = Puppet::Pops::Issues::SYNTAX_ERROR.format(:where => value_at)
|
97
|
+
error = "#{error}, token: #{token}" if @yydebug
|
101
98
|
|
102
99
|
# Note, old parser had processing of "expected token here" - do not try to reinstate:
|
103
100
|
# The 'expected' is only of value at end of input, otherwise any parse error involving a
|
@@ -110,19 +107,19 @@ class Puppet::Pops::Parser::Parser
|
|
110
107
|
# must be handled by the grammar. The lexer may have enqueued tokens far ahead - the lexer's opinion about this
|
111
108
|
# is not trustworthy.
|
112
109
|
#
|
113
|
-
|
114
|
-
|
110
|
+
file = nil
|
111
|
+
line = nil
|
112
|
+
pos = nil
|
115
113
|
if token != 0
|
116
|
-
|
117
|
-
|
118
|
-
|
114
|
+
file = value[:file]
|
115
|
+
line = value[:line]
|
116
|
+
pos = value[:pos]
|
119
117
|
else
|
120
118
|
# At end of input, use what the lexer thinks is the source file
|
121
|
-
|
119
|
+
file = lexer.file
|
122
120
|
end
|
123
|
-
|
124
|
-
|
125
|
-
raise except
|
121
|
+
file = nil unless file.is_a?(String) && !file.empty?
|
122
|
+
raise Puppet::ParseErrorWithIssue.new(error, file, line, pos, nil, issue_code = Puppet::Pops::Issues::SYNTAX_ERROR.issue_code)
|
126
123
|
end
|
127
124
|
|
128
125
|
# Parses a String of pp DSL code.
|
@@ -7,10 +7,13 @@
|
|
7
7
|
# TODO: More detailed performance analysis of excessive character escaping and interpolation.
|
8
8
|
#
|
9
9
|
module Puppet::Pops::Parser::SlurpSupport
|
10
|
+
include Puppet::Pops::Parser::LexerSupport
|
10
11
|
|
11
12
|
SLURP_SQ_PATTERN = /(?:[^\\]|^|[^\\])(?:[\\]{2})*[']/
|
12
13
|
SLURP_DQ_PATTERN = /(?:[^\\]|^|[^\\])(?:[\\]{2})*(["]|[$]\{?)/
|
13
14
|
SLURP_UQ_PATTERN = /(?:[^\\]|^|[^\\])(?:[\\]{2})*([$]\{?|\z)/
|
15
|
+
# unquoted, no escapes
|
16
|
+
SLURP_UQNE_PATTERN = /(\$\{?|\z)/m
|
14
17
|
SLURP_ALL_PATTERN = /.*(\z)/m
|
15
18
|
SQ_ESCAPES = %w{ \\ ' }
|
16
19
|
DQ_ESCAPES = %w{ \\ $ ' " r n t s u}+["\r\n", "\n"]
|
@@ -19,7 +22,8 @@ module Puppet::Pops::Parser::SlurpSupport
|
|
19
22
|
def slurp_sqstring
|
20
23
|
# skip the leading '
|
21
24
|
@scanner.pos += 1
|
22
|
-
str = slurp(@scanner, SLURP_SQ_PATTERN, SQ_ESCAPES, :ignore_invalid_escapes)
|
25
|
+
str = slurp(@scanner, SLURP_SQ_PATTERN, SQ_ESCAPES, :ignore_invalid_escapes)
|
26
|
+
lex_error(Puppet::Pops::Issues::UNCLOSED_QUOTE, :after => "\"'\"", :followed_by => followed_by) unless str
|
23
27
|
str[0..-2] # strip closing "'" from result
|
24
28
|
end
|
25
29
|
|
@@ -28,7 +32,7 @@ module Puppet::Pops::Parser::SlurpSupport
|
|
28
32
|
last = scn.matched
|
29
33
|
str = slurp(scn, SLURP_DQ_PATTERN, DQ_ESCAPES, false)
|
30
34
|
unless str
|
31
|
-
lex_error(
|
35
|
+
lex_error(Puppet::Pops::Issues::UNCLOSED_QUOTE, :after => format_quote(last), :followed_by => followed_by)
|
32
36
|
end
|
33
37
|
|
34
38
|
# Terminator may be a single char '"', '$', or two characters '${' group match 1 (scn[1]) from the last slurp holds this
|
@@ -41,6 +45,7 @@ module Puppet::Pops::Parser::SlurpSupport
|
|
41
45
|
scn = @scanner
|
42
46
|
last = scn.matched
|
43
47
|
ignore = true
|
48
|
+
|
44
49
|
str = slurp(scn, @lexing_context[:uq_slurp_pattern], @lexing_context[:escapes], :ignore_invalid_escapes)
|
45
50
|
|
46
51
|
# Terminator may be a single char '$', two characters '${', or empty string '' at the end of intput.
|
@@ -65,11 +70,12 @@ module Puppet::Pops::Parser::SlurpSupport
|
|
65
70
|
# Process unicode escapes first as they require getting 4 hex digits
|
66
71
|
# If later a \u is found it is warned not to be a unicode escape
|
67
72
|
if escapes.include?('u')
|
68
|
-
str.gsub!(/\\u([\da-fA-F]{4})/m) {
|
69
|
-
[$1.hex].pack("U")
|
73
|
+
str.gsub!(/\\u(?:([\da-fA-F]{4})|\{([\da-fA-F]{1,6})\})/m) {
|
74
|
+
[($1 || $2).hex].pack("U")
|
70
75
|
}
|
71
76
|
end
|
72
77
|
|
78
|
+
begin
|
73
79
|
str.gsub!(/\\([^\r\n]|(?:\r?\n))/m) {
|
74
80
|
ch = $1
|
75
81
|
if escapes.include? ch
|
@@ -79,17 +85,27 @@ module Puppet::Pops::Parser::SlurpSupport
|
|
79
85
|
when 't' ; "\t"
|
80
86
|
when 's' ; " "
|
81
87
|
when 'u'
|
82
|
-
Puppet
|
88
|
+
lex_warning(Puppet::Pops::Issues::ILLEGAL_UNICODE_ESCAPE)
|
83
89
|
"\\u"
|
84
90
|
when "\n" ; ''
|
85
91
|
when "\r\n"; ''
|
86
92
|
else ch
|
87
93
|
end
|
88
94
|
else
|
89
|
-
Puppet
|
95
|
+
lex_warning(Puppet::Pops::Issues::UNRECOGNIZED_ESCAPE, :ch => ch) unless ignore_invalid_escapes
|
90
96
|
"\\#{ch}"
|
91
97
|
end
|
92
98
|
}
|
99
|
+
rescue ArgumentError => e
|
100
|
+
# A invalid byte sequence may be the result of faulty input as well, but that could not possibly
|
101
|
+
# have reached this far... Unfortunately there is no more specific error and a match on message is
|
102
|
+
# required to differentiate from other internal problems.
|
103
|
+
if e.message =~ /invalid byte sequence/
|
104
|
+
lex_error(Puppet::Pops::Issues::ILLEGAL_UNICODE_ESCAPE)
|
105
|
+
else
|
106
|
+
raise e
|
107
|
+
end
|
108
|
+
end
|
93
109
|
str
|
94
110
|
end
|
95
111
|
end
|
@@ -269,14 +269,21 @@ class Puppet::Pops::Types::TypeCalculator
|
|
269
269
|
if t2.is_a?(Class)
|
270
270
|
t2 = type(t2)
|
271
271
|
end
|
272
|
+
t2_class = t2.class
|
273
|
+
|
272
274
|
# Unit can be assigned to anything
|
273
|
-
return true if
|
275
|
+
return true if t2_class == Types::PUnitType
|
274
276
|
|
275
|
-
if
|
277
|
+
if t2_class == Types::PVariantType
|
276
278
|
# Assignable if all contained types are assignable
|
277
279
|
t2.types.all? { |vt| @@assignable_visitor.visit_this_1(self, t, vt) }
|
278
280
|
else
|
279
|
-
|
281
|
+
# Turn NotUndef[T] into T when T is not assignable from Undef
|
282
|
+
if t2_class == Types::PNotUndefType && !(t2.type.nil? || assignable?(t2.type, @nil_t))
|
283
|
+
assignable?(t, t2.type)
|
284
|
+
else
|
285
|
+
@@assignable_visitor.visit_this_1(self, t, t2)
|
286
|
+
end
|
280
287
|
end
|
281
288
|
end
|
282
289
|
|
@@ -354,10 +361,23 @@ class Puppet::Pops::Types::TypeCalculator
|
|
354
361
|
# do nothing, there is nothing to change for most types
|
355
362
|
end
|
356
363
|
|
364
|
+
# @return [Boolean] true if the given argument is contained in a struct element key
|
365
|
+
def is_struct_element_key?(o)
|
366
|
+
c = o.eContainer
|
367
|
+
if c.is_a?(Types::POptionalType)
|
368
|
+
o = c
|
369
|
+
c = c.eContainer
|
370
|
+
end
|
371
|
+
c.is_a?(Types::PStructElement) && c.key_type.equal?(o)
|
372
|
+
end
|
373
|
+
private :is_struct_element_key?
|
374
|
+
|
357
375
|
def generalize_PStringType(o)
|
358
|
-
|
359
|
-
o
|
360
|
-
|
376
|
+
# Skip generalization if the string is contained in a PStructElement key.
|
377
|
+
unless is_struct_element_key?(o)
|
378
|
+
o.values = []
|
379
|
+
o.size_type = nil
|
380
|
+
end
|
361
381
|
end
|
362
382
|
|
363
383
|
def generalize_PCollectionType(o)
|
@@ -434,8 +454,13 @@ class Puppet::Pops::Types::TypeCalculator
|
|
434
454
|
def instance_of_PStringType(t, o)
|
435
455
|
return false unless o.is_a?(String)
|
436
456
|
# true if size compliant
|
437
|
-
size_t = t.size_type
|
438
|
-
instance_of_PIntegerType(size_t, o.size)
|
457
|
+
size_t = t.size_type
|
458
|
+
if size_t.nil? || instance_of_PIntegerType(size_t, o.size)
|
459
|
+
values = t.values
|
460
|
+
values.empty? || values.include?(o)
|
461
|
+
else
|
462
|
+
false
|
463
|
+
end
|
439
464
|
end
|
440
465
|
|
441
466
|
def instance_of_PTupleType(t, o)
|
@@ -452,9 +477,18 @@ class Puppet::Pops::Types::TypeCalculator
|
|
452
477
|
|
453
478
|
def instance_of_PStructType(t, o)
|
454
479
|
return false unless o.is_a?(Hash)
|
455
|
-
|
456
|
-
|
457
|
-
|
480
|
+
matched = 0
|
481
|
+
t.elements.all? do |e|
|
482
|
+
key = e.name
|
483
|
+
v = o[key]
|
484
|
+
if v.nil? && !o.include?(key)
|
485
|
+
# Entry is missing. Only OK when key is optional
|
486
|
+
assignable?(e.key_type, @nil_t)
|
487
|
+
else
|
488
|
+
matched += 1
|
489
|
+
instance_of(e.value_type, v)
|
490
|
+
end
|
491
|
+
end && matched == o.size
|
458
492
|
end
|
459
493
|
|
460
494
|
def instance_of_PHashType(t, o)
|
@@ -471,6 +505,10 @@ class Puppet::Pops::Types::TypeCalculator
|
|
471
505
|
instance_of(@data_variant_t, o)
|
472
506
|
end
|
473
507
|
|
508
|
+
def instance_of_PNotUndefType(t, o)
|
509
|
+
!(o.nil? || o == :undef) && (t.type.nil? || instance_of(t.type, o))
|
510
|
+
end
|
511
|
+
|
474
512
|
def instance_of_PUndefType(t, o)
|
475
513
|
o.nil? || o == :undef
|
476
514
|
end
|
@@ -598,7 +636,8 @@ class Puppet::Pops::Types::TypeCalculator
|
|
598
636
|
|
599
637
|
if t1.is_a?(Types::PStringType) && t2.is_a?(Types::PStringType)
|
600
638
|
t = Types::PStringType.new()
|
601
|
-
t.values = t1.values | t2.values
|
639
|
+
t.values = t1.values | t2.values unless t1.values.empty? || t2.values.empty?
|
640
|
+
t.size_type = common_type(t1.size_type, t2.size_type) unless t1.size_type.nil? || t2.size_type.nil?
|
602
641
|
return t
|
603
642
|
end
|
604
643
|
|
@@ -937,27 +976,23 @@ class Puppet::Pops::Types::TypeCalculator
|
|
937
976
|
type.key_type = Types::PUndefType.new
|
938
977
|
type.element_type = Types::PUndefType.new
|
939
978
|
type.size_type = size_as_type(o)
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
type.key_type = unwrap_single_variant(ktype)
|
948
|
-
type.element_type = unwrap_single_variant(etype)
|
949
|
-
type.size_type = size_as_type(o)
|
950
|
-
else
|
951
|
-
elements = []
|
952
|
-
o.each_pair do |k,v|
|
953
|
-
element = Types::PStructElement.new
|
954
|
-
element.name = k
|
955
|
-
element.type = infer_set(v)
|
956
|
-
elements << element
|
957
|
-
end
|
958
|
-
type = Types::PStructType.new
|
959
|
-
type.elements = elements
|
979
|
+
elsif o.keys.all? {|k| instance_of_PStringType(@non_empty_string_t, k) }
|
980
|
+
type = Types::PStructType.new
|
981
|
+
type.elements = o.map do |k,v|
|
982
|
+
element = Types::PStructElement.new
|
983
|
+
element.key_type = infer_String(k)
|
984
|
+
element.value_type = infer_set(v)
|
985
|
+
element
|
960
986
|
end
|
987
|
+
else
|
988
|
+
type = Types::PHashType.new
|
989
|
+
ktype = Types::PVariantType.new
|
990
|
+
ktype.types = o.keys.map {|k| infer_set(k) }
|
991
|
+
etype = Types::PVariantType.new
|
992
|
+
etype.types = o.values.map {|e| infer_set(e) }
|
993
|
+
type.key_type = unwrap_single_variant(ktype)
|
994
|
+
type.element_type = unwrap_single_variant(etype)
|
995
|
+
type.size_type = size_as_type(o)
|
961
996
|
end
|
962
997
|
type
|
963
998
|
end
|
@@ -981,6 +1016,11 @@ class Puppet::Pops::Types::TypeCalculator
|
|
981
1016
|
t2.is_a?(Types::PAnyType)
|
982
1017
|
end
|
983
1018
|
|
1019
|
+
# @api private
|
1020
|
+
def assignable_PNotUndefType(t, t2)
|
1021
|
+
!assignable?(t2, @nil_t) && (t.type.nil? || assignable?(t.type, t2))
|
1022
|
+
end
|
1023
|
+
|
984
1024
|
# @api private
|
985
1025
|
def assignable_PUndefType(t, t2)
|
986
1026
|
# Only undef/nil is assignable to nil type
|
@@ -1110,6 +1150,17 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1110
1150
|
end
|
1111
1151
|
end
|
1112
1152
|
|
1153
|
+
# @api private
|
1154
|
+
def self.is_kind_of_optional?(t, optional = true)
|
1155
|
+
case t
|
1156
|
+
when Types::POptionalType
|
1157
|
+
true
|
1158
|
+
when Types::PVariantType
|
1159
|
+
t.types.all? {|t2| is_kind_of_optional?(t2, optional) }
|
1160
|
+
else
|
1161
|
+
false
|
1162
|
+
end
|
1163
|
+
end
|
1113
1164
|
|
1114
1165
|
def callable_PArrayType(args_array, callable_t)
|
1115
1166
|
return false unless assignable?(callable_t.param_types, args_array)
|
@@ -1193,22 +1244,34 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1193
1244
|
#
|
1194
1245
|
def assignable_PStructType(t, t2)
|
1195
1246
|
if t2.is_a?(Types::PStructType)
|
1196
|
-
h = t.hashed_elements
|
1197
1247
|
h2 = t2.hashed_elements
|
1198
|
-
|
1248
|
+
matched = 0
|
1249
|
+
t.elements.all? do |e1|
|
1250
|
+
e2 = h2[e1.name]
|
1251
|
+
if e2.nil?
|
1252
|
+
assignable?(e1.key_type, @nil_t)
|
1253
|
+
else
|
1254
|
+
matched += 1
|
1255
|
+
assignable?(e1.key_type, e2.key_type) && assignable?(e1.value_type, e2.value_type)
|
1256
|
+
end
|
1257
|
+
end && matched == h2.size
|
1199
1258
|
elsif t2.is_a?(Types::PHashType)
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1259
|
+
required = 0
|
1260
|
+
required_elements_assignable = t.elements.all? do |e|
|
1261
|
+
if assignable?(e.key_type, @nil_t)
|
1262
|
+
true
|
1263
|
+
else
|
1264
|
+
required += 1
|
1265
|
+
assignable?(e.value_type, t2.element_type)
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
if required_elements_assignable
|
1269
|
+
size_t2 = t2.size_type || @collection_default_size_t
|
1270
|
+
size_t = Types::PIntegerType.new
|
1271
|
+
size_t.from = required
|
1272
|
+
size_t.to = t.elements.size
|
1273
|
+
assignable_PIntegerType(size_t, size_t2)
|
1274
|
+
end
|
1212
1275
|
else
|
1213
1276
|
false
|
1214
1277
|
end
|
@@ -1217,8 +1280,9 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1217
1280
|
# @api private
|
1218
1281
|
def assignable_POptionalType(t, t2)
|
1219
1282
|
return true if t2.is_a?(Types::PUndefType)
|
1283
|
+
return true if t.optional_type.nil?
|
1220
1284
|
if t2.is_a?(Types::POptionalType)
|
1221
|
-
assignable?(t.optional_type, t2.optional_type)
|
1285
|
+
assignable?(t.optional_type, t2.optional_type || @t)
|
1222
1286
|
else
|
1223
1287
|
assignable?(t.optional_type, t2)
|
1224
1288
|
end
|
@@ -1389,11 +1453,11 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1389
1453
|
# @api private
|
1390
1454
|
def assignable_PArrayType(t, t2)
|
1391
1455
|
if t2.is_a?(Types::PArrayType)
|
1392
|
-
return false unless assignable?(t.element_type, t2.element_type)
|
1456
|
+
return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
|
1393
1457
|
assignable_PCollectionType(t, t2)
|
1394
1458
|
|
1395
1459
|
elsif t2.is_a?(Types::PTupleType)
|
1396
|
-
return false unless t2.types.all? {|t2_element| assignable?(t.element_type, t2_element) }
|
1460
|
+
return false unless t.element_type.nil? || t2.types.all? {|t2_element| assignable?(t.element_type, t2_element) }
|
1397
1461
|
t2_regular = t2.types[0..-2]
|
1398
1462
|
t2_ranged = t2.types[-1]
|
1399
1463
|
t2_from, t2_to = size_range(t2.size_type)
|
@@ -1431,7 +1495,8 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1431
1495
|
case t2
|
1432
1496
|
when Types::PHashType
|
1433
1497
|
return true if (t.size_type.nil? || t.size_type.from == 0) && t2.is_the_empty_hash?
|
1434
|
-
return false unless
|
1498
|
+
return false unless t.key_type.nil? || assignable?(t.key_type, t2.key_type || @t)
|
1499
|
+
return false unless t.element_type.nil? || assignable?(t.element_type, t2.element_type || @t)
|
1435
1500
|
assignable_PCollectionType(t, t2)
|
1436
1501
|
when Types::PStructType
|
1437
1502
|
# hash must accept String as key type
|
@@ -1443,7 +1508,7 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1443
1508
|
key_type = t.key_type
|
1444
1509
|
element_type = t.element_type
|
1445
1510
|
( struct_size >= min && struct_size <= max &&
|
1446
|
-
t2.elements.all? {|e| instance_of(key_type, e.name) && assignable?(element_type, e.
|
1511
|
+
t2.elements.all? {|e| (key_type.nil? || instance_of(key_type, e.name)) && (element_type.nil? || assignable?(element_type, e.value_type)) })
|
1447
1512
|
else
|
1448
1513
|
false
|
1449
1514
|
end
|
@@ -1475,7 +1540,15 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1475
1540
|
# Data is assignable by other Data and by Array[Data] and Hash[Scalar, Data]
|
1476
1541
|
# @api private
|
1477
1542
|
def assignable_PDataType(t, t2)
|
1478
|
-
|
1543
|
+
# We cannot put the NotUndefType[Data] in the @data_variant_t since that causes an endless recursion
|
1544
|
+
case t2
|
1545
|
+
when Types::PDataType
|
1546
|
+
true
|
1547
|
+
when Types::PNotUndefType
|
1548
|
+
assignable?(t, t2.type || @t)
|
1549
|
+
else
|
1550
|
+
assignable?(@data_variant_t, t2)
|
1551
|
+
end
|
1479
1552
|
end
|
1480
1553
|
|
1481
1554
|
# Assignable if t2's has the same runtime and the runtime name resolves to
|
@@ -1646,7 +1719,16 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1646
1719
|
end
|
1647
1720
|
|
1648
1721
|
def string_PStructElement(t)
|
1649
|
-
|
1722
|
+
k = t.key_type
|
1723
|
+
value_optional = assignable?(t.value_type, @nil_t)
|
1724
|
+
key_string =
|
1725
|
+
if k.is_a?(Types::POptionalType)
|
1726
|
+
# Output as literal String
|
1727
|
+
value_optional ? "'#{t.name}'" : string(k)
|
1728
|
+
else
|
1729
|
+
value_optional ? "NotUndef['#{t.name}']" : "'#{t.name}'"
|
1730
|
+
end
|
1731
|
+
"#{key_string}=>#{string(t.value_type)}"
|
1650
1732
|
end
|
1651
1733
|
|
1652
1734
|
# @api private
|
@@ -1712,11 +1794,30 @@ class Puppet::Pops::Types::TypeCalculator
|
|
1712
1794
|
end
|
1713
1795
|
end
|
1714
1796
|
|
1797
|
+
# @api private
|
1798
|
+
def string_PNotUndefType(t)
|
1799
|
+
contained_type = t.type
|
1800
|
+
if contained_type.nil? || contained_type.class == Puppet::Pops::Types::PAnyType
|
1801
|
+
'NotUndef'
|
1802
|
+
else
|
1803
|
+
if contained_type.is_a?(Puppet::Pops::Types::PStringType) && contained_type.values.size == 1
|
1804
|
+
"NotUndef['#{contained_type.values[0]}']"
|
1805
|
+
else
|
1806
|
+
"NotUndef[#{string(contained_type)}]"
|
1807
|
+
end
|
1808
|
+
end
|
1809
|
+
end
|
1810
|
+
|
1715
1811
|
def string_POptionalType(t)
|
1716
|
-
|
1812
|
+
optional_type = t.optional_type
|
1813
|
+
if optional_type.nil?
|
1717
1814
|
"Optional"
|
1718
1815
|
else
|
1719
|
-
|
1816
|
+
if optional_type.is_a?(Puppet::Pops::Types::PStringType) && optional_type.values.size == 1
|
1817
|
+
"Optional['#{optional_type.values[0]}']"
|
1818
|
+
else
|
1819
|
+
"Optional[#{string(optional_type)}]"
|
1820
|
+
end
|
1720
1821
|
end
|
1721
1822
|
end
|
1722
1823
|
|