Merge pull request 'Minor fixes and more tests' (#38) from feat/add-tests into main
All checks were successful
Tests / tests (push) Successful in 5s

Reviewed-on: #38
This commit was merged in pull request #38.
This commit is contained in:
2026-07-09 20:19:42 +00:00
25 changed files with 6499 additions and 23 deletions

View File

@@ -1,6 +1,9 @@
from typing import final
import midas.ast.midas as m
@final
class MidasPrinter(
m.Expr.Visitor[str],
m.Stmt.Visitor[str],

View File

@@ -1,7 +1,10 @@
from typing import final
import midas.ast.midas as m
from midas.ast.printer.base import AstPrinter
@final
class MidasAstPrinter(
AstPrinter,
m.Expr.Visitor[None],

View File

@@ -1,9 +1,11 @@
import ast
from typing import final
import midas.ast.python as p
from midas.ast.printer.base import AstPrinter
@final
class PythonAstPrinter(
AstPrinter,
p.MidasType.Visitor[None],
@@ -115,6 +117,24 @@ class PythonAstPrinter(
stmt.iterator.accept(self)
self._write_sequence("body", stmt.body, last=True)
def visit_import_stmt(self, stmt: p.ImportStmt) -> None:
self._write_line("ImportStmt")
with self._child_level(single=True):
self._write_sequence("imports", stmt.imports, print_func=self._print_import)
def visit_from_import_stmt(self, stmt: p.FromImportStmt) -> None:
self._write_line("FromImportStmt")
with self._child_level():
self._write_line(f'module: "{stmt.module}"')
self._write_sequence("imports", stmt.imports, print_func=self._print_import)
self._write_line(f"level: {stmt.level}", last=True)
def _print_import(self, import_: p.ImportAlias) -> None:
self._write_line("ImportAlias")
with self._child_level():
self._write_line(f'name: "{import_.name}"')
self._write_line(f'alias: "{import_.alias}"')
def visit_raw_stmt(self, stmt: p.RawStmt) -> None:
self._write_line("RawStmt")
with self._child_level(single=True):

View File

@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Any, Callable, Optional
from typing import Any, Callable, Optional, final
import midas.ast.midas as m
from midas.ast.location import Location
@@ -18,6 +18,7 @@ class PartialPredicate(Predicate):
"""A dictionary of already applied parameters"""
@final
class Evaluator(m.Expr.Visitor[Any]):
"""Helper class to evaluate an expression

View File

@@ -1,6 +1,6 @@
import logging
from pathlib import Path
from typing import Optional
from typing import Optional, final
import midas.ast.midas as m
from midas.ast.location import Location
@@ -30,6 +30,7 @@ from midas.lexer.token import Token, TokenType
from midas.parser.midas import MidasParser
@final
class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type]):
"""A resolver which evaluates Midas type definitions and build a registry"""
@@ -110,7 +111,7 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
return self._local_variables[name]
return self.types.get_type(name)
def get_variable(self, name: str) -> Type:
def get_variable(self, location: Location, name: str) -> Type:
"""Get the type of a variable
This function will first look into the current predicate's parameters if
@@ -118,11 +119,9 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
The the variable is looked up in the preamble (i.e. global environment)
Args:
location (Location): the location of the variable reference
name (str): the name of the variable
Raises:
NameError: if the variable cannot be found
Returns:
Type: the type of the variable
"""
@@ -136,7 +135,8 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
if global_ is not None:
return global_
raise NameError(f"Unknown variable '{name}'")
self.reporter.error(location, f"Unknown variable '{name}'")
return UnknownType()
def resolve(self, stmts: list[m.Stmt]):
"""Process a sequence of statements
@@ -293,6 +293,9 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
return result.result
def visit_unary_expr(self, expr: m.UnaryExpr) -> Type:
# First evaluate operand to surface all errors
operand: Type = self.type_of(expr.right)
# Special case because there is no __not__ dunder method
match expr.operator:
case Token(type=TokenType.BANG):
@@ -306,7 +309,6 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
)
return UnknownType()
operand: Type = self.type_of(expr.right)
operation: Optional[Type] = self.types.lookup_member(operand, method)
if operation is None:
self.reporter.error(
@@ -350,7 +352,7 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
return member
def visit_variable_expr(self, expr: m.VariableExpr) -> Type:
return self.get_variable(expr.name.lexeme)
return self.get_variable(expr.location, expr.name.lexeme)
def visit_grouping_expr(self, expr: m.GroupingExpr) -> Type:
return expr.expr.accept(self)
@@ -365,12 +367,14 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
return self.types.get_type("float")
case str():
return self.types.get_type("str")
case None:
return self.types.get_type("None")
case _:
self.reporter.warning(expr.location, f"Unknown literal {expr}")
return UnknownType()
def visit_wildcard_expr(self, expr: m.WildcardExpr) -> Type:
return self.get_variable("_")
return self.get_variable(expr.location, "_")
def visit_named_type(self, type: m.NamedType) -> Type:
name: str = type.name.lexeme
@@ -409,7 +413,7 @@ class MidasTyper(m.Stmt.Visitor[None], m.Expr.Visitor[Type], m.Type.Visitor[Type
self._predicate_params = {}
if not self.types.is_subtype(constraint_type, self._bool):
self.reporter.error(
type.location,
type.constraint.location,
f"Constraint must evaluate to a boolean, got {constraint_type}",
)

View File

@@ -1,6 +1,6 @@
import ast
import logging
from typing import Any, Optional
from typing import Any, Optional, final
import midas.ast.python as p
from midas.ast.location import Location
@@ -55,6 +55,7 @@ class UndefinedMethodException(Exception):
pass
@final
class PythonTyper(
p.Stmt.Visitor[None],
p.Expr.Visitor[Type],

View File

@@ -1,3 +1,5 @@
from typing import final
import midas.ast.python as p
from midas.ast.location import Location
from midas.checker.reporter import FileReporter
@@ -6,6 +8,7 @@ from midas.checker.reporter import FileReporter
class ResolverError(Exception): ...
@final
class Resolver(p.Stmt.Visitor[None], p.Expr.Visitor[None]):
"""A variable assignment and reference resolver

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from pathlib import Path
from typing import Generic, Optional, Protocol, TextIO, TypeVar
from typing import Generic, Optional, Protocol, TextIO, TypeVar, final
import midas.ast.midas as m
import midas.ast.python as p
@@ -121,6 +121,7 @@ class Highlighter(ABC):
self.openings.setdefault((l + 1, 0), []).append(opening)
@final
class PythonHighlighter(
Highlighter,
p.MidasType.Visitor[None],
@@ -197,6 +198,10 @@ class PythonHighlighter(
for body_stmt in stmt.body:
body_stmt.accept(self)
def visit_import_stmt(self, stmt: p.ImportStmt) -> None: ...
def visit_from_import_stmt(self, stmt: p.FromImportStmt) -> None: ...
def visit_binary_expr(self, expr: p.BinaryExpr) -> None: ...
def visit_compare_expr(self, expr: p.CompareExpr) -> None: ...
@@ -255,6 +260,7 @@ class PythonHighlighter(
def visit_raw_stmt(self, stmt: p.RawStmt) -> None: ...
@final
class MidasHighlighter(
Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None], m.Type.Visitor[None]
):
@@ -263,6 +269,11 @@ class MidasHighlighter(
def highlight(self, node: Highlightable[MidasHighlighter]):
node.accept(self)
def visit_alias_stmt(self, stmt: m.AliasStmt) -> None:
self.wrap(stmt, "alias-stmt")
self.wrap(LocatableToken(stmt.name), "type-name")
stmt.type.accept(self)
def visit_type_stmt(self, stmt: m.TypeStmt) -> None:
self.wrap(stmt, "type-stmt")
self.wrap(LocatableToken(stmt.name), "type-name")
@@ -352,6 +363,7 @@ class MidasHighlighter(
self.wrap(column, "column")
@final
class DiagnosticsHighlighter(Highlighter):
EXTRA_CSS_PATH: Optional[Path] = Path(__file__).parent / "hl_diagnostic.css"

View File

@@ -1,5 +1,5 @@
import ast
from typing import Optional
from typing import Optional, final
import midas.ast.midas as m
from midas.checker.registry import TypesRegistry
@@ -39,6 +39,7 @@ COMPARISON_OPERATORS: dict[TokenType, type[ast.cmpop]] = {
}
@final
class ConstraintGenerator(m.Expr.Visitor[ast.expr]):
"""Class to generate Python code for constraint expressions"""

View File

@@ -3,7 +3,7 @@ import logging
import shutil
from dataclasses import dataclass, field
from pathlib import Path
from typing import Optional, assert_never
from typing import Optional, assert_never, final
import midas.ast.midas as m
import midas.ast.python as p
@@ -47,6 +47,7 @@ class Scope:
"""A list of aliases defined in the scope, that can be discard afterwards"""
@final
class Generator(p.Stmt.Visitor[ast.stmt], p.Expr.Visitor[ast.expr]):
"""
A class to translate the custom Python AST back into raw `ast` nodes

View File

@@ -0,0 +1,44 @@
def a1(param: int) -> float: ...
def a2(param: float) -> int: ...
a = a1
a = a2
def b1(a: int, /) -> float: ...
def b2(b: float, /) -> int: ...
b = b1
b = b2
def c1(a: int) -> None: ...
def c2(p: float = 0, /, *, a: float = 0) -> None: ...
c = c1
c = c2
# Invalid subtypes
def d1(a: int) -> float: ...
def d2(a: str) -> float: ...
def d3(a: int) -> str: ...
d = d1
d = d2
d = d3
def e1(*, a: int = 0) -> None: ...
def e2(*, a: int) -> None: ...
def e3(*, a: int = 0, b: int) -> None: ...
e = e1
e = e2
e = e3

View File

@@ -0,0 +1,881 @@
{
"diagnostics": [
{
"type": "Warning",
"location": {
"start": [
1,
29
],
"end": [
1,
32
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=1, col_offset=29, end_lineno=1, end_col_offset=32), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
1,
22
],
"end": [
1,
27
]
},
"message": "Return type mismatch, annotated float but returns None"
},
{
"type": "Warning",
"location": {
"start": [
2,
29
],
"end": [
2,
32
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=2, col_offset=29, end_lineno=2, end_col_offset=32), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
2,
24
],
"end": [
2,
27
]
},
"message": "Return type mismatch, annotated int but returns None"
},
{
"type": "Warning",
"location": {
"start": [
9,
28
],
"end": [
9,
31
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=9, col_offset=28, end_lineno=9, end_col_offset=31), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
9,
21
],
"end": [
9,
26
]
},
"message": "Return type mismatch, annotated float but returns None"
},
{
"type": "Warning",
"location": {
"start": [
10,
28
],
"end": [
10,
31
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=10, col_offset=28, end_lineno=10, end_col_offset=31), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
10,
23
],
"end": [
10,
26
]
},
"message": "Return type mismatch, annotated int but returns None"
},
{
"type": "Warning",
"location": {
"start": [
17,
24
],
"end": [
17,
27
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=17, col_offset=24, end_lineno=17, end_col_offset=27), value=Ellipsis)"
},
{
"type": "Warning",
"location": {
"start": [
18,
50
],
"end": [
18,
53
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=18, col_offset=50, end_lineno=18, end_col_offset=53), value=Ellipsis)"
},
{
"type": "Warning",
"location": {
"start": [
27,
25
],
"end": [
27,
28
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=27, col_offset=25, end_lineno=27, end_col_offset=28), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
27,
18
],
"end": [
27,
23
]
},
"message": "Return type mismatch, annotated float but returns None"
},
{
"type": "Warning",
"location": {
"start": [
28,
25
],
"end": [
28,
28
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=28, col_offset=25, end_lineno=28, end_col_offset=28), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
28,
18
],
"end": [
28,
23
]
},
"message": "Return type mismatch, annotated float but returns None"
},
{
"type": "Warning",
"location": {
"start": [
29,
23
],
"end": [
29,
26
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=29, col_offset=23, end_lineno=29, end_col_offset=26), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
29,
18
],
"end": [
29,
21
]
},
"message": "Return type mismatch, annotated str but returns None"
},
{
"type": "Error",
"location": {
"start": [
33,
0
],
"end": [
33,
6
]
},
"message": "Cannot assign (a: str) -> float to variable 'd' of type (a: int) -> float"
},
{
"type": "Error",
"location": {
"start": [
34,
0
],
"end": [
34,
6
]
},
"message": "Cannot assign (a: int) -> str to variable 'd' of type (a: int) -> float"
},
{
"type": "Warning",
"location": {
"start": [
37,
31
],
"end": [
37,
34
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=37, col_offset=31, end_lineno=37, end_col_offset=34), value=Ellipsis)"
},
{
"type": "Warning",
"location": {
"start": [
38,
27
],
"end": [
38,
30
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=38, col_offset=27, end_lineno=38, end_col_offset=30), value=Ellipsis)"
},
{
"type": "Warning",
"location": {
"start": [
39,
39
],
"end": [
39,
42
]
},
"message": "Unknown literal LiteralExpr(location=Location(lineno=39, col_offset=39, end_lineno=39, end_col_offset=42), value=Ellipsis)"
},
{
"type": "Error",
"location": {
"start": [
43,
0
],
"end": [
43,
6
]
},
"message": "Cannot assign (*, a: int) -> None to variable 'e' of type (*, a: int?) -> None"
},
{
"type": "Error",
"location": {
"start": [
44,
0
],
"end": [
44,
6
]
},
"message": "Cannot assign (*, a: int?, b: int) -> None to variable 'e' of type (*, a: int?) -> None"
}
],
"judgments": [
{
"location": {
"from": "L1:29",
"to": "L1:32"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L2:29",
"to": "L2:32"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L5:4",
"to": "L5:6"
},
"expr": {
"_type": "VariableExpr",
"name": "a1"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "param",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {
"name": "float"
}
}
},
{
"location": {
"from": "L6:4",
"to": "L6:6"
},
"expr": {
"_type": "VariableExpr",
"name": "a2"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "param",
"type": {
"name": "float"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {
"name": "int"
}
}
},
{
"location": {
"from": "L9:28",
"to": "L9:31"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L10:28",
"to": "L10:31"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L13:4",
"to": "L13:6"
},
"expr": {
"_type": "VariableExpr",
"name": "b1"
},
"type": {
"params": {
"pos": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
],
"mixed": [],
"kw": []
},
"returns": {
"name": "float"
}
}
},
{
"location": {
"from": "L14:4",
"to": "L14:6"
},
"expr": {
"_type": "VariableExpr",
"name": "b2"
},
"type": {
"params": {
"pos": [
{
"pos": 0,
"name": "b",
"type": {
"name": "float"
},
"required": true,
"unsupported": false
}
],
"mixed": [],
"kw": []
},
"returns": {
"name": "int"
}
}
},
{
"location": {
"from": "L17:24",
"to": "L17:27"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L18:18",
"to": "L18:19"
},
"expr": {
"_type": "LiteralExpr",
"value": 0
},
"type": {
"name": "int"
}
},
{
"location": {
"from": "L18:38",
"to": "L18:39"
},
"expr": {
"_type": "LiteralExpr",
"value": 0
},
"type": {
"name": "int"
}
},
{
"location": {
"from": "L18:50",
"to": "L18:53"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L21:4",
"to": "L21:6"
},
"expr": {
"_type": "VariableExpr",
"name": "c1"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {}
}
},
{
"location": {
"from": "L22:4",
"to": "L22:6"
},
"expr": {
"_type": "VariableExpr",
"name": "c2"
},
"type": {
"params": {
"pos": [
{
"pos": 0,
"name": "p",
"type": {
"name": "float"
},
"required": false,
"unsupported": false
}
],
"mixed": [],
"kw": [
{
"pos": 1,
"name": "a",
"type": {
"name": "float"
},
"required": false,
"unsupported": false
}
]
},
"returns": {}
}
},
{
"location": {
"from": "L27:25",
"to": "L27:28"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L28:25",
"to": "L28:28"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L29:23",
"to": "L29:26"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L32:4",
"to": "L32:6"
},
"expr": {
"_type": "VariableExpr",
"name": "d1"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {
"name": "float"
}
}
},
{
"location": {
"from": "L33:4",
"to": "L33:6"
},
"expr": {
"_type": "VariableExpr",
"name": "d2"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "a",
"type": {
"name": "str"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {
"name": "float"
}
}
},
{
"location": {
"from": "L34:4",
"to": "L34:6"
},
"expr": {
"_type": "VariableExpr",
"name": "d3"
},
"type": {
"params": {
"pos": [],
"mixed": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
],
"kw": []
},
"returns": {
"name": "str"
}
}
},
{
"location": {
"from": "L37:19",
"to": "L37:20"
},
"expr": {
"_type": "LiteralExpr",
"value": 0
},
"type": {
"name": "int"
}
},
{
"location": {
"from": "L37:31",
"to": "L37:34"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L38:27",
"to": "L38:30"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L39:19",
"to": "L39:20"
},
"expr": {
"_type": "LiteralExpr",
"value": 0
},
"type": {
"name": "int"
}
},
{
"location": {
"from": "L39:39",
"to": "L39:42"
},
"expr": {
"_type": "LiteralExpr",
"value": "..."
},
"type": {}
},
{
"location": {
"from": "L42:4",
"to": "L42:6"
},
"expr": {
"_type": "VariableExpr",
"name": "e1"
},
"type": {
"params": {
"pos": [],
"mixed": [],
"kw": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": false,
"unsupported": false
}
]
},
"returns": {}
}
},
{
"location": {
"from": "L43:4",
"to": "L43:6"
},
"expr": {
"_type": "VariableExpr",
"name": "e2"
},
"type": {
"params": {
"pos": [],
"mixed": [],
"kw": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
]
},
"returns": {}
}
},
{
"location": {
"from": "L44:4",
"to": "L44:6"
},
"expr": {
"_type": "VariableExpr",
"name": "e3"
},
"type": {
"params": {
"pos": [],
"mixed": [],
"kw": [
{
"pos": 0,
"name": "a",
"type": {
"name": "int"
},
"required": false,
"unsupported": false
},
{
"pos": 1,
"name": "b",
"type": {
"name": "int"
},
"required": true,
"unsupported": false
}
]
},
"returns": {}
}
}
]
}

