prism 2.0.0.rc2-x86_64-linux-gnu → 2.1.0-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 +4 -4
- data/CHANGELOG.md +57 -41
- data/Makefile +8 -8
- data/README.md +3 -1
- data/docs/fuzzing.md +5 -5
- data/docs/serialization.md +19 -6
- data/ext/prism/api_node.c +80 -80
- data/ext/prism/extension.c +34 -67
- data/ext/prism/extension.h +1 -1
- data/include/prism/arena.h +8 -0
- data/include/prism/arena.hpp +42 -0
- data/include/prism/ast.h +11 -1
- data/include/prism/ast.hpp +641 -0
- data/include/prism/buffer.h +8 -0
- data/include/prism/buffer.hpp +55 -0
- data/include/prism/comments.h +17 -0
- data/include/prism/compiler/branch.h +26 -0
- data/include/prism/compiler/cplusplus.hpp +16 -0
- data/include/prism/compiler/exceptions.hpp +17 -0
- data/include/prism/compiler/format.h +2 -0
- data/include/prism/compiler/lifetimebound.hpp +25 -0
- data/include/prism/constant_pool.h +25 -0
- data/include/prism/diagnostic.h +18 -0
- data/include/prism/errors_format.h +8 -0
- data/include/prism/internal/comments.h +2 -1
- data/include/prism/internal/node.h +8 -4
- data/include/prism/internal/parser.h +26 -15
- data/include/prism/internal/static_literals.h +24 -64
- data/include/prism/internal/stringy.h +1 -6
- data/include/prism/json.h +8 -0
- data/include/prism/line_offset_list.h +8 -0
- data/include/prism/magic_comments.h +18 -0
- data/include/prism/node.h +55 -10
- data/include/prism/node.hpp +272 -0
- data/include/prism/node_type.hpp +38 -0
- data/include/prism/options.h +10 -1
- data/include/prism/options.hpp +43 -0
- data/include/prism/parser.h +72 -64
- data/include/prism/parser.hpp +274 -0
- data/include/prism/prettyprint.h +8 -0
- data/include/prism/serialize.h +8 -0
- data/include/prism/source.h +8 -0
- data/include/prism/stream.h +8 -0
- data/include/prism/string_query.h +8 -0
- data/include/prism/stringy.h +16 -27
- data/include/prism/stringy.hpp +31 -0
- data/include/prism/version.h +10 -2
- data/include/prism.h +0 -8
- data/include/prism.hpp +24 -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/serialize.rb +2550 -3282
- data/prism.gemspec +14 -1
- data/rbi/generated/prism/node.rbi +736 -0
- data/rbi/generated/prism/serialize.rbi +6 -5
- data/sig/generated/prism/node.rbs +736 -0
- data/sig/generated/prism/serialize.rbs +7 -5
- data/src/arena.c +6 -1
- data/src/comments.c +11 -10
- data/src/diagnostic.c +24 -4
- data/src/integer.c +6 -1
- data/src/node.c +216 -368
- data/src/options.c +7 -13
- data/src/parser.c +52 -48
- data/src/prism.c +222 -240
- data/src/regexp.c +0 -1
- data/src/serialize.c +2300 -1950
- data/src/source.c +8 -2
- data/src/static_literals.c +280 -405
- data/src/stringy.c +3 -33
- metadata +14 -1
data/src/prism.c
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "prism/compiler/accel.h"
|
|
2
|
+
#include "prism/compiler/branch.h"
|
|
2
3
|
#include "prism/compiler/fallthrough.h"
|
|
3
4
|
#include "prism/compiler/unused.h"
|
|
4
5
|
|
|
@@ -68,24 +69,6 @@
|
|
|
68
69
|
# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
|
|
69
70
|
#endif
|
|
70
71
|
|
|
71
|
-
/**
|
|
72
|
-
* Support PRISM_LIKELY and PRISM_UNLIKELY to help the compiler optimize its
|
|
73
|
-
* branch predication.
|
|
74
|
-
*/
|
|
75
|
-
#if defined(__GNUC__) || defined(__clang__)
|
|
76
|
-
/** The compiler should predicate that this branch will be taken. */
|
|
77
|
-
#define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
|
|
78
|
-
|
|
79
|
-
/** The compiler should predicate that this branch will not be taken. */
|
|
80
|
-
#define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
|
81
|
-
#else
|
|
82
|
-
/** Void because this platform does not support branch prediction hints. */
|
|
83
|
-
#define PRISM_LIKELY(x) (x)
|
|
84
|
-
|
|
85
|
-
/** Void because this platform does not support branch prediction hints. */
|
|
86
|
-
#define PRISM_UNLIKELY(x) (x)
|
|
87
|
-
#endif
|
|
88
|
-
|
|
89
72
|
/**
|
|
90
73
|
* The prism version and the serialization format.
|
|
91
74
|
*/
|
|
@@ -201,27 +184,22 @@ lex_mode_terminator(const uint8_t start) {
|
|
|
201
184
|
}
|
|
202
185
|
|
|
203
186
|
/**
|
|
204
|
-
* Push a new lex state onto the stack
|
|
205
|
-
*
|
|
206
|
-
* allocate a new pointer and use that.
|
|
187
|
+
* Push a new lex state onto the stack, reusing a popped lex mode if there is
|
|
188
|
+
* one and allocating a new one otherwise.
|
|
207
189
|
*/
|
|
208
190
|
static void
|
|
209
191
|
lex_mode_push(pm_parser_t *parser, pm_lex_mode_t lex_mode) {
|
|
210
|
-
|
|
211
|
-
parser->lex_modes.index++;
|
|
212
|
-
|
|
213
|
-
if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
|
|
214
|
-
parser->lex_modes.current = (pm_lex_mode_t *) xmalloc(sizeof(pm_lex_mode_t));
|
|
215
|
-
if (PRISM_UNLIKELY(parser->lex_modes.current == NULL)) {
|
|
216
|
-
fprintf(stderr, "prism: out of memory; aborting\n");
|
|
217
|
-
abort();
|
|
218
|
-
}
|
|
192
|
+
pm_lex_mode_t *next = parser->lex_modes.free;
|
|
219
193
|
|
|
220
|
-
|
|
194
|
+
if (next != NULL) {
|
|
195
|
+
parser->lex_modes.free = next->prev;
|
|
221
196
|
} else {
|
|
222
|
-
parser->
|
|
223
|
-
parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
|
|
197
|
+
next = (pm_lex_mode_t *) pm_arena_alloc(&parser->scratch_arena, sizeof(pm_lex_mode_t), PRISM_ALIGNOF(pm_lex_mode_t));
|
|
224
198
|
}
|
|
199
|
+
|
|
200
|
+
lex_mode.prev = parser->lex_modes.current;
|
|
201
|
+
*next = lex_mode;
|
|
202
|
+
parser->lex_modes.current = next;
|
|
225
203
|
}
|
|
226
204
|
|
|
227
205
|
/**
|
|
@@ -374,22 +352,20 @@ lex_mode_push_string_eof(pm_parser_t *parser) {
|
|
|
374
352
|
}
|
|
375
353
|
|
|
376
354
|
/**
|
|
377
|
-
* Pop the current lex state off the stack
|
|
378
|
-
*
|
|
379
|
-
*
|
|
355
|
+
* Pop the current lex state off the stack, keeping it for reuse by the next
|
|
356
|
+
* push. The base lex mode is never popped, so popping it instead resets it to
|
|
357
|
+
* the default mode.
|
|
380
358
|
*/
|
|
381
359
|
static void
|
|
382
360
|
lex_mode_pop(pm_parser_t *parser) {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
|
|
361
|
+
pm_lex_mode_t *popped = parser->lex_modes.current;
|
|
362
|
+
|
|
363
|
+
if (popped == &parser->lex_modes.base) {
|
|
364
|
+
popped->mode = PM_LEX_DEFAULT;
|
|
388
365
|
} else {
|
|
389
|
-
parser->lex_modes.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
parser->lex_modes.current = prev;
|
|
366
|
+
parser->lex_modes.current = popped->prev;
|
|
367
|
+
popped->prev = parser->lex_modes.free;
|
|
368
|
+
parser->lex_modes.free = popped;
|
|
393
369
|
}
|
|
394
370
|
}
|
|
395
371
|
|
|
@@ -726,7 +702,7 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) {
|
|
|
726
702
|
memset(locals.locals, 0, locals.capacity * sizeof(pm_local_t));
|
|
727
703
|
}
|
|
728
704
|
} else {
|
|
729
|
-
scope = (pm_scope_t *) pm_arena_alloc(&parser->
|
|
705
|
+
scope = (pm_scope_t *) pm_arena_alloc(&parser->scratch_arena, sizeof(pm_scope_t), PRISM_ALIGNOF(pm_scope_t));
|
|
730
706
|
}
|
|
731
707
|
|
|
732
708
|
*scope = (pm_scope_t) {
|
|
@@ -2452,7 +2428,7 @@ pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node,
|
|
|
2452
2428
|
PM_NODE_LENGTH_SET_NODE(node, argument);
|
|
2453
2429
|
}
|
|
2454
2430
|
|
|
2455
|
-
|
|
2431
|
+
pm_node_list_append_inline(arena, &node->arguments, argument);
|
|
2456
2432
|
|
|
2457
2433
|
if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
|
|
2458
2434
|
if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
|
|
@@ -2500,7 +2476,7 @@ pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_
|
|
|
2500
2476
|
PM_NODE_START_SET_NODE(node, element);
|
|
2501
2477
|
}
|
|
2502
2478
|
|
|
2503
|
-
|
|
2479
|
+
pm_node_list_append_inline(arena, &node->elements, element);
|
|
2504
2480
|
PM_NODE_LENGTH_SET_NODE(node, element);
|
|
2505
2481
|
|
|
2506
2482
|
// If the element is not a static literal, then the array is not a static
|
|
@@ -2553,9 +2529,9 @@ pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *node
|
|
|
2553
2529
|
node->rest = child;
|
|
2554
2530
|
found_rest = true;
|
|
2555
2531
|
} else if (found_rest) {
|
|
2556
|
-
|
|
2532
|
+
pm_node_list_append_inline(parser->arena, &node->posts, child);
|
|
2557
2533
|
} else {
|
|
2558
|
-
|
|
2534
|
+
pm_node_list_append_inline(parser->arena, &node->requireds, child);
|
|
2559
2535
|
}
|
|
2560
2536
|
}
|
|
2561
2537
|
|
|
@@ -2623,7 +2599,7 @@ pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *openin
|
|
|
2623
2599
|
|
|
2624
2600
|
static PRISM_INLINE void
|
|
2625
2601
|
pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
|
|
2626
|
-
|
|
2602
|
+
pm_node_list_append_inline(arena, &node->requireds, inner);
|
|
2627
2603
|
}
|
|
2628
2604
|
|
|
2629
2605
|
/**
|
|
@@ -2887,7 +2863,7 @@ pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name)
|
|
|
2887
2863
|
*/
|
|
2888
2864
|
static void
|
|
2889
2865
|
pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
|
|
2890
|
-
|
|
2866
|
+
pm_node_list_append_inline(arena, &node->locals, UP(local));
|
|
2891
2867
|
|
|
2892
2868
|
if (PM_NODE_LENGTH(node) == 0) {
|
|
2893
2869
|
PM_NODE_START_SET_NODE(node, local);
|
|
@@ -3540,7 +3516,7 @@ static void
|
|
|
3540
3516
|
pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
|
|
3541
3517
|
assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
|
|
3542
3518
|
|
|
3543
|
-
|
|
3519
|
+
pm_node_list_append_inline(arena, &node->conditions, condition);
|
|
3544
3520
|
PM_NODE_LENGTH_SET_NODE(node, condition);
|
|
3545
3521
|
}
|
|
3546
3522
|
|
|
@@ -3587,7 +3563,7 @@ static void
|
|
|
3587
3563
|
pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
|
|
3588
3564
|
assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
|
|
3589
3565
|
|
|
3590
|
-
|
|
3566
|
+
pm_node_list_append_inline(arena, &node->conditions, condition);
|
|
3591
3567
|
PM_NODE_LENGTH_SET_NODE(node, condition);
|
|
3592
3568
|
}
|
|
3593
3569
|
|
|
@@ -4127,7 +4103,7 @@ pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
|
|
|
4127
4103
|
// much more efficient, as we could instead resize the node list to only point
|
|
4128
4104
|
// to 1...-1.
|
|
4129
4105
|
for (size_t index = 1; index < nodes->size - 1; index++) {
|
|
4130
|
-
|
|
4106
|
+
pm_node_list_append_inline(parser->arena, &node->requireds, nodes->nodes[index]);
|
|
4131
4107
|
}
|
|
4132
4108
|
|
|
4133
4109
|
return node;
|
|
@@ -4624,7 +4600,7 @@ pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
|
|
|
4624
4600
|
*/
|
|
4625
4601
|
static PRISM_INLINE void
|
|
4626
4602
|
pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
|
|
4627
|
-
|
|
4603
|
+
pm_node_list_append_inline(arena, &hash->elements, element);
|
|
4628
4604
|
|
|
4629
4605
|
bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
|
|
4630
4606
|
if (static_literal) {
|
|
@@ -5049,7 +5025,7 @@ pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *
|
|
|
5049
5025
|
break;
|
|
5050
5026
|
}
|
|
5051
5027
|
|
|
5052
|
-
|
|
5028
|
+
pm_node_list_append_inline(arena, parts, part);
|
|
5053
5029
|
}
|
|
5054
5030
|
|
|
5055
5031
|
/**
|
|
@@ -5191,7 +5167,7 @@ pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_n
|
|
|
5191
5167
|
// These will only happen in error cases. But we want to handle it
|
|
5192
5168
|
// here so that we don't fail the assertion.
|
|
5193
5169
|
CLEAR_FLAGS(node);
|
|
5194
|
-
|
|
5170
|
+
pm_node_list_append_inline(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
|
|
5195
5171
|
return;
|
|
5196
5172
|
case PM_ERROR_RECOVERY_NODE:
|
|
5197
5173
|
CLEAR_FLAGS(node);
|
|
@@ -5201,7 +5177,7 @@ pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_n
|
|
|
5201
5177
|
break;
|
|
5202
5178
|
}
|
|
5203
5179
|
|
|
5204
|
-
|
|
5180
|
+
pm_node_list_append_inline(arena, &node->parts, part);
|
|
5205
5181
|
|
|
5206
5182
|
#undef CLEAR_FLAGS
|
|
5207
5183
|
#undef MUTABLE_FLAGS
|
|
@@ -5381,7 +5357,7 @@ pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *
|
|
|
5381
5357
|
pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
|
|
5382
5358
|
}
|
|
5383
5359
|
|
|
5384
|
-
|
|
5360
|
+
pm_node_list_append_inline(arena, &hash->elements, element);
|
|
5385
5361
|
if (PM_NODE_LENGTH(hash) == 0) {
|
|
5386
5362
|
PM_NODE_START_SET_NODE(hash, element);
|
|
5387
5363
|
}
|
|
@@ -5729,19 +5705,19 @@ pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t
|
|
|
5729
5705
|
node->rest = target;
|
|
5730
5706
|
} else {
|
|
5731
5707
|
pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
|
|
5732
|
-
|
|
5708
|
+
pm_node_list_append_inline(parser->arena, &node->rights, target);
|
|
5733
5709
|
}
|
|
5734
5710
|
} else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
|
|
5735
5711
|
if (node->rest == NULL) {
|
|
5736
5712
|
node->rest = target;
|
|
5737
5713
|
} else {
|
|
5738
5714
|
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
|
|
5739
|
-
|
|
5715
|
+
pm_node_list_append_inline(parser->arena, &node->rights, target);
|
|
5740
5716
|
}
|
|
5741
5717
|
} else if (node->rest == NULL) {
|
|
5742
|
-
|
|
5718
|
+
pm_node_list_append_inline(parser->arena, &node->lefts, target);
|
|
5743
5719
|
} else {
|
|
5744
|
-
|
|
5720
|
+
pm_node_list_append_inline(parser->arena, &node->rights, target);
|
|
5745
5721
|
}
|
|
5746
5722
|
|
|
5747
5723
|
if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
|
|
@@ -6016,7 +5992,7 @@ pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param)
|
|
|
6016
5992
|
static void
|
|
6017
5993
|
pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
|
|
6018
5994
|
pm_parameters_node_location_set(params, param);
|
|
6019
|
-
|
|
5995
|
+
pm_node_list_append_inline(arena, ¶ms->requireds, param);
|
|
6020
5996
|
}
|
|
6021
5997
|
|
|
6022
5998
|
/**
|
|
@@ -6025,7 +6001,7 @@ pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *par
|
|
|
6025
6001
|
static void
|
|
6026
6002
|
pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
|
|
6027
6003
|
pm_parameters_node_location_set(params, UP(param));
|
|
6028
|
-
|
|
6004
|
+
pm_node_list_append_inline(arena, ¶ms->optionals, UP(param));
|
|
6029
6005
|
}
|
|
6030
6006
|
|
|
6031
6007
|
/**
|
|
@@ -6034,7 +6010,7 @@ pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *par
|
|
|
6034
6010
|
static void
|
|
6035
6011
|
pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
|
|
6036
6012
|
pm_parameters_node_location_set(params, param);
|
|
6037
|
-
|
|
6013
|
+
pm_node_list_append_inline(arena, ¶ms->posts, param);
|
|
6038
6014
|
}
|
|
6039
6015
|
|
|
6040
6016
|
/**
|
|
@@ -6052,7 +6028,7 @@ pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
|
|
|
6052
6028
|
static void
|
|
6053
6029
|
pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
|
|
6054
6030
|
pm_parameters_node_location_set(params, param);
|
|
6055
|
-
|
|
6031
|
+
pm_node_list_append_inline(arena, ¶ms->keywords, param);
|
|
6056
6032
|
}
|
|
6057
6033
|
|
|
6058
6034
|
/**
|
|
@@ -6340,7 +6316,7 @@ pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subseque
|
|
|
6340
6316
|
*/
|
|
6341
6317
|
static void
|
|
6342
6318
|
pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
|
|
6343
|
-
|
|
6319
|
+
pm_node_list_append_inline(arena, &node->exceptions, exception);
|
|
6344
6320
|
PM_NODE_LENGTH_SET_NODE(node, exception);
|
|
6345
6321
|
}
|
|
6346
6322
|
|
|
@@ -6573,7 +6549,7 @@ pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node,
|
|
|
6573
6549
|
}
|
|
6574
6550
|
}
|
|
6575
6551
|
|
|
6576
|
-
|
|
6552
|
+
pm_node_list_append_inline(parser->arena, &node->body, statement);
|
|
6577
6553
|
if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
|
|
6578
6554
|
}
|
|
6579
6555
|
|
|
@@ -6820,7 +6796,7 @@ pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
|
|
|
6820
6796
|
((pm_string_t) { 0 })
|
|
6821
6797
|
);
|
|
6822
6798
|
|
|
6823
|
-
|
|
6799
|
+
pm_string_init(&node->unescaped, (const uint8_t *) content, strlen(content));
|
|
6824
6800
|
return node;
|
|
6825
6801
|
}
|
|
6826
6802
|
|
|
@@ -6963,7 +6939,7 @@ pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
|
|
|
6963
6939
|
static void
|
|
6964
6940
|
pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
|
|
6965
6941
|
PM_NODE_LENGTH_SET_NODE(node, name);
|
|
6966
|
-
|
|
6942
|
+
pm_node_list_append_inline(arena, &node->names, name);
|
|
6967
6943
|
}
|
|
6968
6944
|
|
|
6969
6945
|
/**
|
|
@@ -7105,7 +7081,7 @@ pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
|
|
|
7105
7081
|
static void
|
|
7106
7082
|
pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
|
|
7107
7083
|
PM_NODE_LENGTH_SET_NODE(node, condition);
|
|
7108
|
-
|
|
7084
|
+
pm_node_list_append_inline(arena, &node->conditions, condition);
|
|
7109
7085
|
}
|
|
7110
7086
|
|
|
7111
7087
|
/**
|
|
@@ -7279,7 +7255,7 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
|
|
|
7279
7255
|
*/
|
|
7280
7256
|
static PRISM_INLINE void
|
|
7281
7257
|
pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
|
|
7282
|
-
pm_locals_write(&parser->
|
|
7258
|
+
pm_locals_write(&parser->scratch_arena, &parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
|
|
7283
7259
|
}
|
|
7284
7260
|
|
|
7285
7261
|
/**
|
|
@@ -7692,6 +7668,27 @@ parser_lex_magic_comment_emacs_marker(pm_parser_t *parser, const uint8_t *cursor
|
|
|
7692
7668
|
return NULL;
|
|
7693
7669
|
}
|
|
7694
7670
|
|
|
7671
|
+
/**
|
|
7672
|
+
* Returns true if the given magic comment key matches the given name, which is
|
|
7673
|
+
* written in lowercase with underscores and is the same length as the key.
|
|
7674
|
+
* Keys match case-insensitively, and a dash in the key matches an underscore in
|
|
7675
|
+
* the name. Every byte of a name is ASCII, so a byte of a multibyte character
|
|
7676
|
+
* in the key never matches one.
|
|
7677
|
+
*/
|
|
7678
|
+
static bool
|
|
7679
|
+
parser_magic_comment_key_p(const uint8_t *key, size_t key_length, const char *name) {
|
|
7680
|
+
assert(name[key_length] == '\0');
|
|
7681
|
+
|
|
7682
|
+
for (size_t index = 0; index < key_length; index++) {
|
|
7683
|
+
uint8_t byte = key[index];
|
|
7684
|
+
if (byte == '-') byte = '_';
|
|
7685
|
+
if ('A' <= byte && byte <= 'Z') byte |= 0x20;
|
|
7686
|
+
if (byte != (uint8_t) name[index]) return false;
|
|
7687
|
+
}
|
|
7688
|
+
|
|
7689
|
+
return true;
|
|
7690
|
+
}
|
|
7691
|
+
|
|
7695
7692
|
/**
|
|
7696
7693
|
* Parse the current token on the parser to see if it's a magic comment and
|
|
7697
7694
|
* potentially perform some action based on that. A regular expression that this
|
|
@@ -7783,73 +7780,34 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
|
7783
7780
|
if (cursor != end) return false;
|
|
7784
7781
|
}
|
|
7785
7782
|
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
pm_string_t key;
|
|
7783
|
+
/* Finally, we can start checking the key against the list of known
|
|
7784
|
+
* magic comment keys, and potentially change state based on that. */
|
|
7789
7785
|
const size_t key_length = (size_t) (key_end - key_start);
|
|
7790
|
-
const uint8_t *dash = pm_memchr(key_start, '-', key_length, parser->encoding_changed, parser->encoding);
|
|
7791
|
-
|
|
7792
|
-
if (dash == NULL) {
|
|
7793
|
-
pm_string_shared_init(&key, key_start, key_end);
|
|
7794
|
-
} else {
|
|
7795
|
-
uint8_t *buffer = xmalloc(key_length);
|
|
7796
|
-
if (buffer == NULL) break;
|
|
7797
|
-
|
|
7798
|
-
memcpy(buffer, key_start, key_length);
|
|
7799
|
-
buffer[dash - key_start] = '_';
|
|
7800
|
-
|
|
7801
|
-
while ((dash = pm_memchr(dash + 1, '-', (size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
|
|
7802
|
-
buffer[dash - key_start] = '_';
|
|
7803
|
-
}
|
|
7804
|
-
|
|
7805
|
-
pm_string_owned_init(&key, buffer, key_length);
|
|
7806
|
-
}
|
|
7807
|
-
|
|
7808
|
-
// Finally, we can start checking the key against the list of known
|
|
7809
|
-
// magic comment keys, and potentially change state based on that.
|
|
7810
|
-
const uint8_t *key_source = pm_string_source(&key);
|
|
7811
7786
|
uint32_t value_length = (uint32_t) (value_end - value_start);
|
|
7812
7787
|
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
(
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
}
|
|
7823
|
-
|
|
7824
|
-
if (key_length == 11) {
|
|
7825
|
-
if (pm_strncasecmp(key_source, (const uint8_t *) "warn_indent", 11) == 0) {
|
|
7826
|
-
switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
|
|
7827
|
-
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
|
|
7828
|
-
PM_PARSER_WARN_TOKEN_FORMAT(
|
|
7829
|
-
parser,
|
|
7830
|
-
&parser->current,
|
|
7831
|
-
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
|
|
7832
|
-
(int) key_length,
|
|
7833
|
-
(const char *) key_source,
|
|
7834
|
-
(int) value_length,
|
|
7835
|
-
(const char *) value_start
|
|
7836
|
-
);
|
|
7837
|
-
break;
|
|
7838
|
-
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
|
|
7839
|
-
parser->warn_mismatched_indentation = false;
|
|
7840
|
-
break;
|
|
7841
|
-
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
|
|
7842
|
-
parser->warn_mismatched_indentation = true;
|
|
7843
|
-
break;
|
|
7788
|
+
switch (key_length) {
|
|
7789
|
+
case 6:
|
|
7790
|
+
/* We only want to attempt to compare against encoding comments
|
|
7791
|
+
* if it is the first line in the file (or the second in the
|
|
7792
|
+
* case of a shebang). */
|
|
7793
|
+
if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
|
|
7794
|
+
if (parser_magic_comment_key_p(key_start, key_length, "coding")) {
|
|
7795
|
+
result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
|
|
7796
|
+
}
|
|
7844
7797
|
}
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
if (
|
|
7851
|
-
|
|
7852
|
-
|
|
7798
|
+
break;
|
|
7799
|
+
case 8:
|
|
7800
|
+
/* We only want to attempt to compare against encoding comments
|
|
7801
|
+
* if it is the first line in the file (or the second in the
|
|
7802
|
+
* case of a shebang). */
|
|
7803
|
+
if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
|
|
7804
|
+
if (parser_magic_comment_key_p(key_start, key_length, "encoding")) {
|
|
7805
|
+
result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
|
|
7806
|
+
}
|
|
7807
|
+
}
|
|
7808
|
+
break;
|
|
7809
|
+
case 11:
|
|
7810
|
+
if (parser_magic_comment_key_p(key_start, key_length, "warn_indent")) {
|
|
7853
7811
|
switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
|
|
7854
7812
|
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
|
|
7855
7813
|
PM_PARSER_WARN_TOKEN_FORMAT(
|
|
@@ -7857,53 +7815,79 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
|
7857
7815
|
&parser->current,
|
|
7858
7816
|
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
|
|
7859
7817
|
(int) key_length,
|
|
7860
|
-
|
|
7818
|
+
"warn_indent",
|
|
7861
7819
|
(int) value_length,
|
|
7862
7820
|
(const char *) value_start
|
|
7863
7821
|
);
|
|
7864
7822
|
break;
|
|
7865
7823
|
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
|
|
7866
|
-
parser->
|
|
7824
|
+
parser->warn_mismatched_indentation = false;
|
|
7867
7825
|
break;
|
|
7868
7826
|
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
|
|
7869
|
-
parser->
|
|
7827
|
+
parser->warn_mismatched_indentation = true;
|
|
7870
7828
|
break;
|
|
7871
7829
|
}
|
|
7872
7830
|
}
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7831
|
+
break;
|
|
7832
|
+
case 21:
|
|
7833
|
+
if (parser_magic_comment_key_p(key_start, key_length, "frozen_string_literal")) {
|
|
7834
|
+
/* We only want to handle frozen string literal comments if
|
|
7835
|
+
* it is before any semantic tokens have been seen. */
|
|
7836
|
+
if (semantic_token_seen) {
|
|
7837
|
+
pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
|
|
7838
|
+
} else {
|
|
7839
|
+
switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
|
|
7840
|
+
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
|
|
7841
|
+
PM_PARSER_WARN_TOKEN_FORMAT(
|
|
7842
|
+
parser,
|
|
7843
|
+
&parser->current,
|
|
7844
|
+
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
|
|
7845
|
+
(int) key_length,
|
|
7846
|
+
"frozen_string_literal",
|
|
7847
|
+
(int) value_length,
|
|
7848
|
+
(const char *) value_start
|
|
7849
|
+
);
|
|
7850
|
+
break;
|
|
7851
|
+
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
|
|
7852
|
+
parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
|
|
7853
|
+
break;
|
|
7854
|
+
case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
|
|
7855
|
+
parser->frozen_string_literal = PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED;
|
|
7856
|
+
break;
|
|
7857
|
+
}
|
|
7858
|
+
}
|
|
7899
7859
|
}
|
|
7900
|
-
|
|
7860
|
+
break;
|
|
7861
|
+
case 24:
|
|
7862
|
+
if (parser_magic_comment_key_p(key_start, key_length, "shareable_constant_value")) {
|
|
7863
|
+
const uint8_t *cursor = parser->current.start;
|
|
7864
|
+
while ((cursor > parser->start) && ((cursor[-1] == ' ') || (cursor[-1] == '\t'))) cursor--;
|
|
7865
|
+
|
|
7866
|
+
if (!((cursor == parser->start) || (cursor[-1] == '\n'))) {
|
|
7867
|
+
pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
|
|
7868
|
+
} else if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "none", 4) == 0) {
|
|
7869
|
+
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
|
|
7870
|
+
} else if (value_length == 7 && pm_strncasecmp(value_start, (const uint8_t *) "literal", 7) == 0) {
|
|
7871
|
+
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
|
|
7872
|
+
} else if (value_length == 23 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_everything", 23) == 0) {
|
|
7873
|
+
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
|
|
7874
|
+
} else if (value_length == 17 && pm_strncasecmp(value_start, (const uint8_t *) "experimental_copy", 17) == 0) {
|
|
7875
|
+
pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
|
|
7876
|
+
} else {
|
|
7877
|
+
PM_PARSER_WARN_TOKEN_FORMAT(
|
|
7878
|
+
parser,
|
|
7879
|
+
&parser->current,
|
|
7880
|
+
PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
|
|
7881
|
+
(int) key_length,
|
|
7882
|
+
"shareable_constant_value",
|
|
7883
|
+
(int) value_length,
|
|
7884
|
+
(const char *) value_start
|
|
7885
|
+
);
|
|
7886
|
+
}
|
|
7887
|
+
}
|
|
7888
|
+
break;
|
|
7901
7889
|
}
|
|
7902
7890
|
|
|
7903
|
-
// When we're done, we want to free the string in case we had to
|
|
7904
|
-
// allocate memory for it.
|
|
7905
|
-
pm_string_cleanup(&key);
|
|
7906
|
-
|
|
7907
7891
|
// Allocate a new magic comment node to append to the parser's list.
|
|
7908
7892
|
pm_magic_comment_t *magic_comment = (pm_magic_comment_t *) pm_arena_alloc(&parser->metadata_arena, sizeof(pm_magic_comment_t), PRISM_ALIGNOF(pm_magic_comment_t));
|
|
7909
7893
|
magic_comment->node.next = NULL;
|
|
@@ -8006,7 +7990,7 @@ context_push(pm_parser_t *parser, pm_context_t context) {
|
|
|
8006
7990
|
if (context_node != NULL) {
|
|
8007
7991
|
parser->free_contexts = context_node->prev;
|
|
8008
7992
|
} else {
|
|
8009
|
-
context_node = (pm_context_node_t *) pm_arena_alloc(&parser->
|
|
7993
|
+
context_node = (pm_context_node_t *) pm_arena_alloc(&parser->scratch_arena, sizeof(pm_context_node_t), PRISM_ALIGNOF(pm_context_node_t));
|
|
8010
7994
|
}
|
|
8011
7995
|
|
|
8012
7996
|
pm_context_node_t *previous = parser->current_context;
|
|
@@ -9650,7 +9634,7 @@ lex_question_mark(pm_parser_t *parser) {
|
|
|
9650
9634
|
|
|
9651
9635
|
// Copy buffer data into the arena and free the heap buffer.
|
|
9652
9636
|
void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length, PRISM_ALIGNOF(uint8_t));
|
|
9653
|
-
|
|
9637
|
+
pm_string_init(&parser->current_string, (const uint8_t *) arena_data, buffer.length);
|
|
9654
9638
|
pm_buffer_cleanup(&buffer);
|
|
9655
9639
|
|
|
9656
9640
|
return PM_TOKEN_CHARACTER_LITERAL;
|
|
@@ -9974,7 +9958,7 @@ pm_token_buffer_copy(pm_parser_t *parser, pm_token_buffer_t *token_buffer) {
|
|
|
9974
9958
|
// Copy buffer data into the arena and free the heap buffer.
|
|
9975
9959
|
size_t len = pm_buffer_length(&token_buffer->buffer);
|
|
9976
9960
|
void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->buffer), len, PRISM_ALIGNOF(uint8_t));
|
|
9977
|
-
|
|
9961
|
+
pm_string_init(&parser->current_string, (const uint8_t *) arena_data, len);
|
|
9978
9962
|
pm_buffer_cleanup(&token_buffer->buffer);
|
|
9979
9963
|
}
|
|
9980
9964
|
|
|
@@ -13187,7 +13171,7 @@ parse_starred_expression(pm_parser_t *parser, pm_binding_power_t binding_power,
|
|
|
13187
13171
|
return parse_value_expression(parser, binding_power, flags, diag_id, depth);
|
|
13188
13172
|
}
|
|
13189
13173
|
|
|
13190
|
-
static
|
|
13174
|
+
static pm_visit_result_t
|
|
13191
13175
|
pm_node_unreference_each(const pm_node_t *node, void *data) {
|
|
13192
13176
|
switch (PM_NODE_TYPE(node)) {
|
|
13193
13177
|
/* When we are about to destroy a set of nodes that could potentially
|
|
@@ -13213,15 +13197,15 @@ pm_node_unreference_each(const pm_node_t *node, void *data) {
|
|
|
13213
13197
|
}
|
|
13214
13198
|
parser->current_block_exits->size--;
|
|
13215
13199
|
|
|
13216
|
-
/* Note
|
|
13200
|
+
/* Note descending here because these nodes could have
|
|
13217
13201
|
* arguments that are themselves block exits. */
|
|
13218
|
-
return
|
|
13202
|
+
return PM_VISIT_DESCEND;
|
|
13219
13203
|
}
|
|
13220
13204
|
|
|
13221
13205
|
index++;
|
|
13222
13206
|
}
|
|
13223
13207
|
|
|
13224
|
-
return
|
|
13208
|
+
return PM_VISIT_DESCEND;
|
|
13225
13209
|
}
|
|
13226
13210
|
/* When an implicit local variable is written to or targeted, it becomes
|
|
13227
13211
|
* a regular, named local variable. This branch removes it from the list
|
|
@@ -13245,10 +13229,10 @@ pm_node_unreference_each(const pm_node_t *node, void *data) {
|
|
|
13245
13229
|
}
|
|
13246
13230
|
}
|
|
13247
13231
|
|
|
13248
|
-
return
|
|
13232
|
+
return PM_VISIT_SKIP;
|
|
13249
13233
|
}
|
|
13250
13234
|
default:
|
|
13251
|
-
return
|
|
13235
|
+
return PM_VISIT_DESCEND;
|
|
13252
13236
|
}
|
|
13253
13237
|
}
|
|
13254
13238
|
|
|
@@ -13899,7 +13883,7 @@ parse_statements(pm_parser_t *parser, pm_context_t context, uint16_t depth) {
|
|
|
13899
13883
|
static void
|
|
13900
13884
|
pm_hash_key_duplicated_warn(pm_parser_t *parser, const pm_node_t *duplicated, const pm_node_t *node) {
|
|
13901
13885
|
pm_buffer_t buffer = { 0 };
|
|
13902
|
-
pm_static_literal_inspect(&buffer,
|
|
13886
|
+
pm_static_literal_inspect(&buffer, parser, duplicated);
|
|
13903
13887
|
|
|
13904
13888
|
pm_diagnostic_list_append_format(
|
|
13905
13889
|
&parser->metadata_arena,
|
|
@@ -13921,7 +13905,7 @@ pm_hash_key_duplicated_warn(pm_parser_t *parser, const pm_node_t *duplicated, co
|
|
|
13921
13905
|
*/
|
|
13922
13906
|
static void
|
|
13923
13907
|
pm_hash_key_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
|
|
13924
|
-
const pm_node_t *duplicated = pm_static_literals_add(
|
|
13908
|
+
const pm_node_t *duplicated = pm_static_literals_add(parser, literals, node, true);
|
|
13925
13909
|
|
|
13926
13910
|
if (duplicated != NULL) {
|
|
13927
13911
|
pm_hash_key_duplicated_warn(parser, duplicated, node);
|
|
@@ -13945,7 +13929,7 @@ pm_hash_key_static_literals_merge(pm_parser_t *parser, pm_static_literals_t *lit
|
|
|
13945
13929
|
switch (PM_NODE_TYPE(element)) {
|
|
13946
13930
|
case PM_ASSOC_NODE: {
|
|
13947
13931
|
pm_node_t *key = ((pm_assoc_node_t *) element)->key;
|
|
13948
|
-
const pm_node_t *duplicated = pm_static_literals_add(
|
|
13932
|
+
const pm_node_t *duplicated = pm_static_literals_add(parser, literals, key, true);
|
|
13949
13933
|
|
|
13950
13934
|
if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
|
|
13951
13935
|
pm_hash_key_duplicated_warn(parser, duplicated, key);
|
|
@@ -13976,7 +13960,7 @@ static void
|
|
|
13976
13960
|
pm_when_clause_static_literals_add(pm_parser_t *parser, pm_static_literals_t *literals, pm_node_t *node) {
|
|
13977
13961
|
pm_node_t *previous;
|
|
13978
13962
|
|
|
13979
|
-
if ((previous = pm_static_literals_add(
|
|
13963
|
+
if ((previous = pm_static_literals_add(parser, literals, node, false)) != NULL) {
|
|
13980
13964
|
pm_diagnostic_list_append_format(
|
|
13981
13965
|
&parser->metadata_arena,
|
|
13982
13966
|
&parser->warning_list,
|
|
@@ -15990,7 +15974,7 @@ ensure_valid_jump(pm_parser_t *parser, pm_node_t *node) {
|
|
|
15990
15974
|
// block exit to the list of exits for the expression, and
|
|
15991
15975
|
// the node parsing will handle validating it instead.
|
|
15992
15976
|
assert(parser->current_block_exits != NULL);
|
|
15993
|
-
|
|
15977
|
+
pm_node_list_append_inline(&parser->scratch_arena, parser->current_block_exits, node);
|
|
15994
15978
|
return;
|
|
15995
15979
|
case PM_CONTEXT_BEGIN_ELSE:
|
|
15996
15980
|
case PM_CONTEXT_BEGIN_ENSURE:
|
|
@@ -16082,7 +16066,7 @@ pop_block_exits(pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
|
|
|
16082
16066
|
// However, they could still become valid in a higher level context if
|
|
16083
16067
|
// there is another list above this one. In this case we'll push all of
|
|
16084
16068
|
// the block exits up to the previous list.
|
|
16085
|
-
pm_node_list_concat(parser->
|
|
16069
|
+
pm_node_list_concat(&parser->scratch_arena, previous_block_exits, parser->current_block_exits);
|
|
16086
16070
|
parser->current_block_exits = previous_block_exits;
|
|
16087
16071
|
} else {
|
|
16088
16072
|
// If we did not match a trailing while/until and this was the last
|
|
@@ -16728,12 +16712,12 @@ parse_variable(pm_parser_t *parser) {
|
|
|
16728
16712
|
}
|
|
16729
16713
|
|
|
16730
16714
|
pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0, false));
|
|
16731
|
-
|
|
16715
|
+
pm_node_list_append_inline(&parser->scratch_arena, ¤t_scope->implicit_parameters, node);
|
|
16732
16716
|
|
|
16733
16717
|
return node;
|
|
16734
16718
|
} else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
|
|
16735
16719
|
pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
|
|
16736
|
-
|
|
16720
|
+
pm_node_list_append_inline(&parser->scratch_arena, ¤t_scope->implicit_parameters, node);
|
|
16737
16721
|
|
|
16738
16722
|
return node;
|
|
16739
16723
|
}
|
|
@@ -16790,18 +16774,13 @@ parse_method_definition_name(pm_parser_t *parser) {
|
|
|
16790
16774
|
|
|
16791
16775
|
static void
|
|
16792
16776
|
parse_heredoc_dedent_string(pm_arena_t *arena, pm_string_t *string, size_t common_whitespace) {
|
|
16793
|
-
// Make a writable copy
|
|
16794
|
-
// We keep a mutable pointer to the arena memory so we can
|
|
16795
|
-
// below without casting away const from the string's
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
16799
|
-
|
|
16800
|
-
writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
|
|
16801
|
-
pm_string_constant_init(string, (const char *) writable, length);
|
|
16802
|
-
} else {
|
|
16803
|
-
writable = (uint8_t *) string->source;
|
|
16804
|
-
}
|
|
16777
|
+
// Make a writable copy of the string in the arena, since strings only view
|
|
16778
|
+
// their bytes. We keep a mutable pointer to the arena memory so we can
|
|
16779
|
+
// memmove into it below without casting away const from the string's
|
|
16780
|
+
// source field.
|
|
16781
|
+
size_t length = pm_string_length(string);
|
|
16782
|
+
uint8_t *writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(string), length, PRISM_ALIGNOF(uint8_t));
|
|
16783
|
+
pm_string_init(string, writable, length);
|
|
16805
16784
|
|
|
16806
16785
|
// Now get the bounds of the existing string. We'll use this as a
|
|
16807
16786
|
// destination to move bytes into. We'll also use it for bounds checking
|
|
@@ -16966,11 +16945,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
|
|
|
16966
16945
|
if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
|
|
16967
16946
|
pm_node_list_t parts = { 0 };
|
|
16968
16947
|
pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
|
|
16969
|
-
|
|
16948
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
16970
16949
|
|
|
16971
16950
|
do {
|
|
16972
16951
|
part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
|
|
16973
|
-
|
|
16952
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
16974
16953
|
parser_lex(parser);
|
|
16975
16954
|
} while (match1(parser, PM_TOKEN_STRING_CONTENT));
|
|
16976
16955
|
|
|
@@ -17025,11 +17004,11 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
|
|
|
17025
17004
|
pm_node_list_t parts = { 0 };
|
|
17026
17005
|
pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
|
|
17027
17006
|
pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
|
|
17028
|
-
|
|
17007
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
17029
17008
|
|
|
17030
17009
|
while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
|
|
17031
17010
|
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
|
|
17032
|
-
|
|
17011
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
17033
17012
|
}
|
|
17034
17013
|
}
|
|
17035
17014
|
|
|
@@ -17053,7 +17032,7 @@ parse_strings(pm_parser_t *parser, pm_node_t *current, bool accepts_label, uint1
|
|
|
17053
17032
|
|
|
17054
17033
|
while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
|
|
17055
17034
|
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
|
|
17056
|
-
|
|
17035
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
17057
17036
|
}
|
|
17058
17037
|
}
|
|
17059
17038
|
|
|
@@ -17125,7 +17104,7 @@ parse_pattern_capture(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_co
|
|
|
17125
17104
|
// Skip this capture if it starts with an underscore.
|
|
17126
17105
|
if (peek_at(parser, parser->start + location->start) == '_') return;
|
|
17127
17106
|
|
|
17128
|
-
if (!pm_constant_id_set_insert(parser->
|
|
17107
|
+
if (!pm_constant_id_set_insert(&parser->scratch_arena, captures, capture)) {
|
|
17129
17108
|
pm_parser_err(parser, location->start, location->length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
|
|
17130
17109
|
}
|
|
17131
17110
|
}
|
|
@@ -17391,7 +17370,7 @@ parse_pattern_hash_implicit_value(pm_parser_t *parser, pm_constant_id_set_t *cap
|
|
|
17391
17370
|
*/
|
|
17392
17371
|
static void
|
|
17393
17372
|
parse_pattern_hash_key(pm_parser_t *parser, pm_static_literals_t *keys, pm_node_t *node) {
|
|
17394
|
-
if (pm_static_literals_add(
|
|
17373
|
+
if (pm_static_literals_add(parser, keys, node, true) != NULL) {
|
|
17395
17374
|
pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
|
|
17396
17375
|
}
|
|
17397
17376
|
}
|
|
@@ -17439,7 +17418,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
|
|
|
17439
17418
|
}
|
|
17440
17419
|
|
|
17441
17420
|
pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
|
|
17442
|
-
|
|
17421
|
+
pm_node_list_append_inline(parser->arena, &assocs, assoc);
|
|
17443
17422
|
break;
|
|
17444
17423
|
}
|
|
17445
17424
|
}
|
|
@@ -17454,7 +17433,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
|
|
|
17454
17433
|
pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
|
|
17455
17434
|
pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
|
|
17456
17435
|
|
|
17457
|
-
|
|
17436
|
+
pm_node_list_append_inline(parser->arena, &assocs, assoc);
|
|
17458
17437
|
break;
|
|
17459
17438
|
}
|
|
17460
17439
|
}
|
|
@@ -17482,7 +17461,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
|
|
|
17482
17461
|
rest = assoc;
|
|
17483
17462
|
} else {
|
|
17484
17463
|
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
|
|
17485
|
-
|
|
17464
|
+
pm_node_list_append_inline(parser->arena, &assocs, assoc);
|
|
17486
17465
|
}
|
|
17487
17466
|
} else {
|
|
17488
17467
|
pm_node_t *key;
|
|
@@ -17528,7 +17507,7 @@ parse_pattern_hash(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_node_
|
|
|
17528
17507
|
pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
|
|
17529
17508
|
}
|
|
17530
17509
|
|
|
17531
|
-
|
|
17510
|
+
pm_node_list_append_inline(parser->arena, &assocs, assoc);
|
|
17532
17511
|
}
|
|
17533
17512
|
}
|
|
17534
17513
|
|
|
@@ -17808,7 +17787,7 @@ parse_pattern_primitive(pm_parser_t *parser, pm_constant_id_set_t *captures, pm_
|
|
|
17808
17787
|
* are not captures of this pattern. A nested alternation is not visited
|
|
17809
17788
|
* either: its operands were already checked when it was parsed.
|
|
17810
17789
|
*/
|
|
17811
|
-
static
|
|
17790
|
+
static pm_visit_result_t
|
|
17812
17791
|
parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
|
|
17813
17792
|
pm_parser_t *parser = (pm_parser_t *) data;
|
|
17814
17793
|
|
|
@@ -17819,7 +17798,7 @@ parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
|
|
|
17819
17798
|
if (peek_at(parser, parser->start + PM_NODE_START(node)) != '_') {
|
|
17820
17799
|
pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
|
|
17821
17800
|
}
|
|
17822
|
-
return
|
|
17801
|
+
return PM_VISIT_SKIP;
|
|
17823
17802
|
case PM_ARRAY_PATTERN_NODE:
|
|
17824
17803
|
case PM_ASSOC_NODE:
|
|
17825
17804
|
case PM_ASSOC_SPLAT_NODE:
|
|
@@ -17829,9 +17808,9 @@ parse_pattern_alternation_error_each(const pm_node_t *node, void *data) {
|
|
|
17829
17808
|
case PM_IMPLICIT_NODE:
|
|
17830
17809
|
case PM_PARENTHESES_NODE:
|
|
17831
17810
|
case PM_SPLAT_NODE:
|
|
17832
|
-
return
|
|
17811
|
+
return PM_VISIT_DESCEND;
|
|
17833
17812
|
default:
|
|
17834
|
-
return
|
|
17813
|
+
return PM_VISIT_SKIP;
|
|
17835
17814
|
}
|
|
17836
17815
|
}
|
|
17837
17816
|
|
|
@@ -18027,7 +18006,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
|
|
|
18027
18006
|
// or a find pattern. We need to parse all of the patterns, put them
|
|
18028
18007
|
// into a big list, and then determine which type of node we have.
|
|
18029
18008
|
pm_node_list_t nodes = { 0 };
|
|
18030
|
-
|
|
18009
|
+
pm_node_list_append_inline(parser->arena, &nodes, node);
|
|
18031
18010
|
|
|
18032
18011
|
// Gather up all of the patterns into the list.
|
|
18033
18012
|
while (accept1(parser, PM_TOKEN_COMMA)) {
|
|
@@ -18046,7 +18025,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
|
|
|
18046
18025
|
}
|
|
18047
18026
|
|
|
18048
18027
|
node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
|
|
18049
|
-
|
|
18028
|
+
pm_node_list_append_inline(parser->arena, &nodes, node);
|
|
18050
18029
|
trailing_rest = true;
|
|
18051
18030
|
break;
|
|
18052
18031
|
}
|
|
@@ -18066,7 +18045,7 @@ parse_pattern(pm_parser_t *parser, pm_constant_id_set_t *captures, uint8_t flags
|
|
|
18066
18045
|
node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
|
|
18067
18046
|
}
|
|
18068
18047
|
|
|
18069
|
-
|
|
18048
|
+
pm_node_list_append_inline(parser->arena, &nodes, node);
|
|
18070
18049
|
}
|
|
18071
18050
|
|
|
18072
18051
|
// If the first pattern and the last pattern are rest patterns, then we
|
|
@@ -19572,11 +19551,11 @@ parse_heredoc(pm_parser_t *parser, uint16_t depth) {
|
|
|
19572
19551
|
// so we'll need to create an interpolated string node to hold
|
|
19573
19552
|
// them all.
|
|
19574
19553
|
pm_node_list_t parts = { 0 };
|
|
19575
|
-
|
|
19554
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
19576
19555
|
|
|
19577
19556
|
while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
|
|
19578
19557
|
if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
|
|
19579
|
-
|
|
19558
|
+
pm_node_list_append_inline(parser->arena, &parts, part);
|
|
19580
19559
|
}
|
|
19581
19560
|
}
|
|
19582
19561
|
|
|
@@ -21818,7 +21797,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c
|
|
|
21818
21797
|
* Add this name to the set of constants if it is valid, not duplicated,
|
|
21819
21798
|
* and not a keyword.
|
|
21820
21799
|
*/
|
|
21821
|
-
if (name != 0 && pm_constant_id_set_insert(parser->
|
|
21800
|
+
if (name != 0 && pm_constant_id_set_insert(&parser->scratch_arena, names, name)) {
|
|
21822
21801
|
|
|
21823
21802
|
int depth;
|
|
21824
21803
|
if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
|
|
@@ -21845,7 +21824,7 @@ parse_regular_expression_named_capture(pm_parser_t *parser, const pm_string_t *c
|
|
|
21845
21824
|
pm_token_t token = { .type = 0, .start = start, .end = end };
|
|
21846
21825
|
pm_location_t token_loc = TOK2LOC(parser, &token);
|
|
21847
21826
|
pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
|
|
21848
|
-
|
|
21827
|
+
pm_node_list_append_inline(parser->arena, &name_data->match->targets, target);
|
|
21849
21828
|
}
|
|
21850
21829
|
|
|
21851
21830
|
pm_buffer_cleanup(&unescaped);
|
|
@@ -22014,9 +21993,7 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
|
|
|
22014
21993
|
}
|
|
22015
21994
|
|
|
22016
21995
|
if (!interpolated && total_length > 0) {
|
|
22017
|
-
|
|
22018
|
-
if (!memory) abort();
|
|
22019
|
-
|
|
21996
|
+
uint8_t *memory = (uint8_t *) pm_arena_alloc(&parser->scratch_arena, total_length, PRISM_ALIGNOF(uint8_t));
|
|
22020
21997
|
uint8_t *cursor = memory;
|
|
22021
21998
|
PM_NODE_LIST_FOREACH(parts, index, part) {
|
|
22022
21999
|
pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
|
|
@@ -22026,11 +22003,9 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
|
|
|
22026
22003
|
cursor += length;
|
|
22027
22004
|
}
|
|
22028
22005
|
|
|
22029
|
-
pm_string_t
|
|
22030
|
-
|
|
22031
|
-
|
|
22032
|
-
result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
|
|
22033
|
-
pm_string_cleanup(&owned);
|
|
22006
|
+
pm_string_t content;
|
|
22007
|
+
pm_string_init(&content, memory, total_length);
|
|
22008
|
+
result = parse_interpolated_regular_expression_named_captures(parser, &content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
|
|
22034
22009
|
}
|
|
22035
22010
|
} else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
|
|
22036
22011
|
/* If we have a regular expression node, then we can parse the named
|
|
@@ -22040,7 +22015,7 @@ parse_match(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t binding_pow
|
|
|
22040
22015
|
.call = call,
|
|
22041
22016
|
.match = NULL,
|
|
22042
22017
|
.names = { 0 },
|
|
22043
|
-
.shared = regexp->unescaped
|
|
22018
|
+
.shared = pm_string_source(®exp->unescaped) == parser->start + regexp->content_loc.start,
|
|
22044
22019
|
};
|
|
22045
22020
|
|
|
22046
22021
|
pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
|
|
@@ -23279,6 +23254,16 @@ pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const c
|
|
|
23279
23254
|
parser->frozen_string_literal = next_options.frozen_string_literal;
|
|
23280
23255
|
}
|
|
23281
23256
|
|
|
23257
|
+
/**
|
|
23258
|
+
* The smallest capacity the constant pool starts with, whatever the source
|
|
23259
|
+
* size suggests. An embedder that interns a fixed set of names into the pool
|
|
23260
|
+
* at every parse (a symbol table) can raise it to that set's size, so the
|
|
23261
|
+
* pool does not grow to hold them and leave each outgrown array in the arena.
|
|
23262
|
+
*/
|
|
23263
|
+
#ifndef PM_CONSTANT_POOL_MIN_CAPACITY
|
|
23264
|
+
#define PM_CONSTANT_POOL_MIN_CAPACITY 4
|
|
23265
|
+
#endif
|
|
23266
|
+
|
|
23282
23267
|
/**
|
|
23283
23268
|
* Initialize a parser with the given start and end pointers.
|
|
23284
23269
|
*/
|
|
@@ -23298,9 +23283,8 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si
|
|
|
23298
23283
|
.do_loop_stack = 0,
|
|
23299
23284
|
.accepts_block_stack = 0,
|
|
23300
23285
|
.lex_modes = {
|
|
23301
|
-
.
|
|
23302
|
-
.
|
|
23303
|
-
.current = &parser->lex_modes.stack[0],
|
|
23286
|
+
.current = &parser->lex_modes.base,
|
|
23287
|
+
.base = { .mode = PM_LEX_DEFAULT },
|
|
23304
23288
|
},
|
|
23305
23289
|
.start = source,
|
|
23306
23290
|
.end = source + size,
|
|
@@ -23357,7 +23341,8 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si
|
|
|
23357
23341
|
* frequency. Resizes are cheap with arena allocation, so we lean toward
|
|
23358
23342
|
* under-estimating. */
|
|
23359
23343
|
uint32_t constant_size = ((uint32_t) size) / 120;
|
|
23360
|
-
|
|
23344
|
+
if (constant_size < PM_CONSTANT_POOL_MIN_CAPACITY) constant_size = PM_CONSTANT_POOL_MIN_CAPACITY;
|
|
23345
|
+
pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size);
|
|
23361
23346
|
|
|
23362
23347
|
/* Initialize the line offset list. Similar to the constant pool, we are
|
|
23363
23348
|
* going to estimate the number of newlines that we will need based on the
|
|
@@ -23566,12 +23551,8 @@ pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_op
|
|
|
23566
23551
|
*/
|
|
23567
23552
|
void
|
|
23568
23553
|
pm_parser_cleanup(pm_parser_t *parser) {
|
|
23569
|
-
pm_string_cleanup(&parser->filepath);
|
|
23570
23554
|
pm_arena_cleanup(&parser->metadata_arena);
|
|
23571
|
-
|
|
23572
|
-
while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
|
|
23573
|
-
lex_mode_pop(parser);
|
|
23574
|
-
}
|
|
23555
|
+
pm_arena_cleanup(&parser->scratch_arena);
|
|
23575
23556
|
}
|
|
23576
23557
|
|
|
23577
23558
|
/**
|
|
@@ -23753,6 +23734,7 @@ pm_parse(pm_parser_t *parser) {
|
|
|
23753
23734
|
pm_node_t *node = parse_program(parser);
|
|
23754
23735
|
pm_parse_continuable(parser);
|
|
23755
23736
|
if (parser->attach_comments) pm_comments_attach(parser, node);
|
|
23737
|
+
pm_arena_cleanup(&parser->scratch_arena);
|
|
23756
23738
|
return node;
|
|
23757
23739
|
}
|
|
23758
23740
|
|