jaclang 0.7.17__py3-none-any.whl → 0.7.19__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 +5 -7
- jaclang/compiler/passes/ir_pass.py +2 -0
- jaclang/compiler/passes/main/import_pass.py +2 -1
- jaclang/compiler/passes/main/py_collect_dep_pass.py +8 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +25 -0
- jaclang/compiler/passes/main/registry_pass.py +4 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.pyi +3 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +10 -10
- jaclang/compiler/passes/main/type_check_pass.py +4 -4
- jaclang/compiler/passes/tool/jac_formatter_pass.py +52 -32
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/line_spacing.jac +55 -0
- jaclang/langserve/engine.py +28 -16
- jaclang/langserve/tests/fixtures/import_include_statements.jac +3 -3
- jaclang/langserve/tests/test_server.py +10 -6
- jaclang/langserve/utils.py +11 -100
- jaclang/plugin/builtin.py +8 -4
- jaclang/plugin/default.py +17 -3
- jaclang/plugin/feature.py +10 -0
- jaclang/plugin/spec.py +12 -0
- jaclang/runtimelib/importer.py +2 -0
- jaclang/runtimelib/machine.py +45 -3
- jaclang/runtimelib/memory.py +6 -6
- jaclang/settings.py +4 -0
- jaclang/tests/fixtures/bar.jac +1 -1
- jaclang/tests/fixtures/builtin_dotgen.jac +1 -0
- jaclang/tests/fixtures/foo.jac +0 -1
- jaclang/tests/fixtures/objref.jac +12 -0
- jaclang/tests/fixtures/walker_update.jac +19 -0
- jaclang/tests/test_language.py +73 -4
- {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/METADATA +6 -2
- {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/RECORD +33 -29
- {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/WHEEL +0 -0
- {jaclang-0.7.17.dist-info → jaclang-0.7.19.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py
CHANGED
|
@@ -8,7 +8,6 @@ import pickle
|
|
|
8
8
|
import shutil
|
|
9
9
|
import types
|
|
10
10
|
from typing import Optional
|
|
11
|
-
from uuid import UUID
|
|
12
11
|
|
|
13
12
|
import jaclang.compiler.absyntree as ast
|
|
14
13
|
from jaclang import jac_import
|
|
@@ -159,10 +158,9 @@ def get_object(
|
|
|
159
158
|
raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
|
|
160
159
|
|
|
161
160
|
data = {}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
data = obj.__getstate__()
|
|
161
|
+
obj = Jac.get_object(id)
|
|
162
|
+
if obj:
|
|
163
|
+
data = obj.__jac__.__getstate__()
|
|
166
164
|
else:
|
|
167
165
|
print(f"Object with id {id} not found.")
|
|
168
166
|
|
|
@@ -431,8 +429,8 @@ def dot(
|
|
|
431
429
|
|
|
432
430
|
if filename.endswith(".jac"):
|
|
433
431
|
jac_machine = JacMachine(base)
|
|
434
|
-
jac_import(target=mod, base_path=base)
|
|
435
|
-
module = jac_machine.loaded_modules.get(
|
|
432
|
+
jac_import(target=mod, base_path=base, override_name="__main__")
|
|
433
|
+
module = jac_machine.loaded_modules.get("__main__")
|
|
436
434
|
globals().update(vars(module))
|
|
437
435
|
try:
|
|
438
436
|
node = globals().get(initial, eval(initial)) if initial else None
|
|
@@ -13,6 +13,7 @@ from typing import Optional
|
|
|
13
13
|
import jaclang.compiler.absyntree as ast
|
|
14
14
|
from jaclang.compiler.passes import Pass
|
|
15
15
|
from jaclang.compiler.passes.main import SubNodeTabPass, SymTabBuildPass
|
|
16
|
+
from jaclang.settings import settings
|
|
16
17
|
from jaclang.utils.log import logging
|
|
17
18
|
|
|
18
19
|
|
|
@@ -105,7 +106,7 @@ class JacImportPass(Pass):
|
|
|
105
106
|
or test_folder == os.path.dirname(cur_file)
|
|
106
107
|
) and cur_file.endswith(".test.jac"):
|
|
107
108
|
mod = self.import_jac_mod_from_file(cur_file)
|
|
108
|
-
if mod:
|
|
109
|
+
if mod and not settings.ignore_test_annex:
|
|
109
110
|
node.test_mod.append(mod)
|
|
110
111
|
node.add_kids_right([mod], pos_update=False)
|
|
111
112
|
mod.parent = node
|
|
@@ -7,6 +7,8 @@ that are only relevant to actual references source from Jac code.
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
9
|
|
|
10
|
+
import os
|
|
11
|
+
|
|
10
12
|
import jaclang.compiler.absyntree as ast
|
|
11
13
|
from jaclang.compiler.passes import Pass
|
|
12
14
|
from jaclang.settings import settings
|
|
@@ -28,11 +30,15 @@ class PyCollectDepsPass(Pass):
|
|
|
28
30
|
if not isinstance(node, ast.AstSymbolNode):
|
|
29
31
|
return
|
|
30
32
|
|
|
33
|
+
# Adding the path of the file related to the py import
|
|
31
34
|
path: str = ""
|
|
32
35
|
if isinstance(node, ast.ModulePath):
|
|
33
36
|
if node.path:
|
|
34
37
|
path = ".".join([i.value for i in node.path])
|
|
35
38
|
node.abs_path = self.ir.py_mod_dep_map.get(path)
|
|
39
|
+
if node.abs_path and os.path.isfile(node.abs_path.replace(".pyi", ".py")):
|
|
40
|
+
node.abs_path = node.abs_path.replace(".pyi", ".py")
|
|
41
|
+
|
|
36
42
|
elif isinstance(node, ast.ModuleItem):
|
|
37
43
|
imp = node.parent_of_type(ast.Import)
|
|
38
44
|
mod_path_node = imp.get_all_sub_nodes(ast.ModulePath)[0]
|
|
@@ -40,6 +46,8 @@ class PyCollectDepsPass(Pass):
|
|
|
40
46
|
path = ".".join([i.value for i in mod_path_node.path])
|
|
41
47
|
path += f".{node.name.value}"
|
|
42
48
|
node.abs_path = self.ir.py_mod_dep_map.get(path)
|
|
49
|
+
if node.abs_path and os.path.isfile(node.abs_path.replace(".pyi", ".py")):
|
|
50
|
+
node.abs_path = node.abs_path.replace(".pyi", ".py")
|
|
43
51
|
|
|
44
52
|
if len(node.gen.mypy_ast) == 0:
|
|
45
53
|
return
|
|
@@ -2641,6 +2641,31 @@ class PyastGenPass(Pass):
|
|
|
2641
2641
|
]
|
|
2642
2642
|
elif node.op.name in [Tok.STAR_POW]:
|
|
2643
2643
|
node.gen.py_ast = node.operand.gen.py_ast
|
|
2644
|
+
elif node.op.name in [Tok.BW_AND]:
|
|
2645
|
+
node.gen.py_ast = [
|
|
2646
|
+
self.sync(
|
|
2647
|
+
ast3.Call(
|
|
2648
|
+
func=self.sync(
|
|
2649
|
+
ast3.Attribute(
|
|
2650
|
+
value=self.sync(
|
|
2651
|
+
ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
|
|
2652
|
+
),
|
|
2653
|
+
attr="get_object",
|
|
2654
|
+
ctx=ast3.Load(),
|
|
2655
|
+
)
|
|
2656
|
+
),
|
|
2657
|
+
args=[],
|
|
2658
|
+
keywords=[
|
|
2659
|
+
self.sync(
|
|
2660
|
+
ast3.keyword(
|
|
2661
|
+
arg="id",
|
|
2662
|
+
value=node.operand.gen.py_ast[0],
|
|
2663
|
+
)
|
|
2664
|
+
),
|
|
2665
|
+
],
|
|
2666
|
+
)
|
|
2667
|
+
)
|
|
2668
|
+
]
|
|
2644
2669
|
else:
|
|
2645
2670
|
self.ice(f"Unknown Unary operator {node.op.value}")
|
|
2646
2671
|
|
|
@@ -14,6 +14,7 @@ from jaclang.compiler.constant import Constants as Con
|
|
|
14
14
|
from jaclang.compiler.passes import Pass
|
|
15
15
|
from jaclang.compiler.semtable import SemInfo, SemRegistry
|
|
16
16
|
from jaclang.runtimelib.utils import get_sem_scope
|
|
17
|
+
from jaclang.settings import settings
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class RegistryPass(Pass):
|
|
@@ -23,6 +24,9 @@ class RegistryPass(Pass):
|
|
|
23
24
|
|
|
24
25
|
def enter_module(self, node: ast.Module) -> None:
|
|
25
26
|
"""Create registry for each module."""
|
|
27
|
+
if settings.disable_mtllm:
|
|
28
|
+
self.terminate()
|
|
29
|
+
return None
|
|
26
30
|
node.registry = SemRegistry()
|
|
27
31
|
self.modules_visited.append(node)
|
|
28
32
|
|
|
@@ -70,19 +70,19 @@ class ImportPassPassTests(TestCase):
|
|
|
70
70
|
)
|
|
71
71
|
assert isinstance(build.ir, ast.Module)
|
|
72
72
|
p = {
|
|
73
|
-
"math": "jaclang/
|
|
74
|
-
"pygame_mock": "pygame_mock/__init__.
|
|
75
|
-
"pygame_mock.color": "pygame_mock/color.py",
|
|
76
|
-
"pygame_mock.constants": "pygame_mock/constants.py",
|
|
77
|
-
"argparse": "jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi",
|
|
78
|
-
"builtins": "jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi",
|
|
79
|
-
"pygame_mock.display": "pygame_mock/display.py",
|
|
80
|
-
"os": "jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi",
|
|
81
|
-
"genericpath": "jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi",
|
|
73
|
+
"math": r"jaclang/vendor/mypy/typeshed/stdlib/math.pyi$",
|
|
74
|
+
"pygame_mock": r"pygame_mock/__init__.pyi$",
|
|
75
|
+
"pygame_mock.color": r"pygame_mock/color.py$",
|
|
76
|
+
"pygame_mock.constants": r"pygame_mock/constants.py$",
|
|
77
|
+
"argparse": r"jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi$",
|
|
78
|
+
"builtins": r"jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi$",
|
|
79
|
+
"pygame_mock.display": r"pygame_mock/display.py$",
|
|
80
|
+
"os": r"jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi$",
|
|
81
|
+
"genericpath": r"jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi$",
|
|
82
82
|
}
|
|
83
83
|
for i in p:
|
|
84
84
|
self.assertIn(i, build.ir.py_raise_map)
|
|
85
|
-
self.
|
|
85
|
+
self.assertRegex(re.sub(r".*fixtures/", "", build.ir.py_raise_map[i]), p[i])
|
|
86
86
|
|
|
87
87
|
def test_py_raised_mods(self) -> None:
|
|
88
88
|
"""Basic test for pass."""
|
|
@@ -51,10 +51,10 @@ class JacTypeCheckPass(Pass):
|
|
|
51
51
|
options.ignore_missing_imports = True
|
|
52
52
|
options.cache_dir = Con.JAC_MYPY_CACHE
|
|
53
53
|
options.mypy_path = [
|
|
54
|
-
str(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
54
|
+
# str( # TODO: Remove me, this was the wrong way to point to stubs
|
|
55
|
+
# pathlib.Path(os.path.dirname(__file__)).parent.parent.parent.parent
|
|
56
|
+
# / "stubs"
|
|
57
|
+
# )
|
|
58
58
|
]
|
|
59
59
|
if top_module_path != "":
|
|
60
60
|
options.mypy_path.append(top_module_path)
|
|
@@ -126,11 +126,14 @@ class JacFormatPass(Pass):
|
|
|
126
126
|
last_element = None
|
|
127
127
|
for counter, i in enumerate(node.body):
|
|
128
128
|
counter += 1
|
|
129
|
+
if last_element and (
|
|
130
|
+
i.loc.first_line - last_element.loc.last_line > 1
|
|
131
|
+
and not last_element.gen.jac.endswith("\n\n")
|
|
132
|
+
):
|
|
133
|
+
self.emit_ln(node, "")
|
|
129
134
|
if isinstance(i, ast.Import):
|
|
130
135
|
self.emit_ln(node, i.gen.jac)
|
|
131
136
|
else:
|
|
132
|
-
if isinstance(last_element, ast.Import):
|
|
133
|
-
self.emit_ln(node, "")
|
|
134
137
|
if last_element and (
|
|
135
138
|
isinstance(i, ast.Architype)
|
|
136
139
|
and isinstance(last_element, ast.Architype)
|
|
@@ -140,21 +143,6 @@ class JacFormatPass(Pass):
|
|
|
140
143
|
self.emit_ln(node, "")
|
|
141
144
|
self.emit_ln(node, i.gen.jac)
|
|
142
145
|
|
|
143
|
-
if counter <= len(node.body) - 1:
|
|
144
|
-
if (
|
|
145
|
-
isinstance(i, ast.Ability)
|
|
146
|
-
and isinstance(node.body[counter], ast.Ability)
|
|
147
|
-
and i.gen.jac.endswith(";")
|
|
148
|
-
or (
|
|
149
|
-
isinstance(i, ast.Architype)
|
|
150
|
-
and len(node.body[counter].kid[-1].kid) == 2
|
|
151
|
-
and len(node.body[counter - 1].kid[-1].kid) == 2
|
|
152
|
-
)
|
|
153
|
-
and node.gen.jac.endswith("\n")
|
|
154
|
-
):
|
|
155
|
-
self.emit(node, "")
|
|
156
|
-
else:
|
|
157
|
-
self.emit_ln(node, "")
|
|
158
146
|
last_element = i
|
|
159
147
|
|
|
160
148
|
def exit_global_vars(self, node: ast.GlobalVars) -> None:
|
|
@@ -222,6 +210,20 @@ class JacFormatPass(Pass):
|
|
|
222
210
|
"""
|
|
223
211
|
prev_token = None
|
|
224
212
|
for stmt in node.kid:
|
|
213
|
+
line_emiited = False
|
|
214
|
+
if prev_token and stmt.loc.first_line - prev_token.loc.last_line > 1:
|
|
215
|
+
if (
|
|
216
|
+
stmt.kid
|
|
217
|
+
and isinstance(stmt.kid[-1], ast.SubNodeList)
|
|
218
|
+
and not isinstance(stmt.kid[-1].kid[-1], ast.CommentToken)
|
|
219
|
+
):
|
|
220
|
+
self.emit(node, "")
|
|
221
|
+
|
|
222
|
+
else:
|
|
223
|
+
line_emiited = True
|
|
224
|
+
self.indent_level -= 1
|
|
225
|
+
self.emit_ln(node, "")
|
|
226
|
+
self.indent_level += 1
|
|
225
227
|
if isinstance(node.parent, (ast.EnumDef, ast.Enum)) and stmt.gen.jac == ",":
|
|
226
228
|
self.indent_level -= 1
|
|
227
229
|
self.emit_ln(node, f"{stmt.gen.jac}")
|
|
@@ -266,9 +268,10 @@ class JacFormatPass(Pass):
|
|
|
266
268
|
self.indent_level += 1
|
|
267
269
|
else:
|
|
268
270
|
self.emit(node, f" {stmt.gen.jac}")
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
271
|
+
if not line_emiited:
|
|
272
|
+
self.indent_level -= 1
|
|
273
|
+
self.emit_ln(node, "")
|
|
274
|
+
self.indent_level += 1
|
|
272
275
|
else:
|
|
273
276
|
if not node.gen.jac.endswith("\n"):
|
|
274
277
|
self.indent_level -= 1
|
|
@@ -280,11 +283,10 @@ class JacFormatPass(Pass):
|
|
|
280
283
|
self.emit(node, f"{stmt.gen.jac}")
|
|
281
284
|
else:
|
|
282
285
|
self.emit(node, stmt.gen.jac)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
self.indent_level += 1
|
|
286
|
+
self.indent_level -= 1
|
|
287
|
+
self.emit_ln(stmt, "")
|
|
288
|
+
self.emit_ln(node, "")
|
|
289
|
+
self.indent_level += 1
|
|
288
290
|
elif stmt.gen.jac == ",":
|
|
289
291
|
self.emit(node, f"{stmt.value} ")
|
|
290
292
|
elif stmt.value == "=":
|
|
@@ -304,10 +306,29 @@ class JacFormatPass(Pass):
|
|
|
304
306
|
isinstance(prev_token, ast.Ability)
|
|
305
307
|
and isinstance(stmt, (ast.Ability, ast.AbilityDef))
|
|
306
308
|
):
|
|
307
|
-
if
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
309
|
+
if (
|
|
310
|
+
not isinstance(prev_token.kid[-1], ast.CommentToken)
|
|
311
|
+
and not line_emiited
|
|
312
|
+
):
|
|
313
|
+
if (
|
|
314
|
+
prev_token.kid
|
|
315
|
+
and isinstance(prev_token.kid[-1], ast.SubNodeList)
|
|
316
|
+
and isinstance(prev_token.kid[-1].kid[-1], ast.CommentToken)
|
|
317
|
+
):
|
|
318
|
+
if (
|
|
319
|
+
prev_token
|
|
320
|
+
and stmt.loc.first_line - prev_token.kid[-1].kid[-1].line_no
|
|
321
|
+
> 1
|
|
322
|
+
):
|
|
323
|
+
self.indent_level -= 1
|
|
324
|
+
self.emit_ln(node, "")
|
|
325
|
+
self.indent_level += 1
|
|
326
|
+
else:
|
|
327
|
+
self.emit(node, "")
|
|
328
|
+
else:
|
|
329
|
+
self.indent_level -= 1
|
|
330
|
+
self.emit_ln(node, "")
|
|
331
|
+
self.indent_level += 1
|
|
311
332
|
self.emit(node, stmt.gen.jac)
|
|
312
333
|
else:
|
|
313
334
|
if prev_token and prev_token.gen.jac.strip() == "{":
|
|
@@ -907,8 +928,6 @@ class JacFormatPass(Pass):
|
|
|
907
928
|
"""Check if the length of the current generated code exceeds the max line length."""
|
|
908
929
|
if max_line_length == 0:
|
|
909
930
|
max_line_length = self.MAX_LINE_LENGTH
|
|
910
|
-
# print(content)
|
|
911
|
-
# print(len(content))
|
|
912
931
|
return len(content) > max_line_length
|
|
913
932
|
|
|
914
933
|
def exit_binary_expr(self, node: ast.BinaryExpr) -> None:
|
|
@@ -958,7 +977,6 @@ class JacFormatPass(Pass):
|
|
|
958
977
|
self.error(
|
|
959
978
|
f"Binary operator {node.op.value} not supported in bootstrap Jac"
|
|
960
979
|
)
|
|
961
|
-
# print(node.gen)
|
|
962
980
|
if isinstance(
|
|
963
981
|
node.kid[-1], (ast.Semi, ast.CommentToken)
|
|
964
982
|
) and not node.gen.jac.endswith("\n"):
|
|
@@ -1562,6 +1580,8 @@ class JacFormatPass(Pass):
|
|
|
1562
1580
|
self.emit(node, f"not {node.operand.gen.jac}")
|
|
1563
1581
|
elif node.op.name in [Tok.PIPE_FWD, Tok.KW_SPAWN, Tok.A_PIPE_FWD]:
|
|
1564
1582
|
self.emit(node, f"{node.op.value} {node.operand.gen.jac}")
|
|
1583
|
+
elif node.op.name in [Tok.BW_AND]:
|
|
1584
|
+
self.emit(node, f"{node.op.value}{node.operand.gen.jac}")
|
|
1565
1585
|
else:
|
|
1566
1586
|
self.error(f"Unary operator {node.op.value} not supported in bootstrap Jac")
|
|
1567
1587
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import:py math;
|
|
2
|
+
|
|
3
|
+
glob RAD = 5;
|
|
4
|
+
glob DIA = 10;
|
|
5
|
+
|
|
6
|
+
# this comment is for walker
|
|
7
|
+
walker decorator_walk {
|
|
8
|
+
can hash(func: Any) {
|
|
9
|
+
can inner(a: Any) {
|
|
10
|
+
print(("#" * 20));
|
|
11
|
+
func(a);
|
|
12
|
+
print(("#" * 20));
|
|
13
|
+
}
|
|
14
|
+
return inner;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
can exclaim(func: Any) {
|
|
18
|
+
can inner(b: Any) {
|
|
19
|
+
print(("!" * 20));
|
|
20
|
+
func(b);
|
|
21
|
+
print(("!" * 20));
|
|
22
|
+
}
|
|
23
|
+
return inner;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
can tilde(func: Any) {
|
|
27
|
+
can inner(c: Any) {
|
|
28
|
+
print(("~" * 20));
|
|
29
|
+
func(c);
|
|
30
|
+
print(("~" * 20));
|
|
31
|
+
}
|
|
32
|
+
return inner;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
can greeter(name: Any) {
|
|
36
|
+
print("Hello, " + name + "!");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# Entry point for the walker
|
|
40
|
+
|
|
41
|
+
can start with entry {
|
|
42
|
+
# Apply decorators to greeter
|
|
43
|
+
decorated_greeter = hash(exclaim(tilde(greeter)));
|
|
44
|
+
|
|
45
|
+
# Call the decorated greeter function
|
|
46
|
+
decorated_greeter("World");
|
|
47
|
+
|
|
48
|
+
# this is another comment
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
with entry {
|
|
54
|
+
root spawn decorator_walk();
|
|
55
|
+
}
|
jaclang/langserve/engine.py
CHANGED
|
@@ -22,8 +22,7 @@ from jaclang.langserve.utils import (
|
|
|
22
22
|
find_deepest_symbol_node_at_pos,
|
|
23
23
|
find_index,
|
|
24
24
|
gen_diagnostics,
|
|
25
|
-
|
|
26
|
-
get_mod_path,
|
|
25
|
+
get_location_range,
|
|
27
26
|
get_symbols_for_outline,
|
|
28
27
|
parse_symbol_path,
|
|
29
28
|
resolve_completion_symbol_table,
|
|
@@ -335,8 +334,9 @@ class JacLangServer(LanguageServer):
|
|
|
335
334
|
and node_selected.parent
|
|
336
335
|
and isinstance(node_selected.parent, ast.ModulePath)
|
|
337
336
|
):
|
|
338
|
-
spec =
|
|
337
|
+
spec = node_selected.parent.abs_path
|
|
339
338
|
if spec:
|
|
339
|
+
spec = spec[5:] if spec.startswith("File:") else spec
|
|
340
340
|
return lspt.Location(
|
|
341
341
|
uri=uris.from_fs_path(spec),
|
|
342
342
|
range=lspt.Range(
|
|
@@ -349,19 +349,31 @@ class JacLangServer(LanguageServer):
|
|
|
349
349
|
elif node_selected.parent and isinstance(
|
|
350
350
|
node_selected.parent, ast.ModuleItem
|
|
351
351
|
):
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
352
|
+
path = (
|
|
353
|
+
node_selected.parent.abs_path
|
|
354
|
+
or node_selected.parent.from_mod_path.abs_path
|
|
355
|
+
)
|
|
356
|
+
try: # TODO: Get rid of this when 'from' import is fixed
|
|
357
|
+
loc_range = tuple(
|
|
358
|
+
loc - 1 if loc > 0 else loc
|
|
359
|
+
for loc in get_location_range(node_selected.parent)
|
|
360
|
+
)
|
|
361
|
+
except ValueError:
|
|
362
|
+
loc_range = (0, 0, 0, 0)
|
|
363
|
+
|
|
364
|
+
if path and loc_range:
|
|
365
|
+
path = path[5:] if path.startswith("File:") else path
|
|
366
|
+
return lspt.Location(
|
|
367
|
+
uri=uris.from_fs_path(path),
|
|
368
|
+
range=lspt.Range(
|
|
369
|
+
start=lspt.Position(
|
|
370
|
+
line=loc_range[0], character=loc_range[1]
|
|
361
371
|
),
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
372
|
+
end=lspt.Position(
|
|
373
|
+
line=loc_range[2], character=loc_range[3]
|
|
374
|
+
),
|
|
375
|
+
),
|
|
376
|
+
)
|
|
365
377
|
elif isinstance(node_selected, (ast.ElementStmt, ast.BuiltinType)):
|
|
366
378
|
return None
|
|
367
379
|
decl_node = (
|
|
@@ -378,7 +390,7 @@ class JacLangServer(LanguageServer):
|
|
|
378
390
|
decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
|
|
379
391
|
try:
|
|
380
392
|
decl_range = create_range(decl_node.loc)
|
|
381
|
-
except ValueError:
|
|
393
|
+
except ValueError:
|
|
382
394
|
return None
|
|
383
395
|
decl_location = lspt.Location(
|
|
384
396
|
uri=decl_uri,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import:py os;
|
|
2
|
-
import:py from math
|
|
2
|
+
import:py from math{ sqrt as square_root}
|
|
3
3
|
import:py datetime as dt;
|
|
4
|
-
import:jac from base_module_structure
|
|
4
|
+
import:jac from base_module_structure{ add as add_numbers , subtract,x,Colorenum as clr}
|
|
5
5
|
import:jac base_module_structure as base_module_structure;
|
|
6
|
-
import:py from py_import
|
|
6
|
+
import:py from py_import{add1 as ss, sub1 as subtract1,apple,Orange1}
|
|
@@ -187,11 +187,15 @@ class TestJacLangServer(TestCase):
|
|
|
187
187
|
)
|
|
188
188
|
lsp.deep_check(import_file)
|
|
189
189
|
positions = [
|
|
190
|
-
(
|
|
190
|
+
(0, 12, "tdlib/os/__init__.pyi:0:0-0:0"),
|
|
191
|
+
(1, 18, "stdlib/math.pyi:0:0-0:0"),
|
|
192
|
+
(2, 24, "datetime.pyi:0:0-0:0"),
|
|
191
193
|
(3, 17, "base_module_structure.jac:0:0-0:0"),
|
|
192
|
-
(3, 87, "base_module_structure.jac:23:
|
|
193
|
-
(5, 65, "py_import.py:
|
|
194
|
-
(5, 35, "py_import.py:
|
|
194
|
+
(3, 87, "base_module_structure.jac:23:5-23:14"),
|
|
195
|
+
(5, 65, "py_import.py:0:0-0:0"),
|
|
196
|
+
(5, 35, "py_import.py:0:0-0:0"),
|
|
197
|
+
# (5, 65, "py_import.py:12:0-20:5"), # TODO : Should work after 'from' import files are raised
|
|
198
|
+
# (5, 35, "py_import.py:3:0-4:5"),
|
|
195
199
|
]
|
|
196
200
|
|
|
197
201
|
for line, char, expected in positions:
|
|
@@ -214,9 +218,9 @@ class TestJacLangServer(TestCase):
|
|
|
214
218
|
)
|
|
215
219
|
lsp.deep_check(import_file)
|
|
216
220
|
positions = [
|
|
217
|
-
(6, 39, "/pygame_mock/__init__.
|
|
221
|
+
(6, 39, "/pygame_mock/__init__.pyi:2:0-2:0"),
|
|
218
222
|
(6, 45, "/pygame_mock/constants.py:3:0-4:1"),
|
|
219
|
-
(7, 31, "/pygame_mock/__init__.
|
|
223
|
+
(7, 31, "/pygame_mock/__init__.pyi:2:0-2:0"),
|
|
220
224
|
(7, 35, "/pygame_mock/constants.py:3:0-4:1"),
|
|
221
225
|
(20, 51, "/py_imp_test.jac:6:4-6:11"),
|
|
222
226
|
(20, 64, "/pygame_mock/constants.py:4:3-4:15"),
|
jaclang/langserve/utils.py
CHANGED
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import builtins
|
|
5
|
-
import importlib.util
|
|
6
|
-
import os
|
|
7
5
|
import re
|
|
8
|
-
import sys
|
|
9
6
|
from functools import wraps
|
|
10
7
|
from typing import Any, Awaitable, Callable, Coroutine, Optional, ParamSpec, TypeVar
|
|
11
8
|
|
|
@@ -209,6 +206,17 @@ def create_range(loc: CodeLocInfo) -> lspt.Range:
|
|
|
209
206
|
)
|
|
210
207
|
|
|
211
208
|
|
|
209
|
+
def get_location_range(mod_item: ast.ModuleItem) -> tuple[int, int, int, int]:
|
|
210
|
+
"""Get location range."""
|
|
211
|
+
if not mod_item.from_mod_path.sub_module:
|
|
212
|
+
raise ValueError("Module items should have module path. Not Possible.")
|
|
213
|
+
lookup = mod_item.from_mod_path.sub_module.sym_tab.lookup(mod_item.name.value)
|
|
214
|
+
if not lookup:
|
|
215
|
+
raise ValueError("Module items should have a symbol table entry. Not Possible.")
|
|
216
|
+
loc = lookup.decl.loc
|
|
217
|
+
return loc.first_line, loc.col_start, loc.last_line, loc.col_end
|
|
218
|
+
|
|
219
|
+
|
|
212
220
|
def kind_map(sub_tab: ast.AstNode) -> lspt.SymbolKind:
|
|
213
221
|
"""Map the symbol node to an lspt.SymbolKind."""
|
|
214
222
|
return (
|
|
@@ -273,103 +281,6 @@ def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
|
|
|
273
281
|
)
|
|
274
282
|
|
|
275
283
|
|
|
276
|
-
def get_mod_path(
|
|
277
|
-
mod_path: ast.ModulePath, name_node: ast.Name
|
|
278
|
-
) -> str | None: # TODO: This should go away
|
|
279
|
-
"""Get path for a module import name."""
|
|
280
|
-
ret_target = None
|
|
281
|
-
if mod_path.parent and (
|
|
282
|
-
(
|
|
283
|
-
isinstance(mod_path.parent.parent, ast.Import)
|
|
284
|
-
and mod_path.parent.parent.is_py
|
|
285
|
-
)
|
|
286
|
-
or (
|
|
287
|
-
isinstance(mod_path.parent, ast.Import)
|
|
288
|
-
and mod_path.parent.from_loc
|
|
289
|
-
and mod_path.parent.is_py
|
|
290
|
-
)
|
|
291
|
-
):
|
|
292
|
-
if mod_path.path and name_node in mod_path.path:
|
|
293
|
-
temporary_path_str = ("." * mod_path.level) + ".".join(
|
|
294
|
-
[p.value for p in mod_path.path[: mod_path.path.index(name_node) + 1]]
|
|
295
|
-
if mod_path.path
|
|
296
|
-
else ""
|
|
297
|
-
)
|
|
298
|
-
else:
|
|
299
|
-
temporary_path_str = mod_path.dot_path_str
|
|
300
|
-
sys.path.append(os.path.dirname(mod_path.loc.mod_path))
|
|
301
|
-
spec = importlib.util.find_spec(temporary_path_str)
|
|
302
|
-
sys.path.remove(os.path.dirname(mod_path.loc.mod_path))
|
|
303
|
-
if spec and spec.origin and spec.origin.endswith(".py"):
|
|
304
|
-
ret_target = spec.origin
|
|
305
|
-
elif mod_path.parent and (
|
|
306
|
-
(
|
|
307
|
-
isinstance(mod_path.parent.parent, ast.Import)
|
|
308
|
-
and mod_path.parent.parent.is_jac
|
|
309
|
-
)
|
|
310
|
-
or (
|
|
311
|
-
isinstance(mod_path.parent, ast.Import)
|
|
312
|
-
and mod_path.parent.from_loc
|
|
313
|
-
and mod_path.parent.is_jac
|
|
314
|
-
)
|
|
315
|
-
):
|
|
316
|
-
ret_target = mod_path.resolve_relative_path()
|
|
317
|
-
return ret_target
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
def get_item_path(mod_item: ast.ModuleItem) -> tuple[str, tuple[int, int]] | None:
|
|
321
|
-
"""Get path."""
|
|
322
|
-
item_name = mod_item.name.value
|
|
323
|
-
if mod_item.from_parent.is_py and mod_item.from_parent.from_loc:
|
|
324
|
-
path = get_mod_path(mod_item.from_parent.from_loc, mod_item.name)
|
|
325
|
-
if path:
|
|
326
|
-
return get_definition_range(path, item_name)
|
|
327
|
-
elif mod_item.from_parent.is_jac:
|
|
328
|
-
mod_node = mod_item.from_mod_path
|
|
329
|
-
if mod_node.sub_module and mod_node.sub_module._sym_tab:
|
|
330
|
-
for symbol_name, symbol in mod_node.sub_module._sym_tab.tab.items():
|
|
331
|
-
if symbol_name == item_name:
|
|
332
|
-
return symbol.decl.loc.mod_path, (
|
|
333
|
-
symbol.decl.loc.first_line - 1,
|
|
334
|
-
symbol.decl.loc.last_line - 1,
|
|
335
|
-
)
|
|
336
|
-
return None
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def get_definition_range(
|
|
340
|
-
filename: str, name: str
|
|
341
|
-
) -> tuple[str, tuple[int, int]] | None:
|
|
342
|
-
"""Get the start and end line of a function or class definition in a file."""
|
|
343
|
-
import ast
|
|
344
|
-
|
|
345
|
-
with open(filename, "r") as file:
|
|
346
|
-
source = file.read()
|
|
347
|
-
|
|
348
|
-
tree = ast.parse(source)
|
|
349
|
-
|
|
350
|
-
for node in ast.walk(tree):
|
|
351
|
-
if isinstance(node, (ast.FunctionDef, ast.ClassDef)) and node.name == name:
|
|
352
|
-
start_line = node.lineno
|
|
353
|
-
end_line = (
|
|
354
|
-
node.body[-1].end_lineno
|
|
355
|
-
if hasattr(node.body[-1], "end_lineno")
|
|
356
|
-
else node.body[-1].lineno
|
|
357
|
-
)
|
|
358
|
-
if start_line and end_line:
|
|
359
|
-
return filename, (start_line - 1, end_line - 1)
|
|
360
|
-
elif isinstance(node, ast.Assign):
|
|
361
|
-
for target in node.targets:
|
|
362
|
-
if isinstance(target, ast.Name) and target.id == name:
|
|
363
|
-
start_line = node.lineno
|
|
364
|
-
end_line = (
|
|
365
|
-
node.end_lineno if hasattr(node, "end_lineno") else node.lineno
|
|
366
|
-
)
|
|
367
|
-
if start_line and end_line:
|
|
368
|
-
return filename, (start_line - 1, end_line - 1)
|
|
369
|
-
|
|
370
|
-
return None
|
|
371
|
-
|
|
372
|
-
|
|
373
284
|
def collect_all_symbols_in_scope(
|
|
374
285
|
sym_tab: SymbolTable, up_tree: bool = True
|
|
375
286
|
) -> list[lspt.CompletionItem]:
|