jaclang 0.7.16__py3-none-any.whl → 0.7.17__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 +140 -75
- jaclang/compiler/absyntree.py +9 -4
- jaclang/compiler/constant.py +8 -8
- jaclang/compiler/parser.py +10 -2
- jaclang/compiler/passes/main/__init__.py +1 -1
- jaclang/compiler/passes/main/access_modifier_pass.py +96 -147
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +152 -50
- jaclang/compiler/passes/main/import_pass.py +88 -59
- jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +21 -6
- jaclang/compiler/passes/main/pyast_load_pass.py +1 -0
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
- jaclang/compiler/passes/main/schedules.py +9 -2
- jaclang/compiler/passes/main/sym_tab_build_pass.py +9 -5
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.empty.impl.jac +0 -0
- jaclang/compiler/passes/main/tests/fixtures/autoimpl.jac +1 -1
- jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac +29 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/color.py +3 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/constants.py +5 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/display.py +2 -0
- jaclang/compiler/passes/main/tests/test_import_pass.py +72 -13
- jaclang/compiler/passes/main/type_check_pass.py +15 -5
- jaclang/compiler/passes/tool/jac_formatter_pass.py +11 -3
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
- jaclang/compiler/symtable.py +16 -11
- jaclang/compiler/tests/test_importer.py +17 -9
- jaclang/langserve/engine.py +39 -0
- jaclang/langserve/server.py +16 -1
- jaclang/langserve/tests/fixtures/rename.jac +30 -0
- jaclang/langserve/tests/test_server.py +216 -2
- jaclang/langserve/utils.py +21 -2
- jaclang/plugin/default.py +78 -70
- jaclang/plugin/feature.py +7 -17
- jaclang/plugin/spec.py +6 -19
- jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
- jaclang/plugin/tests/test_jaseci.py +414 -42
- jaclang/runtimelib/architype.py +481 -333
- jaclang/runtimelib/constructs.py +5 -8
- jaclang/runtimelib/context.py +89 -69
- jaclang/runtimelib/importer.py +15 -15
- jaclang/runtimelib/machine.py +66 -2
- jaclang/runtimelib/memory.py +134 -75
- jaclang/runtimelib/utils.py +17 -10
- jaclang/settings.py +2 -4
- jaclang/tests/fixtures/access_checker.jac +12 -17
- jaclang/tests/fixtures/access_modifier.jac +88 -33
- jaclang/tests/fixtures/baddy.jac +3 -0
- jaclang/tests/fixtures/bar.jac +34 -0
- jaclang/tests/fixtures/edge_node_walk.jac +1 -1
- jaclang/tests/fixtures/edge_ops.jac +1 -1
- jaclang/tests/fixtures/edges_walk.jac +1 -1
- jaclang/tests/fixtures/foo.jac +43 -0
- jaclang/tests/fixtures/game1.jac +1 -1
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/import.jac +9 -0
- jaclang/tests/fixtures/index_slice.jac +30 -0
- jaclang/tests/fixtures/pyfunc_1.py +1 -1
- jaclang/tests/fixtures/pyfunc_2.py +2 -2
- jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
- jaclang/tests/fixtures/pygame_mock/color.py +3 -0
- jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
- jaclang/tests/fixtures/pygame_mock/display.py +2 -0
- jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
- jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
- jaclang/tests/test_cli.py +49 -6
- jaclang/tests/test_language.py +113 -78
- jaclang/tests/test_reference.py +2 -9
- jaclang/utils/treeprinter.py +30 -3
- {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/METADATA +1 -1
- {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/RECORD +77 -56
- /jaclang/tests/fixtures/{err.test.jac → baddy.test.jac} +0 -0
- {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/WHEEL +0 -0
- {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/entry_points.txt +0 -0
jaclang/compiler/symtable.py
CHANGED
|
@@ -137,7 +137,7 @@ class SymbolTable:
|
|
|
137
137
|
return k
|
|
138
138
|
return None
|
|
139
139
|
|
|
140
|
-
def
|
|
140
|
+
def push_kid_scope(self, name: str, key_node: ast.AstNode) -> SymbolTable:
|
|
141
141
|
"""Push a new scope onto the symbol table."""
|
|
142
142
|
self.kid.append(SymbolTable(name, key_node, self))
|
|
143
143
|
return self.kid[-1]
|
|
@@ -205,16 +205,21 @@ class SymbolTable:
|
|
|
205
205
|
for i in node_list:
|
|
206
206
|
if cur_sym_tab is None:
|
|
207
207
|
break
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
208
|
+
lookup = self.use_lookup(i, sym_table=cur_sym_tab)
|
|
209
|
+
if lookup:
|
|
210
|
+
cur_sym_tab = lookup.decl.sym_tab
|
|
211
|
+
|
|
212
|
+
# check if the symbol table name is not the same as symbol name
|
|
213
|
+
# then try to find a child scope with the same name
|
|
214
|
+
# This is used to get the scope in case of
|
|
215
|
+
# import:py math;
|
|
216
|
+
# b = math.floor(1.7);
|
|
217
|
+
if cur_sym_tab.name != i.sym_name:
|
|
218
|
+
t = cur_sym_tab.find_scope(i.sym_name)
|
|
219
|
+
if t:
|
|
220
|
+
cur_sym_tab = t
|
|
221
|
+
else:
|
|
222
|
+
cur_sym_tab = None
|
|
218
223
|
|
|
219
224
|
def update_py_ctx_for_def(self, node: ast.AstSymbolNode) -> None:
|
|
220
225
|
"""Update python context for definition."""
|
|
@@ -5,29 +5,37 @@ import sys
|
|
|
5
5
|
|
|
6
6
|
from jaclang import jac_import
|
|
7
7
|
from jaclang.cli import cli
|
|
8
|
-
from jaclang.
|
|
8
|
+
from jaclang.runtimelib.machine import JacMachine, JacProgram
|
|
9
9
|
from jaclang.utils.test import TestCase
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class TestLoader(TestCase):
|
|
13
13
|
"""Test Jac self.prse."""
|
|
14
14
|
|
|
15
|
-
def setUp(self) -> None:
|
|
16
|
-
"""Set up test."""
|
|
17
|
-
return super().setUp()
|
|
18
|
-
|
|
19
15
|
def test_import_basic_python(self) -> None:
|
|
20
16
|
"""Test basic self loading."""
|
|
21
|
-
|
|
17
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
18
|
+
JacProgram(mod_bundle=None, bytecode=None)
|
|
19
|
+
)
|
|
22
20
|
(h,) = jac_import("fixtures.hello_world", base_path=__file__)
|
|
23
21
|
self.assertEqual(h.hello(), "Hello World!") # type: ignore
|
|
22
|
+
JacMachine.detach()
|
|
24
23
|
|
|
25
24
|
def test_modules_correct(self) -> None:
|
|
26
25
|
"""Test basic self loading."""
|
|
27
|
-
|
|
26
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
27
|
+
JacProgram(mod_bundle=None, bytecode=None)
|
|
28
|
+
)
|
|
28
29
|
jac_import("fixtures.hello_world", base_path=__file__)
|
|
29
|
-
self.assertIn(
|
|
30
|
-
|
|
30
|
+
self.assertIn(
|
|
31
|
+
"module 'fixtures.hello_world'",
|
|
32
|
+
str(JacMachine.get().loaded_modules),
|
|
33
|
+
)
|
|
34
|
+
self.assertIn(
|
|
35
|
+
"/tests/fixtures/hello_world.jac",
|
|
36
|
+
str(JacMachine.get().loaded_modules),
|
|
37
|
+
)
|
|
38
|
+
JacMachine.detach()
|
|
31
39
|
|
|
32
40
|
def test_jac_py_import(self) -> None:
|
|
33
41
|
"""Basic test for pass."""
|
jaclang/langserve/engine.py
CHANGED
|
@@ -16,6 +16,7 @@ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
|
|
|
16
16
|
from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
|
|
17
17
|
from jaclang.langserve.sem_manager import SemTokManager
|
|
18
18
|
from jaclang.langserve.utils import (
|
|
19
|
+
add_unique_text_edit,
|
|
19
20
|
collect_all_symbols_in_scope,
|
|
20
21
|
create_range,
|
|
21
22
|
find_deepest_symbol_node_at_pos,
|
|
@@ -127,6 +128,15 @@ class JacLangServer(LanguageServer):
|
|
|
127
128
|
build.warnings_had,
|
|
128
129
|
),
|
|
129
130
|
)
|
|
131
|
+
if annex_view:
|
|
132
|
+
self.publish_diagnostics(
|
|
133
|
+
file_path,
|
|
134
|
+
gen_diagnostics(
|
|
135
|
+
file_path,
|
|
136
|
+
build.errors_had,
|
|
137
|
+
build.warnings_had,
|
|
138
|
+
),
|
|
139
|
+
)
|
|
130
140
|
self.log_py(f"PROFILE: Deep check took {time.time() - start_time} seconds.")
|
|
131
141
|
return len(build.errors_had) == 0
|
|
132
142
|
except Exception as e:
|
|
@@ -404,6 +414,35 @@ class JacLangServer(LanguageServer):
|
|
|
404
414
|
return list_of_references
|
|
405
415
|
return []
|
|
406
416
|
|
|
417
|
+
def rename_symbol(
|
|
418
|
+
self, file_path: str, position: lspt.Position, new_name: str
|
|
419
|
+
) -> Optional[lspt.WorkspaceEdit]:
|
|
420
|
+
"""Rename a symbol in a file."""
|
|
421
|
+
if file_path not in self.modules:
|
|
422
|
+
return None
|
|
423
|
+
index1 = find_index(
|
|
424
|
+
self.modules[file_path].sem_manager.sem_tokens,
|
|
425
|
+
position.line,
|
|
426
|
+
position.character,
|
|
427
|
+
)
|
|
428
|
+
if index1 is None:
|
|
429
|
+
return None
|
|
430
|
+
node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
|
|
431
|
+
if node_selected and node_selected.sym:
|
|
432
|
+
changes: dict[str, list[lspt.TextEdit]] = {}
|
|
433
|
+
for node in [
|
|
434
|
+
*node_selected.sym.uses,
|
|
435
|
+
node_selected.sym.defn[0],
|
|
436
|
+
]:
|
|
437
|
+
key = uris.from_fs_path(node.loc.mod_path)
|
|
438
|
+
new_edit = lspt.TextEdit(
|
|
439
|
+
range=create_range(node.loc),
|
|
440
|
+
new_text=new_name,
|
|
441
|
+
)
|
|
442
|
+
add_unique_text_edit(changes, key, new_edit)
|
|
443
|
+
return lspt.WorkspaceEdit(changes=changes)
|
|
444
|
+
return None
|
|
445
|
+
|
|
407
446
|
def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
|
|
408
447
|
"""Return semantic tokens for a file."""
|
|
409
448
|
if file_path not in self.modules:
|
jaclang/langserve/server.py
CHANGED
|
@@ -17,8 +17,14 @@ server = JacLangServer()
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@server.feature(lspt.TEXT_DOCUMENT_DID_OPEN)
|
|
20
|
-
@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
|
|
21
20
|
async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
|
|
21
|
+
"""Check syntax on change."""
|
|
22
|
+
ls.deep_check(params.text_document.uri)
|
|
23
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
|
|
27
|
+
async def did_save(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
|
|
22
28
|
"""Check syntax on change."""
|
|
23
29
|
await ls.launch_deep_check(params.text_document.uri)
|
|
24
30
|
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
|
|
@@ -132,6 +138,15 @@ def references(ls: JacLangServer, params: lspt.ReferenceParams) -> list[lspt.Loc
|
|
|
132
138
|
return ls.get_references(params.text_document.uri, params.position)
|
|
133
139
|
|
|
134
140
|
|
|
141
|
+
@server.feature(lspt.TEXT_DOCUMENT_RENAME)
|
|
142
|
+
def rename(
|
|
143
|
+
ls: JacLangServer, params: lspt.RenameParams
|
|
144
|
+
) -> Optional[lspt.WorkspaceEdit]:
|
|
145
|
+
"""Rename symbol."""
|
|
146
|
+
ls.log_warning("Auto Rename is Experimental, Please use with caution.")
|
|
147
|
+
return ls.rename_symbol(params.text_document.uri, params.position, params.new_name)
|
|
148
|
+
|
|
149
|
+
|
|
135
150
|
@server.feature(
|
|
136
151
|
lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
137
152
|
lspt.SemanticTokensLegend(
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
can foo;
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
:can:foo{
|
|
6
|
+
print("foo");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
obj out{
|
|
11
|
+
has cnt :int;
|
|
12
|
+
can bar;
|
|
13
|
+
can baz;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
:obj:out:can:bar{
|
|
18
|
+
print("bar");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:obj:out:can:baz{
|
|
22
|
+
print("baz");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
with entry{
|
|
26
|
+
foo();
|
|
27
|
+
new = out();
|
|
28
|
+
new.cnt;
|
|
29
|
+
out(1).bar();
|
|
30
|
+
}
|
|
@@ -201,6 +201,62 @@ class TestJacLangServer(TestCase):
|
|
|
201
201
|
str(lsp.get_definition(import_file, lspt.Position(line, char))),
|
|
202
202
|
)
|
|
203
203
|
|
|
204
|
+
def test_go_to_definition_foolme(self) -> None:
|
|
205
|
+
"""Test that the go to definition is correct."""
|
|
206
|
+
lsp = JacLangServer()
|
|
207
|
+
workspace_path = self.fixture_abs_path("")
|
|
208
|
+
workspace = Workspace(workspace_path, lsp)
|
|
209
|
+
lsp.lsp._workspace = workspace
|
|
210
|
+
import_file = uris.from_fs_path(
|
|
211
|
+
self.fixture_abs_path(
|
|
212
|
+
"../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
|
|
213
|
+
)
|
|
214
|
+
)
|
|
215
|
+
lsp.deep_check(import_file)
|
|
216
|
+
positions = [
|
|
217
|
+
(6, 39, "/pygame_mock/__init__.py:2:0-2:0"),
|
|
218
|
+
(6, 45, "/pygame_mock/constants.py:3:0-4:1"),
|
|
219
|
+
(7, 31, "/pygame_mock/__init__.py:2:0-2:0"),
|
|
220
|
+
(7, 35, "/pygame_mock/constants.py:3:0-4:1"),
|
|
221
|
+
(20, 51, "/py_imp_test.jac:6:4-6:11"),
|
|
222
|
+
(20, 64, "/pygame_mock/constants.py:4:3-4:15"),
|
|
223
|
+
(21, 48, "/py_imp_test.jac:10:4-10:6"),
|
|
224
|
+
(21, 58, "/py_imp_test.jac:11:8-11:15"),
|
|
225
|
+
(21, 68, "/pygame_mock/constants.py:4:3-4:15"),
|
|
226
|
+
(23, 58, "/pygame_mock/constants.py:4:3-4:15"),
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
for line, char, expected in positions:
|
|
230
|
+
with self.subTest(line=line, char=char):
|
|
231
|
+
self.assertIn(
|
|
232
|
+
expected,
|
|
233
|
+
str(lsp.get_definition(import_file, lspt.Position(line, char))),
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
def test_go_to_definition_index_expr(self) -> None:
|
|
237
|
+
"""Test that the go to definition is correct."""
|
|
238
|
+
lsp = JacLangServer()
|
|
239
|
+
workspace_path = self.fixture_abs_path("")
|
|
240
|
+
workspace = Workspace(workspace_path, lsp)
|
|
241
|
+
lsp.lsp._workspace = workspace
|
|
242
|
+
import_file = uris.from_fs_path(
|
|
243
|
+
self.fixture_abs_path("../../../../jaclang/tests/fixtures/index_slice.jac")
|
|
244
|
+
)
|
|
245
|
+
lsp.deep_check(import_file)
|
|
246
|
+
positions = [
|
|
247
|
+
(23, 20, "index_slice.jac:2:8-2:13"),
|
|
248
|
+
(24, 24, "index_slice.jac:2:8-2:13"),
|
|
249
|
+
(27, 33, "index_slice.jac:2:8-2:13"),
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
for line, char, expected in positions:
|
|
253
|
+
with self.subTest(line=line, char=char):
|
|
254
|
+
print(str(lsp.get_definition(import_file, lspt.Position(line, char))))
|
|
255
|
+
self.assertIn(
|
|
256
|
+
expected,
|
|
257
|
+
str(lsp.get_definition(import_file, lspt.Position(line, char))),
|
|
258
|
+
)
|
|
259
|
+
|
|
204
260
|
def test_sem_tokens(self) -> None:
|
|
205
261
|
"""Test that the Semantic Tokens are generated correctly."""
|
|
206
262
|
lsp = JacLangServer()
|
|
@@ -214,7 +270,7 @@ class TestJacLangServer(TestCase):
|
|
|
214
270
|
("<JacSemTokenType.VARIABLE: 8>, <JacSemTokenModifier.READONLY: 4>", 12),
|
|
215
271
|
(
|
|
216
272
|
"<JacSemTokenType.PROPERTY: 9>, <JacSemTokenModifier.DEFINITION: 2>,",
|
|
217
|
-
|
|
273
|
+
21,
|
|
218
274
|
),
|
|
219
275
|
(
|
|
220
276
|
"<JacSemTokenType.PARAMETER: 7>, <JacSemTokenModifier.DECLARATION: 1>,",
|
|
@@ -232,7 +288,6 @@ class TestJacLangServer(TestCase):
|
|
|
232
288
|
3,
|
|
233
289
|
),
|
|
234
290
|
]
|
|
235
|
-
print(str(sem_list))
|
|
236
291
|
for token_type, expected_count in expected_counts:
|
|
237
292
|
self.assertEqual(str(sem_list).count(token_type), expected_count)
|
|
238
293
|
|
|
@@ -351,3 +406,162 @@ class TestJacLangServer(TestCase):
|
|
|
351
406
|
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
|
|
352
407
|
for expected in expected_refs:
|
|
353
408
|
self.assertIn(expected, references)
|
|
409
|
+
|
|
410
|
+
def test_py_type__definition(self) -> None:
|
|
411
|
+
"""Test that the go to definition is correct for pythoon imports."""
|
|
412
|
+
lsp = JacLangServer()
|
|
413
|
+
workspace_path = self.fixture_abs_path("")
|
|
414
|
+
workspace = Workspace(workspace_path, lsp)
|
|
415
|
+
lsp.lsp._workspace = workspace
|
|
416
|
+
import_file = uris.from_fs_path(
|
|
417
|
+
self.fixture_abs_path(
|
|
418
|
+
"../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
|
|
419
|
+
)
|
|
420
|
+
)
|
|
421
|
+
lsp.deep_check(import_file)
|
|
422
|
+
positions = [
|
|
423
|
+
(19, 29, "pygame_mock/color.py:0:0-2:4"),
|
|
424
|
+
(3, 17, "/pygame_mock/__init__.py:0:0-0:0"),
|
|
425
|
+
(20, 45, "pygame_mock/color.py:0:0-2:4"),
|
|
426
|
+
(19, 77, "mock/constants.py:4:3-4:15"),
|
|
427
|
+
(26, 28, "mock/display.py:0:0-1:7"),
|
|
428
|
+
(24, 22, "/argparse.pyi:124:0-249:13"),
|
|
429
|
+
(19, 74, "pygame_mock/constants.py:4:3-4:15"),
|
|
430
|
+
(27, 17, "/stdlib/os/__init__.pyi:50:0-50:3"),
|
|
431
|
+
]
|
|
432
|
+
|
|
433
|
+
for line, char, expected in positions:
|
|
434
|
+
with self.subTest(line=line, char=char):
|
|
435
|
+
self.assertIn(
|
|
436
|
+
expected,
|
|
437
|
+
str(lsp.get_definition(import_file, lspt.Position(line, char))),
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
def test_py_type__references(self) -> None:
|
|
441
|
+
"""Test that the go to definition is correct for pythoon imports."""
|
|
442
|
+
lsp = JacLangServer()
|
|
443
|
+
workspace_path = self.fixture_abs_path("")
|
|
444
|
+
workspace = Workspace(workspace_path, lsp)
|
|
445
|
+
lsp.lsp._workspace = workspace
|
|
446
|
+
|
|
447
|
+
circle_file = uris.from_fs_path(
|
|
448
|
+
self.fixture_abs_path(
|
|
449
|
+
"../../../../jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac"
|
|
450
|
+
)
|
|
451
|
+
)
|
|
452
|
+
lsp.deep_check(circle_file)
|
|
453
|
+
test_cases = [
|
|
454
|
+
(
|
|
455
|
+
2,
|
|
456
|
+
21,
|
|
457
|
+
[
|
|
458
|
+
":6:21-6:32",
|
|
459
|
+
":7:11-7:22",
|
|
460
|
+
":11:25-11:36",
|
|
461
|
+
":12:15-12:26",
|
|
462
|
+
":18:33-18:44",
|
|
463
|
+
"19:46-19:57",
|
|
464
|
+
":19:8-19:19",
|
|
465
|
+
":19:46-19:57",
|
|
466
|
+
":20:8-20:19",
|
|
467
|
+
"21:8-21:19,",
|
|
468
|
+
"23:8-23:19",
|
|
469
|
+
":26:4-26:15",
|
|
470
|
+
],
|
|
471
|
+
),
|
|
472
|
+
(
|
|
473
|
+
19,
|
|
474
|
+
63,
|
|
475
|
+
[
|
|
476
|
+
"6:33-6:42",
|
|
477
|
+
"7:23-7:32",
|
|
478
|
+
"18:45-18:54",
|
|
479
|
+
"19:58-19:67",
|
|
480
|
+
"11:37-11:46",
|
|
481
|
+
"12:27-12:36",
|
|
482
|
+
],
|
|
483
|
+
),
|
|
484
|
+
(
|
|
485
|
+
24,
|
|
486
|
+
53,
|
|
487
|
+
[
|
|
488
|
+
"24:42-24:56",
|
|
489
|
+
"24:16-24:30",
|
|
490
|
+
"argparse.pyi:334:21-334:35",
|
|
491
|
+
"argparse.pyi:163:29-163:43",
|
|
492
|
+
"argparse.pyi:32:52-32:66",
|
|
493
|
+
],
|
|
494
|
+
),
|
|
495
|
+
]
|
|
496
|
+
for line, char, expected_refs in test_cases:
|
|
497
|
+
references = str(lsp.get_references(circle_file, lspt.Position(line, char)))
|
|
498
|
+
for expected in expected_refs:
|
|
499
|
+
self.assertIn(expected, references)
|
|
500
|
+
|
|
501
|
+
def test_rename_symbol(self) -> None:
|
|
502
|
+
"""Test that the rename is correct."""
|
|
503
|
+
lsp = JacLangServer()
|
|
504
|
+
workspace_path = self.fixture_abs_path("")
|
|
505
|
+
workspace = Workspace(workspace_path, lsp)
|
|
506
|
+
lsp.lsp._workspace = workspace
|
|
507
|
+
|
|
508
|
+
circle_file = uris.from_fs_path(self.fixture_abs_path("circle.jac"))
|
|
509
|
+
lsp.deep_check(circle_file)
|
|
510
|
+
test_cases = [
|
|
511
|
+
(
|
|
512
|
+
20,
|
|
513
|
+
14,
|
|
514
|
+
"ShapeKind",
|
|
515
|
+
"27:20-27:29,",
|
|
516
|
+
"36:19-36:28",
|
|
517
|
+
"75:26-75:35",
|
|
518
|
+
"20:5-20:14",
|
|
519
|
+
),
|
|
520
|
+
(12, 34, "circleRadius", "12:21-12:27", "12:30-12:36", "11:19-11:25"),
|
|
521
|
+
(62, 14, "target_area", "65:43-65:56", "70:32-70:45", "62:5-62:18"),
|
|
522
|
+
(57, 33, "type_of_shape", "75:12-75:22", "27:8-27:18,", "57:23-57:33"),
|
|
523
|
+
]
|
|
524
|
+
for tup in test_cases:
|
|
525
|
+
line, char, new_name, *expected_refs = tup
|
|
526
|
+
references = str(
|
|
527
|
+
lsp.rename_symbol(circle_file, lspt.Position(line, char), new_name)
|
|
528
|
+
)
|
|
529
|
+
for expected in expected_refs:
|
|
530
|
+
self.assertIn(expected, references)
|
|
531
|
+
|
|
532
|
+
def test_rename_uses(self) -> None:
|
|
533
|
+
"""Test that the rename is correct."""
|
|
534
|
+
lsp = JacLangServer()
|
|
535
|
+
workspace_path = self.fixture_abs_path("")
|
|
536
|
+
workspace = Workspace(workspace_path, lsp)
|
|
537
|
+
lsp.lsp._workspace = workspace
|
|
538
|
+
|
|
539
|
+
circle_file = uris.from_fs_path(self.fixture_abs_path("rename.jac"))
|
|
540
|
+
lsp.deep_check(circle_file)
|
|
541
|
+
# fmt: off
|
|
542
|
+
test_cases = [
|
|
543
|
+
(0, 7, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
|
|
544
|
+
(4, 6, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
|
|
545
|
+
(25, 7, "func", "25:4-25:7", "0:4-0:7", "4:5-4:8",),
|
|
546
|
+
(10, 10, "canBar", "27:8-27:11", "10:8-10:11"),
|
|
547
|
+
(27, 9, "canBar", "27:8-27:11", "10:8-10:11"),
|
|
548
|
+
(9, 6, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
|
|
549
|
+
(26, 11, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
|
|
550
|
+
(16, 7, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
|
|
551
|
+
(28, 6, "canBar", "26:10-26:13", "28:4-28:7", "16:5-16:8", "9:4-9:7"),
|
|
552
|
+
(11, 10, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
|
|
553
|
+
(16, 14, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
|
|
554
|
+
(28, 13, "canBar", "11:8-11:11", "16:13-16:16", "28:11-28:14"),
|
|
555
|
+
(12, 10, "canBaz", "12:8-12:11", "20:13-20:16"),
|
|
556
|
+
(20, 14, "canBaz", "12:8-12:11", "20:13-20:16"),
|
|
557
|
+
(26, 6, "count", "27:4-27:7", "26:4-26:7"),
|
|
558
|
+
(27, 5, "count", "27:4-27:7", "26:4-26:7"),
|
|
559
|
+
]
|
|
560
|
+
# fmt: on
|
|
561
|
+
for tup in test_cases:
|
|
562
|
+
line, char, new_name, *expected_refs = tup
|
|
563
|
+
references = str(
|
|
564
|
+
lsp.rename_symbol(circle_file, lspt.Position(line, char), new_name)
|
|
565
|
+
)
|
|
566
|
+
for expected in expected_refs:
|
|
567
|
+
self.assertIn(expected, references)
|
jaclang/langserve/utils.py
CHANGED
|
@@ -273,7 +273,9 @@ def label_map(sub_tab: SymbolType) -> lspt.CompletionItemKind:
|
|
|
273
273
|
)
|
|
274
274
|
|
|
275
275
|
|
|
276
|
-
def get_mod_path(
|
|
276
|
+
def get_mod_path(
|
|
277
|
+
mod_path: ast.ModulePath, name_node: ast.Name
|
|
278
|
+
) -> str | None: # TODO: This should go away
|
|
277
279
|
"""Get path for a module import name."""
|
|
278
280
|
ret_target = None
|
|
279
281
|
if mod_path.parent and (
|
|
@@ -294,7 +296,7 @@ def get_mod_path(mod_path: ast.ModulePath, name_node: ast.Name) -> str | None:
|
|
|
294
296
|
else ""
|
|
295
297
|
)
|
|
296
298
|
else:
|
|
297
|
-
temporary_path_str = mod_path.
|
|
299
|
+
temporary_path_str = mod_path.dot_path_str
|
|
298
300
|
sys.path.append(os.path.dirname(mod_path.loc.mod_path))
|
|
299
301
|
spec = importlib.util.find_spec(temporary_path_str)
|
|
300
302
|
sys.path.remove(os.path.dirname(mod_path.loc.mod_path))
|
|
@@ -625,3 +627,20 @@ def get_line_of_code(line_number: int, lines: list[str]) -> Optional[tuple[str,
|
|
|
625
627
|
else first_non_space
|
|
626
628
|
)
|
|
627
629
|
return None
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
def add_unique_text_edit(
|
|
633
|
+
changes: dict[str, list[lspt.TextEdit]], key: str, new_edit: lspt.TextEdit
|
|
634
|
+
) -> None:
|
|
635
|
+
"""Add a new text edit to the changes dictionary if it is unique."""
|
|
636
|
+
if key not in changes:
|
|
637
|
+
changes[key] = [new_edit]
|
|
638
|
+
else:
|
|
639
|
+
for existing_edit in changes[key]:
|
|
640
|
+
if (
|
|
641
|
+
existing_edit.range.start == new_edit.range.start
|
|
642
|
+
and existing_edit.range.end == new_edit.range.end
|
|
643
|
+
and existing_edit.new_text == new_edit.new_text
|
|
644
|
+
):
|
|
645
|
+
return
|
|
646
|
+
changes[key].append(new_edit)
|