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.

Files changed (52) hide show
  1. jaclang/cli/cli.md +1 -0
  2. jaclang/cli/cli.py +38 -18
  3. jaclang/compiler/passes/main/__init__.py +2 -0
  4. jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
  5. jaclang/compiler/passes/main/inheritance_pass.py +8 -1
  6. jaclang/compiler/passes/main/pyast_gen_pass.py +57 -8
  7. jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
  8. jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
  9. jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
  10. jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
  11. jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
  12. jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
  13. jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
  14. jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
  15. jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
  16. jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
  17. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
  18. jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
  19. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
  20. jaclang/compiler/passes/main/tests/test_checker_pass.py +87 -0
  21. jaclang/compiler/passes/main/type_checker_pass.py +128 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +1 -4
  23. jaclang/compiler/program.py +17 -3
  24. jaclang/compiler/type_system/__init__.py +1 -0
  25. jaclang/compiler/type_system/type_evaluator.py +421 -0
  26. jaclang/compiler/type_system/type_utils.py +41 -0
  27. jaclang/compiler/type_system/types.py +240 -0
  28. jaclang/compiler/unitree.py +15 -9
  29. jaclang/langserve/dev_engine.jac +645 -0
  30. jaclang/langserve/dev_server.jac +201 -0
  31. jaclang/langserve/engine.jac +1 -1
  32. jaclang/langserve/tests/server_test/test_lang_serve.py +2 -2
  33. jaclang/langserve/tests/test_dev_server.py +80 -0
  34. jaclang/runtimelib/builtin.py +28 -39
  35. jaclang/runtimelib/importer.py +1 -1
  36. jaclang/runtimelib/machine.py +48 -64
  37. jaclang/runtimelib/memory.py +23 -5
  38. jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
  39. jaclang/runtimelib/utils.py +13 -6
  40. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  41. jaclang/tests/fixtures/edges_walk.jac +1 -1
  42. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  43. jaclang/tests/fixtures/py_run.jac +8 -0
  44. jaclang/tests/fixtures/py_run.py +23 -0
  45. jaclang/tests/fixtures/pyfunc.py +2 -0
  46. jaclang/tests/test_cli.py +40 -0
  47. jaclang/tests/test_language.py +10 -4
  48. jaclang/utils/lang_tools.py +3 -0
  49. {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/METADATA +2 -1
  50. {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/RECORD +52 -31
  51. {jaclang-0.8.5.dist-info → jaclang-0.8.6.dist-info}/WHEEL +0 -0
  52. {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
+ }
@@ -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) == 300
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) == 300
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
+ )
@@ -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 Archetype, NodeArchetype, Root
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
- def jid(obj: Archetype) -> str:
62
- """Get the id of the object."""
63
- return Jac.object_ref(obj)
64
-
65
-
66
- def jobj(id: str) -> Archetype | None:
67
- """Get the object from the id."""
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
- processed: list[Root | NodeArchetype] = []
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",
@@ -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 == "jac" else ".py"
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,
@@ -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 = infer_language(target, base_path)
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
- "mtllm is not installed. Please install it with `pip install mtllm` and run `jac clean`."
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()
@@ -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 close(self) -> None:
98
- """Close memory handler."""
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
- for anchor in self.__gc__:
101
- self.__shelf__.pop(str(anchor.id), None)
102
- self.__mem__.pop(anchor.id, None)
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
- o = SavableObject(
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
- _.save(o);
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
  }