View File

@@ -0,0 +1,49 @@
# type: ignore
# ruff: disable[F821]
import module1
import module2 as alias2
from module3 import submodule3
from module4 import submodule4 as alias4
a: int
b: Generic[int]
c: Generic2[int, float]
d: Frame[a:int, b:float]
e = 3
f: int = 4
g = []
h = [1, 0.1, " ", None, False, True]
i = {}
j = {"a": 1, "b": 2}
k = {"c": 3, **j}
l = cast(int, a)
m = unsafe_cast(int, a)
def n(a: int, /, b: float, *, c: str) -> Any:
return
def o(a: int = 1, /, b: float = 2.0, *, c: str = "") -> Any:
return 1
for i in h:
pass
if e == f:
pass
elif f == g:
pass
else:
pass
p = +a + -b - ~c * d / e**f
q = not (a and b) or c
r = a & b | c ^ d
s = a.b.c
t = a[b][c, d][e:f]
u = a(b)(c=d)

View File

@@ -0,0 +1,249 @@
Module(
body=[
Import(
names=[
alias(name='module1')]),
Import(
names=[
alias(name='module2', asname='alias2')]),
ImportFrom(
module='module3',
names=[
alias(name='submodule3')],
level=0),
ImportFrom(
module='module4',
names=[
alias(name='submodule4', asname='alias4')],
level=0),
Assign(
targets=[
Name(id='e')],
value=Constant(value=3)),
Assign(
targets=[
Name(id='f')],
value=Constant(value=4)),
Assign(
targets=[
Name(id='g')],
value=List(elts=[])),
Assign(
targets=[
Name(id='h')],
value=List(
elts=[
Constant(value=1),
Constant(value=0.1),
Constant(value=' '),
Constant(value=None),
Constant(value=False),
Constant(value=True)])),
Assign(
targets=[
Name(id='i')],
value=Dict(keys=[], values=[])),
Assign(
targets=[
Name(id='j')],
value=Dict(
keys=[
Constant(value='a'),
Constant(value='b')],
values=[
Constant(value=1),
Constant(value=2)])),
Assign(
targets=[
Name(id='k')],
value=Dict(
keys=[
Constant(value='c'),
None],
values=[
Constant(value=3),
Name(id='j')])),
Assign(
targets=[
Name(id='__midas_a0__')],
value=Name(id='a')),
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='__midas_a0__'),
Name(id='int')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='03_simple_syntax.py:L21:5: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a0__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=' to int')])),
Assign(
targets=[
Name(id='l')],
value=Name(id='__midas_a0__')),
Delete(
targets=[
Name(id='__midas_a0__')]),
Assign(
targets=[
Name(id='m')],
value=Name(id='a')),
FunctionDef(
name='n',
args=arguments(
posonlyargs=[
arg(arg='a')],
args=[
arg(arg='b')],
kwonlyargs=[
arg(arg='c')],
kw_defaults=[
None],
defaults=[]),
body=[
Return()],
decorator_list=[]),
FunctionDef(
name='o',
args=arguments(
posonlyargs=[
arg(arg='a')],
args=[
arg(arg='b')],
kwonlyargs=[
arg(arg='c')],
kw_defaults=[
Constant(value='')],
defaults=[
Constant(value=1),
Constant(value=2.0)]),
body=[
Return(
value=Constant(value=1))],
decorator_list=[]),
For(
target=Name(id='i'),
iter=Name(id='h'),
body=[
Pass()],
orelse=[]),
If(
test=Compare(
left=Name(id='e'),
ops=[
Eq()],
comparators=[
Name(id='f')]),
body=[
Pass()],
orelse=[
If(
test=Compare(
left=Name(id='f'),
ops=[
Eq()],
comparators=[
Name(id='g')]),
body=[
Pass()],
orelse=[])]),
Assign(
targets=[
Name(id='p')],
value=BinOp(
left=BinOp(
left=UnaryOp(
op=UAdd(),
operand=Name(id='a')),
op=Add(),
right=UnaryOp(
op=USub(),
operand=Name(id='b'))),
op=Sub(),
right=BinOp(
left=BinOp(
left=UnaryOp(
op=Invert(),
operand=Name(id='c')),
op=Mult(),
right=Name(id='d')),
op=Div(),
right=BinOp(
left=Name(id='e'),
op=Pow(),
right=Name(id='f'))))),
Assign(
targets=[
Name(id='q')],
value=BoolOp(
op=Or(),
values=[
UnaryOp(
op=Not(),
operand=BoolOp(
op=And(),
values=[
Name(id='a'),
Name(id='b')])),
Name(id='c')])),
Assign(
targets=[
Name(id='r')],
value=BinOp(
left=BinOp(
left=Name(id='a'),
op=BitAnd(),
right=Name(id='b')),
op=BitOr(),
right=BinOp(
left=Name(id='c'),
op=BitXor(),
right=Name(id='d')))),
Assign(
targets=[
Name(id='s')],
value=Attribute(
value=Attribute(
value=Name(id='a'),
attr='b'),
attr='c')),
Assign(
targets=[
Name(id='t')],
value=Subscript(
value=Subscript(
value=Subscript(
value=Name(id='a'),
slice=Name(id='b')),
slice=Tuple(
elts=[
Name(id='c'),
Name(id='d')])),
slice=Slice(
lower=Name(id='e'),
upper=Name(id='f')))),
Assign(
targets=[
Name(id='u')],
value=Call(
func=Call(
func=Name(id='a'),
args=[
Name(id='b')],
keywords=[]),
args=[],
keywords=[
keyword(
arg='c',
value=Name(id='d'))]))],
type_ignores=[])

