Scored results

This commit is contained in:
John Doty 2024-06-06 17:09:14 -07:00
parent 07164d51a0
commit 973445a8d8

View file

@ -63,6 +63,7 @@ class ParseError:
class StopResult: class StopResult:
result: Tree | None result: Tree | None
errors: list[ParseError] errors: list[ParseError]
score: int
@dataclass @dataclass
@ -80,6 +81,7 @@ class ParserThread:
table: parser.ParseTable table: parser.ParseTable
stack: list[typing.Tuple[int, TokenValue | Tree | None]] stack: list[typing.Tuple[int, TokenValue | Tree | None]]
errors: list[ParseError] errors: list[ParseError]
score: int
def __init__(self, id, trace, table, stack): def __init__(self, id, trace, table, stack):
self.id = id self.id = id
@ -87,6 +89,7 @@ class ParserThread:
self.table = table self.table = table
self.stack = stack self.stack = stack
self.errors = [] self.errors = []
self.score = 0
def step(self, current_token: TokenValue) -> StepResult: def step(self, current_token: TokenValue) -> StepResult:
stack = self.stack stack = self.stack
@ -103,7 +106,7 @@ class ParserThread:
case parser.Accept(): case parser.Accept():
result = stack[-1][1] result = stack[-1][1]
assert isinstance(result, Tree) assert isinstance(result, Tree)
return StopResult(result, self.errors) return StopResult(result, self.errors, self.score)
case parser.Reduce(name=name, count=size, transparent=transparent): case parser.Reduce(name=name, count=size, transparent=transparent):
children: list[TokenValue | Tree] = [] children: list[TokenValue | Tree] = []
@ -134,7 +137,7 @@ class ParserThread:
case parser.Error(): case parser.Error():
if current_token.kind == "$": if current_token.kind == "$":
message = "Unexpected end of file" message = "Syntax error: Unexpected end of file"
else: else:
message = f"Syntax error: unexpected symbol {current_token.kind}" message = f"Syntax error: unexpected symbol {current_token.kind}"
@ -144,7 +147,7 @@ class ParserThread:
) )
) )
# TODO: Error Recovery Here # TODO: Error Recovery Here
return StopResult(None, self.errors) return StopResult(None, self.errors, self.score)
case _: case _:
raise ValueError(f"Unknown action type: {action}") raise ValueError(f"Unknown action type: {action}")
@ -164,7 +167,7 @@ def parse(table: parser.ParseTable, tokens, trace=None) -> typing.Tuple[Tree | N
threads = [ threads = [
ParserThread(0, trace, table, [(0, None)]), ParserThread(0, trace, table, [(0, None)]),
] ]
results: list[typing.Tuple[ParserThread, Tree | None, list[ParseError]]] = [] results: list[StopResult] = []
while len(threads) > 0: while len(threads) > 0:
current_token = input[input_index] current_token = input[input_index]
@ -172,11 +175,12 @@ def parse(table: parser.ParseTable, tokens, trace=None) -> typing.Tuple[Tree | N
for thread in threads: for thread in threads:
sr = thread.step(current_token) sr = thread.step(current_token)
match sr: match sr:
case StopResult(value, errors): case StopResult():
results.append((thread, value, errors)) results.append(sr)
break break
case ContinueResult(threads): case ContinueResult(threads):
assert len(threads) > 0
next_threads.extend(threads) next_threads.extend(threads)
break break
@ -187,12 +191,12 @@ def parse(table: parser.ParseTable, tokens, trace=None) -> typing.Tuple[Tree | N
threads = next_threads threads = next_threads
input_index += 1 input_index += 1
# TODO: Score results and whatnot, pick the best one.
assert len(results) > 0 assert len(results) > 0
_, result, errors = results[0] results.sort(key=lambda x: x.score)
result = results[0]
error_strings = [] error_strings = []
for parse_error in errors: for parse_error in result.errors:
line_index = bisect.bisect_left(tokens.lines, parse_error.start) line_index = bisect.bisect_left(tokens.lines, parse_error.start)
if line_index == 0: if line_index == 0:
col_start = 0 col_start = 0
@ -203,7 +207,7 @@ def parse(table: parser.ParseTable, tokens, trace=None) -> typing.Tuple[Tree | N
error_strings.append(f"{line_index}:{column_index}: {parse_error.message}") error_strings.append(f"{line_index}:{column_index}: {parse_error.message}")
return (result, error_strings) return (result.result, error_strings)
############################################################################### ###############################################################################