jaclang 0.7.14__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 +147 -77
- jaclang/cli/cmdreg.py +9 -12
- jaclang/compiler/__init__.py +19 -53
- jaclang/compiler/absyntree.py +94 -16
- jaclang/compiler/constant.py +8 -8
- jaclang/compiler/jac.lark +4 -3
- jaclang/compiler/parser.py +41 -25
- jaclang/compiler/passes/ir_pass.py +4 -13
- 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 +155 -54
- jaclang/compiler/passes/main/import_pass.py +99 -75
- jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +328 -565
- jaclang/compiler/passes/main/pyast_load_pass.py +33 -6
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
- jaclang/compiler/passes/main/registry_pass.py +37 -3
- jaclang/compiler/passes/main/schedules.py +9 -2
- jaclang/compiler/passes/main/sym_tab_build_pass.py +10 -6
- jaclang/compiler/passes/main/tests/__init__.py +1 -1
- 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 +22 -5
- jaclang/compiler/passes/tool/jac_formatter_pass.py +135 -89
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
- jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -42
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
- jaclang/compiler/passes/transform.py +4 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
- jaclang/compiler/semtable.py +31 -7
- jaclang/compiler/symtable.py +16 -11
- jaclang/compiler/tests/test_importer.py +25 -10
- jaclang/langserve/engine.py +104 -118
- jaclang/langserve/sem_manager.py +379 -0
- jaclang/langserve/server.py +24 -11
- jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
- 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/import_include_statements.jac +1 -1
- jaclang/langserve/tests/fixtures/rename.jac +30 -0
- jaclang/langserve/tests/test_sem_tokens.py +277 -0
- jaclang/langserve/tests/test_server.py +287 -17
- jaclang/langserve/utils.py +184 -98
- jaclang/plugin/builtin.py +1 -1
- jaclang/plugin/default.py +288 -92
- jaclang/plugin/feature.py +65 -27
- jaclang/plugin/spec.py +62 -23
- jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
- jaclang/plugin/tests/test_jaseci.py +414 -42
- jaclang/runtimelib/architype.py +650 -0
- jaclang/{core → runtimelib}/constructs.py +5 -8
- jaclang/{core → runtimelib}/context.py +86 -59
- jaclang/runtimelib/importer.py +361 -0
- jaclang/runtimelib/machine.py +158 -0
- jaclang/runtimelib/memory.py +158 -0
- jaclang/{core → runtimelib}/utils.py +30 -15
- jaclang/settings.py +5 -4
- jaclang/tests/fixtures/abc.jac +3 -3
- 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/baddy.test.jac +3 -0
- jaclang/tests/fixtures/bar.jac +34 -0
- jaclang/tests/fixtures/byllmissue.jac +1 -5
- jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
- jaclang/tests/fixtures/cls_method.jac +41 -0
- jaclang/tests/fixtures/dblhello.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +3 -3
- jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
- jaclang/tests/fixtures/deep_import_mods.jac +13 -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/err.impl.jac +3 -0
- jaclang/tests/fixtures/err.jac +4 -2
- jaclang/tests/fixtures/err_runtime.jac +15 -0
- jaclang/tests/fixtures/foo.jac +43 -0
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/hello.jac +4 -0
- jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
- jaclang/tests/fixtures/impl_grab.jac +4 -1
- jaclang/tests/fixtures/import.jac +9 -0
- jaclang/tests/fixtures/index_slice.jac +30 -0
- jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
- jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
- jaclang/tests/fixtures/needs_import.jac +2 -2
- jaclang/tests/fixtures/pyfunc_1.py +1 -1
- jaclang/tests/fixtures/pyfunc_2.py +5 -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/fixtures/registry.jac +9 -0
- jaclang/tests/fixtures/run_test.jac +4 -4
- jaclang/tests/fixtures/semstr.jac +1 -4
- jaclang/tests/fixtures/simple_archs.jac +1 -1
- jaclang/tests/test_cli.py +109 -3
- jaclang/tests/test_language.py +170 -68
- jaclang/tests/test_reference.py +2 -3
- jaclang/utils/helpers.py +45 -21
- jaclang/utils/test.py +9 -0
- jaclang/utils/treeprinter.py +30 -7
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/METADATA +3 -2
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/RECORD +126 -90
- jaclang/core/architype.py +0 -502
- jaclang/core/importer.py +0 -344
- jaclang/core/memory.py +0 -99
- jaclang/tests/fixtures/aott_raise.jac +0 -25
- jaclang/tests/fixtures/package_import.jac +0 -6
- /jaclang/{core → runtimelib}/__init__.py +0 -0
- /jaclang/{core → runtimelib}/test.py +0 -0
- {jaclang-0.7.14.dist-info → jaclang-0.7.17.dist-info}/WHEEL +0 -0
- {jaclang-0.7.14.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,26 +5,37 @@ import sys
|
|
|
5
5
|
|
|
6
6
|
from jaclang import jac_import
|
|
7
7
|
from jaclang.cli import cli
|
|
8
|
+
from jaclang.runtimelib.machine import JacMachine, JacProgram
|
|
8
9
|
from jaclang.utils.test import TestCase
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TestLoader(TestCase):
|
|
12
13
|
"""Test Jac self.prse."""
|
|
13
14
|
|
|
14
|
-
def setUp(self) -> None:
|
|
15
|
-
"""Set up test."""
|
|
16
|
-
return super().setUp()
|
|
17
|
-
|
|
18
15
|
def test_import_basic_python(self) -> None:
|
|
19
16
|
"""Test basic self loading."""
|
|
17
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
18
|
+
JacProgram(mod_bundle=None, bytecode=None)
|
|
19
|
+
)
|
|
20
20
|
(h,) = jac_import("fixtures.hello_world", base_path=__file__)
|
|
21
21
|
self.assertEqual(h.hello(), "Hello World!") # type: ignore
|
|
22
|
+
JacMachine.detach()
|
|
22
23
|
|
|
23
24
|
def test_modules_correct(self) -> None:
|
|
24
25
|
"""Test basic self loading."""
|
|
26
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
27
|
+
JacProgram(mod_bundle=None, bytecode=None)
|
|
28
|
+
)
|
|
25
29
|
jac_import("fixtures.hello_world", base_path=__file__)
|
|
26
|
-
self.assertIn(
|
|
27
|
-
|
|
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()
|
|
28
39
|
|
|
29
40
|
def test_jac_py_import(self) -> None:
|
|
30
41
|
"""Basic test for pass."""
|
|
@@ -39,11 +50,15 @@ class TestLoader(TestCase):
|
|
|
39
50
|
stdout_value,
|
|
40
51
|
)
|
|
41
52
|
|
|
42
|
-
def
|
|
43
|
-
"""
|
|
53
|
+
def test_jac_py_import_auto(self) -> None:
|
|
54
|
+
"""Basic test for pass."""
|
|
44
55
|
captured_output = io.StringIO()
|
|
45
56
|
sys.stdout = captured_output
|
|
46
|
-
cli.run(self.fixture_abs_path("../../../tests/fixtures/
|
|
57
|
+
cli.run(self.fixture_abs_path("../../../tests/fixtures/jp_importer_auto.jac"))
|
|
47
58
|
sys.stdout = sys.__stdout__
|
|
48
59
|
stdout_value = captured_output.getvalue()
|
|
49
|
-
self.
|
|
60
|
+
self.assertIn("Hello World!", stdout_value)
|
|
61
|
+
self.assertIn(
|
|
62
|
+
"{SomeObj(a=10): 'check'} [MyObj(apple=5, banana=7), MyObj(apple=5, banana=7)]",
|
|
63
|
+
stdout_value,
|
|
64
|
+
)
|
jaclang/langserve/engine.py
CHANGED
|
@@ -4,25 +4,27 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
|
+
import time
|
|
7
8
|
from concurrent.futures import ThreadPoolExecutor
|
|
8
9
|
from typing import Callable, Optional
|
|
9
10
|
|
|
10
|
-
|
|
11
11
|
import jaclang.compiler.absyntree as ast
|
|
12
12
|
from jaclang.compiler.compile import jac_str_to_pass
|
|
13
13
|
from jaclang.compiler.parser import JacParser
|
|
14
14
|
from jaclang.compiler.passes import Pass
|
|
15
15
|
from jaclang.compiler.passes.main.schedules import py_code_gen_typed
|
|
16
16
|
from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
|
|
17
|
+
from jaclang.langserve.sem_manager import SemTokManager
|
|
17
18
|
from jaclang.langserve.utils import (
|
|
19
|
+
add_unique_text_edit,
|
|
18
20
|
collect_all_symbols_in_scope,
|
|
19
|
-
collect_symbols,
|
|
20
21
|
create_range,
|
|
21
22
|
find_deepest_symbol_node_at_pos,
|
|
23
|
+
find_index,
|
|
22
24
|
gen_diagnostics,
|
|
23
25
|
get_item_path,
|
|
24
26
|
get_mod_path,
|
|
25
|
-
|
|
27
|
+
get_symbols_for_outline,
|
|
26
28
|
parse_symbol_path,
|
|
27
29
|
resolve_completion_symbol_table,
|
|
28
30
|
)
|
|
@@ -43,104 +45,13 @@ class ModuleInfo:
|
|
|
43
45
|
"""Initialize module info."""
|
|
44
46
|
self.ir = ir
|
|
45
47
|
self.impl_parent: Optional[ModuleInfo] = impl_parent
|
|
46
|
-
self.
|
|
48
|
+
self.sem_manager = SemTokManager(ir=ir)
|
|
47
49
|
|
|
48
50
|
@property
|
|
49
51
|
def uri(self) -> str:
|
|
50
52
|
"""Return uri."""
|
|
51
53
|
return uris.from_fs_path(self.ir.loc.mod_path)
|
|
52
54
|
|
|
53
|
-
def gen_sem_tokens(self) -> list[int]:
|
|
54
|
-
"""Return semantic tokens."""
|
|
55
|
-
tokens = []
|
|
56
|
-
prev_line, prev_col = 0, 0
|
|
57
|
-
for node in self.ir._in_mod_nodes:
|
|
58
|
-
if isinstance(node, ast.NameAtom) and node.sem_token:
|
|
59
|
-
line, col_start, col_end = (
|
|
60
|
-
node.loc.first_line - 1,
|
|
61
|
-
node.loc.col_start - 1,
|
|
62
|
-
node.loc.col_end - 1,
|
|
63
|
-
)
|
|
64
|
-
length = col_end - col_start
|
|
65
|
-
tokens += [
|
|
66
|
-
line - prev_line,
|
|
67
|
-
col_start if line != prev_line else col_start - prev_col,
|
|
68
|
-
length,
|
|
69
|
-
*node.sem_token,
|
|
70
|
-
]
|
|
71
|
-
prev_line, prev_col = line, col_start
|
|
72
|
-
return tokens
|
|
73
|
-
|
|
74
|
-
def update_sem_tokens(
|
|
75
|
-
self, content_changes: lspt.DidChangeTextDocumentParams
|
|
76
|
-
) -> list[int]:
|
|
77
|
-
"""Update semantic tokens on change."""
|
|
78
|
-
for change in [
|
|
79
|
-
x
|
|
80
|
-
for x in content_changes.content_changes
|
|
81
|
-
if isinstance(x, lspt.TextDocumentContentChangeEvent_Type1)
|
|
82
|
-
]:
|
|
83
|
-
change_start_line = change.range.start.line
|
|
84
|
-
change_start_char = change.range.start.character
|
|
85
|
-
change_end_line = change.range.end.line
|
|
86
|
-
change_end_char = change.range.end.character
|
|
87
|
-
|
|
88
|
-
line_delta = change.text.count("\n") - (change_end_line - change_start_line)
|
|
89
|
-
if line_delta == 0:
|
|
90
|
-
char_delta = len(change.text) - (change_end_char - change_start_char)
|
|
91
|
-
else:
|
|
92
|
-
last_newline_index = change.text.rfind("\n")
|
|
93
|
-
char_delta = (
|
|
94
|
-
len(change.text)
|
|
95
|
-
- last_newline_index
|
|
96
|
-
- 1
|
|
97
|
-
- change_end_char
|
|
98
|
-
+ change_start_char
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
changed_token_index = locate_affected_token(
|
|
102
|
-
self.sem_tokens,
|
|
103
|
-
change_start_line,
|
|
104
|
-
change_start_char,
|
|
105
|
-
change_end_line,
|
|
106
|
-
change_end_char,
|
|
107
|
-
)
|
|
108
|
-
if changed_token_index:
|
|
109
|
-
self.sem_tokens[changed_token_index + 2] = max(
|
|
110
|
-
1, self.sem_tokens[changed_token_index + 2] + char_delta
|
|
111
|
-
)
|
|
112
|
-
if (
|
|
113
|
-
len(self.sem_tokens) > changed_token_index + 5
|
|
114
|
-
and self.sem_tokens[changed_token_index + 5] == 0
|
|
115
|
-
):
|
|
116
|
-
next_token_index = changed_token_index + 5
|
|
117
|
-
self.sem_tokens[next_token_index + 1] = max(
|
|
118
|
-
0, self.sem_tokens[next_token_index + 1] + char_delta
|
|
119
|
-
)
|
|
120
|
-
return self.sem_tokens
|
|
121
|
-
|
|
122
|
-
current_token_index = 0
|
|
123
|
-
line_offset = 0
|
|
124
|
-
while current_token_index < len(self.sem_tokens):
|
|
125
|
-
token_line_number = self.sem_tokens[current_token_index] + line_offset
|
|
126
|
-
token_start_pos = self.sem_tokens[current_token_index + 1]
|
|
127
|
-
|
|
128
|
-
if token_line_number > change_start_line or (
|
|
129
|
-
token_line_number == change_start_line
|
|
130
|
-
and token_start_pos >= change_start_char
|
|
131
|
-
):
|
|
132
|
-
self.sem_tokens[current_token_index] += line_delta
|
|
133
|
-
if token_line_number == change_start_line:
|
|
134
|
-
self.sem_tokens[current_token_index + 1] += char_delta
|
|
135
|
-
if token_line_number > change_end_line or (
|
|
136
|
-
token_line_number == change_end_line
|
|
137
|
-
and token_start_pos >= change_end_char
|
|
138
|
-
):
|
|
139
|
-
break
|
|
140
|
-
line_offset += self.sem_tokens[current_token_index]
|
|
141
|
-
current_token_index += 5
|
|
142
|
-
return self.sem_tokens
|
|
143
|
-
|
|
144
55
|
|
|
145
56
|
class JacLangServer(LanguageServer):
|
|
146
57
|
"""Class for managing workspace."""
|
|
@@ -190,6 +101,7 @@ class JacLangServer(LanguageServer):
|
|
|
190
101
|
def deep_check(self, file_path: str, annex_view: Optional[str] = None) -> bool:
|
|
191
102
|
"""Rebuild a file and its dependencies."""
|
|
192
103
|
try:
|
|
104
|
+
start_time = time.time()
|
|
193
105
|
document = self.workspace.get_text_document(file_path)
|
|
194
106
|
if file_path in self.modules and (
|
|
195
107
|
parent := self.modules[file_path].impl_parent
|
|
@@ -209,13 +121,23 @@ class JacLangServer(LanguageServer):
|
|
|
209
121
|
)
|
|
210
122
|
|
|
211
123
|
self.publish_diagnostics(
|
|
212
|
-
file_path,
|
|
124
|
+
annex_view if annex_view else file_path,
|
|
213
125
|
gen_diagnostics(
|
|
214
126
|
annex_view if annex_view else file_path,
|
|
215
127
|
build.errors_had,
|
|
216
128
|
build.warnings_had,
|
|
217
129
|
),
|
|
218
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
|
+
)
|
|
140
|
+
self.log_py(f"PROFILE: Deep check took {time.time() - start_time} seconds.")
|
|
219
141
|
return len(build.errors_had) == 0
|
|
220
142
|
except Exception as e:
|
|
221
143
|
self.log_error(f"Error during deep check: {e}")
|
|
@@ -256,12 +178,12 @@ class JacLangServer(LanguageServer):
|
|
|
256
178
|
current_line = document.lines[position.line]
|
|
257
179
|
current_pos = position.character
|
|
258
180
|
current_symbol_path = parse_symbol_path(current_line, current_pos)
|
|
181
|
+
|
|
259
182
|
node_selected = find_deepest_symbol_node_at_pos(
|
|
260
183
|
self.modules[file_path].ir,
|
|
261
184
|
position.line,
|
|
262
185
|
position.character - 2,
|
|
263
186
|
)
|
|
264
|
-
|
|
265
187
|
mod_tab = (
|
|
266
188
|
self.modules[file_path].ir.sym_tab
|
|
267
189
|
if not node_selected
|
|
@@ -269,15 +191,30 @@ class JacLangServer(LanguageServer):
|
|
|
269
191
|
)
|
|
270
192
|
current_tab = self.modules[file_path].ir._sym_tab
|
|
271
193
|
current_symbol_table = mod_tab
|
|
194
|
+
|
|
272
195
|
if completion_trigger == ".":
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
196
|
+
if current_symbol_path:
|
|
197
|
+
completion_items = resolve_completion_symbol_table(
|
|
198
|
+
mod_tab, current_symbol_path, current_tab
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
completion_items = []
|
|
276
202
|
else:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
203
|
+
if node_selected and (
|
|
204
|
+
node_selected.find_parent_of_type(ast.Architype)
|
|
205
|
+
or node_selected.find_parent_of_type(ast.AbilityDef)
|
|
206
|
+
):
|
|
207
|
+
self_symbol = [
|
|
208
|
+
lspt.CompletionItem(
|
|
209
|
+
label="self", kind=lspt.CompletionItemKind.Variable
|
|
210
|
+
)
|
|
211
|
+
]
|
|
212
|
+
else:
|
|
213
|
+
self_symbol = []
|
|
214
|
+
|
|
215
|
+
completion_items = (
|
|
216
|
+
collect_all_symbols_in_scope(current_symbol_table) + self_symbol
|
|
217
|
+
)
|
|
281
218
|
return lspt.CompletionList(is_incomplete=False, items=completion_items)
|
|
282
219
|
|
|
283
220
|
def rename_module(self, old_path: str, new_path: str) -> None:
|
|
@@ -327,9 +264,16 @@ class JacLangServer(LanguageServer):
|
|
|
327
264
|
"""Return hover information for a file."""
|
|
328
265
|
if file_path not in self.modules:
|
|
329
266
|
return None
|
|
330
|
-
|
|
331
|
-
self.modules[file_path].
|
|
267
|
+
token_index = find_index(
|
|
268
|
+
self.modules[file_path].sem_manager.sem_tokens,
|
|
269
|
+
position.line,
|
|
270
|
+
position.character,
|
|
332
271
|
)
|
|
272
|
+
if token_index is None:
|
|
273
|
+
return None
|
|
274
|
+
node_selected = self.modules[file_path].sem_manager.static_sem_tokens[
|
|
275
|
+
token_index
|
|
276
|
+
][3]
|
|
333
277
|
value = self.get_node_info(node_selected) if node_selected else None
|
|
334
278
|
if value:
|
|
335
279
|
return lspt.Hover(
|
|
@@ -361,12 +305,12 @@ class JacLangServer(LanguageServer):
|
|
|
361
305
|
self.log_warning(f"Attribute error when accessing node attributes: {e}")
|
|
362
306
|
return node_info.strip()
|
|
363
307
|
|
|
364
|
-
def
|
|
308
|
+
def get_outline(self, file_path: str) -> list[lspt.DocumentSymbol]:
|
|
365
309
|
"""Return document symbols for a file."""
|
|
366
310
|
if file_path in self.modules and (
|
|
367
311
|
root_node := self.modules[file_path].ir._sym_tab
|
|
368
312
|
):
|
|
369
|
-
return
|
|
313
|
+
return get_symbols_for_outline(root_node)
|
|
370
314
|
return []
|
|
371
315
|
|
|
372
316
|
def get_definition(
|
|
@@ -375,9 +319,16 @@ class JacLangServer(LanguageServer):
|
|
|
375
319
|
"""Return definition location for a file."""
|
|
376
320
|
if file_path not in self.modules:
|
|
377
321
|
return None
|
|
378
|
-
|
|
379
|
-
self.modules[file_path].
|
|
322
|
+
token_index = find_index(
|
|
323
|
+
self.modules[file_path].sem_manager.sem_tokens,
|
|
324
|
+
position.line,
|
|
325
|
+
position.character,
|
|
380
326
|
)
|
|
327
|
+
if token_index is None:
|
|
328
|
+
return None
|
|
329
|
+
node_selected = self.modules[file_path].sem_manager.static_sem_tokens[
|
|
330
|
+
token_index
|
|
331
|
+
][3]
|
|
381
332
|
if node_selected:
|
|
382
333
|
if (
|
|
383
334
|
isinstance(node_selected, ast.Name)
|
|
@@ -400,13 +351,13 @@ class JacLangServer(LanguageServer):
|
|
|
400
351
|
):
|
|
401
352
|
path_range = get_item_path(node_selected.parent)
|
|
402
353
|
if path_range:
|
|
403
|
-
path,
|
|
404
|
-
if path and
|
|
354
|
+
path, loc_range = path_range
|
|
355
|
+
if path and loc_range:
|
|
405
356
|
return lspt.Location(
|
|
406
357
|
uri=uris.from_fs_path(path),
|
|
407
358
|
range=lspt.Range(
|
|
408
|
-
start=lspt.Position(line=
|
|
409
|
-
end=lspt.Position(line=
|
|
359
|
+
start=lspt.Position(line=loc_range[0], character=0),
|
|
360
|
+
end=lspt.Position(line=loc_range[1], character=5),
|
|
410
361
|
),
|
|
411
362
|
)
|
|
412
363
|
else:
|
|
@@ -424,7 +375,6 @@ class JacLangServer(LanguageServer):
|
|
|
424
375
|
else node_selected
|
|
425
376
|
)
|
|
426
377
|
)
|
|
427
|
-
self.log_py(f"{node_selected}, {decl_node}")
|
|
428
378
|
decl_uri = uris.from_fs_path(decl_node.loc.mod_path)
|
|
429
379
|
try:
|
|
430
380
|
decl_range = create_range(decl_node.loc)
|
|
@@ -443,9 +393,16 @@ class JacLangServer(LanguageServer):
|
|
|
443
393
|
self, file_path: str, position: lspt.Position
|
|
444
394
|
) -> list[lspt.Location]:
|
|
445
395
|
"""Return references for a file."""
|
|
446
|
-
|
|
447
|
-
|
|
396
|
+
if file_path not in self.modules:
|
|
397
|
+
return []
|
|
398
|
+
index1 = find_index(
|
|
399
|
+
self.modules[file_path].sem_manager.sem_tokens,
|
|
400
|
+
position.line,
|
|
401
|
+
position.character,
|
|
448
402
|
)
|
|
403
|
+
if index1 is None:
|
|
404
|
+
return []
|
|
405
|
+
node_selected = self.modules[file_path].sem_manager.static_sem_tokens[index1][3]
|
|
449
406
|
if node_selected and node_selected.sym:
|
|
450
407
|
list_of_references: list[lspt.Location] = [
|
|
451
408
|
lspt.Location(
|
|
@@ -457,11 +414,40 @@ class JacLangServer(LanguageServer):
|
|
|
457
414
|
return list_of_references
|
|
458
415
|
return []
|
|
459
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
|
+
|
|
460
446
|
def get_semantic_tokens(self, file_path: str) -> lspt.SemanticTokens:
|
|
461
447
|
"""Return semantic tokens for a file."""
|
|
462
448
|
if file_path not in self.modules:
|
|
463
449
|
return lspt.SemanticTokens(data=[])
|
|
464
|
-
return lspt.SemanticTokens(data=self.modules[file_path].sem_tokens)
|
|
450
|
+
return lspt.SemanticTokens(data=self.modules[file_path].sem_manager.sem_tokens)
|
|
465
451
|
|
|
466
452
|
def log_error(self, message: str) -> None:
|
|
467
453
|
"""Log an error message."""
|