View File

@@ -0,0 +1,15 @@
predicate is_positive(v: float) = v >= 0
type Positive = float where is_positive(_)
alias T1 = Frame[
a: int
]
alias T2 = Frame[
a: int,
b: str,
c: Positive,
d: float where is_positive(_)
]
alias Positives = Column[Positive]

View File

@@ -0,0 +1,13 @@
from typing import Any
from midas import T1, T2, Column, Positive, Positives, cast
o: Any = object()
df1 = cast(T1, o)
df2 = cast(T2, o)
df1 + df2
col1: Positives = df2["c"]
col2 = cast(Column[Positive], col1)

View File

@@ -0,0 +1,731 @@
Module(
body=[
FunctionDef(
name='__midas_column_same_length__',
args=arguments(
posonlyargs=[],
args=[
arg(arg='column1'),
arg(arg='column2')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Compare(
left=Call(
func=Name(id='len'),
args=[
Attribute(
value=Name(id='column1'),
attr='index')],
keywords=[]),
ops=[
Eq()],
comparators=[
Call(
func=Name(id='len'),
args=[
Attribute(
value=Name(id='column2'),
attr='index')],
keywords=[])]))],
decorator_list=[]),
FunctionDef(
name='__midas_frame_same_length__',
args=arguments(
posonlyargs=[],
args=[
arg(arg='frame1'),
arg(arg='frame2')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Compare(
left=Call(
func=Name(id='len'),
args=[
Attribute(
value=Name(id='frame1'),
attr='index')],
keywords=[]),
ops=[
Eq()],
comparators=[
Call(
func=Name(id='len'),
args=[
Attribute(
value=Name(id='frame2'),
attr='index')],
keywords=[])]))],
decorator_list=[]),
FunctionDef(
name='__midas_is_column__',
args=arguments(
posonlyargs=[
arg(arg='obj')],
args=[],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Import(
names=[
alias(name='pandas', asname='pd')]),
Return(
value=Call(
func=Name(id='isinstance'),
args=[
Name(id='obj'),
Attribute(
value=Name(id='pd'),
attr='Series')],
keywords=[]))],
decorator_list=[],
returns=Name(id='bool')),
FunctionDef(
name='__midas_is_dataframe__',
args=arguments(
posonlyargs=[
arg(arg='obj')],
args=[],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Import(
names=[
alias(name='pandas', asname='pd')]),
Return(
value=Call(
func=Name(id='isinstance'),
args=[
Name(id='obj'),
Attribute(
value=Name(id='pd'),
attr='DataFrame')],
keywords=[]))],
decorator_list=[],
returns=Name(id='bool')),
FunctionDef(
name='__midas_is_positive__',
args=arguments(
posonlyargs=[],
args=[
arg(
arg='v',
annotation=Constant(value='float'))],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Compare(
left=Name(id='v'),
ops=[
GtE()],
comparators=[
Constant(value=0)]))],
decorator_list=[],
returns=Constant(value='bool')),
FunctionDef(
name='__midas_p0__',
args=arguments(
posonlyargs=[],
args=[
arg(
arg='_',
annotation=Constant(value='Any'))],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Call(
func=Name(id='__midas_is_positive__'),
args=[
Name(id='_')],
keywords=[]))],
decorator_list=[],
returns=Constant(value='bool')),
FunctionDef(
name='__midas_p1__',
args=arguments(
posonlyargs=[],
args=[
arg(
arg='_',
annotation=Constant(value='Any'))],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
body=[
Return(
value=Call(
func=Name(id='__midas_is_positive__'),
args=[
Name(id='_')],
keywords=[]))],
decorator_list=[],
returns=Constant(value='bool')),
ImportFrom(
module='typing',
names=[
alias(name='Any')],
level=0),
ImportFrom(
module='midas',
names=[
alias(name='T1'),
alias(name='T2'),
alias(name='Column'),
alias(name='Positive'),
alias(name='Positives'),
alias(name='cast')],
level=0),
Assign(
targets=[
Name(id='o')],
value=Call(
func=Name(id='object'),
args=[],
keywords=[])),
Assign(
targets=[
Name(id='__midas_a0__')],
value=Name(id='o')),
Assert(
test=Call(
func=Name(id='__midas_is_dataframe__'),
args=[
Name(id='__midas_a0__')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L7:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a0__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=' to Frame[a: Column[int]]: Not a dataframe')])),
Assert(
test=Compare(
left=Constant(value='a'),
ops=[
In()],
comparators=[
Name(id='__midas_a0__')]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L7:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a0__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Frame[a: Column[int]]: Missing column 'a'")])),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Subscript(
value=Name(id='__midas_a0__'),
slice=Constant(value='a'))],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L7:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Subscript(
value=Name(id='__midas_a0__'),
slice=Constant(value='a'))],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Column[int], in column 'a': Not a column")])),
For(
target=Name(id='value'),
iter=Subscript(
value=Name(id='__midas_a0__'),
slice=Constant(value='a')),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='int')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L7:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to int, in column 'a'")]))],
orelse=[]),
Assign(
targets=[
Name(id='df1')],
value=Name(id='__midas_a0__')),
Delete(
targets=[
Name(id='__midas_a0__')]),
Assign(
targets=[
Name(id='__midas_a1__')],
value=Name(id='o')),
Assert(
test=Call(
func=Name(id='__midas_is_dataframe__'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=' to Frame[a: Column[int], b: Column[str], c: Column[Positive], d: Column[float where is_positive(_)]]: Not a dataframe')])),
Assert(
test=Compare(
left=Constant(value='a'),
ops=[
In()],
comparators=[
Name(id='__midas_a1__')]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Frame[a: Column[int], b: Column[str], c: Column[Positive], d: Column[float where is_positive(_)]]: Missing column 'a'")])),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='a'))],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='a'))],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Column[int], in column 'a': Not a column")])),
For(
target=Name(id='value'),
iter=Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='a')),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='int')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to int, in column 'a'")]))],
orelse=[]),
Assert(
test=Compare(
left=Constant(value='b'),
ops=[
In()],
comparators=[
Name(id='__midas_a1__')]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Frame[a: Column[int], b: Column[str], c: Column[Positive], d: Column[float where is_positive(_)]]: Missing column 'b'")])),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='b'))],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='b'))],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Column[str], in column 'b': Not a column")])),
For(
target=Name(id='value'),
iter=Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='b')),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='str')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to str, in column 'b'")]))],
orelse=[]),
Assert(
test=Compare(
left=Constant(value='c'),
ops=[
In()],
comparators=[
Name(id='__midas_a1__')]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Frame[a: Column[int], b: Column[str], c: Column[Positive], d: Column[float where is_positive(_)]]: Missing column 'c'")])),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='c'))],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='c'))],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Column[Positive], in column 'c': Not a column")])),
For(
target=Name(id='value'),
iter=Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='c')),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='float')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to float, in column 'c'")])),
Assert(
test=Call(
func=Name(id='__midas_p0__'),
args=[
Name(id='value')],
keywords=[]),
msg=Constant(value="04_frames.py:L8:7: ConstraintError: Value does not fit constraint 'is_positive(_)', in column 'c'"))],
orelse=[]),
Assert(
test=Compare(
left=Constant(value='d'),
ops=[
In()],
comparators=[
Name(id='__midas_a1__')]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a1__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Frame[a: Column[int], b: Column[str], c: Column[Positive], d: Column[float where is_positive(_)]]: Missing column 'd'")])),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='d'))],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='d'))],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to Column[float where is_positive(_)], in column 'd': Not a column")])),
For(
target=Name(id='value'),
iter=Subscript(
value=Name(id='__midas_a1__'),
slice=Constant(value='d')),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='float')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L8:7: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=" to float, in column 'd'")])),
Assert(
test=Call(
func=Name(id='__midas_p1__'),
args=[
Name(id='value')],
keywords=[]),
msg=Constant(value="04_frames.py:L8:7: ConstraintError: Value does not fit constraint 'is_positive(_)', in column 'd'"))],
orelse=[]),
Assign(
targets=[
Name(id='df2')],
value=Name(id='__midas_a1__')),
Delete(
targets=[
Name(id='__midas_a1__')]),
Assign(
targets=[
Name(id='__midas_a2__')],
value=Name(id='df1')),
Assign(
targets=[
Name(id='__midas_a3__')],
value=Name(id='df2')),
Assert(
test=Call(
func=Name(id='__midas_column_same_length__'),
args=[
Name(id='__midas_a2__'),
Name(id='__midas_a3__')],
keywords=[]),
msg=Constant(value='04_frames.py:L10:1: AssertionError: Columns must have the same length')),
Assign(
targets=[
Name(id='__midas_a4__')],
value=Name(id='__midas_a2__')),
Assign(
targets=[
Name(id='__midas_a5__')],
value=Name(id='__midas_a3__')),
Assert(
test=Call(
func=Name(id='__midas_frame_same_length__'),
args=[
Name(id='__midas_a4__'),
Name(id='__midas_a5__')],
keywords=[]),
msg=Constant(value='04_frames.py:L10:1: AssertionError: DataFrames must have the same length')),
Expr(
value=BinOp(
left=Name(id='__midas_a2__'),
op=Add(),
right=Name(id='__midas_a3__'))),
Delete(
targets=[
Name(id='__midas_a2__'),
Name(id='__midas_a3__'),
Name(id='__midas_a4__'),
Name(id='__midas_a5__')]),
Assign(
targets=[
Name(id='col1')],
value=Subscript(
value=Name(id='df2'),
slice=Constant(value='c'))),
Assign(
targets=[
Name(id='__midas_a6__')],
value=Name(id='col1')),
Assert(
test=Call(
func=Name(id='__midas_is_column__'),
args=[
Name(id='__midas_a6__')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L13:8: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='__midas_a6__')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=' to Column[Positive]: Not a column')])),
For(
target=Name(id='value'),
iter=Name(id='__midas_a6__'),
body=[
Assert(
test=Call(
func=Name(id='isinstance'),
args=[
Name(id='value'),
Name(id='float')],
keywords=[]),
msg=JoinedStr(
values=[
Constant(value='04_frames.py:L13:8: CastError: Cannot cast '),
FormattedValue(
value=Attribute(
value=Call(
func=Name(id='type'),
args=[
Name(id='value')],
keywords=[]),
attr='__name__'),
conversion=-1),
Constant(value=' to float')])),
Assert(
test=Call(
func=Name(id='__midas_p0__'),
args=[
Name(id='value')],
keywords=[]),
msg=Constant(value="04_frames.py:L13:8: ConstraintError: Value does not fit constraint 'is_positive(_)'"))],
orelse=[]),
Assign(
targets=[
Name(id='col2')],
value=Name(id='__midas_a6__')),
Delete(
targets=[
Name(id='__midas_a6__')])],
type_ignores=[])

