prism 2.0.0.rc1-x86_64-linux-gnu
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 +7 -0
- data/BSDmakefile +58 -0
- data/CHANGELOG.md +870 -0
- data/CODE_OF_CONDUCT.md +76 -0
- data/CONTRIBUTING.md +58 -0
- data/LICENSE.md +7 -0
- data/Makefile +145 -0
- data/README.md +81 -0
- data/config.yml +4752 -0
- data/docs/build_system.md +119 -0
- data/docs/configuration.md +69 -0
- data/docs/cruby_compilation.md +27 -0
- data/docs/design.md +53 -0
- data/docs/encoding.md +121 -0
- data/docs/fuzzing.md +81 -0
- data/docs/heredocs.md +36 -0
- data/docs/javascript.md +133 -0
- data/docs/local_variable_depth.md +229 -0
- data/docs/mapping.md +117 -0
- data/docs/parser_translation.md +24 -0
- data/docs/parsing_rules.md +22 -0
- data/docs/releasing.md +147 -0
- data/docs/relocation.md +32 -0
- data/docs/ripper_translation.md +63 -0
- data/docs/ruby_api.md +45 -0
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +230 -0
- data/docs/testing.md +72 -0
- data/ext/prism/api_node.c +7005 -0
- data/ext/prism/extconf.rb +126 -0
- data/ext/prism/extension.c +1783 -0
- data/ext/prism/extension.h +19 -0
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +10371 -0
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +24 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -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 +93 -0
- 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 +91 -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/internal/encoding.h +242 -0
- 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/internal/list.h +62 -0
- 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 +984 -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/internal/static_literals.h +100 -0
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/internal/strncasecmp.h +18 -0
- data/include/prism/internal/strpbrk.h +33 -0
- data/include/prism/internal/tokens.h +11 -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 +94 -0
- data/include/prism/options.h +354 -0
- data/include/prism/parser.h +404 -0
- data/include/prism/prettyprint.h +31 -0
- 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 +63 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +38 -0
- data/include/prism.h +131 -0
- data/lib/prism/3.3/prism.so +0 -0
- data/lib/prism/3.4/prism.so +0 -0
- data/lib/prism/4.0/prism.so +0 -0
- data/lib/prism/compiler.rb +815 -0
- data/lib/prism/desugar_compiler.rb +463 -0
- data/lib/prism/dispatcher.rb +2383 -0
- data/lib/prism/dot_visitor.rb +4848 -0
- data/lib/prism/dsl.rb +1369 -0
- data/lib/prism/ffi.rb +740 -0
- data/lib/prism/inspect_visitor.rb +2425 -0
- data/lib/prism/lex_compat.rb +953 -0
- data/lib/prism/mutation_compiler.rb +780 -0
- data/lib/prism/node.rb +33204 -0
- data/lib/prism/node_ext.rb +504 -0
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +72 -0
- data/lib/prism/parse_result/newlines.rb +423 -0
- data/lib/prism/parse_result.rb +1221 -0
- data/lib/prism/pattern.rb +314 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/byteindex.rb +13 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/unpack1.rb +14 -0
- data/lib/prism/polyfill/warn.rb +36 -0
- data/lib/prism/reflection.rb +427 -0
- data/lib/prism/relocation.rb +567 -0
- data/lib/prism/serialize.rb +5308 -0
- data/lib/prism/string_query.rb +46 -0
- data/lib/prism/translation/parser/builder.rb +70 -0
- data/lib/prism/translation/parser/compiler.rb +2226 -0
- data/lib/prism/translation/parser/lexer.rb +769 -0
- data/lib/prism/translation/parser.rb +376 -0
- data/lib/prism/translation/parser_current.rb +26 -0
- data/lib/prism/translation/parser_versions.rb +36 -0
- data/lib/prism/translation/ripper/filter.rb +53 -0
- data/lib/prism/translation/ripper/lexer.rb +133 -0
- data/lib/prism/translation/ripper/sexp.rb +118 -0
- data/lib/prism/translation/ripper/shim.rb +7 -0
- data/lib/prism/translation/ripper.rb +4278 -0
- data/lib/prism/translation/ruby_parser.rb +1721 -0
- data/lib/prism/translation.rb +20 -0
- data/lib/prism/visitor.rb +1440 -0
- data/lib/prism.rb +168 -0
- data/prism.gemspec +234 -0
- 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 +13681 -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 +764 -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 +181 -0
- data/rbi/generated/prism/string_query.rbi +36 -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.rbi +11 -0
- data/rbi/prism/translation/parser_versions.rbi +28 -0
- data/rbi/prism/translation/ripper.rbi +15 -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/generated/prism/mutation_compiler.rbs +464 -0
- data/sig/generated/prism/node.rbs +20160 -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 +859 -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 +195 -0
- data/sig/generated/prism/string_query.rbs +36 -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/buffer.c +380 -0
- data/src/char.c +289 -0
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +886 -0
- data/src/encoding.c +5345 -0
- data/src/errors_format.c +519 -0
- data/src/integer.c +681 -0
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/memchr.c +37 -0
- data/src/node.c +4515 -0
- data/src/options.c +451 -0
- data/src/parser.c +349 -0
- data/src/prettyprint.c +9024 -0
- data/src/prism.c +23739 -0
- data/src/regexp.c +1706 -0
- data/src/serialize.c +2309 -0
- data/src/source.c +518 -0
- data/src/static_literals.c +685 -0
- data/src/string_query.c +166 -0
- data/src/stringy.c +91 -0
- data/src/strncasecmp.c +37 -0
- data/src/strpbrk.c +447 -0
- data/src/tokens.c +724 -0
- metadata +259 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# rbs_inline: enabled
|
|
5
|
+
|
|
6
|
+
module Prism
|
|
7
|
+
# Prism parses deterministically for the same input. This provides a nice
|
|
8
|
+
# property that is exposed through the #node_id API on nodes. Effectively this
|
|
9
|
+
# means that for the same input, these values will remain consistent every
|
|
10
|
+
# time the source is parsed. This means we can reparse the source same with a
|
|
11
|
+
# #node_id value and find the exact same node again.
|
|
12
|
+
#
|
|
13
|
+
# The Relocation module provides an API around this property. It allows you to
|
|
14
|
+
# "save" nodes and locations using a minimal amount of memory (just the
|
|
15
|
+
# node_id and a field identifier) and then reify them later.
|
|
16
|
+
module Relocation
|
|
17
|
+
# @rbs!
|
|
18
|
+
# type entry_value = untyped
|
|
19
|
+
# type entry_values = Hash[Symbol, entry_value]
|
|
20
|
+
#
|
|
21
|
+
# interface _Value
|
|
22
|
+
# def start_line: () -> Integer
|
|
23
|
+
# def end_line: () -> Integer
|
|
24
|
+
# def start_offset: () -> Integer
|
|
25
|
+
# def end_offset: () -> Integer
|
|
26
|
+
# def start_character_offset: () -> Integer
|
|
27
|
+
# def end_character_offset: () -> Integer
|
|
28
|
+
# def cached_start_code_units_offset: (_CodeUnitsCache cache) -> Integer
|
|
29
|
+
# def cached_end_code_units_offset: (_CodeUnitsCache cache) -> Integer
|
|
30
|
+
# def start_column: () -> Integer
|
|
31
|
+
# def end_column: () -> Integer
|
|
32
|
+
# def start_character_column: () -> Integer
|
|
33
|
+
# def end_character_column: () -> Integer
|
|
34
|
+
# def cached_start_code_units_column: (_CodeUnitsCache cache) -> Integer
|
|
35
|
+
# def cached_end_code_units_column: (_CodeUnitsCache cache) -> Integer
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# interface _Field
|
|
39
|
+
# def fields: (_Value value) -> entry_values
|
|
40
|
+
# end
|
|
41
|
+
|
|
42
|
+
# An entry in a repository that will lazily reify its values when they are
|
|
43
|
+
# first accessed.
|
|
44
|
+
class Entry
|
|
45
|
+
# Raised if a value that could potentially be on an entry is missing
|
|
46
|
+
# because it was either not configured on the repository or it has not yet
|
|
47
|
+
# been fetched.
|
|
48
|
+
class MissingValueError < StandardError
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @rbs @repository: Repository?
|
|
52
|
+
# @rbs @values: Hash[Symbol, untyped]?
|
|
53
|
+
|
|
54
|
+
# Initialize a new entry with the given repository.
|
|
55
|
+
#
|
|
56
|
+
#: (Repository repository) -> void
|
|
57
|
+
def initialize(repository)
|
|
58
|
+
@repository = repository
|
|
59
|
+
@values = nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Fetch the filepath of the value.
|
|
63
|
+
#
|
|
64
|
+
#: () -> String
|
|
65
|
+
def filepath
|
|
66
|
+
fetch_value(:filepath)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Fetch the start line of the value.
|
|
70
|
+
#
|
|
71
|
+
#: () -> Integer
|
|
72
|
+
def start_line
|
|
73
|
+
fetch_value(:start_line)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Fetch the end line of the value.
|
|
77
|
+
#
|
|
78
|
+
#: () -> Integer
|
|
79
|
+
def end_line
|
|
80
|
+
fetch_value(:end_line)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Fetch the start byte offset of the value.
|
|
84
|
+
#
|
|
85
|
+
#: () -> Integer
|
|
86
|
+
def start_offset
|
|
87
|
+
fetch_value(:start_offset)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Fetch the end byte offset of the value.
|
|
91
|
+
#
|
|
92
|
+
#: () -> Integer
|
|
93
|
+
def end_offset
|
|
94
|
+
fetch_value(:end_offset)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Fetch the start character offset of the value.
|
|
98
|
+
#
|
|
99
|
+
#: () -> Integer
|
|
100
|
+
def start_character_offset
|
|
101
|
+
fetch_value(:start_character_offset)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Fetch the end character offset of the value.
|
|
105
|
+
#
|
|
106
|
+
#: () -> Integer
|
|
107
|
+
def end_character_offset
|
|
108
|
+
fetch_value(:end_character_offset)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Fetch the start code units offset of the value, for the encoding that
|
|
112
|
+
# was configured on the repository.
|
|
113
|
+
#
|
|
114
|
+
#: () -> Integer
|
|
115
|
+
def start_code_units_offset
|
|
116
|
+
fetch_value(:start_code_units_offset)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Fetch the end code units offset of the value, for the encoding that was
|
|
120
|
+
# configured on the repository.
|
|
121
|
+
#
|
|
122
|
+
#: () -> Integer
|
|
123
|
+
def end_code_units_offset
|
|
124
|
+
fetch_value(:end_code_units_offset)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Fetch the start byte column of the value.
|
|
128
|
+
#
|
|
129
|
+
#: () -> Integer
|
|
130
|
+
def start_column
|
|
131
|
+
fetch_value(:start_column)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Fetch the end byte column of the value.
|
|
135
|
+
#
|
|
136
|
+
#: () -> Integer
|
|
137
|
+
def end_column
|
|
138
|
+
fetch_value(:end_column)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Fetch the start character column of the value.
|
|
142
|
+
#
|
|
143
|
+
#: () -> Integer
|
|
144
|
+
def start_character_column
|
|
145
|
+
fetch_value(:start_character_column)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Fetch the end character column of the value.
|
|
149
|
+
#
|
|
150
|
+
#: () -> Integer
|
|
151
|
+
def end_character_column
|
|
152
|
+
fetch_value(:end_character_column)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Fetch the start code units column of the value, for the encoding that
|
|
156
|
+
# was configured on the repository.
|
|
157
|
+
#
|
|
158
|
+
#: () -> Integer
|
|
159
|
+
def start_code_units_column
|
|
160
|
+
fetch_value(:start_code_units_column)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Fetch the end code units column of the value, for the encoding that was
|
|
164
|
+
# configured on the repository.
|
|
165
|
+
#
|
|
166
|
+
#: () -> Integer
|
|
167
|
+
def end_code_units_column
|
|
168
|
+
fetch_value(:end_code_units_column)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Reify the values on this entry with the given values. This is an
|
|
172
|
+
# internal-only API that is called from the repository when it is time to
|
|
173
|
+
# reify the values.
|
|
174
|
+
#
|
|
175
|
+
#: (entry_values values) -> void
|
|
176
|
+
def reify!(values) # :nodoc:
|
|
177
|
+
@repository = nil
|
|
178
|
+
@values = values
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private
|
|
182
|
+
|
|
183
|
+
# Fetch a value from the entry, raising an error if it is missing.
|
|
184
|
+
#
|
|
185
|
+
#: (Symbol name) -> entry_value
|
|
186
|
+
def fetch_value(name)
|
|
187
|
+
values.fetch(name) do
|
|
188
|
+
raise MissingValueError, "No value for #{name}, make sure the " \
|
|
189
|
+
"repository has been properly configured"
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Return the values from the repository, reifying them if necessary.
|
|
194
|
+
#
|
|
195
|
+
#: () -> entry_values
|
|
196
|
+
def values
|
|
197
|
+
@values || (@repository&.reify!; @values) #: entry_values
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Represents the source of a repository that will be reparsed.
|
|
202
|
+
class Source
|
|
203
|
+
# The value that will need to be reparsed.
|
|
204
|
+
attr_reader :value #: untyped
|
|
205
|
+
|
|
206
|
+
# Initialize the source with the given value.
|
|
207
|
+
#
|
|
208
|
+
#: (untyped value) -> void
|
|
209
|
+
def initialize(value)
|
|
210
|
+
@value = value
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Reparse the value and return the parse result.
|
|
214
|
+
#
|
|
215
|
+
#: () -> ParseResult
|
|
216
|
+
def result
|
|
217
|
+
raise NotImplementedError, "Subclasses must implement #result"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Create a code units cache for the given encoding.
|
|
221
|
+
#
|
|
222
|
+
#: (Encoding encoding) -> _CodeUnitsCache
|
|
223
|
+
def code_units_cache(encoding)
|
|
224
|
+
result.code_units_cache(encoding)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# A source that is represented by a file path.
|
|
229
|
+
class SourceFilepath < Source
|
|
230
|
+
# Reparse the file and return the parse result.
|
|
231
|
+
#
|
|
232
|
+
#: () -> ParseResult
|
|
233
|
+
def result
|
|
234
|
+
Prism.parse_file(value)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# A source that is represented by a string.
|
|
239
|
+
class SourceString < Source
|
|
240
|
+
# Reparse the string and return the parse result.
|
|
241
|
+
#
|
|
242
|
+
#: () -> ParseResult
|
|
243
|
+
def result
|
|
244
|
+
Prism.parse(value)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# A field that represents the file path.
|
|
249
|
+
class FilepathField
|
|
250
|
+
# The file path that this field represents.
|
|
251
|
+
attr_reader :value #: String
|
|
252
|
+
|
|
253
|
+
# Initialize a new field with the given file path.
|
|
254
|
+
#
|
|
255
|
+
#: (String value) -> void
|
|
256
|
+
def initialize(value)
|
|
257
|
+
@value = value
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Fetch the file path.
|
|
261
|
+
#
|
|
262
|
+
#: (_Value _value) -> entry_values
|
|
263
|
+
def fields(_value)
|
|
264
|
+
{ filepath: value }
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# A field representing the start and end lines.
|
|
269
|
+
class LinesField
|
|
270
|
+
# Fetches the start and end line of a value.
|
|
271
|
+
#
|
|
272
|
+
#: (_Value value) -> entry_values
|
|
273
|
+
def fields(value)
|
|
274
|
+
{ start_line: value.start_line, end_line: value.end_line }
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
# A field representing the start and end byte offsets.
|
|
279
|
+
class OffsetsField
|
|
280
|
+
# Fetches the start and end byte offset of a value.
|
|
281
|
+
#
|
|
282
|
+
#: (_Value value) -> entry_values
|
|
283
|
+
def fields(value)
|
|
284
|
+
{ start_offset: value.start_offset, end_offset: value.end_offset }
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# A field representing the start and end character offsets.
|
|
289
|
+
class CharacterOffsetsField
|
|
290
|
+
# Fetches the start and end character offset of a value.
|
|
291
|
+
#
|
|
292
|
+
#: (_Value value) -> entry_values
|
|
293
|
+
def fields(value)
|
|
294
|
+
{
|
|
295
|
+
start_character_offset: value.start_character_offset,
|
|
296
|
+
end_character_offset: value.end_character_offset
|
|
297
|
+
}
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# A field representing the start and end code unit offsets.
|
|
302
|
+
class CodeUnitOffsetsField
|
|
303
|
+
# A pointer to the repository object that is used for lazily creating a
|
|
304
|
+
# code units cache.
|
|
305
|
+
attr_reader :repository #: Repository
|
|
306
|
+
|
|
307
|
+
# The associated encoding for the code units.
|
|
308
|
+
attr_reader :encoding #: Encoding
|
|
309
|
+
|
|
310
|
+
# @rbs @cache: _CodeUnitsCache?
|
|
311
|
+
|
|
312
|
+
# Initialize a new field with the associated repository and encoding.
|
|
313
|
+
#
|
|
314
|
+
#: (Repository repository, Encoding encoding) -> void
|
|
315
|
+
def initialize(repository, encoding)
|
|
316
|
+
@repository = repository
|
|
317
|
+
@encoding = encoding
|
|
318
|
+
@cache = nil
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Fetches the start and end code units offset of a value for a particular
|
|
322
|
+
# encoding.
|
|
323
|
+
#
|
|
324
|
+
#: (_Value value) -> entry_values
|
|
325
|
+
def fields(value)
|
|
326
|
+
{
|
|
327
|
+
start_code_units_offset: value.cached_start_code_units_offset(cache),
|
|
328
|
+
end_code_units_offset: value.cached_end_code_units_offset(cache)
|
|
329
|
+
}
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
private
|
|
333
|
+
|
|
334
|
+
# Lazily create a code units cache for the associated encoding.
|
|
335
|
+
#
|
|
336
|
+
#: () -> _CodeUnitsCache
|
|
337
|
+
def cache
|
|
338
|
+
@cache ||= repository.code_units_cache(encoding)
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# A field representing the start and end byte columns.
|
|
343
|
+
class ColumnsField
|
|
344
|
+
# Fetches the start and end byte column of a value.
|
|
345
|
+
#
|
|
346
|
+
#: (_Value value) -> entry_values
|
|
347
|
+
def fields(value)
|
|
348
|
+
{ start_column: value.start_column, end_column: value.end_column }
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# A field representing the start and end character columns.
|
|
353
|
+
class CharacterColumnsField
|
|
354
|
+
# Fetches the start and end character column of a value.
|
|
355
|
+
#
|
|
356
|
+
#: (_Value value) -> entry_values
|
|
357
|
+
def fields(value)
|
|
358
|
+
{
|
|
359
|
+
start_character_column: value.start_character_column,
|
|
360
|
+
end_character_column: value.end_character_column
|
|
361
|
+
}
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# A field representing the start and end code unit columns for a specific
|
|
366
|
+
# encoding.
|
|
367
|
+
class CodeUnitColumnsField
|
|
368
|
+
# The repository object that is used for lazily creating a code units
|
|
369
|
+
# cache.
|
|
370
|
+
attr_reader :repository #: Repository
|
|
371
|
+
|
|
372
|
+
# The associated encoding for the code units.
|
|
373
|
+
attr_reader :encoding #: Encoding
|
|
374
|
+
|
|
375
|
+
# @rbs @cache: _CodeUnitsCache?
|
|
376
|
+
|
|
377
|
+
# Initialize a new field with the associated repository and encoding.
|
|
378
|
+
#
|
|
379
|
+
#: (Repository repository, Encoding encoding) -> void
|
|
380
|
+
def initialize(repository, encoding)
|
|
381
|
+
@repository = repository
|
|
382
|
+
@encoding = encoding
|
|
383
|
+
@cache = nil
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Fetches the start and end code units column of a value for a particular
|
|
387
|
+
# encoding.
|
|
388
|
+
#
|
|
389
|
+
#: (_Value value) -> entry_values
|
|
390
|
+
def fields(value)
|
|
391
|
+
{
|
|
392
|
+
start_code_units_column: value.cached_start_code_units_column(cache),
|
|
393
|
+
end_code_units_column: value.cached_end_code_units_column(cache)
|
|
394
|
+
}
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
private
|
|
398
|
+
|
|
399
|
+
# Lazily create a code units cache for the associated encoding.
|
|
400
|
+
#
|
|
401
|
+
#: () -> _CodeUnitsCache
|
|
402
|
+
def cache
|
|
403
|
+
@cache ||= repository.code_units_cache(encoding)
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# A repository is a configured collection of fields and a set of entries
|
|
408
|
+
# that knows how to reparse a source and reify the values.
|
|
409
|
+
class Repository
|
|
410
|
+
# Raised when multiple fields of the same type are configured on the same
|
|
411
|
+
# repository.
|
|
412
|
+
class ConfigurationError < StandardError
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# The source associated with this repository. This will be either a
|
|
416
|
+
# SourceFilepath (the most common use case) or a SourceString.
|
|
417
|
+
attr_reader :source #: Source
|
|
418
|
+
|
|
419
|
+
# The fields that have been configured on this repository.
|
|
420
|
+
attr_reader :fields #: Hash[Symbol, _Field]
|
|
421
|
+
|
|
422
|
+
# The entries that have been saved on this repository.
|
|
423
|
+
attr_reader :entries #: Hash[Integer, Hash[Symbol, Entry]]
|
|
424
|
+
|
|
425
|
+
# Initialize a new repository with the given source.
|
|
426
|
+
#
|
|
427
|
+
#: (Source source) -> void
|
|
428
|
+
def initialize(source)
|
|
429
|
+
@source = source
|
|
430
|
+
@fields = {}
|
|
431
|
+
@entries = Hash.new { |hash, node_id| hash[node_id] = {} }
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
# Create a code units cache for the given encoding from the source.
|
|
435
|
+
#
|
|
436
|
+
#: (Encoding encoding) -> _CodeUnitsCache
|
|
437
|
+
def code_units_cache(encoding)
|
|
438
|
+
source.code_units_cache(encoding)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Configure the filepath field for this repository and return self.
|
|
442
|
+
#
|
|
443
|
+
#: () -> self
|
|
444
|
+
def filepath
|
|
445
|
+
raise ConfigurationError, "Can only specify filepath for a filepath source" unless source.is_a?(SourceFilepath)
|
|
446
|
+
field(:filepath, FilepathField.new(source.value))
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# Configure the lines field for this repository and return self.
|
|
450
|
+
#
|
|
451
|
+
#: () -> self
|
|
452
|
+
def lines
|
|
453
|
+
field(:lines, LinesField.new)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# Configure the offsets field for this repository and return self.
|
|
457
|
+
#
|
|
458
|
+
#: () -> self
|
|
459
|
+
def offsets
|
|
460
|
+
field(:offsets, OffsetsField.new)
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Configure the character offsets field for this repository and return
|
|
464
|
+
# self.
|
|
465
|
+
#
|
|
466
|
+
#: () -> self
|
|
467
|
+
def character_offsets
|
|
468
|
+
field(:character_offsets, CharacterOffsetsField.new)
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
# Configure the code unit offsets field for this repository for a specific
|
|
472
|
+
# encoding and return self.
|
|
473
|
+
#
|
|
474
|
+
#: (Encoding encoding) -> self
|
|
475
|
+
def code_unit_offsets(encoding)
|
|
476
|
+
field(:code_unit_offsets, CodeUnitOffsetsField.new(self, encoding))
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Configure the columns field for this repository and return self.
|
|
480
|
+
#
|
|
481
|
+
#: () -> self
|
|
482
|
+
def columns
|
|
483
|
+
field(:columns, ColumnsField.new)
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
# Configure the character columns field for this repository and return
|
|
487
|
+
# self.
|
|
488
|
+
#
|
|
489
|
+
#: () -> self
|
|
490
|
+
def character_columns
|
|
491
|
+
field(:character_columns, CharacterColumnsField.new)
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
# Configure the code unit columns field for this repository for a specific
|
|
495
|
+
# encoding and return self.
|
|
496
|
+
#
|
|
497
|
+
#: (Encoding encoding) -> self
|
|
498
|
+
def code_unit_columns(encoding)
|
|
499
|
+
field(:code_unit_columns, CodeUnitColumnsField.new(self, encoding))
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# This method is called from nodes and locations when they want to enter
|
|
503
|
+
# themselves into the repository. It it internal-only and meant to be
|
|
504
|
+
# called from the #save* APIs.
|
|
505
|
+
#
|
|
506
|
+
#: (Integer node_id, Symbol field_name) -> Entry
|
|
507
|
+
def enter(node_id, field_name) # :nodoc:
|
|
508
|
+
entry = Entry.new(self)
|
|
509
|
+
@entries[node_id][field_name] = entry
|
|
510
|
+
entry
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# This method is called from the entries in the repository when they need
|
|
514
|
+
# to reify their values. It is internal-only and meant to be called from
|
|
515
|
+
# the various value APIs.
|
|
516
|
+
#
|
|
517
|
+
#: () -> void
|
|
518
|
+
def reify! # :nodoc:
|
|
519
|
+
result = source.result
|
|
520
|
+
|
|
521
|
+
queue = [result.value] #: Array[Prism::node]
|
|
522
|
+
while (node = queue.shift)
|
|
523
|
+
@entries[node.node_id].each do |field_name, entry|
|
|
524
|
+
value = node.public_send(field_name)
|
|
525
|
+
values = {} #: entry_values
|
|
526
|
+
|
|
527
|
+
fields.each_value do |field|
|
|
528
|
+
values.merge!(field.fields(value))
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
entry.reify!(values)
|
|
532
|
+
end
|
|
533
|
+
|
|
534
|
+
queue.concat(node.compact_child_nodes)
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
@entries.clear
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
private
|
|
541
|
+
|
|
542
|
+
# Append the given field to the repository and return the repository so
|
|
543
|
+
# that these calls can be chained.
|
|
544
|
+
#
|
|
545
|
+
#: (Symbol name, _Field) -> self
|
|
546
|
+
def field(name, value)
|
|
547
|
+
raise ConfigurationError, "Cannot specify multiple #{name} fields" if @fields.key?(name)
|
|
548
|
+
@fields[name] = value
|
|
549
|
+
self
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# Create a new repository for the given filepath.
|
|
554
|
+
#
|
|
555
|
+
#: (String value) -> Repository
|
|
556
|
+
def self.filepath(value)
|
|
557
|
+
Repository.new(SourceFilepath.new(value))
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# Create a new repository for the given string.
|
|
561
|
+
#
|
|
562
|
+
#: (String value) -> Repository
|
|
563
|
+
def self.string(value)
|
|
564
|
+
Repository.new(SourceString.new(value))
|
|
565
|
+
end
|
|
566
|
+
end
|
|
567
|
+
end
|