Add comments around user code blocks to generated Rust module
This takes the place of #line directives
This commit is contained in:
parent
3626bc2caf
commit
7fd1505710
@ -695,10 +695,21 @@ generated output without any surrounding `#line` directives.
|
|||||||
This can be useful when debugging the generated parser itself, or when the
|
This can be useful when debugging the generated parser itself, or when the
|
||||||
`#line` directives interfere with other tooling.
|
`#line` directives interfere with other tooling.
|
||||||
|
|
||||||
The `noline` statement only affects the C, C++, and D targets.
|
Rust has no `#line` directive equivalent.
|
||||||
Rust has no `#line` directive equivalent, so `#line` directives are never
|
For a Rust target, Propane instead emits a comment before and after each
|
||||||
emitted into Rust output and the `noline` statement has no effect for the Rust
|
section of user code naming the grammar file and the line number the code was
|
||||||
target.
|
taken from:
|
||||||
|
|
||||||
|
```
|
||||||
|
/* Begin user code from myparser.propane line 42. */
|
||||||
|
let mut v: i64 = 0;
|
||||||
|
/* End user code from myparser.propane line 42. */
|
||||||
|
```
|
||||||
|
|
||||||
|
A compiler diagnostic that points into the generated Rust module can be traced
|
||||||
|
back to the grammar by reading up to the nearest such comment.
|
||||||
|
The `noline` statement suppresses these comments for a Rust target, in the same
|
||||||
|
way that it suppresses `#line` directives for the other targets.
|
||||||
|
|
||||||
##> `on_tree_node` statement - custom initialization of a token tree node
|
##> `on_tree_node` statement - custom initialization of a token tree node
|
||||||
|
|
||||||
|
|||||||
@ -41,12 +41,23 @@ class Propane
|
|||||||
output_file = @output_file
|
output_file = @output_file
|
||||||
end
|
end
|
||||||
erb = ERB.new(template, trim_mode: "<>")
|
erb = ERB.new(template, trim_mode: "<>")
|
||||||
|
# Rust has no #line directive support. For a Rust target the directives
|
||||||
|
# that the grammar embeds around user code blocks are replaced with
|
||||||
|
# comments naming the grammar file and line number the code came from,
|
||||||
|
# so that the origin of a section of user code can still be found by
|
||||||
|
# reading up from a compiler diagnostic pointing into the generated
|
||||||
|
# module.
|
||||||
|
user_code_origin = nil
|
||||||
result = erb.result(binding.clone).lines.each_with_index.map do |line, i|
|
result = erb.result(binding.clone).lines.each_with_index.map do |line, i|
|
||||||
if @language == "rust"
|
if @language == "rust"
|
||||||
# Rust has no #line directive support, so strip the directives that
|
if md = line.match(/^#line (\d+) "([^"]*)"/)
|
||||||
# the grammar embeds in user code blocks.
|
user_code_origin = "#{md[2]} line #{md[1]}"
|
||||||
line = line.sub(/^#line \d+ "[^"]*"/, "")
|
line.sub(/^#line \d+ "[^"]*"/, %[/* Begin user code from #{user_code_origin}. */])
|
||||||
line == "#linereset\n" ? "" : line
|
elsif line == "#linereset\n"
|
||||||
|
%[/* End user code from #{user_code_origin}. */\n]
|
||||||
|
else
|
||||||
|
line
|
||||||
|
end
|
||||||
elsif line == "#linereset\n"
|
elsif line == "#linereset\n"
|
||||||
%[#line #{i + 2} "#{output_file}"\n]
|
%[#line #{i + 2} "#{output_file}"\n]
|
||||||
else
|
else
|
||||||
|
|||||||
@ -2113,6 +2113,44 @@ EOF
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if language == "rust"
|
||||||
|
it "marks user code sections with their grammar file and line number" do
|
||||||
|
write_grammar <<EOF
|
||||||
|
ptype i64;
|
||||||
|
drop /\\s+/;
|
||||||
|
token num /\\d+/ <<
|
||||||
|
$$ = 42;
|
||||||
|
>>
|
||||||
|
Start -> num << $$ = $1; >>
|
||||||
|
EOF
|
||||||
|
run_propane(language: language)
|
||||||
|
parser = File.binread("spec/run/testparser.rs")
|
||||||
|
# The lexer code block body begins on grammar line 4 and the parser
|
||||||
|
# rule code block is on grammar line 6.
|
||||||
|
expect(parser).to include %[/* Begin user code from spec/run/testparser.propane line 4. */]
|
||||||
|
expect(parser).to include %[/* End user code from spec/run/testparser.propane line 4. */]
|
||||||
|
expect(parser).to include %[/* Begin user code from spec/run/testparser.propane line 6. */]
|
||||||
|
expect(parser).to include %[/* End user code from spec/run/testparser.propane line 6. */]
|
||||||
|
expect(parser).to_not include "#line"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "omits user code section markers when noline is specified" do
|
||||||
|
write_grammar <<EOF
|
||||||
|
noline;
|
||||||
|
ptype i64;
|
||||||
|
drop /\\s+/;
|
||||||
|
token num /\\d+/ <<
|
||||||
|
$$ = 42;
|
||||||
|
>>
|
||||||
|
Start -> num << $$ = $1; >>
|
||||||
|
EOF
|
||||||
|
run_propane(language: language)
|
||||||
|
parser = File.binread("spec/run/testparser.rs")
|
||||||
|
expect(parser).to_not include "user code from"
|
||||||
|
expect(parser).to_not include "#line"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "executes code blocks associated with drop statements" do
|
it "executes code blocks associated with drop statements" do
|
||||||
if language == "rust"
|
if language == "rust"
|
||||||
write_grammar <<EOF
|
write_grammar <<EOF
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user