View File

@@ -0,0 +1,35 @@
// Alias declaration
alias A = object
// Type declaration
type B = object
// Generic declaration
type C[T] = object
type D[T <: A] = object
type E[T, U] = object
// Type expressions
type F[T] = T
type G = A where predicate(_)
type H = A where _ > 0 & _.attr < 1.0 & +_ + 4.0 >= "string" & !(-_ - 4.0 <= 0 & _ == none & _ != false)
type I = fn() -> Any
type J = fn(a: int, /, b: float, *, c: bool) -> Any
type K = fn(a: int, /, b: float, *, c: bool?) -> Any
type L = fn(a: int, /, b: float?, *, c: bool?) -> Any
type M = fn(a: int?, /, b: float?, *, c: bool?) -> Any
// Extend
extend N {}
extend O {
prop a: int
def b: fn(int, /) -> int
def b: fn(float, /) -> float
}
// Predicate
predicate P = true
predicate Q(v: float) = v > 0
predicate R(a: float, b: float)(v: float) = a < v & v < b
predicate S = R(0.0, 1.0)
predicate T = R(a=0.0, b=1.0)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
# type: ignore
# ruff: disable[F821]
import module1
import module2 as alias2
from module3 import submodule3
from module4 import submodule4 as alias4
a: int
b: Generic[int]
c: Generic2[int, float]
d: Frame[a:int, b:float]
e = 3
f: int = 4
g = []
h = [1, 0.1, " ", None, False, True]
i = {}
j = {"a": 1, "b": 2}
k = {"c": 3, **j}
l = cast(int, a)
m = unsafe_cast(int, a)
def n(a: int, /, b: float, *, c: str) -> Any:
return
def o(a: int = 1, /, b: float = 2.0, *, c: str = "") -> Any:
return 1
for i in h:
pass
if e == f:
pass
elif f == g:
pass
else:
pass
p = +a + -b - ~c * d / e**f
q = not (a and b) or c
r = a & b | c ^ d
s = a.b.c
t = a[b][c, d][e:f]
u = a(b)(c=d)

