prism 0.19.0 → 0.24.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 +102 -1
- data/Makefile +5 -0
- data/README.md +9 -6
- data/config.yml +236 -38
- data/docs/build_system.md +19 -2
- data/docs/cruby_compilation.md +27 -0
- data/docs/parser_translation.md +34 -0
- data/docs/parsing_rules.md +19 -0
- data/docs/releasing.md +84 -16
- data/docs/ruby_api.md +1 -1
- data/docs/ruby_parser_translation.md +19 -0
- data/docs/serialization.md +19 -5
- data/ext/prism/api_node.c +1989 -1525
- data/ext/prism/extension.c +130 -30
- data/ext/prism/extension.h +2 -2
- data/include/prism/ast.h +1700 -505
- data/include/prism/defines.h +8 -0
- data/include/prism/diagnostic.h +49 -7
- data/include/prism/encoding.h +17 -0
- data/include/prism/options.h +40 -14
- data/include/prism/parser.h +34 -18
- data/include/prism/util/pm_buffer.h +9 -0
- data/include/prism/util/pm_constant_pool.h +18 -0
- data/include/prism/util/pm_newline_list.h +4 -14
- data/include/prism/util/pm_strpbrk.h +4 -1
- data/include/prism/version.h +2 -2
- data/include/prism.h +19 -2
- data/lib/prism/debug.rb +11 -5
- data/lib/prism/desugar_compiler.rb +225 -80
- data/lib/prism/dot_visitor.rb +36 -14
- data/lib/prism/dsl.rb +302 -299
- data/lib/prism/ffi.rb +107 -76
- data/lib/prism/lex_compat.rb +17 -1
- data/lib/prism/node.rb +4580 -2607
- data/lib/prism/node_ext.rb +27 -4
- data/lib/prism/parse_result.rb +75 -29
- data/lib/prism/serialize.rb +633 -305
- data/lib/prism/translation/parser/compiler.rb +1838 -0
- data/lib/prism/translation/parser/lexer.rb +335 -0
- data/lib/prism/translation/parser/rubocop.rb +45 -0
- data/lib/prism/translation/parser.rb +190 -0
- data/lib/prism/translation/parser33.rb +12 -0
- data/lib/prism/translation/parser34.rb +12 -0
- data/lib/prism/translation/ripper.rb +696 -0
- data/lib/prism/translation/ruby_parser.rb +1521 -0
- data/lib/prism/translation.rb +11 -0
- data/lib/prism.rb +1 -1
- data/prism.gemspec +18 -7
- data/rbi/prism.rbi +150 -88
- data/rbi/prism_static.rbi +15 -3
- data/sig/prism.rbs +996 -961
- data/sig/prism_static.rbs +123 -46
- data/src/diagnostic.c +264 -219
- data/src/encoding.c +21 -26
- data/src/node.c +2 -6
- data/src/options.c +29 -5
- data/src/prettyprint.c +176 -44
- data/src/prism.c +1499 -564
- data/src/serialize.c +35 -21
- data/src/token_type.c +353 -4
- data/src/util/pm_buffer.c +11 -0
- data/src/util/pm_constant_pool.c +37 -11
- data/src/util/pm_newline_list.c +6 -15
- data/src/util/pm_string.c +0 -7
- data/src/util/pm_strpbrk.c +122 -14
- metadata +16 -5
- data/docs/building.md +0 -29
- data/lib/prism/ripper_compat.rb +0 -207
data/ext/prism/extension.c
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
#include "prism/extension.h"
|
2
2
|
|
3
|
+
#ifdef _WIN32
|
4
|
+
#include <ruby/win32.h>
|
5
|
+
#endif
|
6
|
+
|
3
7
|
// NOTE: this file should contain only bindings. All non-trivial logic should be
|
4
8
|
// in libprism so it can be shared its the various callers.
|
5
9
|
|
@@ -21,7 +25,7 @@ ID rb_option_id_filepath;
|
|
21
25
|
ID rb_option_id_encoding;
|
22
26
|
ID rb_option_id_line;
|
23
27
|
ID rb_option_id_frozen_string_literal;
|
24
|
-
ID
|
28
|
+
ID rb_option_id_version;
|
25
29
|
ID rb_option_id_scopes;
|
26
30
|
|
27
31
|
/******************************************************************************/
|
@@ -129,8 +133,14 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
|
129
133
|
if (!NIL_P(value)) pm_options_line_set(options, NUM2INT(value));
|
130
134
|
} else if (key_id == rb_option_id_frozen_string_literal) {
|
131
135
|
if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue);
|
132
|
-
} else if (key_id ==
|
133
|
-
|
136
|
+
} else if (key_id == rb_option_id_version) {
|
137
|
+
if (!NIL_P(value)) {
|
138
|
+
const char *version = check_string(value);
|
139
|
+
|
140
|
+
if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
|
141
|
+
rb_raise(rb_eArgError, "invalid version: %"PRIsVALUE, value);
|
142
|
+
}
|
143
|
+
}
|
134
144
|
} else if (key_id == rb_option_id_scopes) {
|
135
145
|
if (!NIL_P(value)) build_options_scopes(options, value);
|
136
146
|
} else {
|
@@ -206,20 +216,29 @@ string_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options)
|
|
206
216
|
/**
|
207
217
|
* Read options for methods that look like (filepath, **options).
|
208
218
|
*/
|
209
|
-
static
|
219
|
+
static void
|
210
220
|
file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) {
|
211
221
|
VALUE filepath;
|
212
222
|
VALUE keywords;
|
213
223
|
rb_scan_args(argc, argv, "1:", &filepath, &keywords);
|
214
224
|
|
225
|
+
Check_Type(filepath, T_STRING);
|
226
|
+
|
215
227
|
extract_options(options, filepath, keywords);
|
216
228
|
|
217
|
-
|
229
|
+
const char * string_source = (const char *) pm_string_source(&options->filepath);
|
230
|
+
|
231
|
+
if (!pm_string_mapped_init(input, string_source)) {
|
218
232
|
pm_options_free(options);
|
219
|
-
return false;
|
220
|
-
}
|
221
233
|
|
222
|
-
|
234
|
+
#ifdef _WIN32
|
235
|
+
int e = rb_w32_map_errno(GetLastError());
|
236
|
+
#else
|
237
|
+
int e = errno;
|
238
|
+
#endif
|
239
|
+
|
240
|
+
rb_syserr_fail(e, string_source);
|
241
|
+
}
|
223
242
|
}
|
224
243
|
|
225
244
|
/******************************************************************************/
|
@@ -293,7 +312,8 @@ static VALUE
|
|
293
312
|
dump_file(int argc, VALUE *argv, VALUE self) {
|
294
313
|
pm_string_t input;
|
295
314
|
pm_options_t options = { 0 };
|
296
|
-
|
315
|
+
|
316
|
+
file_options(argc, argv, &input, &options);
|
297
317
|
|
298
318
|
VALUE value = dump_input(&input, &options);
|
299
319
|
pm_string_free(&input);
|
@@ -393,12 +413,25 @@ parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
393
413
|
LONG2FIX(error->location.end - error->location.start)
|
394
414
|
};
|
395
415
|
|
416
|
+
VALUE level = Qnil;
|
417
|
+
switch (error->level) {
|
418
|
+
case PM_ERROR_LEVEL_FATAL:
|
419
|
+
level = ID2SYM(rb_intern("fatal"));
|
420
|
+
break;
|
421
|
+
case PM_ERROR_LEVEL_ARGUMENT:
|
422
|
+
level = ID2SYM(rb_intern("argument"));
|
423
|
+
break;
|
424
|
+
default:
|
425
|
+
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level);
|
426
|
+
}
|
427
|
+
|
396
428
|
VALUE error_argv[] = {
|
397
429
|
rb_enc_str_new_cstr(error->message, encoding),
|
398
|
-
rb_class_new_instance(3, location_argv, rb_cPrismLocation)
|
430
|
+
rb_class_new_instance(3, location_argv, rb_cPrismLocation),
|
431
|
+
level
|
399
432
|
};
|
400
433
|
|
401
|
-
rb_ary_push(errors, rb_class_new_instance(
|
434
|
+
rb_ary_push(errors, rb_class_new_instance(3, error_argv, rb_cPrismParseError));
|
402
435
|
}
|
403
436
|
|
404
437
|
return errors;
|
@@ -419,12 +452,25 @@ parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
419
452
|
LONG2FIX(warning->location.end - warning->location.start)
|
420
453
|
};
|
421
454
|
|
455
|
+
VALUE level = Qnil;
|
456
|
+
switch (warning->level) {
|
457
|
+
case PM_WARNING_LEVEL_DEFAULT:
|
458
|
+
level = ID2SYM(rb_intern("default"));
|
459
|
+
break;
|
460
|
+
case PM_WARNING_LEVEL_VERBOSE:
|
461
|
+
level = ID2SYM(rb_intern("verbose"));
|
462
|
+
break;
|
463
|
+
default:
|
464
|
+
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level);
|
465
|
+
}
|
466
|
+
|
422
467
|
VALUE warning_argv[] = {
|
423
468
|
rb_enc_str_new_cstr(warning->message, encoding),
|
424
|
-
rb_class_new_instance(3, location_argv, rb_cPrismLocation)
|
469
|
+
rb_class_new_instance(3, location_argv, rb_cPrismLocation),
|
470
|
+
level
|
425
471
|
};
|
426
472
|
|
427
|
-
rb_ary_push(warnings, rb_class_new_instance(
|
473
|
+
rb_ary_push(warnings, rb_class_new_instance(3, warning_argv, rb_cPrismParseWarning));
|
428
474
|
}
|
429
475
|
|
430
476
|
return warnings;
|
@@ -496,8 +542,9 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
496
542
|
pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
|
497
543
|
pm_parser_register_encoding_changed_callback(&parser, parse_lex_encoding_changed_callback);
|
498
544
|
|
545
|
+
VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input));
|
499
546
|
VALUE offsets = rb_ary_new();
|
500
|
-
VALUE source_argv[] = {
|
547
|
+
VALUE source_argv[] = { source_string, LONG2NUM(parser.start_line), offsets };
|
501
548
|
VALUE source = rb_class_new_instance(3, source_argv, rb_cPrismSource);
|
502
549
|
|
503
550
|
parse_lex_data_t parse_lex_data = {
|
@@ -515,17 +562,21 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
515
562
|
parser.lex_callback = &lex_callback;
|
516
563
|
pm_node_t *node = pm_parse(&parser);
|
517
564
|
|
518
|
-
// Here we need to update the
|
519
|
-
//
|
520
|
-
// it
|
565
|
+
// Here we need to update the Source object to have the correct
|
566
|
+
// encoding for the source string and the correct newline offsets.
|
567
|
+
// We do it here because we've already created the Source object and given
|
568
|
+
// it over to all of the tokens, and both of these are only set after pm_parse().
|
569
|
+
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
570
|
+
rb_enc_associate(source_string, encoding);
|
571
|
+
|
521
572
|
for (size_t index = 0; index < parser.newline_list.size; index++) {
|
522
|
-
rb_ary_push(offsets,
|
573
|
+
rb_ary_push(offsets, ULONG2NUM(parser.newline_list.offsets[index]));
|
523
574
|
}
|
524
575
|
|
525
576
|
VALUE value;
|
526
577
|
if (return_nodes) {
|
527
578
|
value = rb_ary_new_capa(2);
|
528
|
-
rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding));
|
579
|
+
rb_ary_push(value, pm_ast_new(&parser, node, parse_lex_data.encoding, source));
|
529
580
|
rb_ary_push(value, parse_lex_data.tokens);
|
530
581
|
} else {
|
531
582
|
value = parse_lex_data.tokens;
|
@@ -577,7 +628,8 @@ static VALUE
|
|
577
628
|
lex_file(int argc, VALUE *argv, VALUE self) {
|
578
629
|
pm_string_t input;
|
579
630
|
pm_options_t options = { 0 };
|
580
|
-
|
631
|
+
|
632
|
+
file_options(argc, argv, &input, &options);
|
581
633
|
|
582
634
|
VALUE value = parse_lex_input(&input, &options, false);
|
583
635
|
pm_string_free(&input);
|
@@ -603,7 +655,7 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
603
655
|
|
604
656
|
VALUE source = pm_source_new(&parser, encoding);
|
605
657
|
VALUE result_argv[] = {
|
606
|
-
pm_ast_new(&parser, node, encoding),
|
658
|
+
pm_ast_new(&parser, node, encoding, source),
|
607
659
|
parser_comments(&parser, source),
|
608
660
|
parser_magic_comments(&parser, source),
|
609
661
|
parser_data_loc(&parser, source),
|
@@ -635,10 +687,13 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
635
687
|
* integer or nil. Note that this is 1-indexed.
|
636
688
|
* * `frozen_string_literal` - whether or not the frozen string literal pragma
|
637
689
|
* has been set. This should be a boolean or nil.
|
638
|
-
* * `
|
639
|
-
*
|
690
|
+
* * `version` - the version of prism that should be used to parse Ruby code. By
|
691
|
+
* default prism assumes you want to parse with the latest vesion of
|
692
|
+
* prism (which you can trigger with `nil` or `"latest"`). If you want to
|
693
|
+
* parse exactly as CRuby 3.3.0 would, then you can pass `"3.3.0"`.
|
640
694
|
* * `scopes` - the locals that are in scope surrounding the code that is being
|
641
|
-
* parsed. This should be an array of arrays of symbols or nil.
|
695
|
+
* parsed. This should be an array of arrays of symbols or nil. Scopes are
|
696
|
+
* ordered from the outermost scope to the innermost one.
|
642
697
|
*/
|
643
698
|
static VALUE
|
644
699
|
parse(int argc, VALUE *argv, VALUE self) {
|
@@ -675,7 +730,8 @@ static VALUE
|
|
675
730
|
parse_file(int argc, VALUE *argv, VALUE self) {
|
676
731
|
pm_string_t input;
|
677
732
|
pm_options_t options = { 0 };
|
678
|
-
|
733
|
+
|
734
|
+
file_options(argc, argv, &input, &options);
|
679
735
|
|
680
736
|
VALUE value = parse_input(&input, &options);
|
681
737
|
pm_string_free(&input);
|
@@ -735,7 +791,8 @@ static VALUE
|
|
735
791
|
parse_file_comments(int argc, VALUE *argv, VALUE self) {
|
736
792
|
pm_string_t input;
|
737
793
|
pm_options_t options = { 0 };
|
738
|
-
|
794
|
+
|
795
|
+
file_options(argc, argv, &input, &options);
|
739
796
|
|
740
797
|
VALUE value = parse_input_comments(&input, &options);
|
741
798
|
pm_string_free(&input);
|
@@ -789,7 +846,8 @@ static VALUE
|
|
789
846
|
parse_lex_file(int argc, VALUE *argv, VALUE self) {
|
790
847
|
pm_string_t input;
|
791
848
|
pm_options_t options = { 0 };
|
792
|
-
|
849
|
+
|
850
|
+
file_options(argc, argv, &input, &options);
|
793
851
|
|
794
852
|
VALUE value = parse_lex_input(&input, &options, true);
|
795
853
|
pm_string_free(&input);
|
@@ -846,7 +904,8 @@ static VALUE
|
|
846
904
|
parse_file_success_p(int argc, VALUE *argv, VALUE self) {
|
847
905
|
pm_string_t input;
|
848
906
|
pm_options_t options = { 0 };
|
849
|
-
|
907
|
+
|
908
|
+
file_options(argc, argv, &input, &options);
|
850
909
|
|
851
910
|
VALUE result = parse_input_success_p(&input, &options);
|
852
911
|
pm_string_free(&input);
|
@@ -924,7 +983,17 @@ profile_file(VALUE self, VALUE filepath) {
|
|
924
983
|
pm_string_t input;
|
925
984
|
|
926
985
|
const char *checked = check_string(filepath);
|
927
|
-
|
986
|
+
Check_Type(filepath, T_STRING);
|
987
|
+
|
988
|
+
if (!pm_string_mapped_init(&input, checked)) {
|
989
|
+
#ifdef _WIN32
|
990
|
+
int e = rb_w32_map_errno(GetLastError());
|
991
|
+
#else
|
992
|
+
int e = errno;
|
993
|
+
#endif
|
994
|
+
|
995
|
+
rb_syserr_fail(e, checked);
|
996
|
+
}
|
928
997
|
|
929
998
|
pm_options_t options = { 0 };
|
930
999
|
pm_options_filepath_set(&options, checked);
|
@@ -971,6 +1040,36 @@ inspect_node(VALUE self, VALUE source) {
|
|
971
1040
|
return string;
|
972
1041
|
}
|
973
1042
|
|
1043
|
+
/**
|
1044
|
+
* call-seq:
|
1045
|
+
* Debug::format_errors(source, colorize) -> String
|
1046
|
+
*
|
1047
|
+
* Format the errors that are found when parsing the given source string.
|
1048
|
+
*/
|
1049
|
+
static VALUE
|
1050
|
+
format_errors(VALUE self, VALUE source, VALUE colorize) {
|
1051
|
+
pm_string_t input;
|
1052
|
+
input_load_string(&input, source);
|
1053
|
+
|
1054
|
+
pm_parser_t parser;
|
1055
|
+
pm_parser_init(&parser, pm_string_source(&input), pm_string_length(&input), NULL);
|
1056
|
+
|
1057
|
+
pm_node_t *node = pm_parse(&parser);
|
1058
|
+
pm_buffer_t buffer = { 0 };
|
1059
|
+
|
1060
|
+
pm_parser_errors_format(&parser, &buffer, RTEST(colorize));
|
1061
|
+
|
1062
|
+
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
1063
|
+
VALUE result = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), encoding);
|
1064
|
+
|
1065
|
+
pm_buffer_free(&buffer);
|
1066
|
+
pm_node_destroy(&parser, node);
|
1067
|
+
pm_parser_free(&parser);
|
1068
|
+
pm_string_free(&input);
|
1069
|
+
|
1070
|
+
return result;
|
1071
|
+
}
|
1072
|
+
|
974
1073
|
/******************************************************************************/
|
975
1074
|
/* Initialization of the extension */
|
976
1075
|
/******************************************************************************/
|
@@ -1012,7 +1111,7 @@ Init_prism(void) {
|
|
1012
1111
|
rb_option_id_encoding = rb_intern_const("encoding");
|
1013
1112
|
rb_option_id_line = rb_intern_const("line");
|
1014
1113
|
rb_option_id_frozen_string_literal = rb_intern_const("frozen_string_literal");
|
1015
|
-
|
1114
|
+
rb_option_id_version = rb_intern_const("version");
|
1016
1115
|
rb_option_id_scopes = rb_intern_const("scopes");
|
1017
1116
|
|
1018
1117
|
/**
|
@@ -1048,6 +1147,7 @@ Init_prism(void) {
|
|
1048
1147
|
rb_define_singleton_method(rb_cPrismDebug, "memsize", memsize, 1);
|
1049
1148
|
rb_define_singleton_method(rb_cPrismDebug, "profile_file", profile_file, 1);
|
1050
1149
|
rb_define_singleton_method(rb_cPrismDebug, "inspect_node", inspect_node, 1);
|
1150
|
+
rb_define_singleton_method(rb_cPrismDebug, "format_errors", format_errors, 2);
|
1051
1151
|
|
1052
1152
|
// Next, initialize the other APIs.
|
1053
1153
|
Init_prism_api_node();
|
data/ext/prism/extension.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef PRISM_EXT_NODE_H
|
2
2
|
#define PRISM_EXT_NODE_H
|
3
3
|
|
4
|
-
#define EXPECTED_PRISM_VERSION "0.
|
4
|
+
#define EXPECTED_PRISM_VERSION "0.24.0"
|
5
5
|
|
6
6
|
#include <ruby.h>
|
7
7
|
#include <ruby/encoding.h>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
|
10
10
|
VALUE pm_source_new(pm_parser_t *parser, rb_encoding *encoding);
|
11
11
|
VALUE pm_token_new(pm_parser_t *parser, pm_token_t *token, rb_encoding *encoding, VALUE source);
|
12
|
-
VALUE pm_ast_new(pm_parser_t *parser, pm_node_t *node, rb_encoding *encoding);
|
12
|
+
VALUE pm_ast_new(pm_parser_t *parser, pm_node_t *node, rb_encoding *encoding, VALUE source);
|
13
13
|
|
14
14
|
void Init_prism_api_node(void);
|
15
15
|
void Init_prism_pack(void);
|