jaclang 0.8.5__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 +38 -18
- jaclang/compiler/passes/main/__init__.py +2 -0
- jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
- jaclang/compiler/passes/main/inheritance_pass.py +8 -1
- jaclang/compiler/passes/main/pyast_gen_pass.py +57 -8
- jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -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/type_annotation_assignment.jac +8 -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/type_checker_pass.py +128 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +1 -4
- jaclang/compiler/program.py +17 -3
- 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 +15 -9
- jaclang/langserve/dev_engine.jac +645 -0
- jaclang/langserve/dev_server.jac +201 -0
- jaclang/langserve/engine.jac +1 -1
- jaclang/langserve/tests/server_test/test_lang_serve.py +2 -2
- jaclang/langserve/tests/test_dev_server.py +80 -0
- jaclang/runtimelib/builtin.py +28 -39
- jaclang/runtimelib/importer.py +1 -1
- 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 +13 -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/test_cli.py +40 -0
- jaclang/tests/test_language.py +10 -4
- jaclang/utils/lang_tools.py +3 -0
- {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/METADATA +2 -1
- {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/RECORD +52 -31
- {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/WHEEL +0 -0
- {jaclang-0.8.5.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
|
@@ -134,7 +134,7 @@ class JacLangServer(JacProgram , LanguageServer) {
|
|
|
134
134
|
file_path_fs = file_path.removeprefix('file://');
|
|
135
135
|
document = self.workspace.get_text_document(file_path);
|
|
136
136
|
self._clear_alerts_for_file(file_path_fs);
|
|
137
|
-
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);
|
|
138
138
|
self.update_modules(file_path_fs, build);
|
|
139
139
|
if build.annexable_by {
|
|
140
140
|
return self.deep_check(
|
|
@@ -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
|
+
)
|
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
|
@@ -322,7 +322,7 @@ class JacImporter(Importer):
|
|
|
322
322
|
if os.path.isdir(spec.full_target):
|
|
323
323
|
module = self.handle_directory(spec.module_name, spec.full_target)
|
|
324
324
|
else:
|
|
325
|
-
spec.full_target += ".jac" if spec.language
|
|
325
|
+
spec.full_target += ".jac" if spec.language in ["jac", "jir"] else ".py"
|
|
326
326
|
module = self.create_jac_py_module(
|
|
327
327
|
module_name,
|
|
328
328
|
spec.package_path,
|
jaclang/runtimelib/machine.py
CHANGED
|
@@ -57,7 +57,6 @@ from jaclang.runtimelib.constructs import (
|
|
|
57
57
|
from jaclang.runtimelib.memory import Memory, Shelf, ShelfStorage
|
|
58
58
|
from jaclang.runtimelib.utils import (
|
|
59
59
|
all_issubclass,
|
|
60
|
-
collect_node_connections,
|
|
61
60
|
traverse_graph,
|
|
62
61
|
)
|
|
63
62
|
from jaclang.utils import infer_language
|
|
@@ -266,30 +265,6 @@ class JacAccessValidation:
|
|
|
266
265
|
class JacNode:
|
|
267
266
|
"""Jac Node Operations."""
|
|
268
267
|
|
|
269
|
-
@staticmethod
|
|
270
|
-
def node_dot(node: NodeArchetype, dot_file: Optional[str] = None) -> str:
|
|
271
|
-
"""Generate Dot file for visualizing nodes and edges."""
|
|
272
|
-
visited_nodes: set[NodeAnchor] = set()
|
|
273
|
-
connections: set[tuple[NodeArchetype, NodeArchetype, str]] = set()
|
|
274
|
-
unique_node_id_dict = {}
|
|
275
|
-
|
|
276
|
-
collect_node_connections(node.__jac__, visited_nodes, connections)
|
|
277
|
-
dot_content = 'digraph {\nnode [style="filled", shape="ellipse", fillcolor="invis", fontcolor="black"];\n'
|
|
278
|
-
for idx, i in enumerate([nodes_.archetype for nodes_ in visited_nodes]):
|
|
279
|
-
unique_node_id_dict[i] = (i.__class__.__name__, str(idx))
|
|
280
|
-
dot_content += f'{idx} [label="{i}"];\n'
|
|
281
|
-
dot_content += 'edge [color="gray", style="solid"];\n'
|
|
282
|
-
|
|
283
|
-
for pair in list(set(connections)):
|
|
284
|
-
dot_content += (
|
|
285
|
-
f"{unique_node_id_dict[pair[0]][1]} -> {unique_node_id_dict[pair[1]][1]}"
|
|
286
|
-
f' [label="{pair[2]}"];\n'
|
|
287
|
-
)
|
|
288
|
-
if dot_file:
|
|
289
|
-
with open(dot_file, "w") as f:
|
|
290
|
-
f.write(dot_content + "}")
|
|
291
|
-
return dot_content + "}"
|
|
292
|
-
|
|
293
268
|
@staticmethod
|
|
294
269
|
def get_edges(
|
|
295
270
|
origin: list[NodeArchetype], destination: DataSpatialDestination
|
|
@@ -879,6 +854,15 @@ class JacBasics:
|
|
|
879
854
|
"""Get current execution context."""
|
|
880
855
|
return JacMachine.exec_ctx
|
|
881
856
|
|
|
857
|
+
@staticmethod
|
|
858
|
+
def commit(anchor: Anchor | Archetype | None = None) -> None:
|
|
859
|
+
"""Commit all data from memory to datasource."""
|
|
860
|
+
if isinstance(anchor, Archetype):
|
|
861
|
+
anchor = anchor.__jac__
|
|
862
|
+
|
|
863
|
+
mem = JacMachineInterface.get_context().mem
|
|
864
|
+
mem.commit(anchor)
|
|
865
|
+
|
|
882
866
|
@staticmethod
|
|
883
867
|
def reset_graph(root: Optional[Root] = None) -> int:
|
|
884
868
|
"""Purge current or target graph."""
|
|
@@ -987,6 +971,7 @@ class JacBasics:
|
|
|
987
971
|
override_name: Optional[str] = None,
|
|
988
972
|
items: Optional[dict[str, Union[str, Optional[str]]]] = None,
|
|
989
973
|
reload_module: Optional[bool] = False,
|
|
974
|
+
lng: Optional[str] = None,
|
|
990
975
|
) -> tuple[types.ModuleType, ...]:
|
|
991
976
|
"""Core Import Process."""
|
|
992
977
|
from jaclang.runtimelib.importer import (
|
|
@@ -995,7 +980,8 @@ class JacBasics:
|
|
|
995
980
|
PythonImporter,
|
|
996
981
|
)
|
|
997
982
|
|
|
998
|
-
lng
|
|
983
|
+
if lng is None:
|
|
984
|
+
lng = infer_language(target, base_path)
|
|
999
985
|
|
|
1000
986
|
spec = ImportPathSpec(
|
|
1001
987
|
target,
|
|
@@ -1358,12 +1344,10 @@ class JacBasics:
|
|
|
1358
1344
|
return decorator
|
|
1359
1345
|
|
|
1360
1346
|
@staticmethod
|
|
1361
|
-
def call_llm(
|
|
1362
|
-
model: object, caller: Callable, args: dict[str | int, object]
|
|
1363
|
-
) -> Any: # noqa: ANN401
|
|
1347
|
+
def call_llm(model: object, mtir: object) -> Any: # noqa: ANN401
|
|
1364
1348
|
"""Call the LLM model."""
|
|
1365
1349
|
raise ImportError(
|
|
1366
|
-
"
|
|
1350
|
+
"byLLM is not installed. Please install it with `pip install byllm` and run `jac clean`."
|
|
1367
1351
|
)
|
|
1368
1352
|
|
|
1369
1353
|
|
|
@@ -1587,40 +1571,6 @@ class JacMachineInterface(
|
|
|
1587
1571
|
"""Jac Feature."""
|
|
1588
1572
|
|
|
1589
1573
|
|
|
1590
|
-
class JacMachine(JacMachineInterface):
|
|
1591
|
-
"""Jac Machine State."""
|
|
1592
|
-
|
|
1593
|
-
loaded_modules: dict[str, types.ModuleType] = {}
|
|
1594
|
-
base_path_dir: str = os.getcwd()
|
|
1595
|
-
program: JacProgram = JacProgram()
|
|
1596
|
-
pool: ThreadPoolExecutor = ThreadPoolExecutor()
|
|
1597
|
-
exec_ctx: ExecutionContext = ExecutionContext()
|
|
1598
|
-
|
|
1599
|
-
@staticmethod
|
|
1600
|
-
def set_base_path(base_path: str) -> None:
|
|
1601
|
-
"""Set the base path for the machine."""
|
|
1602
|
-
JacMachine.reset_machine()
|
|
1603
|
-
JacMachine.base_path_dir = (
|
|
1604
|
-
base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
|
|
1605
|
-
)
|
|
1606
|
-
|
|
1607
|
-
@staticmethod
|
|
1608
|
-
def set_context(context: ExecutionContext) -> None:
|
|
1609
|
-
"""Set the context for the machine."""
|
|
1610
|
-
JacMachine.exec_ctx = context
|
|
1611
|
-
|
|
1612
|
-
@staticmethod
|
|
1613
|
-
def reset_machine() -> None:
|
|
1614
|
-
"""Reset the machine."""
|
|
1615
|
-
# for i in JacMachine.loaded_modules.values():
|
|
1616
|
-
# sys.modules.pop(i.__name__, None)
|
|
1617
|
-
JacMachine.loaded_modules.clear()
|
|
1618
|
-
JacMachine.base_path_dir = os.getcwd()
|
|
1619
|
-
JacMachine.program = JacProgram()
|
|
1620
|
-
JacMachine.pool = ThreadPoolExecutor()
|
|
1621
|
-
JacMachine.exec_ctx = ExecutionContext()
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
1574
|
def generate_plugin_helpers(
|
|
1625
1575
|
plugin_class: Type[Any],
|
|
1626
1576
|
) -> tuple[Type[Any], Type[Any], Type[Any]]:
|
|
@@ -1726,3 +1676,37 @@ def generate_plugin_helpers(
|
|
|
1726
1676
|
|
|
1727
1677
|
JacMachineSpec, JacMachineImpl, JacMachineInterface = generate_plugin_helpers(JacMachineInterface) # type: ignore[misc]
|
|
1728
1678
|
plugin_manager.add_hookspecs(JacMachineSpec)
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
class JacMachine(JacMachineInterface):
|
|
1682
|
+
"""Jac Machine State."""
|
|
1683
|
+
|
|
1684
|
+
loaded_modules: dict[str, types.ModuleType] = {}
|
|
1685
|
+
base_path_dir: str = os.getcwd()
|
|
1686
|
+
program: JacProgram = JacProgram()
|
|
1687
|
+
pool: ThreadPoolExecutor = ThreadPoolExecutor()
|
|
1688
|
+
exec_ctx: ExecutionContext = ExecutionContext()
|
|
1689
|
+
|
|
1690
|
+
@staticmethod
|
|
1691
|
+
def set_base_path(base_path: str) -> None:
|
|
1692
|
+
"""Set the base path for the machine."""
|
|
1693
|
+
JacMachine.reset_machine()
|
|
1694
|
+
JacMachine.base_path_dir = (
|
|
1695
|
+
base_path if os.path.isdir(base_path) else os.path.dirname(base_path)
|
|
1696
|
+
)
|
|
1697
|
+
|
|
1698
|
+
@staticmethod
|
|
1699
|
+
def set_context(context: ExecutionContext) -> None:
|
|
1700
|
+
"""Set the context for the machine."""
|
|
1701
|
+
JacMachine.exec_ctx = context
|
|
1702
|
+
|
|
1703
|
+
@staticmethod
|
|
1704
|
+
def reset_machine() -> None:
|
|
1705
|
+
"""Reset the machine."""
|
|
1706
|
+
# for i in JacMachine.loaded_modules.values():
|
|
1707
|
+
# sys.modules.pop(i.__name__, None)
|
|
1708
|
+
JacMachine.loaded_modules.clear()
|
|
1709
|
+
JacMachine.base_path_dir = os.getcwd()
|
|
1710
|
+
JacMachine.program = JacProgram()
|
|
1711
|
+
JacMachine.pool = ThreadPoolExecutor()
|
|
1712
|
+
JacMachine.exec_ctx = ExecutionContext()
|
jaclang/runtimelib/memory.py
CHANGED
|
@@ -82,6 +82,9 @@ class Memory(Generic[ID, TANCH]):
|
|
|
82
82
|
if anchor := self.__mem__.pop(id, None):
|
|
83
83
|
self.__gc__.add(anchor)
|
|
84
84
|
|
|
85
|
+
def commit(self, anchor: TANCH | None = None) -> None:
|
|
86
|
+
"""Commit all data from memory to datasource."""
|
|
87
|
+
|
|
85
88
|
|
|
86
89
|
@dataclass
|
|
87
90
|
class ShelfStorage(Memory[UUID, Anchor]):
|
|
@@ -94,12 +97,21 @@ class ShelfStorage(Memory[UUID, Anchor]):
|
|
|
94
97
|
super().__init__()
|
|
95
98
|
self.__shelf__ = open(session) if session else None # noqa: SIM115
|
|
96
99
|
|
|
97
|
-
def
|
|
98
|
-
"""
|
|
100
|
+
def commit(self, anchor: Anchor | None = None) -> None:
|
|
101
|
+
"""Commit all data from memory to datasource."""
|
|
99
102
|
if isinstance(self.__shelf__, Shelf):
|
|
100
|
-
|
|
101
|
-
self.
|
|
102
|
-
|
|
103
|
+
if anchor:
|
|
104
|
+
if anchor in self.__gc__:
|
|
105
|
+
self.__shelf__.pop(str(anchor.id), None)
|
|
106
|
+
self.__mem__.pop(anchor.id, None)
|
|
107
|
+
self.__gc__.remove(anchor)
|
|
108
|
+
else:
|
|
109
|
+
self.sync_mem_to_db([anchor.id])
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
for anc in self.__gc__:
|
|
113
|
+
self.__shelf__.pop(str(anc.id), None)
|
|
114
|
+
self.__mem__.pop(anc.id, None)
|
|
103
115
|
|
|
104
116
|
keys = set(self.__mem__.keys())
|
|
105
117
|
|
|
@@ -109,7 +121,13 @@ class ShelfStorage(Memory[UUID, Anchor]):
|
|
|
109
121
|
# additional after memory sync
|
|
110
122
|
self.sync_mem_to_db(set(self.__mem__.keys() - keys))
|
|
111
123
|
|
|
124
|
+
def close(self) -> None:
|
|
125
|
+
"""Close memory handler."""
|
|
126
|
+
self.commit()
|
|
127
|
+
|
|
128
|
+
if isinstance(self.__shelf__, Shelf):
|
|
112
129
|
self.__shelf__.close()
|
|
130
|
+
|
|
113
131
|
super().close()
|
|
114
132
|
|
|
115
133
|
def sync_mem_to_db(self, keys: Iterable[UUID]) -> None:
|
|
@@ -18,7 +18,7 @@ obj SavableObject {
|
|
|
18
18
|
|
|
19
19
|
walker create_custom_object {
|
|
20
20
|
can enter1 with `root entry {
|
|
21
|
-
|
|
21
|
+
self.obj = SavableObject(
|
|
22
22
|
val=0,
|
|
23
23
|
arr=[],
|
|
24
24
|
json={},
|
|
@@ -36,7 +36,15 @@ walker create_custom_object {
|
|
|
36
36
|
),
|
|
37
37
|
enum_field = Enum.A
|
|
38
38
|
);
|
|
39
|
-
|
|
39
|
+
save(self.obj);
|
|
40
|
+
|
|
41
|
+
# commit the object to db
|
|
42
|
+
commit(self.obj);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
can exit1 with `root exit {
|
|
46
|
+
# get directly from shelf
|
|
47
|
+
o = _.get_context().mem.__shelf__.get(str(self.obj.__jac__.id)).archetype;
|
|
40
48
|
print(jid(o));
|
|
41
49
|
print(o);
|
|
42
50
|
}
|