Ruby 4.1.0dev (2026-10-16 revision f2bc42f6bfe64f1859d3514c0c6767446c6080b6)
options.c
1#include "prism/internal/options.h"
2
4
5#include "prism/internal/allocator.h"
6#include "prism/internal/char.h"
7#include "prism/internal/stringy.h"
8
9#include <stdlib.h>
10#include <string.h>
11
17pm_options_new(void) {
18 pm_options_t *options = xcalloc(1, sizeof(pm_options_t));
19 if (options == NULL) abort();
20 return options;
21}
22
26void
27pm_options_cleanup(pm_options_t *options) {
28 pm_string_cleanup(&options->filepath);
29 pm_string_cleanup(&options->encoding);
30
31 for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
32 pm_options_scope_t *scope = &options->scopes[scope_index];
33
34 for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
35 pm_string_cleanup(&scope->locals[local_index]);
36 }
37
38 xfree_sized(scope->locals, scope->locals_count * sizeof(pm_string_t));
39 }
40
41 xfree_sized(options->scopes, options->scopes_count * sizeof(pm_options_scope_t));
42}
43
49void
50pm_options_free(pm_options_t *options) {
51 pm_options_cleanup(options);
52 xfree_sized(options, sizeof(pm_options_t));
53}
54
58void
59pm_options_shebang_callback_set(pm_options_t *options, pm_options_shebang_callback_t shebang_callback, void *shebang_callback_data) {
60 options->shebang_callback = shebang_callback;
61 options->shebang_callback_data = shebang_callback_data;
62}
63
67const pm_string_t *
68pm_options_filepath(const pm_options_t *options) {
69 return &options->filepath;
70}
71
75void
76pm_options_filepath_set(pm_options_t *options, const char *filepath) {
77 pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
78}
79
83void
84pm_options_encoding_set(pm_options_t *options, const char *encoding) {
85 pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
86}
87
91void
92pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
93 options->encoding_locked = encoding_locked;
94}
95
99void
100pm_options_line_set(pm_options_t *options, int32_t line) {
101 options->line = line;
102}
103
107void
108pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
109 options->frozen_string_literal = frozen_string_literal ? PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED : PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED;
110}
111
115void
116pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
117 options->command_line = command_line;
118}
119
123static PRISM_INLINE bool
124is_number(const char *string, size_t length) {
125 return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
126}
127
133bool
134pm_options_version_set(pm_options_t *options, const char *version, size_t length) {
135 if (version == NULL) {
136 options->version = PM_OPTIONS_VERSION_LATEST;
137 return true;
138 }
139
140 if (length == 3) {
141 if (strncmp(version, "3.3", 3) == 0) {
142 options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
143 return true;
144 }
145
146 if (strncmp(version, "3.4", 3) == 0) {
147 options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
148 return true;
149 }
150
151 if (strncmp(version, "3.5", 3) == 0 || strncmp(version, "4.0", 3) == 0) {
152 options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
153 return true;
154 }
155
156 if (strncmp(version, "4.1", 3) == 0) {
157 options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
158 return true;
159 }
160
161 return false;
162 }
163
164 if (length >= 4 && is_number(version + 4, length - 4)) {
165 if (strncmp(version, "3.3.", 4) == 0) {
166 options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
167 return true;
168 }
169
170 if (strncmp(version, "3.4.", 4) == 0) {
171 options->version = PM_OPTIONS_VERSION_CRUBY_3_4;
172 return true;
173 }
174
175 if (strncmp(version, "3.5.", 4) == 0 || strncmp(version, "4.0.", 4) == 0) {
176 options->version = PM_OPTIONS_VERSION_CRUBY_4_0;
177 return true;
178 }
179
180 if (strncmp(version, "4.1.", 4) == 0) {
181 options->version = PM_OPTIONS_VERSION_CRUBY_4_1;
182 return true;
183 }
184 }
185
186 if (length == 6) {
187 if (strncmp(version, "latest", 6) == 0) {
188 options->version = PM_OPTIONS_VERSION_LATEST;
189 return true;
190 }
191 }
192
193 return false;
194}
195
200void
201pm_options_version_set_lowest(pm_options_t *options) {
202 options->version = PM_OPTIONS_VERSION_CRUBY_3_3;
203}
204
209void
210pm_options_version_set_highest(pm_options_t *options) {
211 options->version = PM_OPTIONS_VERSION_LATEST;
212}
213
217void
218pm_options_main_script_set(pm_options_t *options, bool main_script) {
219 options->main_script = main_script;
220}
221
225void
226pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
227 options->partial_script = partial_script;
228}
229
233bool
234pm_options_freeze(const pm_options_t *options) {
235 return options->freeze;
236}
237
241void
242pm_options_freeze_set(pm_options_t *options, bool freeze) {
243 options->freeze = freeze;
244}
245
249bool
250pm_options_attach_comments(const pm_options_t *options) {
251 return options->attach_comments;
252}
253
257void
258pm_options_attach_comments_set(pm_options_t *options, bool attach_comments) {
259 options->attach_comments = attach_comments;
260}
261
265uint8_t pm_options_raise_error(const pm_options_t *options) {
266 return options->raise_error;
267}
268
272void pm_options_raise_error_set(pm_options_t *options, uint8_t raise_error) {
273 options->raise_error = raise_error;
274}
275
276// For some reason, GCC analyzer thinks we're leaking allocated scopes and
277// locals here, even though we definitely aren't. This is a false positive.
278// Ideally we wouldn't need to suppress this.
279#if defined(__GNUC__) && (__GNUC__ >= 10)
280#pragma GCC diagnostic push
281#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
282#endif
283
287bool
288pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
289 options->scopes_count = scopes_count;
290 options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t));
291 return options->scopes != NULL;
292}
293
298const pm_options_scope_t *
299pm_options_scope(const pm_options_t *options, size_t index) {
300 return &options->scopes[index];
301}
302
308pm_options_scope_mut(pm_options_t *options, size_t index) {
309 return &options->scopes[index];
310}
311
316void
317pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
318 scope->locals_count = locals_count;
319 scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
320 scope->forwarding = PM_OPTIONS_SCOPE_FORWARDING_NONE;
321 if (scope->locals == NULL) abort();
322}
323
328const pm_string_t *
329pm_options_scope_local(const pm_options_scope_t *scope, size_t index) {
330 return &scope->locals[index];
331}
332
338pm_options_scope_local_mut(pm_options_scope_t *scope, size_t index) {
339 return &scope->locals[index];
340}
341
345void
346pm_options_scope_forwarding_set(pm_options_scope_t *scope, uint8_t forwarding) {
347 scope->forwarding = forwarding;
348}
349
355static uint32_t
356pm_options_read_u32(const char *data) {
357 if (((uintptr_t) data) % sizeof(uint32_t) == 0) {
358 return *((uint32_t *) data);
359 } else {
360 uint32_t value;
361 memcpy(&value, data, sizeof(uint32_t));
362 return value;
363 }
364}
365
371static int32_t
372pm_options_read_s32(const char *data) {
373 if (((uintptr_t) data) % sizeof(int32_t) == 0) {
374 return *((int32_t *) data);
375 } else {
376 int32_t value;
377 memcpy(&value, data, sizeof(int32_t));
378 return value;
379 }
380}
381
389void
390pm_options_read(pm_options_t *options, const char *data) {
391 options->line = 1; // default
392 if (data == NULL) return;
393
394 uint32_t filepath_length = pm_options_read_u32(data);
395 data += 4;
396
397 if (filepath_length > 0) {
398 pm_string_constant_init(&options->filepath, data, filepath_length);
399 data += filepath_length;
400 }
401
402 options->line = pm_options_read_s32(data);
403 data += 4;
404
405 uint32_t encoding_length = pm_options_read_u32(data);
406 data += 4;
407
408 if (encoding_length > 0) {
409 pm_string_constant_init(&options->encoding, data, encoding_length);
410 data += encoding_length;
411 }
412
413 options->frozen_string_literal = (int8_t) *data++;
414 options->command_line = (uint8_t) *data++;
415 options->version = (pm_options_version_t) *data++;
416 options->encoding_locked = ((uint8_t) *data++) > 0;
417 options->main_script = ((uint8_t) *data++) > 0;
418 options->partial_script = ((uint8_t) *data++) > 0;
419 options->freeze = ((uint8_t) *data++) > 0;
420 options->attach_comments = ((uint8_t) *data++) > 0;
421
422 uint32_t scopes_count = pm_options_read_u32(data);
423 data += 4;
424
425 if (scopes_count > 0) {
426 if (!pm_options_scopes_init(options, scopes_count)) return;
427
428 for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
429 uint32_t locals_count = pm_options_read_u32(data);
430 data += 4;
431
432 pm_options_scope_t *scope = &options->scopes[scope_index];
433 pm_options_scope_init(scope, locals_count);
434
435 uint8_t forwarding = (uint8_t) *data++;
436 pm_options_scope_forwarding_set(&options->scopes[scope_index], forwarding);
437
438 for (size_t local_index = 0; local_index < locals_count; local_index++) {
439 uint32_t local_length = pm_options_read_u32(data);
440 data += 4;
441
442 pm_string_constant_init(&scope->locals[local_index], data, local_length);
443 data += local_length;
444 }
445 }
446 }
447}
448
449#if defined(__GNUC__) && (__GNUC__ >= 10)
450#pragma GCC diagnostic pop
451#endif
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
Definition inline.h:12
static const uint8_t PM_OPTIONS_SCOPE_FORWARDING_NONE
The default value for parameters.
Definition options.h:45
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should not be frozen.
Definition options.h:31
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made frozen.
Definition options.h:42
void(* pm_options_shebang_callback_t)(pm_options_t *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:71
A generic string type that can have various ownership semantics.
Definition stringy.h:18