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
28 changes: 15 additions & 13 deletions lib/lrama/command.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "stringio"

module Lrama
class Command
LRAMA_LIB = File.realpath(File.join(File.dirname(__FILE__)))
Expand Down Expand Up @@ -33,8 +35,8 @@ def execute_command_workflow
render_reports(states) if @options.report_file
@tracer.trace(grammar)
render_diagram(grammar)
render_output(context, grammar)
states.validate!(@logger)
render_output(context, grammar)
@warnings.warn(grammar, states)
end

Expand Down Expand Up @@ -103,18 +105,18 @@ def render_diagram(grammar)
end

def render_output(context, grammar)
File.open(@options.outfile, "w+") do |f|
Lrama::Output.new(
out: f,
output_file_path: @options.outfile,
template_name: @options.skeleton,
grammar_file_path: @options.grammar_file,
header_file_path: @options.header_file,
context: context,
grammar: grammar,
error_recovery: @options.error_recovery,
).render
end
out = StringIO.new
Lrama::Output.new(
out: out,
output_file_path: @options.outfile,
template_name: @options.skeleton,
grammar_file_path: @options.grammar_file,
header_file_path: @options.header_file,
context: context,
grammar: grammar,
error_recovery: @options.error_recovery,
).render
File.write(@options.outfile, out.string)
end
end
end
44 changes: 44 additions & 0 deletions spec/lrama/command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,49 @@
File.delete("report.output")
end
end

context "when conflicts do not match %expect" do
it "does not create the parser output" do
grammar = <<~Y
%expect 0
%token NUM
%%
expr: NUM | expr '+' expr;
Y

Dir.mktmpdir do |dir|
outfile = File.join(dir, "parse.c")
allow(STDIN).to receive(:read).and_return(grammar)
command = Lrama::Command.new(["-o", outfile, "-", "conflict.y"])
errors = StringIO.new
command.instance_variable_set(:@logger, Lrama::Logger.new(errors))

expect { command.run }.to raise_error(SystemExit)
expect(errors.string).to eq("error: shift/reduce conflicts: 1 found, 0 expected\n")
expect(File).not_to exist(outfile)
end
end
end

context "when rendering fails" do
it "preserves the existing parser output" do
Dir.mktmpdir do |dir|
outfile = File.join(dir, "parse.c")
File.write(outfile, "existing output")
command = Lrama::Command.new(["-o", outfile, fixture_path("command/basic.y")])
allow(Lrama::Output).to receive(:new) do |out:, **|
output = instance_double(Lrama::Output)
allow(output).to receive(:render) do
out << "partial output"
raise "render failed"
end
output
end

expect { command.run }.to raise_error("render failed")
expect(File.read(outfile)).to eq("existing output")
end
end
end
end
end