[ruby/prism] Change frozen_string_literal to be a tri-state

An explicit `false` is not equivalent to the comment being missing,
because the default can be switched with a runtime flag:

```bash
$ ruby --enable-frozen-string-literal -e 'p "foo".frozen?'
true
```

https://github.com/ruby/prism/commit/4660f58775
This commit is contained in:
Jean Boussier 2024-03-12 12:17:55 +01:00 committed by git
parent 0f076fa520
commit 53a77d9b90
6 changed files with 58 additions and 22 deletions

View File

@ -673,7 +673,9 @@ flags:
- name: FORCED_BINARY_ENCODING - name: FORCED_BINARY_ENCODING
comment: "internal bytes forced the encoding to binary" comment: "internal bytes forced the encoding to binary"
- name: FROZEN - name: FROZEN
comment: "frozen by virtue of a `frozen_string_literal` comment" comment: "frozen by virtue of a `frozen_string_literal: true` comment or `--enable-frozen-string-literal`"
- name: MUTABLE
comment: "mutable by virtue of a `frozen_string_literal: false` comment or `--disable-frozen-string-literal`"
comment: Flags for string nodes. comment: Flags for string nodes.
- name: SymbolFlags - name: SymbolFlags
values: values:

View File

@ -142,7 +142,7 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
} else if (key_id == rb_option_id_offset) { } else if (key_id == rb_option_id_offset) {
if (!NIL_P(value)) pm_options_offset_set(options, NUM2UINT(value)); if (!NIL_P(value)) pm_options_offset_set(options, NUM2UINT(value));
} else if (key_id == rb_option_id_frozen_string_literal) { } else if (key_id == rb_option_id_frozen_string_literal) {
if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue); if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, RTEST(value));
} else if (key_id == rb_option_id_version) { } else if (key_id == rb_option_id_version) {
if (!NIL_P(value)) { if (!NIL_P(value)) {
const char *version = check_string(value); const char *version = check_string(value);

View File

@ -37,7 +37,7 @@ pm_options_offset_set(pm_options_t *options, uint32_t offset) {
*/ */
PRISM_EXPORTED_FUNCTION void PRISM_EXPORTED_FUNCTION void
pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) { pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal) {
options->frozen_string_literal = frozen_string_literal; options->frozen_string_literal = frozen_string_literal ? 1 : -1;
} }
/** /**
@ -212,7 +212,7 @@ pm_options_read(pm_options_t *options, const char *data) {
data += encoding_length; data += encoding_length;
} }
options->frozen_string_literal = (*data++) ? true : false; options->frozen_string_literal = (int8_t) *data++;
options->command_line = (uint8_t) *data++; options->command_line = (uint8_t) *data++;
options->version = (pm_options_version_t) *data++; options->version = (pm_options_version_t) *data++;

View File

@ -13,6 +13,22 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
/**
* String literals should be made frozen.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED ((int8_t) -1)
/**
* String literals may be frozen or mutable depending on the implementation
* default.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET ((int8_t) 0)
/**
* String literals should be made mutable.
*/
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED ((int8_t) 1)
/** /**
* A scope of locals surrounding the code that is being parsed. * A scope of locals surrounding the code that is being parsed.
*/ */
@ -85,8 +101,14 @@ typedef struct {
/** A bitset of the various options that were set on the command line. */ /** A bitset of the various options that were set on the command line. */
uint8_t command_line; uint8_t command_line;
/** Whether or not the frozen string literal option has been set. */ /**
bool frozen_string_literal; * Whether or not the frozen string literal option has been set.
* May be:
* - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
* - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
* - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
*/
int8_t frozen_string_literal;
} pm_options_t; } pm_options_t;
/** /**

View File

@ -709,6 +709,16 @@ struct pm_parser {
/** The command line flags given from the options. */ /** The command line flags given from the options. */
uint8_t command_line; uint8_t command_line;
/**
* Whether or not we have found a frozen_string_literal magic comment with
* a true or false value.
* May be:
* - PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
* - PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
* - PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
*/
int8_t frozen_string_literal;
/** Whether or not we're at the beginning of a command. */ /** Whether or not we're at the beginning of a command. */
bool command_start; bool command_start;
@ -737,12 +747,6 @@ struct pm_parser {
*/ */
bool semantic_token_seen; bool semantic_token_seen;
/**
* Whether or not we have found a frozen_string_literal magic comment with
* a true value.
*/
bool frozen_string_literal;
/** /**
* True if the current regular expression being lexed contains only ASCII * True if the current regular expression being lexed contains only ASCII
* characters. * characters.

View File

@ -5898,8 +5898,13 @@ pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening,
pm_string_node_t *node = PM_ALLOC_NODE(parser, pm_string_node_t); pm_string_node_t *node = PM_ALLOC_NODE(parser, pm_string_node_t);
pm_node_flags_t flags = 0; pm_node_flags_t flags = 0;
if (parser->frozen_string_literal) { switch (parser->frozen_string_literal) {
flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN; case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
flags = PM_STRING_FLAGS_MUTABLE;
break;
case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
break;
} }
*node = (pm_string_node_t) { *node = (pm_string_node_t) {
@ -6298,8 +6303,13 @@ pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
pm_string_node_t *new_node = PM_ALLOC_NODE(parser, pm_string_node_t); pm_string_node_t *new_node = PM_ALLOC_NODE(parser, pm_string_node_t);
pm_node_flags_t flags = 0; pm_node_flags_t flags = 0;
if (parser->frozen_string_literal) { switch (parser->frozen_string_literal) {
flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN; case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
flags = PM_STRING_FLAGS_MUTABLE;
break;
case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
break;
} }
*new_node = (pm_string_node_t) { *new_node = (pm_string_node_t) {
@ -7173,9 +7183,9 @@ parser_lex_magic_comment_encoding(pm_parser_t *parser) {
static void static void
parser_lex_magic_comment_frozen_string_literal_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) { parser_lex_magic_comment_frozen_string_literal_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
if ((start + 4 <= end) && pm_strncasecmp(start, (const uint8_t *) "true", 4) == 0) { if ((start + 4 <= end) && pm_strncasecmp(start, (const uint8_t *) "true", 4) == 0) {
parser->frozen_string_literal = true; parser->frozen_string_literal = 1;
} else if ((start + 5 <= end) && pm_strncasecmp(start, (const uint8_t *) "false", 5) == 0) { } else if ((start + 5 <= end) && pm_strncasecmp(start, (const uint8_t *) "false", 5) == 0) {
parser->frozen_string_literal = false; parser->frozen_string_literal = -1;
} }
} }
@ -18912,7 +18922,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
.in_keyword_arg = false, .in_keyword_arg = false,
.current_param_name = 0, .current_param_name = 0,
.semantic_token_seen = false, .semantic_token_seen = false,
.frozen_string_literal = false, .frozen_string_literal = 0,
.current_regular_expression_ascii_only = false .current_regular_expression_ascii_only = false
}; };
@ -18971,9 +18981,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
} }
// frozen_string_literal option // frozen_string_literal option
if (options->frozen_string_literal) { parser->frozen_string_literal = options->frozen_string_literal;
parser->frozen_string_literal = true;
}
// command_line option // command_line option
parser->command_line = options->command_line; parser->command_line = options->command_line;