Ruby 4.1.0dev (2026-04-04 revision 3b6245536cf55da9e8bfcdb03c845fe9ef931d7f)
extension.c
1#include "prism/extension.h"
2
3#ifdef _WIN32
4#include <ruby/win32.h>
5#endif
6
7#include <errno.h>
8
9// NOTE: this file should contain only bindings. All non-trivial logic should be
10// in libprism so it can be shared its the various callers.
11
12VALUE rb_cPrism;
13VALUE rb_cPrismNode;
14VALUE rb_cPrismSource;
15VALUE rb_cPrismToken;
16VALUE rb_cPrismLocation;
17
18VALUE rb_cPrismComment;
19VALUE rb_cPrismInlineComment;
20VALUE rb_cPrismEmbDocComment;
21VALUE rb_cPrismMagicComment;
22VALUE rb_cPrismParseError;
23VALUE rb_cPrismParseWarning;
24VALUE rb_cPrismResult;
25VALUE rb_cPrismParseResult;
26VALUE rb_cPrismLexResult;
27VALUE rb_cPrismParseLexResult;
28VALUE rb_cPrismStringQuery;
29VALUE rb_cPrismScope;
30VALUE rb_cPrismCurrentVersionError;
31
32VALUE rb_cPrismDebugEncoding;
33
34ID rb_id_option_command_line;
35ID rb_id_option_encoding;
36ID rb_id_option_filepath;
37ID rb_id_option_freeze;
38ID rb_id_option_frozen_string_literal;
39ID rb_id_option_line;
40ID rb_id_option_main_script;
41ID rb_id_option_partial_script;
42ID rb_id_option_scopes;
43ID rb_id_option_version;
44ID rb_id_source_for;
45ID rb_id_forwarding_positionals;
46ID rb_id_forwarding_keywords;
47ID rb_id_forwarding_block;
48ID rb_id_forwarding_all;
49
50/******************************************************************************/
51/* IO of Ruby code */
52/******************************************************************************/
53
58static const char *
59check_string(VALUE value) {
60 // Check if the value is a string. If it's not, then raise a type error.
61 if (!RB_TYPE_P(value, T_STRING)) {
62 rb_raise(rb_eTypeError, "wrong argument type %" PRIsVALUE " (expected String)", rb_obj_class(value));
63 }
64
65 // Otherwise, return the value as a C string.
66 return RSTRING_PTR(value);
67}
68
69
70/******************************************************************************/
71/* Building C options from Ruby options */
72/******************************************************************************/
73
77static void
78build_options_scopes(pm_options_t *options, VALUE scopes) {
79 // Check if the value is an array. If it's not, then raise a type error.
80 if (!RB_TYPE_P(scopes, T_ARRAY)) {
81 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(scopes));
82 }
83
84 // Initialize the scopes array.
85 size_t scopes_count = RARRAY_LEN(scopes);
86 if (!pm_options_scopes_init(options, scopes_count)) {
87 rb_raise(rb_eNoMemError, "failed to allocate memory");
88 }
89
90 // Iterate over the scopes and add them to the options.
91 for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
92 VALUE scope = rb_ary_entry(scopes, scope_index);
93
94 // The scope can be either an array or it can be a Prism::Scope object.
95 // Parse out the correct values here from either.
96 VALUE locals;
97 uint8_t forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
98
99 if (RB_TYPE_P(scope, T_ARRAY)) {
100 locals = scope;
101 } else if (rb_obj_is_kind_of(scope, rb_cPrismScope)) {
102 locals = rb_ivar_get(scope, rb_intern("@locals"));
103 if (!RB_TYPE_P(locals, T_ARRAY)) {
104 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(locals));
105 }
106
107 VALUE names = rb_ivar_get(scope, rb_intern("@forwarding"));
108 if (!RB_TYPE_P(names, T_ARRAY)) {
109 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array)", rb_obj_class(names));
110 }
111
112 size_t names_count = RARRAY_LEN(names);
113 for (size_t name_index = 0; name_index < names_count; name_index++) {
114 VALUE name = rb_ary_entry(names, name_index);
115
116 // Check that the name is a symbol. If it's not, then raise
117 // a type error.
118 if (!RB_TYPE_P(name, T_SYMBOL)) {
119 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(name));
120 }
121
122 ID id = SYM2ID(name);
123 if (id == rb_id_forwarding_positionals) {
125 } else if (id == rb_id_forwarding_keywords) {
127 } else if (id == rb_id_forwarding_block) {
129 } else if (id == rb_id_forwarding_all) {
131 } else {
132 rb_raise(rb_eArgError, "invalid forwarding value: %" PRIsVALUE, name);
133 }
134 }
135 } else {
136 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Array or Prism::Scope)", rb_obj_class(scope));
137 }
138
139 // Initialize the scope array.
140 size_t locals_count = RARRAY_LEN(locals);
141 pm_options_scope_t *options_scope = pm_options_scope_mut(options, scope_index);
142 pm_options_scope_init(options_scope, locals_count);
143
144 // Iterate over the locals and add them to the scope.
145 for (size_t local_index = 0; local_index < locals_count; local_index++) {
146 VALUE local = rb_ary_entry(locals, local_index);
147
148 // Check that the local is a symbol. If it's not, then raise a
149 // type error.
150 if (!RB_TYPE_P(local, T_SYMBOL)) {
151 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Symbol)", rb_obj_class(local));
152 }
153
154 // Add the local to the scope.
155 pm_string_t *scope_local = pm_options_scope_local_mut(options_scope, local_index);
156 const char *name = rb_id2name(SYM2ID(local));
157 pm_string_constant_init(scope_local, name, strlen(name));
158 }
159
160 // Now set the forwarding options.
161 pm_options_scope_forwarding_set(options_scope, forwarding);
162 }
163}
164
168static int
169build_options_i(VALUE key, VALUE value, VALUE argument) {
170 pm_options_t *options = (pm_options_t *) argument;
171 ID key_id = SYM2ID(key);
172
173 if (key_id == rb_id_option_filepath) {
174 if (!NIL_P(value)) pm_options_filepath_set(options, check_string(value));
175 } else if (key_id == rb_id_option_encoding) {
176 if (!NIL_P(value)) {
177 if (value == Qfalse) {
178 pm_options_encoding_locked_set(options, true);
179 } else {
180 pm_options_encoding_set(options, rb_enc_name(rb_to_encoding(value)));
181 }
182 }
183 } else if (key_id == rb_id_option_line) {
184 if (!NIL_P(value)) pm_options_line_set(options, NUM2INT(value));
185 } else if (key_id == rb_id_option_frozen_string_literal) {
186 if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, RTEST(value));
187 } else if (key_id == rb_id_option_version) {
188 if (!NIL_P(value)) {
189 const char *version = check_string(value);
190
191 if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
192 if (!pm_options_version_set(options, ruby_version, 3)) {
193 rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
194 }
195 } else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
196 if (!pm_options_version_set(options, ruby_version, 3)) {
197 // Prism doesn't know this specific version. Is it lower?
198 if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
199 pm_options_version_set_lowest(options);
200 } else {
201 // Must be higher.
202 pm_options_version_set_highest(options);
203 }
204 }
205 } else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
206 rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
207 }
208 }
209 } else if (key_id == rb_id_option_scopes) {
210 if (!NIL_P(value)) build_options_scopes(options, value);
211 } else if (key_id == rb_id_option_command_line) {
212 if (!NIL_P(value)) {
213 const char *string = check_string(value);
214 uint8_t command_line = 0;
215
216 for (size_t index = 0; index < strlen(string); index++) {
217 switch (string[index]) {
218 case 'a': command_line |= PM_OPTIONS_COMMAND_LINE_A; break;
219 case 'e': command_line |= PM_OPTIONS_COMMAND_LINE_E; break;
220 case 'l': command_line |= PM_OPTIONS_COMMAND_LINE_L; break;
221 case 'n': command_line |= PM_OPTIONS_COMMAND_LINE_N; break;
222 case 'p': command_line |= PM_OPTIONS_COMMAND_LINE_P; break;
223 case 'x': command_line |= PM_OPTIONS_COMMAND_LINE_X; break;
224 default: rb_raise(rb_eArgError, "invalid command line flag: '%c'", string[index]); break;
225 }
226 }
227
228 pm_options_command_line_set(options, command_line);
229 }
230 } else if (key_id == rb_id_option_main_script) {
231 if (!NIL_P(value)) pm_options_main_script_set(options, RTEST(value));
232 } else if (key_id == rb_id_option_partial_script) {
233 if (!NIL_P(value)) pm_options_partial_script_set(options, RTEST(value));
234 } else if (key_id == rb_id_option_freeze) {
235 if (!NIL_P(value)) pm_options_freeze_set(options, RTEST(value));
236 } else {
237 rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, key);
238 }
239
240 return ST_CONTINUE;
241}
242
249 pm_options_t *options;
250 VALUE keywords;
251};
252
257static VALUE
258build_options(VALUE argument) {
259 struct build_options_data *data = (struct build_options_data *) argument;
260 rb_hash_foreach(data->keywords, build_options_i, (VALUE) data->options);
261 return Qnil;
262}
263
267static void
268extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
269 pm_options_line_set(options, 1); /* default */
270
271 if (!NIL_P(keywords)) {
272 struct build_options_data data = { .options = options, .keywords = keywords };
273 struct build_options_data *argument = &data;
274
275 int state = 0;
276 rb_protect(build_options, (VALUE) argument, &state);
277
278 if (state != 0) {
279 pm_options_free(options);
280 rb_jump_tag(state);
281 }
282 }
283
284 if (!NIL_P(filepath)) {
285 if (!RB_TYPE_P(filepath, T_STRING)) {
286 pm_options_free(options);
287 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(filepath));
288 }
289
290 pm_options_filepath_set(options, RSTRING_PTR(filepath));
291 }
292}
293
297static VALUE
298string_options(int argc, VALUE *argv, pm_options_t *options) {
299 VALUE string;
300 VALUE keywords;
301 rb_scan_args(argc, argv, "1:", &string, &keywords);
302
303 if (!RB_TYPE_P(string, T_STRING)) {
304 pm_options_free(options);
305 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(string));
306 }
307
308 extract_options(options, Qnil, keywords);
309 return string;
310}
311
315static pm_source_t *
316file_options(int argc, VALUE *argv, pm_options_t *options, VALUE *encoded_filepath) {
317 VALUE filepath;
318 VALUE keywords;
319 rb_scan_args(argc, argv, "1:", &filepath, &keywords);
320
321 if (!RB_TYPE_P(filepath, T_STRING)) {
322 pm_options_free(options);
323 rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected String)", rb_obj_class(filepath));
324 }
325
326 *encoded_filepath = rb_str_encode_ospath(filepath);
327 extract_options(options, *encoded_filepath, keywords);
328
329 const char *source = (const char *) pm_string_source(pm_options_filepath(options));
331 pm_source_t *pm_src = pm_source_file_new(source, &result);
332
333 switch (result) {
335 break;
337 pm_options_free(options);
338
339#ifdef _WIN32
340 int e = rb_w32_map_errno(GetLastError());
341#else
342 int e = errno;
343#endif
344
345 rb_syserr_fail(e, source);
346 break;
347 }
349 pm_options_free(options);
350 rb_syserr_fail(EISDIR, source);
351 break;
352 default:
353 pm_options_free(options);
354 rb_raise(rb_eRuntimeError, "Unknown error (%d) initializing file: %s", result, source);
355 break;
356 }
357
358 return pm_src;
359}
360
361#ifndef PRISM_EXCLUDE_SERIALIZATION
362
363/******************************************************************************/
364/* Serializing the AST */
365/******************************************************************************/
366
370static VALUE
371dump_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
372 pm_buffer_t *buffer = pm_buffer_new();
373 if (!buffer) {
374 rb_raise(rb_eNoMemError, "failed to allocate memory");
375 }
376
377 pm_arena_t *arena = pm_arena_new();
378 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
379
380 pm_node_t *node = pm_parse(parser);
381 pm_serialize(parser, node, buffer);
382
383 VALUE result = rb_str_new(pm_buffer_value(buffer), pm_buffer_length(buffer));
384 pm_buffer_free(buffer);
385 pm_parser_free(parser);
386 pm_arena_free(arena);
387
388 return result;
389}
390
399static VALUE
400dump(int argc, VALUE *argv, VALUE self) {
401 pm_options_t *options = pm_options_new();
402 VALUE string = string_options(argc, argv, options);
403
404 const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
405 size_t length = RSTRING_LEN(string);
406
407#ifdef PRISM_BUILD_DEBUG
408 char* dup = xmalloc(length);
409 memcpy(dup, source, length);
410 source = (const uint8_t *) dup;
411#endif
412
413 VALUE value = dump_input(source, length, options);
414 if (pm_options_freeze(options)) rb_obj_freeze(value);
415
416#ifdef PRISM_BUILD_DEBUG
417#ifdef xfree_sized
418 xfree_sized(dup, length);
419#else
420 xfree(dup);
421#endif
422#endif
423
424 pm_options_free(options);
425
426 return value;
427}
428
437static VALUE
438dump_file(int argc, VALUE *argv, VALUE self) {
439 pm_options_t *options = pm_options_new();
440
441 VALUE encoded_filepath;
442 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
443
444 VALUE value = dump_input(pm_source_source(src), pm_source_length(src), options);
445 pm_source_free(src);
446 pm_options_free(options);
447
448 return value;
449}
450
451#endif
452
453/******************************************************************************/
454/* Extracting values for the parse result */
455/******************************************************************************/
456
461static inline VALUE
462rb_class_new_instance_freeze(int argc, const VALUE *argv, VALUE klass, bool freeze) {
463 VALUE value = rb_class_new_instance(argc, argv, klass);
464 if (freeze) rb_obj_freeze(value);
465 return value;
466}
467
471static inline VALUE
472parser_location(VALUE source, bool freeze, uint32_t start, uint32_t length) {
473 VALUE argv[] = { source, LONG2FIX(start), LONG2FIX(length) };
474 return rb_class_new_instance_freeze(3, argv, rb_cPrismLocation, freeze);
475}
476
480#define PARSER_LOCATION(source, freeze, location) \
481 parser_location(source, freeze, location.start, location.length)
482
486static inline VALUE
487parser_comment(VALUE source, bool freeze, const pm_comment_t *comment) {
488 VALUE argv[] = { PARSER_LOCATION(source, freeze, pm_comment_location(comment)) };
489 VALUE type = (pm_comment_type(comment) == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
490 return rb_class_new_instance_freeze(1, argv, type, freeze);
491}
492
493typedef struct {
494 VALUE comments;
495 VALUE source;
496 bool freeze;
498
499static void
500parser_comments_each(const pm_comment_t *comment, void *data) {
502 VALUE value = parser_comment(each_data->source, each_data->freeze, comment);
503 rb_ary_push(each_data->comments, value);
504}
505
509static VALUE
510parser_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
511 VALUE comments = rb_ary_new_capa(pm_parser_comments_size(parser));
512
513 parser_comments_each_data_t each_data = { comments, source, freeze };
514 pm_parser_comments_each(parser, parser_comments_each, &each_data);
515
516 if (freeze) rb_obj_freeze(comments);
517 return comments;
518}
519
523static inline VALUE
524parser_magic_comment(VALUE source, bool freeze, const pm_magic_comment_t *magic_comment) {
527
528 VALUE key_loc = parser_location(source, freeze, key.start, key.length);
529 VALUE value_loc = parser_location(source, freeze, value.start, value.length);
530
531 VALUE argv[] = { key_loc, value_loc };
532 return rb_class_new_instance_freeze(2, argv, rb_cPrismMagicComment, freeze);
533}
534
535typedef struct {
536 VALUE magic_comments;
537 VALUE source;
538 bool freeze;
540
541static void
542parser_magic_comments_each(const pm_magic_comment_t *magic_comment, void *data) {
544 VALUE value = parser_magic_comment(each_data->source, each_data->freeze, magic_comment);
545 rb_ary_push(each_data->magic_comments, value);
546}
547
551static VALUE
552parser_magic_comments(const pm_parser_t *parser, VALUE source, bool freeze) {
553 VALUE magic_comments = rb_ary_new_capa(pm_parser_magic_comments_size(parser));
554
555 parser_magic_comments_each_data_t each_data = { magic_comments, source, freeze };
556 pm_parser_magic_comments_each(parser, parser_magic_comments_each, &each_data);
557
558 if (freeze) rb_obj_freeze(magic_comments);
559 return magic_comments;
560}
561
566static VALUE
567parser_data_loc(const pm_parser_t *parser, VALUE source, bool freeze) {
568 const pm_location_t *data_loc = pm_parser_data_loc(parser);
569
570 if (data_loc->length == 0) {
571 return Qnil;
572 } else {
573 return parser_location(source, freeze, data_loc->start, data_loc->length);
574 }
575}
576
577typedef struct {
578 VALUE errors;
579 rb_encoding *encoding;
580 VALUE source;
581 bool freeze;
583
584static void
585parser_errors_each(const pm_diagnostic_t *diagnostic, void *data) {
587
588 VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
589 VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
590 VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
591
592 pm_error_level_t error_level = pm_diagnostic_error_level(diagnostic);
593 VALUE level = Qnil;
594
595 switch (error_level) {
597 level = ID2SYM(rb_intern("syntax"));
598 break;
600 level = ID2SYM(rb_intern("argument"));
601 break;
603 level = ID2SYM(rb_intern("load"));
604 break;
605 default:
606 rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, error_level);
607 }
608
609 VALUE argv[] = { type, message, location, level };
610 VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseError, each_data->freeze);
611 rb_ary_push(each_data->errors, value);
612}
613
617static VALUE
618parser_errors(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
619 VALUE errors = rb_ary_new_capa(pm_parser_errors_size(parser));
620
621 parser_errors_each_data_t each_data = { errors, encoding, source, freeze };
622 pm_parser_errors_each(parser, parser_errors_each, &each_data);
623
624 if (freeze) rb_obj_freeze(errors);
625 return errors;
626}
627
628typedef struct {
629 VALUE warnings;
630 rb_encoding *encoding;
631 VALUE source;
632 bool freeze;
634
635static void
636parser_warnings_each(const pm_diagnostic_t *diagnostic, void *data) {
638
639 VALUE type = ID2SYM(rb_intern(pm_diagnostic_type(diagnostic)));
640 VALUE message = rb_obj_freeze(rb_enc_str_new_cstr(pm_diagnostic_message(diagnostic), each_data->encoding));
641 VALUE location = PARSER_LOCATION(each_data->source, each_data->freeze, pm_diagnostic_location(diagnostic));
642
643 pm_warning_level_t warning_level = pm_diagnostic_warning_level(diagnostic);
644 VALUE level = Qnil;
645
646 switch (warning_level) {
648 level = ID2SYM(rb_intern("default"));
649 break;
651 level = ID2SYM(rb_intern("verbose"));
652 break;
653 default:
654 rb_raise(rb_eRuntimeError, "Unknown level: %" PRIu8, warning_level);
655 }
656
657 VALUE argv[] = { type, message, location, level };
658 VALUE value = rb_class_new_instance_freeze(4, argv, rb_cPrismParseWarning, each_data->freeze);
659 rb_ary_push(each_data->warnings, value);
660}
661
665static VALUE
666parser_warnings(const pm_parser_t *parser, rb_encoding *encoding, VALUE source, bool freeze) {
667 VALUE warnings = rb_ary_new_capa(pm_parser_warnings_size(parser));
668
669 parser_warnings_each_data_t each_data = { warnings, encoding, source, freeze };
670 pm_parser_warnings_each(parser, parser_warnings_each, &each_data);
671
672 if (freeze) rb_obj_freeze(warnings);
673 return warnings;
674}
675
679static VALUE
680parse_result_create(VALUE class, const pm_parser_t *parser, VALUE value, rb_encoding *encoding, VALUE source, bool freeze) {
681 VALUE result_argv[] = {
682 value,
683 parser_comments(parser, source, freeze),
684 parser_magic_comments(parser, source, freeze),
685 parser_data_loc(parser, source, freeze),
686 parser_errors(parser, encoding, source, freeze),
687 parser_warnings(parser, encoding, source, freeze),
688 pm_parser_continuable(parser) ? Qtrue : Qfalse,
689 source
690 };
691
692 return rb_class_new_instance_freeze(8, result_argv, class, freeze);
693}
694
695/******************************************************************************/
696/* Lexing Ruby code */
697/******************************************************************************/
698
704typedef struct {
705 VALUE source;
706 VALUE tokens;
707 rb_encoding *encoding;
708 bool freeze;
710
716static void
717parse_lex_token(pm_parser_t *parser, pm_token_t *token, void *data) {
718 parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) data;
719
720 VALUE value = pm_token_new(parser, token, parse_lex_data->encoding, parse_lex_data->source, parse_lex_data->freeze);
721 VALUE yields = rb_assoc_new(value, INT2FIX(pm_parser_lex_state(parser)));
722
723 if (parse_lex_data->freeze) {
724 rb_obj_freeze(value);
725 rb_obj_freeze(yields);
726 }
727
728 rb_ary_push(parse_lex_data->tokens, yields);
729}
730
736static void
737parse_lex_encoding_changed_callback(pm_parser_t *parser) {
738 parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) pm_parser_lex_callback_data(parser);
739 parse_lex_data->encoding = rb_enc_find(pm_parser_encoding_name(parser));
740
741 // Since the encoding changed, we need to go back and change the encoding of
742 // the tokens that were already lexed. This is only going to end up being
743 // one or two tokens, since the encoding can only change at the top of the
744 // file.
745 VALUE tokens = parse_lex_data->tokens;
746 VALUE next_tokens = rb_ary_new();
747
748 for (long index = 0; index < RARRAY_LEN(tokens); index++) {
749 VALUE yields = rb_ary_entry(tokens, index);
750 VALUE token = rb_ary_entry(yields, 0);
751
752 VALUE value = rb_ivar_get(token, rb_intern("@value"));
753 VALUE next_value = rb_str_dup(value);
754
755 rb_enc_associate(next_value, parse_lex_data->encoding);
756 if (parse_lex_data->freeze) rb_obj_freeze(next_value);
757
758 VALUE next_token_argv[] = {
759 parse_lex_data->source,
760 rb_ivar_get(token, rb_intern("@type")),
761 next_value,
762 rb_ivar_get(token, rb_intern("@location"))
763 };
764
765 VALUE next_token = rb_class_new_instance(4, next_token_argv, rb_cPrismToken);
766 VALUE next_yields = rb_assoc_new(next_token, rb_ary_entry(yields, 1));
767
768 if (parse_lex_data->freeze) {
769 rb_obj_freeze(next_token);
770 rb_obj_freeze(next_yields);
771 }
772
773 rb_ary_push(next_tokens, next_yields);
774 }
775
776 rb_ary_replace(parse_lex_data->tokens, next_tokens);
777}
778
783static VALUE
784parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *options, bool return_nodes) {
785 pm_arena_t *arena = pm_arena_new();
786 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
787 pm_parser_encoding_changed_callback_set(parser, parse_lex_encoding_changed_callback);
788
789 VALUE source_string = rb_str_new((const char *) input, input_length);
790 VALUE offsets = rb_ary_new_capa(pm_parser_line_offsets(parser)->size);
791 VALUE source = rb_funcall(rb_cPrismSource, rb_id_source_for, 3, source_string, LONG2NUM(pm_parser_start_line(parser)), offsets);
792
793 parse_lex_data_t parse_lex_data = {
794 .source = source,
795 .tokens = rb_ary_new(),
796 .encoding = rb_utf8_encoding(),
797 .freeze = pm_options_freeze(options),
798 };
799
800 parse_lex_data_t *data = &parse_lex_data;
801 pm_parser_lex_callback_set(parser, parse_lex_token, data);
802
803 pm_node_t *node = pm_parse(parser);
804
805 /* Update the Source object with the correct encoding and line offsets,
806 * which are only available after pm_parse() completes. */
807 rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
808 rb_enc_associate(source_string, encoding);
809
810 const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
811 for (size_t index = 0; index < line_offsets->size; index++) {
812 rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index]));
813 }
814
815 if (pm_options_freeze(options)) {
816 rb_obj_freeze(source_string);
817 rb_obj_freeze(offsets);
818 rb_obj_freeze(source);
819 rb_obj_freeze(parse_lex_data.tokens);
820 }
821
822 VALUE result;
823 if (return_nodes) {
824 VALUE value = rb_ary_new_capa(2);
825 rb_ary_push(value, pm_ast_new(parser, node, parse_lex_data.encoding, source, pm_options_freeze(options)));
826 rb_ary_push(value, parse_lex_data.tokens);
827 if (pm_options_freeze(options)) rb_obj_freeze(value);
828 result = parse_result_create(rb_cPrismParseLexResult, parser, value, parse_lex_data.encoding, source, pm_options_freeze(options));
829 } else {
830 result = parse_result_create(rb_cPrismLexResult, parser, parse_lex_data.tokens, parse_lex_data.encoding, source, pm_options_freeze(options));
831 }
832
833 pm_parser_free(parser);
834 pm_arena_free(arena);
835
836 return result;
837}
838
847static VALUE
848lex(int argc, VALUE *argv, VALUE self) {
849 pm_options_t *options = pm_options_new();
850 VALUE string = string_options(argc, argv, options);
851
852 VALUE result = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, false);
853 pm_options_free(options);
854
855 return result;
856}
857
866static VALUE
867lex_file(int argc, VALUE *argv, VALUE self) {
868 pm_options_t *options = pm_options_new();
869
870 VALUE encoded_filepath;
871 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
872
873 VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, false);
874 pm_source_free(src);
875 pm_options_free(options);
876
877 return value;
878}
879
880/******************************************************************************/
881/* Parsing Ruby code */
882/******************************************************************************/
883
887static VALUE
888parse_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
889 pm_arena_t *arena = pm_arena_new();
890 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
891
892 pm_node_t *node = pm_parse(parser);
893 rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
894
895 bool freeze = pm_options_freeze(options);
896 VALUE source = pm_source_new(parser, encoding, freeze);
897 VALUE value = pm_ast_new(parser, node, encoding, source, freeze);
898 VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, freeze);
899
900 if (freeze) {
901 rb_obj_freeze(source);
902 }
903
904 pm_parser_free(parser);
905 pm_arena_free(arena);
906
907 return result;
908}
909
955static VALUE
956parse(int argc, VALUE *argv, VALUE self) {
957 pm_options_t *options = pm_options_new();
958 VALUE string = string_options(argc, argv, options);
959
960 const uint8_t *source = (const uint8_t *) RSTRING_PTR(string);
961 size_t length = RSTRING_LEN(string);
962
963#ifdef PRISM_BUILD_DEBUG
964 char* dup = xmalloc(length);
965 memcpy(dup, source, length);
966 source = (const uint8_t *) dup;
967#endif
968
969 VALUE value = parse_input(source, length, options);
970
971#ifdef PRISM_BUILD_DEBUG
972#ifdef xfree_sized
973 xfree_sized(dup, length);
974#else
975 xfree(dup);
976#endif
977#endif
978
979 pm_options_free(options);
980 return value;
981}
982
991static VALUE
992parse_file(int argc, VALUE *argv, VALUE self) {
993 pm_options_t *options = pm_options_new();
994
995 VALUE encoded_filepath;
996 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
997
998 VALUE value = parse_input(pm_source_source(src), pm_source_length(src), options);
999 pm_source_free(src);
1000 pm_options_free(options);
1001
1002 return value;
1003}
1004
1008static void
1009profile_input(const uint8_t *input, size_t input_length, const pm_options_t *options) {
1010 pm_arena_t *arena = pm_arena_new();
1011 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
1012
1013 pm_parse(parser);
1014 pm_parser_free(parser);
1015 pm_arena_free(arena);
1016}
1017
1027static VALUE
1028profile(int argc, VALUE *argv, VALUE self) {
1029 pm_options_t *options = pm_options_new();
1030 VALUE string = string_options(argc, argv, options);
1031
1032 profile_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
1033 pm_options_free(options);
1034
1035 return Qnil;
1036}
1037
1047static VALUE
1048profile_file(int argc, VALUE *argv, VALUE self) {
1049 pm_options_t *options = pm_options_new();
1050
1051 VALUE encoded_filepath;
1052 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
1053
1054 profile_input(pm_source_source(src), pm_source_length(src), options);
1055 pm_source_free(src);
1056 pm_options_free(options);
1057
1058 return Qnil;
1059}
1060
1061static int
1062parse_stream_eof(void *stream) {
1063 if (rb_funcall((VALUE) stream, rb_intern("eof?"), 0)) {
1064 return 1;
1065 }
1066 return 0;
1067}
1068
1072static char *
1073parse_stream_fgets(char *string, int size, void *stream) {
1074 RUBY_ASSERT(size > 0);
1075
1076 VALUE line = rb_funcall((VALUE) stream, rb_intern("gets"), 1, INT2FIX(size - 1));
1077 if (NIL_P(line)) {
1078 return NULL;
1079 }
1080
1081 const char *cstr = RSTRING_PTR(line);
1082 long length = RSTRING_LEN(line);
1083
1084 memcpy(string, cstr, length);
1085 string[length] = '\0';
1086
1087 return string;
1088}
1089
1098static VALUE
1099parse_stream(int argc, VALUE *argv, VALUE self) {
1100 VALUE stream;
1101 VALUE keywords;
1102 rb_scan_args(argc, argv, "1:", &stream, &keywords);
1103
1104 pm_options_t *options = pm_options_new();
1105 extract_options(options, Qnil, keywords);
1106
1107 pm_source_t *src = pm_source_stream_new((void *) stream, parse_stream_fgets, parse_stream_eof);
1108 pm_arena_t *arena = pm_arena_new();
1109 pm_parser_t *parser;
1110
1111 pm_node_t *node = pm_parse_stream(&parser, arena, src, options);
1112 rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
1113
1114 VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
1115 VALUE value = pm_ast_new(parser, node, encoding, source, pm_options_freeze(options));
1116 VALUE result = parse_result_create(rb_cPrismParseResult, parser, value, encoding, source, pm_options_freeze(options));
1117
1118 pm_source_free(src);
1119 pm_parser_free(parser);
1120 pm_arena_free(arena);
1121 pm_options_free(options);
1122
1123 return result;
1124}
1125
1129static VALUE
1130parse_input_comments(const uint8_t *input, size_t input_length, const pm_options_t *options) {
1131 pm_arena_t *arena = pm_arena_new();
1132 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
1133
1134 pm_parse(parser);
1135 rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
1136
1137 VALUE source = pm_source_new(parser, encoding, pm_options_freeze(options));
1138 VALUE comments = parser_comments(parser, source, pm_options_freeze(options));
1139
1140 pm_parser_free(parser);
1141 pm_arena_free(arena);
1142
1143 return comments;
1144}
1145
1154static VALUE
1155parse_comments(int argc, VALUE *argv, VALUE self) {
1156 pm_options_t *options = pm_options_new();
1157 VALUE string = string_options(argc, argv, options);
1158
1159 VALUE result = parse_input_comments((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
1160 pm_options_free(options);
1161
1162 return result;
1163}
1164
1173static VALUE
1174parse_file_comments(int argc, VALUE *argv, VALUE self) {
1175 pm_options_t *options = pm_options_new();
1176
1177 VALUE encoded_filepath;
1178 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
1179
1180 VALUE value = parse_input_comments(pm_source_source(src), pm_source_length(src), options);
1181 pm_source_free(src);
1182 pm_options_free(options);
1183
1184 return value;
1185}
1186
1202static VALUE
1203parse_lex(int argc, VALUE *argv, VALUE self) {
1204 pm_options_t *options = pm_options_new();
1205 VALUE string = string_options(argc, argv, options);
1206
1207 VALUE value = parse_lex_input((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options, true);
1208 pm_options_free(options);
1209
1210 return value;
1211}
1212
1228static VALUE
1229parse_lex_file(int argc, VALUE *argv, VALUE self) {
1230 pm_options_t *options = pm_options_new();
1231
1232 VALUE encoded_filepath;
1233 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
1234
1235 VALUE value = parse_lex_input(pm_source_source(src), pm_source_length(src), options, true);
1236 pm_source_free(src);
1237 pm_options_free(options);
1238
1239 return value;
1240}
1241
1245static VALUE
1246parse_input_success_p(const uint8_t *input, size_t input_length, const pm_options_t *options) {
1247 pm_arena_t *arena = pm_arena_new();
1248 pm_parser_t *parser = pm_parser_new(arena, input, input_length, options);
1249
1250 pm_parse(parser);
1251
1252 VALUE result = pm_parser_errors_size(parser) == 0 ? Qtrue : Qfalse;
1253 pm_parser_free(parser);
1254 pm_arena_free(arena);
1255
1256 return result;
1257}
1258
1267static VALUE
1268parse_success_p(int argc, VALUE *argv, VALUE self) {
1269 pm_options_t *options = pm_options_new();
1270 VALUE string = string_options(argc, argv, options);
1271
1272 VALUE result = parse_input_success_p((const uint8_t *) RSTRING_PTR(string), RSTRING_LEN(string), options);
1273 pm_options_free(options);
1274
1275 return result;
1276}
1277
1286static VALUE
1287parse_failure_p(int argc, VALUE *argv, VALUE self) {
1288 return RTEST(parse_success_p(argc, argv, self)) ? Qfalse : Qtrue;
1289}
1290
1299static VALUE
1300parse_file_success_p(int argc, VALUE *argv, VALUE self) {
1301 pm_options_t *options = pm_options_new();
1302
1303 VALUE encoded_filepath;
1304 pm_source_t *src = file_options(argc, argv, options, &encoded_filepath);
1305
1306 VALUE result = parse_input_success_p(pm_source_source(src), pm_source_length(src), options);
1307 pm_source_free(src);
1308 pm_options_free(options);
1309
1310 return result;
1311}
1312
1321static VALUE
1322parse_file_failure_p(int argc, VALUE *argv, VALUE self) {
1323 return RTEST(parse_file_success_p(argc, argv, self)) ? Qfalse : Qtrue;
1324}
1325
1326/******************************************************************************/
1327/* String query methods */
1328/******************************************************************************/
1329
1334static VALUE
1335string_query(pm_string_query_t result) {
1336 switch (result) {
1338 rb_raise(rb_eArgError, "Invalid or non ascii-compatible encoding");
1339 return Qfalse;
1341 return Qfalse;
1343 return Qtrue;
1344 }
1345 return Qfalse;
1346}
1347
1357static VALUE
1358string_query_local_p(VALUE self, VALUE string) {
1359 const uint8_t *source = (const uint8_t *) check_string(string);
1360 return string_query(pm_string_query_local(source, RSTRING_LEN(string), rb_enc_get(string)->name));
1361}
1362
1372static VALUE
1373string_query_constant_p(VALUE self, VALUE string) {
1374 const uint8_t *source = (const uint8_t *) check_string(string);
1375 return string_query(pm_string_query_constant(source, RSTRING_LEN(string), rb_enc_get(string)->name));
1376}
1377
1385static VALUE
1386string_query_method_name_p(VALUE self, VALUE string) {
1387 const uint8_t *source = (const uint8_t *) check_string(string);
1388 return string_query(pm_string_query_method_name(source, RSTRING_LEN(string), rb_enc_get(string)->name));
1389}
1390
1391/******************************************************************************/
1392/* Initialization of the extension */
1393/******************************************************************************/
1394
1398RUBY_FUNC_EXPORTED void
1399Init_prism(void) {
1400 // Make sure that the prism library version matches the expected version.
1401 // Otherwise something was compiled incorrectly.
1402 if (strcmp(pm_version(), EXPECTED_PRISM_VERSION) != 0) {
1403 rb_raise(
1405 "The prism library version (%s) does not match the expected version (%s)",
1406 pm_version(),
1407 EXPECTED_PRISM_VERSION
1408 );
1409 }
1410
1411#ifdef HAVE_RB_EXT_RACTOR_SAFE
1412 // Mark this extension as Ractor-safe.
1413 rb_ext_ractor_safe(true);
1414#endif
1415
1416 // Grab up references to all of the constants that we're going to need to
1417 // reference throughout this extension.
1418 rb_cPrism = rb_define_module("Prism");
1419 rb_cPrismNode = rb_define_class_under(rb_cPrism, "Node", rb_cObject);
1420 rb_cPrismSource = rb_define_class_under(rb_cPrism, "Source", rb_cObject);
1421 rb_cPrismToken = rb_define_class_under(rb_cPrism, "Token", rb_cObject);
1422 rb_cPrismLocation = rb_define_class_under(rb_cPrism, "Location", rb_cObject);
1423 rb_cPrismComment = rb_define_class_under(rb_cPrism, "Comment", rb_cObject);
1424 rb_cPrismInlineComment = rb_define_class_under(rb_cPrism, "InlineComment", rb_cPrismComment);
1425 rb_cPrismEmbDocComment = rb_define_class_under(rb_cPrism, "EmbDocComment", rb_cPrismComment);
1426 rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
1427 rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
1428 rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);
1429 rb_cPrismResult = rb_define_class_under(rb_cPrism, "Result", rb_cObject);
1430 rb_cPrismParseResult = rb_define_class_under(rb_cPrism, "ParseResult", rb_cPrismResult);
1431 rb_cPrismLexResult = rb_define_class_under(rb_cPrism, "LexResult", rb_cPrismResult);
1432 rb_cPrismParseLexResult = rb_define_class_under(rb_cPrism, "ParseLexResult", rb_cPrismResult);
1433 rb_cPrismStringQuery = rb_define_class_under(rb_cPrism, "StringQuery", rb_cObject);
1434 rb_cPrismScope = rb_define_class_under(rb_cPrism, "Scope", rb_cObject);
1435
1436 rb_cPrismCurrentVersionError = rb_const_get(rb_cPrism, rb_intern("CurrentVersionError"));
1437
1438 // Intern all of the IDs eagerly that we support so that we don't have to do
1439 // it every time we parse.
1440 rb_id_option_command_line = rb_intern_const("command_line");
1441 rb_id_option_encoding = rb_intern_const("encoding");
1442 rb_id_option_filepath = rb_intern_const("filepath");
1443 rb_id_option_freeze = rb_intern_const("freeze");
1444 rb_id_option_frozen_string_literal = rb_intern_const("frozen_string_literal");
1445 rb_id_option_line = rb_intern_const("line");
1446 rb_id_option_main_script = rb_intern_const("main_script");
1447 rb_id_option_partial_script = rb_intern_const("partial_script");
1448 rb_id_option_scopes = rb_intern_const("scopes");
1449 rb_id_option_version = rb_intern_const("version");
1450 rb_id_source_for = rb_intern("for");
1451 rb_id_forwarding_positionals = rb_intern("*");
1452 rb_id_forwarding_keywords = rb_intern("**");
1453 rb_id_forwarding_block = rb_intern("&");
1454 rb_id_forwarding_all = rb_intern("...");
1455
1459 rb_define_const(rb_cPrism, "VERSION", rb_str_freeze(rb_str_new_cstr(EXPECTED_PRISM_VERSION)));
1460
1461 // First, the functions that have to do with lexing and parsing.
1462 rb_define_singleton_method(rb_cPrism, "lex", lex, -1);
1463 rb_define_singleton_method(rb_cPrism, "lex_file", lex_file, -1);
1464 rb_define_singleton_method(rb_cPrism, "parse", parse, -1);
1465 rb_define_singleton_method(rb_cPrism, "parse_file", parse_file, -1);
1466 rb_define_singleton_method(rb_cPrism, "profile", profile, -1);
1467 rb_define_singleton_method(rb_cPrism, "profile_file", profile_file, -1);
1468 rb_define_singleton_method(rb_cPrism, "parse_stream", parse_stream, -1);
1469 rb_define_singleton_method(rb_cPrism, "parse_comments", parse_comments, -1);
1470 rb_define_singleton_method(rb_cPrism, "parse_file_comments", parse_file_comments, -1);
1471 rb_define_singleton_method(rb_cPrism, "parse_lex", parse_lex, -1);
1472 rb_define_singleton_method(rb_cPrism, "parse_lex_file", parse_lex_file, -1);
1473 rb_define_singleton_method(rb_cPrism, "parse_success?", parse_success_p, -1);
1474 rb_define_singleton_method(rb_cPrism, "parse_failure?", parse_failure_p, -1);
1475 rb_define_singleton_method(rb_cPrism, "parse_file_success?", parse_file_success_p, -1);
1476 rb_define_singleton_method(rb_cPrism, "parse_file_failure?", parse_file_failure_p, -1);
1477
1478#ifndef PRISM_EXCLUDE_SERIALIZATION
1479 rb_define_singleton_method(rb_cPrism, "dump", dump, -1);
1480 rb_define_singleton_method(rb_cPrism, "dump_file", dump_file, -1);
1481#endif
1482
1483 rb_define_singleton_method(rb_cPrismStringQuery, "local?", string_query_local_p, 1);
1484 rb_define_singleton_method(rb_cPrismStringQuery, "constant?", string_query_constant_p, 1);
1485 rb_define_singleton_method(rb_cPrismStringQuery, "method_name?", string_query_method_name_p, 1);
1486
1487 // Next, initialize the other APIs.
1488 Init_prism_api_node();
1489}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
PRISM_EXPORTED_FUNCTION pm_location_t pm_comment_location(const pm_comment_t *comment) PRISM_NONNULL(1)
Returns the location associated with the given comment.
Definition parser.c:158
PRISM_EXPORTED_FUNCTION pm_comment_type_t pm_comment_type(const pm_comment_t *comment) PRISM_NONNULL(1)
Returns the type associated with the given comment.
Definition parser.c:166
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
pm_warning_level_t
The levels of warnings generated during parsing.
Definition diagnostic.h:37
@ PM_WARNING_LEVEL_DEFAULT
For warnings which should be emitted if $VERBOSE != nil.
Definition diagnostic.h:39
@ PM_WARNING_LEVEL_VERBOSE
For warnings which should be emitted if $VERBOSE == true.
Definition diagnostic.h:42
pm_error_level_t
The levels of errors generated during parsing.
Definition diagnostic.h:23
@ PM_ERROR_LEVEL_ARGUMENT
For errors that should raise an argument error.
Definition diagnostic.h:28
@ PM_ERROR_LEVEL_LOAD
For errors that should raise a load error.
Definition diagnostic.h:31
@ PM_ERROR_LEVEL_SYNTAX
For errors that should raise a syntax error.
Definition diagnostic.h:25
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1554
VALUE rb_define_module(const char *name)
Defines a top-level module.
Definition class.c:1636
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3180
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define ULONG2NUM
Old name of RB_ULONG2NUM.
Definition long.h:60
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
Definition value_type.h:80
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:661
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3967
VALUE rb_eNoMemError
NoMemoryError exception.
Definition error.c:1438
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1427
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1425
VALUE rb_cObject
Object class.
Definition object.c:61
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2288
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:229
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:888
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1307
VALUE rb_enc_str_new_cstr(const char *ptr, rb_encoding *enc)
Identical to rb_enc_str_new(), except it assumes the passed pointer is a pointer to a C string.
Definition string.c:1138
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1120
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Replaces the contents of the former object with the contents of the latter.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
void rb_ary_store(VALUE ary, long key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
void rb_ext_ractor_safe(bool flag)
Asserts that the extension library that calls this function is aware of Ractor.
Definition load.c:1272
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1499
#define rb_exc_new_cstr(exc, str)
Identical to rb_exc_new(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1671
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1979
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:3296
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1515
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3465
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1502
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:285
const char ruby_version[]
Stringised version.
Definition version.c:82
PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_value(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1)
Returns the location of the value associated with the given magic comment.
Definition parser.c:204
PRISM_EXPORTED_FUNCTION pm_location_t pm_magic_comment_key(const pm_magic_comment_t *magic_comment) PRISM_NONNULL(1)
Returns the location of the key associated with the given magic comment.
Definition parser.c:196
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
static const uint8_t PM_OPTIONS_COMMAND_LINE_E
A bit representing whether or not the command line -e option was set.
Definition options.h:84
static const uint8_t PM_OPTIONS_COMMAND_LINE_L
A bit representing whether or not the command line -l option was set.
Definition options.h:90
static const uint8_t PM_OPTIONS_COMMAND_LINE_A
A bit representing whether or not the command line -a option was set.
Definition options.h:77
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE
The default value for parameters.
Definition options.h:45
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_ALL
When the scope is forwarding with the ... parameter.
Definition options.h:57
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_POSITIONALS
When the scope is forwarding with the * parameter.
Definition options.h:48
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_KEYWORDS
When the scope is forwarding with the ** parameter.
Definition options.h:51
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
Definition options.h:96
static const uint8_t PM_OPTIONS_COMMAND_LINE_X
A bit representing whether or not the command line -x option was set.
Definition options.h:108
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_BLOCK
When the scope is forwarding with the & parameter.
Definition options.h:54
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
Definition options.h:102
PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1)
Allocate and initialize a parser with the given start and end pointers.
Definition prism.c:22593
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1)
Free both the memory held by the given parser and the parser itself.
Definition prism.c:22626
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1)
Initiate the parser with the given parser.
Definition prism.c:22797
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
pm_source_init_result_t
Represents the result of initializing a source from a file.
Definition source.h:39
@ PM_SOURCE_INIT_ERROR_GENERIC
Indicates a generic error from a source init function, where the type of error should be read from er...
Definition source.h:47
@ PM_SOURCE_INIT_SUCCESS
Indicates that the source was successfully initialized.
Definition source.h:41
@ PM_SOURCE_INIT_ERROR_DIRECTORY
Indicates that the file that was attempted to be opened was a directory.
Definition source.h:52
#define RTEST
This is an old name of RB_TEST.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
We need a struct here to pass through rb_protect and it has to be a single value.
Definition extension.c:248
This struct gets stored in the parser and passed in to the lex callback any time a new token is found...
Definition extension.c:704
A list of offsets of the start of lines in a string.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
This struct represents a slice in the source code, defined by an offset and a length.
Definition ast.h:554
uint32_t start
The offset of the location from the start of the source.
Definition ast.h:556
uint32_t length
The length of the location.
Definition ast.h:559
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1065
A generic string type that can have various ownership semantics.
Definition stringy.h:18
This struct represents a token in the Ruby source.
Definition ast.h:526
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376