From b6ee649458a39323dce40360b2df691a29a751cd Mon Sep 17 00:00:00 2001 From: James Westman Date: Sun, 25 Dec 2022 17:10:21 -0600 Subject: [PATCH] Simplify error & warning handling --- blueprintcompiler/ast_utils.py | 14 ++++++++++++- blueprintcompiler/interactive_port.py | 6 +++--- blueprintcompiler/lsp.py | 1 - blueprintcompiler/main.py | 6 +++--- blueprintcompiler/parser.py | 21 ++++++++++++------- tests/fuzz.py | 2 +- .../sample_errors/menu_toplevel_attribute.blp | 2 +- tests/test_samples.py | 7 +++---- 8 files changed, 38 insertions(+), 21 deletions(-) diff --git a/blueprintcompiler/ast_utils.py b/blueprintcompiler/ast_utils.py index e4f2efa..16298ae 100644 --- a/blueprintcompiler/ast_utils.py +++ b/blueprintcompiler/ast_utils.py @@ -79,7 +79,19 @@ class AstNode: @cached_property def errors(self): - return list(self._get_errors()) + return list( + error + for error in self._get_errors() + if not isinstance(error, CompileWarning) + ) + + @cached_property + def warnings(self): + return list( + warning + for warning in self._get_errors() + if isinstance(warning, CompileWarning) + ) def _get_errors(self): for validator in self.validators: diff --git a/blueprintcompiler/interactive_port.py b/blueprintcompiler/interactive_port.py index dd00317..ddb5e28 100644 --- a/blueprintcompiler/interactive_port.py +++ b/blueprintcompiler/interactive_port.py @@ -24,7 +24,7 @@ import os from . import decompiler, tokenizer, parser from .outputs.xml import XmlOutput -from .errors import MultipleErrors, PrintableError +from .errors import MultipleErrors, PrintableError, CompilerBugError from .utils import Colors @@ -57,8 +57,8 @@ def decompile_file(in_file, out_file) -> T.Union[str, CouldNotPort]: if errors: raise errors - if len(ast.errors): - raise MultipleErrors(ast.errors) + if not ast: + raise CompilerBugError() output = XmlOutput() output.emit(ast) diff --git a/blueprintcompiler/lsp.py b/blueprintcompiler/lsp.py index f579ab4..890eff0 100644 --- a/blueprintcompiler/lsp.py +++ b/blueprintcompiler/lsp.py @@ -75,7 +75,6 @@ class OpenFile: self.diagnostics += warnings if errors is not None: self.diagnostics += errors.errors - self.diagnostics += self.ast.errors except MultipleErrors as e: self.diagnostics += e.errors except CompileError as e: diff --git a/blueprintcompiler/main.py b/blueprintcompiler/main.py index a3a70a2..345f430 100644 --- a/blueprintcompiler/main.py +++ b/blueprintcompiler/main.py @@ -21,7 +21,7 @@ import typing as T import argparse, json, os, sys -from .errors import PrintableError, report_bug, MultipleErrors +from .errors import PrintableError, report_bug, MultipleErrors, CompilerBugError from .lsp import LanguageServer from . import parser, tokenizer, decompiler, interactive_port from .utils import Colors @@ -149,8 +149,8 @@ class BlueprintApp: if errors: raise errors - if len(ast.errors): - raise MultipleErrors(ast.errors) + if ast is None: + raise CompilerBugError() formatter = XmlOutput() diff --git a/blueprintcompiler/parser.py b/blueprintcompiler/parser.py index 12c893a..a44f709 100644 --- a/blueprintcompiler/parser.py +++ b/blueprintcompiler/parser.py @@ -24,14 +24,21 @@ from .tokenizer import TokenType from .language import OBJECT_CONTENT_HOOKS, VALUE_HOOKS, Template, UI -def parse(tokens) -> T.Tuple[UI, T.Optional[MultipleErrors], T.List[PrintableError]]: +def parse( + tokens: T.List[Token], +) -> T.Tuple[T.Optional[UI], T.Optional[MultipleErrors], T.List[PrintableError]]: """Parses a list of tokens into an abstract syntax tree.""" - ctx = ParseContext(tokens) - AnyOf(UI).parse(ctx) + try: + ctx = ParseContext(tokens) + AnyOf(UI).parse(ctx) + ast_node = ctx.last_group.to_ast() if ctx.last_group else None - ast_node = ctx.last_group.to_ast() if ctx.last_group else None - errors = MultipleErrors(ctx.errors) if len(ctx.errors) else None - warnings = ctx.warnings + errors = [*ctx.errors, *ast_node.errors] + warnings = [*ctx.warnings, *ast_node.warnings] - return (ast_node, errors, warnings) + return (ast_node, MultipleErrors(errors) if len(errors) else None, warnings) + except MultipleErrors as e: + return (None, e, []) + except CompileError as e: + return (None, MultipleErrors([e]), []) diff --git a/tests/fuzz.py b/tests/fuzz.py index 0f6a1a7..ad1c764 100644 --- a/tests/fuzz.py +++ b/tests/fuzz.py @@ -26,7 +26,7 @@ def fuzz(buf): ast, errors, warnings = parser.parse(tokens) xml = XmlOutput() - if errors is None and len(ast.errors) == 0: + if errors is None and ast is not None: xml.emit(ast) except CompilerBugError as e: raise e diff --git a/tests/sample_errors/menu_toplevel_attribute.blp b/tests/sample_errors/menu_toplevel_attribute.blp index 21ceeff..e9923c2 100644 --- a/tests/sample_errors/menu_toplevel_attribute.blp +++ b/tests/sample_errors/menu_toplevel_attribute.blp @@ -1,5 +1,5 @@ using Gtk 4.0; -menu { +menu menu { not-allowed: true; } \ No newline at end of file diff --git a/tests/test_samples.py b/tests/test_samples.py index 6f8a4eb..e9e7697 100644 --- a/tests/test_samples.py +++ b/tests/test_samples.py @@ -57,8 +57,6 @@ class TestSamples(unittest.TestCase): if errors: raise errors - if len(ast.errors): - raise MultipleErrors(ast.errors) if len(warnings): raise MultipleErrors(warnings) @@ -94,8 +92,9 @@ class TestSamples(unittest.TestCase): tokens = tokenizer.tokenize(blueprint) ast, errors, warnings = parser.parse(tokens) - self.assert_docs_dont_crash(blueprint, ast) - self.assert_completions_dont_crash(blueprint, ast, tokens) + if ast is not None: + self.assert_docs_dont_crash(blueprint, ast) + self.assert_completions_dont_crash(blueprint, ast, tokens) if errors: raise errors