jaclang 0.8.4__py3-none-any.whl → 0.8.6__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.md +1 -0
- jaclang/cli/cli.py +109 -37
- jaclang/compiler/jac.lark +3 -3
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +14 -21
- jaclang/compiler/passes/main/__init__.py +5 -1
- jaclang/compiler/passes/main/binder_pass.py +594 -0
- jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
- jaclang/compiler/passes/main/import_pass.py +8 -256
- jaclang/compiler/passes/main/inheritance_pass.py +10 -3
- jaclang/compiler/passes/main/pyast_gen_pass.py +92 -77
- jaclang/compiler/passes/main/pyast_load_pass.py +24 -13
- jaclang/compiler/passes/main/sem_def_match_pass.py +1 -1
- jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
- jaclang/compiler/passes/main/tests/fixtures/M1.jac +3 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
- jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
- jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
- jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
- jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
- jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +47 -0
- jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
- jaclang/compiler/passes/main/tests/test_binder_pass.py +111 -0
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
- jaclang/compiler/passes/main/tests/test_checker_pass.py +87 -0
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +13 -13
- jaclang/compiler/passes/main/tests/test_sem_def_match_pass.py +6 -6
- jaclang/compiler/passes/main/type_checker_pass.py +128 -0
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +2 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -0
- jaclang/compiler/program.py +32 -11
- jaclang/compiler/tests/test_sr_errors.py +32 -0
- jaclang/compiler/type_system/__init__.py +1 -0
- jaclang/compiler/type_system/type_evaluator.py +421 -0
- jaclang/compiler/type_system/type_utils.py +41 -0
- jaclang/compiler/type_system/types.py +240 -0
- jaclang/compiler/unitree.py +36 -24
- jaclang/langserve/dev_engine.jac +645 -0
- jaclang/langserve/dev_server.jac +201 -0
- jaclang/langserve/engine.jac +24 -5
- jaclang/langserve/tests/server_test/test_lang_serve.py +2 -2
- jaclang/langserve/tests/test_dev_server.py +80 -0
- jaclang/langserve/tests/test_server.py +13 -0
- jaclang/runtimelib/builtin.py +28 -39
- jaclang/runtimelib/importer.py +34 -63
- jaclang/runtimelib/machine.py +48 -64
- jaclang/runtimelib/memory.py +23 -5
- jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
- jaclang/runtimelib/utils.py +42 -6
- jaclang/tests/fixtures/edge_node_walk.jac +1 -1
- jaclang/tests/fixtures/edges_walk.jac +1 -1
- jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
- jaclang/tests/fixtures/py_run.jac +8 -0
- jaclang/tests/fixtures/py_run.py +23 -0
- jaclang/tests/fixtures/pyfunc.py +2 -0
- jaclang/tests/fixtures/pyfunc_fmt.py +60 -0
- jaclang/tests/fixtures/pyfunc_fstr.py +25 -0
- jaclang/tests/fixtures/pyfunc_kwesc.py +33 -0
- jaclang/tests/fixtures/python_run_test.py +19 -0
- jaclang/tests/test_cli.py +107 -0
- jaclang/tests/test_language.py +106 -5
- jaclang/utils/lang_tools.py +6 -3
- jaclang/utils/module_resolver.py +90 -0
- jaclang/utils/symtable_test_helpers.py +125 -0
- jaclang/utils/test.py +3 -4
- jaclang/vendor/interegular/__init__.py +34 -0
- jaclang/vendor/interegular/comparator.py +163 -0
- jaclang/vendor/interegular/fsm.py +1015 -0
- jaclang/vendor/interegular/patterns.py +732 -0
- jaclang/vendor/interegular/py.typed +0 -0
- jaclang/vendor/interegular/utils/__init__.py +15 -0
- jaclang/vendor/interegular/utils/simple_parser.py +165 -0
- jaclang/vendor/interegular-0.3.3.dist-info/INSTALLER +1 -0
- jaclang/vendor/interegular-0.3.3.dist-info/LICENSE.txt +21 -0
- jaclang/vendor/interegular-0.3.3.dist-info/METADATA +64 -0
- jaclang/vendor/interegular-0.3.3.dist-info/RECORD +20 -0
- jaclang/vendor/interegular-0.3.3.dist-info/REQUESTED +0 -0
- jaclang/vendor/interegular-0.3.3.dist-info/WHEEL +5 -0
- jaclang/vendor/interegular-0.3.3.dist-info/top_level.txt +1 -0
- {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/METADATA +2 -1
- {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/RECORD +88 -43
- {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/WHEEL +0 -0
- {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,201 @@
|
|
|
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 dev_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: JacLangServerV2, 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: JacLangServerV2, params: lspt.DidOpenTextDocumentParams) -> None {
|
|
32
|
+
file_path = params.text_document.uri;
|
|
33
|
+
quick_check_passed = await ls.launch_quick_check(file_path);
|
|
34
|
+
if not quick_check_passed {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
await ls.launch_deep_check(file_path);
|
|
38
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
"""Check syntax on change."""
|
|
43
|
+
@server.feature(lspt.TEXT_DOCUMENT_DID_CHANGE)
|
|
44
|
+
async def did_change(
|
|
45
|
+
ls: JacLangServerV2,
|
|
46
|
+
params: lspt.DidChangeTextDocumentParams
|
|
47
|
+
) -> None {
|
|
48
|
+
file_path = params.text_document.uri;
|
|
49
|
+
quick_check_passed = await ls.launch_quick_check(file_path);
|
|
50
|
+
|
|
51
|
+
if quick_check_passed {
|
|
52
|
+
document = ls.workspace.get_text_document(file_path);
|
|
53
|
+
lines = document.source.splitlines();
|
|
54
|
+
sem_manager = ls.sem_managers[file_path.removeprefix('file://')];
|
|
55
|
+
sem_manager.update_sem_tokens(
|
|
56
|
+
params,sem_manager.sem_tokens,lines
|
|
57
|
+
);
|
|
58
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
59
|
+
await ls.launch_deep_check(file_path);
|
|
60
|
+
ls.lsp.send_request(lspt.WORKSPACE_SEMANTIC_TOKENS_REFRESH);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
"""Format the given document."""
|
|
66
|
+
@server.feature(lspt.TEXT_DOCUMENT_FORMATTING)
|
|
67
|
+
def formatting(
|
|
68
|
+
ls: JacLangServerV2,
|
|
69
|
+
params: lspt.DocumentFormattingParams
|
|
70
|
+
) -> list[lspt.TextEdit] {
|
|
71
|
+
return ls.formatted_jac(params.text_document.uri);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
"""Check syntax on file creation."""
|
|
76
|
+
@server.feature(
|
|
77
|
+
lspt.WORKSPACE_DID_CREATE_FILES,
|
|
78
|
+
lspt.FileOperationRegistrationOptions(
|
|
79
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
def did_create_files(ls: JacLangServerV2, params: lspt.CreateFilesParams) -> None {}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
"""Check syntax on file rename."""
|
|
86
|
+
@server.feature(
|
|
87
|
+
lspt.WORKSPACE_DID_RENAME_FILES,
|
|
88
|
+
lspt.FileOperationRegistrationOptions(
|
|
89
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
def did_rename_files(ls: JacLangServerV2, params: lspt.RenameFilesParams) -> None {
|
|
93
|
+
new_uris = [ file.new_uri for file in params.files ];
|
|
94
|
+
old_uris = [ file.old_uri for file in params.files ];
|
|
95
|
+
for i in range(len(new_uris)) {
|
|
96
|
+
ls.rename_module(old_uris[i], new_uris[i]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
"""Check syntax on file delete."""
|
|
102
|
+
@server.feature(
|
|
103
|
+
lspt.WORKSPACE_DID_DELETE_FILES,
|
|
104
|
+
lspt.FileOperationRegistrationOptions(
|
|
105
|
+
filters=[lspt.FileOperationFilter(pattern=lspt.FileOperationPattern('**/*.jac'))]
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
def did_delete_files(ls: JacLangServerV2, params: lspt.DeleteFilesParams) -> None {
|
|
109
|
+
for file in params.files {
|
|
110
|
+
ls.delete_module(file.uri);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
"""Provide completion."""
|
|
116
|
+
@server.feature(
|
|
117
|
+
lspt.TEXT_DOCUMENT_COMPLETION,
|
|
118
|
+
lspt.CompletionOptions(trigger_characters=['.', ':', 'a-zA-Z0-9'])
|
|
119
|
+
)
|
|
120
|
+
def completion(ls: JacLangServerV2, params: lspt.CompletionParams) -> lspt.CompletionList {
|
|
121
|
+
return ls.get_completion(
|
|
122
|
+
params.text_document.uri,
|
|
123
|
+
params.position,
|
|
124
|
+
params.context.trigger_character if params.context else None
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
"""Provide hover information for the given hover request."""
|
|
130
|
+
@server.feature(lspt.TEXT_DOCUMENT_HOVER, lspt.HoverOptions(work_done_progress=True))
|
|
131
|
+
def hover(
|
|
132
|
+
ls: JacLangServerV2,
|
|
133
|
+
params: lspt.TextDocumentPositionParams
|
|
134
|
+
) -> Optional[lspt.Hover] {
|
|
135
|
+
return ls.get_hover_info(params.text_document.uri, params.position);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
"""Provide document symbols."""
|
|
140
|
+
@server.feature(lspt.TEXT_DOCUMENT_DOCUMENT_SYMBOL)
|
|
141
|
+
def document_symbol(
|
|
142
|
+
ls: JacLangServerV2,
|
|
143
|
+
params: lspt.DocumentSymbolParams
|
|
144
|
+
) -> list[lspt.DocumentSymbol] {
|
|
145
|
+
return ls.get_outline(params.text_document.uri);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
"""Provide definition."""
|
|
150
|
+
@server.feature(lspt.TEXT_DOCUMENT_DEFINITION)
|
|
151
|
+
def definition(
|
|
152
|
+
ls: JacLangServerV2,
|
|
153
|
+
params: lspt.TextDocumentPositionParams
|
|
154
|
+
) -> Optional[lspt.Location] {
|
|
155
|
+
return ls.get_definition(params.text_document.uri, params.position);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
"""Provide references."""
|
|
160
|
+
@server.feature(lspt.TEXT_DOCUMENT_REFERENCES)
|
|
161
|
+
def references(ls: JacLangServerV2, params: lspt.ReferenceParams) -> list[lspt.Location] {
|
|
162
|
+
return ls.get_references(params.text_document.uri, params.position);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
"""Rename symbol."""
|
|
167
|
+
@server.feature(lspt.TEXT_DOCUMENT_RENAME)
|
|
168
|
+
def rename(ls: JacLangServerV2, params: lspt.RenameParams) -> Optional[lspt.WorkspaceEdit] {
|
|
169
|
+
ls.log_warning('Auto Rename is Experimental, Please use with caution.');
|
|
170
|
+
return ls.rename_symbol(params.text_document.uri, params.position, params.new_name);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
"""Provide semantic tokens."""
|
|
175
|
+
@server.feature(
|
|
176
|
+
lspt.TEXT_DOCUMENT_SEMANTIC_TOKENS_FULL,
|
|
177
|
+
lspt.SemanticTokensLegend(
|
|
178
|
+
token_types=SemTokType.as_str_list(),
|
|
179
|
+
token_modifiers=SemTokMod.as_str_list()
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
def semantic_tokens_full(
|
|
183
|
+
ls: JacLangServerV2,
|
|
184
|
+
params: lspt.SemanticTokensParams
|
|
185
|
+
) -> lspt.SemanticTokens {
|
|
186
|
+
return ls.get_semantic_tokens(params.text_document.uri);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
"""Run the language server."""
|
|
191
|
+
def run_lang_server() -> None {
|
|
192
|
+
settings.pass_timer = True;
|
|
193
|
+
server.start_io();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
with entry {
|
|
198
|
+
if __name__ == '__main__' {
|
|
199
|
+
run_lang_server();
|
|
200
|
+
}
|
|
201
|
+
}
|
jaclang/langserve/engine.jac
CHANGED
|
@@ -8,6 +8,7 @@ import from typing { Callable, Optional }
|
|
|
8
8
|
|
|
9
9
|
import jaclang.compiler.unitree as uni;
|
|
10
10
|
import from jaclang { JacMachineInterface as Jac }
|
|
11
|
+
import from jaclang.compiler.constant {SymbolType}
|
|
11
12
|
import from jaclang.compiler.program { JacProgram }
|
|
12
13
|
import from jaclang.compiler.unitree { UniScopeNode }
|
|
13
14
|
import from sem_manager { SemTokManager }
|
|
@@ -133,7 +134,7 @@ class JacLangServer(JacProgram , LanguageServer) {
|
|
|
133
134
|
file_path_fs = file_path.removeprefix('file://');
|
|
134
135
|
document = self.workspace.get_text_document(file_path);
|
|
135
136
|
self._clear_alerts_for_file(file_path_fs);
|
|
136
|
-
build = self.build(use_str=document.source, file_path=document.path);
|
|
137
|
+
build = self.build(use_str=document.source, file_path=document.path,type_check=True);
|
|
137
138
|
self.update_modules(file_path_fs, build);
|
|
138
139
|
if build.annexable_by {
|
|
139
140
|
return self.deep_check(
|
|
@@ -259,7 +260,7 @@ class JacLangServer(JacProgram , LanguageServer) {
|
|
|
259
260
|
}
|
|
260
261
|
symb = temp_tab.lookup(symbol);
|
|
261
262
|
if symb {
|
|
262
|
-
fetc_tab = symb.
|
|
263
|
+
fetc_tab = symb.symbol_table;
|
|
263
264
|
if fetc_tab {
|
|
264
265
|
temp_tab = fetc_tab;
|
|
265
266
|
} else {
|
|
@@ -284,9 +285,9 @@ class JacLangServer(JacProgram , LanguageServer) {
|
|
|
284
285
|
}
|
|
285
286
|
}
|
|
286
287
|
for base_class_symbol in base {
|
|
287
|
-
if base_class_symbol.
|
|
288
|
+
if base_class_symbol.symbol_table {
|
|
288
289
|
completion_items += utils.collect_all_symbols_in_scope(
|
|
289
|
-
base_class_symbol.
|
|
290
|
+
base_class_symbol.symbol_table,
|
|
290
291
|
up_tree=False
|
|
291
292
|
);
|
|
292
293
|
}
|
|
@@ -446,7 +447,25 @@ class JacLangServer(JacProgram , LanguageServer) {
|
|
|
446
447
|
}
|
|
447
448
|
node_selected = sem_mgr.static_sem_tokens[token_index][3];
|
|
448
449
|
if node_selected {
|
|
449
|
-
if
|
|
450
|
+
if (node_selected.sym.sym_type == SymbolType.MODULE) {
|
|
451
|
+
spec = node_selected.sym.decl.parent.resolve_relative_path();
|
|
452
|
+
if spec {
|
|
453
|
+
spec = spec[ 5 : ] if spec.startswith('File:') else spec;
|
|
454
|
+
return lspt.Location(
|
|
455
|
+
uri=uris.from_fs_path(spec),
|
|
456
|
+
range=lspt.Range(
|
|
457
|
+
start=lspt.Position(line=0, character=0),
|
|
458
|
+
end=lspt.Position(line=0, character=0)
|
|
459
|
+
)
|
|
460
|
+
);
|
|
461
|
+
} else {
|
|
462
|
+
return None;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
if isinstance(node_selected.sym, uni.NameAtom) {
|
|
466
|
+
node_selected = node_selected.name_of;
|
|
467
|
+
}
|
|
468
|
+
elif isinstance(node_selected, uni.Name)
|
|
450
469
|
and node_selected.parent
|
|
451
470
|
and isinstance(node_selected.parent, uni.ModulePath)
|
|
452
471
|
{
|
|
@@ -190,7 +190,7 @@ class TestLangServe:
|
|
|
190
190
|
await did_save(ls, params)
|
|
191
191
|
sem_tokens = ls.get_semantic_tokens(uri)
|
|
192
192
|
# semantic tokens should still be present even if there is a syntax error
|
|
193
|
-
assert len(sem_tokens.data) ==
|
|
193
|
+
assert len(sem_tokens.data) == 320
|
|
194
194
|
diagnostics = ls.diagnostics.get(uri, [])
|
|
195
195
|
assert isinstance(diagnostics, list)
|
|
196
196
|
assert len(diagnostics) == 1
|
|
@@ -254,7 +254,7 @@ class TestLangServe:
|
|
|
254
254
|
await did_change(ls, params)
|
|
255
255
|
sem_tokens = ls.get_semantic_tokens(uri)
|
|
256
256
|
# semantic tokens should still be present even if there is a syntax error
|
|
257
|
-
assert len(sem_tokens.data) ==
|
|
257
|
+
assert len(sem_tokens.data) == 320
|
|
258
258
|
diagnostics = ls.diagnostics.get(uri, [])
|
|
259
259
|
assert isinstance(diagnostics, list)
|
|
260
260
|
assert len(diagnostics) == 1
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from jaclang.utils.test import TestCase
|
|
2
|
+
from jaclang.vendor.pygls import uris
|
|
3
|
+
from jaclang.vendor.pygls.workspace import Workspace
|
|
4
|
+
|
|
5
|
+
import lsprotocol.types as lspt
|
|
6
|
+
from jaclang.langserve.dev_engine import JacLangServer
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestJacLangServer(TestCase):
|
|
10
|
+
|
|
11
|
+
def test_type_annotation_assignment_server(self) -> None:
|
|
12
|
+
"""Test that the server doesn't run if there is a syntax error."""
|
|
13
|
+
lsp = JacLangServer()
|
|
14
|
+
workspace_path = self.fixture_abs_path("")
|
|
15
|
+
workspace = Workspace(workspace_path, lsp)
|
|
16
|
+
lsp.lsp._workspace = workspace
|
|
17
|
+
circle_file = uris.from_fs_path(
|
|
18
|
+
self.fixture_abs_path(
|
|
19
|
+
"../../../../jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac"
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
lsp.deep_check(circle_file)
|
|
23
|
+
self.assertIn(
|
|
24
|
+
"(public variable) should_fail1: int",
|
|
25
|
+
lsp.get_hover_info(circle_file, lspt.Position(1, 15)).contents.value,
|
|
26
|
+
)
|
|
27
|
+
self.assertIn(
|
|
28
|
+
"(public variable) should_pass2: str",
|
|
29
|
+
lsp.get_hover_info(circle_file, lspt.Position(2, 15)).contents.value,
|
|
30
|
+
)
|
|
31
|
+
self.assertIn(
|
|
32
|
+
"(public variable) should_fail2: str",
|
|
33
|
+
lsp.get_hover_info(circle_file, lspt.Position(3, 15)).contents.value,
|
|
34
|
+
)
|
|
35
|
+
diagnostics_list = list(lsp.diagnostics.values())[0]
|
|
36
|
+
self.assertEqual(len(diagnostics_list), 2)
|
|
37
|
+
self.assertIn(
|
|
38
|
+
"Cannot assign",
|
|
39
|
+
diagnostics_list[0].message,
|
|
40
|
+
)
|
|
41
|
+
self.assertEqual(
|
|
42
|
+
"1:5-1:30",
|
|
43
|
+
str(diagnostics_list[0].range),
|
|
44
|
+
)
|
|
45
|
+
self.assertEqual(
|
|
46
|
+
"3:5-3:27",
|
|
47
|
+
str(diagnostics_list[1].range),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_member_access_type_inferred_server(self) -> None:
|
|
52
|
+
"""Test that the server doesn't run if there is a syntax error."""
|
|
53
|
+
lsp = JacLangServer()
|
|
54
|
+
workspace_path = self.fixture_abs_path("")
|
|
55
|
+
workspace = Workspace(workspace_path, lsp)
|
|
56
|
+
lsp.lsp._workspace = workspace
|
|
57
|
+
circle_file = uris.from_fs_path(
|
|
58
|
+
self.fixture_abs_path(
|
|
59
|
+
"../../../../jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac"
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
lsp.deep_check(circle_file)
|
|
63
|
+
self.assertIn(
|
|
64
|
+
"(public variable) i: int",
|
|
65
|
+
lsp.get_hover_info(circle_file, lspt.Position(10, 2)).contents.value,
|
|
66
|
+
)
|
|
67
|
+
self.assertIn(
|
|
68
|
+
"(public variable) s: str",
|
|
69
|
+
lsp.get_hover_info(circle_file, lspt.Position(11, 2)).contents.value,
|
|
70
|
+
)
|
|
71
|
+
diagnostics_list = list(lsp.diagnostics.values())[0]
|
|
72
|
+
self.assertEqual(len(diagnostics_list), 1)
|
|
73
|
+
self.assertIn(
|
|
74
|
+
"Cannot assign",
|
|
75
|
+
diagnostics_list[0].message,
|
|
76
|
+
)
|
|
77
|
+
self.assertEqual(
|
|
78
|
+
"11:2-11:12",
|
|
79
|
+
str(diagnostics_list[0].range),
|
|
80
|
+
)
|
|
@@ -588,3 +588,16 @@ class TestJacLangServer(TestCase):
|
|
|
588
588
|
)
|
|
589
589
|
for expected in expected_refs:
|
|
590
590
|
self.assertIn(expected, references)
|
|
591
|
+
|
|
592
|
+
def test_binder_go_to_module(self) -> None:
|
|
593
|
+
"""Test that the go to definition is correct."""
|
|
594
|
+
lsp = JacLangServer()
|
|
595
|
+
workspace_path = self.fixture_abs_path("")
|
|
596
|
+
workspace = Workspace(workspace_path, lsp)
|
|
597
|
+
lsp.lsp._workspace = workspace
|
|
598
|
+
guess_game_file = uris.from_fs_path(self.fixture_abs_path('../../../compiler/passes/main/tests/fixtures/sym_binder.jac'))
|
|
599
|
+
lsp.deep_check(guess_game_file)
|
|
600
|
+
self.assertIn(
|
|
601
|
+
"/tests/fixtures/M1.jac:0:0-0:0",
|
|
602
|
+
str(lsp.get_definition(guess_game_file, lspt.Position(29, 9))),
|
|
603
|
+
)
|
jaclang/runtimelib/builtin.py
CHANGED
|
@@ -7,8 +7,9 @@ from abc import abstractmethod
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from typing import ClassVar, Optional, override
|
|
9
9
|
|
|
10
|
-
from jaclang.runtimelib.constructs import
|
|
10
|
+
from jaclang.runtimelib.constructs import NodeArchetype
|
|
11
11
|
from jaclang.runtimelib.machine import JacMachineInterface as Jac
|
|
12
|
+
from jaclang.runtimelib.utils import collect_node_connections
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class AccessLevelEnum(Enum):
|
|
@@ -58,53 +59,39 @@ def printgraph(
|
|
|
58
59
|
)
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return Jac.get_object(id)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def grant(obj: Archetype, level: AccessLevelEnum) -> None:
|
|
72
|
-
"""Grant permission for the object."""
|
|
73
|
-
assert isinstance(level, AccessLevelEnum), f'Use {ConnectPerm} instead of "CONNECT"'
|
|
74
|
-
Jac.perm_grant(obj, level=level.value)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def revoke(obj: Archetype) -> None:
|
|
78
|
-
"""Revoke permission for the object."""
|
|
79
|
-
Jac.perm_revoke(obj)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def allroots() -> list[Jac.Root]:
|
|
83
|
-
"""Get all the roots."""
|
|
84
|
-
return Jac.get_all_root()
|
|
62
|
+
jid = Jac.object_ref
|
|
63
|
+
jobj = Jac.get_object
|
|
64
|
+
grant = Jac.perm_grant
|
|
65
|
+
revoke = Jac.perm_revoke
|
|
66
|
+
allroots = Jac.get_all_root
|
|
67
|
+
save = Jac.save
|
|
68
|
+
commit = Jac.commit
|
|
85
69
|
|
|
86
70
|
|
|
87
71
|
def _jac_graph_json(file: Optional[str] = None) -> str:
|
|
88
72
|
"""Get the graph in json string."""
|
|
89
|
-
|
|
73
|
+
visited_nodes: set = set()
|
|
74
|
+
connections: set = set()
|
|
75
|
+
edge_ids: set = set()
|
|
90
76
|
nodes: list[dict] = []
|
|
91
77
|
edges: list[dict] = []
|
|
92
|
-
working_set: list[tuple] = []
|
|
93
|
-
|
|
94
78
|
root = Jac.root()
|
|
79
|
+
|
|
80
|
+
collect_node_connections(root, visited_nodes, connections, edge_ids)
|
|
81
|
+
|
|
82
|
+
# Create nodes list from visited nodes
|
|
95
83
|
nodes.append({"id": id(root), "label": "root"})
|
|
84
|
+
for node_arch in visited_nodes:
|
|
85
|
+
if node_arch != root:
|
|
86
|
+
nodes.append({"id": id(node_arch), "label": repr(node_arch)})
|
|
87
|
+
|
|
88
|
+
# Create edges list with labels from connections
|
|
89
|
+
for _, source_node, target_node, edge_arch in connections:
|
|
90
|
+
edge_data = {"from": str(id(source_node)), "to": str(id(target_node))}
|
|
91
|
+
if repr(edge_arch) != "GenericEdge()":
|
|
92
|
+
edge_data["label"] = repr(edge_arch)
|
|
93
|
+
edges.append(edge_data)
|
|
96
94
|
|
|
97
|
-
processed.append(root)
|
|
98
|
-
working_set = [(root, ref) for ref in Jac.refs(root)]
|
|
99
|
-
|
|
100
|
-
while working_set:
|
|
101
|
-
start, end = working_set.pop(0)
|
|
102
|
-
edges.append({"from": id(start), "to": id(end)})
|
|
103
|
-
nodes.append({"id": id(end), "label": repr(end)})
|
|
104
|
-
processed.append(end)
|
|
105
|
-
for ref in Jac.refs(end):
|
|
106
|
-
if ref not in processed:
|
|
107
|
-
working_set.append((end, ref))
|
|
108
95
|
output = json.dumps(
|
|
109
96
|
{
|
|
110
97
|
"version": "1.0",
|
|
@@ -128,6 +115,8 @@ __all__ = [
|
|
|
128
115
|
"grant",
|
|
129
116
|
"revoke",
|
|
130
117
|
"allroots",
|
|
118
|
+
"save",
|
|
119
|
+
"commit",
|
|
131
120
|
"NoPerm",
|
|
132
121
|
"ReadPerm",
|
|
133
122
|
"ConnectPerm",
|
jaclang/runtimelib/importer.py
CHANGED
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import importlib
|
|
6
|
-
import importlib.util
|
|
7
5
|
import os
|
|
8
|
-
import sys
|
|
9
6
|
import types
|
|
10
7
|
from os import getcwd, path
|
|
11
8
|
from typing import Optional, Union
|
|
@@ -146,69 +143,43 @@ class Importer:
|
|
|
146
143
|
|
|
147
144
|
|
|
148
145
|
class PythonImporter(Importer):
|
|
149
|
-
"""Importer for Python modules."""
|
|
146
|
+
"""Importer for Python modules using Jac AST conversion."""
|
|
147
|
+
|
|
148
|
+
def __init__(self) -> None:
|
|
149
|
+
"""Initialize the Python importer."""
|
|
150
|
+
super().__init__()
|
|
151
|
+
from jaclang.utils.module_resolver import PythonModuleResolver
|
|
152
|
+
|
|
153
|
+
self.resolver = PythonModuleResolver()
|
|
154
|
+
|
|
155
|
+
def load_and_execute(self, file_path: str) -> types.ModuleType:
|
|
156
|
+
"""Convert Python file to Jac AST and create module."""
|
|
157
|
+
module_name = os.path.splitext(os.path.basename(file_path))[0]
|
|
158
|
+
module = types.ModuleType(module_name)
|
|
159
|
+
module.__file__ = file_path
|
|
160
|
+
module.__name__ = "__main__"
|
|
161
|
+
|
|
162
|
+
from jaclang.runtimelib.machine import JacMachine
|
|
163
|
+
|
|
164
|
+
codeobj = JacMachine.program.get_bytecode(full_target=file_path)
|
|
165
|
+
if codeobj:
|
|
166
|
+
exec(codeobj, module.__dict__)
|
|
167
|
+
else:
|
|
168
|
+
raise ImportError(f"Failed to generate bytecode for {file_path}")
|
|
169
|
+
|
|
170
|
+
return module
|
|
150
171
|
|
|
151
172
|
def run_import(self, spec: ImportPathSpec) -> ImportReturn:
|
|
152
|
-
"""Run the import process for Python modules."""
|
|
173
|
+
"""Run the import process for Python modules using Jac AST."""
|
|
153
174
|
try:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
imp_spec = importlib.util.spec_from_file_location(
|
|
161
|
-
spec.target, full_target + ".py"
|
|
162
|
-
)
|
|
163
|
-
if imp_spec and imp_spec.loader:
|
|
164
|
-
imported_module = importlib.util.module_from_spec(imp_spec)
|
|
165
|
-
sys.modules[imp_spec.name] = imported_module
|
|
166
|
-
imp_spec.loader.exec_module(imported_module)
|
|
167
|
-
else:
|
|
168
|
-
raise ImportError(
|
|
169
|
-
f"Cannot find module {spec.target} at {full_target}"
|
|
170
|
-
)
|
|
171
|
-
else:
|
|
172
|
-
imported_module = importlib.import_module(name=spec.target)
|
|
173
|
-
|
|
174
|
-
main_module = __import__("__main__")
|
|
175
|
-
if spec.absorb:
|
|
176
|
-
for name in dir(imported_module):
|
|
177
|
-
if not name.startswith("_"):
|
|
178
|
-
setattr(main_module, name, getattr(imported_module, name))
|
|
179
|
-
|
|
180
|
-
elif spec.items:
|
|
181
|
-
for name, alias in spec.items.items():
|
|
182
|
-
if isinstance(alias, bool):
|
|
183
|
-
alias = name
|
|
184
|
-
try:
|
|
185
|
-
item = getattr(imported_module, name)
|
|
186
|
-
if item not in loaded_items:
|
|
187
|
-
setattr(
|
|
188
|
-
main_module,
|
|
189
|
-
alias if isinstance(alias, str) else name,
|
|
190
|
-
item,
|
|
191
|
-
)
|
|
192
|
-
loaded_items.append(item)
|
|
193
|
-
except AttributeError as e:
|
|
194
|
-
if hasattr(imported_module, "__path__"):
|
|
195
|
-
item = importlib.import_module(f"{spec.target}.{name}")
|
|
196
|
-
if item not in loaded_items:
|
|
197
|
-
setattr(
|
|
198
|
-
main_module,
|
|
199
|
-
alias if isinstance(alias, str) else name,
|
|
200
|
-
item,
|
|
201
|
-
)
|
|
202
|
-
loaded_items.append(item)
|
|
203
|
-
else:
|
|
204
|
-
raise e
|
|
175
|
+
python_file_path = self.resolver.resolve_module_path(
|
|
176
|
+
target=spec.target,
|
|
177
|
+
base_path=spec.base_path,
|
|
178
|
+
)
|
|
179
|
+
imported_module = self.load_and_execute(python_file_path)
|
|
180
|
+
# JacMachineInterface.load_module(imported_module.__name__, imported_module)
|
|
205
181
|
|
|
206
|
-
|
|
207
|
-
setattr(
|
|
208
|
-
__import__("__main__"),
|
|
209
|
-
spec.mdl_alias if isinstance(spec.mdl_alias, str) else spec.target,
|
|
210
|
-
imported_module,
|
|
211
|
-
)
|
|
182
|
+
loaded_items: list = []
|
|
212
183
|
self.result = ImportReturn(imported_module, loaded_items, self)
|
|
213
184
|
return self.result
|
|
214
185
|
|
|
@@ -351,7 +322,7 @@ class JacImporter(Importer):
|
|
|
351
322
|
if os.path.isdir(spec.full_target):
|
|
352
323
|
module = self.handle_directory(spec.module_name, spec.full_target)
|
|
353
324
|
else:
|
|
354
|
-
spec.full_target += ".jac" if spec.language
|
|
325
|
+
spec.full_target += ".jac" if spec.language in ["jac", "jir"] else ".py"
|
|
355
326
|
module = self.create_jac_py_module(
|
|
356
327
|
module_name,
|
|
357
328
|
spec.package_path,
|