[ruby/prism] Do not use 0 to indicate the latest ruby version to parse

This makes it hard to do version checks against this value. The current version checks work because there are so few possible values at the moment.

As an example, PR 3337 introduces new syntax for ruby 3.5 and uses `PM_OPTIONS_VERSION_LATEST` as its version guard. Because what is considered the latest changes every year, it must later be changed to `parser->version == parser->version == PM_OPTIONS_VERSION_CRUBY_3_5 || parser->version == PM_OPTIONS_VERSION_LATEST`, with one extra version each year.

With this change, the PR can instead write `parser->version >= PM_OPTIONS_VERSION_CRUBY_3_5` which is self-explanatory
and works for future versions.

8318a113ca
This commit is contained in:
Earlopain 2025-07-22 13:16:40 +02:00 committed by git
parent b22eb0e468
commit 026079925c
4 changed files with 29 additions and 17 deletions

View file

@ -422,13 +422,13 @@ module Prism
def dump_options_version(version)
case version
when nil, "latest"
0
0 # Handled in pm_parser_init
when /\A3\.3(\.\d+)?\z/
1
when /\A3\.4(\.\d+)?\z/
2
when /\A3\.5(\.\d+)?\z/
0
3
else
raise ArgumentError, "invalid version: #{version}"
end

View file

@ -89,7 +89,7 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
}
if (strncmp(version, "3.5", 3) == 0) {
options->version = PM_OPTIONS_VERSION_LATEST;
options->version = PM_OPTIONS_VERSION_CRUBY_3_5;
return true;
}
@ -108,7 +108,7 @@ pm_options_version_set(pm_options_t *options, const char *version, size_t length
}
if (strncmp(version, "3.5.", 4) == 0 && is_number(version + 4, length - 4)) {
options->version = PM_OPTIONS_VERSION_LATEST;
options->version = PM_OPTIONS_VERSION_CRUBY_3_5;
return true;
}
}

View file

@ -82,14 +82,20 @@ typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const
* parse in the same way as a specific version of CRuby would have.
*/
typedef enum {
/** The current version of prism. */
PM_OPTIONS_VERSION_LATEST = 0,
/** If an explicit version is not provided, the current version of prism will be used. */
PM_OPTIONS_VERSION_UNSET = 0,
/** The vendored version of prism in CRuby 3.3.x. */
PM_OPTIONS_VERSION_CRUBY_3_3 = 1,
/** The vendored version of prism in CRuby 3.4.x. */
PM_OPTIONS_VERSION_CRUBY_3_4 = 2
PM_OPTIONS_VERSION_CRUBY_3_4 = 2,
/** The vendored version of prism in CRuby 3.5.x. */
PM_OPTIONS_VERSION_CRUBY_3_5 = 3,
/** The current version of prism. */
PM_OPTIONS_VERSION_LATEST = PM_OPTIONS_VERSION_CRUBY_3_5
} pm_options_version_t;
/**

View file

@ -1409,7 +1409,7 @@ pm_conditional_predicate_warn_write_literal_p(const pm_node_t *node) {
static inline void
pm_conditional_predicate_warn_write_literal(pm_parser_t *parser, const pm_node_t *node) {
if (pm_conditional_predicate_warn_write_literal_p(node)) {
pm_parser_warn_node(parser, node, parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
pm_parser_warn_node(parser, node, parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
}
}
@ -2976,7 +2976,7 @@ pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const
*/
static void
pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
pm_node_t *node;
PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
@ -9113,7 +9113,7 @@ lex_global_variable(pm_parser_t *parser) {
} while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
// $0 isn't allowed to be followed by anything.
pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, diag_id);
}
@ -9150,7 +9150,7 @@ lex_global_variable(pm_parser_t *parser) {
} else {
// If we get here, then we have a $ followed by something that
// isn't recognized as a global variable.
pm_diagnostic_id_t diag_id = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
const uint8_t *end = parser->current.end + parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
PM_PARSER_ERR_FORMAT(parser, parser->current.start, end, diag_id, (int) (end - parser->current.start), (const char *) parser->current.start);
}
@ -10177,7 +10177,7 @@ lex_at_variable(pm_parser_t *parser) {
}
} else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
pm_diagnostic_id_t diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) {
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
diag_id = (type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
}
@ -14667,7 +14667,7 @@ parse_parameters(
parser_lex(parser);
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &name);
uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
@ -14683,7 +14683,7 @@ parse_parameters(
// If the value of the parameter increased the number of
// reads of that parameter, then we need to warn that we
// have a circular definition.
if ((parser->version == PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
}
@ -14768,13 +14768,13 @@ parse_parameters(
if (token_begins_expression_p(parser->current.type)) {
pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &local);
uint32_t reads = parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser, true);
pm_node_t *value = parse_value_expression(parser, binding_power, false, false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
if (parser->version == PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
}
@ -16478,7 +16478,7 @@ parse_variable(pm_parser_t *parser) {
pm_node_list_append(&current_scope->implicit_parameters, node);
return node;
} else if ((parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
} else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.start, parser->previous.end)) {
pm_node_t *node = (pm_node_t *) pm_it_local_variable_read_node_create(parser, &parser->previous);
pm_node_list_append(&current_scope->implicit_parameters, node);
@ -22641,6 +22641,12 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
}
}
// Now that we have established the user-provided options, check if
// a version was given and parse as the latest version otherwise.
if (parser->version == PM_OPTIONS_VERSION_UNSET) {
parser->version = PM_OPTIONS_VERSION_LATEST;
}
pm_accepts_block_stack_push(parser, true);
// Skip past the UTF-8 BOM if it exists.