Commit 0f112489 authored by Tom Niget's avatar Tom Niget

Continue work on errors

parent 57dfb3cf
print("Main") print("Main")
# TODO
"""
webserver => investiguer
scanfs => fork
promesse => faire
self/this => bind/dot
stocker smart ptr dans closures
"""
\ No newline at end of file
...@@ -2,6 +2,8 @@ clang-format==15.0.7 ...@@ -2,6 +2,8 @@ clang-format==15.0.7
pytype~=2023.4.11 pytype~=2023.4.11
dataclasses~=0.6 dataclasses~=0.6
python-dotenv~=1.0.0 python-dotenv~=1.0.0
nanobind~=1.4.0
colorama~=0.4.6 colorama~=0.4.6
numpy~=1.25.1 numpy~=1.25.1
pygments~=2.15.1
colorful~=0.5.5 colorful~=0.5.5
\ No newline at end of file
import sys import sys
import math; x = (math. import math
abcd) x = 5
def f(x: int): x: str = "str"
return x
if __name__ == "__main__": if __name__ == "__main__":
......
# test numpy interop
from numpy import square
import math
if __name__ == "__main__":
x = [1, 2, 3, 4]
y: list[int] = square(x)
print(x, y)
f: int = math.factorial(5)
print("5! =", f)
\ No newline at end of file
"""
def sense(self):
host = self.getConfig('host')
port = self.getConfig('port')
path = self.getConfig('pathname')
abstract = self.getConfig('abstract')
if host:
if path or abstract or not port:
self.logger.error(ADDRESS_USAGE)
return
# type of port must be int or str, unicode is not accepted.
family, _, _, _, addr = socket.getaddrinfo(host, int(port))[0]
else:
if bool(path) == bool(abstract):
self.logger.error(ADDRESS_USAGE)
return
family = socket.AF_UNIX
addr = path or '\0' + abstract
s = socket.socket(family, socket.SOCK_STREAM)
try:
s.connect(addr)
except socket.error as e:
self.logger.error('%s: %s', type(e).__name__, e)
else:
self.logger.info("socket connection OK %r", addr)
finally:
s.close()
"""
import sys
# prog host port
# prog path
# prog @abstract
if __name__ == "__main__":
pass
\ No newline at end of file
...@@ -60,9 +60,14 @@ def exception_hook(exc_type, exc_value, tb): ...@@ -60,9 +60,14 @@ def exception_hook(exc_type, exc_value, tb):
if last_node is not None: if last_node is not None:
print() print()
print(f"In file \"{cf.white(last_file)}\", line {last_node.lineno}") print(f"In file \"{cf.white(last_file)}\", line {last_node.lineno}")
print(f"From {last_node.lineno}:{last_node.col_offset} to {last_node.end_lineno}:{last_node.end_col_offset}")
with open(last_file, "r", encoding="utf-8") as f: with open(last_file, "r", encoding="utf-8") as f:
code = f.read() code = f.read()
hg = str(highlight(code, True)).replace("\x1b[04m", "").replace("\x1b[24m", "").splitlines() hg = (str(highlight(code, True))
.replace("\x1b[04m", "")
.replace("\x1b[24m", "")
.replace("\x1b[39;24m", "\x1b[39m")
.splitlines())
if last_node.lineno == last_node.end_lineno: if last_node.lineno == last_node.end_lineno:
old = hg[last_node.lineno - 1] old = hg[last_node.lineno - 1]
start, end = find_indices(old, [last_node.col_offset, last_node.end_col_offset]) start, end = find_indices(old, [last_node.col_offset, last_node.end_col_offset])
...@@ -81,8 +86,9 @@ def exception_hook(exc_type, exc_value, tb): ...@@ -81,8 +86,9 @@ def exception_hook(exc_type, exc_value, tb):
for i, line in enumerate(hg[start:last_node.end_lineno + CONTEXT_SIZE]): for i, line in enumerate(hg[start:last_node.end_lineno + CONTEXT_SIZE]):
erroneous = last_node.lineno <= offset + i <= last_node.end_lineno erroneous = last_node.lineno <= offset + i <= last_node.end_lineno
indicator = cf.white("**>") if erroneous else " " indicator = cf.white("**>") if erroneous else " "
print( disp = f"\x1b[24m{indicator}{cf.white}{(offset + i):>4}{cf.red if erroneous else cf.reset} |{cf.reset} {line}\x1b[24m"
f"\x1b[24m{indicator}{cf.white}{(offset + i):>4}{cf.red if erroneous else cf.reset} | {cf.reset}{line}\x1b[24m") print(disp)
# print(repr(disp))
print() print()
print(cf.red("Error:"), exc_value) print(cf.red("Error:"), exc_value)
if isinstance(exc_value, CompileError): if isinstance(exc_value, CompileError):
......
...@@ -3,6 +3,7 @@ import dataclasses ...@@ -3,6 +3,7 @@ import dataclasses
import importlib import importlib
from dataclasses import dataclass from dataclasses import dataclass
from transpiler.utils import highlight
from transpiler.phases.typing import make_mod_decl from transpiler.phases.typing import make_mod_decl
from transpiler.phases.typing.common import ScoperVisitor from transpiler.phases.typing.common import ScoperVisitor
from transpiler.phases.typing.expr import ScoperExprVisitor from transpiler.phases.typing.expr import ScoperExprVisitor
...@@ -93,22 +94,19 @@ class ScoperBlockVisitor(ScoperVisitor): ...@@ -93,22 +94,19 @@ class ScoperBlockVisitor(ScoperVisitor):
if not isinstance(node.target, ast.Name): if not isinstance(node.target, ast.Name):
raise NotImplementedError(node) raise NotImplementedError(node)
ty = self.visit_annotation(node.annotation) ty = self.visit_annotation(node.annotation)
try:
node.is_declare = self.visit_assign_target(node.target, ty) node.is_declare = self.visit_assign_target(node.target, ty)
except IncompatibleTypesError as e:
raise IncompatibleTypesError(f"`{ast.unparse(node)}: {e}")
ty_val = self.get_type(node.value) ty_val = self.get_type(node.value)
try: TB = f"unifying annotation {highlight(node.annotation)} with value {highlight(node.value)} of type {highlight(ty_val)}"
ty.unify(ty_val) ty.unify(ty_val)
except IncompatibleTypesError as e:
raise IncompatibleTypesError(f"`{ast.unparse(node)}: {e}")
def visit_assign_target(self, target, decl_val: BaseType) -> bool: def visit_assign_target(self, target, decl_val: BaseType) -> bool:
TB = f"analyzing assignment target {highlight(target)} with value {highlight(decl_val)}"
if isinstance(target, ast.Name): if isinstance(target, ast.Name):
if target.id == "_": if target.id == "_":
return False return False
target.type = decl_val target.type = decl_val
if vdecl := self.scope.get(target.id): if vdecl := self.scope.get(target.id):
TB = f"unifying existing variable {highlight(target.id)} of type {highlight(vdecl.type)} with assigned value {highlight(decl_val)}"
vdecl.type.unify(decl_val) vdecl.type.unify(decl_val)
return False return False
else: else:
......
...@@ -56,30 +56,11 @@ class RecursiveTypeUnificationError(CompileError): ...@@ -56,30 +56,11 @@ class RecursiveTypeUnificationError(CompileError):
""" """
@dataclass
class InvalidCallError(CompileError):
callee: BaseType
args: list[BaseType]
def __str__(self) -> str:
return f"Invalid call: {highlight(self.callee)} with arguments {highlight(self.args)}"
def detail(self, last_node: ast.AST = None) -> str:
return f"""
This generally indicates a type error in a function call.
For example:
{highlight('def f(x: int): pass')}
{highlight('f("hello")')}
In the current case, {highlight(self.callee)} was called with arguments {highlight(self.args)}, but the function
expects arguments of type {highlight(self.callee.args)}.
"""
class TypeMismatchKind(enum.Enum): class TypeMismatchKind(enum.Enum):
NO_COMMON_PARENT = enum.auto() NO_COMMON_PARENT = enum.auto()
DIFFERENT_TYPE = enum.auto() DIFFERENT_TYPE = enum.auto()
@dataclass @dataclass
class TypeMismatchError(CompileError): class TypeMismatchError(CompileError):
expected: BaseType expected: BaseType
...@@ -94,7 +75,7 @@ class TypeMismatchError(CompileError): ...@@ -94,7 +75,7 @@ class TypeMismatchError(CompileError):
This generally indicates a type error. This generally indicates a type error.
For example: For example:
{highlight('def f(x: int): pass')} {highlight('def f(x: int): ...')}
{highlight('f("hello")')} {highlight('f("hello")')}
In the current case, the compiler expected an expression of type {highlight(self.expected)}, but instead got In the current case, the compiler expected an expression of type {highlight(self.expected)}, but instead got
...@@ -124,7 +105,7 @@ class ArgumentCountMismatchError(CompileError): ...@@ -124,7 +105,7 @@ class ArgumentCountMismatchError(CompileError):
The called or instantiated signature was {highlight(self.func)}. The called or instantiated signature was {highlight(self.func)}.
Other examples: Other examples:
{highlight('def f(x: int): pass')} {highlight('def f(x: int): ...')}
{highlight('f(1, 2)')} {highlight('f(1, 2)')}
Here, the function {highlight('f')} expects one argument, but was called with two. Here, the function {highlight('f')} expects one argument, but was called with two.
...@@ -147,13 +128,14 @@ class ProtocolMismatchError(CompileError): ...@@ -147,13 +128,14 @@ class ProtocolMismatchError(CompileError):
This generally indicates a type error. This generally indicates a type error.
For example: For example:
{highlight('def f(x: Iterable[int]): pass')} {highlight('def f(x: Iterable[int]): ...')}
{highlight('f("hello")')} {highlight('f("hello")')}
In the current case, the compiler expected an expression whose type implements {highlight(self.protocol)}, but In the current case, the compiler expected an expression whose type implements {highlight(self.protocol)}, but
instead got an expression of type {highlight(self.value)}. instead got an expression of type {highlight(self.value)}.
""" """
@dataclass @dataclass
class NotCallableError(CompileError): class NotCallableError(CompileError):
value: BaseType value: BaseType
...@@ -170,6 +152,7 @@ class NotCallableError(CompileError): ...@@ -170,6 +152,7 @@ class NotCallableError(CompileError):
{highlight('x()')} {highlight('x()')}
""" """
@dataclass @dataclass
class MissingAttributeError(CompileError): class MissingAttributeError(CompileError):
value: BaseType value: BaseType
...@@ -187,6 +170,7 @@ class MissingAttributeError(CompileError): ...@@ -187,6 +170,7 @@ class MissingAttributeError(CompileError):
{highlight('print(x.y)')} {highlight('print(x.y)')}
""" """
@dataclass @dataclass
class UnknownNameError(CompileError): class UnknownNameError(CompileError):
name: str name: str
...@@ -202,6 +186,7 @@ class UnknownNameError(CompileError): ...@@ -202,6 +186,7 @@ class UnknownNameError(CompileError):
{highlight('print(abcd)')} {highlight('print(abcd)')}
""" """
@dataclass @dataclass
class UnknownModuleMemberError(CompileError): class UnknownModuleMemberError(CompileError):
module: str module: str
......
...@@ -44,7 +44,7 @@ def highlight(code, full=False): ...@@ -44,7 +44,7 @@ def highlight(code, full=False):
res = items[0] res = items[0]
if len(items) > 1: if len(items) > 1:
res += cf.white(" [...]") res += cf.white(" [...]")
return cf.on_gray25(res) return f"\x1b[39;49m{cf.on_gray25(res)}"
def compare_ast(node1: Union[ast.expr, list[ast.expr]], node2: Union[ast.expr, list[ast.expr]]) -> bool: 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