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/parse_result.rb
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
3
5
|
|
|
4
6
|
module Prism
|
|
7
|
+
# @rbs!
|
|
8
|
+
# # An internal interface for a cache that can be used to compute code
|
|
9
|
+
# # units from byte offsets.
|
|
10
|
+
# interface _CodeUnitsCache
|
|
11
|
+
# def []: (Integer byte_offset) -> Integer
|
|
12
|
+
# end
|
|
13
|
+
|
|
5
14
|
# This represents a source of Ruby code that has been parsed. It is used in
|
|
6
15
|
# conjunction with locations to allow them to resolve line numbers and source
|
|
7
16
|
# ranges.
|
|
@@ -10,14 +19,33 @@ module Prism
|
|
|
10
19
|
# be used instead of `new` and it will return either a `Source` or a
|
|
11
20
|
# specialized and more performant `ASCIISource` if no multibyte characters
|
|
12
21
|
# are present in the source code.
|
|
13
|
-
|
|
22
|
+
#
|
|
23
|
+
# Note that if you are calling this method manually, you will need to supply
|
|
24
|
+
# the start_line and offsets parameters. start_line is the line number that
|
|
25
|
+
# the source starts on, which is typically 1 but can be different if this
|
|
26
|
+
# source is a subset of a larger source or if this is an eval. offsets is an
|
|
27
|
+
# array of byte offsets for the start of each line in the source code, which
|
|
28
|
+
# can be calculated by iterating through the source code and recording the
|
|
29
|
+
# byte offset whenever a newline character is encountered. The first
|
|
30
|
+
# element is always 0 to mark the first line.
|
|
31
|
+
#
|
|
32
|
+
# The comments, comment_attachments, and comment_ranges parameters are the
|
|
33
|
+
# lists described by the attributes of the same names. They are passed in
|
|
34
|
+
# empty when the source is created by the parser and filled in afterward,
|
|
35
|
+
# because the comments themselves refer to the source.
|
|
36
|
+
#
|
|
37
|
+
# The checksum parameter is the value described by the attribute of the same
|
|
38
|
+
# name. It is nil when the source is not created by the parser.
|
|
39
|
+
#
|
|
40
|
+
#: (String source, Integer start_line, Array[Integer] offsets, ?Array[Comment] comments, ?Array[Comment] comment_attachments, ?Array[Integer?] comment_ranges, ?Integer? checksum) -> Source
|
|
41
|
+
def self.for(source, start_line, offsets, comments = [], comment_attachments = [], comment_ranges = [], checksum = nil)
|
|
14
42
|
if source.ascii_only?
|
|
15
|
-
ASCIISource.new(source, start_line, offsets)
|
|
43
|
+
ASCIISource.new(source, start_line, offsets, comments, comment_attachments, comment_ranges, checksum)
|
|
16
44
|
elsif source.encoding == Encoding::BINARY
|
|
17
45
|
source.force_encoding(Encoding::UTF_8)
|
|
18
46
|
|
|
19
47
|
if source.valid_encoding?
|
|
20
|
-
new(source, start_line, offsets)
|
|
48
|
+
new(source, start_line, offsets, comments, comment_attachments, comment_ranges, checksum)
|
|
21
49
|
else
|
|
22
50
|
# This is an extremely niche use case where the file is marked as
|
|
23
51
|
# binary, contains multi-byte characters, and those characters are not
|
|
@@ -26,57 +54,125 @@ module Prism
|
|
|
26
54
|
# problems when asking for code units, but it appears to be the
|
|
27
55
|
# cleanest solution at the moment.
|
|
28
56
|
source.force_encoding(Encoding::BINARY)
|
|
29
|
-
ASCIISource.new(source, start_line, offsets)
|
|
57
|
+
ASCIISource.new(source, start_line, offsets, comments, comment_attachments, comment_ranges, checksum)
|
|
30
58
|
end
|
|
31
59
|
else
|
|
32
|
-
new(source, start_line, offsets)
|
|
60
|
+
new(source, start_line, offsets, comments, comment_attachments, comment_ranges, checksum)
|
|
33
61
|
end
|
|
34
62
|
end
|
|
35
63
|
|
|
36
64
|
# The source code that this source object represents.
|
|
37
|
-
attr_reader :source
|
|
65
|
+
attr_reader :source #: String
|
|
38
66
|
|
|
39
67
|
# The line number where this source starts.
|
|
40
|
-
attr_reader :start_line
|
|
41
|
-
|
|
42
|
-
# The
|
|
43
|
-
|
|
68
|
+
attr_reader :start_line #: Integer
|
|
69
|
+
|
|
70
|
+
# The checksum of the source code which can be used to quickly determine if
|
|
71
|
+
# the source has changed.
|
|
72
|
+
attr_reader :checksum #: Integer?
|
|
73
|
+
|
|
74
|
+
# The list of comments that were encountered during parsing. When the source
|
|
75
|
+
# is parsed with the attach_comments option, these are sorted by start
|
|
76
|
+
# offset.
|
|
77
|
+
attr_reader :comments #: Array[Comment]
|
|
78
|
+
|
|
79
|
+
# The comments attached to nodes, grouped by node in order of node id. This
|
|
80
|
+
# is empty unless the source was parsed with the attach_comments option.
|
|
81
|
+
attr_reader :comment_attachments #: Array[Comment]
|
|
82
|
+
|
|
83
|
+
# Indices into comment_attachments, indexed by node id. For each node that
|
|
84
|
+
# owns comments, the index at which its comments begin is stored at its node
|
|
85
|
+
# id and the index at which they end is stored at the following node id. The
|
|
86
|
+
# other entries are nil. This is empty unless the source was parsed with the
|
|
87
|
+
# attach_comments option.
|
|
88
|
+
attr_reader :comment_ranges #: Array[Integer?]
|
|
89
|
+
|
|
90
|
+
# The list of newline byte offsets in the source code. When initialized from
|
|
91
|
+
# the C extension, this may be a packed binary string of uint32_t values
|
|
92
|
+
# that is lazily unpacked on first access.
|
|
93
|
+
#
|
|
94
|
+
#: () -> Array[Integer]
|
|
95
|
+
def offsets
|
|
96
|
+
offsets = @offsets
|
|
97
|
+
return offsets if offsets.is_a?(Array)
|
|
98
|
+
@offsets = offsets.unpack("L*")
|
|
99
|
+
end
|
|
44
100
|
|
|
45
|
-
# Create a new source object with the given source code.
|
|
46
|
-
|
|
101
|
+
# Create a new source object with the given source code. The offsets
|
|
102
|
+
# parameter can be either an Array of Integer byte offsets or a packed
|
|
103
|
+
# binary string of uint32_t values (from the C extension).
|
|
104
|
+
#
|
|
105
|
+
#: (String source, Integer start_line, Array[Integer] | String offsets, ?Array[Comment] comments, ?Array[Comment] comment_attachments, ?Array[Integer?] comment_ranges, ?Integer? checksum) -> void
|
|
106
|
+
def initialize(source, start_line, offsets, comments = [], comment_attachments = [], comment_ranges = [], checksum = nil)
|
|
47
107
|
@source = source
|
|
48
|
-
@start_line = start_line
|
|
49
|
-
@
|
|
108
|
+
@start_line = start_line
|
|
109
|
+
@checksum = checksum
|
|
110
|
+
@offsets = offsets
|
|
111
|
+
@comments = comments
|
|
112
|
+
@comment_attachments = comment_attachments
|
|
113
|
+
@comment_ranges = comment_ranges
|
|
50
114
|
end
|
|
51
115
|
|
|
52
116
|
# Replace the value of start_line with the given value.
|
|
117
|
+
#
|
|
118
|
+
#: (Integer start_line) -> void
|
|
53
119
|
def replace_start_line(start_line)
|
|
54
120
|
@start_line = start_line
|
|
55
121
|
end
|
|
56
122
|
|
|
123
|
+
# Replace the value of checksum with the given value.
|
|
124
|
+
#
|
|
125
|
+
#: (Integer checksum) -> void
|
|
126
|
+
def replace_checksum(checksum)
|
|
127
|
+
@checksum = checksum
|
|
128
|
+
end
|
|
129
|
+
|
|
57
130
|
# Replace the value of offsets with the given value.
|
|
131
|
+
#
|
|
132
|
+
#: (Array[Integer] offsets) -> void
|
|
58
133
|
def replace_offsets(offsets)
|
|
59
|
-
@offsets
|
|
134
|
+
@offsets = offsets
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The comments attached to the node with the given id, ordered by start
|
|
138
|
+
# offset. Comments are only attached when the source is parsed with the
|
|
139
|
+
# attach_comments option.
|
|
140
|
+
#
|
|
141
|
+
#: (Integer node_id) -> Array[Comment]
|
|
142
|
+
def comments_for(node_id)
|
|
143
|
+
start = comment_ranges[node_id]
|
|
144
|
+
finish = comment_ranges[node_id + 1]
|
|
145
|
+
return [] if start.nil? || finish.nil?
|
|
146
|
+
|
|
147
|
+
comment_attachments[start...finish] || []
|
|
60
148
|
end
|
|
61
149
|
|
|
62
150
|
# Returns the encoding of the source code, which is set by parameters to the
|
|
63
151
|
# parser or by the encoding magic comment.
|
|
152
|
+
#
|
|
153
|
+
#: () -> Encoding
|
|
64
154
|
def encoding
|
|
65
155
|
source.encoding
|
|
66
156
|
end
|
|
67
157
|
|
|
68
158
|
# Returns the lines of the source code as an array of strings.
|
|
159
|
+
#
|
|
160
|
+
#: () -> Array[String]
|
|
69
161
|
def lines
|
|
70
162
|
source.lines
|
|
71
163
|
end
|
|
72
164
|
|
|
73
165
|
# Perform a byteslice on the source code using the given byte offset and
|
|
74
166
|
# byte length.
|
|
167
|
+
#
|
|
168
|
+
#: (Integer byte_offset, Integer length) -> String
|
|
75
169
|
def slice(byte_offset, length)
|
|
76
170
|
source.byteslice(byte_offset, length) or raise
|
|
77
171
|
end
|
|
78
172
|
|
|
79
173
|
# Converts the line number and column in bytes to a byte offset.
|
|
174
|
+
#
|
|
175
|
+
#: (Integer line, Integer column) -> Integer
|
|
80
176
|
def byte_offset(line, column)
|
|
81
177
|
normal = line - @start_line
|
|
82
178
|
raise IndexError if normal < 0
|
|
@@ -87,33 +183,45 @@ module Prism
|
|
|
87
183
|
|
|
88
184
|
# Binary search through the offsets to find the line number for the given
|
|
89
185
|
# byte offset.
|
|
186
|
+
#
|
|
187
|
+
#: (Integer byte_offset) -> Integer
|
|
90
188
|
def line(byte_offset)
|
|
91
189
|
start_line + find_line(byte_offset)
|
|
92
190
|
end
|
|
93
191
|
|
|
94
192
|
# Return the byte offset of the start of the line corresponding to the given
|
|
95
193
|
# byte offset.
|
|
194
|
+
#
|
|
195
|
+
#: (Integer byte_offset) -> Integer
|
|
96
196
|
def line_start(byte_offset)
|
|
97
197
|
offsets[find_line(byte_offset)]
|
|
98
198
|
end
|
|
99
199
|
|
|
100
200
|
# Returns the byte offset of the end of the line corresponding to the given
|
|
101
201
|
# byte offset.
|
|
202
|
+
#
|
|
203
|
+
#: (Integer byte_offset) -> Integer
|
|
102
204
|
def line_end(byte_offset)
|
|
103
205
|
offsets[find_line(byte_offset) + 1] || source.bytesize
|
|
104
206
|
end
|
|
105
207
|
|
|
106
|
-
# Return the column
|
|
208
|
+
# Return the column in bytes for the given byte offset.
|
|
209
|
+
#
|
|
210
|
+
#: (Integer byte_offset) -> Integer
|
|
107
211
|
def column(byte_offset)
|
|
108
212
|
byte_offset - line_start(byte_offset)
|
|
109
213
|
end
|
|
110
214
|
|
|
111
215
|
# Return the character offset for the given byte offset.
|
|
216
|
+
#
|
|
217
|
+
#: (Integer byte_offset) -> Integer
|
|
112
218
|
def character_offset(byte_offset)
|
|
113
219
|
(source.byteslice(0, byte_offset) or raise).length
|
|
114
220
|
end
|
|
115
221
|
|
|
116
|
-
# Return the column
|
|
222
|
+
# Return the column in characters for the given byte offset.
|
|
223
|
+
#
|
|
224
|
+
#: (Integer byte_offset) -> Integer
|
|
117
225
|
def character_column(byte_offset)
|
|
118
226
|
character_offset(byte_offset) - character_offset(line_start(byte_offset))
|
|
119
227
|
end
|
|
@@ -130,7 +238,11 @@ module Prism
|
|
|
130
238
|
# possible that the given byte offset will not occur on a character
|
|
131
239
|
# boundary. Second, it's possible that the source code will contain a
|
|
132
240
|
# character that has no equivalent in the given encoding.
|
|
241
|
+
#
|
|
242
|
+
#: (Integer byte_offset, Encoding encoding) -> Integer
|
|
133
243
|
def code_units_offset(byte_offset, encoding)
|
|
244
|
+
return byte_offset if encoding == Encoding::UTF_8
|
|
245
|
+
|
|
134
246
|
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding, invalid: :replace, undef: :replace)
|
|
135
247
|
|
|
136
248
|
if encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE
|
|
@@ -142,28 +254,37 @@ module Prism
|
|
|
142
254
|
|
|
143
255
|
# Generate a cache that targets a specific encoding for calculating code
|
|
144
256
|
# unit offsets.
|
|
257
|
+
#
|
|
258
|
+
#: (Encoding encoding) -> CodeUnitsCache
|
|
145
259
|
def code_units_cache(encoding)
|
|
146
260
|
CodeUnitsCache.new(source, encoding)
|
|
147
261
|
end
|
|
148
262
|
|
|
149
|
-
# Returns the column
|
|
263
|
+
# Returns the column in code units for the given encoding for the
|
|
150
264
|
# given byte offset.
|
|
265
|
+
#
|
|
266
|
+
#: (Integer byte_offset, Encoding encoding) -> Integer
|
|
151
267
|
def code_units_column(byte_offset, encoding)
|
|
152
268
|
code_units_offset(byte_offset, encoding) - code_units_offset(line_start(byte_offset), encoding)
|
|
153
269
|
end
|
|
154
270
|
|
|
155
271
|
# Freeze this object and the objects it contains.
|
|
272
|
+
#
|
|
273
|
+
#: () -> void
|
|
156
274
|
def deep_freeze
|
|
157
275
|
source.freeze
|
|
158
276
|
offsets.freeze
|
|
277
|
+
comments.freeze
|
|
278
|
+
comment_attachments.freeze
|
|
279
|
+
comment_ranges.freeze
|
|
159
280
|
freeze
|
|
160
281
|
end
|
|
161
282
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
# Binary search through the offsets to find the line number for the given
|
|
283
|
+
# Binary search through the offsets to find the index for the given
|
|
165
284
|
# byte offset.
|
|
166
|
-
|
|
285
|
+
#
|
|
286
|
+
#: (Integer byte_offset) -> Integer
|
|
287
|
+
def find_line(byte_offset) # :nodoc:
|
|
167
288
|
index = offsets.bsearch_index { |offset| offset > byte_offset } || offsets.length
|
|
168
289
|
index - 1
|
|
169
290
|
end
|
|
@@ -184,38 +305,69 @@ module Prism
|
|
|
184
305
|
# has not yet been implemented.
|
|
185
306
|
#
|
|
186
307
|
class CodeUnitsCache
|
|
308
|
+
# Counter used for UTF-8, where one code unit equals one byte.
|
|
309
|
+
class UTF8Counter # :nodoc:
|
|
310
|
+
#: (Integer byte_offset, Integer byte_length) -> Integer
|
|
311
|
+
def count(byte_offset, byte_length)
|
|
312
|
+
byte_length
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
187
316
|
class UTF16Counter # :nodoc:
|
|
317
|
+
# @rbs @source: String
|
|
318
|
+
# @rbs @encoding: Encoding
|
|
319
|
+
|
|
320
|
+
#: (String source, Encoding encoding) -> void
|
|
188
321
|
def initialize(source, encoding)
|
|
189
322
|
@source = source
|
|
190
323
|
@encoding = encoding
|
|
191
324
|
end
|
|
192
325
|
|
|
326
|
+
#: (Integer byte_offset, Integer byte_length) -> Integer
|
|
193
327
|
def count(byte_offset, byte_length)
|
|
194
|
-
@source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
|
|
328
|
+
(@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).bytesize / 2
|
|
195
329
|
end
|
|
196
330
|
end
|
|
197
331
|
|
|
198
|
-
|
|
332
|
+
# Counter used for UTF-32, where one code unit equals one code point and
|
|
333
|
+
# matches String#length. Also used as a best-effort fallback for any other
|
|
334
|
+
# encoding that does not have a dedicated counter.
|
|
335
|
+
class UTF32Counter # :nodoc:
|
|
336
|
+
# @rbs @source: String
|
|
337
|
+
# @rbs @encoding: Encoding
|
|
338
|
+
|
|
339
|
+
#: (String source, Encoding encoding) -> void
|
|
199
340
|
def initialize(source, encoding)
|
|
200
341
|
@source = source
|
|
201
342
|
@encoding = encoding
|
|
202
343
|
end
|
|
203
344
|
|
|
345
|
+
#: (Integer byte_offset, Integer byte_length) -> Integer
|
|
204
346
|
def count(byte_offset, byte_length)
|
|
205
|
-
@source.byteslice(byte_offset, byte_length).encode(@encoding, invalid: :replace, undef: :replace).length
|
|
347
|
+
(@source.byteslice(byte_offset, byte_length) or raise).encode(@encoding, invalid: :replace, undef: :replace).length
|
|
206
348
|
end
|
|
207
349
|
end
|
|
208
350
|
|
|
209
|
-
private_constant :UTF16Counter, :
|
|
351
|
+
private_constant :UTF8Counter, :UTF16Counter, :UTF32Counter
|
|
352
|
+
|
|
353
|
+
# @rbs @source: String
|
|
354
|
+
# @rbs @counter: UTF8Counter | UTF16Counter | UTF32Counter
|
|
355
|
+
# @rbs @cache: Hash[Integer, Integer]
|
|
356
|
+
# @rbs @offsets: Array[Integer]
|
|
210
357
|
|
|
211
358
|
# Initialize a new cache with the given source and encoding.
|
|
359
|
+
#
|
|
360
|
+
#: (String source, Encoding encoding) -> void
|
|
212
361
|
def initialize(source, encoding)
|
|
213
362
|
@source = source
|
|
214
363
|
@counter =
|
|
215
|
-
|
|
364
|
+
case encoding
|
|
365
|
+
when Encoding::UTF_8
|
|
366
|
+
UTF8Counter.new
|
|
367
|
+
when Encoding::UTF_16LE, Encoding::UTF_16BE
|
|
216
368
|
UTF16Counter.new(source, encoding)
|
|
217
369
|
else
|
|
218
|
-
|
|
370
|
+
UTF32Counter.new(source, encoding)
|
|
219
371
|
end
|
|
220
372
|
|
|
221
373
|
@cache = {} #: Hash[Integer, Integer]
|
|
@@ -223,6 +375,8 @@ module Prism
|
|
|
223
375
|
end
|
|
224
376
|
|
|
225
377
|
# Retrieve the code units offset from the given byte offset.
|
|
378
|
+
#
|
|
379
|
+
#: (Integer byte_offset) -> Integer
|
|
226
380
|
def [](byte_offset)
|
|
227
381
|
@cache[byte_offset] ||=
|
|
228
382
|
if (index = @offsets.bsearch_index { |offset| offset > byte_offset }).nil?
|
|
@@ -249,11 +403,15 @@ module Prism
|
|
|
249
403
|
# at that point we will treat everything as single-byte characters.
|
|
250
404
|
class ASCIISource < Source
|
|
251
405
|
# Return the character offset for the given byte offset.
|
|
406
|
+
#
|
|
407
|
+
#: (Integer byte_offset) -> Integer
|
|
252
408
|
def character_offset(byte_offset)
|
|
253
409
|
byte_offset
|
|
254
410
|
end
|
|
255
411
|
|
|
256
|
-
# Return the column
|
|
412
|
+
# Return the column in characters for the given byte offset.
|
|
413
|
+
#
|
|
414
|
+
#: (Integer byte_offset) -> Integer
|
|
257
415
|
def character_column(byte_offset)
|
|
258
416
|
byte_offset - line_start(byte_offset)
|
|
259
417
|
end
|
|
@@ -264,6 +422,8 @@ module Prism
|
|
|
264
422
|
# This method is tested with UTF-8, UTF-16, and UTF-32. If there is the
|
|
265
423
|
# concept of code units that differs from the number of characters in other
|
|
266
424
|
# encodings, it is not captured here.
|
|
425
|
+
#
|
|
426
|
+
#: (Integer byte_offset, Encoding encoding) -> Integer
|
|
267
427
|
def code_units_offset(byte_offset, encoding)
|
|
268
428
|
byte_offset
|
|
269
429
|
end
|
|
@@ -271,6 +431,8 @@ module Prism
|
|
|
271
431
|
# Returns a cache that is the identity function in order to maintain the
|
|
272
432
|
# same interface. We can do this because code units are always equivalent to
|
|
273
433
|
# byte offsets for ASCII-only sources.
|
|
434
|
+
#
|
|
435
|
+
#: (Encoding encoding) -> _CodeUnitsCache
|
|
274
436
|
def code_units_cache(encoding)
|
|
275
437
|
->(byte_offset) { byte_offset }
|
|
276
438
|
end
|
|
@@ -278,6 +440,8 @@ module Prism
|
|
|
278
440
|
# Specialized version of `code_units_column` that does not depend on
|
|
279
441
|
# `code_units_offset`, which is a more expensive operation. This is
|
|
280
442
|
# essentially the same as `Prism::Source#column`.
|
|
443
|
+
#
|
|
444
|
+
#: (Integer byte_offset, Encoding encoding) -> Integer
|
|
281
445
|
def code_units_column(byte_offset, encoding)
|
|
282
446
|
byte_offset - line_start(byte_offset)
|
|
283
447
|
end
|
|
@@ -287,79 +451,57 @@ module Prism
|
|
|
287
451
|
class Location
|
|
288
452
|
# A Source object that is used to determine more information from the given
|
|
289
453
|
# offset and length.
|
|
290
|
-
attr_reader :source
|
|
454
|
+
attr_reader :source #: Source
|
|
291
455
|
protected :source
|
|
292
456
|
|
|
293
457
|
# The byte offset from the beginning of the source where this location
|
|
294
458
|
# starts.
|
|
295
|
-
attr_reader :start_offset
|
|
459
|
+
attr_reader :start_offset #: Integer
|
|
296
460
|
|
|
297
461
|
# The length of this location in bytes.
|
|
298
|
-
attr_reader :length
|
|
462
|
+
attr_reader :length #: Integer
|
|
299
463
|
|
|
300
464
|
# Create a new location object with the given source, start byte offset, and
|
|
301
465
|
# byte length.
|
|
466
|
+
#
|
|
467
|
+
#: (Source source, Integer start_offset, Integer length) -> void
|
|
302
468
|
def initialize(source, start_offset, length)
|
|
303
469
|
@source = source
|
|
304
470
|
@start_offset = start_offset
|
|
305
471
|
@length = length
|
|
306
|
-
|
|
307
|
-
# These are used to store comments that are associated with this location.
|
|
308
|
-
# They are initialized to `nil` to save on memory when there are no
|
|
309
|
-
# comments to be attached and/or the comment-related APIs are not used.
|
|
310
|
-
@leading_comments = nil
|
|
311
|
-
@trailing_comments = nil
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
# These are the comments that are associated with this location that exist
|
|
315
|
-
# before the start of this location.
|
|
316
|
-
def leading_comments
|
|
317
|
-
@leading_comments ||= []
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
# Attach a comment to the leading comments of this location.
|
|
321
|
-
def leading_comment(comment)
|
|
322
|
-
leading_comments << comment
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
# These are the comments that are associated with this location that exist
|
|
326
|
-
# after the end of this location.
|
|
327
|
-
def trailing_comments
|
|
328
|
-
@trailing_comments ||= []
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
# Attach a comment to the trailing comments of this location.
|
|
332
|
-
def trailing_comment(comment)
|
|
333
|
-
trailing_comments << comment
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
# Returns all comments that are associated with this location (both leading
|
|
337
|
-
# and trailing comments).
|
|
338
|
-
def comments
|
|
339
|
-
[*@leading_comments, *@trailing_comments]
|
|
340
472
|
end
|
|
341
473
|
|
|
342
474
|
# Create a new location object with the given options.
|
|
475
|
+
#
|
|
476
|
+
#: (?source: Source, ?start_offset: Integer, ?length: Integer) -> Location
|
|
343
477
|
def copy(source: self.source, start_offset: self.start_offset, length: self.length)
|
|
344
478
|
Location.new(source, start_offset, length)
|
|
345
479
|
end
|
|
346
480
|
|
|
347
481
|
# Returns a new location that is the result of chopping off the last byte.
|
|
482
|
+
#
|
|
483
|
+
#: () -> Location
|
|
348
484
|
def chop
|
|
349
485
|
copy(length: length == 0 ? length : length - 1)
|
|
350
486
|
end
|
|
351
487
|
|
|
352
488
|
# Returns a string representation of this location.
|
|
353
|
-
|
|
489
|
+
#
|
|
490
|
+
#: () -> String
|
|
491
|
+
def inspect # :nodoc:
|
|
354
492
|
"#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"
|
|
355
493
|
end
|
|
356
494
|
|
|
357
495
|
# Returns all of the lines of the source code associated with this location.
|
|
496
|
+
#
|
|
497
|
+
#: () -> Array[String]
|
|
358
498
|
def source_lines
|
|
359
499
|
source.lines
|
|
360
500
|
end
|
|
361
501
|
|
|
362
502
|
# The source code that this location represents.
|
|
503
|
+
#
|
|
504
|
+
#: () -> String
|
|
363
505
|
def slice
|
|
364
506
|
source.slice(start_offset, length)
|
|
365
507
|
end
|
|
@@ -367,6 +509,8 @@ module Prism
|
|
|
367
509
|
# The source code that this location represents starting from the beginning
|
|
368
510
|
# of the line that this location starts on to the end of the line that this
|
|
369
511
|
# location ends on.
|
|
512
|
+
#
|
|
513
|
+
#: () -> String
|
|
370
514
|
def slice_lines
|
|
371
515
|
line_start = source.line_start(start_offset)
|
|
372
516
|
line_end = source.line_end(end_offset)
|
|
@@ -375,118 +519,160 @@ module Prism
|
|
|
375
519
|
|
|
376
520
|
# The character offset from the beginning of the source where this location
|
|
377
521
|
# starts.
|
|
522
|
+
#
|
|
523
|
+
#: () -> Integer
|
|
378
524
|
def start_character_offset
|
|
379
525
|
source.character_offset(start_offset)
|
|
380
526
|
end
|
|
381
527
|
|
|
382
528
|
# The offset from the start of the file in code units of the given encoding.
|
|
529
|
+
#
|
|
530
|
+
#: (Encoding encoding) -> Integer
|
|
383
531
|
def start_code_units_offset(encoding = Encoding::UTF_16LE)
|
|
384
532
|
source.code_units_offset(start_offset, encoding)
|
|
385
533
|
end
|
|
386
534
|
|
|
387
535
|
# The start offset from the start of the file in code units using the given
|
|
388
536
|
# cache to fetch or calculate the value.
|
|
537
|
+
#
|
|
538
|
+
#: (_CodeUnitsCache cache) -> Integer
|
|
389
539
|
def cached_start_code_units_offset(cache)
|
|
390
540
|
cache[start_offset]
|
|
391
541
|
end
|
|
392
542
|
|
|
393
543
|
# The byte offset from the beginning of the source where this location ends.
|
|
544
|
+
#
|
|
545
|
+
#: () -> Integer
|
|
394
546
|
def end_offset
|
|
395
547
|
start_offset + length
|
|
396
548
|
end
|
|
397
549
|
|
|
398
550
|
# The character offset from the beginning of the source where this location
|
|
399
551
|
# ends.
|
|
552
|
+
#
|
|
553
|
+
#: () -> Integer
|
|
400
554
|
def end_character_offset
|
|
401
555
|
source.character_offset(end_offset)
|
|
402
556
|
end
|
|
403
557
|
|
|
404
558
|
# The offset from the start of the file in code units of the given encoding.
|
|
559
|
+
#
|
|
560
|
+
#: (Encoding encoding) -> Integer
|
|
405
561
|
def end_code_units_offset(encoding = Encoding::UTF_16LE)
|
|
406
562
|
source.code_units_offset(end_offset, encoding)
|
|
407
563
|
end
|
|
408
564
|
|
|
409
565
|
# The end offset from the start of the file in code units using the given
|
|
410
566
|
# cache to fetch or calculate the value.
|
|
567
|
+
#
|
|
568
|
+
#: (_CodeUnitsCache cache) -> Integer
|
|
411
569
|
def cached_end_code_units_offset(cache)
|
|
412
570
|
cache[end_offset]
|
|
413
571
|
end
|
|
414
572
|
|
|
415
573
|
# The line number where this location starts.
|
|
574
|
+
#
|
|
575
|
+
#: () -> Integer
|
|
416
576
|
def start_line
|
|
417
577
|
source.line(start_offset)
|
|
418
578
|
end
|
|
419
579
|
|
|
420
580
|
# The content of the line where this location starts before this location.
|
|
581
|
+
#
|
|
582
|
+
#: () -> String
|
|
421
583
|
def start_line_slice
|
|
422
584
|
offset = source.line_start(start_offset)
|
|
423
585
|
source.slice(offset, start_offset - offset)
|
|
424
586
|
end
|
|
425
587
|
|
|
426
588
|
# The line number where this location ends.
|
|
589
|
+
#
|
|
590
|
+
#: () -> Integer
|
|
427
591
|
def end_line
|
|
428
592
|
source.line(end_offset)
|
|
429
593
|
end
|
|
430
594
|
|
|
431
|
-
# The column
|
|
595
|
+
# The column in bytes where this location starts from the start of
|
|
432
596
|
# the line.
|
|
597
|
+
#
|
|
598
|
+
#: () -> Integer
|
|
433
599
|
def start_column
|
|
434
600
|
source.column(start_offset)
|
|
435
601
|
end
|
|
436
602
|
|
|
437
|
-
# The column
|
|
603
|
+
# The column in characters where this location ends from the start of
|
|
438
604
|
# the line.
|
|
605
|
+
#
|
|
606
|
+
#: () -> Integer
|
|
439
607
|
def start_character_column
|
|
440
608
|
source.character_column(start_offset)
|
|
441
609
|
end
|
|
442
610
|
|
|
443
|
-
# The column
|
|
611
|
+
# The column in code units of the given encoding where this location
|
|
444
612
|
# starts from the start of the line.
|
|
613
|
+
#
|
|
614
|
+
#: (?Encoding encoding) -> Integer
|
|
445
615
|
def start_code_units_column(encoding = Encoding::UTF_16LE)
|
|
446
616
|
source.code_units_column(start_offset, encoding)
|
|
447
617
|
end
|
|
448
618
|
|
|
449
619
|
# The start column in code units using the given cache to fetch or calculate
|
|
450
620
|
# the value.
|
|
621
|
+
#
|
|
622
|
+
#: (_CodeUnitsCache cache) -> Integer
|
|
451
623
|
def cached_start_code_units_column(cache)
|
|
452
624
|
cache[start_offset] - cache[source.line_start(start_offset)]
|
|
453
625
|
end
|
|
454
626
|
|
|
455
|
-
# The column
|
|
627
|
+
# The column in bytes where this location ends from the start of the
|
|
456
628
|
# line.
|
|
629
|
+
#
|
|
630
|
+
#: () -> Integer
|
|
457
631
|
def end_column
|
|
458
632
|
source.column(end_offset)
|
|
459
633
|
end
|
|
460
634
|
|
|
461
|
-
# The column
|
|
635
|
+
# The column in characters where this location ends from the start of
|
|
462
636
|
# the line.
|
|
637
|
+
#
|
|
638
|
+
#: () -> Integer
|
|
463
639
|
def end_character_column
|
|
464
640
|
source.character_column(end_offset)
|
|
465
641
|
end
|
|
466
642
|
|
|
467
|
-
# The column
|
|
643
|
+
# The column in code units of the given encoding where this location
|
|
468
644
|
# ends from the start of the line.
|
|
645
|
+
#
|
|
646
|
+
#: (?Encoding encoding) -> Integer
|
|
469
647
|
def end_code_units_column(encoding = Encoding::UTF_16LE)
|
|
470
648
|
source.code_units_column(end_offset, encoding)
|
|
471
649
|
end
|
|
472
650
|
|
|
473
651
|
# The end column in code units using the given cache to fetch or calculate
|
|
474
652
|
# the value.
|
|
653
|
+
#
|
|
654
|
+
#: (_CodeUnitsCache cache) -> Integer
|
|
475
655
|
def cached_end_code_units_column(cache)
|
|
476
656
|
cache[end_offset] - cache[source.line_start(end_offset)]
|
|
477
657
|
end
|
|
478
658
|
|
|
479
659
|
# Implement the hash pattern matching interface for Location.
|
|
480
|
-
|
|
660
|
+
#
|
|
661
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
662
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
481
663
|
{ start_offset: start_offset, end_offset: end_offset }
|
|
482
664
|
end
|
|
483
665
|
|
|
484
666
|
# Implement the pretty print interface for Location.
|
|
485
|
-
|
|
667
|
+
#
|
|
668
|
+
#: (PP q) -> void
|
|
669
|
+
def pretty_print(q) # :nodoc:
|
|
486
670
|
q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column})")
|
|
487
671
|
end
|
|
488
672
|
|
|
489
673
|
# Returns true if the given other location is equal to this location.
|
|
674
|
+
#
|
|
675
|
+
#: (untyped other) -> bool
|
|
490
676
|
def ==(other)
|
|
491
677
|
Location === other &&
|
|
492
678
|
other.start_offset == start_offset &&
|
|
@@ -496,6 +682,8 @@ module Prism
|
|
|
496
682
|
# Returns a new location that stretches from this location to the given
|
|
497
683
|
# other location. Raises an error if this location is not before the other
|
|
498
684
|
# location or if they don't share the same source.
|
|
685
|
+
#
|
|
686
|
+
#: (Location other) -> Location
|
|
499
687
|
def join(other)
|
|
500
688
|
raise "Incompatible sources" if source != other.source
|
|
501
689
|
raise "Incompatible locations" if start_offset > other.start_offset
|
|
@@ -506,6 +694,8 @@ module Prism
|
|
|
506
694
|
# Join this location with the first occurrence of the string in the source
|
|
507
695
|
# that occurs after this location on the same line, and return the new
|
|
508
696
|
# location. This will raise an error if the string does not exist.
|
|
697
|
+
#
|
|
698
|
+
#: (String string) -> Location
|
|
509
699
|
def adjoin(string)
|
|
510
700
|
line_suffix = source.slice(end_offset, source.line_end(end_offset) - end_offset)
|
|
511
701
|
|
|
@@ -519,23 +709,38 @@ module Prism
|
|
|
519
709
|
# This represents a comment that was encountered during parsing. It is the
|
|
520
710
|
# base class for all comment types.
|
|
521
711
|
class Comment
|
|
522
|
-
# The
|
|
523
|
-
attr_reader :location
|
|
712
|
+
# The Location of this comment in the source.
|
|
713
|
+
attr_reader :location #: Location
|
|
524
714
|
|
|
525
715
|
# Create a new comment object with the given location.
|
|
716
|
+
#
|
|
717
|
+
#: (Location location) -> void
|
|
526
718
|
def initialize(location)
|
|
527
719
|
@location = location
|
|
528
720
|
end
|
|
529
721
|
|
|
530
722
|
# Implement the hash pattern matching interface for Comment.
|
|
531
|
-
|
|
723
|
+
#
|
|
724
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
725
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
532
726
|
{ location: location }
|
|
533
727
|
end
|
|
534
728
|
|
|
535
729
|
# Returns the content of the comment by slicing it from the source code.
|
|
730
|
+
#
|
|
731
|
+
#: () -> String
|
|
536
732
|
def slice
|
|
537
733
|
location.slice
|
|
538
734
|
end
|
|
735
|
+
|
|
736
|
+
# Returns true if this comment happens on the same line as other code and
|
|
737
|
+
# false if the comment is by itself. This can only be true for inline
|
|
738
|
+
# comments and should be false for block comments.
|
|
739
|
+
#
|
|
740
|
+
#: () -> bool
|
|
741
|
+
def trailing?
|
|
742
|
+
raise NotImplementedError, "trailing? is not implemented for #{self.class}"
|
|
743
|
+
end
|
|
539
744
|
end
|
|
540
745
|
|
|
541
746
|
# InlineComment objects are the most common. They correspond to comments in
|
|
@@ -543,12 +748,18 @@ module Prism
|
|
|
543
748
|
class InlineComment < Comment
|
|
544
749
|
# Returns true if this comment happens on the same line as other code and
|
|
545
750
|
# false if the comment is by itself.
|
|
751
|
+
#
|
|
752
|
+
#: () -> bool
|
|
546
753
|
def trailing?
|
|
547
754
|
!location.start_line_slice.strip.empty?
|
|
755
|
+
rescue ArgumentError # invalid bytes, never whitespace only
|
|
756
|
+
false
|
|
548
757
|
end
|
|
549
758
|
|
|
550
759
|
# Returns a string representation of this comment.
|
|
551
|
-
|
|
760
|
+
#
|
|
761
|
+
#: () -> String
|
|
762
|
+
def inspect # :nodoc:
|
|
552
763
|
"#<Prism::InlineComment @location=#{location.inspect}>"
|
|
553
764
|
end
|
|
554
765
|
end
|
|
@@ -556,13 +767,17 @@ module Prism
|
|
|
556
767
|
# EmbDocComment objects correspond to comments that are surrounded by =begin
|
|
557
768
|
# and =end.
|
|
558
769
|
class EmbDocComment < Comment
|
|
559
|
-
# This can only be true for inline comments.
|
|
770
|
+
# Returns false. This can only be true for inline comments.
|
|
771
|
+
#
|
|
772
|
+
#: () -> bool
|
|
560
773
|
def trailing?
|
|
561
774
|
false
|
|
562
775
|
end
|
|
563
776
|
|
|
564
777
|
# Returns a string representation of this comment.
|
|
565
|
-
|
|
778
|
+
#
|
|
779
|
+
#: () -> String
|
|
780
|
+
def inspect # :nodoc:
|
|
566
781
|
"#<Prism::EmbDocComment @location=#{location.inspect}>"
|
|
567
782
|
end
|
|
568
783
|
end
|
|
@@ -570,34 +785,44 @@ module Prism
|
|
|
570
785
|
# This represents a magic comment that was encountered during parsing.
|
|
571
786
|
class MagicComment
|
|
572
787
|
# A Location object representing the location of the key in the source.
|
|
573
|
-
attr_reader :key_loc
|
|
788
|
+
attr_reader :key_loc #: Location
|
|
574
789
|
|
|
575
790
|
# A Location object representing the location of the value in the source.
|
|
576
|
-
attr_reader :value_loc
|
|
791
|
+
attr_reader :value_loc #: Location
|
|
577
792
|
|
|
578
793
|
# Create a new magic comment object with the given key and value locations.
|
|
794
|
+
#
|
|
795
|
+
#: (Location key_loc, Location value_loc) -> void
|
|
579
796
|
def initialize(key_loc, value_loc)
|
|
580
797
|
@key_loc = key_loc
|
|
581
798
|
@value_loc = value_loc
|
|
582
799
|
end
|
|
583
800
|
|
|
584
801
|
# Returns the key of the magic comment by slicing it from the source code.
|
|
802
|
+
#
|
|
803
|
+
#: () -> String
|
|
585
804
|
def key
|
|
586
805
|
key_loc.slice
|
|
587
806
|
end
|
|
588
807
|
|
|
589
808
|
# Returns the value of the magic comment by slicing it from the source code.
|
|
809
|
+
#
|
|
810
|
+
#: () -> String
|
|
590
811
|
def value
|
|
591
812
|
value_loc.slice
|
|
592
813
|
end
|
|
593
814
|
|
|
594
815
|
# Implement the hash pattern matching interface for MagicComment.
|
|
595
|
-
|
|
816
|
+
#
|
|
817
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
818
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
596
819
|
{ key_loc: key_loc, value_loc: value_loc }
|
|
597
820
|
end
|
|
598
821
|
|
|
599
822
|
# Returns a string representation of this magic comment.
|
|
600
|
-
|
|
823
|
+
#
|
|
824
|
+
#: () -> String
|
|
825
|
+
def inspect # :nodoc:
|
|
601
826
|
"#<Prism::MagicComment @key=#{key.inspect} @value=#{value.inspect}>"
|
|
602
827
|
end
|
|
603
828
|
end
|
|
@@ -606,18 +831,20 @@ module Prism
|
|
|
606
831
|
class ParseError
|
|
607
832
|
# The type of error. This is an _internal_ symbol that is used for
|
|
608
833
|
# communicating with translation layers. It is not meant to be public API.
|
|
609
|
-
attr_reader :type
|
|
834
|
+
attr_reader :type #: Symbol
|
|
610
835
|
|
|
611
836
|
# The message associated with this error.
|
|
612
|
-
attr_reader :message
|
|
837
|
+
attr_reader :message #: String
|
|
613
838
|
|
|
614
839
|
# A Location object representing the location of this error in the source.
|
|
615
|
-
attr_reader :location
|
|
840
|
+
attr_reader :location #: Location
|
|
616
841
|
|
|
617
842
|
# The level of this error.
|
|
618
|
-
attr_reader :level
|
|
843
|
+
attr_reader :level #: Symbol
|
|
619
844
|
|
|
620
845
|
# Create a new error object with the given message and location.
|
|
846
|
+
#
|
|
847
|
+
#: (Symbol type, String message, Location location, Symbol level) -> void
|
|
621
848
|
def initialize(type, message, location, level)
|
|
622
849
|
@type = type
|
|
623
850
|
@message = message
|
|
@@ -626,12 +853,16 @@ module Prism
|
|
|
626
853
|
end
|
|
627
854
|
|
|
628
855
|
# Implement the hash pattern matching interface for ParseError.
|
|
629
|
-
|
|
856
|
+
#
|
|
857
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
858
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
630
859
|
{ type: type, message: message, location: location, level: level }
|
|
631
860
|
end
|
|
632
861
|
|
|
633
862
|
# Returns a string representation of this error.
|
|
634
|
-
|
|
863
|
+
#
|
|
864
|
+
#: () -> String
|
|
865
|
+
def inspect # :nodoc:
|
|
635
866
|
"#<Prism::ParseError @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
|
636
867
|
end
|
|
637
868
|
end
|
|
@@ -640,18 +871,20 @@ module Prism
|
|
|
640
871
|
class ParseWarning
|
|
641
872
|
# The type of warning. This is an _internal_ symbol that is used for
|
|
642
873
|
# communicating with translation layers. It is not meant to be public API.
|
|
643
|
-
attr_reader :type
|
|
874
|
+
attr_reader :type #: Symbol
|
|
644
875
|
|
|
645
876
|
# The message associated with this warning.
|
|
646
|
-
attr_reader :message
|
|
877
|
+
attr_reader :message #: String
|
|
647
878
|
|
|
648
879
|
# A Location object representing the location of this warning in the source.
|
|
649
|
-
attr_reader :location
|
|
880
|
+
attr_reader :location #: Location
|
|
650
881
|
|
|
651
882
|
# The level of this warning.
|
|
652
|
-
attr_reader :level
|
|
883
|
+
attr_reader :level #: Symbol
|
|
653
884
|
|
|
654
885
|
# Create a new warning object with the given message and location.
|
|
886
|
+
#
|
|
887
|
+
#: (Symbol type, String message, Location location, Symbol level) -> void
|
|
655
888
|
def initialize(type, message, location, level)
|
|
656
889
|
@type = type
|
|
657
890
|
@message = message
|
|
@@ -660,73 +893,118 @@ module Prism
|
|
|
660
893
|
end
|
|
661
894
|
|
|
662
895
|
# Implement the hash pattern matching interface for ParseWarning.
|
|
663
|
-
|
|
896
|
+
#
|
|
897
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
898
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
664
899
|
{ type: type, message: message, location: location, level: level }
|
|
665
900
|
end
|
|
666
901
|
|
|
667
902
|
# Returns a string representation of this warning.
|
|
668
|
-
|
|
903
|
+
#
|
|
904
|
+
#: () -> String
|
|
905
|
+
def inspect # :nodoc:
|
|
669
906
|
"#<Prism::ParseWarning @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
|
670
907
|
end
|
|
671
908
|
end
|
|
672
909
|
|
|
673
|
-
# This represents the result of a call to
|
|
674
|
-
# the requested structure, any comments that were encounters,
|
|
675
|
-
# that were encountered.
|
|
910
|
+
# This represents the result of a call to Prism.parse or Prism.parse_file.
|
|
911
|
+
# It contains the requested structure, any comments that were encounters,
|
|
912
|
+
# and any errors that were encountered.
|
|
676
913
|
class Result
|
|
677
|
-
# The list of comments that were encountered during parsing.
|
|
678
|
-
attr_reader :comments
|
|
679
|
-
|
|
680
914
|
# The list of magic comments that were encountered during parsing.
|
|
681
|
-
attr_reader :magic_comments
|
|
915
|
+
attr_reader :magic_comments #: Array[MagicComment]
|
|
682
916
|
|
|
683
917
|
# An optional location that represents the location of the __END__ marker
|
|
684
918
|
# and the rest of the content of the file. This content is loaded into the
|
|
685
919
|
# DATA constant when the file being parsed is the main file being executed.
|
|
686
|
-
attr_reader :data_loc
|
|
920
|
+
attr_reader :data_loc #: Location?
|
|
687
921
|
|
|
688
922
|
# The list of errors that were generated during parsing.
|
|
689
|
-
attr_reader :errors
|
|
923
|
+
attr_reader :errors #: Array[ParseError]
|
|
690
924
|
|
|
691
925
|
# The list of warnings that were generated during parsing.
|
|
692
|
-
attr_reader :warnings
|
|
926
|
+
attr_reader :warnings #: Array[ParseWarning]
|
|
693
927
|
|
|
694
928
|
# A Source instance that represents the source code that was parsed.
|
|
695
|
-
attr_reader :source
|
|
929
|
+
attr_reader :source #: Source
|
|
696
930
|
|
|
697
931
|
# Create a new result object with the given values.
|
|
698
|
-
|
|
699
|
-
|
|
932
|
+
#
|
|
933
|
+
#: (Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
|
|
934
|
+
def initialize(magic_comments, data_loc, errors, warnings, continuable, source)
|
|
700
935
|
@magic_comments = magic_comments
|
|
701
936
|
@data_loc = data_loc
|
|
702
937
|
@errors = errors
|
|
703
938
|
@warnings = warnings
|
|
939
|
+
@continuable = continuable
|
|
704
940
|
@source = source
|
|
705
941
|
end
|
|
706
942
|
|
|
943
|
+
# The list of comments that were encountered during parsing.
|
|
944
|
+
#
|
|
945
|
+
#: () -> Array[Comment]
|
|
946
|
+
def comments
|
|
947
|
+
source.comments
|
|
948
|
+
end
|
|
949
|
+
|
|
707
950
|
# Implement the hash pattern matching interface for Result.
|
|
708
|
-
|
|
951
|
+
#
|
|
952
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
953
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
709
954
|
{ comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
|
|
710
955
|
end
|
|
711
956
|
|
|
712
957
|
# Returns the encoding of the source code that was parsed.
|
|
958
|
+
#
|
|
959
|
+
#: () -> Encoding
|
|
713
960
|
def encoding
|
|
714
961
|
source.encoding
|
|
715
962
|
end
|
|
716
963
|
|
|
717
964
|
# Returns true if there were no errors during parsing and false if there
|
|
718
965
|
# were.
|
|
966
|
+
#
|
|
967
|
+
#: () -> bool
|
|
719
968
|
def success?
|
|
720
969
|
errors.empty?
|
|
721
970
|
end
|
|
722
971
|
|
|
723
972
|
# Returns true if there were errors during parsing and false if there were
|
|
724
973
|
# not.
|
|
974
|
+
#
|
|
975
|
+
#: () -> bool
|
|
725
976
|
def failure?
|
|
726
977
|
!success?
|
|
727
978
|
end
|
|
728
979
|
|
|
980
|
+
# Returns true if the parsed source is an incomplete expression that could
|
|
981
|
+
# become valid with additional input. This is useful for REPL contexts (such
|
|
982
|
+
# as IRB) where the user may be entering a multi-line expression one line at
|
|
983
|
+
# a time and the implementation needs to determine whether to wait for more
|
|
984
|
+
# input or to evaluate what has been entered so far.
|
|
985
|
+
#
|
|
986
|
+
# Concretely, this returns true when every error present is caused by the
|
|
987
|
+
# parser reaching the end of the input before a construct was closed (e.g.
|
|
988
|
+
# an unclosed string, array, block, or keyword), and returns false when any
|
|
989
|
+
# error is caused by a token that makes the input structurally invalid
|
|
990
|
+
# regardless of what might follow (e.g. a stray `end`, `]`, or `)` with no
|
|
991
|
+
# matching opener).
|
|
992
|
+
#
|
|
993
|
+
# Examples:
|
|
994
|
+
#
|
|
995
|
+
# Prism.parse("1 + [").continuable? #=> true (unclosed array)
|
|
996
|
+
# Prism.parse("1 + ]").continuable? #=> false (stray ])
|
|
997
|
+
# Prism.parse("tap do").continuable? #=> true (unclosed block)
|
|
998
|
+
# Prism.parse("end.tap do").continuable? #=> false (stray end)
|
|
999
|
+
#
|
|
1000
|
+
#: () -> bool
|
|
1001
|
+
def continuable?
|
|
1002
|
+
@continuable
|
|
1003
|
+
end
|
|
1004
|
+
|
|
729
1005
|
# Create a code units cache for the given encoding.
|
|
1006
|
+
#
|
|
1007
|
+
#: (Encoding encoding) -> _CodeUnitsCache
|
|
730
1008
|
def code_units_cache(encoding)
|
|
731
1009
|
source.code_units_cache(encoding)
|
|
732
1010
|
end
|
|
@@ -734,41 +1012,42 @@ module Prism
|
|
|
734
1012
|
|
|
735
1013
|
# This is a result specific to the `parse` and `parse_file` methods.
|
|
736
1014
|
class ParseResult < Result
|
|
737
|
-
autoload :Comments, "prism/parse_result/comments"
|
|
738
1015
|
autoload :Errors, "prism/parse_result/errors"
|
|
739
1016
|
autoload :Newlines, "prism/parse_result/newlines"
|
|
740
1017
|
|
|
741
|
-
private_constant :Comments
|
|
742
1018
|
private_constant :Errors
|
|
743
1019
|
private_constant :Newlines
|
|
744
1020
|
|
|
745
1021
|
# The syntax tree that was parsed from the source code.
|
|
746
|
-
attr_reader :value
|
|
1022
|
+
attr_reader :value #: ProgramNode
|
|
747
1023
|
|
|
748
1024
|
# Create a new parse result object with the given values.
|
|
749
|
-
|
|
1025
|
+
#
|
|
1026
|
+
#: (ProgramNode value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
|
|
1027
|
+
def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source)
|
|
750
1028
|
@value = value
|
|
751
|
-
super(
|
|
1029
|
+
super(magic_comments, data_loc, errors, warnings, continuable, source)
|
|
752
1030
|
end
|
|
753
1031
|
|
|
754
1032
|
# Implement the hash pattern matching interface for ParseResult.
|
|
755
|
-
|
|
1033
|
+
#
|
|
1034
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
1035
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
756
1036
|
super.merge!(value: value)
|
|
757
1037
|
end
|
|
758
1038
|
|
|
759
|
-
# Attach the list of comments to their respective locations in the tree.
|
|
760
|
-
def attach_comments!
|
|
761
|
-
Comments.new(self).attach! # steep:ignore
|
|
762
|
-
end
|
|
763
|
-
|
|
764
1039
|
# Walk the tree and mark nodes that are on a new line, loosely emulating
|
|
765
1040
|
# the behavior of CRuby's `:line` tracepoint event.
|
|
1041
|
+
#
|
|
1042
|
+
#: () -> void
|
|
766
1043
|
def mark_newlines!
|
|
767
1044
|
value.accept(Newlines.new(source.offsets.size)) # steep:ignore
|
|
768
1045
|
end
|
|
769
1046
|
|
|
770
1047
|
# Returns a string representation of the syntax tree with the errors
|
|
771
1048
|
# displayed inline.
|
|
1049
|
+
#
|
|
1050
|
+
#: () -> String
|
|
772
1051
|
def errors_format
|
|
773
1052
|
Errors.new(self).format
|
|
774
1053
|
end
|
|
@@ -777,16 +1056,20 @@ module Prism
|
|
|
777
1056
|
# This is a result specific to the `lex` and `lex_file` methods.
|
|
778
1057
|
class LexResult < Result
|
|
779
1058
|
# The list of tokens that were parsed from the source code.
|
|
780
|
-
attr_reader :value
|
|
1059
|
+
attr_reader :value #: Array[Token]
|
|
781
1060
|
|
|
782
1061
|
# Create a new lex result object with the given values.
|
|
783
|
-
|
|
1062
|
+
#
|
|
1063
|
+
#: (Array[Token] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
|
|
1064
|
+
def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source)
|
|
784
1065
|
@value = value
|
|
785
|
-
super(
|
|
1066
|
+
super(magic_comments, data_loc, errors, warnings, continuable, source)
|
|
786
1067
|
end
|
|
787
1068
|
|
|
788
1069
|
# Implement the hash pattern matching interface for LexResult.
|
|
789
|
-
|
|
1070
|
+
#
|
|
1071
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
1072
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
790
1073
|
super.merge!(value: value)
|
|
791
1074
|
end
|
|
792
1075
|
end
|
|
@@ -795,16 +1078,20 @@ module Prism
|
|
|
795
1078
|
class ParseLexResult < Result
|
|
796
1079
|
# A tuple of the syntax tree and the list of tokens that were parsed from
|
|
797
1080
|
# the source code.
|
|
798
|
-
attr_reader :value
|
|
1081
|
+
attr_reader :value #: [ProgramNode, Array[Token]]
|
|
799
1082
|
|
|
800
1083
|
# Create a new parse lex result object with the given values.
|
|
801
|
-
|
|
1084
|
+
#
|
|
1085
|
+
#: ([ProgramNode, Array[Token]] value, Array[MagicComment] magic_comments, Location? data_loc, Array[ParseError] errors, Array[ParseWarning] warnings, bool continuable, Source source) -> void
|
|
1086
|
+
def initialize(value, magic_comments, data_loc, errors, warnings, continuable, source)
|
|
802
1087
|
@value = value
|
|
803
|
-
super(
|
|
1088
|
+
super(magic_comments, data_loc, errors, warnings, continuable, source)
|
|
804
1089
|
end
|
|
805
1090
|
|
|
806
1091
|
# Implement the hash pattern matching interface for ParseLexResult.
|
|
807
|
-
|
|
1092
|
+
#
|
|
1093
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
1094
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
808
1095
|
super.merge!(value: value)
|
|
809
1096
|
end
|
|
810
1097
|
end
|
|
@@ -812,29 +1099,38 @@ module Prism
|
|
|
812
1099
|
# This represents a token from the Ruby source.
|
|
813
1100
|
class Token
|
|
814
1101
|
# The Source object that represents the source this token came from.
|
|
815
|
-
attr_reader :source
|
|
1102
|
+
attr_reader :source #: Source
|
|
816
1103
|
private :source
|
|
817
1104
|
|
|
818
1105
|
# The type of token that this token is.
|
|
819
|
-
attr_reader :type
|
|
1106
|
+
attr_reader :type #: Symbol
|
|
820
1107
|
|
|
821
1108
|
# A byteslice of the source that this token represents.
|
|
822
|
-
attr_reader :value
|
|
1109
|
+
attr_reader :value #: String
|
|
1110
|
+
|
|
1111
|
+
# @rbs @location: Location | Integer
|
|
823
1112
|
|
|
824
1113
|
# Create a new token object with the given type, value, and location.
|
|
825
|
-
|
|
1114
|
+
#
|
|
1115
|
+
#: (Source source, Symbol type, String value, Location | Integer location, Integer state) -> void
|
|
1116
|
+
def initialize(source, type, value, location, state)
|
|
826
1117
|
@source = source
|
|
827
1118
|
@type = type
|
|
828
1119
|
@value = value
|
|
829
1120
|
@location = location
|
|
1121
|
+
@state = state
|
|
830
1122
|
end
|
|
831
1123
|
|
|
832
1124
|
# Implement the hash pattern matching interface for Token.
|
|
833
|
-
|
|
1125
|
+
#
|
|
1126
|
+
#: (Array[Symbol]? keys) -> Hash[Symbol, untyped]
|
|
1127
|
+
def deconstruct_keys(keys) # :nodoc:
|
|
834
1128
|
{ type: type, value: value, location: location }
|
|
835
1129
|
end
|
|
836
1130
|
|
|
837
1131
|
# A Location object representing the location of this token in the source.
|
|
1132
|
+
#
|
|
1133
|
+
#: () -> Location
|
|
838
1134
|
def location
|
|
839
1135
|
location = @location
|
|
840
1136
|
return location if location.is_a?(Location)
|
|
@@ -842,7 +1138,9 @@ module Prism
|
|
|
842
1138
|
end
|
|
843
1139
|
|
|
844
1140
|
# Implement the pretty print interface for Token.
|
|
845
|
-
|
|
1141
|
+
#
|
|
1142
|
+
#: (PP q) -> void
|
|
1143
|
+
def pretty_print(q) # :nodoc:
|
|
846
1144
|
q.group do
|
|
847
1145
|
q.text(type.to_s)
|
|
848
1146
|
self.location.pretty_print(q)
|
|
@@ -857,6 +1155,8 @@ module Prism
|
|
|
857
1155
|
end
|
|
858
1156
|
|
|
859
1157
|
# Returns true if the given other token is equal to this token.
|
|
1158
|
+
#
|
|
1159
|
+
#: (untyped other) -> bool
|
|
860
1160
|
def ==(other)
|
|
861
1161
|
Token === other &&
|
|
862
1162
|
other.type == type &&
|
|
@@ -864,17 +1164,42 @@ module Prism
|
|
|
864
1164
|
end
|
|
865
1165
|
|
|
866
1166
|
# Returns a string representation of this token.
|
|
867
|
-
|
|
1167
|
+
#
|
|
1168
|
+
#: () -> String
|
|
1169
|
+
def inspect # :nodoc:
|
|
868
1170
|
location
|
|
869
1171
|
super
|
|
870
1172
|
end
|
|
871
1173
|
|
|
872
1174
|
# Freeze this object and the objects it contains.
|
|
1175
|
+
#
|
|
1176
|
+
#: () -> void
|
|
873
1177
|
def deep_freeze
|
|
874
1178
|
value.freeze
|
|
875
1179
|
location.freeze
|
|
876
1180
|
freeze
|
|
877
1181
|
end
|
|
1182
|
+
|
|
1183
|
+
# For internal use only.
|
|
1184
|
+
#: () -> Integer
|
|
1185
|
+
def _ripper_state # :nodoc:
|
|
1186
|
+
@state
|
|
1187
|
+
end
|
|
1188
|
+
|
|
1189
|
+
# Backwards compatibility for Prism.lex/Prism.lex_file/Prism.parse_lex
|
|
1190
|
+
# when they returned a 2-element array.
|
|
1191
|
+
|
|
1192
|
+
#: (Integer index) -> Token | Integer
|
|
1193
|
+
def [](index) # :nodoc:
|
|
1194
|
+
return self if index == 0
|
|
1195
|
+
return @state if index == 1
|
|
1196
|
+
raise ArgumentError, "Invalid index #{index}"
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
#: () -> Token
|
|
1200
|
+
def first # :nodoc:
|
|
1201
|
+
self
|
|
1202
|
+
end
|
|
878
1203
|
end
|
|
879
1204
|
|
|
880
1205
|
# This object is passed to the various Prism.* methods that accept the
|
|
@@ -884,14 +1209,16 @@ module Prism
|
|
|
884
1209
|
class Scope
|
|
885
1210
|
# The list of local variables that are defined in this scope. This should be
|
|
886
1211
|
# defined as an array of symbols.
|
|
887
|
-
attr_reader :locals
|
|
1212
|
+
attr_reader :locals #: Array[Symbol]
|
|
888
1213
|
|
|
889
1214
|
# The list of local variables that are forwarded to the next scope. This
|
|
890
1215
|
# should by defined as an array of symbols containing the specific values of
|
|
891
1216
|
# :*, :**, :&, or :"...".
|
|
892
|
-
attr_reader :forwarding
|
|
1217
|
+
attr_reader :forwarding #: Array[Symbol]
|
|
893
1218
|
|
|
894
1219
|
# Create a new scope object with the given locals and forwarding.
|
|
1220
|
+
#
|
|
1221
|
+
#: (Array[Symbol] locals, Array[Symbol] forwarding) -> void
|
|
895
1222
|
def initialize(locals, forwarding)
|
|
896
1223
|
@locals = locals
|
|
897
1224
|
@forwarding = forwarding
|
|
@@ -901,6 +1228,8 @@ module Prism
|
|
|
901
1228
|
# Create a new scope with the given locals and forwarding options that is
|
|
902
1229
|
# suitable for passing into one of the Prism.* methods that accepts the
|
|
903
1230
|
# `scopes` option.
|
|
1231
|
+
#
|
|
1232
|
+
#: (?locals: Array[Symbol], ?forwarding: Array[Symbol]) -> Scope
|
|
904
1233
|
def self.scope(locals: [], forwarding: [])
|
|
905
1234
|
Scope.new(locals, forwarding)
|
|
906
1235
|
end
|