View File

@@ -0,0 +1,725 @@
{
"stmts": [
{
"_type": "ImportStmt",
"imports": [
{
"_type": "ImportAlias",
"name": "module1",
"alias": null
}
]
},
{
"_type": "ImportStmt",
"imports": [
{
"_type": "ImportAlias",
"name": "module2",
"alias": "alias2"
}
]
},
{
"_type": "FromImportStmt",
"module": "module3",
"imports": [
{
"_type": "ImportAlias",
"name": "submodule3",
"alias": null
}
],
"level": 0
},
{
"_type": "FromImportStmt",
"module": "module4",
"imports": [
{
"_type": "ImportAlias",
"name": "submodule4",
"alias": "alias4"
}
],
"level": 0
},
{
"_type": "TypeAssign",
"name": "a",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
}
},
{
"_type": "TypeAssign",
"name": "b",
"type": {
"_type": "BaseType",
"base": "Generic",
"args": [
{
"_type": "BaseType",
"base": "int",
"args": []
}
]
}
},
{
"_type": "TypeAssign",
"name": "c",
"type": {
"_type": "BaseType",
"base": "Generic2",
"args": [
{
"_type": "BaseType",
"base": "int",
"args": []
},
{
"_type": "BaseType",
"base": "float",
"args": []
}
]
}
},
{
"_type": "TypeAssign",
"name": "d",
"type": {
"_type": "FrameType",
"columns": [
{
"_type": "FrameColumn",
"name": "a",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
}
},
{
"_type": "FrameColumn",
"name": "b",
"type": {
"_type": "BaseType",
"base": "float",
"args": []
}
}
]
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "e"
}
],
"value": {
"_type": "LiteralExpr",
"value": 3
}
},
{
"_type": "TypeAssign",
"name": "f",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "f"
}
],
"value": {
"_type": "LiteralExpr",
"value": 4
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "g"
}
],
"value": {
"_type": "ListExpr",
"items": []
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "h"
}
],
"value": {
"_type": "ListExpr",
"items": [
{
"_type": "LiteralExpr",
"value": 1
},
{
"_type": "LiteralExpr",
"value": 0.1
},
{
"_type": "LiteralExpr",
"value": " "
},
{
"_type": "LiteralExpr",
"value": null
},
{
"_type": "LiteralExpr",
"value": false
},
{
"_type": "LiteralExpr",
"value": true
}
]
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "i"
}
],
"value": {
"_type": "DictExpr",
"keys": [],
"values": []
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "j"
}
],
"value": {
"_type": "DictExpr",
"keys": [
{
"_type": "LiteralExpr",
"value": "a"
},
{
"_type": "LiteralExpr",
"value": "b"
}
],
"values": [
{
"_type": "LiteralExpr",
"value": 1
},
{
"_type": "LiteralExpr",
"value": 2
}
]
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "k"
}
],
"value": {
"_type": "DictExpr",
"keys": [
{
"_type": "LiteralExpr",
"value": "c"
},
null
],
"values": [
{
"_type": "LiteralExpr",
"value": 3
},
{
"_type": "VariableExpr",
"name": "j"
}
]
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "l"
}
],
"value": {
"_type": "CastExpr",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
},
"expr": {
"_type": "VariableExpr",
"name": "a"
},
"unsafe": false
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "m"
}
],
"value": {
"_type": "CastExpr",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
},
"expr": {
"_type": "VariableExpr",
"name": "a"
},
"unsafe": true
}
},
{
"_type": "Function",
"name": "n",
"params": {
"_type": "ParamSpec",
"pos": [
{
"name": "a",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
},
"default": null
}
],
"mixed": [
{
"name": "b",
"type": {
"_type": "BaseType",
"base": "float",
"args": []
},
"default": null
}
],
"kw": [
{
"name": "c",
"type": {
"_type": "BaseType",
"base": "str",
"args": []
},
"default": null
}
]
},
"returns": {
"_type": "BaseType",
"base": "Any",
"args": []
},
"body": [
{
"_type": "ReturnStmt",
"value": null
}
]
},
{
"_type": "Function",
"name": "o",
"params": {
"_type": "ParamSpec",
"pos": [
{
"name": "a",
"type": {
"_type": "BaseType",
"base": "int",
"args": []
},
"default": {
"_type": "LiteralExpr",
"value": 1
}
}
],
"mixed": [
{
"name": "b",
"type": {
"_type": "BaseType",
"base": "float",
"args": []
},
"default": {
"_type": "LiteralExpr",
"value": 2.0
}
}
],
"kw": [
{
"name": "c",
"type": {
"_type": "BaseType",
"base": "str",
"args": []
},
"default": {
"_type": "LiteralExpr",
"value": ""
}
}
]
},
"returns": {
"_type": "BaseType",
"base": "Any",
"args": []
},
"body": [
{
"_type": "ReturnStmt",
"value": {
"_type": "LiteralExpr",
"value": 1
}
}
]
},
{
"_type": "ForStmt",
"target": {
"_type": "VariableExpr",
"name": "i"
},
"iterator": {
"_type": "VariableExpr",
"name": "h"
},
"body": []
},
{
"_type": "IfStmt",
"test": {
"_type": "CompareExpr",
"left": {
"_type": "VariableExpr",
"name": "e"
},
"operator": "==",
"right": {
"_type": "VariableExpr",
"name": "f"
}
},
"body": [],
"orelse": [
{
"_type": "IfStmt",
"test": {
"_type": "CompareExpr",
"left": {
"_type": "VariableExpr",
"name": "f"
},
"operator": "==",
"right": {
"_type": "VariableExpr",
"name": "g"
}
},
"body": [],
"orelse": []
}
]
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "p"
}
],
"value": {
"_type": "BinaryExpr",
"left": {
"_type": "BinaryExpr",
"left": {
"_type": "UnaryExpr",
"operator": "+",
"right": {
"_type": "VariableExpr",
"name": "a"
}
},
"operator": "+",
"right": {
"_type": "UnaryExpr",
"operator": "-",
"right": {
"_type": "VariableExpr",
"name": "b"
}
}
},
"operator": "-",
"right": {
"_type": "BinaryExpr",
"left": {
"_type": "BinaryExpr",
"left": {
"_type": "UnaryExpr",
"operator": "~",
"right": {
"_type": "VariableExpr",
"name": "c"
}
},
"operator": "*",
"right": {
"_type": "VariableExpr",
"name": "d"
}
},
"operator": "/",
"right": {
"_type": "BinaryExpr",
"left": {
"_type": "VariableExpr",
"name": "e"
},
"operator": "**",
"right": {
"_type": "VariableExpr",
"name": "f"
}
}
}
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "q"
}
],
"value": {
"_type": "LogicalExpr",
"left": {
"_type": "UnaryExpr",
"operator": "not",
"right": {
"_type": "LogicalExpr",
"left": {
"_type": "VariableExpr",
"name": "a"
},
"operator": "and",
"right": {
"_type": "VariableExpr",
"name": "b"
}
}
},
"operator": "or",
"right": {
"_type": "VariableExpr",
"name": "c"
}
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "r"
}
],
"value": {
"_type": "BinaryExpr",
"left": {
"_type": "BinaryExpr",
"left": {
"_type": "VariableExpr",
"name": "a"
},
"operator": "&",
"right": {
"_type": "VariableExpr",
"name": "b"
}
},
"operator": "|",
"right": {
"_type": "BinaryExpr",
"left": {
"_type": "VariableExpr",
"name": "c"
},
"operator": "^",
"right": {
"_type": "VariableExpr",
"name": "d"
}
}
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "s"
}
],
"value": {
"_type": "GetExpr",
"object": {
"_type": "GetExpr",
"object": {
"_type": "VariableExpr",
"name": "a"
},
"name": "b"
},
"name": "c"
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "t"
}
],
"value": {
"_type": "SubscriptExpr",
"object": {
"_type": "SubscriptExpr",
"object": {
"_type": "SubscriptExpr",
"object": {
"_type": "VariableExpr",
"name": "a"
},
"index": {
"_type": "VariableExpr",
"name": "b"
}
},
"index": {
"_type": "TupleExpr",
"items": [
{
"_type": "VariableExpr",
"name": "c"
},
{
"_type": "VariableExpr",
"name": "d"
}
]
}
},
"index": {
"_type": "SliceExpr",
"lower": {
"_type": "VariableExpr",
"name": "e"
},
"upper": {
"_type": "VariableExpr",
"name": "f"
},
"step": null
}
}
},
{
"_type": "AssignStmt",
"targets": [
{
"_type": "VariableExpr",
"name": "u"
}
],
"value": {
"_type": "CallExpr",
"callee": {
"_type": "CallExpr",
"callee": {
"_type": "VariableExpr",
"name": "a"
},
"arguments": [
{
"_type": "VariableExpr",
"name": "b"
}
],
"keywords": {}
},
"arguments": [],
"keywords": {
"c": {
"_type": "VariableExpr",
"name": "d"
}
}
}
}
]
}

