feat: remove complex and extension types
This commit is contained in:
@@ -136,15 +136,6 @@ class ConstraintType:
|
|||||||
constraint: Expr
|
constraint: Expr
|
||||||
|
|
||||||
|
|
||||||
class ComplexType:
|
|
||||||
members: list[MemberStmt]
|
|
||||||
|
|
||||||
|
|
||||||
class ExtensionType:
|
|
||||||
base: Type
|
|
||||||
extension: ComplexType
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionType:
|
class FunctionType:
|
||||||
params: ParamSpec
|
params: ParamSpec
|
||||||
returns: Type
|
returns: Type
|
||||||
|
|||||||
@@ -256,12 +256,6 @@ class Type(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_constraint_type(self, type: ConstraintType) -> T: ...
|
def visit_constraint_type(self, type: ConstraintType) -> T: ...
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def visit_complex_type(self, type: ComplexType) -> T: ...
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def visit_extension_type(self, type: ExtensionType) -> T: ...
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_function_type(self, type: FunctionType) -> T: ...
|
def visit_function_type(self, type: FunctionType) -> T: ...
|
||||||
|
|
||||||
@@ -295,23 +289,6 @@ class ConstraintType(Type):
|
|||||||
return visitor.visit_constraint_type(self)
|
return visitor.visit_constraint_type(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class ComplexType(Type):
|
|
||||||
members: list[MemberStmt]
|
|
||||||
|
|
||||||
def accept(self, visitor: Type.Visitor[T]) -> T:
|
|
||||||
return visitor.visit_complex_type(self)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
|
||||||
class ExtensionType(Type):
|
|
||||||
base: Type
|
|
||||||
extension: ComplexType
|
|
||||||
|
|
||||||
def accept(self, visitor: Type.Visitor[T]) -> T:
|
|
||||||
return visitor.visit_extension_type(self)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FunctionType(Type):
|
class FunctionType(Type):
|
||||||
params: ParamSpec
|
params: ParamSpec
|
||||||
|
|||||||
@@ -124,19 +124,6 @@ class MidasPrinter(
|
|||||||
res += " where " + type.constraint.accept(self)
|
res += " where " + type.constraint.accept(self)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def visit_complex_type(self, type: m.ComplexType) -> str:
|
|
||||||
res: str = "{\n"
|
|
||||||
self.level += 1
|
|
||||||
for member in type.members:
|
|
||||||
res += member.accept(self)
|
|
||||||
res += "\n"
|
|
||||||
self.level -= 1
|
|
||||||
res += self.indented("}")
|
|
||||||
return res
|
|
||||||
|
|
||||||
def visit_extension_type(self, type: m.ExtensionType) -> str:
|
|
||||||
return f"{type.base.accept(self)} & {type.extension.accept(self)}"
|
|
||||||
|
|
||||||
def visit_function_type(self, type: m.FunctionType) -> str:
|
def visit_function_type(self, type: m.FunctionType) -> str:
|
||||||
spec: str = self._visit_param_spec(type.params)
|
spec: str = self._visit_param_spec(type.params)
|
||||||
return f"fn {spec} -> {type.returns.accept(self)}"
|
return f"fn {spec} -> {type.returns.accept(self)}"
|
||||||
|
|||||||
@@ -177,21 +177,6 @@ class MidasAstPrinter(
|
|||||||
with self._child_level(single=True):
|
with self._child_level(single=True):
|
||||||
type.constraint.accept(self)
|
type.constraint.accept(self)
|
||||||
|
|
||||||
def visit_complex_type(self, type: m.ComplexType) -> None:
|
|
||||||
self._write_line("ComplexType")
|
|
||||||
with self._child_level():
|
|
||||||
self._write_sequence("members", type.members, last=True)
|
|
||||||
|
|
||||||
def visit_extension_type(self, type: m.ExtensionType) -> None:
|
|
||||||
self._write_line("ExtensionType")
|
|
||||||
with self._child_level():
|
|
||||||
self._write_line("base")
|
|
||||||
with self._child_level(single=True):
|
|
||||||
type.base.accept(self)
|
|
||||||
self._write_line("extension", last=True)
|
|
||||||
with self._child_level(single=True):
|
|
||||||
type.extension.accept(self)
|
|
||||||
|
|
||||||
def visit_function_type(self, type: m.FunctionType) -> None:
|
def visit_function_type(self, type: m.FunctionType) -> None:
|
||||||
self._write_line("FunctionType")
|
self._write_line("FunctionType")
|
||||||
with self._child_level():
|
with self._child_level():
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ from midas.checker.registry import TypesRegistry
|
|||||||
from midas.checker.reporter import FileReporter, Reporter
|
from midas.checker.reporter import FileReporter, Reporter
|
||||||
from midas.checker.types import (
|
from midas.checker.types import (
|
||||||
ColumnType,
|
ColumnType,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
DataFrameType,
|
DataFrameType,
|
||||||
DerivedType,
|
DerivedType,
|
||||||
ExtensionType,
|
|
||||||
Function,
|
Function,
|
||||||
GenericType,
|
GenericType,
|
||||||
ParamSpec,
|
ParamSpec,
|
||||||
@@ -422,19 +420,6 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
|
|||||||
constraint=type.constraint,
|
constraint=type.constraint,
|
||||||
)
|
)
|
||||||
|
|
||||||
def visit_complex_type(self, type: m.ComplexType) -> ComplexType:
|
|
||||||
return ComplexType(
|
|
||||||
members={
|
|
||||||
member.name.lexeme: member.type.accept(self) for member in type.members
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def visit_extension_type(self, type: m.ExtensionType) -> Type:
|
|
||||||
return ExtensionType(
|
|
||||||
base=type.base.accept(self),
|
|
||||||
extension=self.visit_complex_type(type.extension),
|
|
||||||
)
|
|
||||||
|
|
||||||
def visit_function_type(self, type: m.FunctionType) -> Type:
|
def visit_function_type(self, type: m.FunctionType) -> Type:
|
||||||
return Function(
|
return Function(
|
||||||
params=self._visit_param_spec(type.params),
|
params=self._visit_param_spec(type.params),
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ from midas.checker.types import (
|
|||||||
AppliedType,
|
AppliedType,
|
||||||
BaseType,
|
BaseType,
|
||||||
ColumnType,
|
ColumnType,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
DataFrameType,
|
DataFrameType,
|
||||||
DerivedType,
|
DerivedType,
|
||||||
ExtensionType,
|
|
||||||
Function,
|
Function,
|
||||||
GenericType,
|
GenericType,
|
||||||
OverloadedFunction,
|
OverloadedFunction,
|
||||||
@@ -202,14 +200,6 @@ class TypesRegistry:
|
|||||||
case (BaseType(name=name1), BaseType(name=name2)):
|
case (BaseType(name=name1), BaseType(name=name2)):
|
||||||
return self.is_builtin_subtype(name1, name2)
|
return self.is_builtin_subtype(name1, name2)
|
||||||
|
|
||||||
case (ComplexType(properties=props1), ComplexType(properties=props2)):
|
|
||||||
for k, t in props2.items():
|
|
||||||
if k not in props1:
|
|
||||||
return False
|
|
||||||
if not self.is_subtype(props1[k], t):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
case (DataFrameType(columns=columns1), DataFrameType(columns=columns2)):
|
case (DataFrameType(columns=columns1), DataFrameType(columns=columns2)):
|
||||||
# TODO: check order?
|
# TODO: check order?
|
||||||
by_name1: dict[str, DataFrameType.Column] = {
|
by_name1: dict[str, DataFrameType.Column] = {
|
||||||
@@ -506,20 +496,6 @@ class TypesRegistry:
|
|||||||
member_type2 = substitute_typevars(member_type2, substitutions)
|
member_type2 = substitute_typevars(member_type2, substitutions)
|
||||||
return member_type2
|
return member_type2
|
||||||
|
|
||||||
case ComplexType(members=members):
|
|
||||||
if member_name in members:
|
|
||||||
return members[member_name]
|
|
||||||
self.logger.debug(f"No member '{member_name}' in {type}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
case ExtensionType(base=base, extension=ComplexType(members=members)):
|
|
||||||
if member_name in members:
|
|
||||||
return members[member_name]
|
|
||||||
self.logger.debug(
|
|
||||||
f"No member '{member_name}' on {type}, looking up in base"
|
|
||||||
)
|
|
||||||
return self.lookup_member(base, member_name)
|
|
||||||
|
|
||||||
case ConstraintType(type=base):
|
case ConstraintType(type=base):
|
||||||
return self.lookup_member(base, member_name)
|
return self.lookup_member(base, member_name)
|
||||||
|
|
||||||
|
|||||||
@@ -113,28 +113,6 @@ class OverloadedFunction:
|
|||||||
return "<overloaded function>"
|
return "<overloaded function>"
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
|
||||||
class ComplexType:
|
|
||||||
"""A type with inline members"""
|
|
||||||
|
|
||||||
members: dict[str, Type]
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
props: list[str] = [f"{name}: {type}" for name, type in self.members.items()]
|
|
||||||
return f"{{{', '.join(props)}}}"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
|
||||||
class ExtensionType:
|
|
||||||
"""An extension of a type, adding members through a `ComplexType`"""
|
|
||||||
|
|
||||||
base: Type
|
|
||||||
extension: ComplexType
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f"{self.base} & {self.extension}"
|
|
||||||
|
|
||||||
|
|
||||||
class Variance(StrEnum):
|
class Variance(StrEnum):
|
||||||
"""The variance of a :class:`TypeVar`"""
|
"""The variance of a :class:`TypeVar`"""
|
||||||
|
|
||||||
@@ -323,24 +301,6 @@ def substitute_typevars(type: Type, substitutions: dict[str, Type]) -> Type:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
case ComplexType(members=members):
|
|
||||||
members2: dict[str, Type] = {
|
|
||||||
name: substitute_typevars(prop, substitutions)
|
|
||||||
for name, prop in members.items()
|
|
||||||
}
|
|
||||||
return ComplexType(members=members2)
|
|
||||||
|
|
||||||
case ExtensionType(base=base, extension=ComplexType(members=members)):
|
|
||||||
return ExtensionType(
|
|
||||||
base=substitute_typevars(base, substitutions),
|
|
||||||
extension=ComplexType(
|
|
||||||
members={
|
|
||||||
name: substitute_typevars(prop, substitutions)
|
|
||||||
for name, prop in members.items()
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
case AppliedType(name=name, args=args, body=body):
|
case AppliedType(name=name, args=args, body=body):
|
||||||
return AppliedType(
|
return AppliedType(
|
||||||
name=name,
|
name=name,
|
||||||
@@ -468,9 +428,6 @@ def to_annotation(type: Type) -> str:
|
|||||||
case OverloadedFunction():
|
case OverloadedFunction():
|
||||||
return "Callable"
|
return "Callable"
|
||||||
|
|
||||||
case ComplexType() | ExtensionType():
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
case TypeVar(name=name):
|
case TypeVar(name=name):
|
||||||
return name
|
return name
|
||||||
|
|
||||||
@@ -519,8 +476,6 @@ Type = (
|
|||||||
| UnitType
|
| UnitType
|
||||||
| Function
|
| Function
|
||||||
| OverloadedFunction
|
| OverloadedFunction
|
||||||
| ComplexType
|
|
||||||
| ExtensionType
|
|
||||||
| TypeVar
|
| TypeVar
|
||||||
| GenericType
|
| GenericType
|
||||||
| AppliedType
|
| AppliedType
|
||||||
|
|||||||
@@ -338,21 +338,11 @@ class MidasHighlighter(
|
|||||||
type.type.accept(self)
|
type.type.accept(self)
|
||||||
type.constraint.accept(self)
|
type.constraint.accept(self)
|
||||||
|
|
||||||
def visit_complex_type(self, type: m.ComplexType) -> None:
|
|
||||||
self.wrap(type, "complex-type")
|
|
||||||
for member in type.members:
|
|
||||||
member.accept(self)
|
|
||||||
|
|
||||||
def visit_function_type(self, type: m.FunctionType) -> None:
|
def visit_function_type(self, type: m.FunctionType) -> None:
|
||||||
self.wrap(type, "function")
|
self.wrap(type, "function")
|
||||||
self._visit_param_spec(type.params)
|
self._visit_param_spec(type.params)
|
||||||
type.returns.accept(self)
|
type.returns.accept(self)
|
||||||
|
|
||||||
def visit_extension_type(self, type: m.ExtensionType) -> None:
|
|
||||||
self.wrap(type, "extension")
|
|
||||||
type.base.accept(self)
|
|
||||||
type.extension.accept(self)
|
|
||||||
|
|
||||||
def _visit_param_spec(self, spec: m.ParamSpec) -> None:
|
def _visit_param_spec(self, spec: m.ParamSpec) -> None:
|
||||||
for param in spec.pos + spec.mixed + spec.kw:
|
for param in spec.pos + spec.mixed + spec.kw:
|
||||||
param.type.accept(self)
|
param.type.accept(self)
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ span {
|
|||||||
|
|
||||||
&.named-type,
|
&.named-type,
|
||||||
&.generic-type,
|
&.generic-type,
|
||||||
&.constraint-type,
|
&.constraint-type {
|
||||||
&.complex-type {
|
|
||||||
--col: 150, 150, 150;
|
--col: 150, 150, 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,9 @@ from midas.checker.types import (
|
|||||||
BaseType,
|
BaseType,
|
||||||
ColumnGroupBy,
|
ColumnGroupBy,
|
||||||
ColumnType,
|
ColumnType,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
DataFrameType,
|
DataFrameType,
|
||||||
DerivedType,
|
DerivedType,
|
||||||
ExtensionType,
|
|
||||||
FrameGroupBy,
|
FrameGroupBy,
|
||||||
Function,
|
Function,
|
||||||
GenericType,
|
GenericType,
|
||||||
@@ -675,8 +673,6 @@ class Generator(p.Stmt.Visitor[ast.stmt], p.Expr.Visitor[ast.expr]):
|
|||||||
case (
|
case (
|
||||||
Function()
|
Function()
|
||||||
| OverloadedFunction()
|
| OverloadedFunction()
|
||||||
| ComplexType()
|
|
||||||
| ExtensionType()
|
|
||||||
| GenericType()
|
| GenericType()
|
||||||
| FrameGroupBy()
|
| FrameGroupBy()
|
||||||
| ColumnGroupBy()
|
| ColumnGroupBy()
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ from midas.checker.types import (
|
|||||||
BaseType,
|
BaseType,
|
||||||
ColumnGroupBy,
|
ColumnGroupBy,
|
||||||
ColumnType,
|
ColumnType,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
DataFrameType,
|
DataFrameType,
|
||||||
DerivedType,
|
DerivedType,
|
||||||
ExtensionType,
|
|
||||||
FrameGroupBy,
|
FrameGroupBy,
|
||||||
Function,
|
Function,
|
||||||
GenericType,
|
GenericType,
|
||||||
@@ -269,14 +267,6 @@ class StubsGenerator:
|
|||||||
right=self.dump_type(overloads[-1]),
|
right=self.dump_type(overloads[-1]),
|
||||||
)
|
)
|
||||||
|
|
||||||
case ComplexType():
|
|
||||||
name: str = self.new_stub_name()
|
|
||||||
self.generate_stub(name, type)
|
|
||||||
return ast.Name(id=name)
|
|
||||||
|
|
||||||
case ExtensionType():
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
case TypeVar():
|
case TypeVar():
|
||||||
return ast.Name(id=type.name)
|
return ast.Name(id=type.name)
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,9 @@ from midas.ast.midas import (
|
|||||||
AliasStmt,
|
AliasStmt,
|
||||||
BinaryExpr,
|
BinaryExpr,
|
||||||
CallExpr,
|
CallExpr,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
Expr,
|
Expr,
|
||||||
ExtendStmt,
|
ExtendStmt,
|
||||||
ExtensionType,
|
|
||||||
FrameType,
|
FrameType,
|
||||||
FunctionType,
|
FunctionType,
|
||||||
GenericType,
|
GenericType,
|
||||||
@@ -187,19 +185,9 @@ class MidasParser(Parser[list[Stmt]]):
|
|||||||
Returns:
|
Returns:
|
||||||
TypeExpr: the parsed type expression
|
TypeExpr: the parsed type expression
|
||||||
"""
|
"""
|
||||||
base: Type
|
|
||||||
if self.match(TokenType.FUNC):
|
if self.match(TokenType.FUNC):
|
||||||
base = self.function()
|
return self.function()
|
||||||
else:
|
return self.constraint_type()
|
||||||
base = self.constraint_type()
|
|
||||||
if self.match(TokenType.AND):
|
|
||||||
extension: ComplexType = self.complex_type()
|
|
||||||
return ExtensionType(
|
|
||||||
location=Location.span(base.location, extension.location),
|
|
||||||
base=base,
|
|
||||||
extension=extension,
|
|
||||||
)
|
|
||||||
return base
|
|
||||||
|
|
||||||
def constraint_type(self) -> Type:
|
def constraint_type(self) -> Type:
|
||||||
"""Parse a constraint type expression
|
"""Parse a constraint type expression
|
||||||
@@ -235,9 +223,6 @@ class MidasParser(Parser[list[Stmt]]):
|
|||||||
self.consume(TokenType.RIGHT_PAREN, "Unclosed parenthesis")
|
self.consume(TokenType.RIGHT_PAREN, "Unclosed parenthesis")
|
||||||
return type
|
return type
|
||||||
|
|
||||||
if self.check(TokenType.LEFT_BRACE):
|
|
||||||
return self.complex_type()
|
|
||||||
|
|
||||||
return self.generic_type()
|
return self.generic_type()
|
||||||
|
|
||||||
def generic_type(self) -> Type:
|
def generic_type(self) -> Type:
|
||||||
@@ -295,34 +280,6 @@ class MidasParser(Parser[list[Stmt]]):
|
|||||||
name=name,
|
name=name,
|
||||||
)
|
)
|
||||||
|
|
||||||
def complex_type(self) -> ComplexType:
|
|
||||||
"""Parse a complex type expression
|
|
||||||
|
|
||||||
A complex type consists of zero or more member statements enclosed in
|
|
||||||
curly braces
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ComplexType: the parsed complex type expression
|
|
||||||
"""
|
|
||||||
left: Token = self.consume(
|
|
||||||
TokenType.LEFT_BRACE, "Expected '{' to start type body"
|
|
||||||
)
|
|
||||||
members: list[MemberStmt] = []
|
|
||||||
# TODO: add keyword to differentiate properties and methods,
|
|
||||||
# and allow multiple methods with the same name but not properties
|
|
||||||
names: set[str] = set()
|
|
||||||
while not self.check(TokenType.RIGHT_BRACE) and not self.is_at_end():
|
|
||||||
member: MemberStmt = self.member_stmt()
|
|
||||||
# if member.name.lexeme in names:
|
|
||||||
# raise self.error(member.name, "Duplicate property")
|
|
||||||
# names.add(member.name.lexeme)
|
|
||||||
members.append(member)
|
|
||||||
right: Token = self.consume(TokenType.RIGHT_BRACE, "Unclosed type body")
|
|
||||||
return ComplexType(
|
|
||||||
location=left.location_to(right),
|
|
||||||
members=members,
|
|
||||||
)
|
|
||||||
|
|
||||||
def frame_type(self) -> FrameType:
|
def frame_type(self) -> FrameType:
|
||||||
"""Parse a frame type expression
|
"""Parse a frame type expression
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ from midas.ast.midas import (
|
|||||||
AliasStmt,
|
AliasStmt,
|
||||||
BinaryExpr,
|
BinaryExpr,
|
||||||
CallExpr,
|
CallExpr,
|
||||||
ComplexType,
|
|
||||||
ConstraintType,
|
ConstraintType,
|
||||||
Expr,
|
Expr,
|
||||||
ExtendStmt,
|
ExtendStmt,
|
||||||
ExtensionType,
|
|
||||||
FrameType,
|
FrameType,
|
||||||
FunctionType,
|
FunctionType,
|
||||||
GenericType,
|
GenericType,
|
||||||
@@ -172,12 +170,6 @@ class MidasAstJsonSerializer(
|
|||||||
"constraint": type.constraint.accept(self),
|
"constraint": type.constraint.accept(self),
|
||||||
}
|
}
|
||||||
|
|
||||||
def visit_complex_type(self, type: ComplexType) -> dict:
|
|
||||||
return {
|
|
||||||
"_type": "ComplexType",
|
|
||||||
"members": self._serialize_list(type.members),
|
|
||||||
}
|
|
||||||
|
|
||||||
def visit_function_type(self, type: FunctionType) -> dict:
|
def visit_function_type(self, type: FunctionType) -> dict:
|
||||||
return {
|
return {
|
||||||
"_type": "FunctionType",
|
"_type": "FunctionType",
|
||||||
@@ -200,13 +192,6 @@ class MidasAstJsonSerializer(
|
|||||||
"required": param.required,
|
"required": param.required,
|
||||||
}
|
}
|
||||||
|
|
||||||
def visit_extension_type(self, type: ExtensionType) -> dict:
|
|
||||||
return {
|
|
||||||
"_type": "ExtensionType",
|
|
||||||
"base": type.base.accept(self),
|
|
||||||
"extension": type.extension.accept(self),
|
|
||||||
}
|
|
||||||
|
|
||||||
def visit_frame_type(self, type: FrameType) -> dict:
|
def visit_frame_type(self, type: FrameType) -> dict:
|
||||||
return {
|
return {
|
||||||
"_type": "FrameType",
|
"_type": "FrameType",
|
||||||
|
|||||||
Reference in New Issue
Block a user