Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions lib/racc/grammarfileparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def _add_many_rule(prev)
return target if target
target = _gen_target_name("many", prev)
@many_rule_registry[prev.to_s] = target
src = SourceText.new("result = val[1] ? val[1].unshift(val[0]) : val", @filename, @scanner.lineno + 1)
src = SourceText.new(_many_action_code, @filename, @scanner.lineno + 1)
act = UserAction.source_text(src)
@grammar.add Rule.new(target, [], act)
@grammar.add Rule.new(target, [prev, target], act)
Expand All @@ -308,13 +308,29 @@ def _add_many1_rule(prev)
return target if target
target = _gen_target_name("many1", prev)
@many1_rule_registry[prev.to_s] = target
src = SourceText.new("result = val[1] ? val[1].unshift(val[0]) : val", @filename, @scanner.lineno + 1)
src = SourceText.new(_many_action_code, @filename, @scanner.lineno + 1)
act = UserAction.source_text(src)
@grammar.add Rule.new(target, [prev], act)
@grammar.add Rule.new(target, [prev, target], act)
target
end

def _many_action_code
if @result.params.result_var?
"result = val[1] ? val[1].unshift(val[0]) : val"
else
"val[1] ? val[1].unshift(val[0]) : val"
end
end

def _group_action_code
if @result.params.result_var?
"result = val"
else
"val"
end
end

def _add_group_rule(enum)
target = @grammar.intern("-temp-group", true)
rules, _ = _add_rule_block(target, enum)
Expand All @@ -323,7 +339,7 @@ def _add_group_rule(enum)
unless target = @group_rule_registry[target_name]
target = @grammar.intern("-group@#{target_name}", true)
@group_rule_registry[target_name] = target
src = SourceText.new("result = val", @filename, @scanner.lineno + 1)
src = SourceText.new(_group_action_code, @filename, @scanner.lineno + 1)
act = UserAction.source_text(src)
rules.each do |syms, sprec|
rule = Rule.new(target, syms, act)
Expand Down
112 changes: 112 additions & 0 deletions test/test_grammar_file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,117 @@ def test_parse
parser = Racc::GrammarFileParser.new(debug_flags)
parser.parse(File.read(file), File.basename(file))
end

def test_no_result_var_with_many_operator
grammar_source = <<~GRAMMAR
class TestParser
options no_result_var

rule
root
: 'a' 'b'*
GRAMMAR

debug_flags = Racc::DebugFlags.parse_option_string('')
parser = Racc::GrammarFileParser.new(debug_flags)
result = parser.parse(grammar_source, 'test.y')

assert_equal false, result.params.result_var?

actions = result.grammar.each_rule.map { |rule| rule.action.source&.text }.compact
actions.each do |action|
refute_match(/\Aresult\s*=/, action, "Action should not start with 'result =' when no_result_var is set")
end
end

def test_no_result_var_with_many1_operator
grammar_source = <<~GRAMMAR
class TestParser
options no_result_var

rule
root
: 'a' 'b'+
GRAMMAR

debug_flags = Racc::DebugFlags.parse_option_string('')
parser = Racc::GrammarFileParser.new(debug_flags)
result = parser.parse(grammar_source, 'test.y')

assert_equal false, result.params.result_var?

actions = result.grammar.each_rule.map { |rule| rule.action.source&.text }.compact
actions.each do |action|
refute_match(/\Aresult\s*=/, action, "Action should not start with 'result =' when no_result_var is set")
end
end

def test_no_result_var_with_group_operator
grammar_source = <<~GRAMMAR
class TestParser
options no_result_var

rule
root
: ('a' | 'b')
GRAMMAR

debug_flags = Racc::DebugFlags.parse_option_string('')
parser = Racc::GrammarFileParser.new(debug_flags)
result = parser.parse(grammar_source, 'test.y')

assert_equal false, result.params.result_var?

actions = result.grammar.each_rule.map { |rule| rule.action.source&.text }.compact
actions.each do |action|
refute_match(/\Aresult\s*=/, action, "Action should not start with 'result =' when no_result_var is set")
end
end

def test_result_var_with_many_operator
grammar_source = <<~GRAMMAR
class TestParser

rule
root
: 'a' 'b'*
GRAMMAR

debug_flags = Racc::DebugFlags.parse_option_string('')
parser = Racc::GrammarFileParser.new(debug_flags)
result = parser.parse(grammar_source, 'test.y')

assert_equal true, result.params.result_var?

actions = result.grammar.each_rule.map { |rule| rule.action.source&.text }.compact.reject(&:empty?)
assert actions.any? { |action| action.match?(/\Aresult\s*=/) }, "Action should start with 'result =' when result_var is enabled"
end

def test_no_result_var_no_warnings
grammar_file = Tempfile.new(['test_no_result_var', '.y'])
grammar_file.write(<<~GRAMMAR)
class TestParser
options no_result_var

rule
root
: 'a' 'b'*
| 'c' 'd'+
| ('e' | 'f')
GRAMMAR
grammar_file.close

output_file = Tempfile.new(['test_no_result_var', '.rb'])
output_file.close

system("ruby", "-I#{LIB_DIR}", "-S", RACC, "-o", output_file.path, grammar_file.path)
assert $?.success?, "racc command failed"

warnings = `ruby -W #{output_file.path} 2>&1`
assert_equal "", warnings, "Expected no warnings but got: #{warnings}"
ensure
grammar_file&.unlink
output_file&.unlink
end
end
end