prism 1.3.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 +24 -1
- data/config.yml +9 -0
- data/docs/releasing.md +1 -1
- data/docs/ruby_api.md +1 -1
- data/ext/prism/api_node.c +1814 -1303
- data/ext/prism/extension.c +230 -109
- data/ext/prism/extension.h +4 -4
- data/include/prism/ast.h +16 -0
- data/include/prism/defines.h +4 -1
- 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 +4 -4
- data/lib/prism/dot_visitor.rb +16 -0
- data/lib/prism/dsl.rb +10 -2
- data/lib/prism/ffi.rb +45 -27
- data/lib/prism/inspect_visitor.rb +2 -1
- data/lib/prism/node.rb +48 -10
- data/lib/prism/parse_result/newlines.rb +1 -1
- data/lib/prism/parse_result.rb +52 -0
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/reflection.rb +2 -2
- data/lib/prism/serialize.rb +1252 -765
- data/lib/prism/translation/parser/builder.rb +61 -0
- data/lib/prism/translation/parser/compiler.rb +192 -136
- 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 +5 -4
- data/lib/prism/translation.rb +1 -0
- data/lib/prism.rb +3 -3
- data/prism.gemspec +5 -1
- data/rbi/prism/dsl.rbi +6 -3
- data/rbi/prism/node.rbi +22 -7
- 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/dsl.rbs +4 -2
- data/sig/prism/node.rbs +17 -7
- data/sig/prism/parse_result.rbs +10 -0
- data/sig/prism/serialize.rbs +4 -2
- data/sig/prism.rbs +22 -1
- data/src/diagnostic.c +2 -2
- data/src/node.c +21 -0
- data/src/options.c +31 -0
- data/src/prettyprint.c +30 -0
- data/src/prism.c +374 -118
- data/src/serialize.c +6 -0
- 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 +7 -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) {
|
@@ -922,9 +1037,9 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
|
|
922
1037
|
pm_node_t *node = pm_parse_stream(&parser, &buffer, (void *) stream, parse_stream_fgets, &options);
|
923
1038
|
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
924
1039
|
|
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);
|
1040
|
+
VALUE source = pm_source_new(&parser, encoding, options.freeze);
|
1041
|
+
VALUE value = pm_ast_new(&parser, node, encoding, source, options.freeze);
|
1042
|
+
VALUE result = parse_result_create(rb_cPrismParseResult, &parser, value, encoding, source, options.freeze);
|
928
1043
|
|
929
1044
|
pm_node_destroy(&parser, node);
|
930
1045
|
pm_buffer_free(&buffer);
|
@@ -944,8 +1059,8 @@ parse_input_comments(pm_string_t *input, const pm_options_t *options) {
|
|
944
1059
|
pm_node_t *node = pm_parse(&parser);
|
945
1060
|
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
946
1061
|
|
947
|
-
VALUE source = pm_source_new(&parser, encoding);
|
948
|
-
VALUE comments = parser_comments(&parser, source);
|
1062
|
+
VALUE source = pm_source_new(&parser, encoding, options->freeze);
|
1063
|
+
VALUE comments = parser_comments(&parser, source, options->freeze);
|
949
1064
|
|
950
1065
|
pm_node_destroy(&parser, node);
|
951
1066
|
pm_parser_free(&parser);
|
@@ -1234,12 +1349,14 @@ Init_prism(void) {
|
|
1234
1349
|
rb_cPrismLexResult = rb_define_class_under(rb_cPrism, "LexResult", rb_cPrismResult);
|
1235
1350
|
rb_cPrismParseLexResult = rb_define_class_under(rb_cPrism, "ParseLexResult", rb_cPrismResult);
|
1236
1351
|
rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
|
1352
|
+
rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
|
1237
1353
|
|
1238
1354
|
// Intern all of the IDs eagerly that we support so that we don't have to do
|
1239
1355
|
// it every time we parse.
|
1240
1356
|
rb_id_option_command_line = rb_intern_const("command_line");
|
1241
1357
|
rb_id_option_encoding = rb_intern_const("encoding");
|
1242
1358
|
rb_id_option_filepath = rb_intern_const("filepath");
|
1359
|
+
rb_id_option_freeze = rb_intern_const("freeze");
|
1243
1360
|
rb_id_option_frozen_string_literal = rb_intern_const("frozen_string_literal");
|
1244
1361
|
rb_id_option_line = rb_intern_const("line");
|
1245
1362
|
rb_id_option_main_script = rb_intern_const("main_script");
|
@@ -1247,11 +1364,15 @@ Init_prism(void) {
|
|
1247
1364
|
rb_id_option_scopes = rb_intern_const("scopes");
|
1248
1365
|
rb_id_option_version = rb_intern_const("version");
|
1249
1366
|
rb_id_source_for = rb_intern("for");
|
1367
|
+
rb_id_forwarding_positionals = rb_intern("*");
|
1368
|
+
rb_id_forwarding_keywords = rb_intern("**");
|
1369
|
+
rb_id_forwarding_block = rb_intern("&");
|
1370
|
+
rb_id_forwarding_all = rb_intern("...");
|
1250
1371
|
|
1251
1372
|
/**
|
1252
1373
|
* The version of the prism library.
|
1253
1374
|
*/
|
1254
|
-
rb_define_const(rb_cPrism, "VERSION",
|
1375
|
+
rb_define_const(rb_cPrism, "VERSION", rb_str_freeze(rb_str_new_cstr(EXPECTED_PRISM_VERSION)));
|
1255
1376
|
|
1256
1377
|
// First, the functions that have to do with lexing and parsing.
|
1257
1378
|
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.4.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);
|
data/include/prism/ast.h
CHANGED
@@ -6441,6 +6441,9 @@ typedef struct pm_parameters_node {
|
|
6441
6441
|
* ^^^^^^^^^
|
6442
6442
|
*
|
6443
6443
|
* Type: ::PM_PARENTHESES_NODE
|
6444
|
+
|
6445
|
+
* Flags (#pm_parentheses_node_flags):
|
6446
|
+
* * ::PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS
|
6444
6447
|
*
|
6445
6448
|
* @extends pm_node_t
|
6446
6449
|
*/
|
@@ -6935,6 +6938,11 @@ typedef struct pm_rescue_node {
|
|
6935
6938
|
*/
|
6936
6939
|
struct pm_node *reference;
|
6937
6940
|
|
6941
|
+
/**
|
6942
|
+
* RescueNode#then_keyword_loc
|
6943
|
+
*/
|
6944
|
+
pm_location_t then_keyword_loc;
|
6945
|
+
|
6938
6946
|
/**
|
6939
6947
|
* RescueNode#statements
|
6940
6948
|
*/
|
@@ -7846,6 +7854,14 @@ typedef enum pm_parameter_flags {
|
|
7846
7854
|
PM_PARAMETER_FLAGS_REPEATED_PARAMETER = 4,
|
7847
7855
|
} pm_parameter_flags_t;
|
7848
7856
|
|
7857
|
+
/**
|
7858
|
+
* Flags for parentheses nodes.
|
7859
|
+
*/
|
7860
|
+
typedef enum pm_parentheses_node_flags {
|
7861
|
+
/** parentheses that contain multiple potentially void statements */
|
7862
|
+
PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS = 4,
|
7863
|
+
} pm_parentheses_node_flags_t;
|
7864
|
+
|
7849
7865
|
/**
|
7850
7866
|
* Flags for range and flip-flop nodes.
|
7851
7867
|
*/
|
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
|
/**
|