Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac620f318b
|
||
|
|
947e9f0149
|
@@ -28,3 +28,8 @@ bar: list[list[Meter]]
|
|||||||
bar.append([p2.x])
|
bar.append([p2.x])
|
||||||
|
|
||||||
foo2 = foo + foo
|
foo2 = foo + foo
|
||||||
|
|
||||||
|
a = foo[0]
|
||||||
|
b = bar[0][1]
|
||||||
|
c = bar[0][1][2] # invalid, not method __getitem__ on Meter
|
||||||
|
c = bar[""] # invalid, wrong index type
|
||||||
|
|||||||
@@ -143,4 +143,9 @@ class ListExpr:
|
|||||||
items: list[Expr]
|
items: list[Expr]
|
||||||
|
|
||||||
|
|
||||||
|
class SubscriptExpr:
|
||||||
|
object: Expr
|
||||||
|
index: Expr
|
||||||
|
|
||||||
|
|
||||||
###<
|
###<
|
||||||
|
|||||||
+11
-1
@@ -664,7 +664,7 @@ class PythonAstPrinter(
|
|||||||
def visit_literal_expr(self, expr: p.LiteralExpr) -> None:
|
def visit_literal_expr(self, expr: p.LiteralExpr) -> None:
|
||||||
self._write_line("LiteralExpr")
|
self._write_line("LiteralExpr")
|
||||||
with self._child_level(single=True):
|
with self._child_level(single=True):
|
||||||
self._write_line(f"value: {expr.value}")
|
self._write_line(f"value: {expr.value!r}")
|
||||||
|
|
||||||
def visit_variable_expr(self, expr: p.VariableExpr) -> None:
|
def visit_variable_expr(self, expr: p.VariableExpr) -> None:
|
||||||
self._write_line("VariableExpr")
|
self._write_line("VariableExpr")
|
||||||
@@ -719,3 +719,13 @@ class PythonAstPrinter(
|
|||||||
if i == len(expr.items) - 1:
|
if i == len(expr.items) - 1:
|
||||||
self._mark_last()
|
self._mark_last()
|
||||||
item.accept(self)
|
item.accept(self)
|
||||||
|
|
||||||
|
def visit_subscript_expr(self, expr: p.SubscriptExpr) -> None:
|
||||||
|
self._write_line("SubscriptExpr")
|
||||||
|
with self._child_level():
|
||||||
|
self._write_line("object")
|
||||||
|
with self._child_level(single=True):
|
||||||
|
expr.object.accept(self)
|
||||||
|
self._write_line("index", last=True)
|
||||||
|
with self._child_level(single=True):
|
||||||
|
expr.index.accept(self)
|
||||||
|
|||||||
@@ -224,6 +224,9 @@ class Expr(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_list_expr(self, expr: ListExpr) -> T: ...
|
def visit_list_expr(self, expr: ListExpr) -> T: ...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visit_subscript_expr(self, expr: SubscriptExpr) -> T: ...
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class BinaryExpr(Expr):
|
class BinaryExpr(Expr):
|
||||||
@@ -324,3 +327,12 @@ class ListExpr(Expr):
|
|||||||
|
|
||||||
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
return visitor.visit_list_expr(self)
|
return visitor.visit_list_expr(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class SubscriptExpr(Expr):
|
||||||
|
object: Expr
|
||||||
|
index: Expr
|
||||||
|
|
||||||
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
|
return visitor.visit_subscript_expr(self)
|
||||||
|
|||||||
+47
-15
@@ -356,7 +356,7 @@ class PythonTyper(
|
|||||||
|
|
||||||
match operation:
|
match operation:
|
||||||
case Function() as function:
|
case Function() as function:
|
||||||
if not self._is_binary_function(function):
|
if not self._check_arity(function, 1, 0, 0):
|
||||||
self.reporter.error(
|
self.reporter.error(
|
||||||
location,
|
location,
|
||||||
f"Wrong definition of binary operation. Expected function with 1 positional-only parameters, got {function}",
|
f"Wrong definition of binary operation. Expected function with 1 positional-only parameters, got {function}",
|
||||||
@@ -395,7 +395,7 @@ class PythonTyper(
|
|||||||
|
|
||||||
match operation:
|
match operation:
|
||||||
case Function() as function:
|
case Function() as function:
|
||||||
if not self._is_unary_function(function):
|
if not self._check_arity(function, 0, 0, 0):
|
||||||
self.reporter.error(
|
self.reporter.error(
|
||||||
expr.location,
|
expr.location,
|
||||||
f"Wrong definition of unary operation. Expected function with 0 parameters, got {function}",
|
f"Wrong definition of unary operation. Expected function with 0 parameters, got {function}",
|
||||||
@@ -512,6 +512,41 @@ class PythonTyper(
|
|||||||
)
|
)
|
||||||
return self.types.apply_generic(list_type, [UnknownType()])
|
return self.types.apply_generic(list_type, [UnknownType()])
|
||||||
|
|
||||||
|
def visit_subscript_expr(self, expr: p.SubscriptExpr) -> Type:
|
||||||
|
object: Type = self.type_of(expr.object)
|
||||||
|
operation: Optional[Type] = self.types.lookup_member(object, "__getitem__")
|
||||||
|
if operation is None:
|
||||||
|
self.reporter.error(
|
||||||
|
expr.location,
|
||||||
|
f"Undefined method __getitem__ on {object}",
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
|
||||||
|
index: Type = self.type_of(expr.index)
|
||||||
|
|
||||||
|
match operation:
|
||||||
|
case Function() as function:
|
||||||
|
if not self._check_arity(function, 1, 0, 0):
|
||||||
|
self.reporter.error(
|
||||||
|
expr.location,
|
||||||
|
f"Wrong definition of __getitem__. Expected function with 1 positional-only parameters, got {function}",
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
|
||||||
|
index_arg: Function.Argument = function.pos_args[0]
|
||||||
|
if not self.is_subtype(index, index_arg.type):
|
||||||
|
self.reporter.error(
|
||||||
|
expr.location,
|
||||||
|
f"Wrong index type, expected {index_arg.type}, got {index}",
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
return function.returns
|
||||||
|
case _:
|
||||||
|
self.reporter.warning(
|
||||||
|
expr.location, f"Unsupported operation {operation}"
|
||||||
|
)
|
||||||
|
return UnknownType()
|
||||||
|
|
||||||
def visit_base_type(self, node: p.BaseType) -> Type:
|
def visit_base_type(self, node: p.BaseType) -> Type:
|
||||||
base: Type
|
base: Type
|
||||||
try:
|
try:
|
||||||
@@ -654,20 +689,17 @@ class PythonTyper(
|
|||||||
|
|
||||||
return mapped
|
return mapped
|
||||||
|
|
||||||
def _is_binary_function(self, function: Function) -> bool:
|
def _check_arity(
|
||||||
if len(function.pos_args) != 1:
|
self,
|
||||||
|
function: Function,
|
||||||
|
n_pos: Optional[int] = None,
|
||||||
|
n_mixed: Optional[int] = None,
|
||||||
|
n_keyword: Optional[int] = None,
|
||||||
|
) -> bool:
|
||||||
|
if n_pos is not None and len(function.pos_args) != n_pos:
|
||||||
return False
|
return False
|
||||||
if len(function.args) != 0:
|
if n_mixed is not None and len(function.args) != n_mixed:
|
||||||
return False
|
return False
|
||||||
if len(function.kw_args) != 0:
|
if n_keyword is not None and len(function.kw_args) != n_keyword:
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _is_unary_function(self, function: Function) -> bool:
|
|
||||||
if len(function.pos_args) != 0:
|
|
||||||
return False
|
|
||||||
if len(function.args) != 0:
|
|
||||||
return False
|
|
||||||
if len(function.kw_args) != 0:
|
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -196,3 +196,7 @@ class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
|
|||||||
def visit_list_expr(self, expr: p.ListExpr) -> None:
|
def visit_list_expr(self, expr: p.ListExpr) -> None:
|
||||||
for item in expr.items:
|
for item in expr.items:
|
||||||
self.resolve(item)
|
self.resolve(item)
|
||||||
|
|
||||||
|
def visit_subscript_expr(self, expr: p.SubscriptExpr) -> None:
|
||||||
|
self.resolve(expr.object)
|
||||||
|
self.resolve(expr.index)
|
||||||
|
|||||||
@@ -218,6 +218,10 @@ class PythonHighlighter(
|
|||||||
for item in expr.items:
|
for item in expr.items:
|
||||||
item.accept(self)
|
item.accept(self)
|
||||||
|
|
||||||
|
def visit_subscript_expr(self, expr: p.SubscriptExpr) -> None:
|
||||||
|
expr.object.accept(self)
|
||||||
|
expr.index.accept(self)
|
||||||
|
|
||||||
|
|
||||||
class MidasHighlighter(
|
class MidasHighlighter(
|
||||||
Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[None]
|
Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[None]
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from midas.ast.python import (
|
|||||||
MidasType,
|
MidasType,
|
||||||
ReturnStmt,
|
ReturnStmt,
|
||||||
Stmt,
|
Stmt,
|
||||||
|
SubscriptExpr,
|
||||||
TernaryExpr,
|
TernaryExpr,
|
||||||
TypeAssign,
|
TypeAssign,
|
||||||
UnaryExpr,
|
UnaryExpr,
|
||||||
@@ -423,6 +424,13 @@ class PythonParser:
|
|||||||
items=[self.parse_expr(item) for item in items],
|
items=[self.parse_expr(item) for item in items],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
case ast.Subscript(value=value, slice=index):
|
||||||
|
return SubscriptExpr(
|
||||||
|
location=location,
|
||||||
|
object=self.parse_expr(value),
|
||||||
|
index=self.parse_expr(index),
|
||||||
|
)
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
raise UnsupportedSyntaxError(node)
|
raise UnsupportedSyntaxError(node)
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from midas.ast.python import (
|
|||||||
MidasType,
|
MidasType,
|
||||||
ReturnStmt,
|
ReturnStmt,
|
||||||
Stmt,
|
Stmt,
|
||||||
|
SubscriptExpr,
|
||||||
TernaryExpr,
|
TernaryExpr,
|
||||||
TypeAssign,
|
TypeAssign,
|
||||||
UnaryExpr,
|
UnaryExpr,
|
||||||
@@ -252,3 +253,10 @@ class PythonAstJsonSerializer(
|
|||||||
"_type": "ListExpr",
|
"_type": "ListExpr",
|
||||||
"items": [item.accept(self) for item in expr.items],
|
"items": [item.accept(self) for item in expr.items],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def visit_subscript_expr(self, expr: SubscriptExpr) -> dict:
|
||||||
|
return {
|
||||||
|
"_type": "SubscriptExpr",
|
||||||
|
"object": expr.object.accept(self),
|
||||||
|
"index": expr.index.accept(self),
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user