jaclang 0.8.5__py3-none-any.whl → 0.8.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of jaclang might be problematic. Click here for more details.
- jaclang/cli/cli.md +4 -3
- jaclang/cli/cli.py +63 -29
- jaclang/cli/cmdreg.py +1 -140
- jaclang/compiler/passes/main/__init__.py +2 -0
- jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
- jaclang/compiler/passes/main/inheritance_pass.py +8 -1
- jaclang/compiler/passes/main/pyast_gen_pass.py +70 -11
- jaclang/compiler/passes/main/pyast_load_pass.py +14 -20
- jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_binary_op.jac +21 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_call_expr_class.jac +12 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cyclic_symbol.jac +4 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_expr_call.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_import_missing_module.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_magic_call.jac +17 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_mod_path.jac +8 -0
- jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
- jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
- jaclang/compiler/passes/main/tests/test_checker_pass.py +161 -0
- jaclang/compiler/passes/main/type_checker_pass.py +147 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +1 -4
- jaclang/compiler/program.py +17 -3
- jaclang/compiler/type_system/__init__.py +1 -0
- jaclang/compiler/type_system/operations.py +104 -0
- jaclang/compiler/type_system/type_evaluator.py +560 -0
- jaclang/compiler/type_system/type_utils.py +41 -0
- jaclang/compiler/type_system/types.py +240 -0
- jaclang/compiler/unitree.py +15 -9
- jaclang/langserve/dev_engine.jac +645 -0
- jaclang/langserve/dev_server.jac +201 -0
- jaclang/langserve/engine.jac +135 -91
- jaclang/langserve/server.jac +21 -14
- jaclang/langserve/tests/server_test/test_lang_serve.py +2 -5
- jaclang/langserve/tests/test_dev_server.py +80 -0
- jaclang/langserve/tests/test_server.py +9 -2
- jaclang/langserve/utils.jac +44 -48
- jaclang/runtimelib/builtin.py +28 -39
- jaclang/runtimelib/importer.py +1 -1
- jaclang/runtimelib/machine.py +48 -64
- jaclang/runtimelib/memory.py +23 -5
- jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
- jaclang/runtimelib/utils.py +13 -6
- jaclang/tests/fixtures/edge_node_walk.jac +1 -1
- jaclang/tests/fixtures/edges_walk.jac +1 -1
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/jac_run_py_bugs.py +18 -0
- jaclang/tests/fixtures/jac_run_py_import.py +13 -0
- jaclang/tests/fixtures/lambda_arg_annotation.jac +15 -0
- jaclang/tests/fixtures/lambda_self.jac +18 -0
- jaclang/tests/fixtures/py_run.jac +8 -0
- jaclang/tests/fixtures/py_run.py +23 -0
- jaclang/tests/fixtures/pyfunc.py +2 -0
- jaclang/tests/test_cli.py +103 -14
- jaclang/tests/test_language.py +10 -4
- jaclang/utils/lang_tools.py +3 -0
- jaclang/utils/module_resolver.py +1 -1
- {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/METADATA +4 -2
- {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/RECORD +70 -37
- {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/WHEEL +1 -1
- {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/entry_points.txt +0 -0
|
@@ -141,17 +141,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
141
141
|
|
|
142
142
|
reserved_keywords = [v for _, v in TOKEN_MAP.items()]
|
|
143
143
|
|
|
144
|
-
value = node.name if node.name not in reserved_keywords else f"<>{node.name}"
|
|
145
144
|
name = uni.Name(
|
|
146
145
|
orig_src=self.orig_src,
|
|
147
146
|
name=Tok.NAME,
|
|
148
|
-
value=
|
|
147
|
+
value=node.name,
|
|
149
148
|
line=node.lineno,
|
|
150
149
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
151
150
|
col_start=node.col_offset,
|
|
152
151
|
col_end=node.col_offset + len(node.name),
|
|
153
152
|
pos_start=0,
|
|
154
153
|
pos_end=0,
|
|
154
|
+
is_kwesc=(node.name in reserved_keywords),
|
|
155
155
|
)
|
|
156
156
|
body = [self.convert(i) for i in node.body]
|
|
157
157
|
valid = [i for i in body if isinstance(i, (uni.CodeBlockStmt))]
|
|
@@ -285,8 +285,8 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
285
285
|
and body_stmt.signature.params
|
|
286
286
|
):
|
|
287
287
|
for param in body_stmt.signature.params:
|
|
288
|
-
if param.name.value == "self":
|
|
289
|
-
param.type_tag
|
|
288
|
+
if param.name.value == "self" and param.type_tag:
|
|
289
|
+
param.type_tag.tag.value = name.value
|
|
290
290
|
doc = (
|
|
291
291
|
body[0].expr
|
|
292
292
|
if isinstance(body[0], uni.ExprStmt)
|
|
@@ -748,17 +748,14 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
748
748
|
attribute = uni.Name(
|
|
749
749
|
orig_src=self.orig_src,
|
|
750
750
|
name=Tok.NAME,
|
|
751
|
-
value=
|
|
752
|
-
("<>" + node.attr)
|
|
753
|
-
if node.attr == "init"
|
|
754
|
-
else "init" if node.attr == "__init__" else node.attr
|
|
755
|
-
),
|
|
751
|
+
value="init" if node.attr == "__init__" else node.attr,
|
|
756
752
|
line=node.lineno,
|
|
757
753
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
758
754
|
col_start=node.col_offset,
|
|
759
755
|
col_end=node.col_offset + len(node.attr),
|
|
760
756
|
pos_start=0,
|
|
761
757
|
pos_end=0,
|
|
758
|
+
is_kwesc=node.attr == "init",
|
|
762
759
|
)
|
|
763
760
|
if isinstance(value, uni.Expr):
|
|
764
761
|
return uni.AtomTrailer(
|
|
@@ -1680,18 +1677,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
1680
1677
|
for _, v in TOKEN_MAP.items()
|
|
1681
1678
|
if v not in ["float", "int", "str", "bool", "self"]
|
|
1682
1679
|
]
|
|
1683
|
-
|
|
1684
|
-
value = node.id if node.id not in reserved_keywords else f"<>{node.id}"
|
|
1685
1680
|
ret = uni.Name(
|
|
1686
1681
|
orig_src=self.orig_src,
|
|
1687
1682
|
name=Tok.NAME,
|
|
1688
|
-
value=
|
|
1683
|
+
value=node.id,
|
|
1689
1684
|
line=node.lineno,
|
|
1690
1685
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
1691
1686
|
col_start=node.col_offset,
|
|
1692
1687
|
col_end=node.col_offset + len(node.id),
|
|
1693
1688
|
pos_start=0,
|
|
1694
1689
|
pos_end=0,
|
|
1690
|
+
is_kwesc=(node.id in reserved_keywords),
|
|
1695
1691
|
)
|
|
1696
1692
|
return ret
|
|
1697
1693
|
|
|
@@ -1735,18 +1731,18 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
1735
1731
|
|
|
1736
1732
|
names: list[uni.NameAtom] = []
|
|
1737
1733
|
for name in node.names:
|
|
1738
|
-
value = name if name not in reserved_keywords else f"<>{name}"
|
|
1739
1734
|
names.append(
|
|
1740
1735
|
uni.Name(
|
|
1741
1736
|
orig_src=self.orig_src,
|
|
1742
1737
|
name=Tok.NAME,
|
|
1743
|
-
value=
|
|
1738
|
+
value=name,
|
|
1744
1739
|
line=node.lineno,
|
|
1745
1740
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
1746
1741
|
col_start=node.col_offset,
|
|
1747
1742
|
col_end=node.col_offset + len(name),
|
|
1748
1743
|
pos_start=0,
|
|
1749
1744
|
pos_end=0,
|
|
1745
|
+
is_kwesc=(name in reserved_keywords),
|
|
1750
1746
|
)
|
|
1751
1747
|
)
|
|
1752
1748
|
return uni.NonLocalStmt(target=names, kid=names)
|
|
@@ -2056,17 +2052,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
2056
2052
|
if v not in ["float", "int", "str", "bool", "self"]
|
|
2057
2053
|
]
|
|
2058
2054
|
|
|
2059
|
-
value = node.arg if node.arg not in reserved_keywords else f"<>{node.arg}"
|
|
2060
2055
|
name = uni.Name(
|
|
2061
2056
|
orig_src=self.orig_src,
|
|
2062
2057
|
name=Tok.NAME,
|
|
2063
|
-
value=
|
|
2058
|
+
value=node.arg,
|
|
2064
2059
|
line=node.lineno,
|
|
2065
2060
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
2066
2061
|
col_start=node.col_offset,
|
|
2067
2062
|
col_end=node.col_offset + len(node.arg),
|
|
2068
2063
|
pos_start=0,
|
|
2069
2064
|
pos_end=0,
|
|
2065
|
+
is_kwesc=(node.arg in reserved_keywords),
|
|
2070
2066
|
)
|
|
2071
2067
|
ann_expr = (
|
|
2072
2068
|
self.convert(node.annotation)
|
|
@@ -2343,19 +2339,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
|
|
|
2343
2339
|
from jaclang.compiler import TOKEN_MAP
|
|
2344
2340
|
|
|
2345
2341
|
reserved_keywords = [v for _, v in TOKEN_MAP.items()]
|
|
2346
|
-
arg_value = (
|
|
2347
|
-
node.arg if node.arg not in reserved_keywords else f"<>{node.arg}"
|
|
2348
|
-
)
|
|
2349
2342
|
arg = uni.Name(
|
|
2350
2343
|
orig_src=self.orig_src,
|
|
2351
2344
|
name=Tok.NAME,
|
|
2352
|
-
value=
|
|
2345
|
+
value=node.arg,
|
|
2353
2346
|
line=node.lineno,
|
|
2354
2347
|
end_line=node.end_lineno if node.end_lineno else node.lineno,
|
|
2355
2348
|
col_start=node.col_offset,
|
|
2356
2349
|
col_end=node.col_offset + len(node.arg if node.arg else "_"),
|
|
2357
2350
|
pos_start=0,
|
|
2358
2351
|
pos_end=0,
|
|
2352
|
+
is_kwesc=(node.arg in reserved_keywords),
|
|
2359
2353
|
)
|
|
2360
2354
|
value = self.convert(node.value)
|
|
2361
2355
|
if isinstance(value, uni.Expr):
|
|
@@ -84,6 +84,10 @@ class SymTabBuildPass(UniPass):
|
|
|
84
84
|
else:
|
|
85
85
|
pass # Need to support pythonic import symbols with dots in it
|
|
86
86
|
|
|
87
|
+
def exit_module_item(self, node: uni.ModuleItem) -> None:
|
|
88
|
+
sym_node = node.alias or node.name
|
|
89
|
+
sym_node.sym_tab.def_insert(sym_node, single_decl="import")
|
|
90
|
+
|
|
87
91
|
def enter_archetype(self, node: uni.Archetype) -> None:
|
|
88
92
|
self.push_scope_and_link(node)
|
|
89
93
|
assert node.parent_scope is not None
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
node B {
|
|
2
|
+
def __mul__(other: B) -> int {
|
|
3
|
+
return 0;
|
|
4
|
+
}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
node A {
|
|
8
|
+
def __add__(other: A) -> B {
|
|
9
|
+
return B();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
with entry {
|
|
14
|
+
a: A = A();
|
|
15
|
+
|
|
16
|
+
r1: B = a + a; # <-- Ok
|
|
17
|
+
r2: A = a + a; # <-- Error
|
|
18
|
+
|
|
19
|
+
r3: int = (a+a) * B(); # <-- Ok
|
|
20
|
+
r4: str = (a+a) * B(); # <-- Error
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import from scipy { stats, optimize }
|
|
2
|
+
import from utils.fake_helpers { helper_func }
|
|
3
|
+
import from non_existent_module { foo }
|
|
4
|
+
import nonexistent_module as nm;
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
with entry {
|
|
8
|
+
a: int = stats.norm.cdf(0);
|
|
9
|
+
d: float = optimize.minimize_scalar(lambda x: int: x ** 2).fun;
|
|
10
|
+
result = helper_func();
|
|
11
|
+
b: int = foo();
|
|
12
|
+
c = nm.some_func();
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import math as alias;
|
|
2
|
+
with entry {
|
|
3
|
+
|
|
4
|
+
# math module imports sys so it has the symbol
|
|
5
|
+
# we're not using math.pi since it's a Final[float]
|
|
6
|
+
# and we haven't implemented generic types yet.
|
|
7
|
+
m = alias;
|
|
8
|
+
|
|
9
|
+
i: int = m.sys.prefix; # <-- Error
|
|
10
|
+
s: str = m.sys.prefix; # <-- Ok
|
|
11
|
+
}
|
|
@@ -16,19 +16,9 @@ class TestCFGBuildPass(TestCase):
|
|
|
16
16
|
"""Test basic blocks."""
|
|
17
17
|
file_name = self.fixture_abs_path("cfg_gen.jac")
|
|
18
18
|
|
|
19
|
-
from jaclang.compiler.passes.main.cfg_build_pass import
|
|
19
|
+
from jaclang.compiler.passes.main.cfg_build_pass import cfg_dot_from_file
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
file_source = f.read()
|
|
23
|
-
|
|
24
|
-
ir = (prog := JacProgram()).compile(use_str=file_source, file_path=file_name)
|
|
25
|
-
|
|
26
|
-
cfg_pass = CoalesceBBPass(
|
|
27
|
-
ir_in=ir,
|
|
28
|
-
prog=prog,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
dot = cfg_pass.printgraph_cfg()
|
|
21
|
+
dot = cfg_dot_from_file(file_name=file_name)
|
|
32
22
|
|
|
33
23
|
expected_dot = (
|
|
34
24
|
"digraph G {\n"
|
|
@@ -62,19 +52,9 @@ class TestCFGBuildPass(TestCase):
|
|
|
62
52
|
"""Test basic blocks."""
|
|
63
53
|
file_name = self.fixture_abs_path("cfg_ability_test.jac")
|
|
64
54
|
|
|
65
|
-
from jaclang.compiler.passes.main.cfg_build_pass import
|
|
66
|
-
|
|
67
|
-
with open(file_name, "r") as f:
|
|
68
|
-
file_source = f.read()
|
|
55
|
+
from jaclang.compiler.passes.main.cfg_build_pass import cfg_dot_from_file
|
|
69
56
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
cfg_pass = CoalesceBBPass(
|
|
73
|
-
ir_in=ir,
|
|
74
|
-
prog=prog,
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
dot = cfg_pass.printgraph_cfg()
|
|
57
|
+
dot = cfg_dot_from_file(file_name=file_name)
|
|
78
58
|
|
|
79
59
|
expected_dot = (
|
|
80
60
|
"digraph G {\n"
|
|
@@ -93,3 +73,61 @@ class TestCFGBuildPass(TestCase):
|
|
|
93
73
|
)
|
|
94
74
|
|
|
95
75
|
self.assertEqual(dot, expected_dot)
|
|
76
|
+
|
|
77
|
+
def test_cfg_ability_with_has(self) -> None:
|
|
78
|
+
"""Test basic blocks with ability and has."""
|
|
79
|
+
file_name = self.fixture_abs_path("cfg_has_var.jac")
|
|
80
|
+
|
|
81
|
+
from jaclang.compiler.passes.main.cfg_build_pass import cfg_dot_from_file
|
|
82
|
+
|
|
83
|
+
dot = cfg_dot_from_file(file_name=file_name)
|
|
84
|
+
|
|
85
|
+
expected_dot = (
|
|
86
|
+
"digraph G {\n"
|
|
87
|
+
' 0 [label="BB0\\nobj Rock", shape=box];\n'
|
|
88
|
+
' 1 [label="BB1\\nhas pellets : list ;", shape=box];\n'
|
|
89
|
+
' 2 [label="BB2\\ncan count_pellets( ) -> int\\nreturn self . pellets . length ( ) ;", shape=box];\n'
|
|
90
|
+
' 3 [label="BB3\\nrock = Rock ( pellets = [ 1 , 2 , 3 ] ) ;\\nprint ( \\"Number of pellets: \\" + rock . count_pellets ( ) . to_string ( ) ) ;", shape=box];\n'
|
|
91
|
+
" 0 -> 1;\n"
|
|
92
|
+
" 0 -> 2;\n"
|
|
93
|
+
"}\n"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
self.assertEqual(dot, expected_dot)
|
|
97
|
+
|
|
98
|
+
def test_cfg_if_no_else(self) -> None:
|
|
99
|
+
"""Test basic blocks with if without else."""
|
|
100
|
+
file_name = self.fixture_abs_path("cfg_if_no_else.jac")
|
|
101
|
+
|
|
102
|
+
from jaclang.compiler.passes.main.cfg_build_pass import cfg_dot_from_file
|
|
103
|
+
|
|
104
|
+
dot = cfg_dot_from_file(file_name=file_name)
|
|
105
|
+
|
|
106
|
+
expected_dot = (
|
|
107
|
+
"digraph G {\n"
|
|
108
|
+
' 0 [label="BB0\\ncan test_if_without_else( x : int )\\nif ( x > 0 )", shape=box];\n'
|
|
109
|
+
' 1 [label="BB1\\nprint ( \\"Positive\\" ) ;", shape=box];\n'
|
|
110
|
+
' 2 [label="BB2\\nprint ( \\"Done\\" ) ;", shape=box];\n'
|
|
111
|
+
' 3 [label="BB3\\ntest_if_without_else ( 5 ) ;\\ntest_if_without_else ( - 3 ) ;", shape=box];\n'
|
|
112
|
+
" 0 -> 1;\n"
|
|
113
|
+
" 0 -> 2;\n"
|
|
114
|
+
" 1 -> 2;\n"
|
|
115
|
+
"}\n"
|
|
116
|
+
)
|
|
117
|
+
self.assertEqual(dot, expected_dot)
|
|
118
|
+
|
|
119
|
+
def test_cfg_return_stmt(self) -> None:
|
|
120
|
+
"""Test basic blocks with return statement."""
|
|
121
|
+
file_name = self.fixture_abs_path("cfg_return.jac")
|
|
122
|
+
|
|
123
|
+
from jaclang.compiler.passes.main.cfg_build_pass import cfg_dot_from_file
|
|
124
|
+
|
|
125
|
+
dot = cfg_dot_from_file(file_name=file_name)
|
|
126
|
+
|
|
127
|
+
expected_dot = (
|
|
128
|
+
"digraph G {\n"
|
|
129
|
+
' 0 [label="BB0\\ncan test_return_direct( )\\nprint ( \\"Before return\\" ) ;\\nreturn ;\\nprint ( \\"After return\\" ) ;", shape=box];\n'
|
|
130
|
+
' 1 [label="BB1\\ntest_return_direct ( ) ;", shape=box];\n'
|
|
131
|
+
"}\n"
|
|
132
|
+
)
|
|
133
|
+
self.assertEqual(dot, expected_dot)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
|
|
2
|
+
"""Tests for typechecker pass (the pyright implementation)."""
|
|
3
|
+
|
|
4
|
+
from tempfile import NamedTemporaryFile
|
|
5
|
+
|
|
6
|
+
from jaclang.utils.test import TestCase
|
|
7
|
+
from jaclang.compiler.passes.main import TypeCheckPass
|
|
8
|
+
from jaclang.compiler.program import JacProgram
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TypeCheckerPassTests(TestCase):
|
|
12
|
+
"""Test class obviously."""
|
|
13
|
+
|
|
14
|
+
def test_explicit_type_annotation_in_assignment(self) -> None:
|
|
15
|
+
"""Test explicit type annotation in assignment."""
|
|
16
|
+
program = JacProgram()
|
|
17
|
+
program.build(
|
|
18
|
+
self.fixture_abs_path("type_annotation_assignment.jac"), type_check=True
|
|
19
|
+
)
|
|
20
|
+
self.assertEqual(len(program.errors_had), 2)
|
|
21
|
+
self._assert_error_pretty_found("""
|
|
22
|
+
glob should_fail1: int = "foo";
|
|
23
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
24
|
+
""", program.errors_had[0].pretty_print())
|
|
25
|
+
|
|
26
|
+
self._assert_error_pretty_found("""
|
|
27
|
+
glob should_fail2: str = 42;
|
|
28
|
+
^^^^^^^^^^^^^^^^^^^^^^
|
|
29
|
+
""", program.errors_had[1].pretty_print())
|
|
30
|
+
|
|
31
|
+
def test_infer_type_of_assignment(self) -> None:
|
|
32
|
+
program = JacProgram()
|
|
33
|
+
mod = program.compile(self.fixture_abs_path("infer_type_assignment.jac"))
|
|
34
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
35
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
36
|
+
|
|
37
|
+
self._assert_error_pretty_found("""
|
|
38
|
+
assigning_to_str: str = some_int_inferred;
|
|
39
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
40
|
+
""", program.errors_had[0].pretty_print())
|
|
41
|
+
|
|
42
|
+
def test_member_access_type_resolve(self) -> None:
|
|
43
|
+
program = JacProgram()
|
|
44
|
+
mod = program.compile(self.fixture_abs_path("member_access_type_resolve.jac"))
|
|
45
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
46
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
47
|
+
self._assert_error_pretty_found("""
|
|
48
|
+
s: str = f.bar.baz;
|
|
49
|
+
^^^^^^^^^^^^^^^^^^^
|
|
50
|
+
""", program.errors_had[0].pretty_print())
|
|
51
|
+
|
|
52
|
+
def test_member_access_type_infered(self) -> None:
|
|
53
|
+
program = JacProgram()
|
|
54
|
+
mod = program.compile(self.fixture_abs_path("member_access_type_inferred.jac"))
|
|
55
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
56
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
57
|
+
self._assert_error_pretty_found("""
|
|
58
|
+
s = f.bar;
|
|
59
|
+
^^^^^^^^^
|
|
60
|
+
""", program.errors_had[0].pretty_print())
|
|
61
|
+
|
|
62
|
+
def test_import_symbol_type_infer(self) -> None:
|
|
63
|
+
program = JacProgram()
|
|
64
|
+
mod = program.compile(self.fixture_abs_path("import_symbol_type_infer.jac"))
|
|
65
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
66
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
67
|
+
self._assert_error_pretty_found("""
|
|
68
|
+
i: int = m.sys.prefix;
|
|
69
|
+
^^^^^^^^^^^^^^^^^^^^^
|
|
70
|
+
""", program.errors_had[0].pretty_print())
|
|
71
|
+
|
|
72
|
+
def test_from_import(self) -> None:
|
|
73
|
+
path = self.fixture_abs_path("checker_importer.jac")
|
|
74
|
+
|
|
75
|
+
program = JacProgram()
|
|
76
|
+
mod = program.compile(path)
|
|
77
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
78
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
79
|
+
self._assert_error_pretty_found("""
|
|
80
|
+
glob s: str = alias;
|
|
81
|
+
^^^^^^^^^^^^^^
|
|
82
|
+
""", program.errors_had[0].pretty_print())
|
|
83
|
+
|
|
84
|
+
def test_call_expr(self) -> None:
|
|
85
|
+
path = self.fixture_abs_path("checker_expr_call.jac")
|
|
86
|
+
program = JacProgram()
|
|
87
|
+
mod = program.compile(path)
|
|
88
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
89
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
90
|
+
self._assert_error_pretty_found("""
|
|
91
|
+
s: str = foo();
|
|
92
|
+
^^^^^^^^^^^^^^
|
|
93
|
+
""", program.errors_had[0].pretty_print())
|
|
94
|
+
|
|
95
|
+
def test_call_expr_magic(self) -> None:
|
|
96
|
+
path = self.fixture_abs_path("checker_magic_call.jac")
|
|
97
|
+
program = JacProgram()
|
|
98
|
+
mod = program.compile(path)
|
|
99
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
100
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
101
|
+
self._assert_error_pretty_found("""
|
|
102
|
+
b: Bar = fn()(); # <-- Ok
|
|
103
|
+
f: Foo = fn()(); # <-- Error
|
|
104
|
+
^^^^^^^^^^^^^^^^
|
|
105
|
+
""", program.errors_had[0].pretty_print())
|
|
106
|
+
|
|
107
|
+
def test_binary_op(self) -> None:
|
|
108
|
+
program = JacProgram()
|
|
109
|
+
mod = program.compile(self.fixture_abs_path("checker_binary_op.jac"))
|
|
110
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
111
|
+
self.assertEqual(len(program.errors_had), 2)
|
|
112
|
+
self._assert_error_pretty_found("""
|
|
113
|
+
r2: A = a + a; # <-- Error
|
|
114
|
+
^^^^^^^^^^^^^
|
|
115
|
+
""", program.errors_had[0].pretty_print())
|
|
116
|
+
self._assert_error_pretty_found("""
|
|
117
|
+
r4: str = (a+a) * B(); # <-- Error
|
|
118
|
+
^^^^^^^^^^^^^^^^^^^^^
|
|
119
|
+
""", program.errors_had[1].pretty_print())
|
|
120
|
+
|
|
121
|
+
def test_checker_call_expr_class(self) -> None:
|
|
122
|
+
path = self.fixture_abs_path("checker_call_expr_class.jac")
|
|
123
|
+
program = JacProgram()
|
|
124
|
+
mod = program.compile(path)
|
|
125
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
126
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
127
|
+
self._assert_error_pretty_found("""
|
|
128
|
+
inst.i = 'str'; # <-- Error
|
|
129
|
+
^^^^^^^^^^^^^^
|
|
130
|
+
""", program.errors_had[0].pretty_print())
|
|
131
|
+
|
|
132
|
+
def test_checker_mod_path(self) -> None:
|
|
133
|
+
path = self.fixture_abs_path("checker_mod_path.jac")
|
|
134
|
+
program = JacProgram()
|
|
135
|
+
mod = program.compile(path)
|
|
136
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
137
|
+
self.assertEqual(len(program.errors_had), 1)
|
|
138
|
+
self._assert_error_pretty_found("""
|
|
139
|
+
a:int = uni.Module; # <-- Error
|
|
140
|
+
^^^^^^^^^^^^^^
|
|
141
|
+
""", program.errors_had[0].pretty_print())
|
|
142
|
+
|
|
143
|
+
def test_checker_import_missing_module(self) -> None:
|
|
144
|
+
path = self.fixture_abs_path("checker_import_missing_module.jac")
|
|
145
|
+
program = JacProgram()
|
|
146
|
+
mod = program.compile(path)
|
|
147
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
148
|
+
self.assertEqual(len(program.errors_had), 0)
|
|
149
|
+
|
|
150
|
+
def test_cyclic_symbol(self) -> None:
|
|
151
|
+
path = self.fixture_abs_path("checker_cyclic_symbol.jac")
|
|
152
|
+
program = JacProgram()
|
|
153
|
+
mod = program.compile(path)
|
|
154
|
+
# This will result in a stack overflow if not handled properly.
|
|
155
|
+
# So the fact that it has 0 errors means it passed.
|
|
156
|
+
TypeCheckPass(ir_in=mod, prog=program)
|
|
157
|
+
self.assertEqual(len(program.errors_had), 0)
|
|
158
|
+
|
|
159
|
+
def _assert_error_pretty_found(self, needle: str, haystack: str) -> None:
|
|
160
|
+
for line in [line.strip() for line in needle.splitlines() if line.strip()]:
|
|
161
|
+
self.assertIn(line, haystack, f"Expected line '{line}' not found in:\n{haystack}")
|