1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-26 07:03:22 +00:00

Distinguish between all parsers passing and failing

Given an input like f(x), which is both a valid statement and
expression, both parsers would accept the whole input. However, this was
treated the same as both parsers rejecting the input, resulting in a
crash when trying to print the error.

We now return immediately when any parser accepts the input.

Fixes #1354
This commit is contained in:
Jonathan Coates 2023-03-04 10:29:52 +00:00
parent 111f971ed0
commit 1c120982a7
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
2 changed files with 32 additions and 5 deletions

View File

@ -120,22 +120,35 @@ local function parse_repl(input)
assert(coroutine.resume(parsers[i], context, coroutine.yield, start_code))
end
-- Run all parsers together in parallel, feeding them one token at a time.
-- Once all parsers have failed, report the last failure (corresponding to
-- the longest parse).
local ok, err = pcall(function()
local parsers_n = #parsers
while true do
local token, start, finish = lexer()
local stop = true
local all_failed = true
for i = 1, parsers_n do
local parser = parsers[i]
if coroutine.status(parser) ~= "dead" then
stop = false
if parser then
local ok, err = coroutine.resume(parser, token, start, finish)
if not ok and err ~= error_sentinel then error(err, 0) end
if ok then
-- This parser accepted our input, succeed immediately.
if coroutine.status(parser) == "dead" then return end
all_failed = false -- Otherwise continue parsing.
elseif err ~= error_sentinel then
-- An internal error occurred: propagate it.
error(err, 0)
else
-- The parser failed, stub it out so we don't try to continue using it.
parsers[i] = false
end
end
end
if stop then error(error_sentinel) end
if all_failed then error(error_sentinel) end
end
end)

View File

@ -49,4 +49,18 @@ describe("cc.internal.syntax", function()
describe_golden("the lexer", "lexer_spec.md", true)
describe_golden("the parser", "parser_spec.md", false)
describe_golden("the parser (all states)", "parser_exhaustive_spec.md", false)
describe("the REPL input parser", function()
it("returns true when accepted by both parsers", function()
helpers.with_window(50, 10, function()
expect(syntax.parse_repl("print(x)")):eq(true)
end)
end)
it("returns true when accepted by one parser", function()
helpers.with_window(50, 10, function()
expect(syntax.parse_repl("x")):eq(true)
end)
end)
end)
end)