Commit b761813b authored by Tom Niget's avatar Tom Niget

Start adding proper error handling infrastructure

parent 50a42e46
......@@ -26,7 +26,7 @@ def run_tests():
with open(path, "r", encoding="utf-8") as f:
code = f.read()
execute = "# norun" not in code
res = format_code(transpile(code))
res = format_code(transpile(code, path.name, path))
#print(res)
name_cpp = path.with_suffix('.cpp')
with open(name_cpp, "w", encoding="utf-8") as fcpp:
......
# coding: utf-8
import ast
import builtins
import inspect
from transpiler.consts import MAPPINGS
from transpiler.phases.desugar_with import DesugarWith
......@@ -13,18 +15,30 @@ import sys
from colorama import Fore
import colorama
from transpiler.utils import highlight
colorama.init()
def exception_hook(exc_type, exc_value, tb):
print = lambda *args, **kwargs: builtins.print(*args, **kwargs, file=sys.stderr)
last_node = None
last_file = None
while tb:
local_vars = tb.tb_frame.f_locals
name = tb.tb_frame.f_code.co_name
if name == "transpile":
last_file = local_vars["path"]
if name == "visit" and (node := local_vars["node"]) and isinstance(node, ast.AST):
last_node = node
if local_vars.get("TB_SKIP", None) and tb.tb_next:
tb = tb.tb_next
continue
filename = tb.tb_frame.f_code.co_filename
name = tb.tb_frame.f_code.co_name
line_no = tb.tb_lineno
print(f"{Fore.RED}File \"{filename}\", line {line_no}, in {name}", end="")
......@@ -34,13 +48,18 @@ def exception_hook(exc_type, exc_value, tb):
print()
tb = tb.tb_next
# Exception type and value
print(f"{exc_type.__name__}, Message: {exc_value}")
if last_node is not None:
print(f"In file \"{Fore.RESET}{last_file}{Fore.RED}\", line {last_node.lineno}")
print("\t" + highlight(ast.unparse(last_node)))
print(f"{Fore.RED}Error:{Fore.RESET} {exc_value}")
print(inspect.cleandoc(exc_value.detail(last_node)))
sys.excepthook = exception_hook
def transpile(source):
def transpile(source, name="<module>", path=None):
TB = f"transpiling module {Fore.RESET}{name}"
res = ast.parse(source, type_comments=True)
#res = initial_pytype.run(source, res)
res = DesugarWith().visit(res)
......
import ast
from abc import ABC
class CompileError(Exception, ABC):
def detail(self, last_node: ast.AST = None) -> str:
return ""
......@@ -7,6 +7,7 @@ from typing import Iterable
from transpiler.phases.emit_cpp.consts import MAPPINGS
from transpiler.phases.typing import TypeVariable
from transpiler.phases.typing.exceptions import UnresolvedTypeVariableError
from transpiler.phases.typing.types import BaseType, TY_INT, TY_BOOL, TY_NONE, Promise, PromiseKind, TY_STR, UserType, \
TypeType, TypeOperator, TY_FLOAT
from transpiler.utils import UnsupportedNodeError, highlight
......@@ -88,7 +89,7 @@ class NodeVisitor(UniversalVisitor):
yield ">"
elif isinstance(node, TypeVariable):
#yield f"TYPEVAR_{node.name}";return
raise NotImplementedError(f"Not unified type variable {node}")
raise UnresolvedTypeVariableError(node)
elif isinstance(node, TypeOperator):
yield "Py" + node.name.title()
if node.args:
......
import ast
from dataclasses import dataclass
from transpiler.utils import highlight
from transpiler.exceptions import CompileError
from transpiler.phases.typing import TypeVariable
@dataclass
class UnresolvedTypeVariableError(CompileError):
variable: TypeVariable
def __str__(self) -> str:
return f"Unresolved type variable: {self.variable}"
def detail(self, last_node: ast.AST = None) -> str:
if isinstance(last_node, (ast.Import, ast.ImportFrom)):
return f"""
This indicates the compiler was unable to infer the type of a function in a module.
Currently, Typon cannot determine the type of Python functions imported from other modules, except
for the standard library.
As such, you need to give enough information to the compiler to infer the type of the function.
For example:
vvv this tells the compiler that {highlight('math.factorial')} returns an {highlight('int')}
{highlight('res: int = math.factorial(5)')}"""
return """
This generally indicates the compiler was unable to infer the type of a variable or expression.
A common fix is to add a type annotation to the variable or function.
"""
......@@ -7,7 +7,7 @@ from typing import Union
from colorama import Fore
def highlight(code):
def highlight(code, full=False):
"""
Syntax highlights code as Python using colorama
"""
......@@ -21,6 +21,8 @@ def highlight(code):
from pygments.formatters import TerminalFormatter
items = pyg_highlight(code, PythonLexer(), TerminalFormatter()).splitlines()
if full:
return Fore.RESET + "\n".join(items)
res = items[0]
if len(items) > 1:
res += Fore.WHITE + " [...]"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment