jaclang 0.7.9__py3-none-any.whl → 0.7.13__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 -3
- jaclang/compiler/absyntree.py +10 -2
- jaclang/compiler/parser.py +2 -1
- jaclang/compiler/passes/ir_pass.py +9 -0
- jaclang/compiler/passes/main/import_pass.py +15 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +238 -32
- jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
- jaclang/compiler/passes/main/tests/test_import_pass.py +13 -0
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -2
- jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
- jaclang/compiler/passes/main/type_check_pass.py +0 -17
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +1 -2
- jaclang/compiler/tests/test_importer.py +1 -1
- jaclang/core/importer.py +233 -62
- jaclang/langserve/engine.py +182 -136
- jaclang/langserve/server.py +29 -7
- jaclang/langserve/tests/fixtures/base_module_structure.jac +28 -2
- jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
- jaclang/langserve/tests/test_server.py +73 -66
- jaclang/langserve/utils.py +266 -0
- jaclang/plugin/default.py +7 -4
- jaclang/plugin/feature.py +3 -3
- jaclang/plugin/spec.py +3 -3
- jaclang/settings.py +1 -0
- jaclang/tests/fixtures/deep/one_lev.jac +6 -4
- jaclang/tests/fixtures/needs_import.jac +1 -1
- jaclang/tests/test_cli.py +7 -9
- jaclang/tests/test_language.py +9 -13
- jaclang/tests/test_man_code.py +8 -10
- jaclang/utils/helpers.py +3 -3
- jaclang/utils/test.py +8 -0
- {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/METADATA +2 -2
- {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/RECORD +35 -35
- {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/WHEEL +0 -0
- {jaclang-0.7.9.dist-info → jaclang-0.7.13.dist-info}/entry_points.txt +0 -0
|
@@ -39,36 +39,6 @@ class TestJacLangServer(TestCase):
|
|
|
39
39
|
],
|
|
40
40
|
)
|
|
41
41
|
|
|
42
|
-
def test_syntax_diagnostics(self) -> None:
|
|
43
|
-
"""Test diagnostics."""
|
|
44
|
-
lsp = JacLangServer()
|
|
45
|
-
# Set up the workspace path to "fixtures/"
|
|
46
|
-
workspace_path = self.fixture_abs_path("")
|
|
47
|
-
workspace = Workspace(workspace_path, lsp)
|
|
48
|
-
lsp.lsp._workspace = workspace
|
|
49
|
-
circle_file = uris.from_fs_path(self.fixture_abs_path("circle_err.jac"))
|
|
50
|
-
lsp.quick_check(circle_file)
|
|
51
|
-
self.assertEqual(len(lsp.modules), 1)
|
|
52
|
-
self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
|
|
53
|
-
|
|
54
|
-
def test_doesnt_run_if_syntax_error(self) -> None:
|
|
55
|
-
"""Test that the server doesn't run if there is a syntax error."""
|
|
56
|
-
lsp = JacLangServer()
|
|
57
|
-
# Set up the workspace path to "fixtures/"
|
|
58
|
-
workspace_path = self.fixture_abs_path("")
|
|
59
|
-
workspace = Workspace(workspace_path, lsp)
|
|
60
|
-
lsp.lsp._workspace = workspace
|
|
61
|
-
circle_file = uris.from_fs_path(self.fixture_abs_path("circle_err.jac"))
|
|
62
|
-
lsp.quick_check(circle_file)
|
|
63
|
-
self.assertEqual(len(lsp.modules), 1)
|
|
64
|
-
self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
|
|
65
|
-
lsp.deep_check(circle_file)
|
|
66
|
-
# self.assertEqual(len(lsp.modules), 1)
|
|
67
|
-
self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
|
|
68
|
-
lsp.type_check(circle_file)
|
|
69
|
-
# self.assertEqual(len(lsp.modules), 1)
|
|
70
|
-
self.assertEqual(lsp.modules[circle_file].diagnostics[0].range.start.line, 22)
|
|
71
|
-
|
|
72
42
|
def test_impl_stay_connected(self) -> None:
|
|
73
43
|
"""Test that the server doesn't run if there is a syntax error."""
|
|
74
44
|
lsp = JacLangServer()
|
|
@@ -80,15 +50,13 @@ class TestJacLangServer(TestCase):
|
|
|
80
50
|
circle_impl_file = uris.from_fs_path(
|
|
81
51
|
self.fixture_abs_path("circle_pure.impl.jac")
|
|
82
52
|
)
|
|
83
|
-
lsp.quick_check(circle_file)
|
|
84
53
|
lsp.deep_check(circle_file)
|
|
85
|
-
lsp.type_check(circle_file)
|
|
86
54
|
pos = lspt.Position(20, 8)
|
|
87
55
|
self.assertIn(
|
|
88
56
|
"Circle class inherits from Shape.",
|
|
89
57
|
lsp.get_hover_info(circle_file, pos).contents.value,
|
|
90
58
|
)
|
|
91
|
-
lsp.
|
|
59
|
+
lsp.deep_check(circle_impl_file)
|
|
92
60
|
pos = lspt.Position(8, 11)
|
|
93
61
|
self.assertIn(
|
|
94
62
|
"ability) calculate_area: float",
|
|
@@ -105,9 +73,7 @@ class TestJacLangServer(TestCase):
|
|
|
105
73
|
circle_impl_file = uris.from_fs_path(
|
|
106
74
|
self.fixture_abs_path("circle_pure.impl.jac")
|
|
107
75
|
)
|
|
108
|
-
lsp.quick_check(circle_impl_file)
|
|
109
76
|
lsp.deep_check(circle_impl_file)
|
|
110
|
-
lsp.type_check(circle_impl_file)
|
|
111
77
|
pos = lspt.Position(8, 11)
|
|
112
78
|
self.assertIn(
|
|
113
79
|
"ability) calculate_area: float",
|
|
@@ -121,12 +87,8 @@ class TestJacLangServer(TestCase):
|
|
|
121
87
|
workspace_path = self.fixture_abs_path("")
|
|
122
88
|
workspace = Workspace(workspace_path, lsp)
|
|
123
89
|
lsp.lsp._workspace = workspace
|
|
124
|
-
target = uris.from_fs_path(
|
|
125
|
-
self.fixture_abs_path("../../../../examples/guess_game/guess_game4.jac")
|
|
126
|
-
)
|
|
127
|
-
lsp.quick_check(target)
|
|
90
|
+
target = uris.from_fs_path(self.examples_abs_path("guess_game/guess_game4.jac"))
|
|
128
91
|
lsp.deep_check(target)
|
|
129
|
-
lsp.type_check(target)
|
|
130
92
|
pos = lspt.Position(43, 18)
|
|
131
93
|
self.assertIn(
|
|
132
94
|
"attempts: int",
|
|
@@ -140,9 +102,7 @@ class TestJacLangServer(TestCase):
|
|
|
140
102
|
workspace = Workspace(workspace_path, lsp)
|
|
141
103
|
lsp.lsp._workspace = workspace
|
|
142
104
|
circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.jac"))
|
|
143
|
-
lsp.quick_check(circle_file)
|
|
144
105
|
lsp.deep_check(circle_file)
|
|
145
|
-
lsp.type_check(circle_file)
|
|
146
106
|
self.assertEqual(8, len(lsp.get_document_symbols(circle_file)))
|
|
147
107
|
|
|
148
108
|
def test_go_to_definition(self) -> None:
|
|
@@ -152,9 +112,7 @@ class TestJacLangServer(TestCase):
|
|
|
152
112
|
workspace = Workspace(workspace_path, lsp)
|
|
153
113
|
lsp.lsp._workspace = workspace
|
|
154
114
|
circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.jac"))
|
|
155
|
-
lsp.quick_check(circle_file)
|
|
156
115
|
lsp.deep_check(circle_file)
|
|
157
|
-
lsp.type_check(circle_file)
|
|
158
116
|
self.assertIn(
|
|
159
117
|
"fixtures/circle_pure.impl.jac:8:0-8:19",
|
|
160
118
|
str(lsp.get_definition(circle_file, lspt.Position(9, 16))),
|
|
@@ -171,11 +129,9 @@ class TestJacLangServer(TestCase):
|
|
|
171
129
|
workspace = Workspace(workspace_path, lsp)
|
|
172
130
|
lsp.lsp._workspace = workspace
|
|
173
131
|
guess_game_file = uris.from_fs_path(
|
|
174
|
-
self.
|
|
132
|
+
self.examples_abs_path("guess_game/guess_game4.jac")
|
|
175
133
|
)
|
|
176
|
-
lsp.quick_check(guess_game_file)
|
|
177
134
|
lsp.deep_check(guess_game_file)
|
|
178
|
-
lsp.type_check(guess_game_file)
|
|
179
135
|
self.assertIn(
|
|
180
136
|
"guess_game4.jac:27:8-27:21",
|
|
181
137
|
str(lsp.get_definition(guess_game_file, lspt.Position(46, 45))),
|
|
@@ -189,9 +145,7 @@ class TestJacLangServer(TestCase):
|
|
|
189
145
|
workspace = Workspace(workspace_path, lsp)
|
|
190
146
|
lsp.lsp._workspace = workspace
|
|
191
147
|
circle_file = uris.from_fs_path(self.fixture_abs_path("circle_pure.test.jac"))
|
|
192
|
-
lsp.quick_check(circle_file)
|
|
193
148
|
lsp.deep_check(circle_file)
|
|
194
|
-
lsp.type_check(circle_file)
|
|
195
149
|
pos = lspt.Position(13, 29)
|
|
196
150
|
self.assertIn(
|
|
197
151
|
"shape_type: circle_pure.ShapeType",
|
|
@@ -207,13 +161,11 @@ class TestJacLangServer(TestCase):
|
|
|
207
161
|
import_file = uris.from_fs_path(
|
|
208
162
|
self.fixture_abs_path("import_include_statements.jac")
|
|
209
163
|
)
|
|
210
|
-
lsp.quick_check(import_file)
|
|
211
164
|
lsp.deep_check(import_file)
|
|
212
|
-
lsp.type_check(import_file)
|
|
213
165
|
positions = [
|
|
214
166
|
(2, 16, "datetime.py:0:0-0:0"),
|
|
215
167
|
(3, 17, "base_module_structure.jac:0:0-0:0"),
|
|
216
|
-
(3,
|
|
168
|
+
(3, 87, "base_module_structure.jac:23:0-23:5"),
|
|
217
169
|
(5, 65, "py_import.py:12:0-20:5"),
|
|
218
170
|
(5, 35, "py_import.py:3:0-4:5"),
|
|
219
171
|
]
|
|
@@ -232,35 +184,90 @@ class TestJacLangServer(TestCase):
|
|
|
232
184
|
workspace = Workspace(workspace_path, lsp)
|
|
233
185
|
lsp.lsp._workspace = workspace
|
|
234
186
|
circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
|
|
235
|
-
lsp.quick_check(circle_file)
|
|
236
187
|
lsp.deep_check(circle_file)
|
|
237
|
-
lsp.type_check(circle_file)
|
|
238
188
|
sem_list = lsp.get_semantic_tokens(circle_file).data
|
|
239
189
|
expected_counts = [
|
|
240
|
-
("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>",
|
|
190
|
+
("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>", 12),
|
|
241
191
|
(
|
|
242
192
|
"<JacSemTokenType.PROPERTY: 9>, <JacSemTokenModifier.DEFINITION: 2>,",
|
|
243
|
-
|
|
193
|
+
19,
|
|
244
194
|
),
|
|
245
195
|
(
|
|
246
196
|
"<JacSemTokenType.PARAMETER: 7>, <JacSemTokenModifier.DECLARATION: 1>,",
|
|
247
|
-
|
|
197
|
+
5,
|
|
248
198
|
),
|
|
249
199
|
(
|
|
250
200
|
"<JacSemTokenType.FUNCTION: 12>, <JacSemTokenModifier.DECLARATION: 1>,",
|
|
251
|
-
|
|
201
|
+
9,
|
|
252
202
|
),
|
|
253
|
-
("<JacSemTokenType.METHOD: 13>, <JacSemTokenModifier.DECLARATION: 1>",
|
|
254
|
-
("<JacSemTokenType.ENUM: 3>, <JacSemTokenModifier.DECLARATION: 1>,",
|
|
255
|
-
("<JacSemTokenType.CLASS: 2>, <JacSemTokenModifier.DECLARATION: ",
|
|
203
|
+
("<JacSemTokenType.METHOD: 13>, <JacSemTokenModifier.DECLARATION: 1>", 6),
|
|
204
|
+
("<JacSemTokenType.ENUM: 3>, <JacSemTokenModifier.DECLARATION: 1>,", 4),
|
|
205
|
+
("<JacSemTokenType.CLASS: 2>, <JacSemTokenModifier.DECLARATION: ", 12),
|
|
256
206
|
(
|
|
257
207
|
"<JacSemTokenType.NAMESPACE: 0>, <JacSemTokenModifier.DEFINITION: 2>,",
|
|
258
|
-
|
|
208
|
+
3,
|
|
259
209
|
),
|
|
260
|
-
("0, 0, 4,", 22),
|
|
261
|
-
("0, 0, 3,", 192),
|
|
262
|
-
("0, 0, 6, ", 65),
|
|
263
|
-
(" 0, 7, 3,", 3),
|
|
264
210
|
]
|
|
265
211
|
for token_type, expected_count in expected_counts:
|
|
266
212
|
self.assertEqual(str(sem_list).count(token_type), expected_count)
|
|
213
|
+
|
|
214
|
+
def test_completion(self) -> None:
|
|
215
|
+
"""Test that the completions are correct."""
|
|
216
|
+
lsp = JacLangServer()
|
|
217
|
+
workspace_path = self.fixture_abs_path("")
|
|
218
|
+
workspace = Workspace(workspace_path, lsp)
|
|
219
|
+
lsp.lsp._workspace = workspace
|
|
220
|
+
base_module_file = uris.from_fs_path(
|
|
221
|
+
self.fixture_abs_path("base_module_structure.jac")
|
|
222
|
+
)
|
|
223
|
+
lsp.deep_check(base_module_file)
|
|
224
|
+
test_cases = [
|
|
225
|
+
(lspt.Position(37, 16), ["get_color1", "color1", "point1"], 3),
|
|
226
|
+
(
|
|
227
|
+
lspt.Position(51, 12),
|
|
228
|
+
[
|
|
229
|
+
"get_color1",
|
|
230
|
+
"color1",
|
|
231
|
+
"point1",
|
|
232
|
+
"base_colorred",
|
|
233
|
+
"pointred",
|
|
234
|
+
"color2",
|
|
235
|
+
],
|
|
236
|
+
6,
|
|
237
|
+
),
|
|
238
|
+
(lspt.Position(52, 19), ["color22", "point22"], 2),
|
|
239
|
+
]
|
|
240
|
+
for position, expected_completions, expected_length in test_cases:
|
|
241
|
+
completions = lsp.get_completion(
|
|
242
|
+
base_module_file, position, completion_trigger="."
|
|
243
|
+
).items
|
|
244
|
+
for completion in expected_completions:
|
|
245
|
+
self.assertIn(completion, str(completions))
|
|
246
|
+
self.assertEqual(expected_length, len(completions))
|
|
247
|
+
|
|
248
|
+
if position == lspt.Position(47, 12):
|
|
249
|
+
self.assertEqual(
|
|
250
|
+
1, str(completions).count("kind=<CompletionItemKind.Function: 3>")
|
|
251
|
+
)
|
|
252
|
+
self.assertEqual(
|
|
253
|
+
4, str(completions).count("kind=<CompletionItemKind.Field: 5>")
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
def test_go_to_reference(self) -> None:
|
|
257
|
+
"""Test that the go to reference is correct."""
|
|
258
|
+
lsp = JacLangServer()
|
|
259
|
+
workspace_path = self.fixture_abs_path("")
|
|
260
|
+
workspace = Workspace(workspace_path, lsp)
|
|
261
|
+
lsp.lsp._workspace = workspace
|
|
262
|
+
|
|
263
|
+
circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
|
|
264
|
+
lsp.deep_check(circle_file)
|
|
265
|
+
test_cases = [
|
|
266
|
+
(47, 12, ["circle.jac:47:8-47:14", "69:8-69:14", "74:8-74:14"]),
|
|
267
|
+
(54, 66, ["54:62-54:76", "65:28-65:42"]),
|
|
268
|
+
(62, 14, ["65:49-65:62", "70:38-70:51"]),
|
|
269
|
+
]
|
|
270
|
+
for line, char, expected_refs in test_cases:
|
|
271
|
+
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
|
|
272
|
+
for expected in expected_refs:
|
|
273
|
+
self.assertIn(expected, references)
|
jaclang/langserve/utils.py
CHANGED
|
@@ -4,14 +4,18 @@ import asyncio
|
|
|
4
4
|
import builtins
|
|
5
5
|
import importlib.util
|
|
6
6
|
import os
|
|
7
|
+
import re
|
|
7
8
|
import sys
|
|
8
9
|
from functools import wraps
|
|
9
10
|
from typing import Any, Awaitable, Callable, Coroutine, Optional, ParamSpec, TypeVar
|
|
10
11
|
|
|
11
12
|
import jaclang.compiler.absyntree as ast
|
|
12
13
|
from jaclang.compiler.codeloc import CodeLocInfo
|
|
14
|
+
from jaclang.compiler.constant import SymbolType
|
|
15
|
+
from jaclang.compiler.passes.transform import Alert
|
|
13
16
|
from jaclang.compiler.symtable import Symbol, SymbolTable
|
|
14
17
|
from jaclang.utils.helpers import import_target_to_relative_path
|
|
18
|
+
from jaclang.vendor.pygls import uris
|
|
15
19
|
|
|
16
20
|
import lsprotocol.types as lspt
|
|
17
21
|
|
|
@@ -19,6 +23,29 @@ T = TypeVar("T", bound=Callable[..., Coroutine[Any, Any, Any]])
|
|
|
19
23
|
P = ParamSpec("P")
|
|
20
24
|
|
|
21
25
|
|
|
26
|
+
def gen_diagnostics(
|
|
27
|
+
from_path: str, errors: list[Alert], warnings: list[Alert]
|
|
28
|
+
) -> list[lspt.Diagnostic]:
|
|
29
|
+
"""Return diagnostics."""
|
|
30
|
+
return [
|
|
31
|
+
lspt.Diagnostic(
|
|
32
|
+
range=create_range(error.loc),
|
|
33
|
+
message=error.msg,
|
|
34
|
+
severity=lspt.DiagnosticSeverity.Error,
|
|
35
|
+
)
|
|
36
|
+
for error in errors
|
|
37
|
+
if error.loc.mod_path == uris.to_fs_path(from_path)
|
|
38
|
+
] + [
|
|
39
|
+
lspt.Diagnostic(
|
|
40
|
+
range=create_range(warning.loc),
|
|
41
|
+
message=warning.msg,
|
|
42
|
+
severity=lspt.DiagnosticSeverity.Warning,
|
|
43
|
+
)
|
|
44
|
+
for warning in warnings
|
|
45
|
+
if warning.loc.mod_path == uris.to_fs_path(from_path)
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
|
|
22
49
|
def debounce(wait: float) -> Callable[[T], Callable[..., Awaitable[None]]]:
|
|
23
50
|
"""Debounce decorator for async functions."""
|
|
24
51
|
|
|
@@ -194,6 +221,49 @@ def kind_map(sub_tab: ast.AstNode) -> lspt.SymbolKind:
|
|
|
194
221
|
)
|
|
195
222
|
|
|
196
223
|
|
|
224
|
+
def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
|
|
225
|
+
"""Map the symbol node to an lspt.CompletionItemKind."""
|
|
226
|
+
return (
|
|
227
|
+
lspt.CompletionItemKind.Function
|
|
228
|
+
if sub_tab in [SymbolType.ABILITY, SymbolType.TEST]
|
|
229
|
+
else (
|
|
230
|
+
lspt.CompletionItemKind.Class
|
|
231
|
+
if sub_tab
|
|
232
|
+
in [
|
|
233
|
+
SymbolType.OBJECT_ARCH,
|
|
234
|
+
SymbolType.NODE_ARCH,
|
|
235
|
+
SymbolType.EDGE_ARCH,
|
|
236
|
+
SymbolType.WALKER_ARCH,
|
|
237
|
+
]
|
|
238
|
+
else (
|
|
239
|
+
lspt.CompletionItemKind.Module
|
|
240
|
+
if sub_tab == SymbolType.MODULE
|
|
241
|
+
else (
|
|
242
|
+
lspt.CompletionItemKind.Enum
|
|
243
|
+
if sub_tab == SymbolType.ENUM_ARCH
|
|
244
|
+
else (
|
|
245
|
+
lspt.CompletionItemKind.Field
|
|
246
|
+
if sub_tab == SymbolType.HAS_VAR
|
|
247
|
+
else (
|
|
248
|
+
lspt.CompletionItemKind.Method
|
|
249
|
+
if sub_tab == SymbolType.METHOD
|
|
250
|
+
else (
|
|
251
|
+
lspt.CompletionItemKind.EnumMember
|
|
252
|
+
if sub_tab == SymbolType.ENUM_MEMBER
|
|
253
|
+
else (
|
|
254
|
+
lspt.CompletionItemKind.Interface
|
|
255
|
+
if sub_tab == SymbolType.IMPL
|
|
256
|
+
else lspt.CompletionItemKind.Variable
|
|
257
|
+
)
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
197
267
|
def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
|
|
198
268
|
"""Get path for a module import name."""
|
|
199
269
|
ret_target = None
|
|
@@ -292,3 +362,199 @@ def get_definition_range(
|
|
|
292
362
|
return filename, (start_line - 1, end_line - 1)
|
|
293
363
|
|
|
294
364
|
return None
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
def locate_affected_token(
|
|
368
|
+
tokens: list[int],
|
|
369
|
+
change_start_line: int,
|
|
370
|
+
change_start_char: int,
|
|
371
|
+
change_end_line: int,
|
|
372
|
+
change_end_char: int,
|
|
373
|
+
) -> Optional[int]:
|
|
374
|
+
"""Find in which token change is occurring."""
|
|
375
|
+
token_index = 0
|
|
376
|
+
current_line = 0
|
|
377
|
+
line_char_offset = 0
|
|
378
|
+
|
|
379
|
+
while token_index < len(tokens):
|
|
380
|
+
token_line_delta = tokens[token_index]
|
|
381
|
+
token_start_char = tokens[token_index + 1]
|
|
382
|
+
token_length = tokens[token_index + 2]
|
|
383
|
+
|
|
384
|
+
if token_line_delta > 0:
|
|
385
|
+
current_line += token_line_delta
|
|
386
|
+
line_char_offset = 0
|
|
387
|
+
token_abs_start_char = line_char_offset + token_start_char
|
|
388
|
+
token_abs_end_char = token_abs_start_char + token_length
|
|
389
|
+
if (
|
|
390
|
+
current_line == change_start_line == change_end_line
|
|
391
|
+
and token_abs_start_char <= change_start_char
|
|
392
|
+
and change_end_char <= token_abs_end_char
|
|
393
|
+
):
|
|
394
|
+
return token_index
|
|
395
|
+
if (
|
|
396
|
+
current_line == change_start_line
|
|
397
|
+
and token_abs_start_char <= change_start_char < token_abs_end_char
|
|
398
|
+
):
|
|
399
|
+
return token_index
|
|
400
|
+
if (
|
|
401
|
+
current_line == change_end_line
|
|
402
|
+
and token_abs_start_char < change_end_char <= token_abs_end_char
|
|
403
|
+
):
|
|
404
|
+
return token_index
|
|
405
|
+
|
|
406
|
+
line_char_offset += token_start_char
|
|
407
|
+
token_index += 5
|
|
408
|
+
return None
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def collect_all_symbols_in_scope(
|
|
412
|
+
sym_tab: SymbolTable, up_tree: bool = True
|
|
413
|
+
) -> list[lspt.CompletionItem]:
|
|
414
|
+
"""Return all symbols in scope."""
|
|
415
|
+
symbols = []
|
|
416
|
+
visited = set()
|
|
417
|
+
current_tab: Optional[SymbolTable] = sym_tab
|
|
418
|
+
|
|
419
|
+
while current_tab is not None and current_tab not in visited:
|
|
420
|
+
visited.add(current_tab)
|
|
421
|
+
for name, symbol in current_tab.tab.items():
|
|
422
|
+
if name not in dir(builtins):
|
|
423
|
+
symbols.append(
|
|
424
|
+
lspt.CompletionItem(label=name, kind=label_map(symbol.sym_type))
|
|
425
|
+
)
|
|
426
|
+
if not up_tree:
|
|
427
|
+
return symbols
|
|
428
|
+
current_tab = current_tab.parent if current_tab.parent != current_tab else None
|
|
429
|
+
return symbols
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def parse_symbol_path(text: str, dot_position: int) -> list[str]:
|
|
433
|
+
"""Parse text and return a list of symbols."""
|
|
434
|
+
text = text[:dot_position].strip()
|
|
435
|
+
pattern = re.compile(r"\b\w+\(\)?|\b\w+\b")
|
|
436
|
+
matches = pattern.findall(text)
|
|
437
|
+
if text.endswith("."):
|
|
438
|
+
matches.append("")
|
|
439
|
+
symbol_path = []
|
|
440
|
+
i = 0
|
|
441
|
+
while i < len(matches):
|
|
442
|
+
if matches[i].endswith("("):
|
|
443
|
+
i += 1
|
|
444
|
+
continue
|
|
445
|
+
elif "(" in matches[i]:
|
|
446
|
+
symbol_path.append(matches[i])
|
|
447
|
+
elif matches[i] == "":
|
|
448
|
+
pass
|
|
449
|
+
else:
|
|
450
|
+
symbol_path.append(matches[i])
|
|
451
|
+
i += 1
|
|
452
|
+
|
|
453
|
+
return symbol_path
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def resolve_symbol_path(sym_name: str, node_tab: SymbolTable) -> str:
|
|
457
|
+
"""Resolve symbol path."""
|
|
458
|
+
visited = set()
|
|
459
|
+
current_tab: Optional[SymbolTable] = node_tab
|
|
460
|
+
|
|
461
|
+
while current_tab is not None and current_tab not in visited:
|
|
462
|
+
visited.add(current_tab)
|
|
463
|
+
for name, symbol in current_tab.tab.items():
|
|
464
|
+
if name not in dir(builtins) and name == sym_name:
|
|
465
|
+
path = symbol.defn[0]._sym_type
|
|
466
|
+
return path
|
|
467
|
+
current_tab = current_tab.parent if current_tab.parent != current_tab else None
|
|
468
|
+
return ""
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def find_symbol_table(path: str, current_tab: Optional[SymbolTable]) -> SymbolTable:
|
|
472
|
+
"""Find symbol table."""
|
|
473
|
+
path = path.lstrip(".")
|
|
474
|
+
current_table = current_tab
|
|
475
|
+
if current_table:
|
|
476
|
+
for segment in path.split("."):
|
|
477
|
+
current_table = next(
|
|
478
|
+
(
|
|
479
|
+
child_table
|
|
480
|
+
for child_table in current_table.kid
|
|
481
|
+
if child_table.name == segment
|
|
482
|
+
),
|
|
483
|
+
current_table,
|
|
484
|
+
)
|
|
485
|
+
if current_table:
|
|
486
|
+
return current_table
|
|
487
|
+
raise ValueError(f"Symbol table not found for path {path}")
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def resolve_completion_symbol_table(
|
|
491
|
+
mod_tab: SymbolTable,
|
|
492
|
+
current_symbol_path: list[str],
|
|
493
|
+
current_tab: Optional[SymbolTable],
|
|
494
|
+
) -> list[lspt.CompletionItem]:
|
|
495
|
+
"""Resolve symbol table for completion items."""
|
|
496
|
+
current_symbol_table = mod_tab
|
|
497
|
+
for obj in current_symbol_path:
|
|
498
|
+
if obj == "self":
|
|
499
|
+
try:
|
|
500
|
+
try:
|
|
501
|
+
is_abilitydef = (
|
|
502
|
+
mod_tab.owner
|
|
503
|
+
if isinstance(mod_tab.owner, ast.AbilityDef)
|
|
504
|
+
else mod_tab.owner.parent_of_type(ast.AbilityDef)
|
|
505
|
+
)
|
|
506
|
+
archi_owner = (
|
|
507
|
+
(is_abilitydef.decl_link.parent_of_type(ast.Architype))
|
|
508
|
+
if is_abilitydef.decl_link
|
|
509
|
+
else None
|
|
510
|
+
)
|
|
511
|
+
current_symbol_table = (
|
|
512
|
+
archi_owner._sym_tab
|
|
513
|
+
if archi_owner and archi_owner._sym_tab
|
|
514
|
+
else mod_tab
|
|
515
|
+
)
|
|
516
|
+
continue
|
|
517
|
+
|
|
518
|
+
except ValueError:
|
|
519
|
+
pass
|
|
520
|
+
archi_owner = mod_tab.owner.parent_of_type(ast.Architype)
|
|
521
|
+
current_symbol_table = (
|
|
522
|
+
archi_owner._sym_tab
|
|
523
|
+
if archi_owner and archi_owner._sym_tab
|
|
524
|
+
else mod_tab
|
|
525
|
+
)
|
|
526
|
+
except ValueError:
|
|
527
|
+
pass
|
|
528
|
+
else:
|
|
529
|
+
path: str = resolve_symbol_path(obj, current_symbol_table)
|
|
530
|
+
if path:
|
|
531
|
+
current_symbol_table = find_symbol_table(path, current_tab)
|
|
532
|
+
else:
|
|
533
|
+
if (
|
|
534
|
+
isinstance(current_symbol_table.owner, ast.Architype)
|
|
535
|
+
and current_symbol_table.owner.base_classes
|
|
536
|
+
):
|
|
537
|
+
for base_name in current_symbol_table.owner.base_classes.items:
|
|
538
|
+
if isinstance(base_name, ast.Name) and base_name.sym:
|
|
539
|
+
path = base_name.sym.sym_dotted_name + "." + obj
|
|
540
|
+
current_symbol_table = find_symbol_table(path, current_tab)
|
|
541
|
+
if (
|
|
542
|
+
isinstance(current_symbol_table.owner, ast.Architype)
|
|
543
|
+
and current_symbol_table.owner.base_classes
|
|
544
|
+
):
|
|
545
|
+
base = []
|
|
546
|
+
for base_name in current_symbol_table.owner.base_classes.items:
|
|
547
|
+
if isinstance(base_name, ast.Name) and base_name.sym:
|
|
548
|
+
base.append(base_name.sym.sym_dotted_name)
|
|
549
|
+
for base_ in base:
|
|
550
|
+
completion_items = collect_all_symbols_in_scope(
|
|
551
|
+
find_symbol_table(base_, current_tab),
|
|
552
|
+
up_tree=False,
|
|
553
|
+
)
|
|
554
|
+
else:
|
|
555
|
+
completion_items = []
|
|
556
|
+
|
|
557
|
+
completion_items.extend(
|
|
558
|
+
collect_all_symbols_in_scope(current_symbol_table, up_tree=False)
|
|
559
|
+
)
|
|
560
|
+
return completion_items
|
jaclang/plugin/default.py
CHANGED
|
@@ -213,8 +213,8 @@ class JacFeatureDefaults:
|
|
|
213
213
|
override_name: Optional[str],
|
|
214
214
|
mod_bundle: Optional[Module | str],
|
|
215
215
|
lng: Optional[str],
|
|
216
|
-
items: Optional[dict[str, Union[str,
|
|
217
|
-
) ->
|
|
216
|
+
items: Optional[dict[str, Union[str, Optional[str]]]],
|
|
217
|
+
) -> tuple[types.ModuleType, ...]:
|
|
218
218
|
"""Core Import Process."""
|
|
219
219
|
result = jac_importer(
|
|
220
220
|
target=target,
|
|
@@ -251,9 +251,10 @@ class JacFeatureDefaults:
|
|
|
251
251
|
maxfail: Optional[int],
|
|
252
252
|
directory: Optional[str],
|
|
253
253
|
verbose: bool,
|
|
254
|
-
) ->
|
|
254
|
+
) -> int:
|
|
255
255
|
"""Run the test suite in the specified .jac file."""
|
|
256
256
|
test_file = False
|
|
257
|
+
ret_count = 0
|
|
257
258
|
if filepath:
|
|
258
259
|
if filepath.endswith(".jac"):
|
|
259
260
|
base, mod_name = os.path.split(filepath)
|
|
@@ -262,6 +263,7 @@ class JacFeatureDefaults:
|
|
|
262
263
|
JacTestCheck.reset()
|
|
263
264
|
Jac.jac_import(target=mod_name, base_path=base)
|
|
264
265
|
JacTestCheck.run_test(xit, maxfail, verbose)
|
|
266
|
+
ret_count = JacTestCheck.failcount
|
|
265
267
|
else:
|
|
266
268
|
print("Not a .jac file.")
|
|
267
269
|
else:
|
|
@@ -293,10 +295,11 @@ class JacFeatureDefaults:
|
|
|
293
295
|
if JacTestCheck.breaker and (xit or maxfail):
|
|
294
296
|
break
|
|
295
297
|
JacTestCheck.breaker = False
|
|
298
|
+
ret_count += JacTestCheck.failcount
|
|
296
299
|
JacTestCheck.failcount = 0
|
|
297
300
|
print("No test files found.") if not test_file else None
|
|
298
301
|
|
|
299
|
-
return
|
|
302
|
+
return ret_count
|
|
300
303
|
|
|
301
304
|
@staticmethod
|
|
302
305
|
@hookimpl
|
jaclang/plugin/feature.py
CHANGED
|
@@ -104,8 +104,8 @@ class JacFeature:
|
|
|
104
104
|
override_name: Optional[str] = None,
|
|
105
105
|
mod_bundle: Optional[Module | str] = None,
|
|
106
106
|
lng: Optional[str] = "jac",
|
|
107
|
-
items: Optional[dict[str, Union[str,
|
|
108
|
-
) ->
|
|
107
|
+
items: Optional[dict[str, Union[str, Optional[str]]]] = None,
|
|
108
|
+
) -> tuple[types.ModuleType, ...]:
|
|
109
109
|
"""Core Import Process."""
|
|
110
110
|
return pm.hook.jac_import(
|
|
111
111
|
target=target,
|
|
@@ -132,7 +132,7 @@ class JacFeature:
|
|
|
132
132
|
maxfail: Optional[int] = None,
|
|
133
133
|
directory: Optional[str] = None,
|
|
134
134
|
verbose: bool = False,
|
|
135
|
-
) ->
|
|
135
|
+
) -> int:
|
|
136
136
|
"""Run the test suite in the specified .jac file."""
|
|
137
137
|
return pm.hook.run_test(
|
|
138
138
|
filepath=filepath,
|
jaclang/plugin/spec.py
CHANGED
|
@@ -101,8 +101,8 @@ class JacFeatureSpec:
|
|
|
101
101
|
override_name: Optional[str],
|
|
102
102
|
mod_bundle: Optional[Module | str],
|
|
103
103
|
lng: Optional[str],
|
|
104
|
-
items: Optional[dict[str, Union[str,
|
|
105
|
-
) ->
|
|
104
|
+
items: Optional[dict[str, Union[str, Optional[str]]]],
|
|
105
|
+
) -> tuple[types.ModuleType, ...]:
|
|
106
106
|
"""Core Import Process."""
|
|
107
107
|
raise NotImplementedError
|
|
108
108
|
|
|
@@ -121,7 +121,7 @@ class JacFeatureSpec:
|
|
|
121
121
|
maxfail: Optional[int],
|
|
122
122
|
directory: Optional[str],
|
|
123
123
|
verbose: bool,
|
|
124
|
-
) ->
|
|
124
|
+
) -> int:
|
|
125
125
|
"""Run the test suite in the specified .jac file."""
|
|
126
126
|
raise NotImplementedError
|
|
127
127
|
|
jaclang/settings.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import:jac deeper
|
|
1
|
+
import:jac from .deeper, snd_lev as snd_lev;
|
|
2
|
+
import:jac from ..deep, deeper;
|
|
3
|
+
import:jac from ., deeper as mydeeper;
|
|
2
4
|
|
|
3
|
-
can olprint ->str {
|
|
5
|
+
can olprint -> str {
|
|
6
|
+
# deeper.snd_lev.slprint(); FIXME:
|
|
4
7
|
return "one level deeper" + snd_lev.slprint();
|
|
5
|
-
}
|
|
6
|
-
|
|
8
|
+
}
|