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

Sign up to get free protection for your applications and to get access to all the features.
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