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,376 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
required_version = ">= 3.3.7.2"
|
|
6
|
+
gem "parser", required_version
|
|
7
|
+
require "parser"
|
|
8
|
+
rescue LoadError
|
|
9
|
+
warn(<<~MSG)
|
|
10
|
+
Error: Unable to load parser #{required_version}. \
|
|
11
|
+
Add `gem "parser"` to your Gemfile or run `bundle update parser`.
|
|
12
|
+
MSG
|
|
13
|
+
exit(1)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Prism
|
|
17
|
+
module Translation
|
|
18
|
+
# This class is the entry-point for converting a prism syntax tree into the
|
|
19
|
+
# whitequark/parser gem's syntax tree. It inherits from the base parser for
|
|
20
|
+
# the parser gem, and overrides the parse* methods to parse with prism and
|
|
21
|
+
# then translate.
|
|
22
|
+
#
|
|
23
|
+
# Note that this version of the parser always parses using the latest
|
|
24
|
+
# version of Ruby syntax supported by Prism. If you want specific version
|
|
25
|
+
# support, use one of the version-specific subclasses, such as
|
|
26
|
+
# `Prism::Translation::Parser34`. If you want to parse using the same
|
|
27
|
+
# version of Ruby syntax as the currently running version of Ruby, use
|
|
28
|
+
# `Prism::Translation::ParserCurrent`.
|
|
29
|
+
class Parser < ::Parser::Base
|
|
30
|
+
Diagnostic = ::Parser::Diagnostic # :nodoc:
|
|
31
|
+
private_constant :Diagnostic
|
|
32
|
+
|
|
33
|
+
# The parser gem has a list of diagnostics with a hard-coded set of error
|
|
34
|
+
# messages. We create our own diagnostic class in order to set our own
|
|
35
|
+
# error messages.
|
|
36
|
+
class PrismDiagnostic < Diagnostic # :nodoc:
|
|
37
|
+
# This is the cached message coming from prism.
|
|
38
|
+
attr_reader :message
|
|
39
|
+
|
|
40
|
+
# Initialize a new diagnostic with the given message and location.
|
|
41
|
+
def initialize(message, level, reason, location)
|
|
42
|
+
@message = message
|
|
43
|
+
super(level, reason, {}, location, [])
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
Racc_debug_parser = false # :nodoc:
|
|
48
|
+
|
|
49
|
+
# The `builder` argument is used to create the parser using our custom builder class by default.
|
|
50
|
+
#
|
|
51
|
+
# By using the `:parser` keyword argument, you can translate in a way that is compatible with
|
|
52
|
+
# the Parser gem using any parser.
|
|
53
|
+
#
|
|
54
|
+
# For example, in RuboCop for Ruby LSP, the following approach can be used to improve performance
|
|
55
|
+
# by reusing a pre-parsed `Prism::ParseLexResult`:
|
|
56
|
+
#
|
|
57
|
+
# class PrismPreparsed
|
|
58
|
+
# def initialize(prism_result)
|
|
59
|
+
# @prism_result = prism_result
|
|
60
|
+
# end
|
|
61
|
+
#
|
|
62
|
+
# def parse_lex(source, **options)
|
|
63
|
+
# @prism_result
|
|
64
|
+
# end
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
67
|
+
# prism_preparsed = PrismPreparsed.new(prism_result)
|
|
68
|
+
#
|
|
69
|
+
# Prism::Translation::Ruby34.new(builder, parser: prism_preparsed)
|
|
70
|
+
#
|
|
71
|
+
# In an object passed to the `:parser` keyword argument, the `parse` and `parse_lex` methods
|
|
72
|
+
# should be implemented as needed.
|
|
73
|
+
#
|
|
74
|
+
def initialize(builder = Prism::Translation::Parser::Builder.new, parser: Prism)
|
|
75
|
+
if !builder.is_a?(Prism::Translation::Parser::Builder)
|
|
76
|
+
warn(<<~MSG, uplevel: 1, category: :deprecated)
|
|
77
|
+
[deprecation]: The builder passed to `Prism::Translation::Parser.new` is not a \
|
|
78
|
+
`Prism::Translation::Parser::Builder` subclass. This will raise in the next major version.
|
|
79
|
+
MSG
|
|
80
|
+
end
|
|
81
|
+
@parser = parser
|
|
82
|
+
|
|
83
|
+
super(builder)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def version # :nodoc:
|
|
87
|
+
41
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# The default encoding for Ruby files is UTF-8.
|
|
91
|
+
def default_encoding
|
|
92
|
+
Encoding::UTF_8
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def yyerror # :nodoc:
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Parses a source buffer and returns the AST.
|
|
99
|
+
def parse(source_buffer)
|
|
100
|
+
@source_buffer = source_buffer
|
|
101
|
+
source = source_buffer.source
|
|
102
|
+
|
|
103
|
+
offset_cache = build_offset_cache(source)
|
|
104
|
+
result = unwrap(@parser.parse(source, **prism_options), offset_cache)
|
|
105
|
+
|
|
106
|
+
build_ast(result.value, offset_cache)
|
|
107
|
+
ensure
|
|
108
|
+
@source_buffer = nil
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Parses a source buffer and returns the AST and the source code comments.
|
|
112
|
+
def parse_with_comments(source_buffer)
|
|
113
|
+
@source_buffer = source_buffer
|
|
114
|
+
source = source_buffer.source
|
|
115
|
+
|
|
116
|
+
offset_cache = build_offset_cache(source)
|
|
117
|
+
result = unwrap(@parser.parse(source, **prism_options), offset_cache)
|
|
118
|
+
|
|
119
|
+
[
|
|
120
|
+
build_ast(result.value, offset_cache),
|
|
121
|
+
build_comments(result.comments, offset_cache)
|
|
122
|
+
]
|
|
123
|
+
ensure
|
|
124
|
+
@source_buffer = nil
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Parses a source buffer and returns the AST, the source code comments,
|
|
128
|
+
# and the tokens emitted by the lexer.
|
|
129
|
+
def tokenize(source_buffer, recover = false)
|
|
130
|
+
@source_buffer = source_buffer
|
|
131
|
+
source = source_buffer.source
|
|
132
|
+
|
|
133
|
+
offset_cache = build_offset_cache(source)
|
|
134
|
+
result =
|
|
135
|
+
begin
|
|
136
|
+
unwrap(@parser.parse_lex(source, **prism_options), offset_cache)
|
|
137
|
+
rescue ::Parser::SyntaxError
|
|
138
|
+
raise if !recover
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
program, tokens = result.value
|
|
142
|
+
ast = build_ast(program, offset_cache) if result.success?
|
|
143
|
+
|
|
144
|
+
[
|
|
145
|
+
ast,
|
|
146
|
+
build_comments(result.comments, offset_cache),
|
|
147
|
+
build_tokens(tokens, offset_cache)
|
|
148
|
+
]
|
|
149
|
+
ensure
|
|
150
|
+
@source_buffer = nil
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Since prism resolves num params for us, we don't need to support this
|
|
154
|
+
# kind of logic here.
|
|
155
|
+
def try_declare_numparam(node)
|
|
156
|
+
node.children[0].match?(/\A_[1-9]\z/)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
private
|
|
160
|
+
|
|
161
|
+
# This is a hook to allow consumers to disable some errors if they don't
|
|
162
|
+
# want them to block creating the syntax tree.
|
|
163
|
+
def valid_error?(error)
|
|
164
|
+
true
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# This is a hook to allow consumers to disable some warnings if they don't
|
|
168
|
+
# want them to block creating the syntax tree.
|
|
169
|
+
def valid_warning?(warning)
|
|
170
|
+
true
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Build a diagnostic from the given prism parse error.
|
|
174
|
+
def error_diagnostic(error, offset_cache)
|
|
175
|
+
location = error.location
|
|
176
|
+
diagnostic_location = build_range(location, offset_cache)
|
|
177
|
+
|
|
178
|
+
case error.type
|
|
179
|
+
when :argument_block_multi
|
|
180
|
+
Diagnostic.new(:error, :block_and_blockarg, {}, diagnostic_location, [])
|
|
181
|
+
when :argument_formal_constant
|
|
182
|
+
Diagnostic.new(:error, :argument_const, {}, diagnostic_location, [])
|
|
183
|
+
when :argument_formal_class
|
|
184
|
+
Diagnostic.new(:error, :argument_cvar, {}, diagnostic_location, [])
|
|
185
|
+
when :argument_formal_global
|
|
186
|
+
Diagnostic.new(:error, :argument_gvar, {}, diagnostic_location, [])
|
|
187
|
+
when :argument_formal_ivar
|
|
188
|
+
Diagnostic.new(:error, :argument_ivar, {}, diagnostic_location, [])
|
|
189
|
+
when :argument_no_forwarding_amp
|
|
190
|
+
Diagnostic.new(:error, :no_anonymous_blockarg, {}, diagnostic_location, [])
|
|
191
|
+
when :argument_no_forwarding_star
|
|
192
|
+
Diagnostic.new(:error, :no_anonymous_restarg, {}, diagnostic_location, [])
|
|
193
|
+
when :argument_no_forwarding_star_star
|
|
194
|
+
Diagnostic.new(:error, :no_anonymous_kwrestarg, {}, diagnostic_location, [])
|
|
195
|
+
when :begin_lonely_else
|
|
196
|
+
location = location.copy(length: 4)
|
|
197
|
+
diagnostic_location = build_range(location, offset_cache)
|
|
198
|
+
Diagnostic.new(:error, :useless_else, {}, diagnostic_location, [])
|
|
199
|
+
when :class_name, :module_name
|
|
200
|
+
Diagnostic.new(:error, :module_name_const, {}, diagnostic_location, [])
|
|
201
|
+
when :class_in_method
|
|
202
|
+
Diagnostic.new(:error, :class_in_def, {}, diagnostic_location, [])
|
|
203
|
+
when :def_endless_setter
|
|
204
|
+
Diagnostic.new(:error, :endless_setter, {}, diagnostic_location, [])
|
|
205
|
+
when :embdoc_term
|
|
206
|
+
Diagnostic.new(:error, :embedded_document, {}, diagnostic_location, [])
|
|
207
|
+
when :incomplete_variable_class, :incomplete_variable_class_3_3
|
|
208
|
+
location = location.copy(length: location.length + 1)
|
|
209
|
+
diagnostic_location = build_range(location, offset_cache)
|
|
210
|
+
|
|
211
|
+
Diagnostic.new(:error, :cvar_name, { name: location.slice }, diagnostic_location, [])
|
|
212
|
+
when :incomplete_variable_instance, :incomplete_variable_instance_3_3
|
|
213
|
+
location = location.copy(length: location.length + 1)
|
|
214
|
+
diagnostic_location = build_range(location, offset_cache)
|
|
215
|
+
|
|
216
|
+
Diagnostic.new(:error, :ivar_name, { name: location.slice }, diagnostic_location, [])
|
|
217
|
+
when :invalid_variable_global, :invalid_variable_global_3_3
|
|
218
|
+
Diagnostic.new(:error, :gvar_name, { name: location.slice }, diagnostic_location, [])
|
|
219
|
+
when :module_in_method
|
|
220
|
+
Diagnostic.new(:error, :module_in_def, {}, diagnostic_location, [])
|
|
221
|
+
when :numbered_parameter_ordinary
|
|
222
|
+
Diagnostic.new(:error, :ordinary_param_defined, {}, diagnostic_location, [])
|
|
223
|
+
when :numbered_parameter_outer_scope
|
|
224
|
+
Diagnostic.new(:error, :numparam_used_in_outer_scope, {}, diagnostic_location, [])
|
|
225
|
+
when :parameter_circular
|
|
226
|
+
Diagnostic.new(:error, :circular_argument_reference, { var_name: location.slice }, diagnostic_location, [])
|
|
227
|
+
when :parameter_name_repeat
|
|
228
|
+
Diagnostic.new(:error, :duplicate_argument, {}, diagnostic_location, [])
|
|
229
|
+
when :parameter_numbered_reserved
|
|
230
|
+
Diagnostic.new(:error, :reserved_for_numparam, { name: location.slice }, diagnostic_location, [])
|
|
231
|
+
when :regexp_unknown_options
|
|
232
|
+
Diagnostic.new(:error, :regexp_options, { options: location.slice[1..] }, diagnostic_location, [])
|
|
233
|
+
when :singleton_for_literals
|
|
234
|
+
Diagnostic.new(:error, :singleton_literal, {}, diagnostic_location, [])
|
|
235
|
+
when :string_literal_eof
|
|
236
|
+
Diagnostic.new(:error, :string_eof, {}, diagnostic_location, [])
|
|
237
|
+
when :unexpected_token_ignore
|
|
238
|
+
Diagnostic.new(:error, :unexpected_token, { token: location.slice }, diagnostic_location, [])
|
|
239
|
+
when :write_target_in_method
|
|
240
|
+
Diagnostic.new(:error, :dynamic_const, {}, diagnostic_location, [])
|
|
241
|
+
else
|
|
242
|
+
PrismDiagnostic.new(error.message, :error, error.type, diagnostic_location)
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Build a diagnostic from the given prism parse warning.
|
|
247
|
+
def warning_diagnostic(warning, offset_cache)
|
|
248
|
+
diagnostic_location = build_range(warning.location, offset_cache)
|
|
249
|
+
|
|
250
|
+
case warning.type
|
|
251
|
+
when :ambiguous_first_argument_plus
|
|
252
|
+
Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "+" }, diagnostic_location, [])
|
|
253
|
+
when :ambiguous_first_argument_minus
|
|
254
|
+
Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "-" }, diagnostic_location, [])
|
|
255
|
+
when :ambiguous_prefix_ampersand
|
|
256
|
+
Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "&" }, diagnostic_location, [])
|
|
257
|
+
when :ambiguous_prefix_star
|
|
258
|
+
Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "*" }, diagnostic_location, [])
|
|
259
|
+
when :ambiguous_prefix_star_star
|
|
260
|
+
Diagnostic.new(:warning, :ambiguous_prefix, { prefix: "**" }, diagnostic_location, [])
|
|
261
|
+
when :ambiguous_slash
|
|
262
|
+
Diagnostic.new(:warning, :ambiguous_regexp, {}, diagnostic_location, [])
|
|
263
|
+
when :dot_dot_dot_eol
|
|
264
|
+
Diagnostic.new(:warning, :triple_dot_at_eol, {}, diagnostic_location, [])
|
|
265
|
+
when :duplicated_hash_key
|
|
266
|
+
# skip, parser does this on its own
|
|
267
|
+
else
|
|
268
|
+
PrismDiagnostic.new(warning.message, :warning, warning.type, diagnostic_location)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# If there was a error generated during the parse, then raise an
|
|
273
|
+
# appropriate syntax error. Otherwise return the result.
|
|
274
|
+
def unwrap(result, offset_cache)
|
|
275
|
+
result.errors.each do |error|
|
|
276
|
+
next unless valid_error?(error)
|
|
277
|
+
diagnostics.process(error_diagnostic(error, offset_cache))
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
result.warnings.each do |warning|
|
|
281
|
+
next unless valid_warning?(warning)
|
|
282
|
+
diagnostic = warning_diagnostic(warning, offset_cache)
|
|
283
|
+
diagnostics.process(diagnostic) if diagnostic
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
result
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Prism deals with offsets in bytes, while the parser gem deals with
|
|
290
|
+
# offsets in characters. We need to handle this conversion in order to
|
|
291
|
+
# build the parser gem AST.
|
|
292
|
+
#
|
|
293
|
+
# If the bytesize of the source is the same as the length, then we can
|
|
294
|
+
# just use the offset directly. Otherwise, we build an array where the
|
|
295
|
+
# index is the byte offset and the value is the character offset.
|
|
296
|
+
def build_offset_cache(source)
|
|
297
|
+
if source.bytesize == source.length
|
|
298
|
+
-> (offset) { offset }
|
|
299
|
+
else
|
|
300
|
+
offset_cache = []
|
|
301
|
+
offset = 0
|
|
302
|
+
|
|
303
|
+
source.each_char do |char|
|
|
304
|
+
char.bytesize.times { offset_cache << offset }
|
|
305
|
+
offset += 1
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
offset_cache << offset
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Build the parser gem AST from the prism AST.
|
|
313
|
+
def build_ast(program, offset_cache)
|
|
314
|
+
program.accept(Compiler.new(self, offset_cache))
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Build the parser gem comments from the prism comments.
|
|
318
|
+
def build_comments(comments, offset_cache)
|
|
319
|
+
comments.map do |comment|
|
|
320
|
+
::Parser::Source::Comment.new(build_range(comment.location, offset_cache))
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Build the parser gem tokens from the prism tokens.
|
|
325
|
+
def build_tokens(tokens, offset_cache)
|
|
326
|
+
Lexer.new(source_buffer, tokens, offset_cache).to_a
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Build a range from a prism location.
|
|
330
|
+
def build_range(location, offset_cache)
|
|
331
|
+
::Parser::Source::Range.new(
|
|
332
|
+
source_buffer,
|
|
333
|
+
offset_cache[location.start_offset],
|
|
334
|
+
offset_cache[location.end_offset]
|
|
335
|
+
)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# Options for how prism should parse/lex the source.
|
|
339
|
+
def prism_options
|
|
340
|
+
options = {
|
|
341
|
+
filepath: @source_buffer.name,
|
|
342
|
+
version: convert_for_prism(version),
|
|
343
|
+
partial_script: true,
|
|
344
|
+
}
|
|
345
|
+
# The parser gem always encodes to UTF-8, unless it is binary.
|
|
346
|
+
# https://github.com/whitequark/parser/blob/v3.3.6.0/lib/parser/source/buffer.rb#L80-L107
|
|
347
|
+
options[:encoding] = false if @source_buffer.source.encoding != Encoding::BINARY
|
|
348
|
+
|
|
349
|
+
options
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Converts the version format handled by Parser to the format handled by Prism.
|
|
353
|
+
def convert_for_prism(version)
|
|
354
|
+
case version
|
|
355
|
+
when 33
|
|
356
|
+
"3.3.1"
|
|
357
|
+
when 34
|
|
358
|
+
"3.4.0"
|
|
359
|
+
when 35, 40
|
|
360
|
+
"4.0.0"
|
|
361
|
+
when 41
|
|
362
|
+
"4.1.0"
|
|
363
|
+
else
|
|
364
|
+
"latest"
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
require_relative "parser/builder"
|
|
369
|
+
require_relative "parser/compiler"
|
|
370
|
+
require_relative "parser/lexer"
|
|
371
|
+
|
|
372
|
+
private_constant :Compiler
|
|
373
|
+
private_constant :Lexer
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
#--
|
|
4
|
+
# typed: ignore
|
|
5
|
+
|
|
6
|
+
module Prism
|
|
7
|
+
module Translation
|
|
8
|
+
case RUBY_VERSION
|
|
9
|
+
when /^3\.3\./
|
|
10
|
+
ParserCurrent = Parser33
|
|
11
|
+
when /^3\.4\./
|
|
12
|
+
ParserCurrent = Parser34
|
|
13
|
+
when /^3\.5\./, /^4\.0\./
|
|
14
|
+
ParserCurrent = Parser40
|
|
15
|
+
when /^4\.1\./
|
|
16
|
+
ParserCurrent = Parser41
|
|
17
|
+
else
|
|
18
|
+
# Keep this in sync with released Ruby.
|
|
19
|
+
parser = Parser40
|
|
20
|
+
major, minor, _patch = Gem::Version.new(RUBY_VERSION).segments
|
|
21
|
+
warn "warning: `Prism::Translation::Current` is loading #{parser.name}, " \
|
|
22
|
+
"but you are running #{major}.#{minor}."
|
|
23
|
+
ParserCurrent = parser
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
|
|
4
|
+
module Prism
|
|
5
|
+
module Translation
|
|
6
|
+
# This class is the entry-point for Ruby 3.3 of `Prism::Translation::Parser`.
|
|
7
|
+
class Parser33 < Parser
|
|
8
|
+
def version # :nodoc:
|
|
9
|
+
33
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# This class is the entry-point for Ruby 3.4 of `Prism::Translation::Parser`.
|
|
14
|
+
class Parser34 < Parser
|
|
15
|
+
def version # :nodoc:
|
|
16
|
+
34
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# This class is the entry-point for Ruby 4.0 of `Prism::Translation::Parser`.
|
|
21
|
+
class Parser40 < Parser
|
|
22
|
+
def version # :nodoc:
|
|
23
|
+
40
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Parser35 = Parser40 # :nodoc:
|
|
28
|
+
|
|
29
|
+
# This class is the entry-point for Ruby 4.1 of `Prism::Translation::Parser`.
|
|
30
|
+
class Parser41 < Parser
|
|
31
|
+
def version # :nodoc:
|
|
32
|
+
41
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prism
|
|
4
|
+
module Translation
|
|
5
|
+
class Ripper
|
|
6
|
+
class Filter # :nodoc:
|
|
7
|
+
# :stopdoc:
|
|
8
|
+
def initialize(src, filename = '-', lineno = 1)
|
|
9
|
+
@__lexer = Lexer.new(src, filename, lineno)
|
|
10
|
+
@__line = nil
|
|
11
|
+
@__col = nil
|
|
12
|
+
@__state = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def filename
|
|
16
|
+
@__lexer.filename
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def lineno
|
|
20
|
+
@__line
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def column
|
|
24
|
+
@__col
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def state
|
|
28
|
+
@__state
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def parse(init = nil)
|
|
32
|
+
data = init
|
|
33
|
+
@__lexer.lex.each do |pos, event, tok, state|
|
|
34
|
+
@__line, @__col = *pos
|
|
35
|
+
@__state = state
|
|
36
|
+
data = if respond_to?(event, true)
|
|
37
|
+
then __send__(event, tok, data)
|
|
38
|
+
else on_default(event, tok, data)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
data
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def on_default(event, token, data)
|
|
47
|
+
data
|
|
48
|
+
end
|
|
49
|
+
# :startdoc:
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# :markup: markdown
|
|
3
|
+
|
|
4
|
+
require_relative "../ripper"
|
|
5
|
+
|
|
6
|
+
module Prism
|
|
7
|
+
module Translation
|
|
8
|
+
class Ripper
|
|
9
|
+
class Lexer < Ripper # :nodoc:
|
|
10
|
+
class State # :nodoc:
|
|
11
|
+
attr_reader :to_int, :to_s
|
|
12
|
+
|
|
13
|
+
def initialize(i)
|
|
14
|
+
@to_int = i
|
|
15
|
+
@to_s = Ripper.lex_state_name(i)
|
|
16
|
+
freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def [](index)
|
|
20
|
+
case index
|
|
21
|
+
when 0, :to_int
|
|
22
|
+
@to_int
|
|
23
|
+
when 1, :to_s
|
|
24
|
+
@to_s
|
|
25
|
+
else
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias to_i to_int
|
|
31
|
+
alias inspect to_s
|
|
32
|
+
def pretty_print(q) q.text(to_s) end
|
|
33
|
+
def ==(i) super or to_int == i end
|
|
34
|
+
def &(i) self.class.new(to_int & i) end
|
|
35
|
+
def |(i) self.class.new(to_int | i) end
|
|
36
|
+
def allbits?(i) to_int.allbits?(i) end
|
|
37
|
+
def anybits?(i) to_int.anybits?(i) end
|
|
38
|
+
def nobits?(i) to_int.nobits?(i) end
|
|
39
|
+
|
|
40
|
+
# Instances are frozen and there are only a handful of them so we
|
|
41
|
+
# cache them here.
|
|
42
|
+
STATES = Hash.new { |hash, key| hash[key] = State.new(key) }
|
|
43
|
+
private_constant :STATES
|
|
44
|
+
|
|
45
|
+
def self.[](i)
|
|
46
|
+
STATES[i]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class Elem # :nodoc:
|
|
51
|
+
attr_accessor :pos, :event, :tok, :state, :message
|
|
52
|
+
|
|
53
|
+
def initialize(pos, event, tok, state, message = nil)
|
|
54
|
+
@pos = pos
|
|
55
|
+
@event = event
|
|
56
|
+
@tok = tok
|
|
57
|
+
@state = State[state]
|
|
58
|
+
@message = message
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def [](index)
|
|
62
|
+
case index
|
|
63
|
+
when 0, :pos
|
|
64
|
+
@pos
|
|
65
|
+
when 1, :event
|
|
66
|
+
@event
|
|
67
|
+
when 2, :tok
|
|
68
|
+
@tok
|
|
69
|
+
when 3, :state
|
|
70
|
+
@state
|
|
71
|
+
when 4, :message
|
|
72
|
+
@message
|
|
73
|
+
else
|
|
74
|
+
nil
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def inspect
|
|
79
|
+
"#<#{self.class}: #{event}@#{pos[0]}:#{pos[1]}:#{state}: #{tok.inspect}#{": " if message}#{message}>"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
alias to_s inspect
|
|
83
|
+
|
|
84
|
+
def pretty_print(q)
|
|
85
|
+
q.group(2, "#<#{self.class}:", ">") {
|
|
86
|
+
q.breakable
|
|
87
|
+
q.text("#{event}@#{pos[0]}:#{pos[1]}")
|
|
88
|
+
q.breakable
|
|
89
|
+
state.pretty_print(q)
|
|
90
|
+
q.breakable
|
|
91
|
+
q.text("token: ")
|
|
92
|
+
tok.pretty_print(q)
|
|
93
|
+
if message
|
|
94
|
+
q.breakable
|
|
95
|
+
q.text("message: ")
|
|
96
|
+
q.text(message)
|
|
97
|
+
end
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def to_a
|
|
102
|
+
if @message
|
|
103
|
+
[@pos, @event, @tok, @state, @message]
|
|
104
|
+
else
|
|
105
|
+
[@pos, @event, @tok, @state]
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Pretty much just the same as Prism.lex_compat.
|
|
111
|
+
def lex(raise_errors: false)
|
|
112
|
+
Ripper.lex(@source, filename, lineno, raise_errors: raise_errors)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Returns the lex_compat result wrapped in `Elem`. Errors are omitted.
|
|
116
|
+
# Since ripper is a streaming parser, tokens are expected to be emitted in the order
|
|
117
|
+
# that the parser encounters them. This is not implemented.
|
|
118
|
+
def parse(...)
|
|
119
|
+
lex(...).map do |position, event, token, state|
|
|
120
|
+
Elem.new(position, event, token, state.to_int)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Similar to parse but ripper sorts the elements by position in the source. Also
|
|
125
|
+
# includes errors. Since prism does error recovery, in cases of syntax errors
|
|
126
|
+
# the result may differ greatly compared to ripper.
|
|
127
|
+
def scan(...)
|
|
128
|
+
parse(...)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|