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
data/lib/prism/lex_compat.rb
CHANGED
|
@@ -1,26 +1,64 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
3
5
|
|
|
4
6
|
module Prism
|
|
7
|
+
# @rbs!
|
|
8
|
+
# module Translation
|
|
9
|
+
# class Ripper
|
|
10
|
+
# EXPR_NONE: Integer
|
|
11
|
+
# EXPR_BEG: Integer
|
|
12
|
+
# EXPR_MID: Integer
|
|
13
|
+
# EXPR_END: Integer
|
|
14
|
+
# EXPR_CLASS: Integer
|
|
15
|
+
# EXPR_VALUE: Integer
|
|
16
|
+
# EXPR_ARG: Integer
|
|
17
|
+
# EXPR_CMDARG: Integer
|
|
18
|
+
# EXPR_ENDARG: Integer
|
|
19
|
+
# EXPR_ENDFN: Integer
|
|
20
|
+
#
|
|
21
|
+
# class Lexer < Ripper
|
|
22
|
+
# class State
|
|
23
|
+
# def self.[]: (Integer value) -> State
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# class LineAndColumnCache
|
|
28
|
+
# def initialize: (Source source) -> void
|
|
29
|
+
#
|
|
30
|
+
# def line_and_column: (Integer byte_offset) -> [Integer, Integer]
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
|
|
5
35
|
# This class is responsible for lexing the source using prism and then
|
|
6
36
|
# converting those tokens to be compatible with Ripper. In the vast majority
|
|
7
37
|
# of cases, this is a one-to-one mapping of the token type. Everything else
|
|
8
38
|
# generally lines up. However, there are a few cases that require special
|
|
9
39
|
# handling.
|
|
10
40
|
class LexCompat # :nodoc:
|
|
41
|
+
# @rbs!
|
|
42
|
+
# # A token produced by the Ripper lexer that Prism is replicating.
|
|
43
|
+
# type lex_compat_token = [[Integer, Integer], Symbol, String, untyped]
|
|
44
|
+
|
|
11
45
|
# A result class specialized for holding tokens produced by the lexer.
|
|
12
46
|
class Result < Prism::Result
|
|
13
47
|
# The list of tokens that were produced by the lexer.
|
|
14
|
-
attr_reader :value
|
|
48
|
+
attr_reader :value #: Array[lex_compat_token]
|
|
15
49
|
|
|
16
50
|
# Create a new lex compat result object with the given values.
|
|
17
|
-
|
|
51
|
+
#
|
|
52
|
+
#: (Array[lex_compat_token] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
|
|
53
|
+
def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source)
|
|
18
54
|
@value = value
|
|
19
|
-
super(
|
|
55
|
+
super(magic_comments, data_loc, errors, warnings, continuable, source)
|
|
20
56
|
end
|
|
21
57
|
|
|
22
58
|
# Implement the hash pattern matching interface for Result.
|
|
23
|
-
|
|
59
|
+
#
|
|
60
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
61
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
24
62
|
super.merge!(value: value)
|
|
25
63
|
end
|
|
26
64
|
end
|
|
@@ -40,6 +78,8 @@ module Prism
|
|
|
40
78
|
BANG_EQUAL: :on_op,
|
|
41
79
|
BANG_TILDE: :on_op,
|
|
42
80
|
BRACE_LEFT: :on_lbrace,
|
|
81
|
+
BRACE_LEFT_ARGUMENT: :on_lbrace,
|
|
82
|
+
BRACE_LEFT_HASH: :on_lbrace,
|
|
43
83
|
BRACE_RIGHT: :on_rbrace,
|
|
44
84
|
BRACKET_LEFT: :on_lbracket,
|
|
45
85
|
BRACKET_LEFT_ARRAY: :on_lbracket,
|
|
@@ -102,6 +142,8 @@ module Prism
|
|
|
102
142
|
KEYWORD_DEF: :on_kw,
|
|
103
143
|
KEYWORD_DEFINED: :on_kw,
|
|
104
144
|
KEYWORD_DO: :on_kw,
|
|
145
|
+
KEYWORD_DO_BLOCK: :on_kw,
|
|
146
|
+
KEYWORD_DO_LAMBDA: :on_kw,
|
|
105
147
|
KEYWORD_DO_LOOP: :on_kw,
|
|
106
148
|
KEYWORD_ELSE: :on_kw,
|
|
107
149
|
KEYWORD_ELSIF: :on_kw,
|
|
@@ -149,8 +191,10 @@ module Prism
|
|
|
149
191
|
MINUS_EQUAL: :on_op,
|
|
150
192
|
MINUS_GREATER: :on_tlambda,
|
|
151
193
|
NEWLINE: :on_nl,
|
|
194
|
+
NEWLINE_TERMINATOR: :on_ignored_nl,
|
|
152
195
|
NUMBERED_REFERENCE: :on_backref,
|
|
153
196
|
PARENTHESIS_LEFT: :on_lparen,
|
|
197
|
+
PARENTHESIS_LEFT_GROUPING: :on_lparen,
|
|
154
198
|
PARENTHESIS_LEFT_PARENTHESES: :on_lparen,
|
|
155
199
|
PARENTHESIS_RIGHT: :on_rparen,
|
|
156
200
|
PERCENT: :on_op,
|
|
@@ -193,60 +237,10 @@ module Prism
|
|
|
193
237
|
USTAR: :on_op,
|
|
194
238
|
USTAR_STAR: :on_op,
|
|
195
239
|
WORDS_SEP: :on_words_sep,
|
|
240
|
+
XSTRING_BEGIN: :on_backtick,
|
|
196
241
|
"__END__": :on___end__
|
|
197
242
|
}.freeze
|
|
198
243
|
|
|
199
|
-
# When we produce tokens, we produce the same arrays that Ripper does.
|
|
200
|
-
# However, we add a couple of convenience methods onto them to make them a
|
|
201
|
-
# little easier to work with. We delegate all other methods to the array.
|
|
202
|
-
class Token < BasicObject
|
|
203
|
-
# Create a new token object with the given ripper-compatible array.
|
|
204
|
-
def initialize(array)
|
|
205
|
-
@array = array
|
|
206
|
-
end
|
|
207
|
-
|
|
208
|
-
# The location of the token in the source.
|
|
209
|
-
def location
|
|
210
|
-
@array[0]
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
# The type of the token.
|
|
214
|
-
def event
|
|
215
|
-
@array[1]
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
# The slice of the source that this token represents.
|
|
219
|
-
def value
|
|
220
|
-
@array[2]
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
# The state of the lexer when this token was produced.
|
|
224
|
-
def state
|
|
225
|
-
@array[3]
|
|
226
|
-
end
|
|
227
|
-
|
|
228
|
-
# We want to pretend that this is just an Array.
|
|
229
|
-
def ==(other) # :nodoc:
|
|
230
|
-
@array == other
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
def respond_to_missing?(name, include_private = false) # :nodoc:
|
|
234
|
-
@array.respond_to?(name, include_private)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def method_missing(name, ...) # :nodoc:
|
|
238
|
-
@array.send(name, ...)
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
# Tokens where state should be ignored
|
|
243
|
-
# used for :on_sp, :on_comment, :on_heredoc_end, :on_embexpr_end
|
|
244
|
-
class IgnoreStateToken < Token
|
|
245
|
-
def ==(other) # :nodoc:
|
|
246
|
-
self[0...-1] == other[0...-1]
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
244
|
# A heredoc in this case is a list of tokens that belong to the body of the
|
|
251
245
|
# heredoc that should be appended onto the list of tokens when the heredoc
|
|
252
246
|
# closes.
|
|
@@ -256,16 +250,19 @@ module Prism
|
|
|
256
250
|
# order back into the token stream and set the state of the last token to
|
|
257
251
|
# the state that the heredoc was opened in.
|
|
258
252
|
class PlainHeredoc # :nodoc:
|
|
259
|
-
attr_reader :tokens
|
|
253
|
+
attr_reader :tokens #: Array[lex_compat_token]
|
|
260
254
|
|
|
255
|
+
#: () -> void
|
|
261
256
|
def initialize
|
|
262
257
|
@tokens = []
|
|
263
258
|
end
|
|
264
259
|
|
|
260
|
+
#: (lex_compat_token token) -> void
|
|
265
261
|
def <<(token)
|
|
266
262
|
tokens << token
|
|
267
263
|
end
|
|
268
264
|
|
|
265
|
+
#: () -> Array[lex_compat_token]
|
|
269
266
|
def to_a
|
|
270
267
|
tokens
|
|
271
268
|
end
|
|
@@ -275,22 +272,26 @@ module Prism
|
|
|
275
272
|
# that need to be split on "\\\n" to mimic Ripper's behavior. We also need
|
|
276
273
|
# to keep track of the state that the heredoc was opened in.
|
|
277
274
|
class DashHeredoc # :nodoc:
|
|
278
|
-
attr_reader :split
|
|
275
|
+
attr_reader :split #: bool
|
|
276
|
+
attr_reader :tokens #: Array[lex_compat_token]
|
|
279
277
|
|
|
278
|
+
#: (bool split) -> void
|
|
280
279
|
def initialize(split)
|
|
281
280
|
@split = split
|
|
282
281
|
@tokens = []
|
|
283
282
|
end
|
|
284
283
|
|
|
284
|
+
#: (lex_compat_token token) -> void
|
|
285
285
|
def <<(token)
|
|
286
286
|
tokens << token
|
|
287
287
|
end
|
|
288
288
|
|
|
289
|
+
#: () -> Array[lex_compat_token]
|
|
289
290
|
def to_a
|
|
290
291
|
embexpr_balance = 0
|
|
291
292
|
|
|
292
|
-
tokens.each_with_object([]) do |token, results| #$ Array[
|
|
293
|
-
case token
|
|
293
|
+
tokens.each_with_object([]) do |token, results| #$ Array[lex_compat_token]
|
|
294
|
+
case token[1]
|
|
294
295
|
when :on_embexpr_beg
|
|
295
296
|
embexpr_balance += 1
|
|
296
297
|
results << token
|
|
@@ -305,9 +306,9 @@ module Prism
|
|
|
305
306
|
if split
|
|
306
307
|
# Split on "\\\n" to mimic Ripper's behavior. Use a lookbehind
|
|
307
308
|
# to keep the delimiter in the result.
|
|
308
|
-
token.
|
|
309
|
+
token[2].split(/(?<=[^\\]\\\n)|(?<=[^\\]\\\r\n)/).each_with_index do |value, index|
|
|
309
310
|
column = 0 if index > 0
|
|
310
|
-
results <<
|
|
311
|
+
results << [[lineno, column], :on_tstring_content, value, token[3]]
|
|
311
312
|
lineno += value.count("\n")
|
|
312
313
|
end
|
|
313
314
|
else
|
|
@@ -336,8 +337,13 @@ module Prism
|
|
|
336
337
|
class DedentingHeredoc # :nodoc:
|
|
337
338
|
TAB_WIDTH = 8
|
|
338
339
|
|
|
339
|
-
attr_reader :tokens
|
|
340
|
+
attr_reader :tokens #: Array[lex_compat_token]
|
|
341
|
+
attr_reader :dedent_next #: bool
|
|
342
|
+
attr_reader :dedent #: Integer?
|
|
343
|
+
attr_reader :embexpr_balance #: Integer
|
|
344
|
+
# @rbs @ended_on_newline: bool
|
|
340
345
|
|
|
346
|
+
#: () -> void
|
|
341
347
|
def initialize
|
|
342
348
|
@tokens = []
|
|
343
349
|
@dedent_next = true
|
|
@@ -349,8 +355,10 @@ module Prism
|
|
|
349
355
|
# As tokens are coming in, we track the minimum amount of common leading
|
|
350
356
|
# whitespace on plain string content tokens. This allows us to later
|
|
351
357
|
# remove that amount of whitespace from the beginning of each line.
|
|
358
|
+
#
|
|
359
|
+
#: (lex_compat_token token) -> void
|
|
352
360
|
def <<(token)
|
|
353
|
-
case token
|
|
361
|
+
case token[1]
|
|
354
362
|
when :on_embexpr_beg, :on_heredoc_beg
|
|
355
363
|
@embexpr_balance += 1
|
|
356
364
|
@dedent = 0 if @dedent_next && @ended_on_newline
|
|
@@ -358,10 +366,10 @@ module Prism
|
|
|
358
366
|
@embexpr_balance -= 1
|
|
359
367
|
when :on_tstring_content
|
|
360
368
|
if embexpr_balance == 0
|
|
361
|
-
line = token
|
|
369
|
+
line = token[2]
|
|
362
370
|
|
|
363
371
|
if dedent_next && !(line.strip.empty? && line.end_with?("\n"))
|
|
364
|
-
leading = line[/\A(\s*)\n?/, 1]
|
|
372
|
+
leading = line[/\A(\s*)\n?/, 1] #: String
|
|
365
373
|
next_dedent = 0
|
|
366
374
|
|
|
367
375
|
leading.each_char do |char|
|
|
@@ -381,20 +389,21 @@ module Prism
|
|
|
381
389
|
end
|
|
382
390
|
end
|
|
383
391
|
|
|
384
|
-
@dedent_next = token
|
|
392
|
+
@dedent_next = token[1] == :on_tstring_content && embexpr_balance == 0
|
|
385
393
|
@ended_on_newline = false
|
|
386
394
|
tokens << token
|
|
387
395
|
end
|
|
388
396
|
|
|
397
|
+
#: () -> Array[lex_compat_token]
|
|
389
398
|
def to_a
|
|
390
399
|
# If every line in the heredoc is blank, we still need to split up the
|
|
391
400
|
# string content token into multiple tokens.
|
|
392
401
|
if dedent.nil?
|
|
393
|
-
results = [] #: Array[
|
|
402
|
+
results = [] #: Array[lex_compat_token]
|
|
394
403
|
embexpr_balance = 0
|
|
395
404
|
|
|
396
405
|
tokens.each do |token|
|
|
397
|
-
case token
|
|
406
|
+
case token[1]
|
|
398
407
|
when :on_embexpr_beg, :on_heredoc_beg
|
|
399
408
|
embexpr_balance += 1
|
|
400
409
|
results << token
|
|
@@ -406,9 +415,9 @@ module Prism
|
|
|
406
415
|
lineno = token[0][0]
|
|
407
416
|
column = token[0][1]
|
|
408
417
|
|
|
409
|
-
token.
|
|
418
|
+
token[2].split(/(?<=\n)/).each_with_index do |value, index|
|
|
410
419
|
column = 0 if index > 0
|
|
411
|
-
results <<
|
|
420
|
+
results << [[lineno, column], :on_tstring_content, value, token[3]]
|
|
412
421
|
lineno += 1
|
|
413
422
|
end
|
|
414
423
|
else
|
|
@@ -425,7 +434,7 @@ module Prism
|
|
|
425
434
|
# If the minimum common whitespace is 0, then we need to concatenate
|
|
426
435
|
# string nodes together that are immediately adjacent.
|
|
427
436
|
if dedent == 0
|
|
428
|
-
results = [] #: Array[
|
|
437
|
+
results = [] #: Array[lex_compat_token]
|
|
429
438
|
embexpr_balance = 0
|
|
430
439
|
|
|
431
440
|
index = 0
|
|
@@ -436,15 +445,15 @@ module Prism
|
|
|
436
445
|
results << token
|
|
437
446
|
index += 1
|
|
438
447
|
|
|
439
|
-
case token
|
|
448
|
+
case token[1]
|
|
440
449
|
when :on_embexpr_beg, :on_heredoc_beg
|
|
441
450
|
embexpr_balance += 1
|
|
442
451
|
when :on_embexpr_end, :on_heredoc_end
|
|
443
452
|
embexpr_balance -= 1
|
|
444
453
|
when :on_tstring_content
|
|
445
454
|
if embexpr_balance == 0
|
|
446
|
-
while index < max_index && tokens[index]
|
|
447
|
-
token
|
|
455
|
+
while index < max_index && tokens[index][1] == :on_tstring_content && !token[2].match?(/\\\r?\n\z/)
|
|
456
|
+
token[2] << tokens[index][2]
|
|
448
457
|
index += 1
|
|
449
458
|
end
|
|
450
459
|
end
|
|
@@ -458,7 +467,7 @@ module Prism
|
|
|
458
467
|
# insert on_ignored_sp tokens for the amount of dedent that we need to
|
|
459
468
|
# perform. We also need to remove the dedent from the beginning of
|
|
460
469
|
# each line of plain string content tokens.
|
|
461
|
-
results = [] #: Array[
|
|
470
|
+
results = [] #: Array[lex_compat_token]
|
|
462
471
|
dedent_next = true
|
|
463
472
|
embexpr_balance = 0
|
|
464
473
|
|
|
@@ -467,7 +476,7 @@ module Prism
|
|
|
467
476
|
# whitespace calculation we performed above. This is because
|
|
468
477
|
# checking if the subsequent token needs to be dedented is common to
|
|
469
478
|
# both the dedent calculation and the ignored_sp insertion.
|
|
470
|
-
case token
|
|
479
|
+
case token[1]
|
|
471
480
|
when :on_embexpr_beg
|
|
472
481
|
embexpr_balance += 1
|
|
473
482
|
results << token
|
|
@@ -479,7 +488,7 @@ module Prism
|
|
|
479
488
|
# Here we're going to split the string on newlines, but maintain
|
|
480
489
|
# the newlines in the resulting array. We'll do that with a look
|
|
481
490
|
# behind assertion.
|
|
482
|
-
splits = token.
|
|
491
|
+
splits = token[2].split(/(?<=\n)/)
|
|
483
492
|
index = 0
|
|
484
493
|
|
|
485
494
|
while index < splits.length
|
|
@@ -497,7 +506,8 @@ module Prism
|
|
|
497
506
|
# line or this line doesn't start with whitespace, then we
|
|
498
507
|
# should concatenate the rest of the string to match ripper.
|
|
499
508
|
if dedent == 0 && (!dedent_next || !line.start_with?(/\s/))
|
|
500
|
-
|
|
509
|
+
unjoined = splits[index..] #: Array[String]
|
|
510
|
+
line = unjoined.join
|
|
501
511
|
index = splits.length
|
|
502
512
|
end
|
|
503
513
|
|
|
@@ -536,12 +546,12 @@ module Prism
|
|
|
536
546
|
ignored = deleted_chars.join
|
|
537
547
|
line.delete_prefix!(ignored)
|
|
538
548
|
|
|
539
|
-
results <<
|
|
549
|
+
results << [[lineno, 0], :on_ignored_sp, ignored, token[3]]
|
|
540
550
|
column = ignored.length
|
|
541
551
|
end
|
|
542
552
|
end
|
|
543
553
|
|
|
544
|
-
results <<
|
|
554
|
+
results << [[lineno, column], token[1], line, token[3]] unless line.empty?
|
|
545
555
|
index += 1
|
|
546
556
|
end
|
|
547
557
|
else
|
|
@@ -552,7 +562,7 @@ module Prism
|
|
|
552
562
|
end
|
|
553
563
|
|
|
554
564
|
dedent_next =
|
|
555
|
-
((token
|
|
565
|
+
((token[1] == :on_tstring_content) || (token[1] == :on_heredoc_end)) &&
|
|
556
566
|
embexpr_balance == 0
|
|
557
567
|
end
|
|
558
568
|
|
|
@@ -562,12 +572,14 @@ module Prism
|
|
|
562
572
|
|
|
563
573
|
# Here we will split between the two types of heredocs and return the
|
|
564
574
|
# object that will store their tokens.
|
|
575
|
+
#
|
|
576
|
+
#: (lex_compat_token opening) -> (PlainHeredoc | DashHeredoc | DedentingHeredoc)
|
|
565
577
|
def self.build(opening)
|
|
566
|
-
case opening
|
|
578
|
+
case opening[2][2]
|
|
567
579
|
when "~"
|
|
568
580
|
DedentingHeredoc.new
|
|
569
581
|
when "-"
|
|
570
|
-
DashHeredoc.new(opening
|
|
582
|
+
DashHeredoc.new(opening[2][3] != "'")
|
|
571
583
|
else
|
|
572
584
|
PlainHeredoc.new
|
|
573
585
|
end
|
|
@@ -581,31 +593,74 @@ module Prism
|
|
|
581
593
|
BOM_FLUSHED = RUBY_VERSION >= "3.3.0"
|
|
582
594
|
private_constant :BOM_FLUSHED
|
|
583
595
|
|
|
584
|
-
attr_reader :options
|
|
596
|
+
attr_reader :options #: Hash[Symbol, untyped]
|
|
597
|
+
# @rbs @source: String
|
|
585
598
|
|
|
586
|
-
|
|
587
|
-
|
|
599
|
+
#: (String source, **untyped options) -> void
|
|
600
|
+
def initialize(source, **options)
|
|
601
|
+
@source = source
|
|
588
602
|
@options = options
|
|
589
603
|
end
|
|
590
604
|
|
|
605
|
+
#: () -> Result
|
|
591
606
|
def result
|
|
592
|
-
tokens = [] #: Array[
|
|
607
|
+
tokens = [] #: Array[lex_compat_token]
|
|
593
608
|
|
|
594
609
|
state = :default
|
|
595
610
|
heredoc_stack = [[]] #: Array[Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]]
|
|
596
611
|
|
|
597
|
-
result = Prism.lex(@
|
|
612
|
+
result = Prism.lex(@source, **options)
|
|
598
613
|
source = result.source
|
|
599
614
|
result_value = result.value
|
|
600
|
-
previous_state = nil #: State?
|
|
615
|
+
previous_state = nil #: Translation::Ripper::Lexer::State?
|
|
601
616
|
last_heredoc_end = nil #: Integer?
|
|
602
|
-
eof_token = nil
|
|
617
|
+
eof_token = nil #: Token?
|
|
618
|
+
|
|
619
|
+
# The two tokens Ripper scanned most recently, oldest last. Tokens that
|
|
620
|
+
# this loop does not emit are not part of Ripper's view, so they never
|
|
621
|
+
# become either one.
|
|
622
|
+
previous_token = nil #: Token?
|
|
623
|
+
previous_previous_token = nil #: Token?
|
|
624
|
+
|
|
625
|
+
# The lex state in effect at each embedded expression that is still open,
|
|
626
|
+
# innermost last, and the state at the opener of the one that closed most
|
|
627
|
+
# recently. Ending an embedded expression restores the state its opener
|
|
628
|
+
# had, which on_regexp_end below has to reproduce.
|
|
629
|
+
embexpr_states = [] #: Array[Integer]
|
|
630
|
+
last_embexpr_state = nil #: Integer?
|
|
603
631
|
|
|
604
632
|
bom = source.slice(0, 3) == "\xEF\xBB\xBF"
|
|
605
633
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
634
|
+
last_comment_token = nil #: lex_compat_token?
|
|
635
|
+
last_comment_end = nil #: Integer?
|
|
636
|
+
|
|
637
|
+
result_value.each_with_index do |prism_token, index|
|
|
638
|
+
lineno = prism_token.location.start_line
|
|
639
|
+
column = prism_token.location.start_column
|
|
640
|
+
|
|
641
|
+
# Ripper is a scanner, so every event it emits corresponds to source
|
|
642
|
+
# characters. Implicit word separators have none.
|
|
643
|
+
next if prism_token.type == :WORDS_SEP_IMPLICIT
|
|
644
|
+
|
|
645
|
+
event = RIPPER.fetch(prism_token.type)
|
|
646
|
+
value = prism_token.value
|
|
647
|
+
lex_state = Translation::Ripper::Lexer::State[prism_token._ripper_state]
|
|
648
|
+
|
|
649
|
+
# A comment token does not include its terminating newline, but
|
|
650
|
+
# ripper's comment value does, so the newline token that directly
|
|
651
|
+
# follows a comment is folded back into it.
|
|
652
|
+
if last_comment_token && last_comment_end == prism_token.location.start_offset && (event == :on_nl || event == :on_ignored_nl)
|
|
653
|
+
last_comment_token[2] += value
|
|
654
|
+
last_comment_token = nil
|
|
655
|
+
last_comment_end = nil
|
|
656
|
+
|
|
657
|
+
# The newline's characters are part of the comment Ripper emits, so
|
|
658
|
+
# it is still the token Ripper scanned most recently, and the trailing
|
|
659
|
+
# whitespace check at on_eof measures from its end.
|
|
660
|
+
previous_previous_token = previous_token
|
|
661
|
+
previous_token = prism_token
|
|
662
|
+
next
|
|
663
|
+
end
|
|
609
664
|
|
|
610
665
|
# If there's a UTF-8 byte-order mark as the start of the file, then for
|
|
611
666
|
# certain tokens ripper sets the first token back by 3 bytes. It also
|
|
@@ -617,46 +672,45 @@ module Prism
|
|
|
617
672
|
|
|
618
673
|
if index == 0 && column == 0 && !BOM_FLUSHED
|
|
619
674
|
flushed =
|
|
620
|
-
case
|
|
675
|
+
case prism_token.type
|
|
621
676
|
when :BACK_REFERENCE, :INSTANCE_VARIABLE, :CLASS_VARIABLE,
|
|
622
677
|
:GLOBAL_VARIABLE, :NUMBERED_REFERENCE, :PERCENT_LOWER_I,
|
|
623
678
|
:PERCENT_LOWER_X, :PERCENT_LOWER_W, :PERCENT_UPPER_I,
|
|
624
679
|
:PERCENT_UPPER_W, :STRING_BEGIN
|
|
625
680
|
true
|
|
626
681
|
when :REGEXP_BEGIN, :SYMBOL_BEGIN
|
|
627
|
-
|
|
682
|
+
value.start_with?("%")
|
|
628
683
|
else
|
|
629
684
|
false
|
|
630
685
|
end
|
|
631
686
|
|
|
632
687
|
unless flushed
|
|
633
688
|
column -= 3
|
|
634
|
-
value = token.value
|
|
635
689
|
value.prepend(String.new("\xEF\xBB\xBF", encoding: value.encoding))
|
|
636
690
|
end
|
|
637
691
|
end
|
|
638
692
|
end
|
|
639
693
|
|
|
640
|
-
|
|
641
|
-
value = token.value
|
|
642
|
-
lex_state = Translation::Ripper::Lexer::State.cached(lex_state)
|
|
643
|
-
|
|
644
|
-
token =
|
|
694
|
+
lex_compat_token =
|
|
645
695
|
case event
|
|
646
696
|
when :on___end__
|
|
647
697
|
# Ripper doesn't include the rest of the token in the event, so we need to
|
|
648
698
|
# trim it down to just the content on the first line.
|
|
649
|
-
value = value[0..value.index("\n")]
|
|
650
|
-
|
|
699
|
+
value = value[0..value.index("\n")] #: String
|
|
700
|
+
[[lineno, column], event, value, lex_state]
|
|
651
701
|
when :on_comment
|
|
652
|
-
|
|
702
|
+
[[lineno, column], event, value, lex_state]
|
|
653
703
|
when :on_heredoc_end
|
|
654
704
|
# Heredoc end tokens can be emitted in an odd order, so we don't
|
|
655
705
|
# want to bother comparing the state on them.
|
|
656
|
-
last_heredoc_end =
|
|
657
|
-
|
|
706
|
+
last_heredoc_end = prism_token.location.end_offset
|
|
707
|
+
[[lineno, column], event, value, lex_state]
|
|
708
|
+
when :on_embexpr_beg
|
|
709
|
+
embexpr_states.push(prism_token._ripper_state)
|
|
710
|
+
[[lineno, column], event, value, lex_state]
|
|
658
711
|
when :on_embexpr_end
|
|
659
|
-
|
|
712
|
+
last_embexpr_state = embexpr_states.pop
|
|
713
|
+
[[lineno, column], event, value, lex_state]
|
|
660
714
|
when :on_words_sep
|
|
661
715
|
# Ripper emits one token each per line.
|
|
662
716
|
value.each_line.with_index do |line, index|
|
|
@@ -664,9 +718,9 @@ module Prism
|
|
|
664
718
|
lineno += 1
|
|
665
719
|
column = 0
|
|
666
720
|
end
|
|
667
|
-
tokens <<
|
|
721
|
+
tokens << [[lineno, column], event, line, lex_state]
|
|
668
722
|
end
|
|
669
|
-
tokens.pop
|
|
723
|
+
tokens.pop #: lex_compat_token
|
|
670
724
|
when :on_regexp_end
|
|
671
725
|
# On regex end, Ripper scans and then sets end state, so the ripper
|
|
672
726
|
# lexed output is begin, when it should be end. prism sets lex state
|
|
@@ -674,63 +728,64 @@ module Prism
|
|
|
674
728
|
# Ripper's lexed state. So here, if it's a regexp end token, we
|
|
675
729
|
# output the state as the previous state, solely for the sake of
|
|
676
730
|
# comparison.
|
|
677
|
-
previous_token = result_value[index - 1][0]
|
|
678
731
|
lex_state =
|
|
679
|
-
if
|
|
680
|
-
#
|
|
681
|
-
#
|
|
682
|
-
|
|
683
|
-
# embedded expression. So we have to go and find that state and
|
|
684
|
-
# set it here.
|
|
685
|
-
counter = 1
|
|
686
|
-
current_index = index - 1
|
|
687
|
-
|
|
688
|
-
until counter == 0
|
|
689
|
-
current_index -= 1
|
|
690
|
-
current_event = RIPPER.fetch(result_value[current_index][0].type)
|
|
691
|
-
counter += { on_embexpr_beg: -1, on_embexpr_end: 1 }[current_event] || 0
|
|
692
|
-
end
|
|
693
|
-
|
|
694
|
-
Translation::Ripper::Lexer::State.cached(result_value[current_index][1])
|
|
732
|
+
if previous_token&.type == :EMBEXPR_END && last_embexpr_state
|
|
733
|
+
# An embedded expression that just closed restored the state its
|
|
734
|
+
# opener had, so that is the state Ripper reports here.
|
|
735
|
+
Translation::Ripper::Lexer::State[last_embexpr_state]
|
|
695
736
|
else
|
|
696
737
|
previous_state
|
|
697
738
|
end
|
|
698
739
|
|
|
699
|
-
|
|
740
|
+
[[lineno, column], event, value, lex_state]
|
|
700
741
|
when :on_eof
|
|
701
|
-
eof_token =
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
#
|
|
711
|
-
#
|
|
712
|
-
#
|
|
713
|
-
#
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
742
|
+
eof_token = prism_token
|
|
743
|
+
|
|
744
|
+
if (previous = previous_token)
|
|
745
|
+
# A newline that was folded back into a comment still marks the
|
|
746
|
+
# comment boundary for the check below.
|
|
747
|
+
before = previous_previous_token
|
|
748
|
+
comment_boundary = previous.type == :COMMENT ||
|
|
749
|
+
(before && %i[NEWLINE NEWLINE_TERMINATOR IGNORED_NEWLINE].include?(previous.type) && before.type == :COMMENT && before.location.end_offset == previous.location.start_offset)
|
|
750
|
+
|
|
751
|
+
# If we're at the end of the file and the previous token was a
|
|
752
|
+
# comment and there is still whitespace after the comment, then
|
|
753
|
+
# Ripper will append a on_nl token (even though there isn't
|
|
754
|
+
# necessarily a newline). We mirror that here.
|
|
755
|
+
if comment_boundary
|
|
756
|
+
# If the comment is at the start of a heredoc: <<HEREDOC # comment
|
|
757
|
+
# then the comment's end_offset is up near the heredoc_beg.
|
|
758
|
+
# This is not the correct offset to use for figuring out if
|
|
759
|
+
# there is trailing whitespace after the last token.
|
|
760
|
+
# Use the greater offset of the two to determine the start of
|
|
761
|
+
# the trailing whitespace.
|
|
762
|
+
start_offset = [previous.location.end_offset, last_heredoc_end].compact.max
|
|
763
|
+
end_offset = prism_token.location.start_offset
|
|
764
|
+
|
|
765
|
+
if start_offset < end_offset
|
|
766
|
+
if bom
|
|
767
|
+
start_offset += 3
|
|
768
|
+
end_offset += 3
|
|
769
|
+
end
|
|
723
770
|
|
|
724
|
-
|
|
771
|
+
tokens << [[lineno, 0], :on_nl, source.slice(start_offset, end_offset - start_offset), lex_state]
|
|
772
|
+
end
|
|
725
773
|
end
|
|
726
774
|
end
|
|
727
775
|
|
|
728
|
-
|
|
776
|
+
[[lineno, column], event, value, lex_state]
|
|
729
777
|
else
|
|
730
|
-
|
|
731
|
-
end
|
|
778
|
+
[[lineno, column], event, value, lex_state]
|
|
779
|
+
end #: lex_compat_token
|
|
732
780
|
|
|
733
781
|
previous_state = lex_state
|
|
782
|
+
previous_previous_token = previous_token
|
|
783
|
+
previous_token = prism_token
|
|
784
|
+
|
|
785
|
+
if event == :on_comment
|
|
786
|
+
last_comment_token = lex_compat_token
|
|
787
|
+
last_comment_end = prism_token.location.end_offset
|
|
788
|
+
end
|
|
734
789
|
|
|
735
790
|
# The order in which tokens appear in our lexer is different from the
|
|
736
791
|
# order that they appear in Ripper. When we hit the declaration of a
|
|
@@ -745,19 +800,19 @@ module Prism
|
|
|
745
800
|
when :default
|
|
746
801
|
# The default state is when there are no heredocs at all. In this
|
|
747
802
|
# state we can append the token to the list of tokens and move on.
|
|
748
|
-
tokens <<
|
|
803
|
+
tokens << lex_compat_token
|
|
749
804
|
|
|
750
805
|
# If we get the declaration of a heredoc, then we open a new heredoc
|
|
751
806
|
# and move into the heredoc_opened state.
|
|
752
807
|
if event == :on_heredoc_beg
|
|
753
808
|
state = :heredoc_opened
|
|
754
|
-
heredoc_stack.last << Heredoc.build(
|
|
809
|
+
heredoc_stack.last << Heredoc.build(lex_compat_token)
|
|
755
810
|
end
|
|
756
811
|
when :heredoc_opened
|
|
757
812
|
# The heredoc_opened state is when we've seen the declaration of a
|
|
758
813
|
# heredoc and are now lexing the body of the heredoc. In this state we
|
|
759
814
|
# push tokens onto the most recently created heredoc.
|
|
760
|
-
heredoc_stack.last.last <<
|
|
815
|
+
heredoc_stack.last.last << lex_compat_token
|
|
761
816
|
|
|
762
817
|
case event
|
|
763
818
|
when :on_heredoc_beg
|
|
@@ -765,7 +820,7 @@ module Prism
|
|
|
765
820
|
# heredoc, this means we have nested heredocs. In this case we'll
|
|
766
821
|
# push a new heredoc onto the stack and stay in the heredoc_opened
|
|
767
822
|
# state since we're now lexing the body of the new heredoc.
|
|
768
|
-
heredoc_stack << [Heredoc.build(
|
|
823
|
+
heredoc_stack << [Heredoc.build(lex_compat_token)]
|
|
769
824
|
when :on_heredoc_end
|
|
770
825
|
# If we receive the end of a heredoc, then we're done lexing the
|
|
771
826
|
# body of the heredoc. In this case we now have a completed heredoc
|
|
@@ -774,10 +829,10 @@ module Prism
|
|
|
774
829
|
state = :heredoc_closed
|
|
775
830
|
end
|
|
776
831
|
when :heredoc_closed
|
|
777
|
-
if %i[on_nl on_ignored_nl on_comment].include?(event) || (event == :on_tstring_content && value.end_with?("\n"))
|
|
832
|
+
if %i[on_nl on_ignored_nl on_comment].include?(event) || ((event == :on_tstring_content) && value.end_with?("\n"))
|
|
778
833
|
if heredoc_stack.size > 1
|
|
779
|
-
flushing = heredoc_stack.pop
|
|
780
|
-
heredoc_stack.last.last <<
|
|
834
|
+
flushing = heredoc_stack.pop #: Array[Heredoc::PlainHeredoc | Heredoc::DashHeredoc | Heredoc::DedentingHeredoc]
|
|
835
|
+
heredoc_stack.last.last << lex_compat_token
|
|
781
836
|
|
|
782
837
|
flushing.each do |heredoc|
|
|
783
838
|
heredoc.to_a.each do |flushed_token|
|
|
@@ -789,12 +844,12 @@ module Prism
|
|
|
789
844
|
next
|
|
790
845
|
end
|
|
791
846
|
elsif event == :on_heredoc_beg
|
|
792
|
-
tokens <<
|
|
847
|
+
tokens << lex_compat_token
|
|
793
848
|
state = :heredoc_opened
|
|
794
|
-
heredoc_stack.last << Heredoc.build(
|
|
849
|
+
heredoc_stack.last << Heredoc.build(lex_compat_token)
|
|
795
850
|
next
|
|
796
851
|
elsif heredoc_stack.size > 1
|
|
797
|
-
heredoc_stack[-2].last <<
|
|
852
|
+
heredoc_stack[-2].last << lex_compat_token
|
|
798
853
|
next
|
|
799
854
|
end
|
|
800
855
|
|
|
@@ -805,34 +860,44 @@ module Prism
|
|
|
805
860
|
heredoc_stack.last.clear
|
|
806
861
|
state = :default
|
|
807
862
|
|
|
808
|
-
tokens <<
|
|
863
|
+
tokens << lex_compat_token
|
|
809
864
|
end
|
|
810
865
|
end
|
|
811
866
|
|
|
812
|
-
# Drop the EOF token from the list
|
|
813
|
-
|
|
867
|
+
# Drop the EOF token from the list. The EOF token may not be
|
|
868
|
+
# present if the source was syntax invalid
|
|
869
|
+
if tokens.dig(-1, 1) == :on_eof
|
|
870
|
+
tokens = tokens[0...-1] #: Array[lex_compat_token]
|
|
871
|
+
end
|
|
814
872
|
|
|
815
873
|
# We sort by location because Ripper.lex sorts.
|
|
816
|
-
# Manually implemented instead of `sort_by!(&:location)` for performance.
|
|
817
874
|
tokens.sort_by! do |token|
|
|
818
|
-
line, column = token
|
|
875
|
+
line, column = token[0]
|
|
819
876
|
source.byte_offset(line, column)
|
|
820
877
|
end
|
|
821
878
|
|
|
822
|
-
|
|
823
|
-
tokens = add_on_sp_tokens(tokens, source, result.data_loc, bom, eof_token)
|
|
879
|
+
tokens = post_process_tokens(tokens, source, result.data_loc, bom, eof_token)
|
|
824
880
|
|
|
825
|
-
Result.new(tokens, result.
|
|
881
|
+
Result.new(tokens, result.magic_comments, result.data_loc, result.errors, result.warnings, result.continuable?, source)
|
|
826
882
|
end
|
|
827
883
|
|
|
828
|
-
|
|
829
|
-
|
|
884
|
+
private
|
|
885
|
+
|
|
886
|
+
#: (Array[lex_compat_token] tokens, Source source, Location? data_loc, bool bom, Token? eof_token) -> Array[lex_compat_token]
|
|
887
|
+
def post_process_tokens(tokens, source, data_loc, bom, eof_token)
|
|
888
|
+
new_tokens = [] #: Array[lex_compat_token]
|
|
830
889
|
|
|
831
|
-
prev_token_state = Translation::Ripper::Lexer::State
|
|
890
|
+
prev_token_state = Translation::Ripper::Lexer::State[Translation::Ripper::EXPR_BEG]
|
|
832
891
|
prev_token_end = bom ? 3 : 0
|
|
833
892
|
|
|
893
|
+
cache = Translation::Ripper::LineAndColumnCache.new(source)
|
|
894
|
+
|
|
834
895
|
tokens.each do |token|
|
|
835
|
-
|
|
896
|
+
# Skip missing heredoc ends.
|
|
897
|
+
next if token[1] == :on_heredoc_end && token[2] == ""
|
|
898
|
+
|
|
899
|
+
# Add :on_sp tokens.
|
|
900
|
+
line, column = token[0]
|
|
836
901
|
start_offset = source.byte_offset(line, column)
|
|
837
902
|
|
|
838
903
|
# Ripper reports columns on line 1 without counting the BOM, so we
|
|
@@ -841,8 +906,7 @@ module Prism
|
|
|
841
906
|
|
|
842
907
|
if start_offset > prev_token_end
|
|
843
908
|
sp_value = source.slice(prev_token_end, start_offset - prev_token_end)
|
|
844
|
-
sp_line =
|
|
845
|
-
sp_column = source.column(prev_token_end)
|
|
909
|
+
sp_line, sp_column = cache.line_and_column(prev_token_end)
|
|
846
910
|
# Ripper reports columns on line 1 without counting the BOM
|
|
847
911
|
sp_column -= 3 if sp_line == 1 && bom
|
|
848
912
|
continuation_index = sp_value.byteindex("\\")
|
|
@@ -852,54 +916,32 @@ module Prism
|
|
|
852
916
|
next_whitespace_index = continuation_index + 1
|
|
853
917
|
next_whitespace_index += 1 if sp_value.byteslice(next_whitespace_index) == "\r"
|
|
854
918
|
next_whitespace_index += 1
|
|
855
|
-
first_whitespace = sp_value[0...continuation_index]
|
|
856
|
-
continuation = sp_value[continuation_index...next_whitespace_index]
|
|
857
|
-
second_whitespace = sp_value[next_whitespace_index..]
|
|
858
|
-
|
|
859
|
-
new_tokens <<
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
first_whitespace,
|
|
863
|
-
prev_token_state
|
|
864
|
-
]) unless first_whitespace.empty?
|
|
865
|
-
|
|
866
|
-
new_tokens << IgnoreStateToken.new([
|
|
867
|
-
[sp_line, sp_column + continuation_index],
|
|
868
|
-
:on_sp,
|
|
869
|
-
continuation,
|
|
870
|
-
prev_token_state
|
|
871
|
-
])
|
|
872
|
-
|
|
873
|
-
new_tokens << IgnoreStateToken.new([
|
|
874
|
-
[sp_line + 1, 0],
|
|
875
|
-
:on_sp,
|
|
876
|
-
second_whitespace,
|
|
877
|
-
prev_token_state
|
|
878
|
-
]) unless second_whitespace.empty?
|
|
919
|
+
first_whitespace = sp_value[0...continuation_index] #: String
|
|
920
|
+
continuation = sp_value[continuation_index...next_whitespace_index] #: String
|
|
921
|
+
second_whitespace = sp_value[next_whitespace_index..] || ""
|
|
922
|
+
|
|
923
|
+
new_tokens << [[sp_line, sp_column], :on_sp, first_whitespace, prev_token_state] unless first_whitespace.empty?
|
|
924
|
+
new_tokens << [[sp_line, sp_column + continuation_index], :on_sp, continuation, prev_token_state]
|
|
925
|
+
new_tokens << [[sp_line + 1, 0], :on_sp, second_whitespace, prev_token_state] unless second_whitespace.empty?
|
|
879
926
|
else
|
|
880
|
-
new_tokens <<
|
|
881
|
-
[sp_line, sp_column],
|
|
882
|
-
:on_sp,
|
|
883
|
-
sp_value,
|
|
884
|
-
prev_token_state
|
|
885
|
-
])
|
|
927
|
+
new_tokens << [[sp_line, sp_column], :on_sp, sp_value, prev_token_state]
|
|
886
928
|
end
|
|
887
929
|
end
|
|
888
930
|
|
|
889
931
|
new_tokens << token
|
|
890
|
-
prev_token_state = token
|
|
891
|
-
prev_token_end = start_offset + token.
|
|
932
|
+
prev_token_state = token[3]
|
|
933
|
+
prev_token_end = start_offset + token[2].bytesize
|
|
892
934
|
end
|
|
893
935
|
|
|
894
|
-
|
|
936
|
+
if !data_loc && eof_token # no trailing :on_sp with __END__ as it is always preceded by :on_nl
|
|
895
937
|
end_offset = eof_token.location.end_offset
|
|
896
938
|
if prev_token_end < end_offset
|
|
897
|
-
new_tokens <<
|
|
939
|
+
new_tokens << [
|
|
898
940
|
[source.line(prev_token_end), source.column(prev_token_end)],
|
|
899
941
|
:on_sp,
|
|
900
942
|
source.slice(prev_token_end, end_offset - prev_token_end),
|
|
901
943
|
prev_token_state
|
|
902
|
-
]
|
|
944
|
+
]
|
|
903
945
|
end
|
|
904
946
|
end
|
|
905
947
|
|