prism 1.9.0 → 2.0.0.rc2
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 +88 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE.md +1 -1
- data/Makefile +41 -12
- data/README.md +35 -97
- data/config.yml +174 -161
- data/docs/build_system.md +2 -2
- data/docs/configuration.md +5 -4
- data/docs/encoding.md +2 -2
- data/docs/fuzzing.md +4 -11
- data/docs/javascript.md +19 -4
- data/docs/mapping.md +1 -1
- data/docs/releasing.md +77 -5
- data/docs/relocation.md +2 -4
- data/docs/serialization.md +22 -24
- data/docs/testing.md +46 -29
- data/ext/prism/api_node.c +1461 -1401
- data/ext/prism/extconf.rb +3 -4
- data/ext/prism/extension.c +796 -422
- data/ext/prism/extension.h +3 -3
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +2727 -610
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +26 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/bswap.h +46 -0
- data/include/prism/compiler/endianness.h +34 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +38 -403
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +94 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/{encoding.h → internal/encoding.h} +27 -68
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +1004 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
- data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/internal/xxh3.h +16 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +18 -53
- data/include/prism/options.h +146 -280
- data/include/prism/parser.h +356 -867
- data/include/prism/prettyprint.h +6 -9
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +74 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +12 -3
- data/include/prism.h +43 -320
- data/lib/prism/compiler.rb +319 -305
- data/lib/prism/desugar_compiler.rb +105 -34
- data/lib/prism/dispatcher.rb +646 -473
- data/lib/prism/dot_visitor.rb +592 -511
- data/lib/prism/dsl.rb +391 -25
- data/lib/prism/ffi.rb +258 -90
- data/lib/prism/inspect_visitor.rb +357 -325
- data/lib/prism/lex_compat.rb +254 -212
- data/lib/prism/mutation_compiler.rb +313 -305
- data/lib/prism/node.rb +20966 -6992
- data/lib/prism/node_ext.rb +180 -187
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +7 -1
- data/lib/prism/parse_result/newlines.rb +276 -8
- data/lib/prism/parse_result.rb +468 -139
- data/lib/prism/pattern.rb +65 -20
- data/lib/prism/reflection.rb +23 -12
- data/lib/prism/relocation.rb +149 -87
- data/lib/prism/serialize.rb +3460 -539
- data/lib/prism/string_query.rb +24 -1
- data/lib/prism/translation/parser/builder.rb +10 -2
- data/lib/prism/translation/parser/compiler.rb +44 -52
- data/lib/prism/translation/parser/lexer.rb +41 -92
- data/lib/prism/translation/parser.rb +1 -1
- data/lib/prism/translation/parser_current.rb +1 -1
- data/lib/prism/translation/ripper/lexer.rb +8 -10
- data/lib/prism/translation/ripper/sexp.rb +2 -10
- data/lib/prism/translation/ripper/shim.rb +2 -0
- data/lib/prism/translation/ripper.rb +967 -209
- data/lib/prism/translation/ruby_parser.rb +73 -316
- data/lib/prism/translation.rb +2 -0
- data/lib/prism/visitor.rb +632 -5
- data/lib/prism.rb +79 -9
- data/prism.gemspec +128 -62
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +14407 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +776 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +184 -0
- data/rbi/generated/prism/string_query.rbi +43 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser_versions.rbi +5 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
- data/sig/generated/prism/node.rbs +20896 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +871 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +198 -0
- data/sig/generated/prism/string_query.rbs +43 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/{util/pm_buffer.c → buffer.c} +53 -21
- data/src/{util/pm_char.c → char.c} +28 -57
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +97 -65
- data/src/encoding.c +8 -3
- data/src/errors_format.c +519 -0
- data/src/{util/pm_integer.c → integer.c} +33 -22
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/{util/pm_memchr.c → memchr.c} +8 -6
- data/src/node.c +3504 -7674
- data/src/options.c +162 -49
- data/src/parser.c +367 -0
- data/src/prettyprint.c +421 -354
- data/src/prism.c +8402 -7161
- data/src/regexp.c +961 -45
- data/src/serialize.c +460 -424
- data/src/source.c +518 -0
- data/src/static_literals.c +111 -43
- data/src/string_query.c +180 -0
- data/src/stringy.c +91 -0
- data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
- data/src/strpbrk.c +447 -0
- data/src/{token_type.c → tokens.c} +39 -18
- data/src/xxh3.c +292 -0
- metadata +128 -63
- data/ext/prism/api_pack.c +0 -276
- data/include/prism/defines.h +0 -260
- data/include/prism/pack.h +0 -163
- data/include/prism/regexp.h +0 -43
- data/include/prism/util/pm_buffer.h +0 -236
- data/include/prism/util/pm_char.h +0 -204
- data/include/prism/util/pm_constant_pool.h +0 -218
- data/include/prism/util/pm_integer.h +0 -130
- data/include/prism/util/pm_memchr.h +0 -29
- data/include/prism/util/pm_newline_list.h +0 -113
- data/include/prism/util/pm_string.h +0 -200
- data/lib/prism/pack.rb +0 -230
- data/lib/prism/parse_result/comments.rb +0 -188
- data/rbi/prism/compiler.rbi +0 -12
- data/rbi/prism/dsl.rbi +0 -524
- data/rbi/prism/inspect_visitor.rbi +0 -12
- data/rbi/prism/node.rbi +0 -8750
- data/rbi/prism/node_ext.rbi +0 -107
- data/rbi/prism/parse_result.rbi +0 -404
- data/rbi/prism/reflection.rbi +0 -58
- data/rbi/prism/string_query.rbi +0 -12
- data/rbi/prism/visitor.rbi +0 -473
- data/rbi/prism.rbi +0 -63
- data/sig/prism/compiler.rbs +0 -9
- data/sig/prism/dispatcher.rbs +0 -19
- data/sig/prism/dot_visitor.rbs +0 -6
- data/sig/prism/dsl.rbs +0 -351
- data/sig/prism/inspect_visitor.rbs +0 -22
- data/sig/prism/lex_compat.rbs +0 -10
- data/sig/prism/node.rbs +0 -4042
- data/sig/prism/node_ext.rbs +0 -149
- data/sig/prism/pack.rbs +0 -43
- data/sig/prism/parse_result/comments.rbs +0 -38
- data/sig/prism/parse_result.rbs +0 -197
- data/sig/prism/pattern.rbs +0 -13
- data/sig/prism/reflection.rbs +0 -50
- data/sig/prism/relocation.rbs +0 -185
- data/sig/prism/serialize.rbs +0 -8
- data/sig/prism/string_query.rbs +0 -11
- data/sig/prism/visitor.rbs +0 -169
- data/sig/prism.rbs +0 -272
- data/src/pack.c +0 -509
- data/src/util/pm_constant_pool.c +0 -342
- data/src/util/pm_list.c +0 -49
- data/src/util/pm_newline_list.c +0 -125
- data/src/util/pm_string.c +0 -381
- data/src/util/pm_strpbrk.c +0 -206
data/ext/prism/extension.c
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
#include <ruby/win32.h>
|
|
5
5
|
#endif
|
|
6
6
|
|
|
7
|
+
#include <errno.h>
|
|
8
|
+
|
|
7
9
|
// NOTE: this file should contain only bindings. All non-trivial logic should be
|
|
8
10
|
// in libprism so it can be shared its the various callers.
|
|
9
11
|
|
|
@@ -29,6 +31,7 @@ VALUE rb_cPrismCurrentVersionError;
|
|
|
29
31
|
|
|
30
32
|
VALUE rb_cPrismDebugEncoding;
|
|
31
33
|
|
|
34
|
+
ID rb_id_option_attach_comments;
|
|
32
35
|
ID rb_id_option_command_line;
|
|
33
36
|
ID rb_id_option_encoding;
|
|
34
37
|
ID rb_id_option_filepath;
|
|
@@ -37,14 +40,52 @@ ID rb_id_option_frozen_string_literal;
|
|
|
37
40
|
ID rb_id_option_line;
|
|
38
41
|
ID rb_id_option_main_script;
|
|
39
42
|
ID rb_id_option_partial_script;
|
|
43
|
+
ID rb_id_option_raise_error;
|
|
40
44
|
ID rb_id_option_scopes;
|
|
41
45
|
ID rb_id_option_version;
|
|
46
|
+
|
|
42
47
|
ID rb_id_source_for;
|
|
48
|
+
|
|
43
49
|
ID rb_id_forwarding_positionals;
|
|
44
50
|
ID rb_id_forwarding_keywords;
|
|
45
51
|
ID rb_id_forwarding_block;
|
|
46
52
|
ID rb_id_forwarding_all;
|
|
47
53
|
|
|
54
|
+
ID rb_id_raise_error_plain;
|
|
55
|
+
ID rb_id_raise_error_style;
|
|
56
|
+
ID rb_id_raise_error_color;
|
|
57
|
+
|
|
58
|
+
/******************************************************************************/
|
|
59
|
+
/* Result struct for working with functions that may need to raise errors. */
|
|
60
|
+
/******************************************************************************/
|
|
61
|
+
|
|
62
|
+
typedef struct {
|
|
63
|
+
enum {
|
|
64
|
+
RESULT_OK,
|
|
65
|
+
RESULT_ERR
|
|
66
|
+
} type;
|
|
67
|
+
VALUE value;
|
|
68
|
+
} result_t;
|
|
69
|
+
|
|
70
|
+
static result_t
|
|
71
|
+
result_ok(VALUE value) {
|
|
72
|
+
return (result_t) { .type = RESULT_OK, .value = value };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static result_t
|
|
76
|
+
result_err(VALUE value) {
|
|
77
|
+
return (result_t) { .type = RESULT_ERR, .value = value };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static VALUE
|
|
81
|
+
result_get(result_t result) {
|
|
82
|
+
if (result.type == RESULT_OK) {
|
|
83
|
+
return result.value;
|
|
84
|
+
} else {
|
|
85
|
+
rb_exc_raise(result.value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
48
89
|
/******************************************************************************/
|
|
49
90
|
/* IO of Ruby code */
|
|
50
91
|
/******************************************************************************/
|
|
@@ -64,19 +105,6 @@ check_string(VALUE value) {
|
|
|
64
105
|
return RSTRING_PTR(value);
|
|
65
106
|
}
|
|
66
107
|
|
|
67
|
-
/**
|
|
68
|
-
* Load the contents and size of the given string into the given pm_string_t.
|
|
69
|
-
*/
|
|
70
|
-
static void
|
|
71
|
-
input_load_string(pm_string_t *input, VALUE string) {
|
|
72
|
-
// Check if the string is a string. If it's not, then raise a type error.
|
|
73
|
-
if (!RB_TYPE_P(string, T_STRING)) {
|
|
74
|
-
rb_raise(rb_eTypeError, "wrong argument type %" PRIsVALUE " (expected String)", rb_obj_class(string));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
pm_string_constant_init(input, RSTRING_PTR(string), RSTRING_LEN(string));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
108
|
/******************************************************************************/
|
|
81
109
|
/* Building C options from Ruby options */
|
|
82
110
|
/******************************************************************************/
|
|
@@ -148,10 +176,8 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
|
148
176
|
|
|
149
177
|
// Initialize the scope array.
|
|
150
178
|
size_t locals_count = RARRAY_LEN(locals);
|
|
151
|
-
pm_options_scope_t *options_scope =
|
|
152
|
-
|
|
153
|
-
rb_raise(rb_eNoMemError, "failed to allocate memory");
|
|
154
|
-
}
|
|
179
|
+
pm_options_scope_t *options_scope = pm_options_scope_mut(options, scope_index);
|
|
180
|
+
pm_options_scope_init(options_scope, locals_count);
|
|
155
181
|
|
|
156
182
|
// Iterate over the locals and add them to the scope.
|
|
157
183
|
for (size_t local_index = 0; local_index < locals_count; local_index++) {
|
|
@@ -164,7 +190,7 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
|
164
190
|
}
|
|
165
191
|
|
|
166
192
|
// Add the local to the scope.
|
|
167
|
-
pm_string_t *scope_local =
|
|
193
|
+
pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index);
|
|
168
194
|
const char *name = rb_id2name(SYM2ID(local));
|
|
169
195
|
pm_string_constant_init(scope_local, name, strlen(name));
|
|
170
196
|
}
|
|
@@ -174,6 +200,23 @@ build_options_scopes(pm_options_t *options, VALUE scopes) {
|
|
|
174
200
|
}
|
|
175
201
|
}
|
|
176
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Set the version option to the syntax version of the currently running Ruby,
|
|
205
|
+
* or to the closest version prism supports if it does not know that one.
|
|
206
|
+
*/
|
|
207
|
+
static void
|
|
208
|
+
options_version_set_nearest(pm_options_t *options) {
|
|
209
|
+
if (!pm_options_version_set(options, ruby_version, 3)) {
|
|
210
|
+
// Prism doesn't know this specific version. Is it lower?
|
|
211
|
+
if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
|
|
212
|
+
pm_options_version_set_lowest(options);
|
|
213
|
+
} else {
|
|
214
|
+
// Must be higher.
|
|
215
|
+
pm_options_version_set_highest(options);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
177
220
|
/**
|
|
178
221
|
* An iterator function that is called for each key-value in the keywords hash.
|
|
179
222
|
*/
|
|
@@ -201,10 +244,11 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
|
|
201
244
|
const char *version = check_string(value);
|
|
202
245
|
|
|
203
246
|
if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, current_version));
|
|
247
|
+
if (!pm_options_version_set(options, ruby_version, 3)) {
|
|
248
|
+
rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
|
|
207
249
|
}
|
|
250
|
+
} else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
|
|
251
|
+
options_version_set_nearest(options);
|
|
208
252
|
} else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
|
|
209
253
|
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
|
|
210
254
|
}
|
|
@@ -236,6 +280,46 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
|
|
236
280
|
if (!NIL_P(value)) pm_options_partial_script_set(options, RTEST(value));
|
|
237
281
|
} else if (key_id == rb_id_option_freeze) {
|
|
238
282
|
if (!NIL_P(value)) pm_options_freeze_set(options, RTEST(value));
|
|
283
|
+
} else if (key_id == rb_id_option_attach_comments) {
|
|
284
|
+
if (!NIL_P(value)) pm_options_attach_comments_set(options, RTEST(value));
|
|
285
|
+
} else if (key_id == rb_id_option_raise_error) {
|
|
286
|
+
if (!NIL_P(value)) {
|
|
287
|
+
if (value == Qtrue) {
|
|
288
|
+
/* When given true, color when $stderr is a terminal (unless
|
|
289
|
+
* NO_COLOR is set), bold styling when NO_COLOR is set, plain
|
|
290
|
+
* otherwise.
|
|
291
|
+
*
|
|
292
|
+
* rb_stderr_tty_p is not available to extensions, so instead
|
|
293
|
+
* we call the tty? method on $stderr, guarding against it
|
|
294
|
+
* having been replaced by an object that does not respond to
|
|
295
|
+
* tty?. */
|
|
296
|
+
if (rb_respond_to(rb_stderr, rb_intern_const("tty?")) && RTEST(rb_funcall(rb_stderr, rb_intern_const("tty?"), 0))) {
|
|
297
|
+
const char *no_color = getenv("NO_COLOR");
|
|
298
|
+
if (no_color == NULL || no_color[0] == '\0') {
|
|
299
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_COLOR);
|
|
300
|
+
} else {
|
|
301
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_STYLE);
|
|
302
|
+
}
|
|
303
|
+
} else {
|
|
304
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_PLAIN);
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
if (!SYMBOL_P(value)) {
|
|
308
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(value));
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
ID value_id = SYM2ID(value);
|
|
312
|
+
if (value_id == rb_id_raise_error_plain) {
|
|
313
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_PLAIN);
|
|
314
|
+
} else if (value_id == rb_id_raise_error_style) {
|
|
315
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_STYLE);
|
|
316
|
+
} else if (value_id == rb_id_raise_error_color) {
|
|
317
|
+
pm_options_raise_error_set(options, (uint8_t) PM_ERRORS_FORMAT_COLOR);
|
|
318
|
+
} else {
|
|
319
|
+
rb_raise(rb_eArgError, "invalid raise_error value: %" PRIsVALUE, value);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
239
323
|
} else {
|
|
240
324
|
rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, key);
|
|
241
325
|
}
|
|
@@ -269,7 +353,8 @@ build_options(VALUE argument) {
|
|
|
269
353
|
*/
|
|
270
354
|
static void
|
|
271
355
|
extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
|
|
272
|
-
options
|
|
356
|
+
pm_options_line_set(options, 1); /* default */
|
|
357
|
+
options_version_set_nearest(options); /* default */
|
|
273
358
|
|
|
274
359
|
if (!NIL_P(keywords)) {
|
|
275
360
|
struct build_options_data data = { .options = options, .keywords = keywords };
|
|
@@ -297,36 +382,48 @@ extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
|
|
|
297
382
|
/**
|
|
298
383
|
* Read options for methods that look like (source, **options).
|
|
299
384
|
*/
|
|
300
|
-
static
|
|
301
|
-
string_options(int argc, VALUE *argv,
|
|
385
|
+
static VALUE
|
|
386
|
+
string_options(int argc, VALUE *argv, pm_options_t *options) {
|
|
302
387
|
VALUE string;
|
|
303
388
|
VALUE keywords;
|
|
304
389
|
rb_scan_args(argc, argv, "1:", &string, &keywords);
|
|
305
390
|
|
|
391
|
+
if (!RB_TYPE_P(string, T_STRING)) {
|
|
392
|
+
pm_options_free(options);
|
|
393
|
+
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string));
|
|
394
|
+
}
|
|
395
|
+
|
|
306
396
|
extract_options(options, Qnil, keywords);
|
|
307
|
-
|
|
397
|
+
return string;
|
|
308
398
|
}
|
|
309
399
|
|
|
310
400
|
/**
|
|
311
401
|
* Read options for methods that look like (filepath, **options).
|
|
312
402
|
*/
|
|
313
|
-
static
|
|
314
|
-
file_options(int argc, VALUE *argv,
|
|
403
|
+
static pm_source_t *
|
|
404
|
+
file_options(int argc, VALUE *argv, pm_options_t *options, VALUE *encoded_filepath) {
|
|
315
405
|
VALUE filepath;
|
|
316
406
|
VALUE keywords;
|
|
317
407
|
rb_scan_args(argc, argv, "1:", &filepath, &keywords);
|
|
318
408
|
|
|
319
|
-
|
|
409
|
+
int state = 0;
|
|
410
|
+
filepath = rb_protect(rb_get_path, filepath, &state);
|
|
411
|
+
if (state != 0) {
|
|
412
|
+
pm_options_free(options);
|
|
413
|
+
rb_jump_tag(state);
|
|
414
|
+
}
|
|
415
|
+
|
|
320
416
|
*encoded_filepath = rb_str_encode_ospath(filepath);
|
|
321
417
|
extract_options(options, *encoded_filepath, keywords);
|
|
322
418
|
|
|
323
|
-
const char *source = (const char *) pm_string_source(
|
|
324
|
-
|
|
419
|
+
const char *source = (const char *) pm_string_source(pm_options_filepath(options));
|
|
420
|
+
pm_source_init_result_t result;
|
|
421
|
+
pm_source_t *pm_src = pm_source_file_new(source, &result);
|
|
325
422
|
|
|
326
|
-
switch (result
|
|
327
|
-
case
|
|
423
|
+
switch (result) {
|
|
424
|
+
case PM_SOURCE_INIT_SUCCESS:
|
|
328
425
|
break;
|
|
329
|
-
case
|
|
426
|
+
case PM_SOURCE_INIT_ERROR_GENERIC: {
|
|
330
427
|
pm_options_free(options);
|
|
331
428
|
|
|
332
429
|
#ifdef _WIN32
|
|
@@ -338,7 +435,7 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
|
|
|
338
435
|
rb_syserr_fail(e, source);
|
|
339
436
|
break;
|
|
340
437
|
}
|
|
341
|
-
case
|
|
438
|
+
case PM_SOURCE_INIT_ERROR_DIRECTORY:
|
|
342
439
|
pm_options_free(options);
|
|
343
440
|
rb_syserr_fail(EISDIR, source);
|
|
344
441
|
break;
|
|
@@ -347,6 +444,58 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
|
|
|
347
444
|
rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source);
|
|
348
445
|
break;
|
|
349
446
|
}
|
|
447
|
+
|
|
448
|
+
return pm_src;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Check if the given parser has any errors and the raise option was set. If
|
|
453
|
+
* both are true, format them and return the formatted error wrapped in a
|
|
454
|
+
* result.
|
|
455
|
+
*/
|
|
456
|
+
static result_t
|
|
457
|
+
check_raise_error_option(pm_parser_t *parser, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
458
|
+
if (pm_parser_errors_size(parser) == 0) return result_ok(Qnil);
|
|
459
|
+
|
|
460
|
+
uint8_t raise_error = pm_options_raise_error(options);
|
|
461
|
+
if (raise_error == 0) return result_ok(Qnil);
|
|
462
|
+
|
|
463
|
+
pm_buffer_t *buffer = pm_buffer_new();
|
|
464
|
+
if (buffer == NULL) {
|
|
465
|
+
return result_err(rb_exc_new_cstr(rb_eNoMemError, "failed to allocate memory"));
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
pm_error_level_t error_level = pm_errors_format(parser, buffer, (pm_errors_format_type_t) raise_error);
|
|
469
|
+
|
|
470
|
+
/* Copy the message out of the buffer and free it before building any
|
|
471
|
+
* other Ruby objects so that the buffer cannot be leaked if building the
|
|
472
|
+
* objects raises. */
|
|
473
|
+
rb_encoding *message_encoding = (error_level == PM_ERROR_LEVEL_LOAD) ? rb_locale_encoding() : rb_enc_find(pm_parser_encoding_name(parser));
|
|
474
|
+
VALUE message = rb_enc_str_new(pm_buffer_value(buffer), (long) pm_buffer_length(buffer), message_encoding);
|
|
475
|
+
pm_buffer_free(buffer);
|
|
476
|
+
|
|
477
|
+
VALUE error = Qnil;
|
|
478
|
+
switch (error_level) {
|
|
479
|
+
case PM_ERROR_LEVEL_SYNTAX: {
|
|
480
|
+
error = rb_exc_new_str(rb_eSyntaxError, message);
|
|
481
|
+
|
|
482
|
+
rb_encoding *path_encoding_normal = path_encoding == NULL ? rb_utf8_encoding() : path_encoding;
|
|
483
|
+
VALUE path = rb_enc_str_new((const char *) pm_string_source(pm_options_filepath(options)), pm_string_length(pm_options_filepath(options)), path_encoding_normal);
|
|
484
|
+
rb_ivar_set(error, rb_intern_const("@path"), path);
|
|
485
|
+
break;
|
|
486
|
+
}
|
|
487
|
+
case PM_ERROR_LEVEL_ARGUMENT: {
|
|
488
|
+
error = rb_exc_new_str(rb_eArgError, message);
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
case PM_ERROR_LEVEL_LOAD: {
|
|
492
|
+
error = rb_exc_new_str(rb_eLoadError, message);
|
|
493
|
+
rb_ivar_set(error, rb_intern_const("@path"), Qnil);
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return result_err(error);
|
|
350
499
|
}
|
|
351
500
|
|
|
352
501
|
#ifndef PRISM_EXCLUDE_SERIALIZATION
|
|
@@ -358,80 +507,88 @@ file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options, V
|
|
|
358
507
|
/**
|
|
359
508
|
* Dump the AST corresponding to the given input to a string.
|
|
360
509
|
*/
|
|
361
|
-
static
|
|
362
|
-
dump_input(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
510
|
+
static result_t
|
|
511
|
+
dump_input(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
512
|
+
pm_arena_t *arena = pm_arena_new();
|
|
513
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
514
|
+
pm_node_t *node = pm_parse(parser);
|
|
515
|
+
|
|
516
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
517
|
+
if (result.type == RESULT_OK) {
|
|
518
|
+
pm_buffer_t *buffer = pm_buffer_new();
|
|
519
|
+
if (buffer) {
|
|
520
|
+
pm_serialize(parser, node, buffer);
|
|
521
|
+
result = result_ok(rb_str_new(pm_buffer_value(buffer), pm_buffer_length(buffer)));
|
|
522
|
+
pm_buffer_free(buffer);
|
|
523
|
+
|
|
524
|
+
if (pm_options_freeze(options)) rb_obj_freeze(result.value);
|
|
525
|
+
} else {
|
|
526
|
+
result = result_err(rb_exc_new_cstr(rb_eNoMemError, "failed to allocate memory"));
|
|
527
|
+
}
|
|
366
528
|
}
|
|
367
529
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
pm_node_t *node = pm_parse(&parser);
|
|
372
|
-
pm_serialize(&parser, node, &buffer);
|
|
373
|
-
|
|
374
|
-
VALUE result = rb_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer));
|
|
375
|
-
pm_node_destroy(&parser, node);
|
|
376
|
-
pm_buffer_free(&buffer);
|
|
377
|
-
pm_parser_free(&parser);
|
|
530
|
+
pm_parser_free(parser);
|
|
531
|
+
pm_arena_free(arena);
|
|
378
532
|
|
|
379
533
|
return result;
|
|
380
534
|
}
|
|
381
535
|
|
|
382
536
|
/**
|
|
537
|
+
* :markup: markdown
|
|
383
538
|
* call-seq:
|
|
384
|
-
*
|
|
539
|
+
* dump(source, **options) -> String
|
|
385
540
|
*
|
|
386
541
|
* Dump the AST corresponding to the given string to a string. For supported
|
|
387
|
-
* options, see Prism
|
|
542
|
+
* options, see Prism.parse.
|
|
388
543
|
*/
|
|
389
544
|
static VALUE
|
|
390
545
|
dump(int argc, VALUE *argv, VALUE self) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
546
|
+
pm_options_t *options = pm_options_new();
|
|
547
|
+
VALUE string = string_options(argc, argv, options);
|
|
548
|
+
|
|
549
|
+
const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
|
|
550
|
+
size_t length = RSTRING_LEN(string);
|
|
394
551
|
|
|
395
552
|
#ifdef PRISM_BUILD_DEBUG
|
|
396
|
-
size_t length = pm_string_length(&input);
|
|
397
553
|
char* dup = xmalloc(length);
|
|
398
|
-
memcpy(dup,
|
|
399
|
-
|
|
554
|
+
memcpy(dup, source, length);
|
|
555
|
+
source = (const uint8_t *) dup;
|
|
400
556
|
#endif
|
|
401
557
|
|
|
402
|
-
|
|
403
|
-
if (options.freeze) rb_obj_freeze(value);
|
|
558
|
+
result_t result = dump_input(source, length, options, NULL);
|
|
404
559
|
|
|
405
560
|
#ifdef PRISM_BUILD_DEBUG
|
|
561
|
+
#ifdef xfree_sized
|
|
562
|
+
xfree_sized(dup, length);
|
|
563
|
+
#else
|
|
406
564
|
xfree(dup);
|
|
565
|
+
#endif
|
|
407
566
|
#endif
|
|
408
567
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
return value;
|
|
568
|
+
pm_options_free(options);
|
|
569
|
+
return result_get(result);
|
|
413
570
|
}
|
|
414
571
|
|
|
415
572
|
/**
|
|
573
|
+
* :markup: markdown
|
|
416
574
|
* call-seq:
|
|
417
|
-
*
|
|
575
|
+
* dump_file(filepath, **options) -> String
|
|
418
576
|
*
|
|
419
577
|
* Dump the AST corresponding to the given file to a string. For supported
|
|
420
|
-
* options, see Prism
|
|
578
|
+
* options, see Prism.parse.
|
|
421
579
|
*/
|
|
422
580
|
static VALUE
|
|
423
581
|
dump_file(int argc, VALUE *argv, VALUE self) {
|
|
424
|
-
|
|
425
|
-
pm_options_t options = { 0 };
|
|
582
|
+
pm_options_t *options = pm_options_new();
|
|
426
583
|
|
|
427
584
|
VALUE encoded_filepath;
|
|
428
|
-
file_options(argc, argv,
|
|
585
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
429
586
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
pm_options_free(
|
|
587
|
+
result_t result = dump_input(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath));
|
|
588
|
+
pm_source_free(src);
|
|
589
|
+
pm_options_free(options);
|
|
433
590
|
|
|
434
|
-
return
|
|
591
|
+
return result_get(result);
|
|
435
592
|
}
|
|
436
593
|
|
|
437
594
|
#endif
|
|
@@ -455,73 +612,89 @@ rb_class_new_instance_freeze(int argc, const VALUE *argv, VALUE klass, bool free
|
|
|
455
612
|
* Create a new Location instance from the given parser and bounds.
|
|
456
613
|
*/
|
|
457
614
|
static inline VALUE
|
|
458
|
-
parser_location(
|
|
459
|
-
VALUE argv[] = { source, LONG2FIX(start
|
|
615
|
+
parser_location(VALUE source, bool freeze, uint32_t start, uint32_t length) {
|
|
616
|
+
VALUE argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
|
|
460
617
|
return rb_class_new_instance_freeze(3, argv, rb_cPrismLocation, freeze);
|
|
461
618
|
}
|
|
462
619
|
|
|
463
620
|
/**
|
|
464
621
|
* Create a new Location instance from the given parser and location.
|
|
465
622
|
*/
|
|
466
|
-
#define
|
|
467
|
-
parser_location(
|
|
623
|
+
#define PARSER_LOCATION(source, freeze, location) \
|
|
624
|
+
parser_location(source, freeze, location.start, location.length)
|
|
468
625
|
|
|
469
626
|
/**
|
|
470
627
|
* Build a new Comment instance from the given parser and comment.
|
|
471
628
|
*/
|
|
472
629
|
static inline VALUE
|
|
473
|
-
parser_comment(
|
|
474
|
-
VALUE argv[] = {
|
|
475
|
-
VALUE type = (comment
|
|
630
|
+
parser_comment(VALUE source, bool freeze, const pm_comment_t *comment) {
|
|
631
|
+
VALUE argv[] = { PARSER_LOCATION(source, freeze, pm_comment_location(comment)) };
|
|
632
|
+
VALUE type = (pm_comment_type(comment) == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
|
|
476
633
|
return rb_class_new_instance_freeze(1, argv, type, freeze);
|
|
477
634
|
}
|
|
478
635
|
|
|
636
|
+
typedef struct {
|
|
637
|
+
VALUE comments;
|
|
638
|
+
VALUE source;
|
|
639
|
+
bool freeze;
|
|
640
|
+
long index;
|
|
641
|
+
} parser_comments_each_data_t;
|
|
642
|
+
|
|
643
|
+
static void
|
|
644
|
+
parser_comments_each(const pm_comment_t *comment, void *data) {
|
|
645
|
+
parser_comments_each_data_t *each_data = (parser_comments_each_data_t *) data;
|
|
646
|
+
VALUE value = parser_comment(each_data->source, each_data->freeze, comment);
|
|
647
|
+
rb_ary_store(each_data->comments, each_data->index++, value);
|
|
648
|
+
}
|
|
649
|
+
|
|
479
650
|
/**
|
|
480
|
-
* Extract the comments out of the parser into
|
|
651
|
+
* Extract the comments out of the parser into the given array, which was
|
|
652
|
+
* created before the source so that the source could hold it.
|
|
481
653
|
*/
|
|
482
|
-
static
|
|
483
|
-
parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
for (
|
|
487
|
-
const pm_comment_t *comment = (const pm_comment_t *) parser->comment_list.head;
|
|
488
|
-
comment != NULL;
|
|
489
|
-
comment = (const pm_comment_t *) comment->node.next
|
|
490
|
-
) {
|
|
491
|
-
VALUE value = parser_comment(parser, source, freeze, comment);
|
|
492
|
-
rb_ary_push(comments, value);
|
|
493
|
-
}
|
|
494
|
-
|
|
654
|
+
static void
|
|
655
|
+
parser_comments(const pm_parser_t *parser, VALUE comments, VALUE source, bool freeze) {
|
|
656
|
+
parser_comments_each_data_t each_data = { .comments = comments, .source = source, .freeze = freeze };
|
|
657
|
+
pm_parser_comments_each(parser, parser_comments_each, &each_data);
|
|
495
658
|
if (freeze) rb_obj_freeze(comments);
|
|
496
|
-
return comments;
|
|
497
659
|
}
|
|
498
660
|
|
|
499
661
|
/**
|
|
500
662
|
* Build a new MagicComment instance from the given parser and magic comment.
|
|
501
663
|
*/
|
|
502
664
|
static inline VALUE
|
|
503
|
-
parser_magic_comment(
|
|
504
|
-
|
|
505
|
-
|
|
665
|
+
parser_magic_comment(VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
|
|
666
|
+
pm_location_t key = pm_magic_comment_key(magic_comment);
|
|
667
|
+
pm_location_t value = pm_magic_comment_value(magic_comment);
|
|
668
|
+
|
|
669
|
+
VALUE key_loc = parser_location(source, freeze, key.start, key.length);
|
|
670
|
+
VALUE value_loc = parser_location(source, freeze, value.start, value.length);
|
|
671
|
+
|
|
506
672
|
VALUE argv[] = { key_loc, value_loc };
|
|
507
673
|
return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze);
|
|
508
674
|
}
|
|
509
675
|
|
|
676
|
+
typedef struct {
|
|
677
|
+
VALUE magic_comments;
|
|
678
|
+
VALUE source;
|
|
679
|
+
bool freeze;
|
|
680
|
+
} parser_magic_comments_each_data_t;
|
|
681
|
+
|
|
682
|
+
static void
|
|
683
|
+
parser_magic_comments_each(const pm_magic_comment_t *magic_comment, void *data) {
|
|
684
|
+
parser_magic_comments_each_data_t *each_data = (parser_magic_comments_each_data_t *) data;
|
|
685
|
+
VALUE value = parser_magic_comment(each_data->source, each_data->freeze, magic_comment);
|
|
686
|
+
rb_ary_push(each_data->magic_comments, value);
|
|
687
|
+
}
|
|
688
|
+
|
|
510
689
|
/**
|
|
511
690
|
* Extract the magic comments out of the parser into an array.
|
|
512
691
|
*/
|
|
513
692
|
static VALUE
|
|
514
693
|
parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
|
|
515
|
-
VALUE magic_comments = rb_ary_new_capa(parser
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
magic_comment != NULL;
|
|
520
|
-
magic_comment = (const pm_magic_comment_t *) magic_comment->node.next
|
|
521
|
-
) {
|
|
522
|
-
VALUE value = parser_magic_comment(parser, source, freeze, magic_comment);
|
|
523
|
-
rb_ary_push(magic_comments, value);
|
|
524
|
-
}
|
|
694
|
+
VALUE magic_comments = rb_ary_new_capa(pm_parser_magic_comments_size(parser));
|
|
695
|
+
|
|
696
|
+
parser_magic_comments_each_data_t each_data = { magic_comments, source, freeze };
|
|
697
|
+
pm_parser_magic_comments_each(parser, parser_magic_comments_each, &each_data);
|
|
525
698
|
|
|
526
699
|
if (freeze) rb_obj_freeze(magic_comments);
|
|
527
700
|
return magic_comments;
|
|
@@ -533,11 +706,50 @@ parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
|
|
|
533
706
|
*/
|
|
534
707
|
static VALUE
|
|
535
708
|
parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
|
|
536
|
-
|
|
709
|
+
const pm_location_t *data_loc = pm_parser_data_loc(parser);
|
|
710
|
+
|
|
711
|
+
if (data_loc->length == 0) {
|
|
537
712
|
return Qnil;
|
|
538
713
|
} else {
|
|
539
|
-
return
|
|
714
|
+
return parser_location(source, freeze, data_loc->start, data_loc->length);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
typedef struct {
|
|
719
|
+
VALUE errors;
|
|
720
|
+
rb_encoding *encoding;
|
|
721
|
+
VALUE source;
|
|
722
|
+
bool freeze;
|
|
723
|
+
} parser_errors_each_data_t;
|
|
724
|
+
|
|
725
|
+
static void
|
|
726
|
+
parser_errors_each(const pm_diagnostic_t *diagnostic, void *data) {
|
|
727
|
+
parser_errors_each_data_t *each_data = (parser_errors_each_data_t *) data;
|
|
728
|
+
|
|
729
|
+
VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
|
|
730
|
+
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
|
|
731
|
+
VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
|
|
732
|
+
|
|
733
|
+
pm_error_level_t error_level = pm_diagnostic_error_level(diagnostic);
|
|
734
|
+
VALUE level = Qnil;
|
|
735
|
+
|
|
736
|
+
switch (error_level) {
|
|
737
|
+
case PM_ERROR_LEVEL_SYNTAX:
|
|
738
|
+
level = ID2SYM(rb_intern("syntax"));
|
|
739
|
+
break;
|
|
740
|
+
case PM_ERROR_LEVEL_ARGUMENT:
|
|
741
|
+
level = ID2SYM(rb_intern("argument"));
|
|
742
|
+
break;
|
|
743
|
+
case PM_ERROR_LEVEL_LOAD:
|
|
744
|
+
level = ID2SYM(rb_intern("load"));
|
|
745
|
+
break;
|
|
746
|
+
default:
|
|
747
|
+
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error_level);
|
|
540
748
|
}
|
|
749
|
+
|
|
750
|
+
VALUE argv[] = { type, message, location, level };
|
|
751
|
+
VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, each_data->freeze);
|
|
752
|
+
rb_ary_push(each_data->errors, value);
|
|
541
753
|
}
|
|
542
754
|
|
|
543
755
|
/**
|
|
@@ -545,78 +757,109 @@ parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
|
|
|
545
757
|
*/
|
|
546
758
|
static VALUE
|
|
547
759
|
parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
|
|
548
|
-
VALUE errors = rb_ary_new_capa(parser
|
|
549
|
-
|
|
550
|
-
for (
|
|
551
|
-
const pm_diagnostic_t *error = (const pm_diagnostic_t *) parser->error_list.head;
|
|
552
|
-
error != NULL;
|
|
553
|
-
error = (const pm_diagnostic_t *) error->node.next
|
|
554
|
-
) {
|
|
555
|
-
VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(error->diag_id)));
|
|
556
|
-
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(error->message, encoding));
|
|
557
|
-
VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, error->location);
|
|
558
|
-
|
|
559
|
-
VALUE level = Qnil;
|
|
560
|
-
switch (error->level) {
|
|
561
|
-
case PM_ERROR_LEVEL_SYNTAX:
|
|
562
|
-
level = ID2SYM(rb_intern("syntax"));
|
|
563
|
-
break;
|
|
564
|
-
case PM_ERROR_LEVEL_ARGUMENT:
|
|
565
|
-
level = ID2SYM(rb_intern("argument"));
|
|
566
|
-
break;
|
|
567
|
-
case PM_ERROR_LEVEL_LOAD:
|
|
568
|
-
level = ID2SYM(rb_intern("load"));
|
|
569
|
-
break;
|
|
570
|
-
default:
|
|
571
|
-
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error->level);
|
|
572
|
-
}
|
|
760
|
+
VALUE errors = rb_ary_new_capa(pm_parser_errors_size(parser));
|
|
573
761
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
rb_ary_push(errors, value);
|
|
577
|
-
}
|
|
762
|
+
parser_errors_each_data_t each_data = { errors, encoding, source, freeze };
|
|
763
|
+
pm_parser_errors_each(parser, parser_errors_each, &each_data);
|
|
578
764
|
|
|
579
765
|
if (freeze) rb_obj_freeze(errors);
|
|
580
766
|
return errors;
|
|
581
767
|
}
|
|
582
768
|
|
|
769
|
+
typedef struct {
|
|
770
|
+
VALUE warnings;
|
|
771
|
+
rb_encoding *encoding;
|
|
772
|
+
VALUE source;
|
|
773
|
+
bool freeze;
|
|
774
|
+
} parser_warnings_each_data_t;
|
|
775
|
+
|
|
776
|
+
static void
|
|
777
|
+
parser_warnings_each(const pm_diagnostic_t *diagnostic, void *data) {
|
|
778
|
+
parser_warnings_each_data_t *each_data = (parser_warnings_each_data_t *) data;
|
|
779
|
+
|
|
780
|
+
VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
|
|
781
|
+
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
|
|
782
|
+
VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
|
|
783
|
+
|
|
784
|
+
pm_warning_level_t warning_level = pm_diagnostic_warning_level(diagnostic);
|
|
785
|
+
VALUE level = Qnil;
|
|
786
|
+
|
|
787
|
+
switch (warning_level) {
|
|
788
|
+
case PM_WARNING_LEVEL_DEFAULT:
|
|
789
|
+
level = ID2SYM(rb_intern("default"));
|
|
790
|
+
break;
|
|
791
|
+
case PM_WARNING_LEVEL_VERBOSE:
|
|
792
|
+
level = ID2SYM(rb_intern("verbose"));
|
|
793
|
+
break;
|
|
794
|
+
default:
|
|
795
|
+
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning_level);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
VALUE argv[] = { type, message, location, level };
|
|
799
|
+
VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, each_data->freeze);
|
|
800
|
+
rb_ary_push(each_data->warnings, value);
|
|
801
|
+
}
|
|
802
|
+
|
|
583
803
|
/**
|
|
584
804
|
* Extract the warnings out of the parser into an array.
|
|
585
805
|
*/
|
|
586
806
|
static VALUE
|
|
587
807
|
parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
|
|
588
|
-
VALUE warnings = rb_ary_new_capa(parser
|
|
589
|
-
|
|
590
|
-
for (
|
|
591
|
-
const pm_diagnostic_t *warning = (const pm_diagnostic_t *) parser->warning_list.head;
|
|
592
|
-
warning != NULL;
|
|
593
|
-
warning = (const pm_diagnostic_t *) warning->node.next
|
|
594
|
-
) {
|
|
595
|
-
VALUE type = ID2SYM(rb_intern(pm_diagnostic_id_human(warning->diag_id)));
|
|
596
|
-
VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(warning->message, encoding));
|
|
597
|
-
VALUE location = PARSER_LOCATION_LOC(parser, source, freeze, warning->location);
|
|
598
|
-
|
|
599
|
-
VALUE level = Qnil;
|
|
600
|
-
switch (warning->level) {
|
|
601
|
-
case PM_WARNING_LEVEL_DEFAULT:
|
|
602
|
-
level = ID2SYM(rb_intern("default"));
|
|
603
|
-
break;
|
|
604
|
-
case PM_WARNING_LEVEL_VERBOSE:
|
|
605
|
-
level = ID2SYM(rb_intern("verbose"));
|
|
606
|
-
break;
|
|
607
|
-
default:
|
|
608
|
-
rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning->level);
|
|
609
|
-
}
|
|
808
|
+
VALUE warnings = rb_ary_new_capa(pm_parser_warnings_size(parser));
|
|
610
809
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
rb_ary_push(warnings, value);
|
|
614
|
-
}
|
|
810
|
+
parser_warnings_each_data_t each_data = { warnings, encoding, source, freeze };
|
|
811
|
+
pm_parser_warnings_each(parser, parser_warnings_each, &each_data);
|
|
615
812
|
|
|
616
813
|
if (freeze) rb_obj_freeze(warnings);
|
|
617
814
|
return warnings;
|
|
618
815
|
}
|
|
619
816
|
|
|
817
|
+
/**
|
|
818
|
+
* Create the arrays that hold the comments attached to each node, sized for the
|
|
819
|
+
* parser's comment attachments. They stay empty unless the attach_comments
|
|
820
|
+
* option was set.
|
|
821
|
+
*/
|
|
822
|
+
static void
|
|
823
|
+
parser_attachments_new(const pm_parser_t *parser, VALUE *attachments, VALUE *ranges) {
|
|
824
|
+
uint32_t ranges_size = pm_parser_comment_ranges_size(parser);
|
|
825
|
+
*attachments = rb_ary_new_capa(ranges_size == 0 ? 0 : (long) pm_parser_comments_size(parser));
|
|
826
|
+
*ranges = rb_ary_new_capa(ranges_size == 0 ? 0 : (long) ranges_size + 1);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Fill in the comments attached to each node. The attachments are the Comment
|
|
831
|
+
* objects in the order of the parser's comment attachments, which groups them
|
|
832
|
+
* by node in order of node id. The ranges are indexed by node id: for each node
|
|
833
|
+
* that owns comments, the index at which its comments begin is stored at its
|
|
834
|
+
* node id and the index at which they end is stored at the following node id.
|
|
835
|
+
*/
|
|
836
|
+
static void
|
|
837
|
+
parser_attachments(const pm_parser_t *parser, VALUE comments, VALUE attachments, VALUE ranges, bool freeze) {
|
|
838
|
+
uint32_t ranges_size = pm_parser_comment_ranges_size(parser);
|
|
839
|
+
|
|
840
|
+
if (ranges_size > 0) {
|
|
841
|
+
long size = RARRAY_LEN(comments);
|
|
842
|
+
|
|
843
|
+
for (long index = 0; index < size; index++) {
|
|
844
|
+
rb_ary_store(attachments, index, RARRAY_AREF(comments, pm_parser_comment_attachment(parser, (uint32_t) index)));
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
for (uint32_t node_id = 0; node_id < ranges_size; node_id++) {
|
|
848
|
+
pm_comment_range_t range = pm_parser_comment_range(parser, node_id);
|
|
849
|
+
|
|
850
|
+
if (range.length > 0) {
|
|
851
|
+
rb_ary_store(ranges, (long) node_id, LONG2FIX(range.index));
|
|
852
|
+
rb_ary_store(ranges, (long) node_id + 1, LONG2FIX(range.index + range.length));
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (freeze) {
|
|
858
|
+
rb_obj_freeze(attachments);
|
|
859
|
+
rb_obj_freeze(ranges);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
620
863
|
/**
|
|
621
864
|
* Create a new parse result from the given parser, value, encoding, and source.
|
|
622
865
|
*/
|
|
@@ -624,11 +867,11 @@ static VALUE
|
|
|
624
867
|
parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source, bool freeze) {
|
|
625
868
|
VALUE result_argv[] = {
|
|
626
869
|
value,
|
|
627
|
-
parser_comments(parser, source, freeze),
|
|
628
870
|
parser_magic_comments(parser, source, freeze),
|
|
629
871
|
parser_data_loc(parser, source, freeze),
|
|
630
872
|
parser_errors(parser, encoding, source, freeze),
|
|
631
873
|
parser_warnings(parser, encoding, source, freeze),
|
|
874
|
+
pm_parser_continuable(parser) ? Qtrue : Qfalse,
|
|
632
875
|
source
|
|
633
876
|
};
|
|
634
877
|
|
|
@@ -657,18 +900,11 @@ typedef struct {
|
|
|
657
900
|
* onto the tokens array.
|
|
658
901
|
*/
|
|
659
902
|
static void
|
|
660
|
-
parse_lex_token(
|
|
661
|
-
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *)
|
|
903
|
+
parse_lex_token(pm_parser_t *parser, pm_token_t *token, void *data) {
|
|
904
|
+
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) data;
|
|
662
905
|
|
|
663
906
|
VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze);
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
if (parse_lex_data->freeze) {
|
|
667
|
-
rb_obj_freeze(value);
|
|
668
|
-
rb_obj_freeze(yields);
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
rb_ary_push(parse_lex_data->tokens, yields);
|
|
907
|
+
rb_ary_push(parse_lex_data->tokens, value);
|
|
672
908
|
}
|
|
673
909
|
|
|
674
910
|
/**
|
|
@@ -678,8 +914,8 @@ parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
|
|
|
678
914
|
*/
|
|
679
915
|
static void
|
|
680
916
|
parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
|
681
|
-
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser
|
|
682
|
-
parse_lex_data->encoding = rb_enc_find(parser
|
|
917
|
+
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) pm_parser_lex_callback_data(parser);
|
|
918
|
+
parse_lex_data->encoding = rb_enc_find(pm_parser_encoding_name(parser));
|
|
683
919
|
|
|
684
920
|
// Since the encoding changed, we need to go back and change the encoding of
|
|
685
921
|
// the tokens that were already lexed. This is only going to end up being
|
|
@@ -689,9 +925,7 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
|
|
689
925
|
VALUE next_tokens = rb_ary_new();
|
|
690
926
|
|
|
691
927
|
for (long index = 0; index < RARRAY_LEN(tokens); index++) {
|
|
692
|
-
VALUE
|
|
693
|
-
VALUE token = rb_ary_entry(yields, 0);
|
|
694
|
-
|
|
928
|
+
VALUE token = rb_ary_entry(tokens, index);
|
|
695
929
|
VALUE value = rb_ivar_get(token, rb_intern("@value"));
|
|
696
930
|
VALUE next_value = rb_str_dup(value);
|
|
697
931
|
|
|
@@ -702,18 +936,17 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
|
|
702
936
|
parse_lex_data->source,
|
|
703
937
|
rb_ivar_get(token, rb_intern("@type")),
|
|
704
938
|
next_value,
|
|
705
|
-
rb_ivar_get(token, rb_intern("@location"))
|
|
939
|
+
rb_ivar_get(token, rb_intern("@location")),
|
|
940
|
+
rb_ivar_get(token, rb_intern("@state")),
|
|
706
941
|
};
|
|
707
942
|
|
|
708
|
-
VALUE next_token = rb_class_new_instance(
|
|
709
|
-
VALUE next_yields = rb_assoc_new(next_token, rb_ary_entry(yields, 1));
|
|
943
|
+
VALUE next_token = rb_class_new_instance(5, next_token_argv, rb_cPrismToken);
|
|
710
944
|
|
|
711
945
|
if (parse_lex_data->freeze) {
|
|
712
946
|
rb_obj_freeze(next_token);
|
|
713
|
-
rb_obj_freeze(next_yields);
|
|
714
947
|
}
|
|
715
948
|
|
|
716
|
-
rb_ary_push(next_tokens,
|
|
949
|
+
rb_ary_push(next_tokens, next_token);
|
|
717
950
|
}
|
|
718
951
|
|
|
719
952
|
rb_ary_replace(parse_lex_data->tokens, next_tokens);
|
|
@@ -723,107 +956,122 @@ parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
|
|
723
956
|
* Parse the given input and return a ParseResult containing just the tokens or
|
|
724
957
|
* the nodes and tokens.
|
|
725
958
|
*/
|
|
726
|
-
static
|
|
727
|
-
parse_lex_input(
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
VALUE source_string = rb_str_new((const char *)
|
|
733
|
-
VALUE offsets = rb_ary_new_capa(parser
|
|
734
|
-
VALUE
|
|
959
|
+
static result_t
|
|
960
|
+
parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding, bool return_nodes) {
|
|
961
|
+
pm_arena_t *arena = pm_arena_new();
|
|
962
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
963
|
+
pm_parser_encoding_changed_callback_set(parser, parse_lex_encoding_changed_callback);
|
|
964
|
+
|
|
965
|
+
VALUE source_string = rb_str_new((const char *) input, input_length);
|
|
966
|
+
VALUE offsets = rb_ary_new_capa(pm_parser_line_offsets(parser)->size);
|
|
967
|
+
VALUE comments = rb_ary_new();
|
|
968
|
+
VALUE attachments = rb_ary_new();
|
|
969
|
+
VALUE ranges = rb_ary_new();
|
|
970
|
+
VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 6, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets, comments, attachments, ranges);
|
|
735
971
|
|
|
736
972
|
parse_lex_data_t parse_lex_data = {
|
|
737
973
|
.source = source,
|
|
738
974
|
.tokens = rb_ary_new(),
|
|
739
|
-
.encoding =
|
|
740
|
-
.freeze = options
|
|
975
|
+
.encoding = rb_enc_find(pm_parser_encoding_name(parser)),
|
|
976
|
+
.freeze = pm_options_freeze(options),
|
|
741
977
|
};
|
|
742
978
|
|
|
743
979
|
parse_lex_data_t *data = &parse_lex_data;
|
|
744
|
-
|
|
745
|
-
.data = (void *) data,
|
|
746
|
-
.callback = parse_lex_token,
|
|
747
|
-
};
|
|
980
|
+
pm_parser_lex_callback_set(parser, parse_lex_token, data);
|
|
748
981
|
|
|
749
|
-
|
|
750
|
-
pm_node_t *node = pm_parse(&parser);
|
|
982
|
+
pm_node_t *node = pm_parse(parser);
|
|
751
983
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
984
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
985
|
+
if (result.type == RESULT_OK) {
|
|
986
|
+
/* Update the Source object with the correct encoding, line offsets,
|
|
987
|
+
* and source hash, which are only available after pm_parse()
|
|
988
|
+
* completes. */
|
|
989
|
+
rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
|
|
990
|
+
rb_enc_associate(source_string, encoding);
|
|
758
991
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
992
|
+
const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
|
|
993
|
+
for (size_t index = 0; index < line_offsets->size; index++) {
|
|
994
|
+
rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index]));
|
|
995
|
+
}
|
|
762
996
|
|
|
763
|
-
|
|
764
|
-
rb_obj_freeze(source_string);
|
|
765
|
-
rb_obj_freeze(offsets);
|
|
766
|
-
rb_obj_freeze(source);
|
|
767
|
-
rb_obj_freeze(parse_lex_data.tokens);
|
|
768
|
-
}
|
|
997
|
+
rb_funcall(source, rb_intern("replace_checksum"), 1, ULL2NUM(pm_parser_checksum(parser)));
|
|
769
998
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
999
|
+
if (pm_options_freeze(options)) {
|
|
1000
|
+
rb_obj_freeze(source_string);
|
|
1001
|
+
rb_obj_freeze(offsets);
|
|
1002
|
+
rb_obj_freeze(source);
|
|
1003
|
+
rb_obj_freeze(parse_lex_data.tokens);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
/* The comment lists were created along with the source before parsing,
|
|
1007
|
+
* so they are grown to their final sizes now that those are known. */
|
|
1008
|
+
uint32_t ranges_size = pm_parser_comment_ranges_size(parser);
|
|
1009
|
+
rb_ary_resize(comments, (long) pm_parser_comments_size(parser));
|
|
1010
|
+
|
|
1011
|
+
if (ranges_size > 0) {
|
|
1012
|
+
rb_ary_resize(attachments, (long) pm_parser_comments_size(parser));
|
|
1013
|
+
rb_ary_resize(ranges, (long) ranges_size + 1);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
parser_comments(parser, comments, source, pm_options_freeze(options));
|
|
1017
|
+
parser_attachments(parser, comments, attachments, ranges, pm_options_freeze(options));
|
|
1018
|
+
|
|
1019
|
+
if (return_nodes) {
|
|
1020
|
+
VALUE value = rb_ary_new_capa(2);
|
|
1021
|
+
rb_ary_push(value, pm_ast_new(parser, node, parse_lex_data.encoding, source, pm_options_freeze(options)));
|
|
1022
|
+
rb_ary_push(value, parse_lex_data.tokens);
|
|
1023
|
+
if (pm_options_freeze(options)) rb_obj_freeze(value);
|
|
1024
|
+
result = result_ok(parse_result_create(rb_cPrismParseLexResult, parser, value, parse_lex_data.encoding, source, pm_options_freeze(options)));
|
|
1025
|
+
} else {
|
|
1026
|
+
result = result_ok(parse_result_create(rb_cPrismLexResult, parser, parse_lex_data.tokens, parse_lex_data.encoding, source, pm_options_freeze(options)));
|
|
1027
|
+
}
|
|
779
1028
|
}
|
|
780
1029
|
|
|
781
|
-
|
|
782
|
-
|
|
1030
|
+
pm_parser_free(parser);
|
|
1031
|
+
pm_arena_free(arena);
|
|
783
1032
|
|
|
784
1033
|
return result;
|
|
785
1034
|
}
|
|
786
1035
|
|
|
787
1036
|
/**
|
|
1037
|
+
* :markup: markdown
|
|
788
1038
|
* call-seq:
|
|
789
|
-
*
|
|
1039
|
+
* lex(source, **options) -> LexResult
|
|
790
1040
|
*
|
|
791
1041
|
* Return a LexResult instance that contains an array of Token instances
|
|
792
|
-
* corresponding to the given string. For supported options, see Prism
|
|
1042
|
+
* corresponding to the given string. For supported options, see Prism.parse.
|
|
793
1043
|
*/
|
|
794
1044
|
static VALUE
|
|
795
1045
|
lex(int argc, VALUE *argv, VALUE self) {
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
string_options(argc, argv, &input, &options);
|
|
1046
|
+
pm_options_t *options = pm_options_new();
|
|
1047
|
+
VALUE string = string_options(argc, argv, options);
|
|
799
1048
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
pm_options_free(&options);
|
|
1049
|
+
result_t result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, NULL, false);
|
|
1050
|
+
pm_options_free(options);
|
|
803
1051
|
|
|
804
|
-
return result;
|
|
1052
|
+
return result_get(result);
|
|
805
1053
|
}
|
|
806
1054
|
|
|
807
1055
|
/**
|
|
1056
|
+
* :markup: markdown
|
|
808
1057
|
* call-seq:
|
|
809
|
-
*
|
|
1058
|
+
* lex_file(filepath, **options) -> LexResult
|
|
810
1059
|
*
|
|
811
1060
|
* Return a LexResult instance that contains an array of Token instances
|
|
812
|
-
* corresponding to the given file. For supported options, see Prism
|
|
1061
|
+
* corresponding to the given file. For supported options, see Prism.parse.
|
|
813
1062
|
*/
|
|
814
1063
|
static VALUE
|
|
815
1064
|
lex_file(int argc, VALUE *argv, VALUE self) {
|
|
816
|
-
|
|
817
|
-
pm_options_t options = { 0 };
|
|
1065
|
+
pm_options_t *options = pm_options_new();
|
|
818
1066
|
|
|
819
1067
|
VALUE encoded_filepath;
|
|
820
|
-
file_options(argc, argv,
|
|
1068
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
821
1069
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
pm_options_free(
|
|
1070
|
+
result_t result = parse_lex_input(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath), false);
|
|
1071
|
+
pm_source_free(src);
|
|
1072
|
+
pm_options_free(options);
|
|
825
1073
|
|
|
826
|
-
return
|
|
1074
|
+
return result_get(result);
|
|
827
1075
|
}
|
|
828
1076
|
|
|
829
1077
|
/******************************************************************************/
|
|
@@ -833,35 +1081,47 @@ lex_file(int argc, VALUE *argv, VALUE self) {
|
|
|
833
1081
|
/**
|
|
834
1082
|
* Parse the given input and return a ParseResult instance.
|
|
835
1083
|
*/
|
|
836
|
-
static
|
|
837
|
-
parse_input(
|
|
838
|
-
|
|
839
|
-
|
|
1084
|
+
static result_t
|
|
1085
|
+
parse_input(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
1086
|
+
pm_arena_t *arena = pm_arena_new();
|
|
1087
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
1088
|
+
|
|
1089
|
+
pm_node_t *node = pm_parse(parser);
|
|
840
1090
|
|
|
841
|
-
|
|
842
|
-
|
|
1091
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
1092
|
+
if (result.type == RESULT_OK) {
|
|
1093
|
+
rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
|
|
843
1094
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1095
|
+
bool freeze = pm_options_freeze(options);
|
|
1096
|
+
VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
|
|
1097
|
+
VALUE attachments, ranges;
|
|
1098
|
+
parser_attachments_new(parser, &attachments, &ranges);
|
|
847
1099
|
|
|
848
|
-
|
|
849
|
-
|
|
1100
|
+
VALUE source = pm_source_new(parser, encoding, comments, attachments, ranges, freeze);
|
|
1101
|
+
parser_comments(parser, comments, source, freeze);
|
|
1102
|
+
parser_attachments(parser, comments, attachments, ranges, freeze);
|
|
1103
|
+
|
|
1104
|
+
VALUE value = pm_ast_new(parser, node, encoding, source, freeze);
|
|
1105
|
+
result = result_ok(parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, freeze));
|
|
850
1106
|
}
|
|
851
1107
|
|
|
852
|
-
|
|
853
|
-
|
|
1108
|
+
pm_parser_free(parser);
|
|
1109
|
+
pm_arena_free(arena);
|
|
854
1110
|
|
|
855
1111
|
return result;
|
|
856
1112
|
}
|
|
857
1113
|
|
|
858
1114
|
/**
|
|
1115
|
+
* :markup: markdown
|
|
859
1116
|
* call-seq:
|
|
860
|
-
*
|
|
1117
|
+
* parse(source, **options) -> ParseResult
|
|
861
1118
|
*
|
|
862
1119
|
* Parse the given string and return a ParseResult instance. The options that
|
|
863
1120
|
* are supported are:
|
|
864
1121
|
*
|
|
1122
|
+
* * `attach_comments` - whether or not to attach each comment to the node that
|
|
1123
|
+
* owns it. When set, the comments on the result are sorted by start
|
|
1124
|
+
* offset. This should be a boolean or nil.
|
|
865
1125
|
* * `command_line` - either nil or a string of the various options that were
|
|
866
1126
|
* set on the command line. Valid values are combinations of "a", "l",
|
|
867
1127
|
* "n", "p", and "x".
|
|
@@ -886,116 +1146,143 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
|
886
1146
|
* script that you know will be embedded inside another script later, but
|
|
887
1147
|
* you do not have that context yet. For example, when parsing an ERB
|
|
888
1148
|
* template that will be evaluated inside another script.
|
|
1149
|
+
* * `raise_error` - either nil, true, or a symbol indicating that an error
|
|
1150
|
+
* should be raised if the source contains any errors. The message of
|
|
1151
|
+
* the error will include the source of the lines that contain errors
|
|
1152
|
+
* when possible, and the value of this option controls how those lines
|
|
1153
|
+
* are formatted. Valid values are `:plain` (no formatting), `:style`
|
|
1154
|
+
* (bold formatting), and `:color` (bold and color formatting). When
|
|
1155
|
+
* `true` is given, the formatting is determined by whether or not
|
|
1156
|
+
* `$stderr` is a terminal and whether or not the `NO_COLOR` environment
|
|
1157
|
+
* variable is set, mirroring the behavior of CRuby itself. Syntax-level
|
|
1158
|
+
* errors raise SyntaxError, argument-level errors raise ArgumentError,
|
|
1159
|
+
* and load-level errors raise LoadError. Note that this option is
|
|
1160
|
+
* honored by every API that accepts these options, including predicates
|
|
1161
|
+
* like Prism.parse_success?, which will raise instead of returning a
|
|
1162
|
+
* boolean when the source contains errors.
|
|
889
1163
|
* * `scopes` - the locals that are in scope surrounding the code that is being
|
|
890
1164
|
* parsed. This should be an array of arrays of symbols or nil. Scopes are
|
|
891
1165
|
* ordered from the outermost scope to the innermost one.
|
|
892
1166
|
* * `version` - the version of Ruby syntax that prism should used to parse Ruby
|
|
893
|
-
* code. By default prism
|
|
894
|
-
*
|
|
895
|
-
* `"
|
|
896
|
-
*
|
|
897
|
-
*
|
|
898
|
-
*
|
|
1167
|
+
* code. By default prism parses with the syntax version nearest to the
|
|
1168
|
+
* current Ruby that is running (which you can trigger with `nil` or
|
|
1169
|
+
* `"nearest"`): the running version if prism supports it, otherwise the
|
|
1170
|
+
* closest version that it does support. You may also restrict the syntax
|
|
1171
|
+
* to a specific version of Ruby, e.g., with `"3.3.0"`. To parse with
|
|
1172
|
+
* exactly the same syntax version that the current Ruby is running use
|
|
1173
|
+
* `version: "current"`, which raises Prism::CurrentVersionError if prism
|
|
1174
|
+
* does not support it. To parse with the latest version of Ruby syntax
|
|
1175
|
+
* that prism supports, use `version: "latest"`. Raises ArgumentError if
|
|
1176
|
+
* the version is not currently supported by Prism.
|
|
899
1177
|
*/
|
|
900
1178
|
static VALUE
|
|
901
1179
|
parse(int argc, VALUE *argv, VALUE self) {
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1180
|
+
pm_options_t *options = pm_options_new();
|
|
1181
|
+
VALUE string = string_options(argc, argv, options);
|
|
1182
|
+
|
|
1183
|
+
const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
|
|
1184
|
+
size_t length = RSTRING_LEN(string);
|
|
905
1185
|
|
|
906
1186
|
#ifdef PRISM_BUILD_DEBUG
|
|
907
|
-
size_t length = pm_string_length(&input);
|
|
908
1187
|
char* dup = xmalloc(length);
|
|
909
|
-
memcpy(dup,
|
|
910
|
-
|
|
1188
|
+
memcpy(dup, source, length);
|
|
1189
|
+
source = (const uint8_t *) dup;
|
|
911
1190
|
#endif
|
|
912
1191
|
|
|
913
|
-
|
|
1192
|
+
result_t result = parse_input(source, length, options, NULL);
|
|
914
1193
|
|
|
915
1194
|
#ifdef PRISM_BUILD_DEBUG
|
|
1195
|
+
#ifdef xfree_sized
|
|
1196
|
+
xfree_sized(dup, length);
|
|
1197
|
+
#else
|
|
916
1198
|
xfree(dup);
|
|
1199
|
+
#endif
|
|
917
1200
|
#endif
|
|
918
1201
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
return value;
|
|
1202
|
+
pm_options_free(options);
|
|
1203
|
+
return result_get(result);
|
|
922
1204
|
}
|
|
923
1205
|
|
|
924
1206
|
/**
|
|
1207
|
+
* :markup: markdown
|
|
925
1208
|
* call-seq:
|
|
926
|
-
*
|
|
1209
|
+
* parse_file(filepath, **options) -> ParseResult
|
|
927
1210
|
*
|
|
928
1211
|
* Parse the given file and return a ParseResult instance. For supported
|
|
929
|
-
* options, see Prism
|
|
1212
|
+
* options, see Prism.parse.
|
|
930
1213
|
*/
|
|
931
1214
|
static VALUE
|
|
932
1215
|
parse_file(int argc, VALUE *argv, VALUE self) {
|
|
933
|
-
|
|
934
|
-
pm_options_t options = { 0 };
|
|
1216
|
+
pm_options_t *options = pm_options_new();
|
|
935
1217
|
|
|
936
1218
|
VALUE encoded_filepath;
|
|
937
|
-
file_options(argc, argv,
|
|
1219
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
938
1220
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
pm_options_free(
|
|
1221
|
+
result_t result = parse_input(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath));
|
|
1222
|
+
pm_source_free(src);
|
|
1223
|
+
pm_options_free(options);
|
|
942
1224
|
|
|
943
|
-
return
|
|
1225
|
+
return result_get(result);
|
|
944
1226
|
}
|
|
945
1227
|
|
|
946
1228
|
/**
|
|
947
1229
|
* Parse the given input and return nothing.
|
|
948
1230
|
*/
|
|
949
|
-
static
|
|
950
|
-
profile_input(
|
|
951
|
-
|
|
952
|
-
|
|
1231
|
+
static result_t
|
|
1232
|
+
profile_input(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
1233
|
+
pm_arena_t *arena = pm_arena_new();
|
|
1234
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
1235
|
+
|
|
1236
|
+
pm_parse(parser);
|
|
953
1237
|
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1238
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
1239
|
+
pm_parser_free(parser);
|
|
1240
|
+
pm_arena_free(arena);
|
|
1241
|
+
|
|
1242
|
+
return result;
|
|
957
1243
|
}
|
|
958
1244
|
|
|
959
1245
|
/**
|
|
1246
|
+
* :markup: markdown
|
|
960
1247
|
* call-seq:
|
|
961
|
-
*
|
|
1248
|
+
* profile(source, **options) -> nil
|
|
962
1249
|
*
|
|
963
1250
|
* Parse the given string and return nothing. This method is meant to allow
|
|
964
1251
|
* profilers to avoid the overhead of reifying the AST to Ruby. For supported
|
|
965
|
-
* options, see Prism
|
|
1252
|
+
* options, see Prism.parse.
|
|
966
1253
|
*/
|
|
967
1254
|
static VALUE
|
|
968
1255
|
profile(int argc, VALUE *argv, VALUE self) {
|
|
969
|
-
|
|
970
|
-
|
|
1256
|
+
pm_options_t *options = pm_options_new();
|
|
1257
|
+
VALUE string = string_options(argc, argv, options);
|
|
971
1258
|
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
pm_options_free(&options);
|
|
1259
|
+
result_t result = profile_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, NULL);
|
|
1260
|
+
pm_options_free(options);
|
|
1261
|
+
result_get(result);
|
|
976
1262
|
|
|
977
1263
|
return Qnil;
|
|
978
1264
|
}
|
|
979
1265
|
|
|
980
1266
|
/**
|
|
1267
|
+
* :markup: markdown
|
|
981
1268
|
* call-seq:
|
|
982
|
-
*
|
|
1269
|
+
* profile_file(filepath, **options) -> nil
|
|
983
1270
|
*
|
|
984
1271
|
* Parse the given file and return nothing. This method is meant to allow
|
|
985
1272
|
* profilers to avoid the overhead of reifying the AST to Ruby. For supported
|
|
986
|
-
* options, see Prism
|
|
1273
|
+
* options, see Prism.parse.
|
|
987
1274
|
*/
|
|
988
1275
|
static VALUE
|
|
989
1276
|
profile_file(int argc, VALUE *argv, VALUE self) {
|
|
990
|
-
|
|
991
|
-
pm_options_t options = { 0 };
|
|
1277
|
+
pm_options_t *options = pm_options_new();
|
|
992
1278
|
|
|
993
1279
|
VALUE encoded_filepath;
|
|
994
|
-
file_options(argc, argv,
|
|
1280
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
995
1281
|
|
|
996
|
-
profile_input(
|
|
997
|
-
|
|
998
|
-
pm_options_free(
|
|
1282
|
+
result_t result = profile_input(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath));
|
|
1283
|
+
pm_source_free(src);
|
|
1284
|
+
pm_options_free(options);
|
|
1285
|
+
result_get(result);
|
|
999
1286
|
|
|
1000
1287
|
return Qnil;
|
|
1001
1288
|
}
|
|
@@ -1009,13 +1296,40 @@ parse_stream_eof(void *stream) {
|
|
|
1009
1296
|
}
|
|
1010
1297
|
|
|
1011
1298
|
/**
|
|
1012
|
-
*
|
|
1299
|
+
* The largest number of bytes a single character can occupy in any encoding
|
|
1300
|
+
* that Ruby supports (CESU-8). `IO#gets(limit)` treats its argument as a soft
|
|
1301
|
+
* limit: to avoid splitting a multi-byte character it may return up to
|
|
1302
|
+
* `MAX_ENC_LEN - 1` more bytes than requested. Reserving `MAX_ENC_LEN` bytes of
|
|
1303
|
+
* headroom therefore leaves room for both that overshoot and the terminating
|
|
1304
|
+
* NUL byte.
|
|
1305
|
+
*
|
|
1306
|
+
* The value can be re-derived from the Ruby source tree with:
|
|
1307
|
+
*
|
|
1308
|
+
* grep -Erh "max (enc|byte) length" enc | grep -Eo '[0-9]+' | sort | tail -n1
|
|
1309
|
+
*/
|
|
1310
|
+
#define MAX_ENC_LEN 6
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* An implementation of fgets that is suitable for use with Ruby IO objects. As
|
|
1314
|
+
* required by pm_source_stream_fgets_t, this never writes more than `size`
|
|
1315
|
+
* bytes into `string` (including the terminating NUL byte).
|
|
1013
1316
|
*/
|
|
1014
1317
|
static char *
|
|
1015
1318
|
parse_stream_fgets(char *string, int size, void *stream) {
|
|
1016
|
-
RUBY_ASSERT(size >
|
|
1319
|
+
RUBY_ASSERT(size > MAX_ENC_LEN);
|
|
1320
|
+
|
|
1321
|
+
/*
|
|
1322
|
+
* Request fewer bytes than the buffer can hold. `gets` may return more
|
|
1323
|
+
* bytes than requested when the limit falls in the middle of a multi-byte
|
|
1324
|
+
* character, and the reserved headroom guarantees the result still fits.
|
|
1325
|
+
*/
|
|
1326
|
+
VALUE line = rb_funcall((VALUE) stream, rb_intern("gets"), 1, INT2FIX(size - MAX_ENC_LEN));
|
|
1017
1327
|
|
|
1018
|
-
|
|
1328
|
+
/*
|
|
1329
|
+
* A well-behaved stream returns a String, or nil at EOF. Coerce anything
|
|
1330
|
+
* else to nil so that we never treat a non-String as a byte buffer.
|
|
1331
|
+
*/
|
|
1332
|
+
line = rb_check_string_type(line);
|
|
1019
1333
|
if (NIL_P(line)) {
|
|
1020
1334
|
return NULL;
|
|
1021
1335
|
}
|
|
@@ -1023,18 +1337,30 @@ parse_stream_fgets(char *string, int size, void *stream) {
|
|
|
1023
1337
|
const char *cstr = RSTRING_PTR(line);
|
|
1024
1338
|
long length = RSTRING_LEN(line);
|
|
1025
1339
|
|
|
1026
|
-
|
|
1340
|
+
/*
|
|
1341
|
+
* Defensively clamp the copy. A misbehaving `gets` may ignore the limit
|
|
1342
|
+
* entirely and return an arbitrarily long string; we must never write past
|
|
1343
|
+
* the caller's buffer. One byte is reserved for the NUL terminator.
|
|
1344
|
+
*/
|
|
1345
|
+
if (length > (long) (size - 1)) {
|
|
1346
|
+
length = (long) (size - 1);
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
memcpy(string, cstr, (size_t) length);
|
|
1027
1350
|
string[length] = '\0';
|
|
1028
1351
|
|
|
1029
1352
|
return string;
|
|
1030
1353
|
}
|
|
1031
1354
|
|
|
1355
|
+
#undef MAX_ENC_LEN
|
|
1356
|
+
|
|
1032
1357
|
/**
|
|
1358
|
+
* :markup: markdown
|
|
1033
1359
|
* call-seq:
|
|
1034
|
-
*
|
|
1360
|
+
* parse_stream(stream, **options) -> ParseResult
|
|
1035
1361
|
*
|
|
1036
1362
|
* Parse the given object that responds to `gets` and return a ParseResult
|
|
1037
|
-
* instance. The options that are supported are the same as Prism
|
|
1363
|
+
* instance. The options that are supported are the same as Prism.parse.
|
|
1038
1364
|
*/
|
|
1039
1365
|
static VALUE
|
|
1040
1366
|
parse_stream(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1042,187 +1368,213 @@ parse_stream(int argc, VALUE *argv, VALUE self) {
|
|
|
1042
1368
|
VALUE keywords;
|
|
1043
1369
|
rb_scan_args(argc, argv, "1:", &stream, &keywords);
|
|
1044
1370
|
|
|
1045
|
-
pm_options_t options =
|
|
1046
|
-
extract_options(
|
|
1371
|
+
pm_options_t *options = pm_options_new();
|
|
1372
|
+
extract_options(options, Qnil, keywords);
|
|
1047
1373
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1374
|
+
pm_source_t *src = pm_source_stream_new((void *) stream, parse_stream_fgets, parse_stream_eof);
|
|
1375
|
+
pm_arena_t *arena = pm_arena_new();
|
|
1376
|
+
pm_parser_t *parser;
|
|
1050
1377
|
|
|
1051
|
-
pm_node_t *node = pm_parse_stream(&parser,
|
|
1052
|
-
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
|
1378
|
+
pm_node_t *node = pm_parse_stream(&parser, arena, src, options);
|
|
1053
1379
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1380
|
+
result_t result = check_raise_error_option(parser, options, NULL);
|
|
1381
|
+
if (result.type == RESULT_OK) {
|
|
1382
|
+
rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
|
|
1057
1383
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1384
|
+
VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
|
|
1385
|
+
VALUE attachments, ranges;
|
|
1386
|
+
parser_attachments_new(parser, &attachments, &ranges);
|
|
1061
1387
|
|
|
1062
|
-
|
|
1388
|
+
VALUE source = pm_source_new(parser, encoding, comments, attachments, ranges, pm_options_freeze(options));
|
|
1389
|
+
parser_comments(parser, comments, source, pm_options_freeze(options));
|
|
1390
|
+
parser_attachments(parser, comments, attachments, ranges, pm_options_freeze(options));
|
|
1391
|
+
|
|
1392
|
+
VALUE value = pm_ast_new(parser, node, encoding, source, pm_options_freeze(options));
|
|
1393
|
+
|
|
1394
|
+
result = result_ok(parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, pm_options_freeze(options)));
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
pm_source_free(src);
|
|
1398
|
+
pm_parser_free(parser);
|
|
1399
|
+
pm_arena_free(arena);
|
|
1400
|
+
pm_options_free(options);
|
|
1401
|
+
|
|
1402
|
+
return result_get(result);
|
|
1063
1403
|
}
|
|
1064
1404
|
|
|
1065
1405
|
/**
|
|
1066
1406
|
* Parse the given input and return an array of Comment objects.
|
|
1067
1407
|
*/
|
|
1068
|
-
static
|
|
1069
|
-
parse_input_comments(
|
|
1070
|
-
|
|
1071
|
-
|
|
1408
|
+
static result_t
|
|
1409
|
+
parse_input_comments(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
1410
|
+
pm_arena_t *arena = pm_arena_new();
|
|
1411
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
1412
|
+
|
|
1413
|
+
pm_parse(parser);
|
|
1072
1414
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1415
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
1416
|
+
if (result.type == RESULT_OK) {
|
|
1417
|
+
rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
|
|
1075
1418
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1419
|
+
VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
|
|
1420
|
+
VALUE attachments, ranges;
|
|
1421
|
+
parser_attachments_new(parser, &attachments, &ranges);
|
|
1078
1422
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1423
|
+
VALUE source = pm_source_new(parser, encoding, comments, attachments, ranges, pm_options_freeze(options));
|
|
1424
|
+
parser_comments(parser, comments, source, pm_options_freeze(options));
|
|
1425
|
+
parser_attachments(parser, comments, attachments, ranges, pm_options_freeze(options));
|
|
1426
|
+
|
|
1427
|
+
result = result_ok(comments);
|
|
1428
|
+
}
|
|
1081
1429
|
|
|
1082
|
-
|
|
1430
|
+
pm_parser_free(parser);
|
|
1431
|
+
pm_arena_free(arena);
|
|
1432
|
+
|
|
1433
|
+
return result;
|
|
1083
1434
|
}
|
|
1084
1435
|
|
|
1085
1436
|
/**
|
|
1437
|
+
* :markup: markdown
|
|
1086
1438
|
* call-seq:
|
|
1087
|
-
*
|
|
1439
|
+
* parse_comments(source, **options) -> Array
|
|
1088
1440
|
*
|
|
1089
1441
|
* Parse the given string and return an array of Comment objects. For supported
|
|
1090
|
-
* options, see Prism
|
|
1442
|
+
* options, see Prism.parse.
|
|
1091
1443
|
*/
|
|
1092
1444
|
static VALUE
|
|
1093
1445
|
parse_comments(int argc, VALUE *argv, VALUE self) {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
string_options(argc, argv, &input, &options);
|
|
1446
|
+
pm_options_t *options = pm_options_new();
|
|
1447
|
+
VALUE string = string_options(argc, argv, options);
|
|
1097
1448
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
pm_options_free(&options);
|
|
1449
|
+
result_t result = parse_input_comments((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, NULL);
|
|
1450
|
+
pm_options_free(options);
|
|
1101
1451
|
|
|
1102
|
-
return result;
|
|
1452
|
+
return result_get(result);
|
|
1103
1453
|
}
|
|
1104
1454
|
|
|
1105
1455
|
/**
|
|
1456
|
+
* :markup: markdown
|
|
1106
1457
|
* call-seq:
|
|
1107
|
-
*
|
|
1458
|
+
* parse_file_comments(filepath, **options) -> Array
|
|
1108
1459
|
*
|
|
1109
1460
|
* Parse the given file and return an array of Comment objects. For supported
|
|
1110
|
-
* options, see Prism
|
|
1461
|
+
* options, see Prism.parse.
|
|
1111
1462
|
*/
|
|
1112
1463
|
static VALUE
|
|
1113
1464
|
parse_file_comments(int argc, VALUE *argv, VALUE self) {
|
|
1114
|
-
|
|
1115
|
-
pm_options_t options = { 0 };
|
|
1465
|
+
pm_options_t *options = pm_options_new();
|
|
1116
1466
|
|
|
1117
1467
|
VALUE encoded_filepath;
|
|
1118
|
-
file_options(argc, argv,
|
|
1468
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
1119
1469
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
pm_options_free(
|
|
1470
|
+
result_t result = parse_input_comments(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath));
|
|
1471
|
+
pm_source_free(src);
|
|
1472
|
+
pm_options_free(options);
|
|
1123
1473
|
|
|
1124
|
-
return
|
|
1474
|
+
return result_get(result);
|
|
1125
1475
|
}
|
|
1126
1476
|
|
|
1127
1477
|
/**
|
|
1478
|
+
* :markup: markdown
|
|
1128
1479
|
* call-seq:
|
|
1129
|
-
*
|
|
1480
|
+
* parse_lex(source, **options) -> ParseLexResult
|
|
1130
1481
|
*
|
|
1131
1482
|
* Parse the given string and return a ParseLexResult instance that contains a
|
|
1132
1483
|
* 2-element array, where the first element is the AST and the second element is
|
|
1133
1484
|
* an array of Token instances.
|
|
1134
1485
|
*
|
|
1135
1486
|
* This API is only meant to be used in the case where you need both the AST and
|
|
1136
|
-
* the tokens. If you only need one or the other, use either Prism
|
|
1137
|
-
* Prism
|
|
1487
|
+
* the tokens. If you only need one or the other, use either Prism.parse or
|
|
1488
|
+
* Prism.lex.
|
|
1138
1489
|
*
|
|
1139
|
-
* For supported options, see Prism
|
|
1490
|
+
* For supported options, see Prism.parse.
|
|
1140
1491
|
*/
|
|
1141
1492
|
static VALUE
|
|
1142
1493
|
parse_lex(int argc, VALUE *argv, VALUE self) {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
string_options(argc, argv, &input, &options);
|
|
1494
|
+
pm_options_t *options = pm_options_new();
|
|
1495
|
+
VALUE string = string_options(argc, argv, options);
|
|
1146
1496
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
pm_options_free(&options);
|
|
1497
|
+
result_t result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, NULL, true);
|
|
1498
|
+
pm_options_free(options);
|
|
1150
1499
|
|
|
1151
|
-
return
|
|
1500
|
+
return result_get(result);
|
|
1152
1501
|
}
|
|
1153
1502
|
|
|
1154
1503
|
/**
|
|
1504
|
+
* :markup: markdown
|
|
1155
1505
|
* call-seq:
|
|
1156
|
-
*
|
|
1506
|
+
* parse_lex_file(filepath, **options) -> ParseLexResult
|
|
1157
1507
|
*
|
|
1158
1508
|
* Parse the given file and return a ParseLexResult instance that contains a
|
|
1159
1509
|
* 2-element array, where the first element is the AST and the second element is
|
|
1160
1510
|
* an array of Token instances.
|
|
1161
1511
|
*
|
|
1162
1512
|
* This API is only meant to be used in the case where you need both the AST and
|
|
1163
|
-
* the tokens. If you only need one or the other, use either Prism
|
|
1164
|
-
* or Prism
|
|
1513
|
+
* the tokens. If you only need one or the other, use either Prism.parse_file
|
|
1514
|
+
* or Prism.lex_file.
|
|
1165
1515
|
*
|
|
1166
|
-
* For supported options, see Prism
|
|
1516
|
+
* For supported options, see Prism.parse.
|
|
1167
1517
|
*/
|
|
1168
1518
|
static VALUE
|
|
1169
1519
|
parse_lex_file(int argc, VALUE *argv, VALUE self) {
|
|
1170
|
-
|
|
1171
|
-
pm_options_t options = { 0 };
|
|
1520
|
+
pm_options_t *options = pm_options_new();
|
|
1172
1521
|
|
|
1173
1522
|
VALUE encoded_filepath;
|
|
1174
|
-
file_options(argc, argv,
|
|
1523
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
1175
1524
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
pm_options_free(
|
|
1525
|
+
result_t result = parse_lex_input(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath), true);
|
|
1526
|
+
pm_source_free(src);
|
|
1527
|
+
pm_options_free(options);
|
|
1179
1528
|
|
|
1180
|
-
return
|
|
1529
|
+
return result_get(result);
|
|
1181
1530
|
}
|
|
1182
1531
|
|
|
1183
1532
|
/**
|
|
1184
1533
|
* Parse the given input and return true if it parses without errors.
|
|
1185
1534
|
*/
|
|
1186
|
-
static
|
|
1187
|
-
parse_input_success_p(
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1535
|
+
static result_t
|
|
1536
|
+
parse_input_success_p(const uint8_t *input, size_t input_length, const pm_options_t *options, rb_encoding *path_encoding) {
|
|
1537
|
+
pm_arena_t *arena = pm_arena_new();
|
|
1538
|
+
pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
|
|
1539
|
+
pm_parse(parser);
|
|
1540
|
+
|
|
1541
|
+
result_t result = check_raise_error_option(parser, options, path_encoding);
|
|
1542
|
+
if (result.type == RESULT_OK) {
|
|
1543
|
+
result = result_ok(pm_parser_errors_size(parser) == 0 ? Qtrue : Qfalse);
|
|
1544
|
+
}
|
|
1193
1545
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1546
|
+
pm_parser_free(parser);
|
|
1547
|
+
pm_arena_free(arena);
|
|
1196
1548
|
|
|
1197
1549
|
return result;
|
|
1198
1550
|
}
|
|
1199
1551
|
|
|
1200
1552
|
/**
|
|
1553
|
+
* :markup: markdown
|
|
1201
1554
|
* call-seq:
|
|
1202
|
-
*
|
|
1555
|
+
* parse_success?(source, **options) -> bool
|
|
1203
1556
|
*
|
|
1204
1557
|
* Parse the given string and return true if it parses without errors. For
|
|
1205
|
-
* supported options, see Prism
|
|
1558
|
+
* supported options, see Prism.parse.
|
|
1206
1559
|
*/
|
|
1207
1560
|
static VALUE
|
|
1208
1561
|
parse_success_p(int argc, VALUE *argv, VALUE self) {
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
string_options(argc, argv, &input, &options);
|
|
1562
|
+
pm_options_t *options = pm_options_new();
|
|
1563
|
+
VALUE string = string_options(argc, argv, options);
|
|
1212
1564
|
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
pm_options_free(&options);
|
|
1565
|
+
result_t result = parse_input_success_p((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, NULL);
|
|
1566
|
+
pm_options_free(options);
|
|
1216
1567
|
|
|
1217
|
-
return result;
|
|
1568
|
+
return result_get(result);
|
|
1218
1569
|
}
|
|
1219
1570
|
|
|
1220
1571
|
/**
|
|
1572
|
+
* :markup: markdown
|
|
1221
1573
|
* call-seq:
|
|
1222
|
-
*
|
|
1574
|
+
* parse_failure?(source, **options) -> bool
|
|
1223
1575
|
*
|
|
1224
1576
|
* Parse the given string and return true if it parses with errors. For
|
|
1225
|
-
* supported options, see Prism
|
|
1577
|
+
* supported options, see Prism.parse.
|
|
1226
1578
|
*/
|
|
1227
1579
|
static VALUE
|
|
1228
1580
|
parse_failure_p(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1230,33 +1582,34 @@ parse_failure_p(int argc, VALUE *argv, VALUE self) {
|
|
|
1230
1582
|
}
|
|
1231
1583
|
|
|
1232
1584
|
/**
|
|
1585
|
+
* :markup: markdown
|
|
1233
1586
|
* call-seq:
|
|
1234
|
-
*
|
|
1587
|
+
* parse_file_success?(filepath, **options) -> bool
|
|
1235
1588
|
*
|
|
1236
1589
|
* Parse the given file and return true if it parses without errors. For
|
|
1237
|
-
* supported options, see Prism
|
|
1590
|
+
* supported options, see Prism.parse.
|
|
1238
1591
|
*/
|
|
1239
1592
|
static VALUE
|
|
1240
1593
|
parse_file_success_p(int argc, VALUE *argv, VALUE self) {
|
|
1241
|
-
|
|
1242
|
-
pm_options_t options = { 0 };
|
|
1594
|
+
pm_options_t *options = pm_options_new();
|
|
1243
1595
|
|
|
1244
1596
|
VALUE encoded_filepath;
|
|
1245
|
-
file_options(argc, argv,
|
|
1597
|
+
pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
|
|
1246
1598
|
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
pm_options_free(
|
|
1599
|
+
result_t result = parse_input_success_p(pm_source_source(src), pm_source_length(src), options, rb_enc_get(encoded_filepath));
|
|
1600
|
+
pm_source_free(src);
|
|
1601
|
+
pm_options_free(options);
|
|
1250
1602
|
|
|
1251
|
-
return result;
|
|
1603
|
+
return result_get(result);
|
|
1252
1604
|
}
|
|
1253
1605
|
|
|
1254
1606
|
/**
|
|
1607
|
+
* :markup: markdown
|
|
1255
1608
|
* call-seq:
|
|
1256
|
-
*
|
|
1609
|
+
* parse_file_failure?(filepath, **options) -> bool
|
|
1257
1610
|
*
|
|
1258
1611
|
* Parse the given file and return true if it parses with errors. For
|
|
1259
|
-
* supported options, see Prism
|
|
1612
|
+
* supported options, see Prism.parse.
|
|
1260
1613
|
*/
|
|
1261
1614
|
static VALUE
|
|
1262
1615
|
parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1286,8 +1639,9 @@ string_query(pm_string_query_t result) {
|
|
|
1286
1639
|
}
|
|
1287
1640
|
|
|
1288
1641
|
/**
|
|
1642
|
+
* :markup: markdown
|
|
1289
1643
|
* call-seq:
|
|
1290
|
-
*
|
|
1644
|
+
* local?(string) -> bool
|
|
1291
1645
|
*
|
|
1292
1646
|
* Returns true if the string constitutes a valid local variable name. Note that
|
|
1293
1647
|
* this means the names that can be set through Binding#local_variable_set, not
|
|
@@ -1300,8 +1654,9 @@ string_query_local_p(VALUE self, VALUE string) {
|
|
|
1300
1654
|
}
|
|
1301
1655
|
|
|
1302
1656
|
/**
|
|
1657
|
+
* :markup: markdown
|
|
1303
1658
|
* call-seq:
|
|
1304
|
-
*
|
|
1659
|
+
* constant?(string) -> bool
|
|
1305
1660
|
*
|
|
1306
1661
|
* Returns true if the string constitutes a valid constant name. Note that this
|
|
1307
1662
|
* means the names that can be set through Module#const_set, not necessarily the
|
|
@@ -1314,8 +1669,9 @@ string_query_constant_p(VALUE self, VALUE string) {
|
|
|
1314
1669
|
}
|
|
1315
1670
|
|
|
1316
1671
|
/**
|
|
1672
|
+
* :markup: markdown
|
|
1317
1673
|
* call-seq:
|
|
1318
|
-
*
|
|
1674
|
+
* method_name?(string) -> bool
|
|
1319
1675
|
*
|
|
1320
1676
|
* Returns true if the string constitutes a valid method name.
|
|
1321
1677
|
*/
|
|
@@ -1325,6 +1681,20 @@ string_query_method_name_p(VALUE self, VALUE string) {
|
|
|
1325
1681
|
return string_query(pm_string_query_method_name(source, RSTRING_LEN(string), rb_enc_get(string)->name));
|
|
1326
1682
|
}
|
|
1327
1683
|
|
|
1684
|
+
/**
|
|
1685
|
+
* :markup: markdown
|
|
1686
|
+
* call-seq:
|
|
1687
|
+
* keyword?(string) -> bool
|
|
1688
|
+
*
|
|
1689
|
+
* Returns true if the string is a valid keyword, such as `if`, `defined?`, or
|
|
1690
|
+
* `__FILE__`.
|
|
1691
|
+
*/
|
|
1692
|
+
static VALUE
|
|
1693
|
+
string_query_keyword_p(VALUE self, VALUE string) {
|
|
1694
|
+
const uint8_t *source = (const uint8_t *) check_string(string);
|
|
1695
|
+
return string_query(pm_string_query_keyword(source, RSTRING_LEN(string), rb_enc_get(string)->name));
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1328
1698
|
/******************************************************************************/
|
|
1329
1699
|
/* Initialization of the extension */
|
|
1330
1700
|
/******************************************************************************/
|
|
@@ -1334,8 +1704,8 @@ string_query_method_name_p(VALUE self, VALUE string) {
|
|
|
1334
1704
|
*/
|
|
1335
1705
|
RUBY_FUNC_EXPORTED void
|
|
1336
1706
|
Init_prism(void) {
|
|
1337
|
-
|
|
1338
|
-
|
|
1707
|
+
/* Make sure that the prism library version matches the expected version.
|
|
1708
|
+
* Otherwise something was compiled incorrectly. */
|
|
1339
1709
|
if (strcmp(pm_version(), EXPECTED_PRISM_VERSION) != 0) {
|
|
1340
1710
|
rb_raise(
|
|
1341
1711
|
rb_eRuntimeError,
|
|
@@ -1346,12 +1716,10 @@ Init_prism(void) {
|
|
|
1346
1716
|
}
|
|
1347
1717
|
|
|
1348
1718
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
1349
|
-
|
|
1719
|
+
/* Mark this extension as Ractor-safe. */
|
|
1350
1720
|
rb_ext_ractor_safe(true);
|
|
1351
1721
|
#endif
|
|
1352
1722
|
|
|
1353
|
-
// Grab up references to all of the constants that we're going to need to
|
|
1354
|
-
// reference throughout this extension.
|
|
1355
1723
|
rb_cPrism = rb_define_module("Prism");
|
|
1356
1724
|
rb_cPrismNode = rb_define_class_under(rb_cPrism, "Node", rb_cObject);
|
|
1357
1725
|
rb_cPrismSource = rb_define_class_under(rb_cPrism, "Source", rb_cObject);
|
|
@@ -1372,8 +1740,9 @@ Init_prism(void) {
|
|
|
1372
1740
|
|
|
1373
1741
|
rb_cPrismCurrentVersionError = rb_const_get(rb_cPrism, rb_intern("CurrentVersionError"));
|
|
1374
1742
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1743
|
+
/* Intern all of the IDs eagerly that we support so that we do not have to
|
|
1744
|
+
* do it every time we parse. */
|
|
1745
|
+
rb_id_option_attach_comments = rb_intern_const("attach_comments");
|
|
1377
1746
|
rb_id_option_command_line = rb_intern_const("command_line");
|
|
1378
1747
|
rb_id_option_encoding = rb_intern_const("encoding");
|
|
1379
1748
|
rb_id_option_filepath = rb_intern_const("filepath");
|
|
@@ -1382,20 +1751,26 @@ Init_prism(void) {
|
|
|
1382
1751
|
rb_id_option_line = rb_intern_const("line");
|
|
1383
1752
|
rb_id_option_main_script = rb_intern_const("main_script");
|
|
1384
1753
|
rb_id_option_partial_script = rb_intern_const("partial_script");
|
|
1754
|
+
rb_id_option_raise_error = rb_intern_const("raise_error");
|
|
1385
1755
|
rb_id_option_scopes = rb_intern_const("scopes");
|
|
1386
1756
|
rb_id_option_version = rb_intern_const("version");
|
|
1757
|
+
|
|
1387
1758
|
rb_id_source_for = rb_intern("for");
|
|
1759
|
+
|
|
1388
1760
|
rb_id_forwarding_positionals = rb_intern("*");
|
|
1389
1761
|
rb_id_forwarding_keywords = rb_intern("**");
|
|
1390
1762
|
rb_id_forwarding_block = rb_intern("&");
|
|
1391
1763
|
rb_id_forwarding_all = rb_intern("...");
|
|
1392
1764
|
|
|
1765
|
+
rb_id_raise_error_plain = rb_intern_const("plain");
|
|
1766
|
+
rb_id_raise_error_style = rb_intern_const("style");
|
|
1767
|
+
rb_id_raise_error_color = rb_intern_const("color");
|
|
1768
|
+
|
|
1393
1769
|
/**
|
|
1394
1770
|
* The version of the prism library.
|
|
1395
1771
|
*/
|
|
1396
1772
|
rb_define_const(rb_cPrism, "VERSION", rb_str_freeze(rb_str_new_cstr(EXPECTED_PRISM_VERSION)));
|
|
1397
1773
|
|
|
1398
|
-
// First, the functions that have to do with lexing and parsing.
|
|
1399
1774
|
rb_define_singleton_method(rb_cPrism, "lex", lex, -1);
|
|
1400
1775
|
rb_define_singleton_method(rb_cPrism, "lex_file", lex_file, -1);
|
|
1401
1776
|
rb_define_singleton_method(rb_cPrism, "parse", parse, -1);
|
|
@@ -1420,8 +1795,7 @@ Init_prism(void) {
|
|
|
1420
1795
|
rb_define_singleton_method(rb_cPrismStringQuery, "local?", string_query_local_p, 1);
|
|
1421
1796
|
rb_define_singleton_method(rb_cPrismStringQuery, "constant?", string_query_constant_p, 1);
|
|
1422
1797
|
rb_define_singleton_method(rb_cPrismStringQuery, "method_name?", string_query_method_name_p, 1);
|
|
1798
|
+
rb_define_singleton_method(rb_cPrismStringQuery, "keyword?", string_query_keyword_p, 1);
|
|
1423
1799
|
|
|
1424
|
-
// Next, initialize the other APIs.
|
|
1425
1800
|
Init_prism_api_node();
|
|
1426
|
-
Init_prism_pack();
|
|
1427
1801
|
}
|