mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +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:
		| @@ -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) | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates