jaclang 0.8.7__py3-none-any.whl → 0.8.8__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.py +13 -27
- jaclang/cli/cmdreg.py +44 -0
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +3 -6
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +213 -34
- jaclang/compiler/passes/main/__init__.py +2 -4
- jaclang/compiler/passes/main/def_use_pass.py +0 -4
- jaclang/compiler/passes/main/predynamo_pass.py +221 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +70 -52
- jaclang/compiler/passes/main/pyast_load_pass.py +52 -20
- jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
- jaclang/compiler/passes/main/tests/test_checker_pass.py +191 -0
- jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
- jaclang/compiler/passes/main/type_checker_pass.py +29 -73
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
- jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
- jaclang/compiler/passes/transform.py +12 -8
- jaclang/compiler/program.py +14 -6
- jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
- jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
- jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
- jaclang/compiler/tests/fixtures/python_module.py +1 -0
- jaclang/compiler/tests/test_importer.py +39 -0
- jaclang/compiler/tests/test_parser.py +49 -0
- jaclang/compiler/type_system/type_evaluator.py +351 -67
- jaclang/compiler/type_system/type_utils.py +246 -0
- jaclang/compiler/type_system/types.py +58 -2
- jaclang/compiler/unitree.py +79 -94
- jaclang/langserve/engine.jac +138 -159
- jaclang/langserve/server.jac +25 -1
- jaclang/langserve/tests/fixtures/circle.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
- jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
- jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
- jaclang/langserve/tests/server_test/circle_template.jac +80 -0
- jaclang/langserve/tests/server_test/glob_template.jac +4 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
- jaclang/langserve/tests/server_test/utils.py +153 -116
- jaclang/langserve/tests/test_server.py +21 -84
- jaclang/langserve/utils.jac +12 -15
- jaclang/runtimelib/machine.py +7 -0
- jaclang/runtimelib/meta_importer.py +27 -1
- jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
- jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
- jaclang/settings.py +18 -14
- jaclang/tests/fixtures/abc_check.jac +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
- jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
- jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
- jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
- jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
- jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
- jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
- jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
- jaclang/tests/fixtures/py2jac_params.py +8 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/test_cli.py +37 -1
- jaclang/tests/test_language.py +74 -16
- jaclang/utils/helpers.py +47 -2
- jaclang/utils/module_resolver.py +10 -0
- jaclang/utils/test.py +8 -0
- jaclang/utils/treeprinter.py +0 -18
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/METADATA +1 -2
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/RECORD +85 -60
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/inheritance_pass.py +0 -131
- jaclang/langserve/dev_engine.jac +0 -645
- jaclang/langserve/dev_server.jac +0 -201
- jaclang/langserve/tests/server_test/code_test.py +0 -0
- {jaclang-0.8.7.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
PyrightReference: packages/pyright-internal/src/analyzer/typeUtils.ts
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
import jaclang.compiler.unitree as uni
|
|
10
|
+
from jaclang.compiler.constant import Tokens as Tok
|
|
6
11
|
from jaclang.compiler.unitree import Symbol
|
|
7
12
|
|
|
8
13
|
from . import types
|
|
@@ -39,3 +44,244 @@ class ClassMember:
|
|
|
39
44
|
# True if member lookup skipped an undeclared (inferred) type
|
|
40
45
|
# in a subclass before finding a declared type in a base class
|
|
41
46
|
self.skipped_undeclared_type = False
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def compute_mro_linearization(cls: types.ClassType) -> None:
|
|
50
|
+
"""Compute the method resolution order (MRO) for a class type.
|
|
51
|
+
|
|
52
|
+
This uses the C3 linearization algorithm to compute the MRO.
|
|
53
|
+
See https://www.python.org/download/releases/2.3/mro/
|
|
54
|
+
"""
|
|
55
|
+
if cls.shared.mro:
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
# FIXME: This is an ad-hoc implementation to make the MRO works
|
|
59
|
+
# and it'll cover the 90% or more of the user cases.
|
|
60
|
+
|
|
61
|
+
# Computer MRO for base classes first
|
|
62
|
+
cls.shared.mro.append(cls)
|
|
63
|
+
for base in cls.shared.base_classes:
|
|
64
|
+
if isinstance(base, types.ClassType):
|
|
65
|
+
compute_mro_linearization(base)
|
|
66
|
+
|
|
67
|
+
# Then add base classes and their MROs
|
|
68
|
+
for base in cls.shared.base_classes:
|
|
69
|
+
if isinstance(base, types.ClassType):
|
|
70
|
+
for mro_cls in base.shared.mro:
|
|
71
|
+
if mro_cls not in cls.shared.mro:
|
|
72
|
+
cls.shared.mro.append(mro_cls)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# In pyright, this class lives in the parameterUtils.ts however we're
|
|
76
|
+
# putting it here for now and if the scale of the code grows we can
|
|
77
|
+
# split it into a separate file.
|
|
78
|
+
class ParamAssignmentTracker:
|
|
79
|
+
"""Tracks parameter assignments for function calls.
|
|
80
|
+
|
|
81
|
+
This class helps in tracking which parameters have been matched
|
|
82
|
+
with arguments in a function call. It supports positional, named,
|
|
83
|
+
*args, and **kwargs arguments.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
def __init__(self, params: list[types.Parameter]) -> None:
|
|
87
|
+
"""Initialize obviously."""
|
|
88
|
+
self.params = params
|
|
89
|
+
self.curr_param_idx = 0
|
|
90
|
+
self.matched_params: set[types.Parameter] = set()
|
|
91
|
+
|
|
92
|
+
# Quick access to vararg and kwarg parameters
|
|
93
|
+
self.varargs: types.Parameter | None = None
|
|
94
|
+
self.kwargs: types.Parameter | None = None
|
|
95
|
+
|
|
96
|
+
# "Cache" vararg and kwarg parameters for quick access
|
|
97
|
+
for param in self.params:
|
|
98
|
+
if param.param_kind == types.ParamKind.VARARG:
|
|
99
|
+
self.varargs = param
|
|
100
|
+
elif param.param_kind == types.ParamKind.KWARG:
|
|
101
|
+
self.kwargs = param
|
|
102
|
+
|
|
103
|
+
def lookup_named_parameter(self, param_name: str) -> types.Parameter | None:
|
|
104
|
+
"""Lookup a named parameter by name and if any match is found we mark it as such."""
|
|
105
|
+
for param in self.params:
|
|
106
|
+
# User try to pass a positional only parameter with a name, should be an error.
|
|
107
|
+
if (param.param_kind == types.ParamKind.POSONLY) and (
|
|
108
|
+
param_name == param.name
|
|
109
|
+
):
|
|
110
|
+
self.matched_params.add(param)
|
|
111
|
+
raise Exception(
|
|
112
|
+
f"Positional only parameter '{param.name}' cannot be matched with a named argument"
|
|
113
|
+
)
|
|
114
|
+
if param.param_kind not in (types.ParamKind.NORMAL, types.ParamKind.KWONLY):
|
|
115
|
+
continue
|
|
116
|
+
if param.name == param_name:
|
|
117
|
+
if param in self.matched_params:
|
|
118
|
+
raise Exception(f"Parameter '{param.name}' already matched")
|
|
119
|
+
self.matched_params.add(param)
|
|
120
|
+
return param
|
|
121
|
+
# If we reached here, there is no named parameter to match with
|
|
122
|
+
# however if we have **kwargs, we can match it with that, if that
|
|
123
|
+
# also None, it'll return None indicating no match.
|
|
124
|
+
return self.kwargs
|
|
125
|
+
|
|
126
|
+
def _mark_all_named_params_as_matched(self) -> None:
|
|
127
|
+
"""Mark all named parameters as matched."""
|
|
128
|
+
for param in self.params:
|
|
129
|
+
if param.param_kind in (
|
|
130
|
+
types.ParamKind.NORMAL,
|
|
131
|
+
types.ParamKind.KWONLY,
|
|
132
|
+
types.ParamKind.KWARG,
|
|
133
|
+
):
|
|
134
|
+
self.matched_params.add(param)
|
|
135
|
+
|
|
136
|
+
def _mark_all_positional_params_as_matched(self) -> None:
|
|
137
|
+
"""Mark all positional parameters as matched."""
|
|
138
|
+
for param in self.params:
|
|
139
|
+
if param.param_kind in (
|
|
140
|
+
types.ParamKind.POSONLY,
|
|
141
|
+
types.ParamKind.NORMAL,
|
|
142
|
+
types.ParamKind.VARARG,
|
|
143
|
+
):
|
|
144
|
+
self.matched_params.add(param)
|
|
145
|
+
self.curr_param_idx = -1
|
|
146
|
+
|
|
147
|
+
def match_named_argument(self, arg: uni.KWPair) -> types.Parameter | None:
|
|
148
|
+
"""Match a named argument to a parameter."""
|
|
149
|
+
if arg.key is None:
|
|
150
|
+
# **{} <- This can be matched with any named parameter
|
|
151
|
+
# in the current parameter list.
|
|
152
|
+
self._mark_all_named_params_as_matched()
|
|
153
|
+
return None
|
|
154
|
+
else:
|
|
155
|
+
if param := self.lookup_named_parameter(arg.key.sym_name):
|
|
156
|
+
return param
|
|
157
|
+
raise Exception(
|
|
158
|
+
f"Named argument '{arg.key.sym_name}' does not match any parameter"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def match_positional_argument(self, arg: uni.Expr) -> types.Parameter | None:
|
|
162
|
+
"""Match a positional argument to a parameter."""
|
|
163
|
+
# NOTE: The curr_param_idx can be -1 only when a unpack (*expr) is passed
|
|
164
|
+
# at that point there is no reliable way to match the remaining positional
|
|
165
|
+
# arguments after the unpack, so we either match with *args or not match with
|
|
166
|
+
# anything.
|
|
167
|
+
if self.curr_param_idx == -1:
|
|
168
|
+
return self.varargs
|
|
169
|
+
|
|
170
|
+
if isinstance(arg, uni.UnaryExpr) and arg.op.value == Tok.STAR_MUL:
|
|
171
|
+
self._mark_all_positional_params_as_matched()
|
|
172
|
+
return None
|
|
173
|
+
else:
|
|
174
|
+
if self.curr_param_idx < len(self.params):
|
|
175
|
+
param = self.params[self.curr_param_idx]
|
|
176
|
+
if param.param_kind == types.ParamKind.VARARG:
|
|
177
|
+
self.matched_params.add(param)
|
|
178
|
+
return param
|
|
179
|
+
if param.param_kind in (
|
|
180
|
+
types.ParamKind.NORMAL,
|
|
181
|
+
types.ParamKind.POSONLY,
|
|
182
|
+
):
|
|
183
|
+
self.curr_param_idx += 1
|
|
184
|
+
self.matched_params.add(param)
|
|
185
|
+
return param
|
|
186
|
+
|
|
187
|
+
# If we reached here, there is no parameter to match with
|
|
188
|
+
raise Exception("Too many positional arguments")
|
|
189
|
+
|
|
190
|
+
def get_unmatched_required_params(self) -> list[types.Parameter]:
|
|
191
|
+
"""Check if there are any unmatched required parameters."""
|
|
192
|
+
ret: list[types.Parameter] = []
|
|
193
|
+
for param in self.params:
|
|
194
|
+
if (
|
|
195
|
+
param not in self.matched_params
|
|
196
|
+
and param.default_value is None
|
|
197
|
+
and param.param_kind
|
|
198
|
+
not in (types.ParamKind.VARARG, types.ParamKind.KWARG)
|
|
199
|
+
):
|
|
200
|
+
ret.append(param)
|
|
201
|
+
return ret
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
# -----------------------------------------------------------------------------
|
|
205
|
+
# Completion item utils
|
|
206
|
+
# -----------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
@dataclass
|
|
210
|
+
class CompletionItem:
|
|
211
|
+
"""A completion item."""
|
|
212
|
+
|
|
213
|
+
label: str
|
|
214
|
+
kind: int
|
|
215
|
+
detail: str | None = None
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class CompletionItemKind(int, Enum):
|
|
219
|
+
"""The kind of a completion entry."""
|
|
220
|
+
|
|
221
|
+
Text = 1
|
|
222
|
+
Method = 2
|
|
223
|
+
Function = 3
|
|
224
|
+
Constructor = 4
|
|
225
|
+
Field = 5
|
|
226
|
+
Variable = 6
|
|
227
|
+
Class = 7
|
|
228
|
+
Interface = 8
|
|
229
|
+
Module = 9
|
|
230
|
+
Property = 10
|
|
231
|
+
Unit = 11
|
|
232
|
+
Value = 12
|
|
233
|
+
Enum = 13
|
|
234
|
+
Keyword = 14
|
|
235
|
+
Snippet = 15
|
|
236
|
+
Color = 16
|
|
237
|
+
File = 17
|
|
238
|
+
Reference = 18
|
|
239
|
+
Folder = 19
|
|
240
|
+
EnumMember = 20
|
|
241
|
+
Constant = 21
|
|
242
|
+
Struct = 22
|
|
243
|
+
Event = 23
|
|
244
|
+
Operator = 24
|
|
245
|
+
TypeParameter = 25
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def completion_kind_from_sym(sym: Symbol) -> int:
|
|
249
|
+
"""Get the completion item kind from a symbol."""
|
|
250
|
+
match sym.decl.name_of:
|
|
251
|
+
case uni.ModulePath():
|
|
252
|
+
return CompletionItemKind.Module
|
|
253
|
+
case uni.Ability():
|
|
254
|
+
return CompletionItemKind.Function
|
|
255
|
+
case uni.Archetype():
|
|
256
|
+
return CompletionItemKind.Class
|
|
257
|
+
case uni.Enum():
|
|
258
|
+
return CompletionItemKind.Enum
|
|
259
|
+
case uni.HasVar():
|
|
260
|
+
return CompletionItemKind.Variable
|
|
261
|
+
return CompletionItemKind.Text
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def get_completion_items(ty: types.TypeBase | uni.UniScopeNode) -> list[CompletionItem]:
|
|
265
|
+
"""Return a list of completion items for the type."""
|
|
266
|
+
ret = []
|
|
267
|
+
|
|
268
|
+
if isinstance(ty, uni.UniScopeNode):
|
|
269
|
+
scope = ty
|
|
270
|
+
while scope:
|
|
271
|
+
for name, sym in scope.names_in_scope.items():
|
|
272
|
+
kind = completion_kind_from_sym(sym)
|
|
273
|
+
ret.append(CompletionItem(label=name, kind=kind))
|
|
274
|
+
scope = scope.parent_scope
|
|
275
|
+
|
|
276
|
+
elif isinstance(ty, types.ClassType):
|
|
277
|
+
for cls in ty.shared.mro:
|
|
278
|
+
for name, sym in cls.shared.symbol_table.names_in_scope.items():
|
|
279
|
+
kind = completion_kind_from_sym(sym)
|
|
280
|
+
ret.append(CompletionItem(label=name, kind=kind))
|
|
281
|
+
|
|
282
|
+
elif isinstance(ty, types.ModuleType):
|
|
283
|
+
for name, sym in ty.symbol_table.names_in_scope.items():
|
|
284
|
+
kind = completion_kind_from_sym(sym)
|
|
285
|
+
ret.append(CompletionItem(label=name, kind=kind))
|
|
286
|
+
|
|
287
|
+
return ret
|
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
from typing import ClassVar, TYPE_CHECKING
|
|
10
10
|
|
|
11
11
|
if TYPE_CHECKING:
|
|
12
|
-
from jaclang.compiler.unitree import Symbol, UniScopeNode as SymbolTable
|
|
12
|
+
from jaclang.compiler.unitree import Expr, Symbol, UniScopeNode as SymbolTable
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class TypeCategory(IntEnum):
|
|
@@ -163,11 +163,25 @@ class ClassType(TypeBase):
|
|
|
163
163
|
class_name: str,
|
|
164
164
|
symbol_table: SymbolTable,
|
|
165
165
|
base_classes: list[TypeBase] | None = None,
|
|
166
|
+
is_builtin_class: bool = False,
|
|
166
167
|
) -> None:
|
|
167
168
|
"""Initialize obviously."""
|
|
168
169
|
self.class_name = class_name
|
|
169
170
|
self.symbol_table = symbol_table
|
|
170
171
|
self.base_classes = base_classes or []
|
|
172
|
+
self.mro: list[ClassType] = []
|
|
173
|
+
|
|
174
|
+
# In pyright classes have ClassTypeFlags to indicate if it's builtin
|
|
175
|
+
# along with other information, I'm adding only the builtin flag for now.
|
|
176
|
+
# add the other flags if needed in the future with a bitmask enum.
|
|
177
|
+
#
|
|
178
|
+
# export const enum ClassTypeFlags {
|
|
179
|
+
# ...
|
|
180
|
+
# // Class is defined in the "builtins" or "typing" file.
|
|
181
|
+
# BuiltIn = 1 << 0,
|
|
182
|
+
# ...
|
|
183
|
+
#
|
|
184
|
+
self.is_builtin_class = is_builtin_class
|
|
171
185
|
|
|
172
186
|
def __init__(
|
|
173
187
|
self,
|
|
@@ -178,6 +192,10 @@ class ClassType(TypeBase):
|
|
|
178
192
|
super().__init__(flags=flags)
|
|
179
193
|
self.shared = shared
|
|
180
194
|
|
|
195
|
+
def __str__(self) -> str:
|
|
196
|
+
"""Return a string representation of the class type."""
|
|
197
|
+
return f"<class {self.shared.class_name}>"
|
|
198
|
+
|
|
181
199
|
def clone_as_instance(self) -> "ClassType":
|
|
182
200
|
"""Clone this class type as an instance type."""
|
|
183
201
|
if self.is_instance():
|
|
@@ -196,19 +214,57 @@ class ClassType(TypeBase):
|
|
|
196
214
|
"""Lookup a member in the class type."""
|
|
197
215
|
return self.shared.symbol_table.lookup(member, deep=True)
|
|
198
216
|
|
|
217
|
+
def is_builtin(self, class_name: str | None = None) -> bool:
|
|
218
|
+
"""
|
|
219
|
+
Return true if this class is a builtin class.
|
|
220
|
+
|
|
221
|
+
If class_name is provided, also check if the class name matches.
|
|
222
|
+
"""
|
|
223
|
+
if not self.shared.is_builtin_class:
|
|
224
|
+
return False
|
|
225
|
+
if class_name is not None:
|
|
226
|
+
return self.shared.class_name == class_name
|
|
227
|
+
return True
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class ParamKind(IntEnum):
|
|
231
|
+
"""Enumeration of parameter kinds."""
|
|
232
|
+
|
|
233
|
+
POSONLY = 0
|
|
234
|
+
NORMAL = 1
|
|
235
|
+
VARARG = 2
|
|
236
|
+
KWONLY = 3
|
|
237
|
+
KWARG = 4
|
|
238
|
+
|
|
199
239
|
|
|
200
240
|
class Parameter:
|
|
201
241
|
"""Represents a function parameter."""
|
|
202
242
|
|
|
203
243
|
def __init__(
|
|
204
|
-
self,
|
|
244
|
+
self,
|
|
245
|
+
name: str,
|
|
246
|
+
category: ParameterCategory,
|
|
247
|
+
param_type: TypeBase | None,
|
|
248
|
+
default_value: Expr | None = None,
|
|
249
|
+
is_self: bool = False,
|
|
250
|
+
param_kind: ParamKind = ParamKind.NORMAL,
|
|
205
251
|
) -> None:
|
|
206
252
|
"""Initialize obviously."""
|
|
207
253
|
super().__init__()
|
|
208
254
|
self.name = name
|
|
209
255
|
self.category = category
|
|
256
|
+
self.default_value = default_value
|
|
210
257
|
self.param_type = param_type
|
|
211
258
|
|
|
259
|
+
# This will set to true if the parameter is `self`. In jaclang self
|
|
260
|
+
# in the context of obj, node, edge, walker methods is not required to
|
|
261
|
+
# be explicitly defined. However, in the `class` methods it should be
|
|
262
|
+
# explicitly defined.
|
|
263
|
+
self.is_self = is_self
|
|
264
|
+
|
|
265
|
+
# Kind is wheather it's normal, posonly, vararg, kwonly, kwarg.
|
|
266
|
+
self.param_kind: ParamKind = param_kind
|
|
267
|
+
|
|
212
268
|
|
|
213
269
|
class FunctionType(TypeBase):
|
|
214
270
|
"""Represents a function type."""
|
jaclang/compiler/unitree.py
CHANGED
|
@@ -7,6 +7,7 @@ import builtins
|
|
|
7
7
|
import os
|
|
8
8
|
from copy import copy
|
|
9
9
|
from dataclasses import dataclass
|
|
10
|
+
from enum import IntEnum
|
|
10
11
|
from hashlib import md5
|
|
11
12
|
from types import EllipsisType
|
|
12
13
|
from typing import (
|
|
@@ -306,7 +307,6 @@ class UniScopeNode(UniNode):
|
|
|
306
307
|
self.parent_scope = parent_scope
|
|
307
308
|
self.kid_scope: list[UniScopeNode] = []
|
|
308
309
|
self.names_in_scope: dict[str, Symbol] = {}
|
|
309
|
-
self.inherited_scope: list[InheritedSymbolTable] = []
|
|
310
310
|
|
|
311
311
|
def get_type(self) -> SymbolType:
|
|
312
312
|
"""Get type."""
|
|
@@ -322,10 +322,6 @@ class UniScopeNode(UniNode):
|
|
|
322
322
|
"""Lookup a variable in the symbol table."""
|
|
323
323
|
if name in self.names_in_scope:
|
|
324
324
|
return self.names_in_scope[name]
|
|
325
|
-
for i in self.inherited_scope:
|
|
326
|
-
found = i.lookup(name, deep=False)
|
|
327
|
-
if found:
|
|
328
|
-
return found
|
|
329
325
|
if deep and self.parent_scope:
|
|
330
326
|
return self.parent_scope.lookup(name, deep)
|
|
331
327
|
return None
|
|
@@ -369,9 +365,6 @@ class UniScopeNode(UniNode):
|
|
|
369
365
|
for k in self.kid_scope:
|
|
370
366
|
if k.scope_name == name:
|
|
371
367
|
return k
|
|
372
|
-
for k2 in self.inherited_scope:
|
|
373
|
-
if k2.base_symbol_table.scope_name == name:
|
|
374
|
-
return k2.base_symbol_table
|
|
375
368
|
return None
|
|
376
369
|
|
|
377
370
|
def link_kid_scope(self, key_node: UniScopeNode) -> UniScopeNode:
|
|
@@ -489,22 +482,6 @@ class UniScopeNode(UniNode):
|
|
|
489
482
|
|
|
490
483
|
fix(node)
|
|
491
484
|
|
|
492
|
-
def inherit_baseclasses_sym(self, node: Archetype | Enum) -> None:
|
|
493
|
-
"""Inherit base classes symbol tables."""
|
|
494
|
-
if node.base_classes:
|
|
495
|
-
for base_cls in node.base_classes:
|
|
496
|
-
if (
|
|
497
|
-
isinstance(base_cls, AstSymbolNode)
|
|
498
|
-
and (found := self.use_lookup(base_cls))
|
|
499
|
-
and found
|
|
500
|
-
):
|
|
501
|
-
found_tab = found.decl.sym_tab
|
|
502
|
-
inher_sym_tab = InheritedSymbolTable(
|
|
503
|
-
base_symbol_table=found_tab, load_all_symbols=True, symbols=[]
|
|
504
|
-
)
|
|
505
|
-
self.inherited_scope.append(inher_sym_tab)
|
|
506
|
-
base_cls.name_spec.name_of = found.decl.name_of
|
|
507
|
-
|
|
508
485
|
def sym_pp(self, depth: Optional[int] = None) -> str:
|
|
509
486
|
"""Pretty print."""
|
|
510
487
|
return print_symtab_tree(root=self, depth=depth)
|
|
@@ -521,31 +498,6 @@ class UniScopeNode(UniNode):
|
|
|
521
498
|
return out
|
|
522
499
|
|
|
523
500
|
|
|
524
|
-
class InheritedSymbolTable:
|
|
525
|
-
"""Inherited symbol table."""
|
|
526
|
-
|
|
527
|
-
def __init__(
|
|
528
|
-
self,
|
|
529
|
-
base_symbol_table: UniScopeNode,
|
|
530
|
-
load_all_symbols: bool = False, # This is needed for python imports
|
|
531
|
-
symbols: Optional[list[str]] = None,
|
|
532
|
-
) -> None:
|
|
533
|
-
"""Initialize."""
|
|
534
|
-
self.base_symbol_table: UniScopeNode = base_symbol_table
|
|
535
|
-
self.load_all_symbols: bool = load_all_symbols
|
|
536
|
-
self.symbols: list[str] = symbols if symbols else []
|
|
537
|
-
|
|
538
|
-
def lookup(self, name: str, deep: bool = False) -> Optional[Symbol]:
|
|
539
|
-
"""Lookup a variable in the symbol table."""
|
|
540
|
-
if self.load_all_symbols:
|
|
541
|
-
return self.base_symbol_table.lookup(name, deep)
|
|
542
|
-
else:
|
|
543
|
-
if name in self.symbols:
|
|
544
|
-
return self.base_symbol_table.lookup(name, deep)
|
|
545
|
-
else:
|
|
546
|
-
return None
|
|
547
|
-
|
|
548
|
-
|
|
549
501
|
class AstSymbolNode(UniNode):
|
|
550
502
|
"""Nodes that have link to a symbol in symbol table."""
|
|
551
503
|
|
|
@@ -922,6 +874,12 @@ class Module(AstDocNode, UniScopeNode):
|
|
|
922
874
|
self.src_terminals: list[Token] = terminals
|
|
923
875
|
self.is_raised_from_py: bool = False
|
|
924
876
|
|
|
877
|
+
# We continue to parse a module even if there are syntax errors
|
|
878
|
+
# so that we can report more errors in a single pass and support
|
|
879
|
+
# features like code completion, lsp, format etc. This flag
|
|
880
|
+
# indicates if there were syntax errors during parsing.
|
|
881
|
+
self.has_syntax_errors: bool = False
|
|
882
|
+
|
|
925
883
|
UniNode.__init__(self, kid=kid)
|
|
926
884
|
AstDocNode.__init__(self, doc=doc)
|
|
927
885
|
UniScopeNode.__init__(self, name=self.name)
|
|
@@ -1441,23 +1399,12 @@ class Archetype(
|
|
|
1441
1399
|
self,
|
|
1442
1400
|
sym_name=name.value,
|
|
1443
1401
|
name_spec=name,
|
|
1444
|
-
sym_category=
|
|
1445
|
-
SymbolType.OBJECT_ARCH
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
else (
|
|
1451
|
-
SymbolType.EDGE_ARCH
|
|
1452
|
-
if arch_type.name == Tok.KW_EDGE
|
|
1453
|
-
else (
|
|
1454
|
-
SymbolType.WALKER_ARCH
|
|
1455
|
-
if arch_type.name == Tok.KW_WALKER
|
|
1456
|
-
else SymbolType.TYPE
|
|
1457
|
-
)
|
|
1458
|
-
)
|
|
1459
|
-
)
|
|
1460
|
-
),
|
|
1402
|
+
sym_category={
|
|
1403
|
+
Tok.KW_OBJECT.value: SymbolType.OBJECT_ARCH,
|
|
1404
|
+
Tok.KW_NODE.value: SymbolType.NODE_ARCH,
|
|
1405
|
+
Tok.KW_EDGE.value: SymbolType.EDGE_ARCH,
|
|
1406
|
+
Tok.KW_WALKER.value: SymbolType.WALKER_ARCH,
|
|
1407
|
+
}.get(arch_type.name, SymbolType.TYPE),
|
|
1461
1408
|
)
|
|
1462
1409
|
AstImplNeedingNode.__init__(self, body=body)
|
|
1463
1410
|
AstAccessNode.__init__(self, access=access)
|
|
@@ -1941,11 +1888,19 @@ class FuncSignature(UniNode):
|
|
|
1941
1888
|
|
|
1942
1889
|
def __init__(
|
|
1943
1890
|
self,
|
|
1891
|
+
posonly_params: Sequence[ParamVar],
|
|
1944
1892
|
params: Sequence[ParamVar] | None,
|
|
1893
|
+
varargs: Optional[ParamVar],
|
|
1894
|
+
kwonlyargs: Sequence[ParamVar],
|
|
1895
|
+
kwargs: Optional[ParamVar],
|
|
1945
1896
|
return_type: Optional[Expr],
|
|
1946
1897
|
kid: Sequence[UniNode],
|
|
1947
1898
|
) -> None:
|
|
1899
|
+
self.posonly_params: list[ParamVar] = list(posonly_params)
|
|
1948
1900
|
self.params: list[ParamVar] = list(params) if params else []
|
|
1901
|
+
self.varargs = varargs
|
|
1902
|
+
self.kwonlyargs: list[ParamVar] = list(kwonlyargs)
|
|
1903
|
+
self.kwargs = kwargs
|
|
1949
1904
|
self.return_type = return_type
|
|
1950
1905
|
UniNode.__init__(self, kid=kid)
|
|
1951
1906
|
|
|
@@ -1953,14 +1908,36 @@ class FuncSignature(UniNode):
|
|
|
1953
1908
|
res = True
|
|
1954
1909
|
is_lambda = self.parent and isinstance(self.parent, LambdaExpr)
|
|
1955
1910
|
if deep:
|
|
1911
|
+
for prm in self.posonly_params:
|
|
1912
|
+
res = res and prm.normalize(deep)
|
|
1956
1913
|
for prm in self.params:
|
|
1957
1914
|
res = res and prm.normalize(deep)
|
|
1958
1915
|
res = res and self.return_type.normalize(deep) if self.return_type else res
|
|
1959
1916
|
new_kid: list[UniNode] = [self.gen_token(Tok.LPAREN)] if not is_lambda else []
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1917
|
+
if self.posonly_params:
|
|
1918
|
+
for prm in self.posonly_params:
|
|
1919
|
+
new_kid.append(prm)
|
|
1963
1920
|
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1921
|
+
new_kid.append(self.gen_token(Tok.DIV))
|
|
1922
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1923
|
+
if self.params:
|
|
1924
|
+
for prm in self.params:
|
|
1925
|
+
new_kid.append(prm)
|
|
1926
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1927
|
+
if self.varargs:
|
|
1928
|
+
new_kid.append(self.varargs)
|
|
1929
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1930
|
+
elif self.kwonlyargs:
|
|
1931
|
+
new_kid.append(self.gen_token(Tok.STAR_MUL))
|
|
1932
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1933
|
+
for prm in self.kwonlyargs:
|
|
1934
|
+
new_kid.append(prm)
|
|
1935
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1936
|
+
if self.kwargs:
|
|
1937
|
+
new_kid.append(self.kwargs)
|
|
1938
|
+
new_kid.append(self.gen_token(Tok.COMMA))
|
|
1939
|
+
if new_kid and isinstance(new_kid[-1], Token) and new_kid[-1].name == Tok.COMMA:
|
|
1940
|
+
new_kid = new_kid[:-1]
|
|
1964
1941
|
if not is_lambda:
|
|
1965
1942
|
new_kid.append(self.gen_token(Tok.RPAREN))
|
|
1966
1943
|
if self.return_type:
|
|
@@ -1969,6 +1946,16 @@ class FuncSignature(UniNode):
|
|
|
1969
1946
|
self.set_kids(nodes=new_kid)
|
|
1970
1947
|
return res
|
|
1971
1948
|
|
|
1949
|
+
def get_parameters(self) -> list[ParamVar]:
|
|
1950
|
+
"""Return all parameters in the declared order."""
|
|
1951
|
+
params = self.posonly_params + self.params
|
|
1952
|
+
if self.varargs:
|
|
1953
|
+
params.append(self.varargs)
|
|
1954
|
+
params += self.kwonlyargs
|
|
1955
|
+
if self.kwargs:
|
|
1956
|
+
params.append(self.kwargs)
|
|
1957
|
+
return params
|
|
1958
|
+
|
|
1972
1959
|
@property
|
|
1973
1960
|
def is_static(self) -> bool:
|
|
1974
1961
|
return (isinstance(self.parent, Ability) and self.parent.is_static) or (
|
|
@@ -2025,6 +2012,16 @@ class EventSignature(WalkerStmtOnlyNode):
|
|
|
2025
2012
|
return res
|
|
2026
2013
|
|
|
2027
2014
|
|
|
2015
|
+
class ParamKind(IntEnum):
|
|
2016
|
+
"""Parameter kinds."""
|
|
2017
|
+
|
|
2018
|
+
POSONLY = 0
|
|
2019
|
+
NORMAL = 1
|
|
2020
|
+
VARARG = 2
|
|
2021
|
+
KWONLY = 3
|
|
2022
|
+
KWARG = 4
|
|
2023
|
+
|
|
2024
|
+
|
|
2028
2025
|
class ParamVar(AstSymbolNode, AstTypedVarNode):
|
|
2029
2026
|
"""ParamVar node type for Jac Ast."""
|
|
2030
2027
|
|
|
@@ -2038,6 +2035,7 @@ class ParamVar(AstSymbolNode, AstTypedVarNode):
|
|
|
2038
2035
|
) -> None:
|
|
2039
2036
|
self.name = name
|
|
2040
2037
|
self.unpack = unpack
|
|
2038
|
+
self.param_kind = ParamKind.NORMAL
|
|
2041
2039
|
self.value = value
|
|
2042
2040
|
UniNode.__init__(self, kid=kid)
|
|
2043
2041
|
AstSymbolNode.__init__(
|
|
@@ -2048,6 +2046,14 @@ class ParamVar(AstSymbolNode, AstTypedVarNode):
|
|
|
2048
2046
|
)
|
|
2049
2047
|
AstTypedVarNode.__init__(self, type_tag=type_tag)
|
|
2050
2048
|
|
|
2049
|
+
@property
|
|
2050
|
+
def is_vararg(self) -> bool:
|
|
2051
|
+
return bool((self.unpack) and (self.unpack.name == Tok.STAR_MUL.name))
|
|
2052
|
+
|
|
2053
|
+
@property
|
|
2054
|
+
def is_kwargs(self) -> bool:
|
|
2055
|
+
return bool((self.unpack) and (self.unpack.name == Tok.STAR_POW.name))
|
|
2056
|
+
|
|
2051
2057
|
def normalize(self, deep: bool = True) -> bool:
|
|
2052
2058
|
res = True
|
|
2053
2059
|
if deep:
|
|
@@ -2687,31 +2693,6 @@ class AssertStmt(CodeBlockStmt):
|
|
|
2687
2693
|
return res
|
|
2688
2694
|
|
|
2689
2695
|
|
|
2690
|
-
class CheckStmt(CodeBlockStmt):
|
|
2691
|
-
"""CheckStmt node type for Jac Ast."""
|
|
2692
|
-
|
|
2693
|
-
def __init__(
|
|
2694
|
-
self,
|
|
2695
|
-
target: Expr,
|
|
2696
|
-
kid: Sequence[UniNode],
|
|
2697
|
-
) -> None:
|
|
2698
|
-
self.target = target
|
|
2699
|
-
UniNode.__init__(self, kid=kid)
|
|
2700
|
-
CodeBlockStmt.__init__(self)
|
|
2701
|
-
|
|
2702
|
-
def normalize(self, deep: bool = False) -> bool:
|
|
2703
|
-
res = True
|
|
2704
|
-
if deep:
|
|
2705
|
-
res = self.target.normalize(deep)
|
|
2706
|
-
new_kid: list[UniNode] = [
|
|
2707
|
-
self.gen_token(Tok.KW_CHECK),
|
|
2708
|
-
self.target,
|
|
2709
|
-
self.gen_token(Tok.SEMI),
|
|
2710
|
-
]
|
|
2711
|
-
self.set_kids(nodes=new_kid)
|
|
2712
|
-
return res
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
2696
|
class CtrlStmt(CodeBlockStmt):
|
|
2716
2697
|
"""CtrlStmt node type for Jac Ast."""
|
|
2717
2698
|
|
|
@@ -3831,10 +3812,12 @@ class EdgeRefTrailer(Expr):
|
|
|
3831
3812
|
self,
|
|
3832
3813
|
chain: list[Expr | FilterCompr],
|
|
3833
3814
|
edges_only: bool,
|
|
3815
|
+
is_async: bool,
|
|
3834
3816
|
kid: Sequence[UniNode],
|
|
3835
3817
|
) -> None:
|
|
3836
3818
|
self.chain = chain
|
|
3837
3819
|
self.edges_only = edges_only
|
|
3820
|
+
self.is_async = is_async
|
|
3838
3821
|
UniNode.__init__(self, kid=kid)
|
|
3839
3822
|
Expr.__init__(self)
|
|
3840
3823
|
|
|
@@ -3844,6 +3827,8 @@ class EdgeRefTrailer(Expr):
|
|
|
3844
3827
|
res = res and expr.normalize(deep)
|
|
3845
3828
|
new_kid: list[UniNode] = []
|
|
3846
3829
|
new_kid.append(self.gen_token(Tok.LSQUARE))
|
|
3830
|
+
if self.is_async:
|
|
3831
|
+
new_kid.append(self.gen_token(Tok.KW_ASYNC))
|
|
3847
3832
|
if self.edges_only:
|
|
3848
3833
|
new_kid.append(self.gen_token(Tok.KW_EDGE))
|
|
3849
3834
|
new_kid.extend(self.chain)
|