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.

Files changed (88) hide show
  1. jaclang/cli/cli.md +1 -0
  2. jaclang/cli/cli.py +109 -37
  3. jaclang/compiler/jac.lark +3 -3
  4. jaclang/compiler/larkparse/jac_parser.py +2 -2
  5. jaclang/compiler/parser.py +14 -21
  6. jaclang/compiler/passes/main/__init__.py +5 -1
  7. jaclang/compiler/passes/main/binder_pass.py +594 -0
  8. jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
  9. jaclang/compiler/passes/main/import_pass.py +8 -256
  10. jaclang/compiler/passes/main/inheritance_pass.py +10 -3
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +92 -77
  12. jaclang/compiler/passes/main/pyast_load_pass.py +24 -13
  13. jaclang/compiler/passes/main/sem_def_match_pass.py +1 -1
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
  15. jaclang/compiler/passes/main/tests/fixtures/M1.jac +3 -0
  16. jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
  17. jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
  18. jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
  21. jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
  22. jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
  23. jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
  24. jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
  25. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
  26. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +47 -0
  27. jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
  28. jaclang/compiler/passes/main/tests/test_binder_pass.py +111 -0
  29. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
  30. jaclang/compiler/passes/main/tests/test_checker_pass.py +87 -0
  31. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +13 -13
  32. jaclang/compiler/passes/main/tests/test_sem_def_match_pass.py +6 -6
  33. jaclang/compiler/passes/main/type_checker_pass.py +128 -0
  34. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +2 -0
  35. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -0
  36. jaclang/compiler/program.py +32 -11
  37. jaclang/compiler/tests/test_sr_errors.py +32 -0
  38. jaclang/compiler/type_system/__init__.py +1 -0
  39. jaclang/compiler/type_system/type_evaluator.py +421 -0
  40. jaclang/compiler/type_system/type_utils.py +41 -0
  41. jaclang/compiler/type_system/types.py +240 -0
  42. jaclang/compiler/unitree.py +36 -24
  43. jaclang/langserve/dev_engine.jac +645 -0
  44. jaclang/langserve/dev_server.jac +201 -0
  45. jaclang/langserve/engine.jac +24 -5
  46. jaclang/langserve/tests/server_test/test_lang_serve.py +2 -2
  47. jaclang/langserve/tests/test_dev_server.py +80 -0
  48. jaclang/langserve/tests/test_server.py +13 -0
  49. jaclang/runtimelib/builtin.py +28 -39
  50. jaclang/runtimelib/importer.py +34 -63
  51. jaclang/runtimelib/machine.py +48 -64
  52. jaclang/runtimelib/memory.py +23 -5
  53. jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
  54. jaclang/runtimelib/utils.py +42 -6
  55. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  56. jaclang/tests/fixtures/edges_walk.jac +1 -1
  57. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  58. jaclang/tests/fixtures/py_run.jac +8 -0
  59. jaclang/tests/fixtures/py_run.py +23 -0
  60. jaclang/tests/fixtures/pyfunc.py +2 -0
  61. jaclang/tests/fixtures/pyfunc_fmt.py +60 -0
  62. jaclang/tests/fixtures/pyfunc_fstr.py +25 -0
  63. jaclang/tests/fixtures/pyfunc_kwesc.py +33 -0
  64. jaclang/tests/fixtures/python_run_test.py +19 -0
  65. jaclang/tests/test_cli.py +107 -0
  66. jaclang/tests/test_language.py +106 -5
  67. jaclang/utils/lang_tools.py +6 -3
  68. jaclang/utils/module_resolver.py +90 -0
  69. jaclang/utils/symtable_test_helpers.py +125 -0
  70. jaclang/utils/test.py +3 -4
  71. jaclang/vendor/interegular/__init__.py +34 -0
  72. jaclang/vendor/interegular/comparator.py +163 -0
  73. jaclang/vendor/interegular/fsm.py +1015 -0
  74. jaclang/vendor/interegular/patterns.py +732 -0
  75. jaclang/vendor/interegular/py.typed +0 -0
  76. jaclang/vendor/interegular/utils/__init__.py +15 -0
  77. jaclang/vendor/interegular/utils/simple_parser.py +165 -0
  78. jaclang/vendor/interegular-0.3.3.dist-info/INSTALLER +1 -0
  79. jaclang/vendor/interegular-0.3.3.dist-info/LICENSE.txt +21 -0
  80. jaclang/vendor/interegular-0.3.3.dist-info/METADATA +64 -0
  81. jaclang/vendor/interegular-0.3.3.dist-info/RECORD +20 -0
  82. jaclang/vendor/interegular-0.3.3.dist-info/REQUESTED +0 -0
  83. jaclang/vendor/interegular-0.3.3.dist-info/WHEEL +5 -0
  84. jaclang/vendor/interegular-0.3.3.dist-info/top_level.txt +1 -0
  85. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/METADATA +2 -1
  86. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/RECORD +88 -43
  87. {jaclang-0.8.4.dist-info → jaclang-0.8.6.dist-info}/WHEEL +0 -0
  88. {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
+ }
@@ -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.fetch_sym_tab;
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.fetch_sym_tab {
288
+ if base_class_symbol.symbol_table {
288
289
  completion_items += utils.collect_all_symbols_in_scope(
289
- base_class_symbol.fetch_sym_tab,
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 isinstance(node_selected, uni.Name)
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) == 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
+ )
@@ -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
+ )
@@ -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",
@@ -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
- loaded_items: list = []
155
- if spec.target.startswith("."):
156
- spec.target = spec.target.lstrip(".")
157
- if len(spec.target.split(".")) > 1:
158
- spec.target = spec.target.split(".")[-1]
159
- full_target = path.normpath(path.join(spec.caller_dir, spec.target))
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
- else:
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 == "jac" else ".py"
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,