View File

@@ -1,3 +1,4 @@
import ast
import json
from dataclasses import asdict, dataclass, field
from pathlib import Path
@@ -6,17 +7,30 @@ import midas.ast.python as p
from midas.checker.checker import TypeChecker
from midas.checker.diagnostic import Diagnostic
from midas.checker.types import Type
from midas.lexer.token import TokenType
from tests.base import Tester
from tests.serializer.python import PythonAstJsonSerializer
class CustomEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ast.AST):
return ast.dump(o)
if isinstance(o, TokenType):
return o.name
if o == ...:
return "..."
return super().default(o)
@dataclass
class CaseResult:
diagnostics: list[dict] = field(default_factory=list)
judgments: list = field(default_factory=list)
def dumps(self) -> str:
return json.dumps(asdict(self), indent=2)
return json.dumps(asdict(self), indent=2, cls=CustomEncoder)
class CheckerTester(Tester):

View File

@@ -3,7 +3,6 @@ from dataclasses import dataclass
from pathlib import Path
from midas.checker.checker import TypeChecker
from midas.checker.diagnostic import DiagnosticType
from midas.generator.generator import Generator
from midas.utils import TypedAST
from tests.base import Tester
@@ -44,10 +43,11 @@ class GeneratorTester(Tester):
typed_ast: TypedAST = checker.type_check(path)
if not any(d.type == DiagnosticType.ERROR for d in checker.diagnostics):
generator = Generator(workdir=path.parent, types=checker.types)
generator.set_src_path(path)
result.compiled_ast = generator.generate_ast(typed_ast)
# Ignore errors and generate anyway, easier here and errors should be
# covered by checker tests
generator = Generator(workdir=path.parent, types=checker.types)
generator.set_src_path(path)
result.compiled_ast = generator.generate_ast(typed_ast)
return result

View File

@@ -1,4 +1,4 @@
from typing import Optional, Sequence
from typing import Optional, Sequence, final
from midas.ast.midas import (
AliasStmt,
@@ -28,6 +28,7 @@ from midas.ast.midas import (
)
@final
class MidasAstJsonSerializer(
Stmt.Visitor[dict], Expr.Visitor[dict], Type.Visitor[dict]
):

View File

@@ -1,5 +1,5 @@
import ast
from typing import Optional, Sequence, Type
from typing import Optional, Sequence, Type, final
from midas.ast.python import (
AssignStmt,
@@ -78,6 +78,7 @@ boolean_ops: dict[Type[ast.boolop], str] = {
}
@final
class PythonAstJsonSerializer(
Stmt.Visitor[dict], Expr.Visitor[dict], MidasType.Visitor[dict]
):