mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-compiler: preserve line number across multi-file boundary
When mrbc compiles multiple input files (e.g. `mrbc -g -o out.mrb a.rb b.rb`), the bison parser's one-token lookahead can buffer the final token of one file before partial_hook switches to the next. By the time bison reduces that token into an AST node, `mrb_parser_set_filename` has already reset `p->lineno` to 0, so init_var_header recorded lineno=0 for the previous file's last statement and codegen propagated the previous instruction's line. Save the lineno into `prev_file_lineno` immediately before the reset so init_var_header can restore the correct value when it detects the lookahead edge case (lineno==0 && filename_index>0). close #1316 Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -134,6 +134,7 @@ struct mrb_parser_state {
|
||||
mrb_sym* filename_table;
|
||||
uint16_t filename_table_length;
|
||||
uint16_t current_filename_index;
|
||||
uint16_t prev_file_lineno; /* saved lineno before partial_hook file switch */
|
||||
|
||||
/* Variable-sized node management */
|
||||
mrb_ast_node *nvars;
|
||||
|
||||
@@ -28,3 +28,20 @@ assert('embedded document with invalid terminator') do
|
||||
assert_equal "#{a.path}:3:0: embedded document meets end of file", result.chomp
|
||||
assert_equal 1, $?.exitstatus
|
||||
end
|
||||
|
||||
assert('debug info preserves line/filename across multiple inputs. #1316') do
|
||||
a = Tempfile.new(['a', '.rb'])
|
||||
b = Tempfile.new(['b', '.rb'])
|
||||
out = Tempfile.new(['out', '.mrb'])
|
||||
a.write("# line 1\n# line 2\nputs \"from a\"\n# line 4\nundefined_in_a\n")
|
||||
a.flush
|
||||
b.write("# b line 1\nputs \"from b\"\n")
|
||||
b.flush
|
||||
`#{cmd('mrbc')} -g -o #{out.path} #{a.path} #{b.path}`
|
||||
assert_equal 0, $?.exitstatus
|
||||
result = `#{cmd('mruby')} -b #{out.path} 2>&1`
|
||||
# Error should point at a.rb line 5 (the `undefined_in_a` line),
|
||||
# not b.rb or a different line within a.rb.
|
||||
assert_include result, "#{a.path}:5:"
|
||||
assert_not_include result, b.path
|
||||
end
|
||||
|
||||
@@ -151,9 +151,13 @@ init_var_header(struct mrb_ast_var_header *header, parser_state *p, enum node_ty
|
||||
header->filename_index = p->current_filename_index;
|
||||
header->node_type = (uint8_t)type;
|
||||
|
||||
/* Handle file boundary edge case */
|
||||
/* Handle file boundary edge case: this node is reduced from a token that
|
||||
was buffered by bison lookahead before partial_hook switched the file,
|
||||
so attribute it to the previous file at its last known lineno rather
|
||||
than the new file at lineno=0. */
|
||||
if (p->lineno == 0 && p->current_filename_index > 0) {
|
||||
header->filename_index--;
|
||||
header->lineno = p->prev_file_lineno;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7658,6 +7662,10 @@ mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
|
||||
|
||||
sym = mrb_intern_cstr(p->mrb, f);
|
||||
p->filename_sym = sym;
|
||||
/* Save current lineno so that AST nodes produced from a bison lookahead
|
||||
across the file boundary (in partial_hook) can recover the correct
|
||||
line in init_var_header instead of recording lineno=0. */
|
||||
p->prev_file_lineno = p->lineno;
|
||||
p->lineno = (p->filename_table_length > 0)? 0 : 1;
|
||||
|
||||
for (i = 0; i < p->filename_table_length; i++) {
|
||||
|
||||
+1262
-1254
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user