prism 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -1
- data/Makefile +1 -1
- data/config.yml +429 -2
- data/docs/build_system.md +8 -11
- data/docs/releasing.md +1 -1
- data/docs/relocation.md +34 -0
- data/docs/ruby_api.md +1 -1
- data/ext/prism/api_node.c +1824 -1305
- data/ext/prism/extconf.rb +13 -36
- data/ext/prism/extension.c +298 -109
- data/ext/prism/extension.h +4 -4
- data/include/prism/ast.h +442 -2
- data/include/prism/defines.h +26 -8
- data/include/prism/options.h +47 -1
- data/include/prism/util/pm_buffer.h +10 -0
- data/include/prism/version.h +2 -2
- data/include/prism.h +51 -4
- data/lib/prism/dot_visitor.rb +26 -0
- data/lib/prism/dsl.rb +14 -6
- data/lib/prism/ffi.rb +93 -28
- data/lib/prism/inspect_visitor.rb +4 -1
- data/lib/prism/node.rb +1886 -105
- data/lib/prism/parse_result/errors.rb +1 -1
- data/lib/prism/parse_result/newlines.rb +1 -1
- data/lib/prism/parse_result.rb +54 -2
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/reflection.rb +4 -4
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +1252 -765
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/builder.rb +61 -0
- data/lib/prism/translation/parser/compiler.rb +228 -162
- data/lib/prism/translation/parser/lexer.rb +435 -61
- data/lib/prism/translation/parser.rb +51 -3
- data/lib/prism/translation/parser35.rb +12 -0
- data/lib/prism/translation/ripper.rb +13 -3
- data/lib/prism/translation/ruby_parser.rb +17 -7
- data/lib/prism/translation.rb +1 -0
- data/lib/prism.rb +9 -7
- data/prism.gemspec +11 -1
- data/rbi/prism/dsl.rbi +10 -7
- data/rbi/prism/node.rbi +44 -17
- data/rbi/prism/parse_result.rbi +17 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism/translation/parser35.rbi +6 -0
- data/rbi/prism.rbi +39 -36
- data/sig/prism/dsl.rbs +6 -4
- data/sig/prism/node.rbs +29 -15
- data/sig/prism/parse_result.rbs +10 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/serialize.rbs +4 -2
- data/sig/prism/string_query.rbs +11 -0
- data/sig/prism.rbs +22 -1
- data/src/diagnostic.c +2 -2
- data/src/node.c +39 -0
- data/src/options.c +31 -0
- data/src/prettyprint.c +62 -0
- data/src/prism.c +738 -199
- data/src/regexp.c +7 -3
- data/src/serialize.c +18 -0
- data/src/static_literals.c +1 -1
- data/src/util/pm_buffer.c +40 -0
- data/src/util/pm_char.c +1 -1
- data/src/util/pm_constant_pool.c +6 -2
- data/src/util/pm_string.c +1 -0
- data/src/util/pm_strncasecmp.c +13 -1
- metadata +13 -7
data/include/prism/defines.h
CHANGED
@@ -23,6 +23,9 @@
|
|
23
23
|
* some platforms they aren't included unless this is already defined.
|
24
24
|
*/
|
25
25
|
#define __STDC_FORMAT_MACROS
|
26
|
+
// Include sys/types.h before inttypes.h to work around issue with
|
27
|
+
// certain versions of GCC and newlib which causes omission of PRIx64
|
28
|
+
#include <sys/types.h>
|
26
29
|
#include <inttypes.h>
|
27
30
|
|
28
31
|
/**
|
@@ -31,7 +34,7 @@
|
|
31
34
|
* specifying a maximum depth to which we are allowed to recurse.
|
32
35
|
*/
|
33
36
|
#ifndef PRISM_DEPTH_MAXIMUM
|
34
|
-
#define PRISM_DEPTH_MAXIMUM
|
37
|
+
#define PRISM_DEPTH_MAXIMUM 10000
|
35
38
|
#endif
|
36
39
|
|
37
40
|
/**
|
@@ -137,14 +140,15 @@
|
|
137
140
|
#endif
|
138
141
|
|
139
142
|
/**
|
140
|
-
* isinf on
|
141
|
-
*
|
142
|
-
*
|
143
|
+
* isinf on POSIX systems it accepts a float, a double, or a long double.
|
144
|
+
* But mingw didn't provide an isinf macro, only an isinf function that only
|
145
|
+
* accepts floats, so we need to use _finite instead.
|
143
146
|
*/
|
144
|
-
#ifdef
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
147
|
+
#ifdef __MINGW64__
|
148
|
+
#include <float.h>
|
149
|
+
#define PRISM_ISINF(x) (!_finite(x))
|
150
|
+
#else
|
151
|
+
#define PRISM_ISINF(x) isinf(x)
|
148
152
|
#endif
|
149
153
|
|
150
154
|
/**
|
@@ -239,4 +243,18 @@
|
|
239
243
|
#define PRISM_UNLIKELY(x) (x)
|
240
244
|
#endif
|
241
245
|
|
246
|
+
/**
|
247
|
+
* We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
|
248
|
+
* Use PRISM_FALLTHROUGH to explicitly annotate cases where the fallthrough is intentional.
|
249
|
+
*/
|
250
|
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L // C23 or later
|
251
|
+
#define PRISM_FALLTHROUGH [[fallthrough]];
|
252
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
253
|
+
#define PRISM_FALLTHROUGH __attribute__((fallthrough));
|
254
|
+
#elif defined(_MSC_VER)
|
255
|
+
#define PRISM_FALLTHROUGH __fallthrough;
|
256
|
+
#else
|
257
|
+
#define PRISM_FALLTHROUGH
|
258
|
+
#endif
|
259
|
+
|
242
260
|
#endif
|
data/include/prism/options.h
CHANGED
@@ -39,8 +39,26 @@ typedef struct pm_options_scope {
|
|
39
39
|
|
40
40
|
/** The names of the locals in the scope. */
|
41
41
|
pm_string_t *locals;
|
42
|
+
|
43
|
+
/** Flags for the set of forwarding parameters in this scope. */
|
44
|
+
uint8_t forwarding;
|
42
45
|
} pm_options_scope_t;
|
43
46
|
|
47
|
+
/** The default value for parameters. */
|
48
|
+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE = 0x0;
|
49
|
+
|
50
|
+
/** When the scope is fowarding with the * parameter. */
|
51
|
+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS = 0x1;
|
52
|
+
|
53
|
+
/** When the scope is fowarding with the ** parameter. */
|
54
|
+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS = 0x2;
|
55
|
+
|
56
|
+
/** When the scope is fowarding with the & parameter. */
|
57
|
+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK = 0x4;
|
58
|
+
|
59
|
+
/** When the scope is fowarding with the ... parameter. */
|
60
|
+
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL = 0x8;
|
61
|
+
|
44
62
|
// Forward declaration needed by the callback typedef.
|
45
63
|
struct pm_options;
|
46
64
|
|
@@ -68,7 +86,10 @@ typedef enum {
|
|
68
86
|
PM_OPTIONS_VERSION_LATEST = 0,
|
69
87
|
|
70
88
|
/** The vendored version of prism in CRuby 3.3.x. */
|
71
|
-
PM_OPTIONS_VERSION_CRUBY_3_3 = 1
|
89
|
+
PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
|
90
|
+
|
91
|
+
/** The vendored version of prism in CRuby 3.4.x. */
|
92
|
+
PM_OPTIONS_VERSION_CRUBY_3_4 = 2
|
72
93
|
} pm_options_version_t;
|
73
94
|
|
74
95
|
/**
|
@@ -157,6 +178,13 @@ typedef struct pm_options {
|
|
157
178
|
* inside another script.
|
158
179
|
*/
|
159
180
|
bool partial_script;
|
181
|
+
|
182
|
+
/**
|
183
|
+
* Whether or not the parser should freeze the nodes that it creates. This
|
184
|
+
* makes it possible to have a deeply frozen AST that is safe to share
|
185
|
+
* between concurrency primitives.
|
186
|
+
*/
|
187
|
+
bool freeze;
|
160
188
|
} pm_options_t;
|
161
189
|
|
162
190
|
/**
|
@@ -282,6 +310,14 @@ PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, b
|
|
282
310
|
*/
|
283
311
|
PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script);
|
284
312
|
|
313
|
+
/**
|
314
|
+
* Set the freeze option on the given options struct.
|
315
|
+
*
|
316
|
+
* @param options The options struct to set the freeze value on.
|
317
|
+
* @param freeze The freeze value to set.
|
318
|
+
*/
|
319
|
+
PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze);
|
320
|
+
|
285
321
|
/**
|
286
322
|
* Allocate and zero out the scopes array on the given options struct.
|
287
323
|
*
|
@@ -319,6 +355,14 @@ PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, si
|
|
319
355
|
*/
|
320
356
|
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index);
|
321
357
|
|
358
|
+
/**
|
359
|
+
* Set the forwarding option on the given scope struct.
|
360
|
+
*
|
361
|
+
* @param scope The scope struct to set the forwarding on.
|
362
|
+
* @param forwarding The forwarding value to set.
|
363
|
+
*/
|
364
|
+
PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding);
|
365
|
+
|
322
366
|
/**
|
323
367
|
* Free the internal memory associated with the options.
|
324
368
|
*
|
@@ -352,6 +396,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
|
|
352
396
|
* | `1` | encoding locked |
|
353
397
|
* | `1` | main script |
|
354
398
|
* | `1` | partial script |
|
399
|
+
* | `1` | freeze |
|
355
400
|
* | `4` | the number of scopes |
|
356
401
|
* | ... | the scopes |
|
357
402
|
*
|
@@ -367,6 +412,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
|
|
367
412
|
* | # bytes | field |
|
368
413
|
* | ------- | -------------------------- |
|
369
414
|
* | `4` | the number of locals |
|
415
|
+
* | `1` | the forwarding flags |
|
370
416
|
* | ... | the locals |
|
371
417
|
*
|
372
418
|
* Each local is laid out as follows:
|
@@ -137,6 +137,16 @@ void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
|
|
137
137
|
*/
|
138
138
|
void pm_buffer_append_double(pm_buffer_t *buffer, double value);
|
139
139
|
|
140
|
+
/**
|
141
|
+
* Append a unicode codepoint to the buffer.
|
142
|
+
*
|
143
|
+
* @param buffer The buffer to append to.
|
144
|
+
* @param value The character to append.
|
145
|
+
* @returns True if the codepoint was valid and appended successfully, false
|
146
|
+
* otherwise.
|
147
|
+
*/
|
148
|
+
bool pm_buffer_append_unicode_codepoint(pm_buffer_t *buffer, uint32_t value);
|
149
|
+
|
140
150
|
/**
|
141
151
|
* The different types of escaping that can be performed by the buffer when
|
142
152
|
* appending a slice of Ruby source code.
|
data/include/prism/version.h
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
/**
|
15
15
|
* The minor version of the Prism library as an int.
|
16
16
|
*/
|
17
|
-
#define PRISM_VERSION_MINOR
|
17
|
+
#define PRISM_VERSION_MINOR 4
|
18
18
|
|
19
19
|
/**
|
20
20
|
* The patch version of the Prism library as an int.
|
@@ -24,6 +24,6 @@
|
|
24
24
|
/**
|
25
25
|
* The version of the Prism library as a constant string.
|
26
26
|
*/
|
27
|
-
#define PRISM_VERSION "1.
|
27
|
+
#define PRISM_VERSION "1.4.0"
|
28
28
|
|
29
29
|
#endif
|
data/include/prism.h
CHANGED
@@ -93,11 +93,11 @@ typedef char * (pm_parse_stream_fgets_t)(char *string, int size, void *stream);
|
|
93
93
|
* @param parser The parser to use.
|
94
94
|
* @param buffer The buffer to use.
|
95
95
|
* @param stream The stream to parse.
|
96
|
-
* @param
|
96
|
+
* @param stream_fgets The function to use to read from the stream.
|
97
97
|
* @param options The optional options to use when parsing.
|
98
98
|
* @return The AST representing the source.
|
99
99
|
*/
|
100
|
-
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *
|
100
|
+
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const pm_options_t *options);
|
101
101
|
|
102
102
|
// We optionally support serializing to a binary string. For systems that don't
|
103
103
|
// want or need this functionality, it can be turned off with the
|
@@ -110,10 +110,10 @@ PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buff
|
|
110
110
|
*
|
111
111
|
* @param buffer The buffer to serialize to.
|
112
112
|
* @param stream The stream to parse.
|
113
|
-
* @param
|
113
|
+
* @param stream_fgets The function to use to read from the stream.
|
114
114
|
* @param data The optional data to pass to the parser.
|
115
115
|
*/
|
116
|
-
PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *
|
116
|
+
PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, const char *data);
|
117
117
|
|
118
118
|
/**
|
119
119
|
* Serialize the given list of comments to the given buffer.
|
@@ -234,6 +234,53 @@ PRISM_EXPORTED_FUNCTION void pm_dump_json(pm_buffer_t *buffer, const pm_parser_t
|
|
234
234
|
|
235
235
|
#endif
|
236
236
|
|
237
|
+
/**
|
238
|
+
* Represents the results of a slice query.
|
239
|
+
*/
|
240
|
+
typedef enum {
|
241
|
+
/** Returned if the encoding given to a slice query was invalid. */
|
242
|
+
PM_STRING_QUERY_ERROR = -1,
|
243
|
+
|
244
|
+
/** Returned if the result of the slice query is false. */
|
245
|
+
PM_STRING_QUERY_FALSE,
|
246
|
+
|
247
|
+
/** Returned if the result of the slice query is true. */
|
248
|
+
PM_STRING_QUERY_TRUE
|
249
|
+
} pm_string_query_t;
|
250
|
+
|
251
|
+
/**
|
252
|
+
* Check that the slice is a valid local variable name.
|
253
|
+
*
|
254
|
+
* @param source The source to check.
|
255
|
+
* @param length The length of the source.
|
256
|
+
* @param encoding_name The name of the encoding of the source.
|
257
|
+
* @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
|
258
|
+
* the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
|
259
|
+
*/
|
260
|
+
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name);
|
261
|
+
|
262
|
+
/**
|
263
|
+
* Check that the slice is a valid constant name.
|
264
|
+
*
|
265
|
+
* @param source The source to check.
|
266
|
+
* @param length The length of the source.
|
267
|
+
* @param encoding_name The name of the encoding of the source.
|
268
|
+
* @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
|
269
|
+
* the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
|
270
|
+
*/
|
271
|
+
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name);
|
272
|
+
|
273
|
+
/**
|
274
|
+
* Check that the slice is a valid method name.
|
275
|
+
*
|
276
|
+
* @param source The source to check.
|
277
|
+
* @param length The length of the source.
|
278
|
+
* @param encoding_name The name of the encoding of the source.
|
279
|
+
* @return PM_STRING_QUERY_TRUE if the query is true, PM_STRING_QUERY_FALSE if
|
280
|
+
* the query is false, and PM_STRING_QUERY_ERROR if the encoding was invalid.
|
281
|
+
*/
|
282
|
+
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name);
|
283
|
+
|
237
284
|
/**
|
238
285
|
* @mainpage
|
239
286
|
*
|
data/lib/prism/dot_visitor.rb
CHANGED
@@ -3608,6 +3608,9 @@ module Prism
|
|
3608
3608
|
table = Table.new("ParenthesesNode")
|
3609
3609
|
id = node_id(node)
|
3610
3610
|
|
3611
|
+
# flags
|
3612
|
+
table.field("flags", parentheses_node_flags_inspect(node))
|
3613
|
+
|
3611
3614
|
# body
|
3612
3615
|
unless (body = node.body).nil?
|
3613
3616
|
table.field("body", port: true)
|
@@ -3954,6 +3957,11 @@ module Prism
|
|
3954
3957
|
digraph.edge("#{id}:reference -> #{node_id(reference)};")
|
3955
3958
|
end
|
3956
3959
|
|
3960
|
+
# then_keyword_loc
|
3961
|
+
unless (then_keyword_loc = node.then_keyword_loc).nil?
|
3962
|
+
table.field("then_keyword_loc", location_inspect(then_keyword_loc))
|
3963
|
+
end
|
3964
|
+
|
3957
3965
|
# statements
|
3958
3966
|
unless (statements = node.statements).nil?
|
3959
3967
|
table.field("statements", port: true)
|
@@ -4414,6 +4422,11 @@ module Prism
|
|
4414
4422
|
# keyword_loc
|
4415
4423
|
table.field("keyword_loc", location_inspect(node.keyword_loc))
|
4416
4424
|
|
4425
|
+
# do_keyword_loc
|
4426
|
+
unless (do_keyword_loc = node.do_keyword_loc).nil?
|
4427
|
+
table.field("do_keyword_loc", location_inspect(do_keyword_loc))
|
4428
|
+
end
|
4429
|
+
|
4417
4430
|
# closing_loc
|
4418
4431
|
unless (closing_loc = node.closing_loc).nil?
|
4419
4432
|
table.field("closing_loc", location_inspect(closing_loc))
|
@@ -4490,6 +4503,11 @@ module Prism
|
|
4490
4503
|
# keyword_loc
|
4491
4504
|
table.field("keyword_loc", location_inspect(node.keyword_loc))
|
4492
4505
|
|
4506
|
+
# do_keyword_loc
|
4507
|
+
unless (do_keyword_loc = node.do_keyword_loc).nil?
|
4508
|
+
table.field("do_keyword_loc", location_inspect(do_keyword_loc))
|
4509
|
+
end
|
4510
|
+
|
4493
4511
|
# closing_loc
|
4494
4512
|
unless (closing_loc = node.closing_loc).nil?
|
4495
4513
|
table.field("closing_loc", location_inspect(closing_loc))
|
@@ -4672,6 +4690,14 @@ module Prism
|
|
4672
4690
|
flags.join(", ")
|
4673
4691
|
end
|
4674
4692
|
|
4693
|
+
# Inspect a node that has parentheses_node_flags flags to display the flags as a
|
4694
|
+
# comma-separated list.
|
4695
|
+
def parentheses_node_flags_inspect(node)
|
4696
|
+
flags = [] #: Array[String]
|
4697
|
+
flags << "multiple_statements" if node.multiple_statements?
|
4698
|
+
flags.join(", ")
|
4699
|
+
end
|
4700
|
+
|
4675
4701
|
# Inspect a node that has range_flags flags to display the flags as a
|
4676
4702
|
# comma-separated list.
|
4677
4703
|
def range_flags_inspect(node)
|
data/lib/prism/dsl.rb
CHANGED
@@ -714,8 +714,8 @@ module Prism
|
|
714
714
|
end
|
715
715
|
|
716
716
|
# Create a new RescueNode node.
|
717
|
-
def rescue_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, exceptions: [], operator_loc: nil, reference: nil, statements: nil, subsequent: nil)
|
718
|
-
RescueNode.new(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, statements, subsequent)
|
717
|
+
def rescue_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, exceptions: [], operator_loc: nil, reference: nil, then_keyword_loc: nil, statements: nil, subsequent: nil)
|
718
|
+
RescueNode.new(source, node_id, location, flags, keyword_loc, exceptions, operator_loc, reference, then_keyword_loc, statements, subsequent)
|
719
719
|
end
|
720
720
|
|
721
721
|
# Create a new RestParameterNode node.
|
@@ -804,8 +804,8 @@ module Prism
|
|
804
804
|
end
|
805
805
|
|
806
806
|
# Create a new UntilNode node.
|
807
|
-
def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil)
|
808
|
-
UntilNode.new(source, node_id, location, flags, keyword_loc, closing_loc, predicate, statements)
|
807
|
+
def until_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil)
|
808
|
+
UntilNode.new(source, node_id, location, flags, keyword_loc, do_keyword_loc, closing_loc, predicate, statements)
|
809
809
|
end
|
810
810
|
|
811
811
|
# Create a new WhenNode node.
|
@@ -814,8 +814,8 @@ module Prism
|
|
814
814
|
end
|
815
815
|
|
816
816
|
# Create a new WhileNode node.
|
817
|
-
def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, closing_loc: nil, predicate: default_node(source, location), statements: nil)
|
818
|
-
WhileNode.new(source, node_id, location, flags, keyword_loc, closing_loc, predicate, statements)
|
817
|
+
def while_node(source: default_source, node_id: 0, location: default_location, flags: 0, keyword_loc: location, do_keyword_loc: nil, closing_loc: nil, predicate: default_node(source, location), statements: nil)
|
818
|
+
WhileNode.new(source, node_id, location, flags, keyword_loc, do_keyword_loc, closing_loc, predicate, statements)
|
819
819
|
end
|
820
820
|
|
821
821
|
# Create a new XStringNode node.
|
@@ -912,6 +912,14 @@ module Prism
|
|
912
912
|
end
|
913
913
|
end
|
914
914
|
|
915
|
+
# Retrieve the value of one of the ParenthesesNodeFlags flags.
|
916
|
+
def parentheses_node_flag(name)
|
917
|
+
case name
|
918
|
+
when :multiple_statements then ParenthesesNodeFlags::MULTIPLE_STATEMENTS
|
919
|
+
else Kernel.raise ArgumentError, "invalid ParenthesesNodeFlags flag: #{name.inspect}"
|
920
|
+
end
|
921
|
+
end
|
922
|
+
|
915
923
|
# Retrieve the value of one of the RangeFlags flags.
|
916
924
|
def range_flag(name)
|
917
925
|
case name
|
data/lib/prism/ffi.rb
CHANGED
@@ -13,7 +13,16 @@ module Prism
|
|
13
13
|
|
14
14
|
# Define the library that we will be pulling functions from. Note that this
|
15
15
|
# must align with the build shared library from make/rake.
|
16
|
-
|
16
|
+
libprism_in_build = File.expand_path("../../build/libprism.#{RbConfig::CONFIG["SOEXT"]}", __dir__)
|
17
|
+
libprism_in_libdir = "#{RbConfig::CONFIG["libdir"]}/prism/libprism.#{RbConfig::CONFIG["SOEXT"]}"
|
18
|
+
|
19
|
+
if File.exist?(libprism_in_build)
|
20
|
+
INCLUDE_DIR = File.expand_path("../../include", __dir__)
|
21
|
+
ffi_lib libprism_in_build
|
22
|
+
else
|
23
|
+
INCLUDE_DIR = "#{RbConfig::CONFIG["libdir"]}/prism/include"
|
24
|
+
ffi_lib libprism_in_libdir
|
25
|
+
end
|
17
26
|
|
18
27
|
# Convert a native C type declaration into a symbol that FFI understands.
|
19
28
|
# For example:
|
@@ -38,7 +47,7 @@ module Prism
|
|
38
47
|
# given functions. For each one, define a function with the same name and
|
39
48
|
# signature as the C function.
|
40
49
|
def self.load_exported_functions_from(header, *functions, callbacks)
|
41
|
-
File.foreach(
|
50
|
+
File.foreach("#{INCLUDE_DIR}/#{header}") do |line|
|
42
51
|
# We only want to attempt to load exported functions.
|
43
52
|
next unless line.start_with?("PRISM_EXPORTED_FUNCTION ")
|
44
53
|
|
@@ -73,6 +82,7 @@ module Prism
|
|
73
82
|
|
74
83
|
callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
75
84
|
enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
|
85
|
+
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
76
86
|
|
77
87
|
load_exported_functions_from(
|
78
88
|
"prism.h",
|
@@ -83,6 +93,9 @@ module Prism
|
|
83
93
|
"pm_serialize_lex",
|
84
94
|
"pm_serialize_parse_lex",
|
85
95
|
"pm_parse_success_p",
|
96
|
+
"pm_string_query_local",
|
97
|
+
"pm_string_query_constant",
|
98
|
+
"pm_string_query_method_name",
|
86
99
|
[:pm_parse_stream_fgets_t]
|
87
100
|
)
|
88
101
|
|
@@ -267,7 +280,7 @@ module Prism
|
|
267
280
|
# access to the IO object already through the closure of the lambda, we
|
268
281
|
# can pass a null pointer here and not worry.
|
269
282
|
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
|
270
|
-
Prism.load(source, buffer.read)
|
283
|
+
Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
271
284
|
end
|
272
285
|
end
|
273
286
|
|
@@ -342,50 +355,37 @@ module Prism
|
|
342
355
|
def dump_common(string, options) # :nodoc:
|
343
356
|
LibRubyParser::PrismBuffer.with do |buffer|
|
344
357
|
LibRubyParser.pm_serialize_parse(buffer.pointer, string.pointer, string.length, dump_options(options))
|
345
|
-
|
358
|
+
|
359
|
+
dumped = buffer.read
|
360
|
+
dumped.freeze if options.fetch(:freeze, false)
|
361
|
+
|
362
|
+
dumped
|
346
363
|
end
|
347
364
|
end
|
348
365
|
|
349
366
|
def lex_common(string, code, options) # :nodoc:
|
350
|
-
|
367
|
+
LibRubyParser::PrismBuffer.with do |buffer|
|
351
368
|
LibRubyParser.pm_serialize_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
352
|
-
buffer.read
|
369
|
+
Serialize.load_lex(code, buffer.read, options.fetch(:freeze, false))
|
353
370
|
end
|
354
|
-
|
355
|
-
Serialize.load_tokens(Source.for(code), serialized)
|
356
371
|
end
|
357
372
|
|
358
373
|
def parse_common(string, code, options) # :nodoc:
|
359
374
|
serialized = dump_common(string, options)
|
360
|
-
|
375
|
+
Serialize.load_parse(code, serialized, options.fetch(:freeze, false))
|
361
376
|
end
|
362
377
|
|
363
378
|
def parse_comments_common(string, code, options) # :nodoc:
|
364
379
|
LibRubyParser::PrismBuffer.with do |buffer|
|
365
380
|
LibRubyParser.pm_serialize_parse_comments(buffer.pointer, string.pointer, string.length, dump_options(options))
|
366
|
-
|
367
|
-
source = Source.for(code)
|
368
|
-
loader = Serialize::Loader.new(source, buffer.read)
|
369
|
-
|
370
|
-
loader.load_header
|
371
|
-
loader.load_encoding
|
372
|
-
loader.load_start_line
|
373
|
-
loader.load_comments
|
381
|
+
Serialize.load_parse_comments(code, buffer.read, options.fetch(:freeze, false))
|
374
382
|
end
|
375
383
|
end
|
376
384
|
|
377
385
|
def parse_lex_common(string, code, options) # :nodoc:
|
378
386
|
LibRubyParser::PrismBuffer.with do |buffer|
|
379
387
|
LibRubyParser.pm_serialize_parse_lex(buffer.pointer, string.pointer, string.length, dump_options(options))
|
380
|
-
|
381
|
-
source = Source.for(code)
|
382
|
-
loader = Serialize::Loader.new(source, buffer.read)
|
383
|
-
|
384
|
-
tokens = loader.load_tokens
|
385
|
-
node, comments, magic_comments, data_loc, errors, warnings = loader.load_nodes
|
386
|
-
tokens.each { |token,| token.value.force_encoding(loader.encoding) }
|
387
|
-
|
388
|
-
ParseLexResult.new([node, tokens], comments, magic_comments, data_loc, errors, warnings, source)
|
388
|
+
Serialize.load_parse_lex(code, buffer.read, options.fetch(:freeze, false))
|
389
389
|
end
|
390
390
|
end
|
391
391
|
|
@@ -419,6 +419,8 @@ module Prism
|
|
419
419
|
when /\A3\.3(\.\d+)?\z/
|
420
420
|
1
|
421
421
|
when /\A3\.4(\.\d+)?\z/
|
422
|
+
2
|
423
|
+
when /\A3\.5(\.\d+)?\z/
|
422
424
|
0
|
423
425
|
else
|
424
426
|
raise ArgumentError, "invalid version: #{version}"
|
@@ -468,15 +470,43 @@ module Prism
|
|
468
470
|
template << "C"
|
469
471
|
values << (options.fetch(:partial_script, false) ? 1 : 0)
|
470
472
|
|
473
|
+
template << "C"
|
474
|
+
values << (options.fetch(:freeze, false) ? 1 : 0)
|
475
|
+
|
471
476
|
template << "L"
|
472
477
|
if (scopes = options[:scopes])
|
473
478
|
values << scopes.length
|
474
479
|
|
475
480
|
scopes.each do |scope|
|
481
|
+
locals = nil
|
482
|
+
forwarding = 0
|
483
|
+
|
484
|
+
case scope
|
485
|
+
when Array
|
486
|
+
locals = scope
|
487
|
+
when Scope
|
488
|
+
locals = scope.locals
|
489
|
+
|
490
|
+
scope.forwarding.each do |forward|
|
491
|
+
case forward
|
492
|
+
when :* then forwarding |= 0x1
|
493
|
+
when :** then forwarding |= 0x2
|
494
|
+
when :& then forwarding |= 0x4
|
495
|
+
when :"..." then forwarding |= 0x8
|
496
|
+
else raise ArgumentError, "invalid forwarding value: #{forward}"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
else
|
500
|
+
raise TypeError, "wrong argument type #{scope.class.inspect} (expected Array or Prism::Scope)"
|
501
|
+
end
|
502
|
+
|
476
503
|
template << "L"
|
477
|
-
values <<
|
504
|
+
values << locals.length
|
505
|
+
|
506
|
+
template << "C"
|
507
|
+
values << forwarding
|
478
508
|
|
479
|
-
|
509
|
+
locals.each do |local|
|
480
510
|
name = local.name
|
481
511
|
template << "L"
|
482
512
|
values << name.bytesize
|
@@ -492,4 +522,39 @@ module Prism
|
|
492
522
|
values.pack(template)
|
493
523
|
end
|
494
524
|
end
|
525
|
+
|
526
|
+
# Here we are going to patch StringQuery to put in the class-level methods so
|
527
|
+
# that it can maintain a consistent interface
|
528
|
+
class StringQuery
|
529
|
+
class << self
|
530
|
+
# Mirrors the C extension's StringQuery::local? method.
|
531
|
+
def local?(string)
|
532
|
+
query(LibRubyParser.pm_string_query_local(string, string.bytesize, string.encoding.name))
|
533
|
+
end
|
534
|
+
|
535
|
+
# Mirrors the C extension's StringQuery::constant? method.
|
536
|
+
def constant?(string)
|
537
|
+
query(LibRubyParser.pm_string_query_constant(string, string.bytesize, string.encoding.name))
|
538
|
+
end
|
539
|
+
|
540
|
+
# Mirrors the C extension's StringQuery::method_name? method.
|
541
|
+
def method_name?(string)
|
542
|
+
query(LibRubyParser.pm_string_query_method_name(string, string.bytesize, string.encoding.name))
|
543
|
+
end
|
544
|
+
|
545
|
+
private
|
546
|
+
|
547
|
+
# Parse the enum result and return an appropriate boolean.
|
548
|
+
def query(result)
|
549
|
+
case result
|
550
|
+
when :PM_STRING_QUERY_ERROR
|
551
|
+
raise ArgumentError, "Invalid or non ascii-compatible encoding"
|
552
|
+
when :PM_STRING_QUERY_FALSE
|
553
|
+
false
|
554
|
+
when :PM_STRING_QUERY_TRUE
|
555
|
+
true
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
495
560
|
end
|
@@ -1879,7 +1879,7 @@ module Prism
|
|
1879
1879
|
# Inspect a ParenthesesNode node.
|
1880
1880
|
def visit_parentheses_node(node)
|
1881
1881
|
commands << [inspect_node("ParenthesesNode", node), indent]
|
1882
|
-
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ].compact
|
1882
|
+
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("multiple_statements" if node.multiple_statements?)].compact
|
1883
1883
|
commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
|
1884
1884
|
if (body = node.body).nil?
|
1885
1885
|
commands << ["├── body: ∅\n", indent]
|
@@ -2053,6 +2053,7 @@ module Prism
|
|
2053
2053
|
commands << ["├── reference:\n", indent]
|
2054
2054
|
commands << [reference, "#{indent}│ "]
|
2055
2055
|
end
|
2056
|
+
commands << ["├── then_keyword_loc: #{inspect_location(node.then_keyword_loc)}\n", indent]
|
2056
2057
|
if (statements = node.statements).nil?
|
2057
2058
|
commands << ["├── statements: ∅\n", indent]
|
2058
2059
|
else
|
@@ -2287,6 +2288,7 @@ module Prism
|
|
2287
2288
|
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("begin_modifier" if node.begin_modifier?)].compact
|
2288
2289
|
commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
|
2289
2290
|
commands << ["├── keyword_loc: #{inspect_location(node.keyword_loc)}\n", indent]
|
2291
|
+
commands << ["├── do_keyword_loc: #{inspect_location(node.do_keyword_loc)}\n", indent]
|
2290
2292
|
commands << ["├── closing_loc: #{inspect_location(node.closing_loc)}\n", indent]
|
2291
2293
|
commands << ["├── predicate:\n", indent]
|
2292
2294
|
commands << [node.predicate, "#{indent}│ "]
|
@@ -2328,6 +2330,7 @@ module Prism
|
|
2328
2330
|
flags = [("newline" if node.newline?), ("static_literal" if node.static_literal?), ("begin_modifier" if node.begin_modifier?)].compact
|
2329
2331
|
commands << ["├── flags: #{flags.empty? ? "∅" : flags.join(", ")}\n", indent]
|
2330
2332
|
commands << ["├── keyword_loc: #{inspect_location(node.keyword_loc)}\n", indent]
|
2333
|
+
commands << ["├── do_keyword_loc: #{inspect_location(node.do_keyword_loc)}\n", indent]
|
2331
2334
|
commands << ["├── closing_loc: #{inspect_location(node.closing_loc)}\n", indent]
|
2332
2335
|
commands << ["├── predicate:\n", indent]
|
2333
2336
|
commands << [node.predicate, "#{indent}│ "]
|