Ruby  3.4.0dev (2024-12-06 revision 892c46283a5ea4179500d951c9d4866c0051f27b)
options.c
1 #include "prism/options.h"
2 
7 pm_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 
16 pm_options_filepath_set(pm_options_t *options, const char *filepath) {
17  pm_string_constant_init(&options->filepath, filepath, strlen(filepath));
18 }
19 
24 pm_options_encoding_set(pm_options_t *options, const char *encoding) {
25  pm_string_constant_init(&options->encoding, encoding, strlen(encoding));
26 }
27 
32 pm_options_encoding_locked_set(pm_options_t *options, bool encoding_locked) {
33  options->encoding_locked = encoding_locked;
34 }
35 
40 pm_options_line_set(pm_options_t *options, int32_t line) {
41  options->line = line;
42 }
43 
48 pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
50 }
51 
56 pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
57  options->command_line = command_line;
58 }
59 
63 static inline bool
64 is_number(const char *string, size_t length) {
65  return pm_strspn_decimal_digit((const uint8_t *) string, (ptrdiff_t) length) == length;
66 }
67 
74 pm_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  return false;
92  }
93 
94  if (length >= 4) {
95  if (strncmp(version, "3.3.", 4) == 0 && is_number(version + 4, length - 4)) {
97  return true;
98  }
99 
100  if (strncmp(version, "3.4.", 4) == 0 && is_number(version + 4, length - 4)) {
102  return true;
103  }
104  }
105 
106  if (length >= 6) {
107  if (strncmp(version, "latest", 7) == 0) { // 7 to compare the \0 as well
109  return true;
110  }
111  }
112 
113  return false;
114 }
115 
120 pm_options_main_script_set(pm_options_t *options, bool main_script) {
121  options->main_script = main_script;
122 }
123 
128 pm_options_partial_script_set(pm_options_t *options, bool partial_script) {
129  options->partial_script = partial_script;
130 }
131 
132 // For some reason, GCC analyzer thinks we're leaking allocated scopes and
133 // locals here, even though we definitely aren't. This is a false positive.
134 // Ideally we wouldn't need to suppress this.
135 #if defined(__GNUC__) && (__GNUC__ >= 10)
136 #pragma GCC diagnostic push
137 #pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak"
138 #endif
139 
144 pm_options_scopes_init(pm_options_t *options, size_t scopes_count) {
145  options->scopes_count = scopes_count;
146  options->scopes = xcalloc(scopes_count, sizeof(pm_options_scope_t));
147  return options->scopes != NULL;
148 }
149 
154 pm_options_scope_get(const pm_options_t *options, size_t index) {
155  return &options->scopes[index];
156 }
157 
163 pm_options_scope_init(pm_options_scope_t *scope, size_t locals_count) {
164  scope->locals_count = locals_count;
165  scope->locals = xcalloc(locals_count, sizeof(pm_string_t));
166  return scope->locals != NULL;
167 }
168 
173 pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index) {
174  return &scope->locals[index];
175 }
176 
182  pm_string_free(&options->filepath);
183  pm_string_free(&options->encoding);
184 
185  for (size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
186  pm_options_scope_t *scope = &options->scopes[scope_index];
187 
188  for (size_t local_index = 0; local_index < scope->locals_count; local_index++) {
189  pm_string_free(&scope->locals[local_index]);
190  }
191 
192  xfree(scope->locals);
193  }
194 
195  xfree(options->scopes);
196 }
197 
203 static uint32_t
204 pm_options_read_u32(const char *data) {
205  if (((uintptr_t) data) % sizeof(uint32_t) == 0) {
206  return *((uint32_t *) data);
207  } else {
208  uint32_t value;
209  memcpy(&value, data, sizeof(uint32_t));
210  return value;
211  }
212 }
213 
219 static int32_t
220 pm_options_read_s32(const char *data) {
221  if (((uintptr_t) data) % sizeof(int32_t) == 0) {
222  return *((int32_t *) data);
223  } else {
224  int32_t value;
225  memcpy(&value, data, sizeof(int32_t));
226  return value;
227  }
228 }
229 
237 void
238 pm_options_read(pm_options_t *options, const char *data) {
239  options->line = 1; // default
240  if (data == NULL) return;
241 
242  uint32_t filepath_length = pm_options_read_u32(data);
243  data += 4;
244 
245  if (filepath_length > 0) {
246  pm_string_constant_init(&options->filepath, data, filepath_length);
247  data += filepath_length;
248  }
249 
250  options->line = pm_options_read_s32(data);
251  data += 4;
252 
253  uint32_t encoding_length = pm_options_read_u32(data);
254  data += 4;
255 
256  if (encoding_length > 0) {
257  pm_string_constant_init(&options->encoding, data, encoding_length);
258  data += encoding_length;
259  }
260 
261  options->frozen_string_literal = (int8_t) *data++;
262  options->command_line = (uint8_t) *data++;
263  options->version = (pm_options_version_t) *data++;
264  options->encoding_locked = ((uint8_t) *data++) > 0;
265  options->main_script = ((uint8_t) *data++) > 0;
266  options->partial_script = ((uint8_t) *data++) > 0;
267 
268  uint32_t scopes_count = pm_options_read_u32(data);
269  data += 4;
270 
271  if (scopes_count > 0) {
272  if (!pm_options_scopes_init(options, scopes_count)) return;
273 
274  for (size_t scope_index = 0; scope_index < scopes_count; scope_index++) {
275  uint32_t locals_count = pm_options_read_u32(data);
276  data += 4;
277 
278  pm_options_scope_t *scope = &options->scopes[scope_index];
279  if (!pm_options_scope_init(scope, locals_count)) {
280  pm_options_free(options);
281  return;
282  }
283 
284  for (size_t local_index = 0; local_index < locals_count; local_index++) {
285  uint32_t local_length = pm_options_read_u32(data);
286  data += 4;
287 
288  pm_string_constant_init(&scope->locals[local_index], data, local_length);
289  data += local_length;
290  }
291  }
292  }
293 }
294 
295 #if defined(__GNUC__) && (__GNUC__ >= 10)
296 #pragma GCC diagnostic pop
297 #endif
#define xfree
Old name of ruby_xfree.
Definition: xmalloc.h:58
#define xcalloc
Old name of ruby_xcalloc.
Definition: xmalloc.h:55
The options that can be passed to parsing.
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:181
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:128
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:120
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:59
void pm_options_read(pm_options_t *options, const char *data)
Deserialize an options struct from the given binary string.
Definition: options.c:238
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:163
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 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
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
Definition: options.h:20
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:154
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
Definition: options.h:31
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:173
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:144
pm_options_version_t
The version of Ruby syntax that we should be parsing with.
Definition: options.h:66
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
Definition: options.h:71
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
Definition: options.h:68
size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are decimal digits.
Definition: pm_char.c:225
void pm_string_constant_init(pm_string_t *string, const char *source, size_t length)
Initialize a constant string that doesn't own its memory source.
Definition: pm_string.c:42
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
Definition: pm_string.c:369
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
Definition: defines.h:50
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
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:77
uint8_t command_line
A bitset of the various options that were set on the command line.
Definition: options.h:126
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
Definition: options.h:88
bool encoding_locked
Whether or not the encoding magic comments should be respected.
Definition: options.h:142
pm_options_scope_t * scopes
The scopes surrounding the code that is being parsed.
Definition: options.h:116
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
Definition: options.h:149
pm_string_t encoding
The name of the encoding that the source file is in.
Definition: options.h:103
int32_t line
The line within the file that the parse starts on.
Definition: options.h:97
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
Definition: options.h:82
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
Definition: options.h:135
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:159
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
Definition: options.h:108
pm_string_t filepath
The name of the file that is currently being parsed.
Definition: options.h:91
pm_options_version_t version
The version of prism that we should be parsing with.
Definition: options.h:123
A generic string type that can have various ownership semantics.
Definition: pm_string.h:33