Ruby 4.1.0dev (2026-01-08 revision dcfbbdc38c2c0502f2eeb9172d1a82721b5ca45b)
options.c
1#include "prism/options.h"
2
7pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) {
8 options->shebang_callback = shebang_callback;
9 options->shebang_callback_data = shebang_callback_data;
10}
11
16pm_options_filepath_set(pm_options_t *options, const char *filepath) {
17 pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
18}
19
24pm_options_encoding_set(pm_options_t *options, const char *encoding) {
25 pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
26}
27
32pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
33 options->encoding_locked = encoding_locked;
34}
35
40pm_options_line_set(pm_options_t *options, int32_t line) {
41 options->line = line;
42}
43
51
56pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
57 options->command_line = command_line;
58}
59
63static inline bool
64is_number(const char *string, size_t length) {
65 return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
66}
67
74pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
75 if (version == NULL) {
77 return true;
78 }
79
80 if (length == 3) {
81 if (strncmp(version, "3.3", 3) == 0) {
83 return true;
84 }
85
86 if (strncmp(version, "3.4", 3) == 0) {
88 return true;
89 }
90
91 if (strncmp(version, "3.5", 3) == 0 || strncmp(version, "4.0", 3) == 0) {
93 return true;
94 }
95
96 if (strncmp(version, "4.1", 3) == 0) {
98 return true;
99 }
100
101 return false;
102 }
103
104 if (length >= 4 && is_number(version + 4, length - 4)) {
105 if (strncmp(version, "3.3.", 4) == 0) {
107 return true;
108 }
109
110 if (strncmp(version, "3.4.", 4) == 0) {
112 return true;
113 }
114
115 if (strncmp(version, "3.5.", 4) == 0 || strncmp(version, "4.0.", 4) == 0) {
117 return true;
118 }
119
120 if (strncmp(version, "4.1.", 4) == 0) {
122 return true;
123 }
124 }
125
126 if (length >= 6) {
127 if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well
129 return true;
130 }
131 }
132
133 return false;
134}
135
140pm_options_main_script_set(pm_options_t *options, bool main_script) {
141 options->main_script = main_script;
142}
143
148pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
149 options->partial_script = partial_script;
150}
151
156pm_options_freeze_set(pm_options_t *options, bool freeze) {
157 options->freeze = freeze;
158}
159
160// For some reason, GCC analyzer thinks we're leaking allocated scopes and
161// locals here, even though we definitely aren't. This is a false positive.
162// Ideally we wouldn't need to suppress this.
163#if defined(__GNUC__) && (__GNUC__ >= 10)
164#pragma GCC diagnostic push
165#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
166#endif
167
172pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
173 options->scopes_count = scopes_count;
174 options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t));
175 return options->scopes != NULL;
176}
177
182pm_options_scope_get(const pm_options_t *options, size_t index) {
183 return &options->scopes[index];
184}
185
191pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
192 scope->locals_count = locals_count;
193 scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
195 return scope->locals != NULL;
196}
197
203 return &scope->locals[index];
204}
205
211 scope->forwarding = forwarding;
212}
213
219 pm_string_free(&options->filepath);
220 pm_string_free(&options->encoding);
221
222 for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
223 pm_options_scope_t *scope = &options->scopes[scope_index];
224
225 for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
226 pm_string_free(&scope->locals[local_index]);
227 }
228
229 xfree(scope->locals);
230 }
231
232 xfree(options->scopes);
233}
234
240static uint32_t
241pm_options_read_u32(const char *data) {
242 if (((uintptr_t) data) % sizeof(uint32_t) == 0) {
243 return *((uint32_t *) data);
244 } else {
245 uint32_t value;
246 memcpy(&value, data, sizeof(uint32_t));
247 return value;
248 }
249}
250
256static int32_t
257pm_options_read_s32(const char *data) {
258 if (((uintptr_t) data) % sizeof(int32_t) == 0) {
259 return *((int32_t *) data);
260 } else {
261 int32_t value;
262 memcpy(&value, data, sizeof(int32_t));
263 return value;
264 }
265}
266
274void
275pm_options_read(pm_options_t *options, const char *data) {
276 options->line = 1; // default
277 if (data == NULL) return;
278
279 uint32_t filepath_length = pm_options_read_u32(data);
280 data += 4;
281
282 if (filepath_length > 0) {
283 pm_string_constant_init(&options->filepath, data, filepath_length);
284 data += filepath_length;
285 }
286
287 options->line = pm_options_read_s32(data);
288 data += 4;
289
290 uint32_t encoding_length = pm_options_read_u32(data);
291 data += 4;
292
293 if (encoding_length > 0) {
294 pm_string_constant_init(&options->encoding, data, encoding_length);
295 data += encoding_length;
296 }
297
298 options->frozen_string_literal = (int8_t) *data++;
299 options->command_line = (uint8_t) *data++;
300 options->version = (pm_options_version_t) *data++;
301 options->encoding_locked = ((uint8_t) *data++) > 0;
302 options->main_script = ((uint8_t) *data++) > 0;
303 options->partial_script = ((uint8_t) *data++) > 0;
304 options->freeze = ((uint8_t) *data++) > 0;
305
306 uint32_t scopes_count = pm_options_read_u32(data);
307 data += 4;
308
309 if (scopes_count > 0) {
310 if (!pm_options_scopes_init(options, scopes_count)) return;
311
312 for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
313 uint32_t locals_count = pm_options_read_u32(data);
314 data += 4;
315
316 pm_options_scope_t *scope = &options->scopes[scope_index];
317 if (!pm_options_scope_init(scope, locals_count)) {
318 pm_options_free(options);
319 return;
320 }
321
322 uint8_t forwarding = (uint8_t) *data++;
323 pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
324
325 for (size_t local_index = 0; local_index < locals_count; local_index++) {
326 uint32_t local_length = pm_options_read_u32(data);
327 data += 4;
328
329 pm_string_constant_init(&scope->locals[local_index], data, local_length);
330 data += local_length;
331 }
332 }
333 }
334}
335
336#if defined(__GNUC__) && (__GNUC__ >= 10)
337#pragma GCC diagnostic pop
338#endif
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
PRISM_EXPORTED_FUNCTION void pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data)
Set the shebang callback option on the given options struct.
Definition options.c:7
PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, const char *encoding)
Set the encoding option on the given options struct.
Definition options.c:24
PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options)
Free the internal memory associated with the options.
Definition options.c:218
PRISM_EXPORTED_FUNCTION void pm_options_partial_script_set(pm_options_t *options, bool partial_script)
Set the partial script option on the given options struct.
Definition options.c:148
PRISM_EXPORTED_FUNCTION void pm_options_main_script_set(pm_options_t *options, bool main_script)
Set the main script option on the given options struct.
Definition options.c:140
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index)
Return a pointer to the local at the given index within the given scope.
Definition options.c:202
PRISM_EXPORTED_FUNCTION bool pm_options_version_set(pm_options_t *options, const char *version, size_t length)
Set the version option on the given options struct by parsing the given string.
Definition options.c:74
PRISM_EXPORTED_FUNCTION bool pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count)
Create a new options scope struct.
Definition options.c:191
PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line)
Set the line option on the given options struct.
Definition options.c:40
PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index)
Return a pointer to the scope at the given index within the given options.
Definition options.c:182
PRISM_EXPORTED_FUNCTION void pm_options_freeze_set(pm_options_t *options, bool freeze)
Set the freeze option on the given options struct.
Definition options.c:156
PRISM_EXPORTED_FUNCTION void pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked)
Set the encoding_locked option on the given options struct.
Definition options.c:32
PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal)
Set the frozen string literal option on the given options struct.
Definition options.c:48
PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line)
Sets the command line option on the given options struct.
Definition options.c:56
PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, const char *filepath)
Set the filepath option on the given options struct.
Definition options.c:16
PRISM_EXPORTED_FUNCTION bool pm_options_scopes_init(pm_options_t *options, size_t scopes_count)
Allocate and zero out the scopes array on the given options struct.
Definition options.c:172
PRISM_EXPORTED_FUNCTION void pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding)
Set the forwarding option on the given scope struct.
Definition options.c:210
The options that can be passed to parsing.
void(* pm_options_shebang_callback_t)(struct pm_options *options, const uint8_t *source, size_t length, void *shebang_callback_data)
The callback called when additional switches are found in a shebang comment that need to be processed...
Definition options.h:77
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE
The default value for parameters.
Definition options.h:48
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
Definition options.h:20
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
Definition options.h:31
pm_options_version_t
The version of Ruby syntax that we should be parsing with.
Definition options.h:84
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
Definition options.h:89
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
Definition options.h:104
@ PM_OPTIONS_VERSION_CRUBY_4_1
The vendored version of prism in CRuby 4.1.x.
Definition options.h:101
@ PM_OPTIONS_VERSION_CRUBY_3_4
The vendored version of prism in CRuby 3.4.x.
Definition options.h:92
@ PM_OPTIONS_VERSION_CRUBY_4_0
The vendored version of prism in CRuby 4.0.x.
Definition options.h:98
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
Definition pm_string.c:367
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
Definition defines.h:53
A scope of locals surrounding the code that is being parsed.
Definition options.h:36
size_t locals_count
The number of locals in the scope.
Definition options.h:38
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
Definition options.h:44
pm_string_t * locals
The names of the locals in the scope.
Definition options.h:41
The options that can be passed to the parser.
Definition options.h:110
bool freeze
Whether or not the parser should freeze the nodes that it creates.
Definition options.h:199
uint8_t command_line
A bitset of the various options that were set on the command line.
Definition options.h:159
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
Definition options.h:121
bool encoding_locked
Whether or not the encoding magic comments should be respected.
Definition options.h:175
pm_options_scope_t * scopes
The scopes surrounding the code that is being parsed.
Definition options.h:149
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
Definition options.h:182
pm_string_t encoding
The name of the encoding that the source file is in.
Definition options.h:136
int32_t line
The line within the file that the parse starts on.
Definition options.h:130
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
Definition options.h:115
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
Definition options.h:168
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
Definition options.h:192
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
Definition options.h:141
pm_string_t filepath
The name of the file that is currently being parsed.
Definition options.h:124
pm_options_version_t version
The version of prism that we should be parsing with.
Definition options.h:156
A generic string type that can have various ownership semantics.
Definition pm_string.h:33