Skip to content

Commit

Permalink
Initialize the Prism::Source directly with all 3 fields for the C ext…
Browse files Browse the repository at this point in the history
…ension

* 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
  • Loading branch information
eregon authored and matzbot committed Feb 14, 2024
1 parent 1b2708b commit c2d8d6e
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 18 deletions.
6 changes: 3 additions & 3 deletions lib/prism/parse_result.rb
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions prism/extension.c
Expand Up @@ -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,
Expand All @@ -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) {
Expand Down
1 change: 0 additions & 1 deletion prism/extension.h
Expand Up @@ -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);

Expand Down
14 changes: 3 additions & 11 deletions prism/templates/ext/prism/api_node.c.erb
Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions test/prism/parse_test.rb
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit c2d8d6e

Please sign in to comment.