prism 1.3.0 → 1.5.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 +2 -1
- data/README.md +1 -0
- data/config.yml +273 -37
- data/docs/parser_translation.md +8 -23
- data/docs/releasing.md +1 -1
- data/docs/ripper_translation.md +1 -1
- data/docs/ruby_api.md +1 -1
- data/ext/prism/api_node.c +1816 -1303
- data/ext/prism/extension.c +244 -110
- data/ext/prism/extension.h +4 -4
- data/include/prism/ast.h +291 -49
- data/include/prism/defines.h +4 -1
- data/include/prism/diagnostic.h +4 -0
- data/include/prism/options.h +89 -3
- data/include/prism/regexp.h +2 -2
- data/include/prism/util/pm_buffer.h +18 -0
- data/include/prism/util/pm_integer.h +4 -0
- data/include/prism/util/pm_list.h +6 -0
- data/include/prism/util/pm_string.h +12 -2
- data/include/prism/version.h +2 -2
- data/include/prism.h +41 -16
- data/lib/prism/compiler.rb +456 -151
- data/lib/prism/desugar_compiler.rb +1 -0
- data/lib/prism/dispatcher.rb +16 -0
- data/lib/prism/dot_visitor.rb +21 -1
- data/lib/prism/dsl.rb +13 -2
- data/lib/prism/ffi.rb +62 -34
- data/lib/prism/inspect_visitor.rb +5 -1
- data/lib/prism/lex_compat.rb +1 -0
- data/lib/prism/mutation_compiler.rb +3 -0
- data/lib/prism/node.rb +554 -345
- data/lib/prism/node_ext.rb +4 -1
- data/lib/prism/pack.rb +2 -0
- data/lib/prism/parse_result/comments.rb +1 -0
- data/lib/prism/parse_result/errors.rb +1 -0
- data/lib/prism/parse_result/newlines.rb +2 -1
- data/lib/prism/parse_result.rb +53 -0
- data/lib/prism/pattern.rb +1 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/scan_byte.rb +14 -0
- data/lib/prism/polyfill/warn.rb +42 -0
- data/lib/prism/reflection.rb +5 -2
- data/lib/prism/relocation.rb +1 -0
- data/lib/prism/serialize.rb +1275 -783
- data/lib/prism/string_query.rb +1 -0
- data/lib/prism/translation/parser/builder.rb +62 -0
- data/lib/prism/translation/parser/compiler.rb +230 -152
- data/lib/prism/translation/parser/lexer.rb +446 -64
- data/lib/prism/translation/parser.rb +64 -4
- data/lib/prism/translation/parser33.rb +1 -0
- data/lib/prism/translation/parser34.rb +1 -0
- data/lib/prism/translation/parser35.rb +13 -0
- data/lib/prism/translation/parser_current.rb +24 -0
- data/lib/prism/translation/ripper/sexp.rb +1 -0
- data/lib/prism/translation/ripper.rb +30 -4
- data/lib/prism/translation/ruby_parser.rb +291 -7
- data/lib/prism/translation.rb +3 -0
- data/lib/prism/visitor.rb +457 -152
- data/lib/prism.rb +5 -3
- data/prism.gemspec +9 -1
- data/rbi/prism/dsl.rbi +9 -6
- data/rbi/prism/node.rbi +43 -16
- data/rbi/prism/parse_result.rbi +17 -0
- data/rbi/prism/translation/parser35.rbi +6 -0
- data/rbi/prism.rbi +39 -36
- data/sig/prism/dispatcher.rbs +3 -0
- data/sig/prism/dsl.rbs +7 -5
- data/sig/prism/node.rbs +461 -37
- data/sig/prism/node_ext.rbs +84 -17
- data/sig/prism/parse_result/comments.rbs +38 -0
- data/sig/prism/parse_result.rbs +14 -0
- data/sig/prism/reflection.rbs +1 -1
- data/sig/prism/serialize.rbs +4 -2
- data/sig/prism.rbs +22 -1
- data/src/diagnostic.c +9 -3
- data/src/node.c +23 -0
- data/src/options.c +33 -2
- data/src/prettyprint.c +32 -0
- data/src/prism.c +620 -242
- data/src/serialize.c +8 -0
- data/src/token_type.c +36 -34
- data/src/util/pm_buffer.c +40 -0
- data/src/util/pm_constant_pool.c +6 -2
- data/src/util/pm_strncasecmp.c +13 -1
- metadata +11 -7
data/ext/prism/extension.c
CHANGED
@@ -24,12 +24,14 @@ VALUE rb_cPrismParseResult;
|
|
24
24
|
VALUE rb_cPrismLexResult;
|
25
25
|
VALUE rb_cPrismParseLexResult;
|
26
26
|
VALUE rb_cPrismStringQuery;
|
27
|
+
VALUE rb_cPrismScope;
|
27
28
|
|
28
29
|
VALUE rb_cPrismDebugEncoding;
|
29
30
|
|
30
31
|
ID rb_id_option_command_line;
|
31
32
|
ID rb_id_option_encoding;
|
32
33
|
ID rb_id_option_filepath;
|
34
|
+
ID rb_id_option_freeze;
|
33
35
|
ID rb_id_option_frozen_string_literal;
|
34
36
|
ID rb_id_option_line;
|
35
37
|
ID rb_id_option_main_script;
|
@@ -37,6 +39,10 @@ ID rb_id_option_partial_script;
|
|
37
39
|
ID rb_id_option_scopes;
|
38
40
|
ID rb_id_option_version;
|
39
41
|
ID rb_id_source_for;
|
42
|
+
ID rb_id_forwarding_positionals;
|
43
|
+
ID rb_id_forwarding_keywords;
|
44
|
+
ID rb_id_forwarding_block;
|
45
|
+
ID rb_id_forwarding_all;
|
40
46
|
|
41
47
|
/******************************************************************************/
|
42
48
|
/* IO of Ruby code */
|
@@ -94,14 +100,53 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
94
100
|
for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
|
95
101
|
VALUE scope = rb_ary_entry(scopes, scope_index);
|
96
102
|
|
97
|
-
//
|
98
|
-
//
|
99
|
-
|
100
|
-
|
103
|
+
// The scope can be either an array or it can be a Prism::Scope object.
|
104
|
+
// Parse out the correct values here from either.
|
105
|
+
VALUE locals;
|
106
|
+
uint8_t forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
|
107
|
+
|
108
|
+
if (RB_TYPE_P(scope, T_ARRAY)) {
|
109
|
+
locals = scope;
|
110
|
+
} else if (rb_obj_is_kind_of(scope, rb_cPrismScope)) {
|
111
|
+
locals = rb_ivar_get(scope, rb_intern("@locals"));
|
112
|
+
if (!RB_TYPE_P(locals, T_ARRAY)) {
|
113
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(locals));
|
114
|
+
}
|
115
|
+
|
116
|
+
VALUE names = rb_ivar_get(scope, rb_intern("@forwarding"));
|
117
|
+
if (!RB_TYPE_P(names, T_ARRAY)) {
|
118
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(names));
|
119
|
+
}
|
120
|
+
|
121
|
+
size_t names_count = RARRAY_LEN(names);
|
122
|
+
for (size_t name_index = 0; name_index < names_count; name_index++) {
|
123
|
+
VALUE name = rb_ary_entry(names, name_index);
|
124
|
+
|
125
|
+
// Check that the name is a symbol. If it's not, then raise
|
126
|
+
// a type error.
|
127
|
+
if (!RB_TYPE_P(name, T_SYMBOL)) {
|
128
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(name));
|
129
|
+
}
|
130
|
+
|
131
|
+
ID id = SYM2ID(name);
|
132
|
+
if (id == rb_id_forwarding_positionals) {
|
133
|
+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS;
|
134
|
+
} else if (id == rb_id_forwarding_keywords) {
|
135
|
+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS;
|
136
|
+
} else if (id == rb_id_forwarding_block) {
|
137
|
+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_BLOCK;
|
138
|
+
} else if (id == rb_id_forwarding_all) {
|
139
|
+
forwarding |= PM_OPTIONS_SCOPE_FORWARDING_ALL;
|
140
|
+
} else {
|
141
|
+
rb_raise(rb_eArgError, "invalid forwarding value: %" PRIsVALUE, name);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
} else {
|
145
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array or Prism::Scope)", rb_obj_class(scope));
|
101
146
|
}
|
102
147
|
|
103
148
|
// Initialize the scope array.
|
104
|
-
size_t locals_count = RARRAY_LEN(
|
149
|
+
size_t locals_count = RARRAY_LEN(locals);
|
105
150
|
pm_options_scope_t *options_scope = &options->scopes[scope_index];
|
106
151
|
if (!pm_options_scope_init(options_scope, locals_count)) {
|
107
152
|
rb_raise(rb_eNoMemError, "failed to allocate memory");
|
@@ -109,7 +154,7 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
109
154
|
|
110
155
|
// Iterate over the locals and add them to the scope.
|
111
156
|
for (size_t local_index = 0; local_index < locals_count; local_index++) {
|
112
|
-
VALUE local = rb_ary_entry(
|
157
|
+
VALUE local = rb_ary_entry(locals, local_index);
|
113
158
|
|
114
159
|
// Check that the local is a symbol. If it's not, then raise a
|
115
160
|
// type error.
|
@@ -122,6 +167,9 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
122
167
|
const char *name = rb_id2name(SYM2ID(local));
|
123
168
|
pm_string_constant_init(scope_local, name, strlen(name));
|
124
169
|
}
|
170
|
+
|
171
|
+
// Now set the forwarding options.
|
172
|
+
pm_options_scope_forwarding_set(options_scope, forwarding);
|
125
173
|
}
|
126
174
|
}
|
127
175
|
|
@@ -180,6 +228,8 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
|
180
228
|
if (!NIL_P(value)) pm_options_main_script_set(options, RTEST(value));
|
181
229
|
} else if (key_id == rb_id_option_partial_script) {
|
182
230
|
if (!NIL_P(value)) pm_options_partial_script_set(options, RTEST(value));
|
231
|
+
} else if (key_id == rb_id_option_freeze) {
|
232
|
+
if (!NIL_P(value)) pm_options_freeze_set(options, RTEST(value));
|
183
233
|
} else {
|
184
234
|
rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, key);
|
185
235
|
}
|
@@ -344,6 +394,7 @@ dump(int argc, VALUE *argv, VALUE self) {
|
|
344
394
|
#endif
|
345
395
|
|
346
396
|
VALUE value = dump_input(&input, &options);
|
397
|
+
if (options.freeze) rb_obj_freeze(value);
|
347
398
|
|
348
399
|
#ifdef PRISM_BUILD_DEBUG
|
349
400
|
xfree(dup);
|
@@ -383,56 +434,90 @@ dump_file(int argc, VALUE *argv, VALUE self) {
|
|
383
434
|
/* Extracting values for the parse result */
|
384
435
|
/******************************************************************************/
|
385
436
|
|
437
|
+
/**
|
438
|
+
* The same as rb_class_new_instance, but accepts an additional boolean to
|
439
|
+
* indicate whether or not the resulting class instance should be frozen.
|
440
|
+
*/
|
441
|
+
static inline VALUE
|
442
|
+
rb_class_new_instance_freeze(int argc, const VALUE *argv, VALUE klass, bool freeze) {
|
443
|
+
VALUE value = rb_class_new_instance(argc, argv, klass);
|
444
|
+
if (freeze) rb_obj_freeze(value);
|
445
|
+
return value;
|
446
|
+
}
|
447
|
+
|
448
|
+
/**
|
449
|
+
* Create a new Location instance from the given parser and bounds.
|
450
|
+
*/
|
451
|
+
static inline VALUE
|
452
|
+
parser_location(const pm_parser_t *parser, VALUE source, bool freeze, const uint8_t *start, size_t length) {
|
453
|
+
VALUE argv[] = { source, LONG2FIX(start - parser->start), LONG2FIX(length) };
|
454
|
+
return rb_class_new_instance_freeze(3, argv, rb_cPrismLocation, freeze);
|
455
|
+
}
|
456
|
+
|
457
|
+
/**
|
458
|
+
* Create a new Location instance from the given parser and location.
|
459
|
+
*/
|
460
|
+
#define PARSER_LOCATION_LOC(parser, source, freeze, loc) \
|
461
|
+
parser_location(parser, source, freeze, loc.start, (size_t) (loc.end - loc.start))
|
462
|
+
|
463
|
+
/**
|
464
|
+
* Build a new Comment instance from the given parser and comment.
|
465
|
+
*/
|
466
|
+
static inline VALUE
|
467
|
+
parser_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_comment_t *comment) {
|
468
|
+
VALUE argv[] = { PARSER_LOCATION_LOC(parser, source, freeze, comment->location) };
|
469
|
+
VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
|
470
|
+
return rb_class_new_instance_freeze(1, argv, type, freeze);
|
471
|
+
}
|
472
|
+
|
386
473
|
/**
|
387
474
|
* Extract the comments out of the parser into an array.
|
388
475
|
*/
|
389
476
|
static VALUE
|
390
|
-
parser_comments(pm_parser_t *parser, VALUE source) {
|
477
|
+
parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
|
391
478
|
VALUE comments = rb_ary_new_capa(parser->comment_list.size);
|
392
479
|
|
393
|
-
for (
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
|
401
|
-
VALUE comment_argv[] = { rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
|
402
|
-
rb_ary_push(comments, rb_class_new_instance(1, comment_argv, type));
|
480
|
+
for (
|
481
|
+
const pm_comment_t *comment = (const pm_comment_t *) parser->comment_list.head;
|
482
|
+
comment != NULL;
|
483
|
+
comment = (const pm_comment_t *) comment->node.next
|
484
|
+
) {
|
485
|
+
VALUE value = parser_comment(parser, source, freeze, comment);
|
486
|
+
rb_ary_push(comments, value);
|
403
487
|
}
|
404
488
|
|
489
|
+
if (freeze) rb_obj_freeze(comments);
|
405
490
|
return comments;
|
406
491
|
}
|
407
492
|
|
493
|
+
/**
|
494
|
+
* Build a new MagicComment instance from the given parser and magic comment.
|
495
|
+
*/
|
496
|
+
static inline VALUE
|
497
|
+
parser_magic_comment(const pm_parser_t *parser, VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
|
498
|
+
VALUE key_loc = parser_location(parser, source, freeze, magic_comment->key_start, magic_comment->key_length);
|
499
|
+
VALUE value_loc = parser_location(parser, source, freeze, magic_comment->value_start, magic_comment->value_length);
|
500
|
+
VALUE argv[] = { key_loc, value_loc };
|
501
|
+
return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze);
|
502
|
+
}
|
503
|
+
|
408
504
|
/**
|
409
505
|
* Extract the magic comments out of the parser into an array.
|
410
506
|
*/
|
411
507
|
static VALUE
|
412
|
-
parser_magic_comments(pm_parser_t *parser, VALUE source) {
|
508
|
+
parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
|
413
509
|
VALUE magic_comments = rb_ary_new_capa(parser->magic_comment_list.size);
|
414
510
|
|
415
|
-
for (
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
VALUE value_loc_argv[] = {
|
423
|
-
source,
|
424
|
-
LONG2FIX(magic_comment->value_start - parser->start),
|
425
|
-
LONG2FIX(magic_comment->value_length)
|
426
|
-
};
|
427
|
-
|
428
|
-
VALUE magic_comment_argv[] = {
|
429
|
-
rb_class_new_instance(3, key_loc_argv, rb_cPrismLocation),
|
430
|
-
rb_class_new_instance(3, value_loc_argv, rb_cPrismLocation)
|
431
|
-
};
|
432
|
-
|
433
|
-
rb_ary_push(magic_comments, rb_class_new_instance(2, magic_comment_argv, rb_cPrismMagicComment));
|
511
|
+
for (
|
512
|
+
const pm_magic_comment_t *magic_comment = (const pm_magic_comment_t *) parser->magic_comment_list.head;
|
513
|
+
magic_comment != NULL;
|
514
|
+
magic_comment = (const pm_magic_comment_t *) magic_comment->node.next
|
515
|
+
) {
|
516
|
+
VALUE value = parser_magic_comment(parser, source, freeze, magic_comment);
|
517
|
+
rb_ary_push(magic_comments, value);
|
434
518
|
}
|
435
519
|
|
520
|
+
if (freeze) rb_obj_freeze(magic_comments);
|
436
521
|
return magic_comments;
|
437
522
|
}
|
438
523
|
|
@@ -441,17 +526,11 @@ parser_magic_comments(pm_parser_t *parser, VALUE source) {
|
|
441
526
|
* exists.
|
442
527
|
*/
|
443
528
|
static VALUE
|
444
|
-
parser_data_loc(const pm_parser_t *parser, VALUE source) {
|
529
|
+
parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
|
445
530
|
if (parser->data_loc.end == NULL) {
|
446
531
|
return Qnil;
|
447
532
|
} else {
|
448
|
-
|
449
|
-
source,
|
450
|
-
LONG2FIX(parser->data_loc.start - parser->start),
|
451
|
-
LONG2FIX(parser->data_loc.end - parser->data_loc.start)
|
452
|
-
};
|
453
|
-
|
454
|
-
return rb_class_new_instance(3, argv, rb_cPrismLocation);
|
533
|
+
return PARSER_LOCATION_LOC(parser, source, freeze, parser->data_loc);
|
455
534
|
}
|
456
535
|
}
|
457
536
|
|
@@ -459,16 +538,17 @@ parser_data_loc(const pm_parser_t *parser, VALUE source) {
|
|
459
538
|
* Extract the errors out of the parser into an array.
|
460
539
|
*/
|
461
540
|
static VALUE
|
462
|
-
parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
541
|
+
parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
|
463
542
|
VALUE errors = rb_ary_new_capa(parser->error_list.size);
|
464
|
-
pm_diagnostic_t *error;
|
465
543
|
|
466
|
-
for (
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
544
|
+
for (
|
545
|
+
const pm_diagnostic_t *error = (const pm_diagnostic_t *) parser->error_list.head;
|
546
|
+
error != NULL;
|
547
|
+
error = (const pm_diagnostic_t *) error->node.next
|
548
|
+
) {
|
549
|
+
VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id)));
|
550
|
+
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(error->message, encoding));
|
551
|
+
VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, error->location);
|
472
552
|
|
473
553
|
VALUE level = Qnil;
|
474
554
|
switch (error->level) {
|
@@ -485,16 +565,12 @@ parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
485
565
|
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level);
|
486
566
|
}
|
487
567
|
|
488
|
-
VALUE
|
489
|
-
|
490
|
-
|
491
|
-
rb_class_new_instance(3, location_argv, rb_cPrismLocation),
|
492
|
-
level
|
493
|
-
};
|
494
|
-
|
495
|
-
rb_ary_push(errors, rb_class_new_instance(4, error_argv, rb_cPrismParseError));
|
568
|
+
VALUE argv[] = { type, message, location, level };
|
569
|
+
VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, freeze);
|
570
|
+
rb_ary_push(errors, value);
|
496
571
|
}
|
497
572
|
|
573
|
+
if (freeze) rb_obj_freeze(errors);
|
498
574
|
return errors;
|
499
575
|
}
|
500
576
|
|
@@ -502,16 +578,17 @@ parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
502
578
|
* Extract the warnings out of the parser into an array.
|
503
579
|
*/
|
504
580
|
static VALUE
|
505
|
-
parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
581
|
+
parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
|
506
582
|
VALUE warnings = rb_ary_new_capa(parser->warning_list.size);
|
507
|
-
pm_diagnostic_t *warning;
|
508
583
|
|
509
|
-
for (
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
584
|
+
for (
|
585
|
+
const pm_diagnostic_t *warning = (const pm_diagnostic_t *) parser->warning_list.head;
|
586
|
+
warning != NULL;
|
587
|
+
warning = (const pm_diagnostic_t *) warning->node.next
|
588
|
+
) {
|
589
|
+
VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id)));
|
590
|
+
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(warning->message, encoding));
|
591
|
+
VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, warning->location);
|
515
592
|
|
516
593
|
VALUE level = Qnil;
|
517
594
|
switch (warning->level) {
|
@@ -525,16 +602,12 @@ parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
525
602
|
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level);
|
526
603
|
}
|
527
604
|
|
528
|
-
VALUE
|
529
|
-
|
530
|
-
|
531
|
-
rb_class_new_instance(3, location_argv, rb_cPrismLocation),
|
532
|
-
level
|
533
|
-
};
|
534
|
-
|
535
|
-
rb_ary_push(warnings, rb_class_new_instance(4, warning_argv, rb_cPrismParseWarning));
|
605
|
+
VALUE argv[] = { type, message, location, level };
|
606
|
+
VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, freeze);
|
607
|
+
rb_ary_push(warnings, value);
|
536
608
|
}
|
537
609
|
|
610
|
+
if (freeze) rb_obj_freeze(warnings);
|
538
611
|
return warnings;
|
539
612
|
}
|
540
613
|
|
@@ -542,18 +615,18 @@ parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
542
615
|
* Create a new parse result from the given parser, value, encoding, and source.
|
543
616
|
*/
|
544
617
|
static VALUE
|
545
|
-
parse_result_create(VALUE class, pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source) {
|
618
|
+
parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source, bool freeze) {
|
546
619
|
VALUE result_argv[] = {
|
547
620
|
value,
|
548
|
-
parser_comments(parser, source),
|
549
|
-
parser_magic_comments(parser, source),
|
550
|
-
parser_data_loc(parser, source),
|
551
|
-
parser_errors(parser, encoding, source),
|
552
|
-
parser_warnings(parser, encoding, source),
|
621
|
+
parser_comments(parser, source, freeze),
|
622
|
+
parser_magic_comments(parser, source, freeze),
|
623
|
+
parser_data_loc(parser, source, freeze),
|
624
|
+
parser_errors(parser, encoding, source, freeze),
|
625
|
+
parser_warnings(parser, encoding, source, freeze),
|
553
626
|
source
|
554
627
|
};
|
555
628
|
|
556
|
-
return
|
629
|
+
return rb_class_new_instance_freeze(7, result_argv, class, freeze);
|
557
630
|
}
|
558
631
|
|
559
632
|
/******************************************************************************/
|
@@ -569,6 +642,7 @@ typedef struct {
|
|
569
642
|
VALUE source;
|
570
643
|
VALUE tokens;
|
571
644
|
rb_encoding *encoding;
|
645
|
+
bool freeze;
|
572
646
|
} parse_lex_data_t;
|
573
647
|
|
574
648
|
/**
|
@@ -580,10 +654,13 @@ static void
|
|
580
654
|
parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
|
581
655
|
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
|
582
656
|
|
583
|
-
VALUE
|
584
|
-
|
585
|
-
|
586
|
-
)
|
657
|
+
VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze);
|
658
|
+
VALUE yields = rb_assoc_new(value, INT2FIX(parser->lex_state));
|
659
|
+
|
660
|
+
if (parse_lex_data->freeze) {
|
661
|
+
rb_obj_freeze(value);
|
662
|
+
rb_obj_freeze(yields);
|
663
|
+
}
|
587
664
|
|
588
665
|
rb_ary_push(parse_lex_data->tokens, yields);
|
589
666
|
}
|
@@ -603,14 +680,37 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
|
603
680
|
// one or two tokens, since the encoding can only change at the top of the
|
604
681
|
// file.
|
605
682
|
VALUE tokens = parse_lex_data->tokens;
|
683
|
+
VALUE next_tokens = rb_ary_new();
|
684
|
+
|
606
685
|
for (long index = 0; index < RARRAY_LEN(tokens); index++) {
|
607
686
|
VALUE yields = rb_ary_entry(tokens, index);
|
608
687
|
VALUE token = rb_ary_entry(yields, 0);
|
609
688
|
|
610
689
|
VALUE value = rb_ivar_get(token, rb_intern("@value"));
|
611
|
-
|
612
|
-
|
690
|
+
VALUE next_value = rb_str_dup(value);
|
691
|
+
|
692
|
+
rb_enc_associate(next_value, parse_lex_data->encoding);
|
693
|
+
if (parse_lex_data->freeze) rb_obj_freeze(next_value);
|
694
|
+
|
695
|
+
VALUE next_token_argv[] = {
|
696
|
+
parse_lex_data->source,
|
697
|
+
rb_ivar_get(token, rb_intern("@type")),
|
698
|
+
next_value,
|
699
|
+
rb_ivar_get(token, rb_intern("@location"))
|
700
|
+
};
|
701
|
+
|
702
|
+
VALUE next_token = rb_class_new_instance(4, next_token_argv, rb_cPrismToken);
|
703
|
+
VALUE next_yields = rb_assoc_new(next_token, rb_ary_entry(yields, 1));
|
704
|
+
|
705
|
+
if (parse_lex_data->freeze) {
|
706
|
+
rb_obj_freeze(next_token);
|
707
|
+
rb_obj_freeze(next_yields);
|
708
|
+
}
|
709
|
+
|
710
|
+
rb_ary_push(next_tokens, next_yields);
|
613
711
|
}
|
712
|
+
|
713
|
+
rb_ary_replace(parse_lex_data->tokens, next_tokens);
|
614
714
|
}
|
615
715
|
|
616
716
|
/**
|
@@ -630,7 +730,8 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
630
730
|
parse_lex_data_t parse_lex_data = {
|
631
731
|
.source = source,
|
632
732
|
.tokens = rb_ary_new(),
|
633
|
-
.encoding = rb_utf8_encoding()
|
733
|
+
.encoding = rb_utf8_encoding(),
|
734
|
+
.freeze = options->freeze,
|
634
735
|
};
|
635
736
|
|
636
737
|
parse_lex_data_t *data = &parse_lex_data;
|
@@ -653,14 +754,22 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
653
754
|
rb_ary_push(offsets, ULONG2NUM(parser.newline_list.offsets[index]));
|
654
755
|
}
|
655
756
|
|
757
|
+
if (options->freeze) {
|
758
|
+
rb_obj_freeze(source_string);
|
759
|
+
rb_obj_freeze(offsets);
|
760
|
+
rb_obj_freeze(source);
|
761
|
+
rb_obj_freeze(parse_lex_data.tokens);
|
762
|
+
}
|
763
|
+
|
656
764
|
VALUE result;
|
657
765
|
if (return_nodes) {
|
658
766
|
VALUE value = rb_ary_new_capa(2);
|
659
|
-
rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source));
|
767
|
+
rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source, options->freeze));
|
660
768
|
rb_ary_push(value, parse_lex_data.tokens);
|
661
|
-
|
769
|
+
if (options->freeze) rb_obj_freeze(value);
|
770
|
+
result = parse_result_create(rb_cPrismParseLexResult, &parser, value, parse_lex_data.encoding, source, options->freeze);
|
662
771
|
} else {
|
663
|
-
result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source);
|
772
|
+
result = parse_result_create(rb_cPrismLexResult, &parser, parse_lex_data.tokens, parse_lex_data.encoding, source, options->freeze);
|
664
773
|
}
|
665
774
|
|
666
775
|
pm_node_destroy(&parser, node);
|
@@ -726,9 +835,13 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
726
835
|
pm_node_t *node = pm_parse(&parser);
|
727
836
|
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
728
837
|
|
729
|
-
VALUE source = pm_source_new(&parser, encoding);
|
730
|
-
VALUE value = pm_ast_new(&parser, node, encoding, source);
|
731
|
-
VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source)
|
838
|
+
VALUE source = pm_source_new(&parser, encoding, options->freeze);
|
839
|
+
VALUE value = pm_ast_new(&parser, node, encoding, source, options->freeze);
|
840
|
+
VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options->freeze);
|
841
|
+
|
842
|
+
if (options->freeze) {
|
843
|
+
rb_obj_freeze(source);
|
844
|
+
}
|
732
845
|
|
733
846
|
pm_node_destroy(&parser, node);
|
734
847
|
pm_parser_free(&parser);
|
@@ -750,6 +863,8 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
750
863
|
* encoding or nil.
|
751
864
|
* * `filepath` - the filepath of the source being parsed. This should be a
|
752
865
|
* string or nil.
|
866
|
+
* * `freeze` - whether or not to deeply freeze the AST. This should be a
|
867
|
+
* boolean or nil.
|
753
868
|
* * `frozen_string_literal` - whether or not the frozen string literal pragma
|
754
869
|
* has been set. This should be a boolean or nil.
|
755
870
|
* * `line` - the line number that the parse starts on. This should be an
|
@@ -769,12 +884,12 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
769
884
|
* parsed. This should be an array of arrays of symbols or nil. Scopes are
|
770
885
|
* ordered from the outermost scope to the innermost one.
|
771
886
|
* * `version` - the version of Ruby syntax that prism should used to parse Ruby
|
772
|
-
* code. By default prism assumes you want to parse with the latest
|
773
|
-
* of Ruby syntax (which you can trigger with `nil` or
|
774
|
-
* may also restrict the syntax to a specific version of
|
775
|
-
* To parse with the same syntax version that
|
776
|
-
* use `version: RUBY_VERSION`. Raises
|
777
|
-
* currently supported by Prism.
|
887
|
+
* code. By default prism assumes you want to parse with the latest
|
888
|
+
* version of Ruby syntax (which you can trigger with `nil` or
|
889
|
+
* `"latest"`). You may also restrict the syntax to a specific version of
|
890
|
+
* Ruby, e.g., with `"3.3.0"`. To parse with the same syntax version that
|
891
|
+
* the current Ruby is running use `version: RUBY_VERSION`. Raises
|
892
|
+
* ArgumentError if the version is not currently supported by Prism.
|
778
893
|
*/
|
779
894
|
static VALUE
|
780
895
|
parse(int argc, VALUE *argv, VALUE self) {
|
@@ -879,6 +994,14 @@ profile_file(int argc, VALUE *argv, VALUE self) {
|
|
879
994
|
return Qnil;
|
880
995
|
}
|
881
996
|
|
997
|
+
static int
|
998
|
+
parse_stream_eof(void *stream) {
|
999
|
+
if (rb_funcall((VALUE) stream, rb_intern("eof?"), 0)) {
|
1000
|
+
return 1;
|
1001
|
+
}
|
1002
|
+
return 0;
|
1003
|
+
}
|
1004
|
+
|
882
1005
|
/**
|
883
1006
|
* An implementation of fgets that is suitable for use with Ruby IO objects.
|
884
1007
|
*/
|
@@ -919,12 +1042,12 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
|
|
919
1042
|
pm_parser_t parser;
|
920
1043
|
pm_buffer_t buffer;
|
921
1044
|
|
922
|
-
pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
|
1045
|
+
pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, parse_stream_eof, &options);
|
923
1046
|
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
924
1047
|
|
925
|
-
VALUE source = pm_source_new(&parser, encoding);
|
926
|
-
VALUE value = pm_ast_new(&parser, node, encoding, source);
|
927
|
-
VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source);
|
1048
|
+
VALUE source = pm_source_new(&parser, encoding, options.freeze);
|
1049
|
+
VALUE value = pm_ast_new(&parser, node, encoding, source, options.freeze);
|
1050
|
+
VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options.freeze);
|
928
1051
|
|
929
1052
|
pm_node_destroy(&parser, node);
|
930
1053
|
pm_buffer_free(&buffer);
|
@@ -944,8 +1067,8 @@ parse_input_comments(pm_string_t *input, const pm_options_t *options) {
|
|
944
1067
|
pm_node_t *node = pm_parse(&parser);
|
945
1068
|
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
946
1069
|
|
947
|
-
VALUE source = pm_source_new(&parser, encoding);
|
948
|
-
VALUE comments = parser_comments(&parser, source);
|
1070
|
+
VALUE source = pm_source_new(&parser, encoding, options->freeze);
|
1071
|
+
VALUE comments = parser_comments(&parser, source, options->freeze);
|
949
1072
|
|
950
1073
|
pm_node_destroy(&parser, node);
|
951
1074
|
pm_parser_free(&parser);
|
@@ -1216,6 +1339,11 @@ Init_prism(void) {
|
|
1216
1339
|
);
|
1217
1340
|
}
|
1218
1341
|
|
1342
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
1343
|
+
// Mark this extension as Ractor-safe.
|
1344
|
+
rb_ext_ractor_safe(true);
|
1345
|
+
#endif
|
1346
|
+
|
1219
1347
|
// Grab up references to all of the constants that we're going to need to
|
1220
1348
|
// reference throughout this extension.
|
1221
1349
|
rb_cPrism = rb_define_module("Prism");
|
@@ -1234,12 +1362,14 @@ Init_prism(void) {
|
|
1234
1362
|
rb_cPrismLexResult = rb_define_class_under(rb_cPrism, "LexResult", rb_cPrismResult);
|
1235
1363
|
rb_cPrismParseLexResult = rb_define_class_under(rb_cPrism, "ParseLexResult", rb_cPrismResult);
|
1236
1364
|
rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
|
1365
|
+
rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
|
1237
1366
|
|
1238
1367
|
// Intern all of the IDs eagerly that we support so that we don't have to do
|
1239
1368
|
// it every time we parse.
|
1240
1369
|
rb_id_option_command_line = rb_intern_const("command_line");
|
1241
1370
|
rb_id_option_encoding = rb_intern_const("encoding");
|
1242
1371
|
rb_id_option_filepath = rb_intern_const("filepath");
|
1372
|
+
rb_id_option_freeze = rb_intern_const("freeze");
|
1243
1373
|
rb_id_option_frozen_string_literal = rb_intern_const("frozen_string_literal");
|
1244
1374
|
rb_id_option_line = rb_intern_const("line");
|
1245
1375
|
rb_id_option_main_script = rb_intern_const("main_script");
|
@@ -1247,11 +1377,15 @@ Init_prism(void) {
|
|
1247
1377
|
rb_id_option_scopes = rb_intern_const("scopes");
|
1248
1378
|
rb_id_option_version = rb_intern_const("version");
|
1249
1379
|
rb_id_source_for = rb_intern("for");
|
1380
|
+
rb_id_forwarding_positionals = rb_intern("*");
|
1381
|
+
rb_id_forwarding_keywords = rb_intern("**");
|
1382
|
+
rb_id_forwarding_block = rb_intern("&");
|
1383
|
+
rb_id_forwarding_all = rb_intern("...");
|
1250
1384
|
|
1251
1385
|
/**
|
1252
1386
|
* The version of the prism library.
|
1253
1387
|
*/
|
1254
|
-
rb_define_const(rb_cPrism, "VERSION",
|
1388
|
+
rb_define_const(rb_cPrism, "VERSION", rb_str_freeze(rb_str_new_cstr(EXPECTED_PRISM_VERSION)));
|
1255
1389
|
|
1256
1390
|
// First, the functions that have to do with lexing and parsing.
|
1257
1391
|
rb_define_singleton_method(rb_cPrism, "lex", lex, -1);
|
data/ext/prism/extension.h
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
#ifndef PRISM_EXT_NODE_H
|
2
2
|
#define PRISM_EXT_NODE_H
|
3
3
|
|
4
|
-
#define EXPECTED_PRISM_VERSION "1.
|
4
|
+
#define EXPECTED_PRISM_VERSION "1.5.0"
|
5
5
|
|
6
6
|
#include <ruby.h>
|
7
7
|
#include <ruby/encoding.h>
|
8
8
|
#include "prism.h"
|
9
9
|
|
10
|
-
VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding);
|
11
|
-
VALUE pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source);
|
12
|
-
VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source);
|
10
|
+
VALUE pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze);
|
11
|
+
VALUE pm_token_new(const pm_parser_t *parser, const pm_token_t *token, rb_encoding *encoding, VALUE source, bool freeze);
|
12
|
+
VALUE pm_ast_new(const pm_parser_t *parser, const pm_node_t *node, rb_encoding *encoding, VALUE source, bool freeze);
|
13
13
|
VALUE pm_integer_new(const pm_integer_t *integer);
|
14
14
|
|
15
15
|
void Init_prism_api_node(void);
|