jaclang 0.8.0__py3-none-any.whl → 0.8.1__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 +11 -9
- jaclang/compiler/jac.lark +2 -12
- jaclang/compiler/larkparse/jac_parser.py +1 -1
- jaclang/compiler/parser.py +360 -521
- jaclang/compiler/passes/main/cfg_build_pass.py +2 -2
- jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
- jaclang/compiler/passes/main/def_use_pass.py +4 -7
- jaclang/compiler/passes/main/import_pass.py +3 -3
- jaclang/compiler/passes/main/inheritance_pass.py +2 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +196 -218
- jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
- jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
- jaclang/compiler/passes/main/sym_tab_link_pass.py +4 -4
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +4 -2
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +197 -120
- jaclang/compiler/program.py +2 -7
- jaclang/compiler/tests/fixtures/fam.jac +2 -2
- jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +11 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +7 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
- jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
- jaclang/compiler/tests/test_importer.py +20 -0
- jaclang/compiler/tests/test_parser.py +1 -0
- jaclang/compiler/unitree.py +456 -304
- jaclang/langserve/engine.jac +498 -0
- jaclang/langserve/sem_manager.jac +309 -0
- jaclang/langserve/server.jac +186 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +6 -7
- jaclang/langserve/tests/server_test/utils.py +4 -1
- jaclang/langserve/tests/session.jac +294 -0
- jaclang/langserve/tests/test_sem_tokens.py +2 -2
- jaclang/langserve/tests/test_server.py +12 -7
- jaclang/langserve/utils.jac +51 -30
- jaclang/runtimelib/archetype.py +1 -1
- jaclang/runtimelib/builtin.py +17 -14
- jaclang/runtimelib/importer.py +26 -8
- jaclang/runtimelib/machine.py +96 -55
- jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
- jaclang/runtimelib/utils.py +3 -3
- jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
- jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
- jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
- jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
- jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
- jaclang/tests/fixtures/concurrency.jac +1 -1
- jaclang/tests/fixtures/edge_ability.jac +49 -0
- jaclang/tests/fixtures/guess_game.jac +1 -1
- jaclang/tests/fixtures/here_usage_error.jac +21 -0
- jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
- jaclang/tests/fixtures/node_del.jac +30 -36
- jaclang/tests/fixtures/visit_traversal.jac +47 -0
- jaclang/tests/test_cli.py +12 -7
- jaclang/tests/test_language.py +91 -16
- jaclang/utils/helpers.py +14 -6
- jaclang/utils/lang_tools.py +2 -3
- jaclang/utils/tests/test_lang_tools.py +2 -1
- jaclang/utils/treeprinter.py +3 -4
- {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/METADATA +4 -3
- {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/RECORD +71 -55
- {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/WHEEL +1 -1
- jaclang/langserve/engine.py +0 -553
- jaclang/langserve/sem_manager.py +0 -383
- jaclang/langserve/server.py +0 -167
- jaclang/langserve/tests/session.py +0 -255
- jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
- jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
- /jaclang/langserve/{__init__.py → __init__.jac} +0 -0
- {jaclang-0.8.0.dist-info → jaclang-0.8.1.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"""Semantic Token Manager module."""
|
|
2
|
+
|
|
3
|
+
import from __future__ { annotations }
|
|
4
|
+
|
|
5
|
+
import from typing { List, Optional, Tuple }
|
|
6
|
+
|
|
7
|
+
import jaclang.compiler.unitree as uni;
|
|
8
|
+
import from jaclang { JacMachineInterface as Jac }
|
|
9
|
+
import utils;
|
|
10
|
+
import lsprotocol.types as lspt;
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
"""Semantic Token Manager class."""
|
|
14
|
+
class SemTokManager {
|
|
15
|
+
"""Initialize semantic token manager."""
|
|
16
|
+
def init(self: SemTokManager, ir: uni.Module) -> None {
|
|
17
|
+
self.sem_tokens: List[int] = self.gen_sem_tokens(ir);
|
|
18
|
+
self.static_sem_tokens: List[Tuple[lspt.Position, int, int, uni.AstSymbolNode]] = self.gen_sem_tok_node(ir);
|
|
19
|
+
}
|
|
20
|
+
"""Return semantic tokens."""
|
|
21
|
+
def gen_sem_tokens(self: SemTokManager, ir: uni.Module) -> list[int] {
|
|
22
|
+
tokens= [];
|
|
23
|
+
(prev_line, prev_col)= (0, 0);
|
|
24
|
+
for nd in ir._in_mod_nodes {
|
|
25
|
+
if isinstance(nd, uni.NameAtom) and nd.sem_token {
|
|
26
|
+
(line, col_start, col_end)= (( nd.loc.first_line - 1 ),
|
|
27
|
+
( nd.loc.col_start - 1 ), ( nd.loc.col_end - 1 ));
|
|
28
|
+
length= ( col_end - col_start );
|
|
29
|
+
tokens += [
|
|
30
|
+
( line - prev_line ),
|
|
31
|
+
col_start if line != prev_line else ( col_start - prev_col ),
|
|
32
|
+
length,
|
|
33
|
+
* nd.sem_token
|
|
34
|
+
];
|
|
35
|
+
(prev_line, prev_col)= (line, col_start);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return tokens ;
|
|
39
|
+
}
|
|
40
|
+
"""Return semantic tokens."""
|
|
41
|
+
def gen_sem_tok_node(self: SemTokManager, ir: uni.Module) -> List[
|
|
42
|
+
Tuple[(lspt.Position, int, int, uni.AstSymbolNode)]
|
|
43
|
+
] {
|
|
44
|
+
tokens: List[Tuple[(lspt.Position, int, int, uni.AstSymbolNode)]] = [];
|
|
45
|
+
for nd in ir._in_mod_nodes {
|
|
46
|
+
if isinstance(nd, uni.NameAtom) and nd.sem_token {
|
|
47
|
+
(line, col_start, col_end)= (( nd.loc.first_line - 1 ),
|
|
48
|
+
( nd.loc.col_start - 1 ), ( nd.loc.col_end - 1 ));
|
|
49
|
+
length= ( col_end - col_start );
|
|
50
|
+
pos= lspt.Position(line, col_start);
|
|
51
|
+
tokens += [(pos, col_end, length, nd)];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return tokens ;
|
|
55
|
+
}
|
|
56
|
+
"""Update semantic tokens on change."""
|
|
57
|
+
def update_sem_tokens(self: SemTokManager,
|
|
58
|
+
content_changes: lspt.DidChangeTextDocumentParams,
|
|
59
|
+
sem_tokens: list[int],
|
|
60
|
+
document_lines: List[str]) -> list[int] {
|
|
61
|
+
for change in [ x for x in content_changes.content_changes if isinstance(x,
|
|
62
|
+
lspt.TextDocumentContentChangeEvent_Type1) ] {
|
|
63
|
+
change_start_line= change.range.start.line;
|
|
64
|
+
change_start_char= change.range.start.character;
|
|
65
|
+
change_end_line= change.range.end.line;
|
|
66
|
+
change_end_char= change.range.end.character;
|
|
67
|
+
is_delete= change.text == '';
|
|
68
|
+
(prev_token_index, next_token_index, insert_inside_token)= utils.find_surrounding_tokens(change_start_line,
|
|
69
|
+
change_start_char,
|
|
70
|
+
change_end_line,
|
|
71
|
+
change_end_char,
|
|
72
|
+
sem_tokens);
|
|
73
|
+
prev_tok_pos= utils.get_token_start(prev_token_index, sem_tokens);
|
|
74
|
+
nxt_tok_pos= utils.get_token_start(next_token_index, sem_tokens);
|
|
75
|
+
changing_line_text= utils.get_line_of_code(change_start_line, document_lines);
|
|
76
|
+
if not changing_line_text {return sem_tokens ;}
|
|
77
|
+
is_edit_between_tokens= bool(change_start_line > prev_tok_pos[0] or change_start_line == prev_tok_pos[0] and change_start_char > ( prev_tok_pos[
|
|
78
|
+
1
|
|
79
|
+
] + sem_tokens[( prev_token_index + 2 )] ) if prev_token_index and ( prev_token_index + 2 ) < len(sem_tokens) else 0 and change_end_line < nxt_tok_pos[
|
|
80
|
+
0
|
|
81
|
+
] or change_end_line == nxt_tok_pos[0] and change_end_char < nxt_tok_pos[1]);
|
|
82
|
+
text= ( '%s' % change.text );
|
|
83
|
+
line_delta= ( len(text.split('\n')) - 1 );
|
|
84
|
+
is_multiline_insertion= line_delta > 0;
|
|
85
|
+
is_next_token_same_line= change_end_line == nxt_tok_pos[0];
|
|
86
|
+
if is_delete {
|
|
87
|
+
next_token_index= ( prev_token_index + 5 ) if insert_inside_token and prev_token_index is not None or next_token_index and prev_token_index is not None and next_token_index >= 10 and ( next_token_index - prev_token_index ) == 10 else next_token_index;
|
|
88
|
+
if next_token_index is None {return sem_tokens ;}
|
|
89
|
+
nxt_tok_pos= utils.get_token_start(next_token_index, sem_tokens);
|
|
90
|
+
is_single_line_change= change_end_line == change_start_line;
|
|
91
|
+
is_next_token_same_line= change_end_line == nxt_tok_pos[0];
|
|
92
|
+
if is_single_line_change and insert_inside_token and prev_token_index is not None {
|
|
93
|
+
sem_tokens= SemTokManager.handle_single_line_delete(self,
|
|
94
|
+
sem_tokens,
|
|
95
|
+
next_token_index,
|
|
96
|
+
prev_token_index,
|
|
97
|
+
is_next_token_same_line,
|
|
98
|
+
change);
|
|
99
|
+
} elif is_single_line_change and is_edit_between_tokens {
|
|
100
|
+
sem_tokens= SemTokManager.handle_single_line_delete_between_tokens(self,
|
|
101
|
+
sem_tokens,
|
|
102
|
+
next_token_index,
|
|
103
|
+
is_next_token_same_line,
|
|
104
|
+
change,
|
|
105
|
+
change_start_line,
|
|
106
|
+
change_end_line);
|
|
107
|
+
} else {
|
|
108
|
+
sem_tokens= SemTokManager.handle_multi_line_delete(self,
|
|
109
|
+
sem_tokens,
|
|
110
|
+
next_token_index,
|
|
111
|
+
nxt_tok_pos,
|
|
112
|
+
change_start_line,
|
|
113
|
+
change_end_line,
|
|
114
|
+
change_start_char,
|
|
115
|
+
change_end_char,
|
|
116
|
+
prev_tok_pos,
|
|
117
|
+
is_next_token_same_line);
|
|
118
|
+
}
|
|
119
|
+
return sem_tokens ;
|
|
120
|
+
}
|
|
121
|
+
is_token_boundary_edit= False;
|
|
122
|
+
if insert_inside_token and prev_token_index is not None {
|
|
123
|
+
(sem_tokens, is_token_boundary_edit, nxt_tok_pos, next_token_index)= SemTokManager.handle_insert_inside_token(self,
|
|
124
|
+
change,
|
|
125
|
+
sem_tokens,
|
|
126
|
+
prev_token_index,
|
|
127
|
+
changing_line_text,
|
|
128
|
+
line_delta,
|
|
129
|
+
prev_tok_pos,
|
|
130
|
+
change_start_char,
|
|
131
|
+
change_end_char,
|
|
132
|
+
is_token_boundary_edit,
|
|
133
|
+
nxt_tok_pos);
|
|
134
|
+
}
|
|
135
|
+
tokens_on_same_line= prev_tok_pos[0] == nxt_tok_pos[0];
|
|
136
|
+
if is_edit_between_tokens or is_token_boundary_edit or is_multiline_insertion and next_token_index is not None {
|
|
137
|
+
if is_multiline_insertion {
|
|
138
|
+
sem_tokens= SemTokManager.handle_multi_line_insertion(self,
|
|
139
|
+
sem_tokens,
|
|
140
|
+
next_token_index,
|
|
141
|
+
nxt_tok_pos,
|
|
142
|
+
change_start_line,
|
|
143
|
+
change_end_line,
|
|
144
|
+
change_end_char,
|
|
145
|
+
prev_tok_pos,
|
|
146
|
+
tokens_on_same_line,
|
|
147
|
+
changing_line_text,
|
|
148
|
+
line_delta);
|
|
149
|
+
} else {
|
|
150
|
+
sem_tokens= SemTokManager.handle_single_line_insertion(self,
|
|
151
|
+
sem_tokens,
|
|
152
|
+
next_token_index,
|
|
153
|
+
is_next_token_same_line,
|
|
154
|
+
change,
|
|
155
|
+
tokens_on_same_line,
|
|
156
|
+
nxt_tok_pos,
|
|
157
|
+
change_start_line,
|
|
158
|
+
line_delta);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return sem_tokens ;
|
|
163
|
+
}
|
|
164
|
+
"""Handle multi line deletion."""
|
|
165
|
+
static def handle_multi_line_delete(self: SemTokManager,
|
|
166
|
+
sem_tokens: list[int],
|
|
167
|
+
next_token_index: int,
|
|
168
|
+
nxt_tok_pos: <>tuple[(int, int, int)],
|
|
169
|
+
change_start_line: int,
|
|
170
|
+
change_end_line: int,
|
|
171
|
+
change_start_char: int,
|
|
172
|
+
change_end_char: int,
|
|
173
|
+
prev_tok_pos: <>tuple[(int, int, int)],
|
|
174
|
+
is_next_token_same_line: bool) -> list[int] {
|
|
175
|
+
if is_next_token_same_line {
|
|
176
|
+
char_del= ( nxt_tok_pos[1] - change_end_char );
|
|
177
|
+
total_char_del= ( change_start_char + char_del );
|
|
178
|
+
sem_tokens[( next_token_index + 1 )]= ( total_char_del - prev_tok_pos[1] ) if prev_tok_pos[
|
|
179
|
+
0
|
|
180
|
+
] == change_start_line else total_char_del;
|
|
181
|
+
}
|
|
182
|
+
sem_tokens[next_token_index] -= ( change_end_line - change_start_line );
|
|
183
|
+
return sem_tokens ;
|
|
184
|
+
}
|
|
185
|
+
"""Handle single line deletion between tokens."""
|
|
186
|
+
static def handle_single_line_delete_between_tokens(self: SemTokManager,
|
|
187
|
+
sem_tokens: list[int],
|
|
188
|
+
next_token_index: int,
|
|
189
|
+
is_next_token_same_line: bool,
|
|
190
|
+
change: lspt.TextDocumentContentChangeEvent_Type1,
|
|
191
|
+
change_start_line: int,
|
|
192
|
+
change_end_line: int) -> list[int] {
|
|
193
|
+
if is_next_token_same_line and change.range_length {
|
|
194
|
+
sem_tokens[( next_token_index + 1 )] -= change.range_length;
|
|
195
|
+
} else {
|
|
196
|
+
sem_tokens[next_token_index] -= ( change_end_line - change_start_line );
|
|
197
|
+
}
|
|
198
|
+
return sem_tokens ;
|
|
199
|
+
}
|
|
200
|
+
"""Handle single line deletion."""
|
|
201
|
+
static def handle_single_line_delete(self: SemTokManager,
|
|
202
|
+
sem_tokens: list[int],
|
|
203
|
+
next_token_index: int,
|
|
204
|
+
prev_token_index: int,
|
|
205
|
+
is_next_token_same_line: bool,
|
|
206
|
+
change: lspt.TextDocumentContentChangeEvent_Type1) -> list[int] {
|
|
207
|
+
assert change.range_length is not None ;
|
|
208
|
+
sem_tokens[( prev_token_index + 2 )] -= change.range_length;
|
|
209
|
+
if is_next_token_same_line {
|
|
210
|
+
sem_tokens[( next_token_index + 1 )] -= change.range_length;
|
|
211
|
+
}
|
|
212
|
+
return sem_tokens ;
|
|
213
|
+
}
|
|
214
|
+
"""Handle single line insertion."""
|
|
215
|
+
static def handle_single_line_insertion(self: SemTokManager,
|
|
216
|
+
sem_tokens: list[int],
|
|
217
|
+
next_token_index: int,
|
|
218
|
+
is_next_token_same_line: bool,
|
|
219
|
+
change: lspt.TextDocumentContentChangeEvent_Type1,
|
|
220
|
+
tokens_on_same_line: bool,
|
|
221
|
+
nxt_tok_pos: <>tuple[(int, int, int)],
|
|
222
|
+
change_start_line: int,
|
|
223
|
+
line_delta: int) -> list[int] {
|
|
224
|
+
if tokens_on_same_line {
|
|
225
|
+
sem_tokens[( next_token_index + 1 )] += len(change.text);
|
|
226
|
+
sem_tokens[next_token_index] += line_delta;
|
|
227
|
+
} else {
|
|
228
|
+
is_next_token_same_line= change_start_line == nxt_tok_pos[0];
|
|
229
|
+
if is_next_token_same_line {
|
|
230
|
+
sem_tokens[next_token_index] += line_delta;
|
|
231
|
+
sem_tokens[( next_token_index + 1 )] += len(change.text);
|
|
232
|
+
} else {sem_tokens[next_token_index] += line_delta;}
|
|
233
|
+
}
|
|
234
|
+
return sem_tokens ;
|
|
235
|
+
}
|
|
236
|
+
"""Handle multi line insertion."""
|
|
237
|
+
static def handle_multi_line_insertion(self: SemTokManager,
|
|
238
|
+
sem_tokens: list[int],
|
|
239
|
+
next_token_index: int,
|
|
240
|
+
nxt_tok_pos: <>tuple[(int, int, int)],
|
|
241
|
+
change_start_line: int,
|
|
242
|
+
change_end_line: int,
|
|
243
|
+
change_end_char: int,
|
|
244
|
+
prev_tok_pos: <>tuple[(int, int, int)],
|
|
245
|
+
tokens_on_same_line: bool,
|
|
246
|
+
changing_line_text: <>tuple[(str, int)],
|
|
247
|
+
line_delta: int) -> list[int] {
|
|
248
|
+
if tokens_on_same_line {
|
|
249
|
+
char_del= ( nxt_tok_pos[1] - change_end_char );
|
|
250
|
+
total_char_del= ( changing_line_text[1] + char_del );
|
|
251
|
+
} else {
|
|
252
|
+
is_prev_token_same_line= change_end_line == prev_tok_pos[0];
|
|
253
|
+
is_next_token_same_line= change_start_line == nxt_tok_pos[0];
|
|
254
|
+
if is_prev_token_same_line {total_char_del= nxt_tok_pos[1];} elif is_next_token_same_line {
|
|
255
|
+
char_del= ( nxt_tok_pos[1] - change_end_char );
|
|
256
|
+
total_char_del= ( changing_line_text[1] + char_del );
|
|
257
|
+
} else {
|
|
258
|
+
total_char_del= sem_tokens[( next_token_index + 1 )];
|
|
259
|
+
line_delta -= ( change_end_line - change_start_line );
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
sem_tokens[( next_token_index + 1 )]= total_char_del;
|
|
263
|
+
sem_tokens[next_token_index] += line_delta;
|
|
264
|
+
return sem_tokens ;
|
|
265
|
+
}
|
|
266
|
+
"""Handle insert inside token."""
|
|
267
|
+
static def handle_insert_inside_token(self: SemTokManager,
|
|
268
|
+
change: lspt.TextDocumentContentChangeEvent_Type1,
|
|
269
|
+
sem_tokens: list[int],
|
|
270
|
+
prev_token_index: int,
|
|
271
|
+
changing_line_text: <>tuple[(str, int)],
|
|
272
|
+
line_delta: int,
|
|
273
|
+
prev_tok_pos: <>tuple[(int, int, int)],
|
|
274
|
+
change_start_char: int,
|
|
275
|
+
change_end_char: int,
|
|
276
|
+
is_token_boundary_edit: bool,
|
|
277
|
+
nxt_tok_pos: <>tuple[(int, int, int)]) -> <>tuple[
|
|
278
|
+
list[int], bool, <>tuple[(int, int, int)], Optional[int]
|
|
279
|
+
] {
|
|
280
|
+
next_token_index= None;
|
|
281
|
+
for i in ['\n', ' ', '\t'] {
|
|
282
|
+
if i in change.text {
|
|
283
|
+
if prev_tok_pos[1] == change_start_char {
|
|
284
|
+
if i == '\n' {
|
|
285
|
+
sem_tokens[prev_token_index] += line_delta;
|
|
286
|
+
sem_tokens[( prev_token_index + 1 )]= changing_line_text[1];
|
|
287
|
+
} else {sem_tokens[( prev_token_index + 1 )] += len(change.text);}
|
|
288
|
+
return (sem_tokens,
|
|
289
|
+
is_token_boundary_edit, nxt_tok_pos, next_token_index) ;
|
|
290
|
+
} else {
|
|
291
|
+
is_token_boundary_edit= True;
|
|
292
|
+
next_token_index= ( prev_token_index + 5 );
|
|
293
|
+
nxt_tok_pos= utils.get_token_start(next_token_index, sem_tokens);
|
|
294
|
+
break ;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
if not is_token_boundary_edit {
|
|
299
|
+
selected_region= ( change_end_char - change_start_char );
|
|
300
|
+
index_offset= 2;
|
|
301
|
+
sem_tokens[( prev_token_index + index_offset )] += ( len(change.text) - selected_region );
|
|
302
|
+
if prev_tok_pos[0] == utils.get_token_start(( prev_token_index + 5 ),
|
|
303
|
+
sem_tokens)[0] {
|
|
304
|
+
sem_tokens[( ( prev_token_index + index_offset ) + 4 )] += ( len(change.text) - selected_region );
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return (sem_tokens, is_token_boundary_edit, nxt_tok_pos, next_token_index) ;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Jaclang Language Server."""
|
|
2
|
+
|
|
3
|
+
import from typing { Optional }
|
|
4
|
+
|
|
5
|
+
import from jaclang.compiler.constant {
|
|
6
|
+
JacSemTokenModifier as SemTokMod,
|
|
7
|
+
JacSemTokenType as SemTokType
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
import from engine { JacLangServer }
|
|
11
|
+
import from jaclang.settings { settings }
|
|
12
|
+
|
|
13
|
+
import lsprotocol.types as lspt;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
with entry {
|
|
17
|
+
server = JacLangServer();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
"""Check syntax on change."""
|
|
22
|
+
@server.feature(lspt.TEXT_DOCUMENT_DID_OPEN)
|
|
23
|
+
async def did_open(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None {
|
|
24
|
+
await ls.launch_deep_check(params.text_document.uri);
|
|
25
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
"""Check syntax on change."""
|
|
30
|
+
@server.feature(lspt.TEXT_DOCUMENT_DID_SAVE)
|
|
31
|
+
async def did_save(ls: JacLangServer, params: lspt.DidOpenTextDocumentParams) -> None {
|
|
32
|
+
file_path = params.text_document.uri;
|
|
33
|
+
await ls.launch_deep_check(file_path);
|
|
34
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
"""Check syntax on change."""
|
|
39
|
+
@server.feature(lspt.TEXT_DOCUMENT_DID_CHANGE)
|
|
40
|
+
async def did_change(
|
|
41
|
+
ls: JacLangServer,
|
|
42
|
+
params: lspt.DidChangeTextDocumentParams
|
|
43
|
+
) -> None {
|
|
44
|
+
file_path = params.text_document.uri;
|
|
45
|
+
await ls.launch_quick_check(file_path);
|
|
46
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
"""Format the given document."""
|
|
51
|
+
@server.feature(lspt.TEXT_DOCUMENT_FORMATTING)
|
|
52
|
+
def formatting(
|
|
53
|
+
ls: JacLangServer,
|
|
54
|
+
params: lspt.DocumentFormattingParams
|
|
55
|
+
) -> list[lspt.TextEdit] {
|
|
56
|
+
return ls.formatted_jac(params.text_document.uri);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
"""Check syntax on file creation."""
|
|
61
|
+
@server.feature(
|
|
62
|
+
lspt.WORKSPACE_DID_CREATE_FILES,
|
|
63
|
+
lspt.FileOperationRegistrationOptions(
|
|
64
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
def did_create_files(ls: JacLangServer, params: lspt.CreateFilesParams) -> None {}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
"""Check syntax on file rename."""
|
|
71
|
+
@server.feature(
|
|
72
|
+
lspt.WORKSPACE_DID_RENAME_FILES,
|
|
73
|
+
lspt.FileOperationRegistrationOptions(
|
|
74
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
def did_rename_files(ls: JacLangServer, params: lspt.RenameFilesParams) -> None {
|
|
78
|
+
new_uris = [ file.new_uri for file in params.files ];
|
|
79
|
+
old_uris = [ file.old_uri for file in params.files ];
|
|
80
|
+
for i in range(len(new_uris)) {
|
|
81
|
+
ls.rename_module(old_uris[i], new_uris[i]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
"""Check syntax on file delete."""
|
|
87
|
+
@server.feature(
|
|
88
|
+
lspt.WORKSPACE_DID_DELETE_FILES,
|
|
89
|
+
lspt.FileOperationRegistrationOptions(
|
|
90
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
91
|
+
)
|
|
92
|
+
)
|
|
93
|
+
def did_delete_files(ls: JacLangServer, params: lspt.DeleteFilesParams) -> None {
|
|
94
|
+
for file in params.files {
|
|
95
|
+
ls.delete_module(file.uri);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
"""Provide completion."""
|
|
101
|
+
@server.feature(
|
|
102
|
+
lspt.TEXT_DOCUMENT_COMPLETION,
|
|
103
|
+
lspt.CompletionOptions(trigger_characters=['.', ':', 'a-zA-Z0-9'])
|
|
104
|
+
)
|
|
105
|
+
def completion(ls: JacLangServer, params: lspt.CompletionParams) -> lspt.CompletionList {
|
|
106
|
+
return ls.get_completion(
|
|
107
|
+
params.text_document.uri,
|
|
108
|
+
params.position,
|
|
109
|
+
params.context.trigger_character if params.context else None
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
"""Provide hover information for the given hover request."""
|
|
115
|
+
@server.feature(lspt.TEXT_DOCUMENT_HOVER, lspt.HoverOptions(work_done_progress=True))
|
|
116
|
+
def hover(
|
|
117
|
+
ls: JacLangServer,
|
|
118
|
+
params: lspt.TextDocumentPositionParams
|
|
119
|
+
) -> Optional[lspt.Hover] {
|
|
120
|
+
return ls.get_hover_info(params.text_document.uri, params.position);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
"""Provide document symbols."""
|
|
125
|
+
@server.feature(lspt.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
|
|
126
|
+
def document_symbol(
|
|
127
|
+
ls: JacLangServer,
|
|
128
|
+
params: lspt.DocumentSymbolParams
|
|
129
|
+
) -> list[lspt.DocumentSymbol] {
|
|
130
|
+
return ls.get_outline(params.text_document.uri);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
"""Provide definition."""
|
|
135
|
+
@server.feature(lspt.TEXT_DOCUMENT_DEFINITION)
|
|
136
|
+
def definition(
|
|
137
|
+
ls: JacLangServer,
|
|
138
|
+
params: lspt.TextDocumentPositionParams
|
|
139
|
+
) -> Optional[lspt.Location] {
|
|
140
|
+
return ls.get_definition(params.text_document.uri, params.position);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
"""Provide references."""
|
|
145
|
+
@server.feature(lspt.TEXT_DOCUMENT_REFERENCES)
|
|
146
|
+
def references(ls: JacLangServer, params: lspt.ReferenceParams) -> list[lspt.Location] {
|
|
147
|
+
return ls.get_references(params.text_document.uri, params.position);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
"""Rename symbol."""
|
|
152
|
+
@server.feature(lspt.TEXT_DOCUMENT_RENAME)
|
|
153
|
+
def rename(ls: JacLangServer, params: lspt.RenameParams) -> Optional[lspt.WorkspaceEdit] {
|
|
154
|
+
ls.log_warning('Auto Rename is Experimental, Please use with caution.');
|
|
155
|
+
return ls.rename_symbol(params.text_document.uri, params.position, params.new_name);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
"""Provide semantic tokens."""
|
|
160
|
+
@server.feature(
|
|
161
|
+
lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
162
|
+
lspt.SemanticTokensLegend(
|
|
163
|
+
token_types=SemTokType.as_str_list(),
|
|
164
|
+
token_modifiers=SemTokMod.as_str_list()
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
def semantic_tokens_full(
|
|
168
|
+
ls: JacLangServer,
|
|
169
|
+
params: lspt.SemanticTokensParams
|
|
170
|
+
) -> lspt.SemanticTokens {
|
|
171
|
+
return ls.get_semantic_tokens(params.text_document.uri);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
"""Run the language server."""
|
|
176
|
+
def run_lang_server() -> None {
|
|
177
|
+
settings.pass_timer = True;
|
|
178
|
+
server.start_io();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
with entry {
|
|
183
|
+
if __name__ == '__main__' {
|
|
184
|
+
run_lang_server();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -12,13 +12,6 @@ from lsprotocol.types import (
|
|
|
12
12
|
VersionedTextDocumentIdentifier,
|
|
13
13
|
TextDocumentIdentifier,
|
|
14
14
|
)
|
|
15
|
-
from jaclang.langserve.engine import JacLangServer
|
|
16
|
-
from jaclang.langserve.server import (
|
|
17
|
-
did_open,
|
|
18
|
-
did_save,
|
|
19
|
-
did_change,
|
|
20
|
-
formatting,
|
|
21
|
-
)
|
|
22
15
|
from jaclang.langserve.tests.server_test.utils import (
|
|
23
16
|
create_temp_jac_file,
|
|
24
17
|
get_code,
|
|
@@ -27,6 +20,12 @@ from jaclang.langserve.tests.server_test.utils import (
|
|
|
27
20
|
)
|
|
28
21
|
from jaclang.vendor.pygls.uris import from_fs_path
|
|
29
22
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
23
|
+
from jaclang import JacMachineInterface as _
|
|
24
|
+
|
|
25
|
+
JacLangServer = _.py_jac_import(
|
|
26
|
+
"....langserve.engine", __file__, items={"JacLangServer": None}
|
|
27
|
+
)[0]
|
|
28
|
+
(did_open, did_save, did_change, formatting) = _.py_jac_import( "....langserve.server", __file__, items={"did_open": None, "did_save": None, "did_change": None, "formatting": None})
|
|
30
29
|
|
|
31
30
|
JAC_FILE = get_jac_file_path()
|
|
32
31
|
|
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
import os
|
|
3
3
|
import tempfile
|
|
4
4
|
|
|
5
|
-
from jaclang.langserve.engine import JacLangServer
|
|
6
5
|
from jaclang.vendor.pygls.uris import from_fs_path
|
|
7
6
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
8
7
|
|
|
9
8
|
from textwrap import dedent
|
|
9
|
+
from jaclang import JacMachineInterface as _
|
|
10
|
+
JacLangServer = _.py_jac_import(
|
|
11
|
+
"....langserve.engine", __file__, items={"JacLangServer": None}
|
|
12
|
+
)[0]
|
|
10
13
|
|
|
11
14
|
def get_jac_file_path():
|
|
12
15
|
"""Return the absolute path to the sample Jac file used for testing."""
|