From c2d8d6eba6a1c9e51c2f2ae136e92468c6841472 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 14 Feb 2024 13:43:32 +0100 Subject: [PATCH] Initialize the Prism::Source directly with all 3 fields for the C extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Faster that way: $ ruby -Ilib -rprism -rbenchmark/ips -e 'Benchmark.ips { |x| x.report("parse") { Prism.parse("1 + 2") } }' 195.722k (± 0.5%) i/s rb_iv_set(): 179.609k (± 0.5%) i/s rb_funcall(): 190.030k (± 0.3%) i/s before this PR: 183.319k (± 0.4%) i/s --- lib/prism/parse_result.rb | 6 +++--- prism/extension.c | 10 +++++++--- prism/extension.h | 1 - prism/templates/ext/prism/api_node.c.erb | 14 +++----------- test/prism/parse_test.rb | 6 ++++++ 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index a3f588bb20a67e..bcebc1a4377bbf 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -15,10 +15,10 @@ class Source attr_reader :offsets # Create a new source object with the given source code. - def initialize(source) + def initialize(source, start_line = 1, offsets = []) @source = source - @start_line = 1 # set after parsing is done - @offsets = [] # set after parsing is done + @start_line = start_line # set after parsing is done + @offsets = offsets # set after parsing is done end # Perform a byteslice on the source code using the given byte offset and diff --git a/prism/extension.c b/prism/extension.c index 5ea6f57ca5939c..cf3c7edca5e88a 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -543,8 +543,9 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod pm_parser_register_encoding_changed_callback(&parser, parse_lex_encoding_changed_callback); VALUE source_string = rb_str_new((const char *) pm_string_source(input), pm_string_length(input)); - VALUE source_argv[] = { source_string }; - VALUE source = rb_class_new_instance(1, source_argv, rb_cPrismSource); + VALUE offsets = rb_ary_new(); + VALUE source_argv[] = { source_string, LONG2NUM(parser.start_line), offsets }; + VALUE source = rb_class_new_instance(3, source_argv, rb_cPrismSource); parse_lex_data_t parse_lex_data = { .source = source, @@ -567,7 +568,10 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod // it over to all of the tokens, and both of these are only set after pm_parse(). rb_encoding *encoding = rb_enc_find(parser.encoding->name); rb_enc_associate(source_string, encoding); - pm_source_init(source, &parser); + + for (size_t index = 0; index < parser.newline_list.size; index++) { + rb_ary_push(offsets, ULONG2NUM(parser.newline_list.offsets[index])); + } VALUE value; if (return_nodes) { diff --git a/prism/extension.h b/prism/extension.h index 83cb9f394277dd..2cf314e46fd2d4 100644 --- a/prism/extension.h +++ b/prism/extension.h @@ -8,7 +8,6 @@ #include "prism.h" VALUE pm_source_new(pm_parser_t *parser, rb_encoding *encoding); -void pm_source_init(VALUE source, pm_parser_t *parser); VALUE pm_token_new(pm_parser_t *parser, pm_token_t *token, rb_encoding *encoding, VALUE source); VALUE pm_ast_new(pm_parser_t *parser, pm_node_t *node, rb_encoding *encoding, VALUE source); diff --git a/prism/templates/ext/prism/api_node.c.erb b/prism/templates/ext/prism/api_node.c.erb index b4a9d28cf7d117..f52d537dbcbe54 100644 --- a/prism/templates/ext/prism/api_node.c.erb +++ b/prism/templates/ext/prism/api_node.c.erb @@ -40,22 +40,14 @@ pm_string_new(pm_string_t *string, rb_encoding *encoding) { VALUE pm_source_new(pm_parser_t *parser, rb_encoding *encoding) { VALUE source_string = rb_enc_str_new((const char *) parser->start, parser->end - parser->start, encoding); - VALUE source_argv[] = { source_string }; - VALUE source = rb_class_new_instance(1, source_argv, rb_cPrismSource); - - pm_source_init(source, parser); - return source; -} - -void -pm_source_init(VALUE source, pm_parser_t *parser) { - rb_iv_set(source, "@start_line", LONG2NUM(parser->start_line)); VALUE offsets = rb_ary_new_capa(parser->newline_list.size); for (size_t index = 0; index < parser->newline_list.size; index++) { rb_ary_push(offsets, ULONG2NUM(parser->newline_list.offsets[index])); } - rb_iv_set(source, "@offsets", offsets); + + VALUE source_argv[] = { source_string, LONG2NUM(parser->start_line), offsets }; + return rb_class_new_instance(3, source_argv, rb_cPrismSource); } typedef struct pm_node_stack_node { diff --git a/test/prism/parse_test.rb b/test/prism/parse_test.rb index 3a2bc3716f328f..574a1c1714f8d1 100644 --- a/test/prism/parse_test.rb +++ b/test/prism/parse_test.rb @@ -52,6 +52,9 @@ def test_parse_takes_line assert_equal line, result.value.location.start_line assert_equal line + 1, find_source_file_node(result.value).location.start_line + + result = Prism.parse_lex("def foo\n __FILE__\nend", line: line) + assert_equal line, result.value.first.location.start_line end def test_parse_takes_negative_lines @@ -60,6 +63,9 @@ def test_parse_takes_negative_lines assert_equal line, result.value.location.start_line assert_equal line + 1, find_source_file_node(result.value).location.start_line + + result = Prism.parse_lex("def foo\n __FILE__\nend", line: line) + assert_equal line, result.value.first.location.start_line end def test_parse_lex