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
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Representation of types used during type analysis."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# Pyright Reference: packages\pyright-internal\src\analyzer\types.ts
|
|
6
|
+
from abc import ABC
|
|
7
|
+
from enum import IntEnum, auto
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import ClassVar, TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from jaclang.compiler.unitree import Symbol, UniScopeNode as SymbolTable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TypeCategory(IntEnum):
|
|
16
|
+
"""Enumeration of type categories."""
|
|
17
|
+
|
|
18
|
+
Unbound = auto() # Name is not bound to a value of any type
|
|
19
|
+
Unknown = auto() # Implicit Any type
|
|
20
|
+
Never = auto() # The bottom type, equivalent to an empty union
|
|
21
|
+
Any = auto() # Type can be anything
|
|
22
|
+
Module = auto() # Module instance
|
|
23
|
+
Class = auto() # Class definition
|
|
24
|
+
Function = auto() # Callable type
|
|
25
|
+
Union = auto() # Union of two or more other types
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TypeFlags(IntEnum):
|
|
29
|
+
"""Flags to set on a type.
|
|
30
|
+
|
|
31
|
+
foo = 42 # <-- Here type of foo is `int` class, Instance type.
|
|
32
|
+
foo = int # <-- Here type of foo is `type[int]`, Instantiable is set.
|
|
33
|
+
foo: int = 42
|
|
34
|
+
^^^------- Here the type of the expression `int` is `type[int]`
|
|
35
|
+
That is same as the prefetched int_class that has the
|
|
36
|
+
flag Instantiable set.
|
|
37
|
+
|
|
38
|
+
calling convertToInstance() will return the same type
|
|
39
|
+
with Instance flag set.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
Null = 0 # Pyright use None but python can't
|
|
43
|
+
|
|
44
|
+
# This type refers to something that can be instantiated.
|
|
45
|
+
Instantiable = 1 << 0
|
|
46
|
+
|
|
47
|
+
# This type refers to something that has been instantiated.
|
|
48
|
+
Instance = 1 << 1
|
|
49
|
+
|
|
50
|
+
# This type is inferred within a py.typed source file and could be
|
|
51
|
+
# inferred differently by other type checkers.
|
|
52
|
+
Ambiguous = 1 << 2
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ParameterCategory(IntEnum):
|
|
56
|
+
"""Enumeration of parameter categories."""
|
|
57
|
+
|
|
58
|
+
Positional = auto()
|
|
59
|
+
ArgsList = auto()
|
|
60
|
+
KwargsDict = auto()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TypeBase(ABC):
|
|
64
|
+
"""Maps to pyright's TypeBase<T> in the types.ts file.
|
|
65
|
+
|
|
66
|
+
This is the base class for all type instance of the jaclang that holds
|
|
67
|
+
information about the type's category and any additional metadata and
|
|
68
|
+
utilities to analyze type information and provide type checking.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
# Each subclass should provide a class-level CATEGORY constant indicating its type category.
|
|
72
|
+
CATEGORY: ClassVar[TypeCategory]
|
|
73
|
+
|
|
74
|
+
def __init__(self, flags: TypeFlags = TypeFlags.Null) -> None:
|
|
75
|
+
"""Initialize obviously."""
|
|
76
|
+
self.flags: TypeFlags = flags
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def category(self) -> TypeCategory:
|
|
80
|
+
"""Returns the category of the type."""
|
|
81
|
+
return self.CATEGORY
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def unknown() -> "UnknownType":
|
|
85
|
+
"""Return an instance of an unknown type."""
|
|
86
|
+
return UnknownType()
|
|
87
|
+
|
|
88
|
+
def is_instantiable(self) -> bool:
|
|
89
|
+
"""Return whether the type is instantiable."""
|
|
90
|
+
return bool(self.flags & TypeFlags.Instantiable)
|
|
91
|
+
|
|
92
|
+
def is_instance(self) -> bool:
|
|
93
|
+
"""Return whether the type is an instance."""
|
|
94
|
+
return bool(self.flags & TypeFlags.Instance)
|
|
95
|
+
|
|
96
|
+
def is_instantiable_class(self) -> bool:
|
|
97
|
+
"""Return whether the class can be instantiated."""
|
|
98
|
+
return (self.category == TypeCategory.Class) and self.is_instantiable()
|
|
99
|
+
|
|
100
|
+
def is_class_instance(self) -> bool:
|
|
101
|
+
"""Return whether the class is an instance."""
|
|
102
|
+
return (self.category == TypeCategory.Class) and self.is_instance()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class UnboundType(TypeBase):
|
|
106
|
+
"""Represents a type that is not bound to a specific value or context."""
|
|
107
|
+
|
|
108
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Unbound
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class UnknownType(TypeBase):
|
|
112
|
+
"""Represents a type that is not known or cannot be determined."""
|
|
113
|
+
|
|
114
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Unknown
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class NeverType(TypeBase):
|
|
118
|
+
"""Represents a type that can never occur."""
|
|
119
|
+
|
|
120
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Never
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class AnyType(TypeBase):
|
|
124
|
+
"""Represents a type that can be anything."""
|
|
125
|
+
|
|
126
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Any
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class ModuleType(TypeBase):
|
|
130
|
+
"""Represents a module type."""
|
|
131
|
+
|
|
132
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Module
|
|
133
|
+
|
|
134
|
+
def __init__(
|
|
135
|
+
self, mod_name: str, file_uri: Path, symbol_table: SymbolTable
|
|
136
|
+
) -> None:
|
|
137
|
+
"""Initialize the class."""
|
|
138
|
+
super().__init__()
|
|
139
|
+
self.mod_name = mod_name
|
|
140
|
+
self.file_uri = file_uri
|
|
141
|
+
self.symbol_table = symbol_table
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class ClassType(TypeBase):
|
|
145
|
+
"""Represents a class type."""
|
|
146
|
+
|
|
147
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Class
|
|
148
|
+
|
|
149
|
+
# Pyright has both ClassDetailsShared; and ClassDetailsPriv;
|
|
150
|
+
# however we're only using shared instance and the private details
|
|
151
|
+
# will be part of the class itself.
|
|
152
|
+
|
|
153
|
+
class ClassDetailsShared:
|
|
154
|
+
"""Holds the shared details of class type.
|
|
155
|
+
|
|
156
|
+
The shared detail of classes will points to the same instance across multiple clones
|
|
157
|
+
of the same class. This is needed when we do `==` between two classes, if they have the
|
|
158
|
+
same shared object, that means they both are the same class (with different context).
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
def __init__(
|
|
162
|
+
self,
|
|
163
|
+
class_name: str,
|
|
164
|
+
symbol_table: SymbolTable,
|
|
165
|
+
base_classes: list[TypeBase] | None = None,
|
|
166
|
+
) -> None:
|
|
167
|
+
"""Initialize obviously."""
|
|
168
|
+
self.class_name = class_name
|
|
169
|
+
self.symbol_table = symbol_table
|
|
170
|
+
self.base_classes = base_classes or []
|
|
171
|
+
|
|
172
|
+
def __init__(
|
|
173
|
+
self,
|
|
174
|
+
shared: ClassType.ClassDetailsShared,
|
|
175
|
+
flags: TypeFlags = TypeFlags.Null,
|
|
176
|
+
) -> None:
|
|
177
|
+
"""Initialize the class type."""
|
|
178
|
+
super().__init__(flags=flags)
|
|
179
|
+
self.shared = shared
|
|
180
|
+
|
|
181
|
+
def clone_as_instance(self) -> "ClassType":
|
|
182
|
+
"""Clone this class type as an instance type."""
|
|
183
|
+
if self.is_instance():
|
|
184
|
+
return self
|
|
185
|
+
new_instance = ClassType(self.shared)
|
|
186
|
+
|
|
187
|
+
# TODO: There is more to this but we're not over complicating this atm.
|
|
188
|
+
new_flag = self.flags
|
|
189
|
+
new_flag = TypeFlags(new_flag & ~TypeFlags.Instantiable)
|
|
190
|
+
new_flags = TypeFlags(new_flag | TypeFlags.Instance)
|
|
191
|
+
new_instance.flags = new_flags
|
|
192
|
+
|
|
193
|
+
return new_instance
|
|
194
|
+
|
|
195
|
+
def lookup_member_symbol(self, member: str) -> Symbol | None:
|
|
196
|
+
"""Lookup a member in the class type."""
|
|
197
|
+
return self.shared.symbol_table.lookup(member, deep=True)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class Parameter:
|
|
201
|
+
"""Represents a function parameter."""
|
|
202
|
+
|
|
203
|
+
def __init__(
|
|
204
|
+
self, name: str, category: ParameterCategory, param_type: TypeBase | None
|
|
205
|
+
) -> None:
|
|
206
|
+
"""Initialize obviously."""
|
|
207
|
+
super().__init__()
|
|
208
|
+
self.name = name
|
|
209
|
+
self.category = category
|
|
210
|
+
self.param_type = param_type
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class FunctionType(TypeBase):
|
|
214
|
+
"""Represents a function type."""
|
|
215
|
+
|
|
216
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Function
|
|
217
|
+
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
func_name: str,
|
|
221
|
+
return_type: TypeBase | None = None,
|
|
222
|
+
parameters: list[Parameter] | None = None,
|
|
223
|
+
flags: TypeFlags = TypeFlags.Null,
|
|
224
|
+
) -> None:
|
|
225
|
+
"""Initialize obviously."""
|
|
226
|
+
super().__init__(flags=flags)
|
|
227
|
+
self.func_name = func_name
|
|
228
|
+
self.return_type = return_type
|
|
229
|
+
self.parameters = parameters or []
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class UnionType(TypeBase):
|
|
233
|
+
"""Represents a union type."""
|
|
234
|
+
|
|
235
|
+
CATEGORY: ClassVar[TypeCategory] = TypeCategory.Union
|
|
236
|
+
|
|
237
|
+
def __init__(self, types: list[TypeBase]) -> None:
|
|
238
|
+
"""Initialize obviously."""
|
|
239
|
+
super().__init__()
|
|
240
|
+
self.types = types
|
jaclang/compiler/unitree.py
CHANGED
|
@@ -30,6 +30,7 @@ from jaclang.compiler.constant import (
|
|
|
30
30
|
SymbolType,
|
|
31
31
|
)
|
|
32
32
|
from jaclang.compiler.constant import DELIM_MAP, SymbolAccess, Tokens as Tok
|
|
33
|
+
from jaclang.compiler.type_system.types import TypeBase
|
|
33
34
|
from jaclang.utils import resolve_relative_path
|
|
34
35
|
from jaclang.utils.treeprinter import (
|
|
35
36
|
print_ast_tree,
|
|
@@ -721,6 +722,14 @@ class Expr(UniNode):
|
|
|
721
722
|
self._sym_type: str = "NoType"
|
|
722
723
|
self._type_sym_tab: Optional[UniScopeNode] = None
|
|
723
724
|
|
|
725
|
+
# When the type of an expression is resolved, we'll be caching
|
|
726
|
+
# the type here.
|
|
727
|
+
#
|
|
728
|
+
# TODO:
|
|
729
|
+
# 1. Find a better name for this
|
|
730
|
+
# 2. Migrate this to expr_type property
|
|
731
|
+
self.type: TypeBase | None = None
|
|
732
|
+
|
|
724
733
|
@property
|
|
725
734
|
def expr_type(self) -> str:
|
|
726
735
|
return self._sym_type
|
|
@@ -1371,7 +1380,7 @@ class ModuleItem(AstSymbolNode):
|
|
|
1371
1380
|
AstSymbolNode.__init__(
|
|
1372
1381
|
self,
|
|
1373
1382
|
sym_name=alias.sym_name if alias else name.sym_name,
|
|
1374
|
-
name_spec=alias
|
|
1383
|
+
name_spec=alias or name,
|
|
1375
1384
|
sym_category=SymbolType.MOD_VAR,
|
|
1376
1385
|
)
|
|
1377
1386
|
self.abs_path: Optional[str] = None
|
|
@@ -1379,13 +1388,9 @@ class ModuleItem(AstSymbolNode):
|
|
|
1379
1388
|
@property
|
|
1380
1389
|
def from_parent(self) -> Import:
|
|
1381
1390
|
"""Get import parent."""
|
|
1382
|
-
if (
|
|
1383
|
-
not self.parent
|
|
1384
|
-
or not self.parent.parent
|
|
1385
|
-
or not isinstance(self.parent.parent, Import)
|
|
1386
|
-
):
|
|
1391
|
+
if not self.parent or not isinstance(self.parent, Import):
|
|
1387
1392
|
raise ValueError("Import parent not found. Not Possible.")
|
|
1388
|
-
return self.parent
|
|
1393
|
+
return self.parent
|
|
1389
1394
|
|
|
1390
1395
|
@property
|
|
1391
1396
|
def from_mod_path(self) -> ModulePath:
|
|
@@ -1524,7 +1529,8 @@ class Archetype(
|
|
|
1524
1529
|
new_kid.append(stmt)
|
|
1525
1530
|
new_kid.append(self.gen_token(Tok.RBRACE))
|
|
1526
1531
|
else:
|
|
1527
|
-
new_kid.append(self.gen_token(Tok.
|
|
1532
|
+
new_kid.append(self.gen_token(Tok.LBRACE))
|
|
1533
|
+
new_kid.append(self.gen_token(Tok.RBRACE))
|
|
1528
1534
|
self.set_kids(nodes=new_kid)
|
|
1529
1535
|
return res
|
|
1530
1536
|
|
|
@@ -4655,7 +4661,7 @@ class String(Literal):
|
|
|
4655
4661
|
|
|
4656
4662
|
def unparse(self) -> str:
|
|
4657
4663
|
super().unparse()
|
|
4658
|
-
return
|
|
4664
|
+
return self.value
|
|
4659
4665
|
|
|
4660
4666
|
|
|
4661
4667
|
class Bool(Literal):
|