prism 1.9.0 → 2.0.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +88 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE.md +1 -1
- data/Makefile +41 -12
- data/README.md +35 -97
- data/config.yml +174 -161
- data/docs/build_system.md +2 -2
- data/docs/configuration.md +5 -4
- data/docs/encoding.md +2 -2
- data/docs/fuzzing.md +4 -11
- data/docs/javascript.md +19 -4
- data/docs/mapping.md +1 -1
- data/docs/releasing.md +77 -5
- data/docs/relocation.md +2 -4
- data/docs/serialization.md +22 -24
- data/docs/testing.md +46 -29
- data/ext/prism/api_node.c +1461 -1401
- data/ext/prism/extconf.rb +3 -4
- data/ext/prism/extension.c +796 -422
- data/ext/prism/extension.h +3 -3
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +2727 -610
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +26 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/bswap.h +46 -0
- data/include/prism/compiler/endianness.h +34 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +38 -403
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +94 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/{encoding.h → internal/encoding.h} +27 -68
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +1004 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
- data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/internal/xxh3.h +16 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +18 -53
- data/include/prism/options.h +146 -280
- data/include/prism/parser.h +356 -867
- data/include/prism/prettyprint.h +6 -9
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +74 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +12 -3
- data/include/prism.h +43 -320
- data/lib/prism/compiler.rb +319 -305
- data/lib/prism/desugar_compiler.rb +105 -34
- data/lib/prism/dispatcher.rb +646 -473
- data/lib/prism/dot_visitor.rb +592 -511
- data/lib/prism/dsl.rb +391 -25
- data/lib/prism/ffi.rb +258 -90
- data/lib/prism/inspect_visitor.rb +357 -325
- data/lib/prism/lex_compat.rb +254 -212
- data/lib/prism/mutation_compiler.rb +313 -305
- data/lib/prism/node.rb +20966 -6992
- data/lib/prism/node_ext.rb +180 -187
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +7 -1
- data/lib/prism/parse_result/newlines.rb +276 -8
- data/lib/prism/parse_result.rb +468 -139
- data/lib/prism/pattern.rb +65 -20
- data/lib/prism/reflection.rb +23 -12
- data/lib/prism/relocation.rb +149 -87
- data/lib/prism/serialize.rb +3460 -539
- data/lib/prism/string_query.rb +24 -1
- data/lib/prism/translation/parser/builder.rb +10 -2
- data/lib/prism/translation/parser/compiler.rb +44 -52
- data/lib/prism/translation/parser/lexer.rb +41 -92
- data/lib/prism/translation/parser.rb +1 -1
- data/lib/prism/translation/parser_current.rb +1 -1
- data/lib/prism/translation/ripper/lexer.rb +8 -10
- data/lib/prism/translation/ripper/sexp.rb +2 -10
- data/lib/prism/translation/ripper/shim.rb +2 -0
- data/lib/prism/translation/ripper.rb +967 -209
- data/lib/prism/translation/ruby_parser.rb +73 -316
- data/lib/prism/translation.rb +2 -0
- data/lib/prism/visitor.rb +632 -5
- data/lib/prism.rb +79 -9
- data/prism.gemspec +128 -62
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +14407 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +776 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +184 -0
- data/rbi/generated/prism/string_query.rbi +43 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser_versions.rbi +5 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
- data/sig/generated/prism/node.rbs +20896 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +871 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +198 -0
- data/sig/generated/prism/string_query.rbs +43 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/{util/pm_buffer.c → buffer.c} +53 -21
- data/src/{util/pm_char.c → char.c} +28 -57
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +97 -65
- data/src/encoding.c +8 -3
- data/src/errors_format.c +519 -0
- data/src/{util/pm_integer.c → integer.c} +33 -22
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/{util/pm_memchr.c → memchr.c} +8 -6
- data/src/node.c +3504 -7674
- data/src/options.c +162 -49
- data/src/parser.c +367 -0
- data/src/prettyprint.c +421 -354
- data/src/prism.c +8402 -7161
- data/src/regexp.c +961 -45
- data/src/serialize.c +460 -424
- data/src/source.c +518 -0
- data/src/static_literals.c +111 -43
- data/src/string_query.c +180 -0
- data/src/stringy.c +91 -0
- data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
- data/src/strpbrk.c +447 -0
- data/src/{token_type.c → tokens.c} +39 -18
- data/src/xxh3.c +292 -0
- metadata +128 -63
- data/ext/prism/api_pack.c +0 -276
- data/include/prism/defines.h +0 -260
- data/include/prism/pack.h +0 -163
- data/include/prism/regexp.h +0 -43
- data/include/prism/util/pm_buffer.h +0 -236
- data/include/prism/util/pm_char.h +0 -204
- data/include/prism/util/pm_constant_pool.h +0 -218
- data/include/prism/util/pm_integer.h +0 -130
- data/include/prism/util/pm_memchr.h +0 -29
- data/include/prism/util/pm_newline_list.h +0 -113
- data/include/prism/util/pm_string.h +0 -200
- data/lib/prism/pack.rb +0 -230
- data/lib/prism/parse_result/comments.rb +0 -188
- data/rbi/prism/compiler.rbi +0 -12
- data/rbi/prism/dsl.rbi +0 -524
- data/rbi/prism/inspect_visitor.rbi +0 -12
- data/rbi/prism/node.rbi +0 -8750
- data/rbi/prism/node_ext.rbi +0 -107
- data/rbi/prism/parse_result.rbi +0 -404
- data/rbi/prism/reflection.rbi +0 -58
- data/rbi/prism/string_query.rbi +0 -12
- data/rbi/prism/visitor.rbi +0 -473
- data/rbi/prism.rbi +0 -63
- data/sig/prism/compiler.rbs +0 -9
- data/sig/prism/dispatcher.rbs +0 -19
- data/sig/prism/dot_visitor.rbs +0 -6
- data/sig/prism/dsl.rbs +0 -351
- data/sig/prism/inspect_visitor.rbs +0 -22
- data/sig/prism/lex_compat.rbs +0 -10
- data/sig/prism/node.rbs +0 -4042
- data/sig/prism/node_ext.rbs +0 -149
- data/sig/prism/pack.rbs +0 -43
- data/sig/prism/parse_result/comments.rbs +0 -38
- data/sig/prism/parse_result.rbs +0 -197
- data/sig/prism/pattern.rbs +0 -13
- data/sig/prism/reflection.rbs +0 -50
- data/sig/prism/relocation.rbs +0 -185
- data/sig/prism/serialize.rbs +0 -8
- data/sig/prism/string_query.rbs +0 -11
- data/sig/prism/visitor.rbs +0 -169
- data/sig/prism.rbs +0 -272
- data/src/pack.c +0 -509
- data/src/util/pm_constant_pool.c +0 -342
- data/src/util/pm_list.c +0 -49
- data/src/util/pm_newline_list.c +0 -125
- data/src/util/pm_string.c +0 -381
- data/src/util/pm_strpbrk.c +0 -206
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
5
|
+
|
|
6
|
+
module Prism
|
|
7
|
+
# Finds the Prism AST node corresponding to a given Method, UnboundMethod,
|
|
8
|
+
# Proc, or Thread::Backtrace::Location. On CRuby, uses node_id from the
|
|
9
|
+
# instruction sequence for an exact match. On other implementations, falls
|
|
10
|
+
# back to best-effort matching by source location line number.
|
|
11
|
+
#
|
|
12
|
+
# This module is autoloaded so that programs that don't use Prism.find don't
|
|
13
|
+
# pay for its definition.
|
|
14
|
+
module NodeFind # :nodoc:
|
|
15
|
+
# Find the node for the given callable or backtrace location.
|
|
16
|
+
#
|
|
17
|
+
#: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node?
|
|
18
|
+
def self.find(callable)
|
|
19
|
+
if callable.respond_to?(:source_range) && !defined?(::RubyVM)
|
|
20
|
+
return SourceRangeFind.new.find(callable)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
case callable
|
|
24
|
+
when Proc
|
|
25
|
+
if defined?(::RubyVM)
|
|
26
|
+
RubyVMCallableFind.new.find(callable)
|
|
27
|
+
elsif callable.lambda?
|
|
28
|
+
LineLambdaFind.new.find(callable)
|
|
29
|
+
else
|
|
30
|
+
LineProcFind.new.find(callable)
|
|
31
|
+
end
|
|
32
|
+
when Method, UnboundMethod
|
|
33
|
+
if defined?(::RubyVM)
|
|
34
|
+
RubyVMCallableFind.new.find(callable)
|
|
35
|
+
else
|
|
36
|
+
LineMethodFind.new.find(callable)
|
|
37
|
+
end
|
|
38
|
+
when Thread::Backtrace::Location
|
|
39
|
+
if defined?(::RubyVM)
|
|
40
|
+
RubyVMBacktraceLocationFind.new.find(callable)
|
|
41
|
+
else
|
|
42
|
+
LineBacktraceLocationFind.new.find(callable)
|
|
43
|
+
end
|
|
44
|
+
else
|
|
45
|
+
raise ArgumentError, "Expected a Method, UnboundMethod, Proc, or Thread::Backtrace::Location, got #{callable.class}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Base class that handles parsing a file.
|
|
50
|
+
class Find
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# Parse the given file path, returning a ParseResult or nil.
|
|
54
|
+
#
|
|
55
|
+
#: (String? file) -> ParseResult?
|
|
56
|
+
def parse_file(file)
|
|
57
|
+
return unless file && File.readable?(file)
|
|
58
|
+
result = Prism.parse_file(file)
|
|
59
|
+
result if result.success?
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Finds the AST node for a Method, UnboundMethod, Proc or Thread::Backtrace::Location
|
|
64
|
+
# using the #source_range
|
|
65
|
+
class SourceRangeFind < Find
|
|
66
|
+
# Find the node for the given callable using the #source_range.
|
|
67
|
+
#
|
|
68
|
+
#: (Method | UnboundMethod | Proc | Thread::Backtrace::Location callable) -> Node?
|
|
69
|
+
def find(callable)
|
|
70
|
+
begin
|
|
71
|
+
range = callable.source_range
|
|
72
|
+
rescue ArgumentError # eval
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
return unless range
|
|
76
|
+
return unless (result = parse_file(range.absolute_path))
|
|
77
|
+
|
|
78
|
+
start_offset = result.source.byte_offset(range.start_line, range.start_column)
|
|
79
|
+
end_offset = result.source.byte_offset(range.end_line, range.end_column)
|
|
80
|
+
result.value.tunnel(range.start_line, range.start_column).reverse_each do |node|
|
|
81
|
+
if node.start_offset == start_offset && node.end_offset == end_offset
|
|
82
|
+
return node
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
nil
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Finds the AST node for a Method, UnboundMethod, or Proc using the node_id
|
|
90
|
+
# from the instruction sequence.
|
|
91
|
+
class RubyVMCallableFind < Find
|
|
92
|
+
# Find the node for the given callable using the ISeq node_id.
|
|
93
|
+
#
|
|
94
|
+
#: (Method | UnboundMethod | Proc callable) -> Node?
|
|
95
|
+
def find(callable)
|
|
96
|
+
return unless (source_location = callable.source_location)
|
|
97
|
+
return unless (result = parse_file(source_location[0]))
|
|
98
|
+
return unless (iseq = RubyVM::InstructionSequence.of(callable))
|
|
99
|
+
|
|
100
|
+
header = iseq.to_a[4]
|
|
101
|
+
return unless header[:parser] == :prism
|
|
102
|
+
|
|
103
|
+
result.value.find { |node| node.node_id == header[:node_id] }
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Finds the AST node for a Thread::Backtrace::Location using the node_id
|
|
108
|
+
# from the backtrace location.
|
|
109
|
+
class RubyVMBacktraceLocationFind < Find
|
|
110
|
+
# Find the node for the given backtrace location using node_id.
|
|
111
|
+
#
|
|
112
|
+
#: (Thread::Backtrace::Location location) -> Node?
|
|
113
|
+
def find(location)
|
|
114
|
+
file = location.absolute_path || location.path
|
|
115
|
+
return unless (result = parse_file(file))
|
|
116
|
+
return unless RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location)
|
|
117
|
+
|
|
118
|
+
node_id = RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location(location)
|
|
119
|
+
|
|
120
|
+
result.value.find { |node| node.node_id == node_id }
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Finds the AST node for a Method or UnboundMethod using best-effort line
|
|
125
|
+
# matching. Used on non-CRuby implementations.
|
|
126
|
+
class LineMethodFind < Find
|
|
127
|
+
# Find the node for the given method by matching on name and line.
|
|
128
|
+
#
|
|
129
|
+
#: (Method | UnboundMethod callable) -> Node?
|
|
130
|
+
def find(callable)
|
|
131
|
+
return unless (source_location = callable.source_location)
|
|
132
|
+
return unless (result = parse_file(source_location[0]))
|
|
133
|
+
|
|
134
|
+
name = callable.name
|
|
135
|
+
start_line = source_location[1]
|
|
136
|
+
|
|
137
|
+
result.value.find do |node|
|
|
138
|
+
case node
|
|
139
|
+
when DefNode
|
|
140
|
+
node.name == name && node.location.start_line == start_line
|
|
141
|
+
when CallNode
|
|
142
|
+
node.block.is_a?(BlockNode) && node.location.start_line == start_line
|
|
143
|
+
else
|
|
144
|
+
false
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Finds the AST node for a lambda using best-effort line matching. Used
|
|
151
|
+
# on non-CRuby implementations.
|
|
152
|
+
class LineLambdaFind < Find
|
|
153
|
+
# Find the node for the given lambda by matching on line.
|
|
154
|
+
#
|
|
155
|
+
#: (Proc callable) -> Node?
|
|
156
|
+
def find(callable)
|
|
157
|
+
return unless (source_location = callable.source_location)
|
|
158
|
+
return unless (result = parse_file(source_location[0]))
|
|
159
|
+
|
|
160
|
+
start_line = source_location[1]
|
|
161
|
+
|
|
162
|
+
result.value.find do |node|
|
|
163
|
+
case node
|
|
164
|
+
when LambdaNode
|
|
165
|
+
node.location.start_line == start_line
|
|
166
|
+
when CallNode
|
|
167
|
+
node.block.is_a?(BlockNode) && node.location.start_line == start_line
|
|
168
|
+
else
|
|
169
|
+
false
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Finds the AST node for a non-lambda Proc using best-effort line
|
|
176
|
+
# matching. Used on non-CRuby implementations.
|
|
177
|
+
class LineProcFind < Find
|
|
178
|
+
# Find the node for the given proc by matching on line.
|
|
179
|
+
#
|
|
180
|
+
#: (Proc callable) -> Node?
|
|
181
|
+
def find(callable)
|
|
182
|
+
return unless (source_location = callable.source_location)
|
|
183
|
+
return unless (result = parse_file(source_location[0]))
|
|
184
|
+
|
|
185
|
+
start_line = source_location[1]
|
|
186
|
+
|
|
187
|
+
result.value.find do |node|
|
|
188
|
+
case node
|
|
189
|
+
when ForNode
|
|
190
|
+
node.location.start_line == start_line
|
|
191
|
+
when CallNode
|
|
192
|
+
node.block.is_a?(BlockNode) && node.location.start_line == start_line
|
|
193
|
+
else
|
|
194
|
+
false
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Finds the AST node for a Thread::Backtrace::Location using best-effort
|
|
201
|
+
# line matching. Used on non-CRuby implementations.
|
|
202
|
+
class LineBacktraceLocationFind < Find
|
|
203
|
+
# Find the node for the given backtrace location by matching on line.
|
|
204
|
+
#
|
|
205
|
+
#: (Thread::Backtrace::Location location) -> Node?
|
|
206
|
+
def find(location)
|
|
207
|
+
file = location.absolute_path || location.path
|
|
208
|
+
return unless (result = parse_file(file))
|
|
209
|
+
|
|
210
|
+
start_line = location.lineno
|
|
211
|
+
result.value.find { |node| node.location.start_line == start_line }
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
3
5
|
|
|
4
6
|
require "stringio"
|
|
5
7
|
|
|
@@ -9,14 +11,18 @@ module Prism
|
|
|
9
11
|
# can be used to format the errors in a human-readable way.
|
|
10
12
|
class Errors
|
|
11
13
|
# The parse result that contains the errors.
|
|
12
|
-
attr_reader :parse_result
|
|
14
|
+
attr_reader :parse_result #: ParseResult
|
|
13
15
|
|
|
14
16
|
# Initialize a new set of errors from the given parse result.
|
|
17
|
+
#
|
|
18
|
+
#: (ParseResult parse_result) -> void
|
|
15
19
|
def initialize(parse_result)
|
|
16
20
|
@parse_result = parse_result
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
# Formats the errors in a human-readable way and return them as a string.
|
|
24
|
+
#
|
|
25
|
+
#: () -> String
|
|
20
26
|
def format
|
|
21
27
|
error_lines = {} #: Hash[Integer, Array[ParseError]]
|
|
22
28
|
parse_result.errors.each do |error|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
3
5
|
|
|
4
6
|
module Prism
|
|
5
7
|
class ParseResult < Result
|
|
@@ -24,13 +26,20 @@ module Prism
|
|
|
24
26
|
# that case. We do that to avoid storing the extra `@newline` instance
|
|
25
27
|
# variable on every node if we don't need it.
|
|
26
28
|
class Newlines < Visitor
|
|
29
|
+
# The map of lines indices to whether or not they have been marked as
|
|
30
|
+
# emitting a newline event.
|
|
31
|
+
# @rbs @lines: Array[bool]
|
|
32
|
+
|
|
27
33
|
# Create a new Newlines visitor with the given newline offsets.
|
|
34
|
+
#
|
|
35
|
+
#: (Integer lines) -> void
|
|
28
36
|
def initialize(lines)
|
|
29
|
-
# @type var lines: Integer
|
|
30
37
|
@lines = Array.new(1 + lines, false)
|
|
31
38
|
end
|
|
32
39
|
|
|
33
|
-
# Permit block
|
|
40
|
+
# Permit block nodes to mark newlines within themselves.
|
|
41
|
+
#
|
|
42
|
+
#: (BlockNode node) -> void
|
|
34
43
|
def visit_block_node(node)
|
|
35
44
|
old_lines = @lines
|
|
36
45
|
@lines = Array.new(old_lines.size, false)
|
|
@@ -42,17 +51,150 @@ module Prism
|
|
|
42
51
|
end
|
|
43
52
|
end
|
|
44
53
|
|
|
45
|
-
|
|
54
|
+
# Permit lambda nodes to mark newlines within themselves.
|
|
55
|
+
#
|
|
56
|
+
#: (LambdaNode node) -> void
|
|
57
|
+
def visit_lambda_node(node)
|
|
58
|
+
old_lines = @lines
|
|
59
|
+
@lines = Array.new(old_lines.size, false)
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
super(node)
|
|
63
|
+
ensure
|
|
64
|
+
@lines = old_lines
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Permit def nodes to mark newlines within themselves. The body of an
|
|
69
|
+
# endless method definition never emits newline events, so in that case
|
|
70
|
+
# mark every line as already seen while visiting it instead. Nested
|
|
71
|
+
# scopes (blocks, lambdas, etc.) reset the lines and emit events again.
|
|
72
|
+
#
|
|
73
|
+
#: (DefNode node) -> void
|
|
74
|
+
def visit_def_node(node)
|
|
75
|
+
old_lines = @lines
|
|
76
|
+
@lines = Array.new(old_lines.size, !node.equal_loc.nil?)
|
|
77
|
+
|
|
78
|
+
begin
|
|
79
|
+
super(node)
|
|
80
|
+
ensure
|
|
81
|
+
@lines = old_lines
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Permit class nodes to mark newlines within themselves.
|
|
86
|
+
#
|
|
87
|
+
#: (ClassNode node) -> void
|
|
88
|
+
def visit_class_node(node)
|
|
89
|
+
old_lines = @lines
|
|
90
|
+
@lines = Array.new(old_lines.size, false)
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
super(node)
|
|
94
|
+
ensure
|
|
95
|
+
@lines = old_lines
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Permit module nodes to mark newlines within themselves.
|
|
100
|
+
#
|
|
101
|
+
#: (ModuleNode node) -> void
|
|
102
|
+
def visit_module_node(node)
|
|
103
|
+
old_lines = @lines
|
|
104
|
+
@lines = Array.new(old_lines.size, false)
|
|
105
|
+
|
|
106
|
+
begin
|
|
107
|
+
super(node)
|
|
108
|
+
ensure
|
|
109
|
+
@lines = old_lines
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Permit singleton class nodes to mark newlines within themselves.
|
|
114
|
+
#
|
|
115
|
+
#: (SingletonClassNode node) -> void
|
|
116
|
+
def visit_singleton_class_node(node)
|
|
117
|
+
old_lines = @lines
|
|
118
|
+
@lines = Array.new(old_lines.size, false)
|
|
119
|
+
|
|
120
|
+
begin
|
|
121
|
+
super(node)
|
|
122
|
+
ensure
|
|
123
|
+
@lines = old_lines
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Statements inside string interpolation do not emit newline events, so
|
|
128
|
+
# mark every line as already seen while visiting them. Nested scopes
|
|
129
|
+
# (blocks, lambdas, defs, etc.) reset the lines and emit events again.
|
|
130
|
+
#
|
|
131
|
+
#: (EmbeddedStatementsNode node) -> void
|
|
132
|
+
def visit_embedded_statements_node(node)
|
|
133
|
+
old_lines = @lines
|
|
134
|
+
@lines = Array.new(old_lines.size, true)
|
|
135
|
+
|
|
136
|
+
begin
|
|
137
|
+
super(node)
|
|
138
|
+
ensure
|
|
139
|
+
@lines = old_lines
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# The predicate of a while loop is compiled at the end of the loop,
|
|
144
|
+
# after the body, so any statements it contains (from parentheses)
|
|
145
|
+
# emit their line events again even if the lines were already seen.
|
|
146
|
+
#
|
|
147
|
+
#: (WhileNode node) -> void
|
|
148
|
+
def visit_while_node(node)
|
|
149
|
+
old_lines = @lines
|
|
150
|
+
@lines = Array.new(old_lines.size, false)
|
|
151
|
+
|
|
152
|
+
begin
|
|
153
|
+
visit(node.predicate)
|
|
154
|
+
ensure
|
|
155
|
+
@lines = old_lines
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
visit(node.statements)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# The predicate of an until loop is compiled at the end of the loop,
|
|
162
|
+
# after the body, so any statements it contains (from parentheses)
|
|
163
|
+
# emit their line events again even if the lines were already seen.
|
|
164
|
+
#
|
|
165
|
+
#: (UntilNode node) -> void
|
|
166
|
+
def visit_until_node(node)
|
|
167
|
+
old_lines = @lines
|
|
168
|
+
@lines = Array.new(old_lines.size, false)
|
|
46
169
|
|
|
47
|
-
|
|
170
|
+
begin
|
|
171
|
+
visit(node.predicate)
|
|
172
|
+
ensure
|
|
173
|
+
@lines = old_lines
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
visit(node.statements)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Mark if nodes as newlines.
|
|
180
|
+
#
|
|
181
|
+
#: (IfNode node) -> void
|
|
48
182
|
def visit_if_node(node)
|
|
49
183
|
node.newline_flag!(@lines)
|
|
50
184
|
super(node)
|
|
51
185
|
end
|
|
52
186
|
|
|
53
|
-
|
|
187
|
+
# Mark unless nodes as newlines.
|
|
188
|
+
#
|
|
189
|
+
#: (UnlessNode node) -> void
|
|
190
|
+
def visit_unless_node(node)
|
|
191
|
+
node.newline_flag!(@lines)
|
|
192
|
+
super(node)
|
|
193
|
+
end
|
|
54
194
|
|
|
55
195
|
# Permit statements lists to mark newlines within themselves.
|
|
196
|
+
#
|
|
197
|
+
#: (StatementsNode node) -> void
|
|
56
198
|
def visit_statements_node(node)
|
|
57
199
|
node.body.each do |child|
|
|
58
200
|
child.newline_flag!(@lines)
|
|
@@ -63,10 +205,16 @@ module Prism
|
|
|
63
205
|
end
|
|
64
206
|
|
|
65
207
|
class Node
|
|
208
|
+
# Tracks whether or not this node should emit a newline event when the
|
|
209
|
+
# instructions that it represents are executed.
|
|
210
|
+
# @rbs @newline_flag: bool
|
|
211
|
+
|
|
212
|
+
#: () -> bool
|
|
66
213
|
def newline_flag? # :nodoc:
|
|
67
214
|
!!defined?(@newline_flag)
|
|
68
215
|
end
|
|
69
216
|
|
|
217
|
+
#: (Array[bool] lines) -> void
|
|
70
218
|
def newline_flag!(lines) # :nodoc:
|
|
71
219
|
line = location.start_line
|
|
72
220
|
unless lines[line]
|
|
@@ -77,48 +225,160 @@ module Prism
|
|
|
77
225
|
end
|
|
78
226
|
|
|
79
227
|
class BeginNode < Node
|
|
228
|
+
#: (Array[bool] lines) -> void
|
|
80
229
|
def newline_flag!(lines) # :nodoc:
|
|
81
230
|
# Never mark BeginNode with a newline flag, mark children instead.
|
|
82
231
|
end
|
|
83
232
|
end
|
|
84
233
|
|
|
85
234
|
class ParenthesesNode < Node
|
|
235
|
+
#: (Array[bool] lines) -> void
|
|
86
236
|
def newline_flag!(lines) # :nodoc:
|
|
87
237
|
# Never mark ParenthesesNode with a newline flag, mark children instead.
|
|
88
238
|
end
|
|
89
239
|
end
|
|
90
240
|
|
|
91
241
|
class IfNode < Node
|
|
242
|
+
#: (Array[bool] lines) -> void
|
|
92
243
|
def newline_flag!(lines) # :nodoc:
|
|
93
244
|
predicate.newline_flag!(lines)
|
|
94
245
|
end
|
|
95
246
|
end
|
|
96
247
|
|
|
97
248
|
class UnlessNode < Node
|
|
249
|
+
#: (Array[bool] lines) -> void
|
|
98
250
|
def newline_flag!(lines) # :nodoc:
|
|
99
251
|
predicate.newline_flag!(lines)
|
|
100
252
|
end
|
|
101
253
|
end
|
|
102
254
|
|
|
103
255
|
class UntilNode < Node
|
|
256
|
+
#: (Array[bool] lines) -> void
|
|
104
257
|
def newline_flag!(lines) # :nodoc:
|
|
105
|
-
predicate.
|
|
258
|
+
if location.start_offset == keyword_loc.start_offset && predicate.is_a?(ParenthesesNode)
|
|
259
|
+
# A parenthesized predicate emits its own line event when it is
|
|
260
|
+
# compiled at the end of the loop, in addition to this one.
|
|
261
|
+
super
|
|
262
|
+
else
|
|
263
|
+
predicate.newline_flag!(lines)
|
|
264
|
+
end
|
|
106
265
|
end
|
|
107
266
|
end
|
|
108
267
|
|
|
109
268
|
class WhileNode < Node
|
|
269
|
+
#: (Array[bool] lines) -> void
|
|
110
270
|
def newline_flag!(lines) # :nodoc:
|
|
111
|
-
predicate.
|
|
271
|
+
if location.start_offset == keyword_loc.start_offset && predicate.is_a?(ParenthesesNode)
|
|
272
|
+
# A parenthesized predicate emits its own line event when it is
|
|
273
|
+
# compiled at the end of the loop, in addition to this one.
|
|
274
|
+
super
|
|
275
|
+
else
|
|
276
|
+
predicate.newline_flag!(lines)
|
|
277
|
+
end
|
|
112
278
|
end
|
|
113
279
|
end
|
|
114
280
|
|
|
115
281
|
class RescueModifierNode < Node
|
|
282
|
+
#: (Array[bool] lines) -> void
|
|
116
283
|
def newline_flag!(lines) # :nodoc:
|
|
117
284
|
expression.newline_flag!(lines)
|
|
118
285
|
end
|
|
119
286
|
end
|
|
120
287
|
|
|
288
|
+
# The line event for a statement is emitted where its first instruction is
|
|
289
|
+
# compiled, so nodes whose first instruction comes from a sub-expression
|
|
290
|
+
# delegate their newline flag to that sub-expression: assignments to their
|
|
291
|
+
# value, calls to their receiver, and array, hash, and interpolated string
|
|
292
|
+
# literals to their first element. Static literals are the exception: they
|
|
293
|
+
# are compiled to a single instruction on the first line of the literal, so
|
|
294
|
+
# they do not delegate.
|
|
295
|
+
|
|
296
|
+
class LocalVariableWriteNode < Node
|
|
297
|
+
#: (Array[bool] lines) -> void
|
|
298
|
+
def newline_flag!(lines) # :nodoc:
|
|
299
|
+
value.newline_flag!(lines)
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
class InstanceVariableWriteNode < Node
|
|
304
|
+
#: (Array[bool] lines) -> void
|
|
305
|
+
def newline_flag!(lines) # :nodoc:
|
|
306
|
+
value.newline_flag!(lines)
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
class ClassVariableWriteNode < Node
|
|
311
|
+
#: (Array[bool] lines) -> void
|
|
312
|
+
def newline_flag!(lines) # :nodoc:
|
|
313
|
+
value.newline_flag!(lines)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
class GlobalVariableWriteNode < Node
|
|
318
|
+
#: (Array[bool] lines) -> void
|
|
319
|
+
def newline_flag!(lines) # :nodoc:
|
|
320
|
+
value.newline_flag!(lines)
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
class ConstantWriteNode < Node
|
|
325
|
+
#: (Array[bool] lines) -> void
|
|
326
|
+
def newline_flag!(lines) # :nodoc:
|
|
327
|
+
value.newline_flag!(lines)
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
class ConstantPathWriteNode < Node
|
|
332
|
+
#: (Array[bool] lines) -> void
|
|
333
|
+
def newline_flag!(lines) # :nodoc:
|
|
334
|
+
value.newline_flag!(lines)
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
class MultiWriteNode < Node
|
|
339
|
+
#: (Array[bool] lines) -> void
|
|
340
|
+
def newline_flag!(lines) # :nodoc:
|
|
341
|
+
value.newline_flag!(lines)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
class CallNode < Node
|
|
346
|
+
#: (Array[bool] lines) -> void
|
|
347
|
+
def newline_flag!(lines) # :nodoc:
|
|
348
|
+
if (receiver = self.receiver)
|
|
349
|
+
receiver.newline_flag!(lines)
|
|
350
|
+
else
|
|
351
|
+
super
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
class ArrayNode < Node
|
|
357
|
+
#: (Array[bool] lines) -> void
|
|
358
|
+
def newline_flag!(lines) # :nodoc:
|
|
359
|
+
first = elements.first
|
|
360
|
+
if first && !static_literal?
|
|
361
|
+
first.newline_flag!(lines)
|
|
362
|
+
else
|
|
363
|
+
super
|
|
364
|
+
end
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
class HashNode < Node
|
|
369
|
+
#: (Array[bool] lines) -> void
|
|
370
|
+
def newline_flag!(lines) # :nodoc:
|
|
371
|
+
first = elements.first
|
|
372
|
+
if first && !static_literal?
|
|
373
|
+
first.newline_flag!(lines)
|
|
374
|
+
else
|
|
375
|
+
super
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
121
380
|
class InterpolatedMatchLastLineNode < Node
|
|
381
|
+
#: (Array[bool] lines) -> void
|
|
122
382
|
def newline_flag!(lines) # :nodoc:
|
|
123
383
|
first = parts.first
|
|
124
384
|
first.newline_flag!(lines) if first
|
|
@@ -126,6 +386,7 @@ module Prism
|
|
|
126
386
|
end
|
|
127
387
|
|
|
128
388
|
class InterpolatedRegularExpressionNode < Node
|
|
389
|
+
#: (Array[bool] lines) -> void
|
|
129
390
|
def newline_flag!(lines) # :nodoc:
|
|
130
391
|
first = parts.first
|
|
131
392
|
first.newline_flag!(lines) if first
|
|
@@ -133,13 +394,19 @@ module Prism
|
|
|
133
394
|
end
|
|
134
395
|
|
|
135
396
|
class InterpolatedStringNode < Node
|
|
397
|
+
#: (Array[bool] lines) -> void
|
|
136
398
|
def newline_flag!(lines) # :nodoc:
|
|
137
399
|
first = parts.first
|
|
138
|
-
first
|
|
400
|
+
if first && !static_literal?
|
|
401
|
+
first.newline_flag!(lines)
|
|
402
|
+
else
|
|
403
|
+
super
|
|
404
|
+
end
|
|
139
405
|
end
|
|
140
406
|
end
|
|
141
407
|
|
|
142
408
|
class InterpolatedSymbolNode < Node
|
|
409
|
+
#: (Array[bool] lines) -> void
|
|
143
410
|
def newline_flag!(lines) # :nodoc:
|
|
144
411
|
first = parts.first
|
|
145
412
|
first.newline_flag!(lines) if first
|
|
@@ -147,6 +414,7 @@ module Prism
|
|
|
147
414
|
end
|
|
148
415
|
|
|
149
416
|
class InterpolatedXStringNode < Node
|
|
417
|
+
#: (Array[bool] lines) -> void
|
|
150
418
|
def newline_flag!(lines) # :nodoc:
|
|
151
419
|
first = parts.first
|
|
152
420
|
first.newline_flag!(lines) if first
|