jruby-prism-parser 0.23.0.pre.SNAPSHOT-java

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.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +401 -0
  3. data/CODE_OF_CONDUCT.md +76 -0
  4. data/CONTRIBUTING.md +62 -0
  5. data/LICENSE.md +7 -0
  6. data/Makefile +101 -0
  7. data/README.md +98 -0
  8. data/config.yml +2902 -0
  9. data/docs/build_system.md +91 -0
  10. data/docs/configuration.md +64 -0
  11. data/docs/cruby_compilation.md +27 -0
  12. data/docs/design.md +53 -0
  13. data/docs/encoding.md +121 -0
  14. data/docs/fuzzing.md +88 -0
  15. data/docs/heredocs.md +36 -0
  16. data/docs/javascript.md +118 -0
  17. data/docs/local_variable_depth.md +229 -0
  18. data/docs/mapping.md +117 -0
  19. data/docs/parser_translation.md +34 -0
  20. data/docs/parsing_rules.md +19 -0
  21. data/docs/releasing.md +98 -0
  22. data/docs/ripper.md +36 -0
  23. data/docs/ruby_api.md +43 -0
  24. data/docs/ruby_parser_translation.md +19 -0
  25. data/docs/serialization.md +209 -0
  26. data/docs/testing.md +55 -0
  27. data/ext/prism/api_node.c +5098 -0
  28. data/ext/prism/api_pack.c +267 -0
  29. data/ext/prism/extconf.rb +110 -0
  30. data/ext/prism/extension.c +1155 -0
  31. data/ext/prism/extension.h +18 -0
  32. data/include/prism/ast.h +5807 -0
  33. data/include/prism/defines.h +102 -0
  34. data/include/prism/diagnostic.h +339 -0
  35. data/include/prism/encoding.h +265 -0
  36. data/include/prism/node.h +57 -0
  37. data/include/prism/options.h +230 -0
  38. data/include/prism/pack.h +152 -0
  39. data/include/prism/parser.h +732 -0
  40. data/include/prism/prettyprint.h +26 -0
  41. data/include/prism/regexp.h +33 -0
  42. data/include/prism/util/pm_buffer.h +155 -0
  43. data/include/prism/util/pm_char.h +205 -0
  44. data/include/prism/util/pm_constant_pool.h +209 -0
  45. data/include/prism/util/pm_list.h +97 -0
  46. data/include/prism/util/pm_memchr.h +29 -0
  47. data/include/prism/util/pm_newline_list.h +93 -0
  48. data/include/prism/util/pm_state_stack.h +42 -0
  49. data/include/prism/util/pm_string.h +150 -0
  50. data/include/prism/util/pm_string_list.h +44 -0
  51. data/include/prism/util/pm_strncasecmp.h +32 -0
  52. data/include/prism/util/pm_strpbrk.h +46 -0
  53. data/include/prism/version.h +29 -0
  54. data/include/prism.h +289 -0
  55. data/jruby-prism.jar +0 -0
  56. data/lib/prism/compiler.rb +486 -0
  57. data/lib/prism/debug.rb +206 -0
  58. data/lib/prism/desugar_compiler.rb +207 -0
  59. data/lib/prism/dispatcher.rb +2150 -0
  60. data/lib/prism/dot_visitor.rb +4634 -0
  61. data/lib/prism/dsl.rb +785 -0
  62. data/lib/prism/ffi.rb +346 -0
  63. data/lib/prism/lex_compat.rb +908 -0
  64. data/lib/prism/mutation_compiler.rb +753 -0
  65. data/lib/prism/node.rb +17864 -0
  66. data/lib/prism/node_ext.rb +212 -0
  67. data/lib/prism/node_inspector.rb +68 -0
  68. data/lib/prism/pack.rb +224 -0
  69. data/lib/prism/parse_result/comments.rb +177 -0
  70. data/lib/prism/parse_result/newlines.rb +64 -0
  71. data/lib/prism/parse_result.rb +498 -0
  72. data/lib/prism/pattern.rb +250 -0
  73. data/lib/prism/serialize.rb +1354 -0
  74. data/lib/prism/translation/parser/compiler.rb +1838 -0
  75. data/lib/prism/translation/parser/lexer.rb +335 -0
  76. data/lib/prism/translation/parser/rubocop.rb +37 -0
  77. data/lib/prism/translation/parser.rb +178 -0
  78. data/lib/prism/translation/ripper.rb +577 -0
  79. data/lib/prism/translation/ruby_parser.rb +1521 -0
  80. data/lib/prism/translation.rb +11 -0
  81. data/lib/prism/version.rb +3 -0
  82. data/lib/prism/visitor.rb +495 -0
  83. data/lib/prism.rb +99 -0
  84. data/prism.gemspec +135 -0
  85. data/rbi/prism.rbi +7767 -0
  86. data/rbi/prism_static.rbi +207 -0
  87. data/sig/prism.rbs +4773 -0
  88. data/sig/prism_static.rbs +201 -0
  89. data/src/diagnostic.c +400 -0
  90. data/src/encoding.c +5132 -0
  91. data/src/node.c +2786 -0
  92. data/src/options.c +213 -0
  93. data/src/pack.c +493 -0
  94. data/src/prettyprint.c +8881 -0
  95. data/src/prism.c +18406 -0
  96. data/src/regexp.c +638 -0
  97. data/src/serialize.c +1554 -0
  98. data/src/token_type.c +700 -0
  99. data/src/util/pm_buffer.c +190 -0
  100. data/src/util/pm_char.c +318 -0
  101. data/src/util/pm_constant_pool.c +322 -0
  102. data/src/util/pm_list.c +49 -0
  103. data/src/util/pm_memchr.c +35 -0
  104. data/src/util/pm_newline_list.c +84 -0
  105. data/src/util/pm_state_stack.c +25 -0
  106. data/src/util/pm_string.c +203 -0
  107. data/src/util/pm_string_list.c +28 -0
  108. data/src/util/pm_strncasecmp.c +24 -0
  109. data/src/util/pm_strpbrk.c +180 -0
  110. metadata +156 -0
