Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0179bc442
|
||
|
|
e665d03533
|
||
|
|
b8cb2b4273
|
@@ -0,0 +1,11 @@
|
|||||||
|
type Meter = float
|
||||||
|
|
||||||
|
extend Meter {
|
||||||
|
op __add__(Meter) -> Meter
|
||||||
|
op __sub__(Meter) -> Meter
|
||||||
|
}
|
||||||
|
|
||||||
|
type Coordinate = {
|
||||||
|
x: Meter
|
||||||
|
y: Meter
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# type: ignore
|
||||||
|
# ruff: disable [F821]
|
||||||
|
p1: Coordinate
|
||||||
|
p2: Coordinate
|
||||||
|
|
||||||
|
diff_x = p2.x - p1.x
|
||||||
|
diff_y = p2.y - p1.y
|
||||||
|
|
||||||
|
dist = diff_x + diff_y
|
||||||
|
|
||||||
|
p2.x += cast(Meter, 1)
|
||||||
@@ -128,12 +128,6 @@ class LogicalExpr:
|
|||||||
right: Expr
|
right: Expr
|
||||||
|
|
||||||
|
|
||||||
class SetExpr:
|
|
||||||
object: Expr
|
|
||||||
name: str
|
|
||||||
value: Expr
|
|
||||||
|
|
||||||
|
|
||||||
class CastExpr:
|
class CastExpr:
|
||||||
type: MidasType
|
type: MidasType
|
||||||
expr: Expr
|
expr: Expr
|
||||||
|
|||||||
@@ -602,17 +602,6 @@ class PythonAstPrinter(
|
|||||||
with self._child_level(single=True):
|
with self._child_level(single=True):
|
||||||
expr.right.accept(self)
|
expr.right.accept(self)
|
||||||
|
|
||||||
def visit_set_expr(self, expr: p.SetExpr) -> None:
|
|
||||||
self._write_line("SetExpr")
|
|
||||||
with self._child_level():
|
|
||||||
self._write_line("object")
|
|
||||||
with self._child_level(single=True):
|
|
||||||
expr.object.accept(self)
|
|
||||||
self._write_line(f"name: {expr.name}")
|
|
||||||
self._write_line("value", last=True)
|
|
||||||
with self._child_level(single=True):
|
|
||||||
expr.value.accept(self)
|
|
||||||
|
|
||||||
def visit_cast_expr(self, expr: p.CastExpr) -> None:
|
def visit_cast_expr(self, expr: p.CastExpr) -> None:
|
||||||
self._write_line("CastExpr")
|
self._write_line("CastExpr")
|
||||||
with self._child_level():
|
with self._child_level():
|
||||||
|
|||||||
@@ -214,9 +214,6 @@ class Expr(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_logical_expr(self, expr: LogicalExpr) -> T: ...
|
def visit_logical_expr(self, expr: LogicalExpr) -> T: ...
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def visit_set_expr(self, expr: SetExpr) -> T: ...
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_cast_expr(self, expr: CastExpr) -> T: ...
|
def visit_cast_expr(self, expr: CastExpr) -> T: ...
|
||||||
|
|
||||||
@@ -298,16 +295,6 @@ class LogicalExpr(Expr):
|
|||||||
return visitor.visit_logical_expr(self)
|
return visitor.visit_logical_expr(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class SetExpr(Expr):
|
|
||||||
object: Expr
|
|
||||||
name: str
|
|
||||||
value: Expr
|
|
||||||
|
|
||||||
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
|
||||||
return visitor.visit_set_expr(self)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class CastExpr(Expr):
|
class CastExpr(Expr):
|
||||||
type: MidasType
|
type: MidasType
|
||||||
|
|||||||
+82
-18
@@ -178,6 +178,13 @@ class Checker(
|
|||||||
stmts: list[m.Stmt] = parser.parse()
|
stmts: list[m.Stmt] = parser.parse()
|
||||||
self.ctx.resolve(stmts)
|
self.ctx.resolve(stmts)
|
||||||
|
|
||||||
|
def unfold_type(self, type: Type) -> Type:
|
||||||
|
match type:
|
||||||
|
case AliasType(type=ref_type):
|
||||||
|
return self.unfold_type(ref_type)
|
||||||
|
case _:
|
||||||
|
return type
|
||||||
|
|
||||||
def is_subtype(self, type1: Type, type2: Type) -> bool:
|
def is_subtype(self, type1: Type, type2: Type) -> bool:
|
||||||
"""Check whether `type1` is a subtype of `type2`
|
"""Check whether `type1` is a subtype of `type2`
|
||||||
|
|
||||||
@@ -430,24 +437,64 @@ class Checker(
|
|||||||
def visit_assign_stmt(self, stmt: p.AssignStmt) -> None:
|
def visit_assign_stmt(self, stmt: p.AssignStmt) -> None:
|
||||||
value_type: Type = self.type_of(stmt.value)
|
value_type: Type = self.type_of(stmt.value)
|
||||||
for target in stmt.targets:
|
for target in stmt.targets:
|
||||||
if not isinstance(target, p.VariableExpr):
|
self._assign(stmt.location, target, value_type)
|
||||||
self.logger.warning(f"Unsupported assignment to {target}")
|
|
||||||
self.warning(target.location, f"Unsupported assignment to {target}")
|
|
||||||
continue
|
|
||||||
name: str = target.name
|
|
||||||
var_type: Optional[Type] = self.look_up_variable(name, target)
|
|
||||||
|
|
||||||
if var_type is None:
|
def _assign(self, location: Location, target: p.Expr, value_type: Type):
|
||||||
self.env.define(name, value_type)
|
match target:
|
||||||
else:
|
case p.VariableExpr():
|
||||||
# S <: T
|
self._assign_var(location, target, value_type)
|
||||||
# Γ, x: T v: S
|
|
||||||
# x = v
|
case p.GetExpr():
|
||||||
if not self.is_subtype(value_type, var_type):
|
self._assign_attr(location, target, value_type)
|
||||||
|
|
||||||
|
case _:
|
||||||
|
if not isinstance(target, p.VariableExpr):
|
||||||
|
self.logger.warning(f"Unsupported assignment to {target}")
|
||||||
|
self.warning(target.location, f"Unsupported assignment to {target}")
|
||||||
|
|
||||||
|
def _assign_var(self, location: Location, target: p.VariableExpr, value_type: Type):
|
||||||
|
name: str = target.name
|
||||||
|
var_type: Optional[Type] = self.look_up_variable(name, target)
|
||||||
|
|
||||||
|
if var_type is None:
|
||||||
|
self.env.define(name, value_type)
|
||||||
|
else:
|
||||||
|
# S <: T
|
||||||
|
# Γ, x: T v: S
|
||||||
|
# x = v
|
||||||
|
if not self.is_subtype(value_type, var_type):
|
||||||
|
self.error(
|
||||||
|
location,
|
||||||
|
f"Cannot assign {value_type} to {name} of type {var_type}",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _assign_attr(self, location: Location, target: p.GetExpr, value_type: Type):
|
||||||
|
object: Type = self.type_of(target.object)
|
||||||
|
base_object: Type = self.unfold_type(object)
|
||||||
|
match base_object:
|
||||||
|
case ComplexType(properties=properties):
|
||||||
|
if target.name not in properties:
|
||||||
self.error(
|
self.error(
|
||||||
stmt.location,
|
target.location, f"Unknown property '{target.name} on {object}"
|
||||||
f"Cannot assign {value_type} to {name} of type {var_type}",
|
|
||||||
)
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
prop_type: Type = properties[target.name]
|
||||||
|
if not self.is_subtype(value_type, prop_type):
|
||||||
|
self.error(
|
||||||
|
location,
|
||||||
|
f"Cannot assign {value_type} to property '{target.name}' of type {prop_type} on {object}",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
case UnknownType():
|
||||||
|
pass
|
||||||
|
|
||||||
|
case _:
|
||||||
|
self.error(
|
||||||
|
target.location,
|
||||||
|
f"Cannot assign {value_type} to unknown property '{target.name}' on {object}",
|
||||||
|
)
|
||||||
|
|
||||||
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
|
def visit_return_stmt(self, stmt: p.ReturnStmt) -> None:
|
||||||
type: Type = stmt.value.accept(self) if stmt.value is not None else UnitType()
|
type: Type = stmt.value.accept(self) if stmt.value is not None else UnitType()
|
||||||
@@ -562,7 +609,26 @@ class Checker(
|
|||||||
)
|
)
|
||||||
return function.returns
|
return function.returns
|
||||||
|
|
||||||
def visit_get_expr(self, expr: p.GetExpr) -> Type: ...
|
def visit_get_expr(self, expr: p.GetExpr) -> Type:
|
||||||
|
object: Type = self.type_of(expr.object)
|
||||||
|
base_object: Type = self.unfold_type(object)
|
||||||
|
match base_object:
|
||||||
|
case ComplexType(properties=properties):
|
||||||
|
if expr.name not in properties:
|
||||||
|
self.error(
|
||||||
|
expr.location, f"Unknown property '{expr.name} on {object}"
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
return properties[expr.name]
|
||||||
|
|
||||||
|
case UnknownType():
|
||||||
|
return UnknownType()
|
||||||
|
|
||||||
|
case _:
|
||||||
|
self.error(
|
||||||
|
expr.location, f"Cannot get property '{expr.name}' on {object}"
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
|
||||||
def visit_literal_expr(self, expr: p.LiteralExpr) -> Type:
|
def visit_literal_expr(self, expr: p.LiteralExpr) -> Type:
|
||||||
match expr.value:
|
match expr.value:
|
||||||
@@ -596,8 +662,6 @@ class Checker(
|
|||||||
)
|
)
|
||||||
return UnknownType()
|
return UnknownType()
|
||||||
|
|
||||||
def visit_set_expr(self, expr: p.SetExpr) -> Type: ...
|
|
||||||
|
|
||||||
def visit_cast_expr(self, expr: p.CastExpr) -> Type:
|
def visit_cast_expr(self, expr: p.CastExpr) -> Type:
|
||||||
return expr.type.accept(self)
|
return expr.type.accept(self)
|
||||||
|
|
||||||
|
|||||||
@@ -210,8 +210,6 @@ class PythonHighlighter(
|
|||||||
|
|
||||||
def visit_logical_expr(self, expr: p.LogicalExpr) -> None: ...
|
def visit_logical_expr(self, expr: p.LogicalExpr) -> None: ...
|
||||||
|
|
||||||
def visit_set_expr(self, expr: p.SetExpr) -> None: ...
|
|
||||||
|
|
||||||
def visit_cast_expr(self, expr: p.CastExpr) -> None: ...
|
def visit_cast_expr(self, expr: p.CastExpr) -> None: ...
|
||||||
|
|
||||||
def visit_ternary_expr(self, expr: p.TernaryExpr) -> None: ...
|
def visit_ternary_expr(self, expr: p.TernaryExpr) -> None: ...
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from typing import Optional
|
|||||||
import midas.ast.midas as m
|
import midas.ast.midas as m
|
||||||
from midas.checker.types import (
|
from midas.checker.types import (
|
||||||
AliasType,
|
AliasType,
|
||||||
|
ComplexType,
|
||||||
Operation,
|
Operation,
|
||||||
Type,
|
Type,
|
||||||
UnknownType,
|
UnknownType,
|
||||||
@@ -178,7 +179,8 @@ class MidasResolver(m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[T
|
|||||||
return UnknownType()
|
return UnknownType()
|
||||||
|
|
||||||
def visit_complex_type(self, type: m.ComplexType) -> Type:
|
def visit_complex_type(self, type: m.ComplexType) -> Type:
|
||||||
for prop in type.properties:
|
return ComplexType(
|
||||||
prop.accept(self)
|
properties={
|
||||||
# TODO
|
prop.name.lexeme: prop.type.accept(self) for prop in type.properties
|
||||||
return UnknownType()
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -111,9 +111,8 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
self.resolve(stmt.value)
|
self.resolve(stmt.value)
|
||||||
for target in stmt.targets:
|
for target in stmt.targets:
|
||||||
match target:
|
match target:
|
||||||
case p.VariableExpr(name=name):
|
case p.VariableExpr() | p.GetExpr():
|
||||||
self.resolve_local(target, name)
|
target.accept(self)
|
||||||
# TODO: declare if not found
|
|
||||||
case _:
|
case _:
|
||||||
raise Exception(f"Unsupported assignment to {target}")
|
raise Exception(f"Unsupported assignment to {target}")
|
||||||
|
|
||||||
@@ -174,10 +173,6 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
self.resolve(expr.left)
|
self.resolve(expr.left)
|
||||||
self.resolve(expr.right)
|
self.resolve(expr.right)
|
||||||
|
|
||||||
def visit_set_expr(self, expr: p.SetExpr) -> None:
|
|
||||||
self.resolve(expr.value)
|
|
||||||
self.resolve(expr.object)
|
|
||||||
|
|
||||||
def visit_cast_expr(self, expr: p.CastExpr) -> None:
|
def visit_cast_expr(self, expr: p.CastExpr) -> None:
|
||||||
self.resolve(expr.expr)
|
self.resolve(expr.expr)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ from midas.ast.python import (
|
|||||||
LogicalExpr,
|
LogicalExpr,
|
||||||
MidasType,
|
MidasType,
|
||||||
ReturnStmt,
|
ReturnStmt,
|
||||||
SetExpr,
|
|
||||||
Stmt,
|
Stmt,
|
||||||
TernaryExpr,
|
TernaryExpr,
|
||||||
TypeAssign,
|
TypeAssign,
|
||||||
@@ -232,14 +231,6 @@ class PythonAstJsonSerializer(
|
|||||||
"right": expr.right.accept(self),
|
"right": expr.right.accept(self),
|
||||||
}
|
}
|
||||||
|
|
||||||
def visit_set_expr(self, expr: SetExpr) -> dict:
|
|
||||||
return {
|
|
||||||
"_type": "SetExpr",
|
|
||||||
"object": expr.object.accept(self),
|
|
||||||
"name": expr.name,
|
|
||||||
"value": expr.value.accept(self),
|
|
||||||
}
|
|
||||||
|
|
||||||
def visit_cast_expr(self, expr: CastExpr) -> dict:
|
def visit_cast_expr(self, expr: CastExpr) -> dict:
|
||||||
return {
|
return {
|
||||||
"_type": "CastExpr",
|
"_type": "CastExpr",
|
||||||
|
|||||||
Reference in New Issue
Block a user