Commit a0ec2949 authored by Tom Niget's avatar Tom Niget

Finish removing old error types

parent af3b9c3e
import sys
import math
x = [6]
x = 5
#x: str = "str"
y = "ab"
u = (math.abcd) # abcd
a = 5 if True else 3
def c(x: int):
return x
for v in 6:
g = 6
h = 7
i = 8
pass
if __name__ == "__main__":
pass
\ No newline at end of file
......@@ -5,7 +5,7 @@ import importlib
import inspect
import os
os.environ["TERM"] = "xterm-256"
#os.environ["TERM"] = "xterm-256"
import colorama
colorama.init()
......@@ -80,6 +80,10 @@ def exception_hook(exc_type, exc_value, tb):
old = hg[last_node.lineno - 1]
[start] = find_indices(old, [last_node.col_offset])
hg[last_node.lineno - 1] = old[:start] + "\x1b[4m" + old[start:]
for lineid in range(last_node.lineno, last_node.end_lineno - 1):
old = hg[lineid]
first_nonspace = len(old) - len(old.lstrip())
hg[lineid] = old[:first_nonspace] + "\x1b[4m" + old[first_nonspace:] + "\x1b[24m"
old = hg[last_node.end_lineno - 1]
first_nonspace = len(old) - len(old.lstrip())
[end] = find_indices(old, [last_node.end_col_offset])
......@@ -96,8 +100,10 @@ def exception_hook(exc_type, exc_value, tb):
print()
print(cf.red("Error:"), exc_value)
if isinstance(exc_value, CompileError):
detail = inspect.cleandoc(exc_value.detail(last_node))
if detail:
print()
print(inspect.cleandoc(exc_value.detail(last_node)))
print(detail)
print()
def find_indices(s, indices: list[int]) -> list[int]:
......
......@@ -9,7 +9,7 @@ from transpiler.phases.typing.common import ScoperVisitor
from transpiler.phases.typing.expr import ScoperExprVisitor
from transpiler.phases.typing.class_ import ScoperClassVisitor
from transpiler.phases.typing.scope import VarDecl, VarKind, ScopeKind, Scope
from transpiler.phases.typing.types import BaseType, TypeVariable, FunctionType, IncompatibleTypesError, \
from transpiler.phases.typing.types import BaseType, TypeVariable, FunctionType, \
Promise, TY_NONE, PromiseKind, TupleType, UserType, TypeType, ModuleType
from transpiler.phases.utils import PlainBlock
......@@ -40,7 +40,8 @@ class ScoperBlockVisitor(ScoperVisitor):
mod.type.is_python = True
self.scope.vars[name] = mod
if mod is None:
raise NameError(name)
from transpiler.phases.typing.exceptions import UnknownNameError
raise UnknownNameError(name)
assert isinstance(mod, VarDecl), mod
assert isinstance(mod.type, ModuleType), mod.type
return mod
......@@ -81,10 +82,7 @@ class ScoperBlockVisitor(ScoperVisitor):
raise NotImplementedError(node)
target = node.targets[0]
ty = self.get_type(node.value)
try:
node.is_declare = self.visit_assign_target(target, ty)
except IncompatibleTypesError as e:
raise IncompatibleTypesError(f"`{ast.unparse(node)}: {e}") from e
def visit_AnnAssign(self, node: ast.AnnAssign):
# if node.value is not None:
......@@ -116,8 +114,12 @@ class ScoperBlockVisitor(ScoperVisitor):
self.root_decls[target.id] = VarDecl(VarKind.OUTER_DECL, decl_val)
return True
elif isinstance(target, ast.Tuple):
if not (isinstance(decl_val, TupleType) and len(target.elts) == len(decl_val.args)):
raise IncompatibleTypesError(f"Cannot unpack {decl_val} into {target}")
if not isinstance(decl_val, TupleType):
from transpiler.phases.typing.exceptions import InvalidUnpackError
raise InvalidUnpackError(decl_val)
if len(target.elts) != len(decl_val.args):
from transpiler.phases.typing.exceptions import InvalidUnpackCountError
raise InvalidUnpackCountError(decl_val, len(target.elts))
decls = [self.visit_assign_target(t, ty) for t, ty in zip(target.elts, decl_val.args)] # eager evaluated
return any(decls)
elif isinstance(target, ast.Attribute):
......@@ -210,11 +212,13 @@ class ScoperBlockVisitor(ScoperVisitor):
try:
iter_type = seq_type.methods["__iter__"].return_type
except:
raise IncompatibleTypesError(f"{seq_type} is not iterable in `{ast.unparse(node.iter)}`")
from transpiler.phases.typing.exceptions import NotIterableError
raise NotIterableError(seq_type)
try:
next_type = iter_type.methods["__next__"].return_type
except:
raise IncompatibleTypesError(f"iter({iter_type}) is not an iterator")
from transpiler.phases.typing.exceptions import NotIteratorError
raise NotIteratorError(iter_type)
var_var.unify(next_type)
body_scope = scope.child(ScopeKind.FUNCTION_INNER)
body_visitor = ScoperBlockVisitor(body_scope, self.root_decls)
......@@ -228,7 +232,8 @@ class ScoperBlockVisitor(ScoperVisitor):
def visit_Return(self, node: ast.Return):
fct = self.scope.function
if fct is None:
raise IncompatibleTypesError("Return outside function")
from transpiler.phases.typing.exceptions import ReturnOutsideFunctionError
raise ReturnOutsideFunctionError()
ftype = fct.obj_type
assert isinstance(ftype, FunctionType)
vtype = self.expr().visit(node.value) if node.value else TY_NONE
......
......@@ -180,6 +180,7 @@ class UnknownNameError(CompileError):
For example:
{highlight('print(abcd)')}
{highlight('import foobar')}
"""
......@@ -198,3 +199,81 @@ class UnknownModuleMemberError(CompileError):
For example:
{highlight('from math import abcd')}
"""
@dataclass
class InvalidUnpackCountError(CompileError):
value: BaseType
count: int
def __str__(self) -> str:
return f"Invalid unpack: {highlight(self.value)} cannot be unpacked into {self.count} variables"
def detail(self, last_node: ast.AST = None) -> str:
return f"""
This indicates that an attempt was made to unpack a value that cannot be unpacked into the given number of
variables.
For example:
{highlight('a, b, c = 1, 2')}
"""
@dataclass
class InvalidUnpackError(CompileError):
value: BaseType
def __str__(self) -> str:
return f"Invalid unpack: {highlight(self.value)} cannot be unpacked"
def detail(self, last_node: ast.AST = None) -> str:
return f"""
This indicates that an attempt was made to unpack a value that cannot be unpacked.
For example:
{highlight('a, b, c = 1')}
Moreover, currently typon only supports unpacking tuples.
"""
@dataclass
class NotIterableError(CompileError):
value: BaseType
def __str__(self) -> str:
return f"Not iterable: {highlight(self.value)} is not iterable"
def detail(self, last_node: ast.AST = None) -> str:
return f"""
This indicates that an attempt was made to iterate over a value that is not iterable.
For example:
{highlight('for x in 1: ...')}
Iterable types must implement the Python {highlight('Iterable')} protocol, which requires the presence of a
{highlight('__iter__')} method.
"""
@dataclass
class NotIteratorError(CompileError):
value: BaseType
def __str__(self) -> str:
return f"Not iterator: {highlight(self.value)} is not an iterator"
def detail(self, last_node: ast.AST = None) -> str:
return f"""
This indicates that an attempt was made to iterate over a value that is not an iterator.
For example:
{highlight('x = next(5)')}
Iterator types must implement the Python {highlight('Iterator')} protocol, which requires the presence of a
{highlight('__next__')} method.
"""
@dataclass
class ReturnOutsideFunctionError(CompileError):
def __str__(self) -> str:
return f"{highlight('return')} cannot be used outside of a function"
def detail(self, last_node: ast.AST = None) -> str:
return ""
\ No newline at end of file
......@@ -5,7 +5,7 @@ from typing import List
from transpiler.phases.typing import ScopeKind, VarDecl, VarKind
from transpiler.phases.typing.common import ScoperVisitor
from transpiler.phases.typing.types import IncompatibleTypesError, BaseType, TupleType, TY_STR, TY_BOOL, TY_INT, \
from transpiler.phases.typing.types import BaseType, TupleType, TY_STR, TY_BOOL, TY_INT, \
TY_COMPLEX, TY_NONE, FunctionType, PyList, TypeVariable, PySet, TypeType, PyDict, Promise, PromiseKind, UserType
DUNDER = {
......
......@@ -136,7 +136,8 @@ class StdlibVisitor(NodeVisitorSeq):
def visit_str(self, node: str) -> BaseType:
if existing := self.scope.get(node):
return existing.type
raise NameError(node)
from transpiler.phases.typing.exceptions import UnknownNameError
raise UnknownNameError(node)
def visit_Name(self, node: ast.Name) -> BaseType:
return self.visit_str(node.id)
\ No newline at end of file
......@@ -8,10 +8,6 @@ from typing import Dict, Optional, List, ClassVar, Callable
from transpiler.utils import highlight
class IncompatibleTypesError(Exception):
pass
@dataclass(eq=False)
class BaseType(ABC):
members: Dict[str, "BaseType"] = field(default_factory=dict, init=False)
......@@ -68,7 +64,8 @@ class MagicType(BaseType, typing.Generic[T]):
def unify_internal(self, other: "BaseType"):
if type(self) != type(other) or self.val != other.val:
raise IncompatibleTypesError()
from transpiler.phases.typing.exceptions import TypeMismatchError, TypeMismatchKind
raise TypeMismatchError(self, other, TypeMismatchKind.DIFFERENT_TYPE)
def contains_internal(self, other: "BaseType") -> bool:
return False
......@@ -173,7 +170,7 @@ class TypeOperator(BaseType, ABC):
def unify_internal(self, other: BaseType):
from transpiler.phases.typing.exceptions import TypeMismatchError, TypeMismatchKind
if not isinstance(other, TypeOperator):
raise IncompatibleTypesError()
raise TypeMismatchError(self, other, TypeMismatchKind.DIFFERENT_TYPE)
if other.is_protocol and not self.is_protocol:
return other.unify_internal(self)
if self.is_protocol and not other.is_protocol:
......@@ -185,14 +182,14 @@ class TypeOperator(BaseType, ABC):
for parent in other.get_parents():
try:
self.unify(parent)
except IncompatibleTypesError:
except TypeMismatchError:
pass
else:
return
for parent in self.get_parents():
try:
parent.unify(other)
except IncompatibleTypesError:
except TypeMismatchError:
pass
else:
return
......@@ -447,4 +444,5 @@ class UserType(TypeOperator):
def unify_internal(self, other: "BaseType"):
if type(self) != type(other):
raise IncompatibleTypesError()
from transpiler.phases.typing.exceptions import TypeMismatchError, TypeMismatchKind
raise TypeMismatchError(self, other, TypeMismatchKind.DIFFERENT_TYPE)
......@@ -19,7 +19,6 @@ class NodeVisitorSeq:
return visitor(node)
except Exception as e:
raise
#raise IncompatibleTypesError(f"{e} in `{ast.unparse(node)}`")
else:
self.missing_impl(node)
......
......@@ -4,6 +4,8 @@ from dataclasses import dataclass
from itertools import zip_longest
from typing import Union
import colorful as cf
from pygments.token import *
#
# from colorama import Fore, Back
# from colorama.ansi import AnsiCodes
......@@ -23,6 +25,38 @@ import colorful as cf
#
# Style = AnsiStyle()
COLOR_SCHEME = {
Token: ('', ''),
Whitespace: ('gray', 'brightblack'),
Comment: ('brightblack', 'brightblack'),
Comment.Preproc: ('cyan', 'brightcyan'),
Keyword: ('brightblue', 'brightblue'),
Keyword.Type: ('cyan', 'brightcyan'),
Operator.Word: ('magenta', 'brightmagenta'),
Name.Builtin: ('cyan', 'brightcyan'),
Name.Function: ('green', 'brightgreen'),
Name.Namespace: ('brightcyan', 'brightcyan'),
Name.Class: ('green', 'brightgreen'),
Name.Exception: ('cyan', 'brightcyan'),
Name.Decorator: ('brightblack', 'gray'),
Name.Variable: ('red', 'brightred'),
Name.Constant: ('red', 'brightred'),
Name.Attribute: ('cyan', 'brightcyan'),
Name.Tag: ('brightblue', 'brightblue'),
String: ('yellow', 'yellow'),
Number: ('brightmagenta', 'brightblue'),
Generic.Deleted: ('brightred', 'brightred'),
Generic.Inserted: ('green', 'brightgreen'),
Generic.Heading: ('**', '**'),
Generic.Subheading: ('*magenta*', '*brightmagenta*'),
Generic.Prompt: ('**', '**'),
Generic.Error: ('brightred', 'brightred'),
Error: ('brightred', 'brightred'),
}
def highlight(code, full=False):
"""
Syntax highlights code as Python using colorama
......@@ -42,14 +76,14 @@ def highlight(code, full=False):
from pygments.formatters import TerminalFormatter
lexer = get_lexer_by_name("python", stripnl=False)
items = pyg_highlight(code, lexer, TerminalFormatter()).replace("\x1b[39;49;00m", "\x1b[39;24m")
items = pyg_highlight(code, lexer, TerminalFormatter(colorscheme=COLOR_SCHEME)).replace("\x1b[39;49;00m", "\x1b[39m")
if full:
return items
items = items.splitlines()
res = items[0]
if len(items) > 1:
res += cf.white(" [...]")
return f"\x1b[39;49m{cf.on_gray25(res)}"
return f"\x1b[39;49m{cf.on_gray23(res)}"
def compare_ast(node1: Union[ast.expr, list[ast.expr]], node2: Union[ast.expr, list[ast.expr]]) -> bool:
......
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