data/lib/prism/ffi.rb ADDED
@@ -0,0 +1,346 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is responsible for mirroring the API provided by the C extension by
4
+ # using FFI to call into the shared library.
5
+
6
+ require "rbconfig"
7
+ require "ffi"
8
+
9
+ module Prism
10
+ BACKEND = :FFI
11
+
12
+ module LibRubyParser # :nodoc:
13
+ extend FFI::Library
14
+
15
+ # Define the library that we will be pulling functions from. Note that this
16
+ # must align with the build shared library from make/rake.
17
+ ffi_lib File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
18
+
19
+ # Convert a native C type declaration into a symbol that FFI understands.
20
+ # For example:
21
+ #
22
+ # const char * -> :pointer
23
+ # bool -> :bool
24
+ # size_t -> :size_t
25
+ # void -> :void
26
+ #
27
+ def self.resolve_type(type)
28
+ type = type.strip
29
+ type.end_with?("*") ? :pointer : type.delete_prefix("const ").to_sym
30
+ end
31
+
32
+ # Read through the given header file and find the declaration of each of the
33
+ # given functions. For each one, define a function with the same name and
34
+ # signature as the C function.
35
+ def self.load_exported_functions_from(header, *functions)
36
+ File.foreach(File.expand_path("../../include/#{header}", __dir__)) do |line|
37
+ # We only want to attempt to load exported functions.
38
+ next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
39
+
40
+ # We only want to load the functions that we are interested in.
41
+ next unless functions.any? { |function| line.include?(function) }
42
+
43
+ # Parse the function declaration.
44
+ unless /^PRISM_EXPORTED_FUNCTION (?<return_type>.+) (?<name>\w+)\((?<arg_types>.+)\);$/ =~ line
45
+ raise "Could not parse #{line}"
46
+ end
47
+
48
+ # Delete the function from the list of functions we are looking for to
49
+ # mark it as having been found.
50
+ functions.delete(name)
51
+
52
+ # Split up the argument types into an array, ensure we handle the case
53
+ # where there are no arguments (by explicit void).
54
+ arg_types = arg_types.split(",").map(&:strip)
55
+ arg_types = [] if arg_types == %w[void]
56
+
57
+ # Resolve the type of the argument by dropping the name of the argument
58
+ # first if it is present.
59
+ arg_types.map! { |type| resolve_type(type.sub(/\w+$/, "")) }
60
+
61
+ # Attach the function using the FFI library.
62
+ attach_function name, arg_types, resolve_type(return_type)
63
+ end
64
+
65
+ # If we didn't find all of the functions, raise an error.
66
+ raise "Could not find functions #{functions.inspect}" unless functions.empty?
67
+ end
68
+
69
+ load_exported_functions_from(
70
+ "prism.h",
71
+ "pm_version",
72
+ "pm_serialize_parse",
73
+ "pm_serialize_parse_comments",
74
+ "pm_serialize_lex",
75
+ "pm_serialize_parse_lex",
76
+ "pm_parse_success_p"
77
+ )
78
+
79
+ load_exported_functions_from(
80
+ "prism/util/pm_buffer.h",
81
+ "pm_buffer_sizeof",
82
+ "pm_buffer_init",
83
+ "pm_buffer_value",
84
+ "pm_buffer_length",
85
+ "pm_buffer_free"
86
+ )
87
+
88
+ load_exported_functions_from(
89
+ "prism/util/pm_string.h",
90
+ "pm_string_mapped_init",
91
+ "pm_string_free",
92
+ "pm_string_source",
93
+ "pm_string_length",
94
+ "pm_string_sizeof"
95
+ )
96
+
97
+ # This object represents a pm_buffer_t. We only use it as an opaque pointer,
98
+ # so it doesn't need to know the fields of pm_buffer_t.
99
+ class PrismBuffer # :nodoc:
100
+ SIZEOF = LibRubyParser.pm_buffer_sizeof
101
+
102
+ attr_reader :pointer
103
+
104
+ def initialize(pointer)
105
+ @pointer = pointer
106
+ end
107
+
108
+ def value
109
+ LibRubyParser.pm_buffer_value(pointer)
110
+ end
111
+
112
+ def length
113
+ LibRubyParser.pm_buffer_length(pointer)
114
+ end
115
+
116
+ def read
117
+ value.read_string(length)
118
+ end
119
+
120
+ # Initialize a new buffer and yield it to the block. The buffer will be
121
+ # automatically freed when the block returns.
122
+ def self.with(&block)
123
+ pointer = FFI::MemoryPointer.new(SIZEOF)
124
+
125
+ begin
126
+ raise unless LibRubyParser.pm_buffer_init(pointer)
127
+ yield new(pointer)
128
+ ensure
129
+ LibRubyParser.pm_buffer_free(pointer)
130
+ pointer.free
131
+ end
132
+ end
133
+ end
134
+
135
+ # This object represents a pm_string_t. We only use it as an opaque pointer,
136
+ # so it doesn't have to be an FFI::Struct.
137
+ class PrismString # :nodoc:
138
+ SIZEOF = LibRubyParser.pm_string_sizeof
139
+
140
+ attr_reader :pointer
141
+
142
+ def initialize(pointer)
143
+ @pointer = pointer
144
+ end
145
+
146
+ def source
147
+ LibRubyParser.pm_string_source(pointer)
148
+ end
149
+
150
+ def length
151
+ LibRubyParser.pm_string_length(pointer)
152
+ end
153
+
154
+ def read
155
+ source.read_string(length)
156
+ end
157
+
158
+ # Yields a pm_string_t pointer to the given block.
159
+ def self.with(filepath, &block)
160
+ pointer = FFI::MemoryPointer.new(SIZEOF)
161
+
162
+ begin
163
+ raise TypeError unless filepath.is_a?(String)
164
+
165
+ if LibRubyParser.pm_string_mapped_init(pointer, filepath)
166
+ yield new(pointer)
167
+ else
168
+ raise SystemCallError.new(filepath, FFI.errno)
169
+ end
170
+ ensure
171
+ LibRubyParser.pm_string_free(pointer)
172
+ pointer.free
173
+ end
174
+ end
175
+ end
176
+ end
177
+
178
+ # Mark the LibRubyParser module as private as it should only be called through
179
+ # the prism module.
180
+ private_constant :LibRubyParser
181
+
182
+ # The version constant is set by reading the result of calling pm_version.
183
+ VERSION = LibRubyParser.pm_version.read_string
184
+
185
+ class << self
186
+ # Mirror the Prism.dump API by using the serialization API.
187
+ def dump(code, **options)
188
+ LibRubyParser::PrismBuffer.with do |buffer|
189
+ LibRubyParser.pm_serialize_parse(buffer.pointer, code, code.bytesize, dump_options(options))
190
+ buffer.read
191
+ end
192
+ end
193
+
194
+ # Mirror the Prism.dump_file API by using the serialization API.
195
+ def dump_file(filepath, **options)
196
+ LibRubyParser::PrismString.with(filepath) do |string|
197
+ dump(string.read, **options, filepath: filepath)
198
+ end
199
+ end
200
+
201
+ # Mirror the Prism.lex API by using the serialization API.
202
+ def lex(code, **options)
203
+ LibRubyParser::PrismBuffer.with do |buffer|
204
+ LibRubyParser.pm_serialize_lex(buffer.pointer, code, code.bytesize, dump_options(options))
205
+ Serialize.load_tokens(Source.new(code), buffer.read)
206
+ end
207
+ end
208
+
209
+ # Mirror the Prism.lex_file API by using the serialization API.
210
+ def lex_file(filepath, **options)
211
+ LibRubyParser::PrismString.with(filepath) do |string|
212
+ lex(string.read, **options, filepath: filepath)
213
+ end
214
+ end
215
+
216
+ # Mirror the Prism.parse API by using the serialization API.
217
+ def parse(code, **options)
218
+ Prism.load(code, dump(code, **options))
219
+ end
220
+
221
+ # Mirror the Prism.parse_file API by using the serialization API. This uses
222
+ # native strings instead of Ruby strings because it allows us to use mmap when
223
+ # it is available.
224
+ def parse_file(filepath, **options)
225
+ LibRubyParser::PrismString.with(filepath) do |string|
226
+ parse(string.read, **options, filepath: filepath)
227
+ end
228
+ end
229
+
230
+ # Mirror the Prism.parse_comments API by using the serialization API.
231
+ def parse_comments(code, **options)
232
+ LibRubyParser::PrismBuffer.with do |buffer|
233
+ LibRubyParser.pm_serialize_parse_comments(buffer.pointer, code, code.bytesize, dump_options(options))
234
+
235
+ source = Source.new(code)
236
+ loader = Serialize::Loader.new(source, buffer.read)
237
+
238
+ loader.load_header
239
+ loader.load_encoding
240
+ loader.load_start_line
241
+ loader.load_comments
242
+ end
243
+ end
244
+
245
+ # Mirror the Prism.parse_file_comments API by using the serialization
246
+ # API. This uses native strings instead of Ruby strings because it allows us
247
+ # to use mmap when it is available.
248
+ def parse_file_comments(filepath, **options)
249
+ LibRubyParser::PrismString.with(filepath) do |string|
250
+ parse_comments(string.read, **options, filepath: filepath)
251
+ end
252
+ end
253
+
254
+ # Mirror the Prism.parse_lex API by using the serialization API.
255
+ def parse_lex(code, **options)
256
+ LibRubyParser::PrismBuffer.with do |buffer|
257
+ LibRubyParser.pm_serialize_parse_lex(buffer.pointer, code, code.bytesize, dump_options(options))
258
+
259
+ source = Source.new(code)
260
+ loader = Serialize::Loader.new(source, buffer.read)
261
+
262
+ tokens = loader.load_tokens
263
+ node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
264
+ tokens.each { |token,| token.value.force_encoding(loader.encoding) }
265
+
266
+ ParseResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
267
+ end
268
+ end
269
+
270
+ # Mirror the Prism.parse_lex_file API by using the serialization API.
271
+ def parse_lex_file(filepath, **options)
272
+ LibRubyParser::PrismString.with(filepath) do |string|
273
+ parse_lex(string.read, **options, filepath: filepath)
274
+ end
275
+ end
276
+
277
+ # Mirror the Prism.parse_success? API by using the serialization API.
278
+ def parse_success?(code, **options)
279
+ LibRubyParser.pm_parse_success_p(code, code.bytesize, dump_options(options))
280
+ end
281
+
282
+ # Mirror the Prism.parse_file_success? API by using the serialization API.
283
+ def parse_file_success?(filepath, **options)
284
+ LibRubyParser::PrismString.with(filepath) do |string|
285
+ parse_success?(string.read, **options, filepath: filepath)
286
+ end
287
+ end
288
+
289
+ private
290
+
291
+ # Convert the given options into a serialized options string.
292
+ def dump_options(options)
293
+ template = +""
294
+ values = []
295
+
296
+ template << "L"
297
+ if (filepath = options[:filepath])
298
+ values.push(filepath.bytesize, filepath.b)
299
+ template << "A*"
300
+ else
301
+ values << 0
302
+ end
303
+
304
+ template << "l"
305
+ values << options.fetch(:line, 1)
306
+
307
+ template << "L"
308
+ if (encoding = options[:encoding])
309
+ name = encoding.name
310
+ values.push(name.bytesize, name.b)
311
+ template << "A*"
312
+ else
313
+ values << 0
314
+ end
315
+
316
+ template << "C"
317
+ values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
318
+
319
+ template << "C"
320
+ values << { nil => 0, "3.3.0" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
321
+
322
+ template << "L"
323
+ if (scopes = options[:scopes])
324
+ values << scopes.length
325
+
326
+ scopes.each do |scope|
327
+ template << "L"
328
+ values << scope.length
329
+
330
+ scope.each do |local|
331
+ name = local.name
332
+ template << "L"
333
+ values << name.bytesize
334
+
335
+ template << "A*"
336
+ values << name.b
337
+ end
338
+ end
339
+ else
340
+ values << 0
341
+ end
342
+
343
+ values.pack(template)
344
+ end
345
+ end
346
+ end