mirror of
https://github.com/ruby/ruby.git
synced 2026-01-27 04:24:23 +00:00
[ruby/prism] Convert start line to signed integers
Ruby allows for 0 or negative line start, this is often used
with `eval` calls to get a correct offset when prefixing a snippet.
e.g.
```ruby
caller = caller_locations(1, 1).first
class_eval <<~RUBY, caller.path, caller.line - 2
# frozen_string_literal: true
def some_method
#{caller_provided_code_snippet}
end
RUBY
```
https://github.com/ruby/prism/commit/0d14ed1452
This commit is contained in:
parent
2653404840
commit
2af82e2316
@ -126,7 +126,7 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
||||
} else if (key_id == rb_option_id_encoding) {
|
||||
if (!NIL_P(value)) pm_options_encoding_set(options, rb_enc_name(rb_to_encoding(value)));
|
||||
} else if (key_id == rb_option_id_line) {
|
||||
if (!NIL_P(value)) pm_options_line_set(options, NUM2UINT(value));
|
||||
if (!NIL_P(value)) pm_options_line_set(options, NUM2INT(value));
|
||||
} else if (key_id == rb_option_id_frozen_string_literal) {
|
||||
if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue);
|
||||
} else if (key_id == rb_option_id_verbose) {
|
||||
@ -166,6 +166,7 @@ build_options(VALUE argument) {
|
||||
*/
|
||||
static void
|
||||
extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
|
||||
options->line = 1; // default
|
||||
if (!NIL_P(keywords)) {
|
||||
struct build_options_data data = { .options = options, .keywords = keywords };
|
||||
struct build_options_data *argument = &data;
|
||||
|
||||
@ -20,7 +20,7 @@ pm_options_encoding_set(pm_options_t *options, const char *encoding) {
|
||||
* Set the line option on the given options struct.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_options_line_set(pm_options_t *options, uint32_t line) {
|
||||
pm_options_line_set(pm_options_t *options, int32_t line) {
|
||||
options->line = line;
|
||||
}
|
||||
|
||||
@ -114,6 +114,22 @@ pm_options_read_u32(const char *data) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit signed integer from a pointer. This function is used to read
|
||||
* the options that are passed into the parser from the Ruby implementation. It
|
||||
* handles aligned and unaligned reads.
|
||||
*/
|
||||
static int32_t
|
||||
pm_options_read_s32(const char *data) {
|
||||
if (((uintptr_t) data) % sizeof(int32_t) == 0) {
|
||||
return *((int32_t *) data);
|
||||
} else {
|
||||
int32_t value;
|
||||
memcpy(&value, data, sizeof(int32_t));
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserialize an options struct from the given binary string. This is used to
|
||||
* pass options to the parser from an FFI call so that consumers of the library
|
||||
@ -123,6 +139,9 @@ pm_options_read_u32(const char *data) {
|
||||
*/
|
||||
void
|
||||
pm_options_read(pm_options_t *options, const char *data) {
|
||||
options->line = 1; // default
|
||||
if (data == NULL) return;
|
||||
|
||||
uint32_t filepath_length = pm_options_read_u32(data);
|
||||
data += 4;
|
||||
|
||||
@ -131,7 +150,7 @@ pm_options_read(pm_options_t *options, const char *data) {
|
||||
data += filepath_length;
|
||||
}
|
||||
|
||||
options->line = pm_options_read_u32(data);
|
||||
options->line = pm_options_read_s32(data);
|
||||
data += 4;
|
||||
|
||||
uint32_t encoding_length = pm_options_read_u32(data);
|
||||
|
||||
@ -35,7 +35,7 @@ typedef struct {
|
||||
* The line within the file that the parse starts on. This value is
|
||||
* 0-indexed.
|
||||
*/
|
||||
uint32_t line;
|
||||
int32_t line;
|
||||
|
||||
/**
|
||||
* The name of the encoding that the source file is in. Note that this must
|
||||
@ -80,7 +80,7 @@ PRISM_EXPORTED_FUNCTION void pm_options_filepath_set(pm_options_t *options, cons
|
||||
* @param options The options struct to set the line on.
|
||||
* @param line The line to set.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, uint32_t line);
|
||||
PRISM_EXPORTED_FUNCTION void pm_options_line_set(pm_options_t *options, int32_t line);
|
||||
|
||||
/**
|
||||
* Set the encoding option on the given options struct.
|
||||
|
||||
@ -661,7 +661,7 @@ struct pm_parser {
|
||||
* The line number at the start of the parse. This will be used to offset
|
||||
* the line numbers of all of the locations.
|
||||
*/
|
||||
uint32_t start_line;
|
||||
int32_t start_line;
|
||||
|
||||
/** Whether or not we're at the beginning of a command. */
|
||||
bool command_start;
|
||||
|
||||
@ -17067,9 +17067,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm
|
||||
parser->filepath_string = options->filepath;
|
||||
|
||||
// line option
|
||||
if (options->line > 0) {
|
||||
parser->start_line = options->line;
|
||||
}
|
||||
parser->start_line = options->line;
|
||||
|
||||
// encoding option
|
||||
size_t encoding_length = pm_string_length(&options->encoding);
|
||||
@ -17238,7 +17236,7 @@ pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
|
||||
pm_options_t options = { 0 };
|
||||
if (data != NULL) pm_options_read(&options, data);
|
||||
pm_options_read(&options, data);
|
||||
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, source, size, &options);
|
||||
@ -17260,7 +17258,7 @@ pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, cons
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
|
||||
pm_options_t options = { 0 };
|
||||
if (data != NULL) pm_options_read(&options, data);
|
||||
pm_options_read(&options, data);
|
||||
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, source, size, &options);
|
||||
@ -17268,7 +17266,7 @@ pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t s
|
||||
pm_node_t *node = pm_parse(&parser);
|
||||
pm_serialize_header(buffer);
|
||||
pm_serialize_encoding(&parser.encoding, buffer);
|
||||
pm_buffer_append_varuint(buffer, parser.start_line);
|
||||
pm_buffer_append_varsint(buffer, parser.start_line);
|
||||
pm_serialize_comment_list(&parser, &parser.comment_list, buffer);
|
||||
|
||||
pm_node_destroy(&parser, node);
|
||||
|
||||
@ -46,7 +46,7 @@ pm_source_new(pm_parser_t *parser, rb_encoding *encoding) {
|
||||
rb_ary_push(offsets, INT2FIX(parser->newline_list.offsets[index]));
|
||||
}
|
||||
|
||||
VALUE source_argv[] = { source, ULONG2NUM(parser->start_line), offsets };
|
||||
VALUE source_argv[] = { source, LONG2NUM(parser->start_line), offsets };
|
||||
return rb_class_new_instance(3, source_argv, rb_cPrismSource);
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ module Prism
|
||||
end
|
||||
|
||||
def load_start_line
|
||||
source.start_line = load_varuint
|
||||
source.start_line = load_varsint
|
||||
end
|
||||
|
||||
def load_comments
|
||||
@ -161,6 +161,11 @@ module Prism
|
||||
end
|
||||
end
|
||||
|
||||
def load_varsint
|
||||
n = load_varuint
|
||||
(n >> 1) ^ (-(n & 1))
|
||||
end
|
||||
|
||||
def load_serialized_length
|
||||
io.read(4).unpack1("L")
|
||||
end
|
||||
|
||||
@ -219,7 +219,7 @@ pm_serialize_encoding(pm_encoding_t *encoding, pm_buffer_t *buffer) {
|
||||
void
|
||||
pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer) {
|
||||
pm_serialize_encoding(&parser->encoding, buffer);
|
||||
pm_buffer_append_varuint(buffer, parser->start_line);
|
||||
pm_buffer_append_varsint(buffer, parser->start_line);
|
||||
<%- unless Prism::SERIALIZE_ONLY_SEMANTICS_FIELDS -%>
|
||||
pm_serialize_comment_list(parser, &parser->comment_list, buffer);
|
||||
<%- end -%>
|
||||
@ -301,7 +301,7 @@ serialize_token(void *data, pm_parser_t *parser, pm_token_t *token) {
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
|
||||
pm_options_t options = { 0 };
|
||||
if (data != NULL) pm_options_read(&options, data);
|
||||
pm_options_read(&options, data);
|
||||
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, source, size, &options);
|
||||
@ -318,7 +318,7 @@ pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const
|
||||
pm_buffer_append_byte(buffer, 0);
|
||||
|
||||
pm_serialize_encoding(&parser.encoding, buffer);
|
||||
pm_buffer_append_varuint(buffer, parser.start_line);
|
||||
pm_buffer_append_varsint(buffer, parser.start_line);
|
||||
pm_serialize_comment_list(&parser, &parser.comment_list, buffer);
|
||||
pm_serialize_magic_comment_list(&parser, &parser.magic_comment_list, buffer);
|
||||
pm_serialize_data_loc(&parser, buffer);
|
||||
@ -337,7 +337,7 @@ pm_serialize_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const
|
||||
PRISM_EXPORTED_FUNCTION void
|
||||
pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data) {
|
||||
pm_options_t options = { 0 };
|
||||
if (data != NULL) pm_options_read(&options, data);
|
||||
pm_options_read(&options, data);
|
||||
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, source, size, &options);
|
||||
|
||||
@ -151,6 +151,15 @@ pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a 32-bit signed integer to the buffer as a variable-length integer.
|
||||
*/
|
||||
void
|
||||
pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value) {
|
||||
uint32_t unsigned_int = ((uint32_t)(value) << 1) ^ ((uint32_t)(value >> 31));
|
||||
pm_buffer_append_varuint(buffer, unsigned_int);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate one buffer onto another.
|
||||
*/
|
||||
|
||||
@ -120,6 +120,14 @@ void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value);
|
||||
*/
|
||||
void pm_buffer_append_varuint(pm_buffer_t *buffer, uint32_t value);
|
||||
|
||||
/**
|
||||
* Append a 32-bit signed integer to the buffer as a variable-length integer.
|
||||
*
|
||||
* @param buffer The buffer to append to.
|
||||
* @param value The integer to append.
|
||||
*/
|
||||
void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value);
|
||||
|
||||
/**
|
||||
* Concatenate one buffer onto another.
|
||||
*
|
||||
|
||||
@ -46,6 +46,22 @@ module Prism
|
||||
assert_equal filepath, find_source_file_node(result.value).filepath
|
||||
end
|
||||
|
||||
def test_parse_takes_line
|
||||
line = 4
|
||||
result = Prism.parse("def foo\n __FILE__\nend", line: line)
|
||||
|
||||
assert_equal line, result.value.location.start_line
|
||||
assert_equal line + 1, find_source_file_node(result.value).location.start_line
|
||||
end
|
||||
|
||||
def test_parse_takes_negative_lines
|
||||
line = -2
|
||||
result = Prism.parse("def foo\n __FILE__\nend", line: line)
|
||||
|
||||
assert_equal line, result.value.location.start_line
|
||||
assert_equal line + 1, find_source_file_node(result.value).location.start_line
|
||||
end
|
||||
|
||||
def test_parse_lex
|
||||
node, tokens = Prism.parse_lex("def foo; end").value
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user