[ruby/prism] Command line options as a bitset
https://github.com/ruby/prism/commit/369ffbd57e
This commit is contained in:
parent
cd8d1018bb
commit
50e999c56d
@ -313,6 +313,24 @@ module Prism
|
||||
LibRubyParser.pm_parse_success_p(string.pointer, string.length, dump_options(options))
|
||||
end
|
||||
|
||||
# Return the value that should be dumped for the command_line option.
|
||||
def dump_options_command_line(options)
|
||||
command_line = options.fetch(:command_line, "")
|
||||
raise ArgumentError, "command_line must be a string" unless command_line.is_a?(String)
|
||||
|
||||
command_line.each_char.inject(0) do |value, char|
|
||||
case char
|
||||
when "a" then value | 0b000001
|
||||
when "e" then value | 0b000010
|
||||
when "l" then value | 0b000100
|
||||
when "n" then value | 0b001000
|
||||
when "p" then value | 0b010000
|
||||
when "x" then value | 0b100000
|
||||
else raise ArgumentError, "invalid command_line option: #{char}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Convert the given options into a serialized options string.
|
||||
def dump_options(options)
|
||||
template = +""
|
||||
@ -342,16 +360,7 @@ module Prism
|
||||
values << (options.fetch(:frozen_string_literal, false) ? 1 : 0)
|
||||
|
||||
template << "C"
|
||||
values << (options.fetch(:command_line_p, false) ? 1 : 0)
|
||||
|
||||
template << "C"
|
||||
values << (options.fetch(:command_line_n, false) ? 1 : 0)
|
||||
|
||||
template << "C"
|
||||
values << (options.fetch(:command_line_l, false) ? 1 : 0)
|
||||
|
||||
template << "C"
|
||||
values << (options.fetch(:command_line_a, false) ? 1 : 0)
|
||||
values << dump_options_command_line(options)
|
||||
|
||||
template << "C"
|
||||
values << { nil => 0, "3.3.0" => 1, "3.4.0" => 0, "latest" => 0 }.fetch(options[:version])
|
||||
|
@ -29,10 +29,7 @@ ID rb_option_id_line;
|
||||
ID rb_option_id_frozen_string_literal;
|
||||
ID rb_option_id_version;
|
||||
ID rb_option_id_scopes;
|
||||
ID rb_option_id_command_line_p;
|
||||
ID rb_option_id_command_line_n;
|
||||
ID rb_option_id_command_line_l;
|
||||
ID rb_option_id_command_line_a;
|
||||
ID rb_option_id_command_line;
|
||||
|
||||
/******************************************************************************/
|
||||
/* IO of Ruby code */
|
||||
@ -148,21 +145,32 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
||||
const char *version = check_string(value);
|
||||
|
||||
if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
|
||||
rb_raise(rb_eArgError, "invalid version: %"PRIsVALUE, value);
|
||||
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
|
||||
}
|
||||
}
|
||||
} else if (key_id == rb_option_id_scopes) {
|
||||
if (!NIL_P(value)) build_options_scopes(options, value);
|
||||
} else if (key_id == rb_option_id_command_line_p) {
|
||||
if (!NIL_P(value)) pm_options_command_line_p_set(options, value == Qtrue);
|
||||
} else if (key_id == rb_option_id_command_line_n) {
|
||||
if (!NIL_P(value)) pm_options_command_line_n_set(options, value == Qtrue);
|
||||
} else if (key_id == rb_option_id_command_line_l) {
|
||||
if (!NIL_P(value)) pm_options_command_line_l_set(options, value == Qtrue);
|
||||
} else if (key_id == rb_option_id_command_line_a) {
|
||||
if (!NIL_P(value)) pm_options_command_line_a_set(options, value == Qtrue);
|
||||
} else if (key_id == rb_option_id_command_line) {
|
||||
if (!NIL_P(value)) {
|
||||
const char *string = check_string(value);
|
||||
uint8_t command_line = 0;
|
||||
|
||||
for (size_t index = 0; index < strlen(string); index++) {
|
||||
switch (string[index]) {
|
||||
case 'a': command_line |= PM_OPTIONS_COMMAND_LINE_A; break;
|
||||
case 'e': command_line |= PM_OPTIONS_COMMAND_LINE_E; break;
|
||||
case 'l': command_line |= PM_OPTIONS_COMMAND_LINE_L; break;
|
||||
case 'n': command_line |= PM_OPTIONS_COMMAND_LINE_N; break;
|
||||
case 'p': command_line |= PM_OPTIONS_COMMAND_LINE_P; break;
|
||||
case 'x': command_line |= PM_OPTIONS_COMMAND_LINE_X; break;
|
||||
default: rb_raise(rb_eArgError, "invalid command line flag: '%c'", string[index]); break;
|
||||
}
|
||||
}
|
||||
|
||||
pm_options_command_line_set(options, command_line);
|
||||
}
|
||||
} else {
|
||||
rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, key);
|
||||
rb_raise(rb_eArgError, "unknown keyword: %" PRIsVALUE, key);
|
||||
}
|
||||
|
||||
return ST_CONTINUE;
|
||||
@ -697,21 +705,25 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
||||
* Parse the given string and return a ParseResult instance. The options that
|
||||
* are supported are:
|
||||
*
|
||||
* * `filepath` - the filepath of the source being parsed. This should be a
|
||||
* string or nil
|
||||
* * `command_line` - either nil or a string of the various options that were
|
||||
* set on the command line. Valid values are combinations of "a", "l",
|
||||
* "n", "p", and "x".
|
||||
* * `encoding` - the encoding of the source being parsed. This should be an
|
||||
* encoding or nil
|
||||
* * `line` - the line number that the parse starts on. This should be an
|
||||
* integer or nil. Note that this is 1-indexed.
|
||||
* encoding or nil.
|
||||
* * `filepath` - the filepath of the source being parsed. This should be a
|
||||
* string or nil.
|
||||
* * `frozen_string_literal` - whether or not the frozen string literal pragma
|
||||
* has been set. This should be a boolean or nil.
|
||||
* * `version` - the version of prism that should be used to parse Ruby code. By
|
||||
* default prism assumes you want to parse with the latest vesion of
|
||||
* prism (which you can trigger with `nil` or `"latest"`). If you want to
|
||||
* parse exactly as CRuby 3.3.0 would, then you can pass `"3.3.0"`.
|
||||
* * `line` - the line number that the parse starts on. This should be an
|
||||
* integer or nil. Note that this is 1-indexed.
|
||||
* * `scopes` - the locals that are in scope surrounding the code that is being
|
||||
* parsed. This should be an array of arrays of symbols or nil. Scopes are
|
||||
* ordered from the outermost scope to the innermost one.
|
||||
* * `version` - the version of Ruby syntax that prism should used to parse Ruby
|
||||
* code. By default prism assumes you want to parse with the latest vesion
|
||||
* of Ruby syntax (which you can trigger with `nil` or `"latest"`). You
|
||||
* may also restrict the syntax to a specific version of Ruby. The
|
||||
* supported values are `"3.3.0"` and `"3.4.0"`.
|
||||
*/
|
||||
static VALUE
|
||||
parse(int argc, VALUE *argv, VALUE self) {
|
||||
@ -1244,10 +1256,7 @@ Init_prism(void) {
|
||||
rb_option_id_frozen_string_literal = rb_intern_const("frozen_string_literal");
|
||||
rb_option_id_version = rb_intern_const("version");
|
||||
rb_option_id_scopes = rb_intern_const("scopes");
|
||||
rb_option_id_command_line_p = rb_intern_const("command_line_p");
|
||||
rb_option_id_command_line_n = rb_intern_const("command_line_n");
|
||||
rb_option_id_command_line_l = rb_intern_const("command_line_l");
|
||||
rb_option_id_command_line_a = rb_intern_const("command_line_a");
|
||||
rb_option_id_command_line = rb_intern_const("command_line");
|
||||
|
||||
/**
|
||||
* The version of the prism library.
|
||||
|
@ -33,35 +33,11 @@ pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_l
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the -p command line option on the given options struct.
|
||||
* Sets the command line option on the given options struct.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_options_command_line_p_set(pm_options_t *options, bool command_line_p) {
|
||||
options->command_line_p = command_line_p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the -n command line option on the given options struct.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_options_command_line_n_set(pm_options_t *options, bool command_line_n) {
|
||||
options->command_line_n = command_line_n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the -l command line option on the given options struct.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_options_command_line_l_set(pm_options_t *options, bool command_line_l) {
|
||||
options->command_line_l = command_line_l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the -a command line option on the given options struct.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_options_command_line_a_set(pm_options_t *options, bool command_line_a) {
|
||||
options->command_line_a = command_line_a;
|
||||
pm_options_command_line_set(pm_options_t *options, uint8_t command_line) {
|
||||
options->command_line = command_line;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,10 +202,7 @@ pm_options_read(pm_options_t *options, const char *data) {
|
||||
}
|
||||
|
||||
options->frozen_string_literal = (*data++) ? true : false;
|
||||
options->command_line_p = (*data++) ? true : false;
|
||||
options->command_line_n = (*data++) ? true : false;
|
||||
options->command_line_l = (*data++) ? true : false;
|
||||
options->command_line_a = (*data++) ? true : false;
|
||||
options->command_line = (uint8_t) *data++;
|
||||
options->version = (pm_options_version_t) *data++;
|
||||
|
||||
uint32_t scopes_count = pm_options_read_u32(data);
|
||||
|
@ -76,22 +76,50 @@ typedef struct {
|
||||
*/
|
||||
pm_options_version_t version;
|
||||
|
||||
/** A bitset of the various options that were set on the 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 -p command line option has been set. */
|
||||
bool command_line_p;
|
||||
|
||||
/** Whether or not the -n command line option has been set. */
|
||||
bool command_line_n;
|
||||
|
||||
/** Whether or not the -l command line option has been set. */
|
||||
bool command_line_l;
|
||||
|
||||
/** Whether or not the -a command line option has been set. */
|
||||
bool command_line_a;
|
||||
} pm_options_t;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -a option was set. -a
|
||||
* splits the input line $_ into $F.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_A = 0x1;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -e option was set. -e
|
||||
* allow the user to specify a script to be executed. This is necessary for
|
||||
* prism to know because certain warnings are not generated when -e is used.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_E = 0x2;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -l option was set. -l
|
||||
* chomps the input line by default.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_L = 0x4;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -n option was set. -n
|
||||
* wraps the script in a while gets loop.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_N = 0x8;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -p option was set. -p
|
||||
* prints the value of $_ at the end of each loop.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_P = 0x10;
|
||||
|
||||
/**
|
||||
* A bit representing whether or not the command line -x option was set. -x
|
||||
* searches the input file for a shebang that matches the current Ruby engine.
|
||||
*/
|
||||
static const uint8_t PM_OPTIONS_COMMAND_LINE_X = 0x20;
|
||||
|
||||
/**
|
||||
* Set the filepath option on the given options struct.
|
||||
*
|
||||
@ -125,36 +153,12 @@ PRISM_EXPORTED_FUNCTION void pm_options_encoding_set(pm_options_t *options, cons
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_frozen_string_literal_set(pm_options_t *options, bool frozen_string_literal);
|
||||
|
||||
/**
|
||||
* Sets the -p command line option on the given options struct.
|
||||
* Sets the command line option on the given options struct.
|
||||
*
|
||||
* @param options The options struct to set the -p command line option on.
|
||||
* @param command_line_p The -p command line option to set.
|
||||
* @param options The options struct to set the command line option on.
|
||||
* @param command_line The command_line value to set.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_command_line_p_set(pm_options_t *options, bool command_line_p);
|
||||
|
||||
/**
|
||||
* Sets the -n command line option on the given options struct.
|
||||
*
|
||||
* @param options The options struct to set the -n command line option on.
|
||||
* @param command_line_n The -n command line option to set.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_command_line_n_set(pm_options_t *options, bool command_line_n);
|
||||
|
||||
/**
|
||||
* Sets the -l command line option on the given options struct.
|
||||
*
|
||||
* @param options The options struct to set the -l command line option on.
|
||||
* @param command_line_l The -l command line option to set.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_command_line_l_set(pm_options_t *options, bool command_line_l);
|
||||
|
||||
/**
|
||||
* Sets the -a command line option on the given options struct.
|
||||
*
|
||||
* @param options The options struct to set the -a command line option on.
|
||||
* @param command_line_a The -a command line option to set.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_command_line_a_set(pm_options_t *options, bool command_line_a);
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_command_line_set(pm_options_t *options, uint8_t command_line);
|
||||
|
||||
/**
|
||||
* Set the version option on the given options struct by parsing the given
|
||||
|
@ -703,6 +703,9 @@ struct pm_parser {
|
||||
/** The version of prism that we should use to parse. */
|
||||
pm_options_version_t version;
|
||||
|
||||
/** The command line flags given from the options. */
|
||||
uint8_t command_line;
|
||||
|
||||
/** Whether or not we're at the beginning of a command. */
|
||||
bool command_start;
|
||||
|
||||
@ -736,30 +739,6 @@ struct pm_parser {
|
||||
* a true value.
|
||||
*/
|
||||
bool frozen_string_literal;
|
||||
|
||||
/**
|
||||
* Whether or not -p was present on the command line that invoked the
|
||||
* parser. -p prints the value of $_ at the end of each loop.
|
||||
*/
|
||||
bool command_line_p;
|
||||
|
||||
/**
|
||||
* Whether or not -n was present on the command line that invoked the
|
||||
* parser. -n wraps the script in a while gets loop.
|
||||
*/
|
||||
bool command_line_n;
|
||||
|
||||
/**
|
||||
* Whether or not -l was present on the command line that invoked the
|
||||
* parser. -l chomps the input line by default.
|
||||
*/
|
||||
bool command_line_l;
|
||||
|
||||
/**
|
||||
* Whether or not -a was present on the command line that invoked the
|
||||
* parser. -a splits the input line $_ into $F.
|
||||
*/
|
||||
bool command_line_a;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -18273,7 +18273,7 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
||||
*/
|
||||
static pm_statements_node_t *
|
||||
wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
|
||||
if (parser->command_line_p) {
|
||||
if (parser->command_line & PM_OPTIONS_COMMAND_LINE_P) {
|
||||
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
|
||||
pm_arguments_node_arguments_append(
|
||||
arguments,
|
||||
@ -18287,8 +18287,8 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
|
||||
));
|
||||
}
|
||||
|
||||
if (parser->command_line_n) {
|
||||
if (parser->command_line_a) {
|
||||
if (parser->command_line & PM_OPTIONS_COMMAND_LINE_N) {
|
||||
if (parser->command_line & PM_OPTIONS_COMMAND_LINE_A) {
|
||||
pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
|
||||
pm_arguments_node_arguments_append(
|
||||
arguments,
|
||||
@ -18313,7 +18313,7 @@ wrap_statements(pm_parser_t *parser, pm_statements_node_t *statements) {
|
||||
(pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser, "$/", 2))
|
||||
);
|
||||
|
||||
if (parser->command_line_l) {
|
||||
if (parser->command_line & PM_OPTIONS_COMMAND_LINE_L) {
|
||||
pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
|
||||
pm_keyword_hash_node_elements_append(keywords, (pm_node_t *) pm_assoc_node_create(
|
||||
parser,
|
||||
@ -18367,7 +18367,7 @@ parse_program(pm_parser_t *parser) {
|
||||
|
||||
// At the top level, see if we need to wrap the statements in a program
|
||||
// node with a while loop based on the options.
|
||||
if (parser->command_line_p || parser->command_line_n) {
|
||||
if (parser->command_line & (PM_OPTIONS_COMMAND_LINE_P | PM_OPTIONS_COMMAND_LINE_N)) {
|
||||
statements = wrap_statements(parser, statements);
|
||||
}
|
||||
|
||||
@ -18421,6 +18421,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
||||
.current_string = PM_STRING_EMPTY,
|
||||
.start_line = 1,
|
||||
.explicit_encoding = NULL,
|
||||
.command_line = 0,
|
||||
.command_start = true,
|
||||
.recovering = false,
|
||||
.encoding_changed = false,
|
||||
@ -18428,11 +18429,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
||||
.in_keyword_arg = false,
|
||||
.current_param_name = 0,
|
||||
.semantic_token_seen = false,
|
||||
.frozen_string_literal = false,
|
||||
.command_line_p = options != NULL && options->command_line_p,
|
||||
.command_line_n = options != NULL && options->command_line_n,
|
||||
.command_line_l = options != NULL && options->command_line_l,
|
||||
.command_line_a = options != NULL && options->command_line_a
|
||||
.frozen_string_literal = false
|
||||
};
|
||||
|
||||
// Initialize the constant pool. We're going to completely guess as to the
|
||||
@ -18478,6 +18475,9 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
||||
parser->frozen_string_literal = true;
|
||||
}
|
||||
|
||||
// command_line option
|
||||
parser->command_line = options->command_line;
|
||||
|
||||
// version option
|
||||
parser->version = options->version;
|
||||
|
||||
|
@ -5,7 +5,7 @@ require_relative "test_helper"
|
||||
module Prism
|
||||
class CommandLineTest < TestCase
|
||||
def test_command_line_p
|
||||
program = Prism.parse("1", command_line_p: true).value
|
||||
program = Prism.parse("1", command_line: "p").value
|
||||
statements = program.statements.body
|
||||
|
||||
assert_equal 2, statements.length
|
||||
@ -14,7 +14,7 @@ module Prism
|
||||
end
|
||||
|
||||
def test_command_line_n
|
||||
program = Prism.parse("1", command_line_n: true).value
|
||||
program = Prism.parse("1", command_line: "n").value
|
||||
statements = program.statements.body
|
||||
|
||||
assert_equal 1, statements.length
|
||||
@ -30,7 +30,7 @@ module Prism
|
||||
end
|
||||
|
||||
def test_command_line_a
|
||||
program = Prism.parse("1", command_line_n: true, command_line_a: true).value
|
||||
program = Prism.parse("1", command_line: "na").value
|
||||
statements = program.statements.body
|
||||
|
||||
assert_equal 1, statements.length
|
||||
@ -42,7 +42,7 @@ module Prism
|
||||
end
|
||||
|
||||
def test_command_line_l
|
||||
program = Prism.parse("1", command_line_n: true, command_line_l: true).value
|
||||
program = Prism.parse("1", command_line: "nl").value
|
||||
statements = program.statements.body
|
||||
|
||||
assert_equal 1, statements.length
|
||||
|
Loading…
x
Reference in New Issue
Block a user