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,294 @@
|
|
|
1
|
+
"""Provides LSP session helpers for testing."""
|
|
2
|
+
|
|
3
|
+
import os;
|
|
4
|
+
import subprocess;
|
|
5
|
+
import sys;
|
|
6
|
+
import from concurrent.futures { Future, ThreadPoolExecutor }
|
|
7
|
+
import from threading { Event }
|
|
8
|
+
|
|
9
|
+
import from pylsp_jsonrpc.dispatchers { MethodDispatcher }
|
|
10
|
+
import from pylsp_jsonrpc.endpoint { Endpoint }
|
|
11
|
+
import from pylsp_jsonrpc.streams { JsonRpcStreamReader, JsonRpcStreamWriter }
|
|
12
|
+
|
|
13
|
+
import defaults;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
with entry {
|
|
17
|
+
LSP_EXIT_TIMEOUT = 5000;
|
|
18
|
+
PUBLISH_DIAGNOSTICS = 'textDocument/publishDiagnostics';
|
|
19
|
+
WINDOW_LOG_MESSAGE = 'window/logMessage';
|
|
20
|
+
WINDOW_SHOW_MESSAGE = 'window/showMessage';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
"""Send and Receive messages over LSP as a test LS Client."""
|
|
25
|
+
class LspSession (MethodDispatcher) {
|
|
26
|
+
def init(self: LspSession, cwd: Any = None) {
|
|
27
|
+
self.cwd = cwd if cwd else os.getcwd() ;
|
|
28
|
+
self._thread_pool = ThreadPoolExecutor();
|
|
29
|
+
self._sub = None;
|
|
30
|
+
self._writer = None;
|
|
31
|
+
self._reader = None;
|
|
32
|
+
self._endpoint = None;
|
|
33
|
+
self._notification_callbacks = {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
"""Context manager entrypoint.\n\n shell=True needed for pytest-cov to work in subprocess.\n """
|
|
37
|
+
def __enter__(self: LspSession) {
|
|
38
|
+
self._sub = subprocess.Popen(
|
|
39
|
+
["jac", "run",
|
|
40
|
+
os.path.join(os.path.dirname(os.path.dirname(__file__)), 'server.jac')],
|
|
41
|
+
stdout=subprocess.PIPE,
|
|
42
|
+
stdin=subprocess.PIPE,
|
|
43
|
+
stderr=subprocess.DEVNULL,
|
|
44
|
+
bufsize=0,
|
|
45
|
+
cwd=self.cwd,
|
|
46
|
+
env=os.environ,
|
|
47
|
+
shell=('WITH_COVERAGE' in os.environ)
|
|
48
|
+
);
|
|
49
|
+
self._writer = JsonRpcStreamWriter(os.fdopen(self._sub.stdin.fileno(), 'wb'));
|
|
50
|
+
self._reader = JsonRpcStreamReader(os.fdopen(self._sub.stdout.fileno(), 'rb'));
|
|
51
|
+
dispatcher =
|
|
52
|
+
{PUBLISH_DIAGNOSTICS : self._publish_diagnostics , WINDOW_SHOW_MESSAGE : self._window_show_message , WINDOW_LOG_MESSAGE : self._window_log_message };
|
|
53
|
+
self._endpoint = Endpoint(dispatcher, self._writer.write);
|
|
54
|
+
self._thread_pool.submit(self._reader.listen, self._endpoint.consume);
|
|
55
|
+
return self;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def __exit__(self: LspSession, typ: Any, value: Any, _tb: Any) {
|
|
59
|
+
self.shutdown(True);
|
|
60
|
+
try {
|
|
61
|
+
self._sub.terminate();
|
|
62
|
+
} except Exception as e {
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
self._endpoint.shutdown();
|
|
67
|
+
self._thread_pool.shutdown();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
"""Sends the initialize request to LSP server."""
|
|
71
|
+
def initialize(
|
|
72
|
+
self: LspSession,
|
|
73
|
+
initialize_params: Any = None,
|
|
74
|
+
process_server_capabilities: Any = None
|
|
75
|
+
) {
|
|
76
|
+
server_initialized = Event();
|
|
77
|
+
def _after_initialize(fut: Any) {
|
|
78
|
+
if process_server_capabilities {
|
|
79
|
+
process_server_capabilities(fut.result());
|
|
80
|
+
}
|
|
81
|
+
self.initialized();
|
|
82
|
+
server_initialized.set();
|
|
83
|
+
}
|
|
84
|
+
self._send_request(
|
|
85
|
+
'initialize',
|
|
86
|
+
params=initialize_params
|
|
87
|
+
if (initialize_params is not None)
|
|
88
|
+
else defaults.VSCODE_DEFAULT_INITIALIZE
|
|
89
|
+
,
|
|
90
|
+
handle_response=_after_initialize
|
|
91
|
+
);
|
|
92
|
+
server_initialized.wait();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
"""Sends the initialized notification to LSP server."""
|
|
96
|
+
def initialized(self: LspSession, initialized_params: Any = None) {
|
|
97
|
+
if (initialized_params is None) {
|
|
98
|
+
initialized_params = {};
|
|
99
|
+
}
|
|
100
|
+
self._endpoint.notify('initialized', initialized_params);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
"""Sends the shutdown request to LSP server."""
|
|
104
|
+
def shutdown(
|
|
105
|
+
self: LspSession,
|
|
106
|
+
should_exit: Any,
|
|
107
|
+
exit_timeout: Any = LSP_EXIT_TIMEOUT
|
|
108
|
+
) {
|
|
109
|
+
def _after_shutdown(_: Any) {
|
|
110
|
+
if should_exit {
|
|
111
|
+
self.exit_lsp(exit_timeout);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
self._send_request('shutdown', handle_response=_after_shutdown);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
"""Handles LSP server process exit."""
|
|
118
|
+
def exit_lsp(self: LspSession, exit_timeout: Any = LSP_EXIT_TIMEOUT) {
|
|
119
|
+
self._endpoint.notify('exit');
|
|
120
|
+
assert (self._sub.wait(exit_timeout) == 0) ;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
"""Sends text document completion request to LSP server."""
|
|
124
|
+
def text_document_completion(self: LspSession, completion_params: Any) {
|
|
125
|
+
fut = self._send_request('textDocument/completion', params=completion_params);
|
|
126
|
+
return fut.result();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
"""Sends text document rename request to LSP server."""
|
|
130
|
+
def text_document_rename(self: LspSession, rename_params: Any) {
|
|
131
|
+
fut = self._send_request('textDocument/rename', params=rename_params);
|
|
132
|
+
return fut.result();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
"""Sends text document code action request to LSP server."""
|
|
136
|
+
def text_document_code_action(self: LspSession, code_action_params: Any) {
|
|
137
|
+
fut = self._send_request('textDocument/codeAction', params=code_action_params);
|
|
138
|
+
return fut.result();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
"""Sends text document hover request to LSP server."""
|
|
142
|
+
def text_document_hover(self: LspSession, hover_params: Any) {
|
|
143
|
+
fut = self._send_request('textDocument/hover', params=hover_params);
|
|
144
|
+
return fut.result();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
"""Sends text document formatting request to LSP server."""
|
|
148
|
+
def text_document_formatting(self: LspSession, formatting_params: Any) {
|
|
149
|
+
fut = self._send_request('textDocument/formatting', params=formatting_params);
|
|
150
|
+
return fut.result();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
"""Sends text document hover request to LSP server."""
|
|
154
|
+
def text_document_signature_help(self: LspSession, signature_help_params: Any) {
|
|
155
|
+
fut = self._send_request(
|
|
156
|
+
'textDocument/signatureHelp',
|
|
157
|
+
params=signature_help_params
|
|
158
|
+
);
|
|
159
|
+
return fut.result();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
"""Sends text document declaration request to LSP server."""
|
|
163
|
+
def text_document_declaration(self: LspSession, declaration_params: Any) {
|
|
164
|
+
fut = self._send_request('textDocument/declaration', params=declaration_params);
|
|
165
|
+
return fut.result();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
"""Sends text document definition request to LSP server."""
|
|
169
|
+
def text_document_definition(self: LspSession, definition_params: Any) {
|
|
170
|
+
fut = self._send_request('textDocument/definition', params=definition_params);
|
|
171
|
+
return fut.result();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
"""Sends text document symbol request to LSP server."""
|
|
175
|
+
def text_document_symbol(self: LspSession, document_symbol_params: Any) {
|
|
176
|
+
fut = self._send_request(
|
|
177
|
+
'textDocument/documentSymbol',
|
|
178
|
+
params=document_symbol_params
|
|
179
|
+
);
|
|
180
|
+
return fut.result();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
"""Sends text document highlight request to LSP server."""
|
|
184
|
+
def text_document_highlight(self: LspSession, document_highlight_params: Any) {
|
|
185
|
+
fut = self._send_request(
|
|
186
|
+
'textDocument/documentHighlight',
|
|
187
|
+
params=document_highlight_params
|
|
188
|
+
);
|
|
189
|
+
return fut.result();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
"""Sends text document references request to LSP server."""
|
|
193
|
+
def text_document_references(self: LspSession, references_params: Any) {
|
|
194
|
+
fut = self._send_request('textDocument/references', params=references_params);
|
|
195
|
+
return fut.result();
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
"""Sends workspace symbol request to LSP server."""
|
|
199
|
+
def workspace_symbol(self: LspSession, workspace_symbol_params: Any) {
|
|
200
|
+
fut = self._send_request('workspace/symbol', params=workspace_symbol_params);
|
|
201
|
+
return fut.result();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
"""Sends completion item resolve request to LSP server."""
|
|
205
|
+
def completion_item_resolve(self: LspSession, resolve_params: Any) {
|
|
206
|
+
fut = self._send_request('completionItem/resolve', params=resolve_params);
|
|
207
|
+
return fut.result();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
"""Sends did change notification to LSP Server."""
|
|
211
|
+
def notify_did_change(self: LspSession, did_change_params: Any) {
|
|
212
|
+
self._send_notification('textDocument/didChange', params=did_change_params);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
"""Sends did save notification to LSP Server."""
|
|
216
|
+
def notify_did_save(self: LspSession, did_save_params: Any) {
|
|
217
|
+
self._send_notification('textDocument/didSave', params=did_save_params);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
"""Sends did open notification to LSP Server."""
|
|
221
|
+
def notify_did_open(self: LspSession, did_open_params: Any) {
|
|
222
|
+
self._send_notification('textDocument/didOpen', params=did_open_params);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
"""Set custom LS notification handler."""
|
|
226
|
+
def set_notification_callback(
|
|
227
|
+
self: LspSession,
|
|
228
|
+
notification_name: Any,
|
|
229
|
+
callback: Any
|
|
230
|
+
) {
|
|
231
|
+
self._notification_callbacks[notification_name] = callback;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
"""Gets callback if set or default callback for a given LS notification."""
|
|
235
|
+
def get_notification_callback(self: LspSession, notification_name: Any) {
|
|
236
|
+
try {
|
|
237
|
+
return self._notification_callbacks[notification_name];
|
|
238
|
+
} except KeyError {
|
|
239
|
+
def _default_handler(_params: Any) -> None {}
|
|
240
|
+
return _default_handler;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
"""Internal handler for text document publish diagnostics."""
|
|
246
|
+
def _publish_diagnostics(self: LspSession, publish_diagnostics_params: Any) {
|
|
247
|
+
return self._handle_notification(
|
|
248
|
+
PUBLISH_DIAGNOSTICS,
|
|
249
|
+
publish_diagnostics_params
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
"""Internal handler for window log message."""
|
|
254
|
+
def _window_log_message(self: LspSession, window_log_message_params: Any) {
|
|
255
|
+
return self._handle_notification(WINDOW_LOG_MESSAGE, window_log_message_params);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
"""Internal handler for window show message."""
|
|
259
|
+
def _window_show_message(self: LspSession, window_show_message_params: Any) {
|
|
260
|
+
return self._handle_notification(
|
|
261
|
+
WINDOW_SHOW_MESSAGE,
|
|
262
|
+
window_show_message_params
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
"""Internal handler for notifications."""
|
|
267
|
+
def _handle_notification(self: LspSession, notification_name: Any, params: Any) {
|
|
268
|
+
fut = Future();
|
|
269
|
+
def _handler() {
|
|
270
|
+
callback = self.get_notification_callback(notification_name);
|
|
271
|
+
callback(params);
|
|
272
|
+
fut.set_result(None);
|
|
273
|
+
}
|
|
274
|
+
self._thread_pool.submit(_handler);
|
|
275
|
+
return fut;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
"""Sends {name} request to the LSP server."""
|
|
279
|
+
def _send_request(
|
|
280
|
+
self: LspSession,
|
|
281
|
+
name: Any,
|
|
282
|
+
params: Any = None,
|
|
283
|
+
handle_response: Any = lambda f: Any: f.done()
|
|
284
|
+
) {
|
|
285
|
+
fut = self._endpoint.request(name, params);
|
|
286
|
+
fut.add_done_callback(handle_response);
|
|
287
|
+
return fut;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
"""Sends {name} notification to the LSP server."""
|
|
291
|
+
def _send_notification(self: LspSession, name: Any, params: Any = None) {
|
|
292
|
+
self._endpoint.notify(name, params);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import lsprotocol.types as lspt
|
|
5
|
-
|
|
6
|
-
from jaclang.langserve.sem_manager import SemTokManager
|
|
5
|
+
from jaclang import JacMachineInterface as _
|
|
7
6
|
from jaclang.utils.test import TestCase
|
|
8
7
|
|
|
9
8
|
from typing import Tuple
|
|
10
9
|
|
|
10
|
+
SemTokManager = _.py_jac_import("..sem_manager", __file__, items={"SemTokManager": None})[0]
|
|
11
11
|
|
|
12
12
|
class TestUpdateSemTokens(TestCase):
|
|
13
13
|
"""Test update semantic tokens"""
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
from jaclang.utils.test import TestCase
|
|
2
2
|
from jaclang.vendor.pygls import uris
|
|
3
3
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
4
|
-
from jaclang.langserve.engine import JacLangServer
|
|
5
|
-
from .session import LspSession
|
|
6
4
|
|
|
7
5
|
import lsprotocol.types as lspt
|
|
8
6
|
import pytest
|
|
7
|
+
from jaclang import JacMachineInterface as _
|
|
9
8
|
|
|
9
|
+
JacLangServer = _.py_jac_import(
|
|
10
|
+
"...langserve.engine", __file__, items={"JacLangServer": None}
|
|
11
|
+
)[0]
|
|
12
|
+
LspSession = _.py_jac_import(
|
|
13
|
+
"session", __file__, items={"LspSession": None}
|
|
14
|
+
)[0]
|
|
10
15
|
|
|
11
16
|
class TestJacLangServer(TestCase):
|
|
12
17
|
|
|
@@ -62,7 +67,7 @@ class TestJacLangServer(TestCase):
|
|
|
62
67
|
self.assertIn(
|
|
63
68
|
# "ability) calculate_area: float",
|
|
64
69
|
"ability) calculate_area\n( radius : float ) -> float",
|
|
65
|
-
lsp.get_hover_info(circle_impl_file, pos).contents.value,
|
|
70
|
+
lsp.get_hover_info(circle_impl_file, pos).contents.value.replace("'", ""),
|
|
66
71
|
)
|
|
67
72
|
|
|
68
73
|
def test_impl_auto_discover(self) -> None:
|
|
@@ -80,7 +85,7 @@ class TestJacLangServer(TestCase):
|
|
|
80
85
|
self.assertIn(
|
|
81
86
|
# "ability) calculate_area: float",
|
|
82
87
|
"(public ability) calculate_area\n( radius : float ) -> float",
|
|
83
|
-
lsp.get_hover_info(circle_impl_file, pos).contents.value,
|
|
88
|
+
lsp.get_hover_info(circle_impl_file, pos).contents.value.replace("'", ""),
|
|
84
89
|
)
|
|
85
90
|
|
|
86
91
|
@pytest.mark.xfail(reason="TODO: Fix when we have the type checker")
|
|
@@ -133,12 +138,12 @@ class TestJacLangServer(TestCase):
|
|
|
133
138
|
workspace = Workspace(workspace_path, lsp)
|
|
134
139
|
lsp.lsp._workspace = workspace
|
|
135
140
|
guess_game_file = uris.from_fs_path(
|
|
136
|
-
self.examples_abs_path("guess_game/guess_game4.jac")
|
|
141
|
+
self.examples_abs_path("guess_game/guess_game4.impl.jac")
|
|
137
142
|
)
|
|
138
143
|
lsp.deep_check(guess_game_file)
|
|
139
144
|
self.assertIn(
|
|
140
|
-
"guess_game4.jac:
|
|
141
|
-
str(lsp.get_definition(guess_game_file, lspt.Position(
|
|
145
|
+
"guess_game4.jac:16:8-16:21",
|
|
146
|
+
str(lsp.get_definition(guess_game_file, lspt.Position(14, 45))),
|
|
142
147
|
)
|
|
143
148
|
|
|
144
149
|
def test_go_to_definition_method_manual_impl(self) -> None:
|
jaclang/langserve/utils.jac
CHANGED
|
@@ -24,10 +24,8 @@ import from jaclang.vendor.pygls { uris }
|
|
|
24
24
|
import lsprotocol.types as lspt;
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
T = TypeVar('T', bound=Callable[(P, Coroutine[(Any, Any, Any)])]);
|
|
30
|
-
}
|
|
27
|
+
glob P = ParamSpec('P');
|
|
28
|
+
glob T = TypeVar('T', bound=Callable[(P, Coroutine[(Any, Any, Any)])]);
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
"""Return diagnostics."""
|
|
@@ -36,11 +34,15 @@ def gen_diagnostics(
|
|
|
36
34
|
errors: <>list[Alert],
|
|
37
35
|
warnings: <>list[Alert]
|
|
38
36
|
) -> <>list[lspt.Diagnostic] {
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
return [ lspt.Diagnostic(
|
|
38
|
+
range=create_range(error.loc),
|
|
39
|
+
message=error.msg,
|
|
40
|
+
severity=lspt.DiagnosticSeverity.Error
|
|
41
|
+
) for error in errors if error.loc.mod_path == uris.to_fs_path(from_path) ] + [ lspt.Diagnostic(
|
|
42
|
+
range=create_range(warning.loc),
|
|
43
|
+
message=warning.msg,
|
|
44
|
+
severity=lspt.DiagnosticSeverity.Warning
|
|
45
|
+
) for warning in warnings if warning.loc.mod_path == uris.to_fs_path(from_path) ];
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
|
|
@@ -156,25 +158,31 @@ def get_symbols_for_outline(<>node: UniScopeNode) -> <>list[lspt.DocumentSymbol]
|
|
|
156
158
|
continue;
|
|
157
159
|
}
|
|
158
160
|
pos = create_range(item.decl.loc);
|
|
159
|
-
symbol = lspt.DocumentSymbol(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
symbol = lspt.DocumentSymbol(
|
|
162
|
+
name=key,
|
|
163
|
+
kind=kind_map(item.decl),
|
|
164
|
+
range=pos,
|
|
165
|
+
selection_range=pos,
|
|
166
|
+
children=[]
|
|
167
|
+
);
|
|
164
168
|
symbols.append(symbol);
|
|
165
169
|
}
|
|
166
170
|
for sub_tab in [ i for i in <>node.kid_scope if i.loc.mod_path == <>node.loc.mod_path ] {
|
|
167
171
|
sub_symbols = get_symbols_for_outline(sub_tab);
|
|
168
|
-
if isinstance(
|
|
169
|
-
|
|
172
|
+
if isinstance(
|
|
173
|
+
sub_tab,
|
|
174
|
+
(uni.IfStmt, uni.ElseStmt, uni.WhileStmt, uni.IterForStmt, uni.InForStmt)
|
|
175
|
+
) {
|
|
170
176
|
symbols.extend(sub_symbols);
|
|
171
177
|
} else {
|
|
172
178
|
sub_pos = create_range(sub_tab.loc);
|
|
173
|
-
symbol = lspt.DocumentSymbol(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
symbol = lspt.DocumentSymbol(
|
|
180
|
+
name=sub_tab.scope_name,
|
|
181
|
+
kind=kind_map(sub_tab),
|
|
182
|
+
range=sub_pos,
|
|
183
|
+
selection_range=sub_pos,
|
|
184
|
+
children=sub_symbols
|
|
185
|
+
);
|
|
178
186
|
symbols.append(symbol);
|
|
179
187
|
}
|
|
180
188
|
}
|
|
@@ -193,10 +201,16 @@ def owner_sym(table: UniScopeNode) -> Optional[Symbol] {
|
|
|
193
201
|
|
|
194
202
|
"""Create an lspt.Range from a location object."""
|
|
195
203
|
def create_range(loc: CodeLocInfo) -> lspt.Range {
|
|
196
|
-
return lspt.Range(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
204
|
+
return lspt.Range(
|
|
205
|
+
start=lspt.Position(
|
|
206
|
+
line=(loc.first_line - 1) if loc.first_line > 0 else 0 ,
|
|
207
|
+
character=(loc.col_start - 1) if loc.col_start > 0 else 0
|
|
208
|
+
),
|
|
209
|
+
end=lspt.Position(
|
|
210
|
+
line=(loc.last_line - 1) if loc.last_line > 0 else 0 ,
|
|
211
|
+
character=(loc.col_end - 1) if loc.col_end > 0 else 0
|
|
212
|
+
)
|
|
213
|
+
);
|
|
200
214
|
}
|
|
201
215
|
|
|
202
216
|
|
|
@@ -263,8 +277,9 @@ def collect_all_symbols_in_scope(
|
|
|
263
277
|
visited.add(current_tab);
|
|
264
278
|
for (name, symbol) in current_tab.names_in_scope.items() {
|
|
265
279
|
if name not in dir(builtins) and symbol.sym_type != SymbolType.IMPL {
|
|
266
|
-
symbols.append(
|
|
267
|
-
|
|
280
|
+
symbols.append(
|
|
281
|
+
lspt.CompletionItem(label=name, kind=label_map(symbol.sym_type))
|
|
282
|
+
);
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
if not up_tree {
|
|
@@ -284,8 +299,12 @@ def collect_child_tabs(sym_tab: UniScopeNode) -> <>list[lspt.CompletionItem] {
|
|
|
284
299
|
symbols : <>list[lspt.CompletionItem] = [];
|
|
285
300
|
for tab in sym_tab.kid_scope {
|
|
286
301
|
if tab.scope_name not in [ i.label for i in symbols ] {
|
|
287
|
-
symbols.append(
|
|
288
|
-
|
|
302
|
+
symbols.append(
|
|
303
|
+
lspt.CompletionItem(
|
|
304
|
+
label=tab.scope_name,
|
|
305
|
+
kind=label_map(tab.get_type())
|
|
306
|
+
)
|
|
307
|
+
);
|
|
289
308
|
}
|
|
290
309
|
}
|
|
291
310
|
return symbols;
|
|
@@ -368,7 +387,9 @@ def find_surrounding_tokens(
|
|
|
368
387
|
prev_token_index = None;
|
|
369
388
|
next_token_index = None;
|
|
370
389
|
inside_tok = False;
|
|
371
|
-
for (i, tok) in enumerate(
|
|
390
|
+
for (i, tok) in enumerate(
|
|
391
|
+
[ get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5) ][ 0 : ]
|
|
392
|
+
) {
|
|
372
393
|
if (not (prev_token_index is None or next_token_index is None ))
|
|
373
394
|
and (tok[0] > change_end_line
|
|
374
395
|
or (tok[0] == change_end_line and tok[1] > change_end_char )
|
jaclang/runtimelib/archetype.py
CHANGED
|
@@ -223,7 +223,7 @@ class WalkerAnchor(Anchor):
|
|
|
223
223
|
|
|
224
224
|
archetype: WalkerArchetype
|
|
225
225
|
path: list[NodeAnchor] = field(default_factory=list)
|
|
226
|
-
next: list[NodeAnchor] = field(default_factory=list)
|
|
226
|
+
next: list[NodeAnchor | EdgeAnchor] = field(default_factory=list)
|
|
227
227
|
ignores: list[NodeAnchor] = field(default_factory=list)
|
|
228
228
|
disengaged: bool = False
|
|
229
229
|
|
jaclang/runtimelib/builtin.py
CHANGED
|
@@ -10,10 +10,7 @@ from jaclang.runtimelib.constructs import Archetype, NodeArchetype, Root
|
|
|
10
10
|
from jaclang.runtimelib.machine import JacMachineInterface as Jac
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
# the existing code. Currently it can return the jac graph in both dot and json format.
|
|
15
|
-
# So the name shuouldn't be dotgen but something more generic.
|
|
16
|
-
def dotgen(
|
|
13
|
+
def printgraph(
|
|
17
14
|
node: Optional[NodeArchetype] = None,
|
|
18
15
|
depth: int = -1,
|
|
19
16
|
traverse: bool = False,
|
|
@@ -21,16 +18,17 @@ def dotgen(
|
|
|
21
18
|
bfs: bool = True,
|
|
22
19
|
edge_limit: int = 512,
|
|
23
20
|
node_limit: int = 512,
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
file: Optional[str] = None,
|
|
22
|
+
format: str = "dot",
|
|
26
23
|
) -> str:
|
|
27
|
-
"""Print the
|
|
24
|
+
"""Print the graph in different formats."""
|
|
28
25
|
from jaclang.runtimelib.machine import JacMachineInterface as Jac
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
fmt = format.lower()
|
|
28
|
+
if fmt == "json":
|
|
29
|
+
return _jac_graph_json(file)
|
|
32
30
|
|
|
33
|
-
return Jac.
|
|
31
|
+
return Jac.printgraph(
|
|
34
32
|
edge_type=edge_type,
|
|
35
33
|
node=node or Jac.root(),
|
|
36
34
|
depth=depth,
|
|
@@ -38,7 +36,8 @@ def dotgen(
|
|
|
38
36
|
bfs=bfs,
|
|
39
37
|
edge_limit=edge_limit,
|
|
40
38
|
node_limit=node_limit,
|
|
41
|
-
|
|
39
|
+
file=file,
|
|
40
|
+
format=fmt,
|
|
42
41
|
)
|
|
43
42
|
|
|
44
43
|
|
|
@@ -52,7 +51,7 @@ def jobj(id: str) -> Archetype | None:
|
|
|
52
51
|
return Jac.get_object(id)
|
|
53
52
|
|
|
54
53
|
|
|
55
|
-
def _jac_graph_json() -> str:
|
|
54
|
+
def _jac_graph_json(file: Optional[str] = None) -> str:
|
|
56
55
|
"""Get the graph in json string."""
|
|
57
56
|
processed: list[Root | NodeArchetype] = []
|
|
58
57
|
nodes: list[dict] = []
|
|
@@ -73,20 +72,24 @@ def _jac_graph_json() -> str:
|
|
|
73
72
|
for ref in Jac.refs(end):
|
|
74
73
|
if ref not in processed:
|
|
75
74
|
working_set.append((end, ref))
|
|
76
|
-
|
|
75
|
+
output = json.dumps(
|
|
77
76
|
{
|
|
78
77
|
"version": "1.0",
|
|
79
78
|
"nodes": nodes,
|
|
80
79
|
"edges": edges,
|
|
81
80
|
}
|
|
82
81
|
)
|
|
82
|
+
if file:
|
|
83
|
+
with open(file, "w") as f:
|
|
84
|
+
f.write(output)
|
|
85
|
+
return output
|
|
83
86
|
|
|
84
87
|
|
|
85
88
|
__all__ = [
|
|
86
89
|
"abstractmethod",
|
|
87
90
|
"ClassVar",
|
|
88
91
|
"override",
|
|
89
|
-
"
|
|
92
|
+
"printgraph",
|
|
90
93
|
"jid",
|
|
91
94
|
"jobj",
|
|
92
95
|
]
|
jaclang/runtimelib/importer.py
CHANGED
|
@@ -102,14 +102,34 @@ class ImportReturn:
|
|
|
102
102
|
item = getattr(module, name)
|
|
103
103
|
handle_item_loading(item, alias)
|
|
104
104
|
except AttributeError:
|
|
105
|
+
found = False
|
|
105
106
|
if lang == "jac":
|
|
106
107
|
jac_file_path = (
|
|
107
108
|
os.path.join(module.__path__[0], f"{name}.jac")
|
|
108
109
|
if hasattr(module, "__path__")
|
|
109
110
|
else module.__file__
|
|
110
111
|
)
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
if hasattr(module, "__path__"):
|
|
113
|
+
init_jac = os.path.join(module.__path__[0], "__init__.jac")
|
|
114
|
+
if os.path.isfile(init_jac):
|
|
115
|
+
package_name = module.__name__
|
|
116
|
+
init_mod = self.importer.jac_machine.loaded_modules.get(
|
|
117
|
+
package_name,
|
|
118
|
+
self.load_jac_mod_as_item(
|
|
119
|
+
module=module,
|
|
120
|
+
name="__init__",
|
|
121
|
+
jac_file_path=init_jac,
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
# Attach all public names from __init__.jac to the package module
|
|
125
|
+
for k, v in init_mod.__dict__.items():
|
|
126
|
+
if not k.startswith("_"):
|
|
127
|
+
setattr(module, k, v)
|
|
128
|
+
if hasattr(module, name):
|
|
129
|
+
item = getattr(module, name)
|
|
130
|
+
handle_item_loading(item, alias)
|
|
131
|
+
found = True
|
|
132
|
+
if not found and jac_file_path and os.path.isfile(jac_file_path):
|
|
113
133
|
item = self.load_jac_mod_as_item(
|
|
114
134
|
module=module,
|
|
115
135
|
name=name,
|
|
@@ -144,9 +164,8 @@ class ImportReturn:
|
|
|
144
164
|
jac_file_path,
|
|
145
165
|
),
|
|
146
166
|
)
|
|
147
|
-
codeobj = self.importer.jac_machine.
|
|
148
|
-
full_target=jac_file_path
|
|
149
|
-
full_compile=not self.importer.jac_machine.interp_mode,
|
|
167
|
+
codeobj = self.importer.jac_machine.program.get_bytecode(
|
|
168
|
+
full_target=jac_file_path
|
|
150
169
|
)
|
|
151
170
|
if not codeobj:
|
|
152
171
|
raise ImportError(f"No bytecode found for {jac_file_path}")
|
|
@@ -379,9 +398,8 @@ class JacImporter(Importer):
|
|
|
379
398
|
spec.package_path,
|
|
380
399
|
spec.full_target,
|
|
381
400
|
)
|
|
382
|
-
codeobj = self.jac_machine.
|
|
383
|
-
full_target=spec.full_target
|
|
384
|
-
full_compile=not self.jac_machine.interp_mode,
|
|
401
|
+
codeobj = self.jac_machine.program.get_bytecode(
|
|
402
|
+
full_target=spec.full_target
|
|
385
403
|
)
|
|
386
404
|
|
|
387
405
|
# Since this is a compile time error, we can safely raise an exception here.
|