jaclang 0.7.11__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 +10 -2
- jaclang/compiler/absyntree.py +10 -2
- jaclang/compiler/parser.py +2 -1
- jaclang/compiler/passes/main/pyast_gen_pass.py +238 -32
- jaclang/compiler/passes/main/pyast_load_pass.py +3 -1
- jaclang/compiler/passes/main/type_check_pass.py +0 -17
- jaclang/compiler/tests/test_importer.py +1 -1
- jaclang/core/importer.py +126 -89
- jaclang/langserve/engine.py +177 -165
- jaclang/langserve/server.py +19 -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 +53 -64
- jaclang/langserve/utils.py +266 -0
- jaclang/plugin/default.py +2 -2
- jaclang/plugin/feature.py +2 -2
- jaclang/plugin/spec.py +2 -2
- jaclang/tests/fixtures/deep/one_lev.jac +3 -0
- jaclang/tests/fixtures/needs_import.jac +1 -1
- jaclang/tests/test_cli.py +6 -6
- {jaclang-0.7.11.dist-info → jaclang-0.7.13.dist-info}/METADATA +1 -1
- {jaclang-0.7.11.dist-info → jaclang-0.7.13.dist-info}/RECORD +24 -24
- {jaclang-0.7.11.dist-info → jaclang-0.7.13.dist-info}/WHEEL +0 -0
- {jaclang-0.7.11.dist-info → jaclang-0.7.13.dist-info}/entry_points.txt +0 -0
jaclang/langserve/engine.py
CHANGED
|
@@ -5,23 +5,27 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import logging
|
|
7
7
|
from concurrent.futures import ThreadPoolExecutor
|
|
8
|
-
from
|
|
9
|
-
from typing import Optional
|
|
8
|
+
from typing import Callable, Optional
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
import jaclang.compiler.absyntree as ast
|
|
13
|
-
from jaclang.compiler.compile import
|
|
12
|
+
from jaclang.compiler.compile import jac_str_to_pass
|
|
14
13
|
from jaclang.compiler.parser import JacParser
|
|
15
14
|
from jaclang.compiler.passes import Pass
|
|
16
|
-
from jaclang.compiler.passes.main.schedules import
|
|
15
|
+
from jaclang.compiler.passes.main.schedules import py_code_gen_typed
|
|
17
16
|
from jaclang.compiler.passes.tool import FuseCommentsPass, JacFormatPass
|
|
18
17
|
from jaclang.compiler.passes.transform import Alert
|
|
19
18
|
from jaclang.langserve.utils import (
|
|
19
|
+
collect_all_symbols_in_scope,
|
|
20
20
|
collect_symbols,
|
|
21
21
|
create_range,
|
|
22
22
|
find_deepest_symbol_node_at_pos,
|
|
23
|
+
gen_diagnostics,
|
|
23
24
|
get_item_path,
|
|
24
25
|
get_mod_path,
|
|
26
|
+
locate_affected_token,
|
|
27
|
+
parse_symbol_path,
|
|
28
|
+
resolve_completion_symbol_table,
|
|
25
29
|
)
|
|
26
30
|
from jaclang.vendor.pygls import uris
|
|
27
31
|
from jaclang.vendor.pygls.server import LanguageServer
|
|
@@ -29,14 +33,6 @@ from jaclang.vendor.pygls.server import LanguageServer
|
|
|
29
33
|
import lsprotocol.types as lspt
|
|
30
34
|
|
|
31
35
|
|
|
32
|
-
class ALev(IntEnum):
|
|
33
|
-
"""Analysis Level successfully completed."""
|
|
34
|
-
|
|
35
|
-
QUICK = 1
|
|
36
|
-
DEEP = 2
|
|
37
|
-
TYPE = 3
|
|
38
|
-
|
|
39
|
-
|
|
40
36
|
class ModuleInfo:
|
|
41
37
|
"""Module IR and Stats."""
|
|
42
38
|
|
|
@@ -45,16 +41,11 @@ class ModuleInfo:
|
|
|
45
41
|
ir: ast.Module,
|
|
46
42
|
errors: list[Alert],
|
|
47
43
|
warnings: list[Alert],
|
|
48
|
-
alev: ALev,
|
|
49
44
|
parent: Optional[ModuleInfo] = None,
|
|
50
45
|
) -> None:
|
|
51
46
|
"""Initialize module info."""
|
|
52
47
|
self.ir = ir
|
|
53
|
-
self.errors = errors
|
|
54
|
-
self.warnings = warnings
|
|
55
|
-
self.alev = alev
|
|
56
48
|
self.parent: Optional[ModuleInfo] = parent
|
|
57
|
-
self.diagnostics = self.gen_diagnostics()
|
|
58
49
|
self.sem_tokens: list[int] = self.gen_sem_tokens()
|
|
59
50
|
|
|
60
51
|
@property
|
|
@@ -62,57 +53,6 @@ class ModuleInfo:
|
|
|
62
53
|
"""Return uri."""
|
|
63
54
|
return uris.from_fs_path(self.ir.loc.mod_path)
|
|
64
55
|
|
|
65
|
-
def update_with(
|
|
66
|
-
self,
|
|
67
|
-
build: Pass,
|
|
68
|
-
alev: ALev,
|
|
69
|
-
refresh: bool = False,
|
|
70
|
-
mod_override: Optional[ast.Module] = None,
|
|
71
|
-
) -> None:
|
|
72
|
-
"""Update module info."""
|
|
73
|
-
target_mod = mod_override if mod_override else build.ir
|
|
74
|
-
if not isinstance(target_mod, ast.Module):
|
|
75
|
-
return
|
|
76
|
-
self.ir = target_mod # if alev > ALev.QUICK else self.ir
|
|
77
|
-
if refresh:
|
|
78
|
-
self.errors = build.errors_had
|
|
79
|
-
self.warnings = build.warnings_had
|
|
80
|
-
else:
|
|
81
|
-
self.errors += [
|
|
82
|
-
i
|
|
83
|
-
for i in build.errors_had
|
|
84
|
-
if i not in self.errors
|
|
85
|
-
if i.loc.mod_path == target_mod.loc.mod_path
|
|
86
|
-
]
|
|
87
|
-
self.warnings += [
|
|
88
|
-
i
|
|
89
|
-
for i in build.warnings_had
|
|
90
|
-
if i not in self.warnings
|
|
91
|
-
if i.loc.mod_path == target_mod.loc.mod_path
|
|
92
|
-
]
|
|
93
|
-
self.alev = alev
|
|
94
|
-
self.diagnostics = self.gen_diagnostics()
|
|
95
|
-
if self.alev == ALev.TYPE:
|
|
96
|
-
self.sem_tokens = self.gen_sem_tokens()
|
|
97
|
-
|
|
98
|
-
def gen_diagnostics(self) -> list[lspt.Diagnostic]:
|
|
99
|
-
"""Return diagnostics."""
|
|
100
|
-
return [
|
|
101
|
-
lspt.Diagnostic(
|
|
102
|
-
range=create_range(error.loc),
|
|
103
|
-
message=error.msg,
|
|
104
|
-
severity=lspt.DiagnosticSeverity.Error,
|
|
105
|
-
)
|
|
106
|
-
for error in self.errors
|
|
107
|
-
] + [
|
|
108
|
-
lspt.Diagnostic(
|
|
109
|
-
range=create_range(warning.loc),
|
|
110
|
-
message=warning.msg,
|
|
111
|
-
severity=lspt.DiagnosticSeverity.Warning,
|
|
112
|
-
)
|
|
113
|
-
for warning in self.warnings
|
|
114
|
-
]
|
|
115
|
-
|
|
116
56
|
def gen_sem_tokens(self) -> list[int]:
|
|
117
57
|
"""Return semantic tokens."""
|
|
118
58
|
tokens = []
|
|
@@ -134,6 +74,76 @@ class ModuleInfo:
|
|
|
134
74
|
prev_line, prev_col = line, col_start
|
|
135
75
|
return tokens
|
|
136
76
|
|
|
77
|
+
def update_sem_tokens(
|
|
78
|
+
self, content_changes: lspt.DidChangeTextDocumentParams
|
|
79
|
+
) -> list[int]:
|
|
80
|
+
"""Update semantic tokens on change."""
|
|
81
|
+
for change in [
|
|
82
|
+
x
|
|
83
|
+
for x in content_changes.content_changes
|
|
84
|
+
if isinstance(x, lspt.TextDocumentContentChangeEvent_Type1)
|
|
85
|
+
]:
|
|
86
|
+
change_start_line = change.range.start.line
|
|
87
|
+
change_start_char = change.range.start.character
|
|
88
|
+
change_end_line = change.range.end.line
|
|
89
|
+
change_end_char = change.range.end.character
|
|
90
|
+
|
|
91
|
+
line_delta = change.text.count("\n") - (change_end_line - change_start_line)
|
|
92
|
+
if line_delta == 0:
|
|
93
|
+
char_delta = len(change.text) - (change_end_char - change_start_char)
|
|
94
|
+
else:
|
|
95
|
+
last_newline_index = change.text.rfind("\n")
|
|
96
|
+
char_delta = (
|
|
97
|
+
len(change.text)
|
|
98
|
+
- last_newline_index
|
|
99
|
+
- 1
|
|
100
|
+
- change_end_char
|
|
101
|
+
+ change_start_char
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
changed_token_index = locate_affected_token(
|
|
105
|
+
self.sem_tokens,
|
|
106
|
+
change_start_line,
|
|
107
|
+
change_start_char,
|
|
108
|
+
change_end_line,
|
|
109
|
+
change_end_char,
|
|
110
|
+
)
|
|
111
|
+
if changed_token_index:
|
|
112
|
+
self.sem_tokens[changed_token_index + 2] = max(
|
|
113
|
+
1, self.sem_tokens[changed_token_index + 2] + char_delta
|
|
114
|
+
)
|
|
115
|
+
if (
|
|
116
|
+
len(self.sem_tokens) > changed_token_index + 5
|
|
117
|
+
and self.sem_tokens[changed_token_index + 5] == 0
|
|
118
|
+
):
|
|
119
|
+
next_token_index = changed_token_index + 5
|
|
120
|
+
self.sem_tokens[next_token_index + 1] = max(
|
|
121
|
+
0, self.sem_tokens[next_token_index + 1] + char_delta
|
|
122
|
+
)
|
|
123
|
+
return self.sem_tokens
|
|
124
|
+
|
|
125
|
+
current_token_index = 0
|
|
126
|
+
line_offset = 0
|
|
127
|
+
while current_token_index < len(self.sem_tokens):
|
|
128
|
+
token_line_number = self.sem_tokens[current_token_index] + line_offset
|
|
129
|
+
token_start_pos = self.sem_tokens[current_token_index + 1]
|
|
130
|
+
|
|
131
|
+
if token_line_number > change_start_line or (
|
|
132
|
+
token_line_number == change_start_line
|
|
133
|
+
and token_start_pos >= change_start_char
|
|
134
|
+
):
|
|
135
|
+
self.sem_tokens[current_token_index] += line_delta
|
|
136
|
+
if token_line_number == change_start_line:
|
|
137
|
+
self.sem_tokens[current_token_index + 1] += char_delta
|
|
138
|
+
if token_line_number > change_end_line or (
|
|
139
|
+
token_line_number == change_end_line
|
|
140
|
+
and token_start_pos >= change_end_char
|
|
141
|
+
):
|
|
142
|
+
break
|
|
143
|
+
line_offset += self.sem_tokens[current_token_index]
|
|
144
|
+
current_token_index += 5
|
|
145
|
+
return self.sem_tokens
|
|
146
|
+
|
|
137
147
|
|
|
138
148
|
class JacLangServer(LanguageServer):
|
|
139
149
|
"""Class for managing workspace."""
|
|
@@ -143,65 +153,35 @@ class JacLangServer(LanguageServer):
|
|
|
143
153
|
super().__init__("jac-lsp", "v0.1")
|
|
144
154
|
self.modules: dict[str, ModuleInfo] = {}
|
|
145
155
|
self.executor = ThreadPoolExecutor()
|
|
146
|
-
|
|
147
|
-
async def push_diagnostics(self, file_path: str) -> None:
|
|
148
|
-
"""Push diagnostics for a file."""
|
|
149
|
-
if file_path in self.modules:
|
|
150
|
-
self.publish_diagnostics(
|
|
151
|
-
file_path,
|
|
152
|
-
self.modules[file_path].diagnostics,
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
def unwind_to_parent(self, file_path: str) -> str:
|
|
156
|
-
"""Unwind to parent."""
|
|
157
|
-
orig_file_path = file_path
|
|
158
|
-
if file_path in self.modules:
|
|
159
|
-
while cur := self.modules[file_path].parent:
|
|
160
|
-
file_path = cur.uri
|
|
161
|
-
if file_path == orig_file_path and (
|
|
162
|
-
discover := self.modules[file_path].ir.annexable_by
|
|
163
|
-
):
|
|
164
|
-
file_path = uris.from_fs_path(discover)
|
|
165
|
-
self.quick_check(file_path)
|
|
166
|
-
return file_path
|
|
156
|
+
self.tasks: dict[str, asyncio.Task] = {}
|
|
167
157
|
|
|
168
158
|
def update_modules(
|
|
169
|
-
self, file_path: str, build: Pass,
|
|
159
|
+
self, file_path: str, build: Pass, refresh: bool = False
|
|
170
160
|
) -> None:
|
|
171
161
|
"""Update modules."""
|
|
172
162
|
if not isinstance(build.ir, ast.Module):
|
|
173
163
|
self.log_error("Error with module build.")
|
|
174
164
|
return
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if i.loc.mod_path == uris.to_fs_path(file_path)
|
|
189
|
-
],
|
|
190
|
-
alev=alev,
|
|
191
|
-
)
|
|
165
|
+
self.modules[file_path] = ModuleInfo(
|
|
166
|
+
ir=build.ir,
|
|
167
|
+
errors=[
|
|
168
|
+
i
|
|
169
|
+
for i in build.errors_had
|
|
170
|
+
if i.loc.mod_path == uris.to_fs_path(file_path)
|
|
171
|
+
],
|
|
172
|
+
warnings=[
|
|
173
|
+
i
|
|
174
|
+
for i in build.warnings_had
|
|
175
|
+
if i.loc.mod_path == uris.to_fs_path(file_path)
|
|
176
|
+
],
|
|
177
|
+
)
|
|
192
178
|
for p in build.ir.mod_deps.keys():
|
|
193
179
|
uri = uris.from_fs_path(p)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
self.modules[uri] = ModuleInfo(
|
|
200
|
-
ir=build.ir.mod_deps[p],
|
|
201
|
-
errors=[i for i in build.errors_had if i.loc.mod_path == p],
|
|
202
|
-
warnings=[i for i in build.warnings_had if i.loc.mod_path == p],
|
|
203
|
-
alev=alev,
|
|
204
|
-
)
|
|
180
|
+
self.modules[uri] = ModuleInfo(
|
|
181
|
+
ir=build.ir.mod_deps[p],
|
|
182
|
+
errors=[i for i in build.errors_had if i.loc.mod_path == p],
|
|
183
|
+
warnings=[i for i in build.warnings_had if i.loc.mod_path == p],
|
|
184
|
+
)
|
|
205
185
|
self.modules[uri].parent = (
|
|
206
186
|
self.modules[file_path] if file_path != uri else None
|
|
207
187
|
)
|
|
@@ -213,72 +193,100 @@ class JacLangServer(LanguageServer):
|
|
|
213
193
|
build = jac_str_to_pass(
|
|
214
194
|
jac_str=document.source, file_path=document.path, schedule=[]
|
|
215
195
|
)
|
|
196
|
+
self.publish_diagnostics(
|
|
197
|
+
file_path,
|
|
198
|
+
gen_diagnostics(file_path, build.errors_had, build.warnings_had),
|
|
199
|
+
)
|
|
200
|
+
return len(build.errors_had) == 0
|
|
216
201
|
except Exception as e:
|
|
217
202
|
self.log_error(f"Error during syntax check: {e}")
|
|
218
203
|
return False
|
|
219
|
-
self.update_modules(file_path, build, ALev.QUICK, refresh=True)
|
|
220
|
-
return len(self.modules[file_path].errors) == 0
|
|
221
|
-
|
|
222
|
-
def deep_check(self, file_path: str) -> bool:
|
|
223
|
-
"""Rebuild a file and its dependencies."""
|
|
224
|
-
if file_path not in self.modules:
|
|
225
|
-
self.quick_check(file_path)
|
|
226
|
-
try:
|
|
227
|
-
file_path = self.unwind_to_parent(file_path)
|
|
228
|
-
build = jac_ir_to_pass(ir=self.modules[file_path].ir)
|
|
229
|
-
except Exception as e:
|
|
230
|
-
self.log_error(f"Error during syntax check: {e}")
|
|
231
|
-
return False
|
|
232
|
-
self.update_modules(file_path, build, ALev.DEEP)
|
|
233
|
-
return len(self.modules[file_path].errors) == 0
|
|
234
204
|
|
|
235
|
-
def
|
|
205
|
+
def deep_check(self, file_path: str, annex_view: Optional[str] = None) -> bool:
|
|
236
206
|
"""Rebuild a file and its dependencies."""
|
|
237
|
-
if file_path not in self.modules:
|
|
238
|
-
self.deep_check(file_path)
|
|
239
207
|
try:
|
|
240
|
-
|
|
241
|
-
build =
|
|
242
|
-
|
|
208
|
+
document = self.workspace.get_text_document(file_path)
|
|
209
|
+
build = jac_str_to_pass(
|
|
210
|
+
jac_str=document.source,
|
|
211
|
+
file_path=document.path,
|
|
212
|
+
schedule=py_code_gen_typed,
|
|
213
|
+
)
|
|
214
|
+
self.update_modules(file_path, build)
|
|
215
|
+
if discover := self.modules[file_path].ir.annexable_by:
|
|
216
|
+
return self.deep_check(
|
|
217
|
+
uris.from_fs_path(discover), annex_view=file_path
|
|
218
|
+
)
|
|
219
|
+
self.publish_diagnostics(
|
|
220
|
+
file_path,
|
|
221
|
+
gen_diagnostics(
|
|
222
|
+
annex_view if annex_view else file_path,
|
|
223
|
+
build.errors_had,
|
|
224
|
+
build.warnings_had,
|
|
225
|
+
),
|
|
243
226
|
)
|
|
227
|
+
return len(build.errors_had) == 0
|
|
244
228
|
except Exception as e:
|
|
245
|
-
self.log_error(f"Error during
|
|
229
|
+
self.log_error(f"Error during deep check: {e}")
|
|
246
230
|
return False
|
|
247
|
-
self.update_modules(file_path, build, ALev.TYPE)
|
|
248
|
-
return len(self.modules[file_path].errors) == 0
|
|
249
231
|
|
|
250
|
-
async def
|
|
232
|
+
async def launch_quick_check(self, uri: str) -> None:
|
|
251
233
|
"""Analyze and publish diagnostics."""
|
|
252
|
-
|
|
253
|
-
success = await asyncio.get_event_loop().run_in_executor(
|
|
234
|
+
await asyncio.get_event_loop().run_in_executor(
|
|
254
235
|
self.executor, self.quick_check, uri
|
|
255
236
|
)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
237
|
+
|
|
238
|
+
async def launch_deep_check(self, uri: str) -> None:
|
|
239
|
+
"""Analyze and publish diagnostics."""
|
|
240
|
+
|
|
241
|
+
async def run_in_executor(
|
|
242
|
+
func: Callable[[str, Optional[str]], bool],
|
|
243
|
+
file_path: str,
|
|
244
|
+
annex_view: Optional[str] = None,
|
|
245
|
+
) -> None:
|
|
246
|
+
loop = asyncio.get_event_loop()
|
|
247
|
+
await loop.run_in_executor(self.executor, func, file_path, annex_view)
|
|
248
|
+
|
|
249
|
+
if uri in self.tasks and not self.tasks[uri].done():
|
|
250
|
+
self.log_py(f"Canceling {uri} deep check...")
|
|
251
|
+
self.tasks[uri].cancel()
|
|
252
|
+
del self.tasks[uri]
|
|
253
|
+
self.log_py(f"Analyzing {uri}...")
|
|
254
|
+
task = asyncio.create_task(run_in_executor(self.deep_check, uri))
|
|
255
|
+
self.tasks[uri] = task
|
|
256
|
+
await task
|
|
267
257
|
|
|
268
258
|
def get_completion(
|
|
269
|
-
self, file_path: str, position: lspt.Position
|
|
259
|
+
self, file_path: str, position: lspt.Position, completion_trigger: Optional[str]
|
|
270
260
|
) -> lspt.CompletionList:
|
|
271
261
|
"""Return completion for a file."""
|
|
272
|
-
|
|
262
|
+
completion_items = []
|
|
273
263
|
document = self.workspace.get_text_document(file_path)
|
|
274
|
-
current_line = document.lines[position.line]
|
|
275
|
-
|
|
264
|
+
current_line = document.lines[position.line]
|
|
265
|
+
current_pos = position.character
|
|
266
|
+
current_symbol_path = parse_symbol_path(current_line, current_pos)
|
|
267
|
+
node_selected = find_deepest_symbol_node_at_pos(
|
|
268
|
+
self.modules[file_path].ir,
|
|
269
|
+
position.line,
|
|
270
|
+
position.character - 2,
|
|
271
|
+
)
|
|
276
272
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
273
|
+
mod_tab = (
|
|
274
|
+
self.modules[file_path].ir.sym_tab
|
|
275
|
+
if not node_selected
|
|
276
|
+
else node_selected.sym_tab
|
|
277
|
+
)
|
|
278
|
+
current_tab = self.modules[file_path].ir._sym_tab
|
|
279
|
+
current_symbol_table = mod_tab
|
|
280
|
+
if completion_trigger == ".":
|
|
281
|
+
completion_items = resolve_completion_symbol_table(
|
|
282
|
+
mod_tab, current_symbol_path, current_tab
|
|
283
|
+
)
|
|
284
|
+
else:
|
|
285
|
+
try: # noqa SIM105
|
|
286
|
+
completion_items = collect_all_symbols_in_scope(current_symbol_table)
|
|
287
|
+
except AttributeError:
|
|
288
|
+
pass
|
|
289
|
+
return lspt.CompletionList(is_incomplete=False, items=completion_items)
|
|
282
290
|
|
|
283
291
|
def rename_module(self, old_path: str, new_path: str) -> None:
|
|
284
292
|
"""Rename module."""
|
|
@@ -325,6 +333,8 @@ class JacLangServer(LanguageServer):
|
|
|
325
333
|
self, file_path: str, position: lspt.Position
|
|
326
334
|
) -> Optional[lspt.Hover]:
|
|
327
335
|
"""Return hover information for a file."""
|
|
336
|
+
if file_path not in self.modules:
|
|
337
|
+
return None
|
|
328
338
|
node_selected = find_deepest_symbol_node_at_pos(
|
|
329
339
|
self.modules[file_path].ir, position.line, position.character
|
|
330
340
|
)
|
|
@@ -371,6 +381,8 @@ class JacLangServer(LanguageServer):
|
|
|
371
381
|
self, file_path: str, position: lspt.Position
|
|
372
382
|
) -> Optional[lspt.Location]:
|
|
373
383
|
"""Return definition location for a file."""
|
|
384
|
+
if file_path not in self.modules:
|
|
385
|
+
return None
|
|
374
386
|
node_selected: Optional[ast.AstSymbolNode] = find_deepest_symbol_node_at_pos(
|
|
375
387
|
self.modules[file_path].ir, position.line, position.character
|
|
376
388
|
)
|
jaclang/langserve/server.py
CHANGED
|
@@ -9,7 +9,6 @@ from jaclang.compiler.constant import (
|
|
|
9
9
|
JacSemTokenType as SemTokType,
|
|
10
10
|
)
|
|
11
11
|
from jaclang.langserve.engine import JacLangServer
|
|
12
|
-
from jaclang.langserve.utils import debounce
|
|
13
12
|
|
|
14
13
|
import lsprotocol.types as lspt
|
|
15
14
|
|
|
@@ -20,18 +19,19 @@ server = JacLangServer()
|
|
|
20
19
|
@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
|
|
21
20
|
async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None:
|
|
22
21
|
"""Check syntax on change."""
|
|
23
|
-
await ls.
|
|
22
|
+
await ls.launch_deep_check(params.text_document.uri)
|
|
24
23
|
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
@server.feature(lspt.TEXT_DOCUMENT_DID_CHANGE)
|
|
28
|
-
@debounce(0.3)
|
|
29
27
|
async def did_change(
|
|
30
28
|
ls: JacLangServer, params: lspt.DidChangeTextDocumentParams
|
|
31
29
|
) -> None:
|
|
32
30
|
"""Check syntax on change."""
|
|
33
|
-
await ls.
|
|
34
|
-
ls.
|
|
31
|
+
await ls.launch_quick_check(file_path := params.text_document.uri)
|
|
32
|
+
if file_path in ls.modules:
|
|
33
|
+
ls.modules[file_path].update_sem_tokens(params)
|
|
34
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH)
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
@server.feature(lspt.TEXT_DOCUMENT_FORMATTING)
|
|
@@ -86,11 +86,15 @@ def did_delete_files(ls: JacLangServer, params: lspt.DeleteFilesParams) -> None:
|
|
|
86
86
|
|
|
87
87
|
@server.feature(
|
|
88
88
|
lspt.TEXT_DOCUMENT_COMPLETION,
|
|
89
|
-
lspt.CompletionOptions(trigger_characters=[".", ":", ""]),
|
|
89
|
+
lspt.CompletionOptions(trigger_characters=[".", ":", "a-zA-Z0-9"]),
|
|
90
90
|
)
|
|
91
91
|
def completion(ls: JacLangServer, params: lspt.CompletionParams) -> lspt.CompletionList:
|
|
92
92
|
"""Provide completion."""
|
|
93
|
-
return ls.get_completion(
|
|
93
|
+
return ls.get_completion(
|
|
94
|
+
params.text_document.uri,
|
|
95
|
+
params.position,
|
|
96
|
+
params.context.trigger_character if params.context else None,
|
|
97
|
+
)
|
|
94
98
|
|
|
95
99
|
|
|
96
100
|
@server.feature(lspt.TEXT_DOCUMENT_HOVER, lspt.HoverOptions(work_done_progress=True))
|
|
@@ -134,6 +138,14 @@ def semantic_tokens_full(
|
|
|
134
138
|
ls: JacLangServer, params: lspt.SemanticTokensParams
|
|
135
139
|
) -> lspt.SemanticTokens:
|
|
136
140
|
"""Provide semantic tokens."""
|
|
141
|
+
# import logging
|
|
142
|
+
|
|
143
|
+
# logging.info("\nGetting semantic tokens\n")
|
|
144
|
+
# # logging.info(ls.get_semantic_tokens(params.text_document.uri))
|
|
145
|
+
# i = 0
|
|
146
|
+
# while i < len(ls.get_semantic_tokens(params.text_document.uri).data):
|
|
147
|
+
# logging.info(ls.get_semantic_tokens(params.text_document.uri).data[i : i + 5])
|
|
148
|
+
# i += 5
|
|
137
149
|
return ls.get_semantic_tokens(params.text_document.uri)
|
|
138
150
|
|
|
139
151
|
|
|
@@ -21,8 +21,34 @@ with entry:__main__ {
|
|
|
21
21
|
|
|
22
22
|
glob x: int = 10;
|
|
23
23
|
|
|
24
|
-
enum
|
|
24
|
+
enum Colorenum {
|
|
25
25
|
RED,
|
|
26
26
|
GREEN,
|
|
27
27
|
BLUE
|
|
28
|
-
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
obj Colour1 {
|
|
31
|
+
has color1: Colorenum,
|
|
32
|
+
point1: int;
|
|
33
|
+
|
|
34
|
+
can get_color1 -> Colorenum;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
:obj:Colour1:can:get_color1 -> Colorenum {
|
|
38
|
+
return self.color;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
obj red :Colour1: {
|
|
42
|
+
has base_colorred: Colorenum = Color.RED,
|
|
43
|
+
pointred: int = 10;
|
|
44
|
+
obj color2 {
|
|
45
|
+
has color22: Color = Colorenum.BLUE,
|
|
46
|
+
point22: int = 20;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
with entry:__main__ {
|
|
51
|
+
r = red(color1=Color.GREEN, point1=20);
|
|
52
|
+
print(r.get_color1());
|
|
53
|
+
print(r.color2.color22);
|
|
54
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import:py os;
|
|
2
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_numbers as adsd, subtract,x,Colorenum as clr;
|
|
5
5
|
import:jac base_module_structure as base_module_structure;
|
|
6
6
|
import:py from py_import,add1 as ss, sub1 as subtract1,apple,Orange1;
|