Compare commits

...

2 Commits

9 changed files with 78 additions and 18 deletions

View File

@@ -15,7 +15,7 @@ from midas.ast.location import Location
###> MidasType | Type annotations | node ###> MidasType | Type annotations | node
class BaseType: class BaseType:
base: str base: str
param: Optional[MidasType] args: tuple[MidasType, ...]
class ConstraintType: class ConstraintType:
@@ -174,6 +174,10 @@ class SliceExpr:
step: Optional[Expr] step: Optional[Expr]
class TupleExpr:
items: tuple[Expr, ...]
class RawExpr: class RawExpr:
expr: ast.expr expr: ast.expr

View File

@@ -549,7 +549,13 @@ class PythonAstPrinter(
self._write_line("BaseType") self._write_line("BaseType")
with self._child_level(): with self._child_level():
self._write_line(f"base: {node.base}") self._write_line(f"base: {node.base}")
self._write_optional_child("param", node.param, last=True) self._write_line("args:", last=True)
with self._child_level():
for i, arg in enumerate(node.args):
self._idx = i
if i == len(node.args) - 1:
self._mark_last()
arg.accept(self)
def visit_constraint_type(self, node: p.ConstraintType) -> None: def visit_constraint_type(self, node: p.ConstraintType) -> None:
self._write_line("ConstraintType") self._write_line("ConstraintType")
@@ -862,6 +868,17 @@ class PythonAstPrinter(
self._write_optional_child("upper", expr.upper) self._write_optional_child("upper", expr.upper)
self._write_optional_child("step", expr.step, last=True) self._write_optional_child("step", expr.step, last=True)
def visit_tuple_expr(self, expr: p.TupleExpr) -> None:
self._write_line("TupleExpr")
with self._child_level():
self._write_line("items", last=True)
with self._child_level():
for i, item in enumerate(expr.items):
self._idx = i
if i == len(expr.items) - 1:
self._mark_last()
item.accept(self)
def visit_raw_expr(self, expr: p.RawExpr) -> None: def visit_raw_expr(self, expr: p.RawExpr) -> None:
self._write_line("RawExpr") self._write_line("RawExpr")
with self._child_level(single=True): with self._child_level(single=True):

View File

@@ -44,7 +44,7 @@ class MidasType(ABC):
@dataclass(frozen=True) @dataclass(frozen=True)
class BaseType(MidasType): class BaseType(MidasType):
base: str base: str
param: Optional[MidasType] args: tuple[MidasType, ...]
def accept(self, visitor: MidasType.Visitor[T]) -> T: def accept(self, visitor: MidasType.Visitor[T]) -> T:
return visitor.visit_base_type(self) return visitor.visit_base_type(self)
@@ -268,6 +268,9 @@ class Expr(ABC):
@abstractmethod @abstractmethod
def visit_slice_expr(self, expr: SliceExpr) -> T: ... def visit_slice_expr(self, expr: SliceExpr) -> T: ...
@abstractmethod
def visit_tuple_expr(self, expr: TupleExpr) -> T: ...
@abstractmethod @abstractmethod
def visit_raw_expr(self, expr: RawExpr) -> T: ... def visit_raw_expr(self, expr: RawExpr) -> T: ...
@@ -402,6 +405,14 @@ class SliceExpr(Expr):
return visitor.visit_slice_expr(self) return visitor.visit_slice_expr(self)
@dataclass(frozen=True)
class TupleExpr(Expr):
items: tuple[Expr, ...]
def accept(self, visitor: Expr.Visitor[T]) -> T:
return visitor.visit_tuple_expr(self)
@dataclass(frozen=True) @dataclass(frozen=True)
class RawExpr(Expr): class RawExpr(Expr):
expr: ast.expr expr: ast.expr

View File

@@ -750,6 +750,11 @@ class PythonTyper(
def visit_slice_expr(self, expr: p.SliceExpr) -> Type: def visit_slice_expr(self, expr: p.SliceExpr) -> Type:
return self.types.get_type("slice") return self.types.get_type("slice")
def visit_tuple_expr(self, expr: p.TupleExpr) -> Type:
return TupleType(
items=tuple(self.type_of(item) for item in expr.items),
)
def visit_raw_expr(self, expr: p.RawExpr) -> Type: def visit_raw_expr(self, expr: p.RawExpr) -> Type:
return UnknownType() return UnknownType()
@@ -761,9 +766,9 @@ class PythonTyper(
self.reporter.warning(node.location, f"Unknown type '{node.base}'") self.reporter.warning(node.location, f"Unknown type '{node.base}'")
return UnknownType() return UnknownType()
if node.param is not None: if len(node.args) != 0:
param: Type = self.resolve_type_expr(node.param) args: list[Type] = [self.resolve_type_expr(arg) for arg in node.args]
return self.types.apply_generic(base, [param]) return self.types.apply_generic(base, args)
return base return base
def visit_constraint_type(self, node: p.ConstraintType) -> Type: def visit_constraint_type(self, node: p.ConstraintType) -> Type:

View File

@@ -236,5 +236,9 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
if expr.step is not None: if expr.step is not None:
self.resolve(expr.step) self.resolve(expr.step)
def visit_tuple_expr(self, expr: p.TupleExpr) -> None:
for item in expr.items:
self.resolve(item)
def visit_raw_expr(self, expr: p.RawExpr) -> None: def visit_raw_expr(self, expr: p.RawExpr) -> None:
pass pass

View File

@@ -134,9 +134,9 @@ class PythonHighlighter(
def visit_base_type(self, node: p.BaseType) -> None: def visit_base_type(self, node: p.BaseType) -> None:
self.wrap(node, "base-type") self.wrap(node, "base-type")
if node.param is not None: for arg in node.args:
self.wrap(node.param, "param") self.wrap(arg, "arg")
node.param.accept(self) arg.accept(self)
def visit_constraint_type(self, node: p.ConstraintType) -> None: def visit_constraint_type(self, node: p.ConstraintType) -> None:
self.wrap(node, "constraint-type") self.wrap(node, "constraint-type")
@@ -247,6 +247,10 @@ class PythonHighlighter(
if expr.step is not None: if expr.step is not None:
expr.step.accept(self) expr.step.accept(self)
def visit_tuple_expr(self, expr: p.TupleExpr) -> None:
for item in expr.items:
item.accept(self)
def visit_raw_expr(self, expr: p.RawExpr) -> None: ... def visit_raw_expr(self, expr: p.RawExpr) -> None: ...
def visit_raw_stmt(self, stmt: p.RawStmt) -> None: ... def visit_raw_stmt(self, stmt: p.RawStmt) -> None: ...

View File

@@ -3,7 +3,7 @@ span {
--col: 108, 233, 108; --col: 108, 233, 108;
} }
&.param { &.arg {
--col: 103, 192, 224; --col: 103, 192, 224;
} }

View File

@@ -30,6 +30,7 @@ from midas.ast.python import (
Stmt, Stmt,
SubscriptExpr, SubscriptExpr,
TernaryExpr, TernaryExpr,
TupleExpr,
TypeAssign, TypeAssign,
UnaryExpr, UnaryExpr,
VariableExpr, VariableExpr,
@@ -300,26 +301,28 @@ class PythonParser:
case ast.Subscript(value=ast.Name(id="Frame"), slice=schema): case ast.Subscript(value=ast.Name(id="Frame"), slice=schema):
return self._parse_frame_type(schema) return self._parse_frame_type(schema)
case ast.Subscript(value=ast.Name(id=name), slice=param): case ast.Subscript(value=ast.Name(id=name), slice=arg):
args: tuple[MidasType, ...] = (
tuple(self._parse_type(a) for a in arg.elts)
if isinstance(arg, ast.Tuple)
else (self._parse_type(arg),)
)
return BaseType( return BaseType(
location=loc, location=loc,
base=name, base=name,
param=self._parse_type(param), args=args,
) )
case ast.Name(id=name): case ast.Name(id=name):
return BaseType( return BaseType(
location=loc, location=loc,
base=name, base=name,
param=None, args=(),
) )
case ast.BinOp(left=left_expr, op=ast.Add(), right=right_expr): case ast.BinOp(left=left_expr, op=ast.Add(), right=right_expr):
left = self._parse_type(left_expr) left = self._parse_type(left_expr)
match left: match left:
case None:
raise InvalidSyntaxError()
# If chained constraints, separate base type and rebuild constraint # If chained constraints, separate base type and rebuild constraint
case ConstraintType(type=left_type, constraint=left_constraint): case ConstraintType(type=left_type, constraint=left_constraint):
constraint = ast.BinOp( constraint = ast.BinOp(
@@ -345,7 +348,7 @@ class PythonParser:
return BaseType( return BaseType(
location=loc, location=loc,
base="None", base="None",
param=None, args=(),
) )
case _: case _:
@@ -477,6 +480,12 @@ class PythonParser:
step=self.parse_expr(step) if step is not None else None, step=self.parse_expr(step) if step is not None else None,
) )
case ast.Tuple(elts=items):
return TupleExpr(
location=location,
items=tuple(self.parse_expr(item) for item in items),
)
case _: case _:
print(f"Unsupported expression: {ast.unparse(node)}") print(f"Unsupported expression: {ast.unparse(node)}")
return RawExpr(location=location, expr=node) return RawExpr(location=location, expr=node)

View File

@@ -98,7 +98,7 @@ class PythonAstJsonSerializer(
return { return {
"_type": "BaseType", "_type": "BaseType",
"base": node.base, "base": node.base,
"param": self._serialize_optional(node.param), "args": self._serialize_list(node.args),
} }
def visit_constraint_type(self, node: ConstraintType) -> dict: def visit_constraint_type(self, node: ConstraintType) -> dict:
@@ -302,6 +302,12 @@ class PythonAstJsonSerializer(
"step": self._serialize_optional(expr.step), "step": self._serialize_optional(expr.step),
} }
def visit_tuple_expr(self, expr: TupleExpr) -> dict:
return {
"_type": "TupleExpr",
"items": [item.accept(self) for item in expr.items],
}
def visit_raw_expr(self, expr: RawExpr) -> dict: def visit_raw_expr(self, expr: RawExpr) -> dict:
return { return {
"_type": "RawExpr", "_type": "RawExpr",