jaclang 0.8.0__py3-none-any.whl → 0.8.2__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 (124) hide show
  1. jaclang/__init__.py +6 -0
  2. jaclang/cli/cli.py +23 -50
  3. jaclang/compiler/codeinfo.py +0 -1
  4. jaclang/compiler/jac.lark +14 -22
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +378 -531
  7. jaclang/compiler/passes/main/__init__.py +0 -14
  8. jaclang/compiler/passes/main/annex_pass.py +2 -8
  9. jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
  11. jaclang/compiler/passes/main/def_use_pass.py +4 -7
  12. jaclang/compiler/passes/main/import_pass.py +6 -14
  13. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  14. jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
  15. jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
  16. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
  18. jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
  19. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
  20. jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
  21. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
  22. jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
  23. jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
  24. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
  25. jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
  26. jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
  27. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
  28. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
  29. jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
  30. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
  31. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
  32. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
  33. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
  34. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
  35. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
  36. jaclang/compiler/program.py +22 -66
  37. jaclang/compiler/tests/fixtures/fam.jac +2 -2
  38. jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
  39. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
  40. jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
  41. jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
  42. jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
  43. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
  44. jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
  45. jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
  46. jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
  47. jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
  48. jaclang/compiler/tests/test_importer.py +30 -13
  49. jaclang/compiler/tests/test_parser.py +1 -0
  50. jaclang/compiler/unitree.py +488 -320
  51. jaclang/langserve/__init__.jac +1 -0
  52. jaclang/langserve/engine.jac +503 -0
  53. jaclang/langserve/sem_manager.jac +309 -0
  54. jaclang/langserve/server.jac +201 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
  56. jaclang/langserve/tests/server_test/utils.py +35 -6
  57. jaclang/langserve/tests/session.jac +294 -0
  58. jaclang/langserve/tests/test_sem_tokens.py +2 -2
  59. jaclang/langserve/tests/test_server.py +8 -7
  60. jaclang/langserve/utils.jac +51 -30
  61. jaclang/runtimelib/archetype.py +128 -6
  62. jaclang/runtimelib/builtin.py +17 -14
  63. jaclang/runtimelib/importer.py +51 -76
  64. jaclang/runtimelib/machine.py +469 -305
  65. jaclang/runtimelib/meta_importer.py +86 -0
  66. jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
  67. jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
  68. jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
  69. jaclang/runtimelib/tests/test_jaseci.py +3 -1
  70. jaclang/runtimelib/utils.py +3 -3
  71. jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
  72. jaclang/tests/fixtures/async_ability.jac +43 -10
  73. jaclang/tests/fixtures/async_function.jac +18 -0
  74. jaclang/tests/fixtures/async_walker.jac +17 -12
  75. jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
  76. jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
  77. jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
  78. jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
  79. jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
  80. jaclang/tests/fixtures/concurrency.jac +1 -1
  81. jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
  82. jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
  83. jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
  84. jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
  85. jaclang/tests/fixtures/deep/one_lev.jac +2 -2
  86. jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
  87. jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
  88. jaclang/tests/fixtures/edge_ability.jac +49 -0
  89. jaclang/tests/fixtures/foo.jac +14 -22
  90. jaclang/tests/fixtures/guess_game.jac +1 -1
  91. jaclang/tests/fixtures/here_usage_error.jac +21 -0
  92. jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
  93. jaclang/tests/fixtures/jac_from_py.py +1 -1
  94. jaclang/tests/fixtures/jp_importer.jac +6 -6
  95. jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
  96. jaclang/tests/fixtures/node_del.jac +30 -36
  97. jaclang/tests/fixtures/unicode_strings.jac +24 -0
  98. jaclang/tests/fixtures/visit_traversal.jac +47 -0
  99. jaclang/tests/fixtures/walker_update.jac +5 -7
  100. jaclang/tests/test_cli.py +12 -7
  101. jaclang/tests/test_language.py +218 -145
  102. jaclang/tests/test_reference.py +9 -4
  103. jaclang/tests/test_typecheck.py +13 -26
  104. jaclang/utils/helpers.py +14 -6
  105. jaclang/utils/lang_tools.py +9 -8
  106. jaclang/utils/module_resolver.py +23 -0
  107. jaclang/utils/tests/test_lang_tools.py +2 -1
  108. jaclang/utils/treeprinter.py +3 -4
  109. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
  110. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
  111. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
  112. jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
  113. jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
  114. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
  115. jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
  116. jaclang/langserve/__init__.py +0 -1
  117. jaclang/langserve/engine.py +0 -553
  118. jaclang/langserve/sem_manager.py +0 -383
  119. jaclang/langserve/server.py +0 -167
  120. jaclang/langserve/tests/session.py +0 -255
  121. jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
  122. jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
  123. jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
  124. {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
@@ -94,6 +94,8 @@ class JacFormatPass(Transform[uni.Module, uni.Module]):
94
94
  part_str = self.format_doc_ir(
95
95
  part, indent_level, current_line_budget, is_broken
96
96
  )
97
+ if part_str.startswith("\n"):
98
+ result = result.rstrip(" ")
97
99
  result += part_str
98
100
 
99
101
  if "\n" in part_str:
@@ -0,0 +1,14 @@
1
+ obj Anchor(ArchetypeProtocol) {
2
+ static def on_entry(cls: type, triggers: list[type]);
3
+ static def on_exit(cls: type, triggers: list[type]);
4
+ def make_public_ro;
5
+ def make_public_rw;
6
+ def make_private;
7
+ def is_public_ro -> bool;
8
+ def is_public_rw -> bool;
9
+ def is_private -> bool;
10
+ def is_readable(caller_id: UUID) -> bool;
11
+ def is_writable(caller_id: UUID) -> bool;
12
+ def give_access(caller_id: UUID, read_write: bool = False);
13
+ def revoke_access(caller_id: UUID);
14
+ }
@@ -1,6 +1,7 @@
1
1
  with entry {
2
- triple_quoted_string = """This is a triple quoted string.
3
- It can span multiple lines.
4
- It can contain any number of quotes or apostrophes.
5
- """;
2
+ triple_quoted_string =
3
+ """This is a triple quoted string.
4
+ It can span multiple lines.
5
+ It can contain any number of quotes or apostrophes.
6
+ """;
6
7
  }
@@ -0,0 +1,6 @@
1
+ import from datetime { datetime }
2
+ import from uuid { UUID, uuid4 }
3
+ import from jaclang.compiler.constant { EdgeDir }
4
+ import from jaclang.plugin { Archetype, ArchetypeProtocol, DSFunc, AbsRootHook, hookimpl }
5
+ import math;
6
+ import numpy as np;
@@ -10,7 +10,7 @@ edge Checking {}
10
10
 
11
11
  walker Creator {
12
12
  has count: int = 0;
13
-
13
+
14
14
  can create with `root | Item entry {
15
15
  here ++> Item();
16
16
  self.count += 1;
@@ -24,11 +24,11 @@ walker Creator {
24
24
  walker Walk {
25
25
  has count: int = 0;
26
26
  has value: int = 0;
27
-
27
+
28
28
  can skip_root with `root entry {
29
29
  visit [-->];
30
30
  }
31
-
31
+
32
32
  can step with Item entry {
33
33
  here.value = self.count;
34
34
  self.count += 1;
@@ -0,0 +1,9 @@
1
+ class SemTokManager {
2
+ """Initialize semantic token manager."""
3
+ def init(self: SemTokManager, ir: uni.Module) -> None {
4
+ self.sem_tokens: List[int] = self.gen_sem_tokens(ir);
5
+ self.aaaaastatic_sem_tokens:
6
+ List[Tuple[lspt.Position, int, int, uni.AstSymbolNode]] =
7
+ self.gen_sem_tok_node(ir);
8
+ }
9
+ }
@@ -51,6 +51,23 @@ class JacFormatPassTests(TestCaseMicroSuite):
51
51
  os.path.join(self.fixture_abs_path(""), "simple_walk_fmt.jac"),
52
52
  )
53
53
 
54
+ def test_tagbreak(self) -> None:
55
+ """Tests if the file matches a particular format."""
56
+ self.compare_files(
57
+ os.path.join(self.fixture_abs_path(""), "tagbreak.jac"),
58
+ )
59
+
60
+ def test_import_fmt(self) -> None:
61
+ """Tests if the file matches a particular format."""
62
+ self.compare_files(
63
+ os.path.join(self.fixture_abs_path(""), "import_fmt.jac"),
64
+ )
65
+
66
+ def test_archetype(self) -> None:
67
+ """Tests if the file matches a particular format."""
68
+ self.compare_files(
69
+ os.path.join(self.fixture_abs_path(""), "archetype_frmt.jac"),
70
+ )
54
71
  # def test_corelib_fmt(self) -> None:
55
72
  # """Tests if the file matches a particular format."""
56
73
  # self.compare_files(
@@ -99,9 +116,7 @@ class JacFormatPassTests(TestCaseMicroSuite):
99
116
  """
100
117
  code_gen_pure = JacProgram().compile(self.fixture_abs_path(filename))
101
118
  code_gen_format = JacProgram.jac_file_formatter(self.fixture_abs_path(filename))
102
- code_gen_jac = JacProgram().compile_from_str(
103
- source_str=code_gen_format, file_path=filename
104
- )
119
+ code_gen_jac = JacProgram().compile(use_str=code_gen_format, file_path=filename)
105
120
  if "circle_clean_tests.jac" in filename:
106
121
  tokens = code_gen_format.split()
107
122
  num_test = 0
@@ -34,8 +34,8 @@ class JacUnparseTests(TestCaseMicroSuite):
34
34
  )
35
35
  before = ast3.dump(code_gen_pure.gen.py_ast[0], indent=2)
36
36
  x = code_gen_pure.unparse()
37
- code_gen_jac = JacProgram().compile_from_str(
38
- source_str=x,
37
+ code_gen_jac = JacProgram().compile(
38
+ use_str=x,
39
39
  file_path=filename,
40
40
  )
41
41
  after = ast3.dump(code_gen_jac.gen.py_ast[0], indent=2)
@@ -12,14 +12,12 @@ from jaclang.compiler.parser import JacParser
12
12
  from jaclang.compiler.passes.main import (
13
13
  Alert,
14
14
  CFGBuildPass,
15
- CompilerMode,
16
15
  DeclImplMatchPass,
17
16
  DefUsePass,
18
17
  InheritancePass,
19
18
  JacAnnexPass,
20
19
  JacImportDepsPass,
21
20
  PyBytecodeGenPass,
22
- PyImportDepsPass,
23
21
  PyJacAstLinkPass,
24
22
  PyastBuildPass,
25
23
  PyastGenPass,
@@ -38,6 +36,7 @@ from jaclang.utils.log import logging
38
36
  logger = logging.getLogger(__name__)
39
37
 
40
38
  ir_gen_sched = [
39
+ SymTabBuildPass,
41
40
  DeclImplMatchPass,
42
41
  DefUsePass,
43
42
  CFGBuildPass,
@@ -61,36 +60,15 @@ class JacProgram:
61
60
  self.errors_had: list[Alert] = []
62
61
  self.warnings_had: list[Alert] = []
63
62
 
64
- def get_bytecode(
65
- self, full_target: str, full_compile: bool = True
66
- ) -> Optional[types.CodeType]:
63
+ def get_bytecode(self, full_target: str) -> Optional[types.CodeType]:
67
64
  """Get the bytecode for a specific module."""
68
- if full_target in self.mod.hub:
65
+ if full_target in self.mod.hub and self.mod.hub[full_target].gen.py_bytecode:
69
66
  codeobj = self.mod.hub[full_target].gen.py_bytecode
70
67
  return marshal.loads(codeobj) if isinstance(codeobj, bytes) else None
71
- result = self.compile(
72
- file_path=full_target,
73
- mode=CompilerMode.COMPILE if full_compile else CompilerMode.COMPILE_SINGLE,
74
- )
68
+ result = self.compile(file_path=full_target)
75
69
  return marshal.loads(result.gen.py_bytecode) if result.gen.py_bytecode else None
76
70
 
77
- def compile(
78
- self,
79
- file_path: str,
80
- mode: CompilerMode = CompilerMode.COMPILE,
81
- ) -> uni.Module:
82
- """Convert a Jac file to an AST."""
83
- with open(file_path, "r", encoding="utf-8") as file:
84
- return self.compile_from_str(
85
- source_str=file.read(), file_path=file_path, mode=mode
86
- )
87
-
88
- def compile_from_str(
89
- self,
90
- source_str: str,
91
- file_path: str,
92
- mode: CompilerMode = CompilerMode.COMPILE,
93
- ) -> uni.Module:
71
+ def parse_str(self, source_str: str, file_path: str) -> uni.Module:
94
72
  """Convert a Jac file to an AST."""
95
73
  had_error = False
96
74
  if file_path.endswith(".py"):
@@ -116,54 +94,32 @@ class JacProgram:
116
94
  if self.mod.main.stub_only:
117
95
  self.mod = uni.ProgramModule(mod)
118
96
  self.mod.hub[mod.loc.mod_path] = mod
119
- return self.run_pass_schedule(mod_targ=mod, mode=mode)
97
+ JacAnnexPass(ir_in=mod, prog=self)
98
+ return mod
120
99
 
121
- def run_pass_schedule(
122
- self,
123
- mod_targ: uni.Module,
124
- mode: CompilerMode = CompilerMode.COMPILE,
100
+ def compile(
101
+ self, file_path: str, use_str: str | None = None, no_cgen: bool = False
125
102
  ) -> uni.Module:
126
103
  """Convert a Jac file to an AST."""
127
- JacAnnexPass(ir_in=mod_targ, prog=self)
128
- SymTabBuildPass(ir_in=mod_targ, prog=self)
129
- if mode == CompilerMode.PARSE:
130
- return mod_targ
131
- elif mode in (CompilerMode.COMPILE_SINGLE, CompilerMode.NO_CGEN_SINGLE):
132
- self.schedule_runner(mod_targ, mode=mode)
133
- return mod_targ
104
+ if not use_str:
105
+ with open(file_path, "r", encoding="utf-8") as file:
106
+ use_str = file.read()
107
+ mod_targ = self.parse_str(use_str, file_path)
108
+ self.run_schedule(mod=mod_targ, passes=ir_gen_sched)
109
+ if not no_cgen:
110
+ self.run_schedule(mod=mod_targ, passes=py_code_gen)
111
+ return mod_targ
112
+
113
+ def build(self, file_path: str, use_str: str | None = None) -> uni.Module:
114
+ """Convert a Jac file to an AST."""
115
+ mod_targ = self.compile(file_path, use_str)
134
116
  JacImportDepsPass(ir_in=mod_targ, prog=self)
135
- if len(self.errors_had):
136
- return mod_targ
137
- SymTabLinkPass(ir_in=mod_targ, prog=self)
138
117
  for mod in self.mod.hub.values():
139
- self.schedule_runner(mod, mode=CompilerMode.COMPILE)
140
- if mode == CompilerMode.COMPILE:
141
- return mod_targ
142
- PyImportDepsPass(mod_targ, prog=self)
143
- SymTabLinkPass(ir_in=mod_targ, prog=self)
118
+ SymTabLinkPass(ir_in=mod, prog=self)
144
119
  for mod in self.mod.hub.values():
145
120
  DefUsePass(mod, prog=self)
146
- for mod in self.mod.hub.values():
147
- self.schedule_runner(mod, mode=CompilerMode.TYPECHECK)
148
121
  return mod_targ
149
122
 
150
- def schedule_runner(
151
- self,
152
- mod: uni.Module,
153
- mode: CompilerMode = CompilerMode.COMPILE,
154
- ) -> None:
155
- """Run premade passes on the module."""
156
- match mode:
157
- case CompilerMode.NO_CGEN | CompilerMode.NO_CGEN_SINGLE:
158
- passes = ir_gen_sched
159
- case CompilerMode.COMPILE | CompilerMode.COMPILE_SINGLE:
160
- passes = [*ir_gen_sched, *py_code_gen]
161
- case CompilerMode.TYPECHECK:
162
- passes = []
163
- case _:
164
- raise ValueError(f"Invalid mode: {mode}")
165
- self.run_schedule(mod, passes)
166
-
167
123
  def run_schedule(
168
124
  self,
169
125
  mod: uni.Module,
@@ -25,14 +25,14 @@ node location {
25
25
 
26
26
  for i in activities {
27
27
  i.duration = visitor.duration;
28
- if here.name not in visitor.passport {
28
+ if visitor.name not in visitor.passport {
29
29
  if i.name == "Hiking" {
30
30
  for j=0 to j<3 by j+=1 {
31
31
  i.duration+=1;
32
32
  }
33
33
  i.duration+=1;
34
34
  }
35
- visitor.passport.append(here.name);
35
+ visitor.passport.append(visitor.name);
36
36
  }
37
37
  }
38
38
  }
@@ -0,0 +1 @@
1
+ import from .tools { tool_func }
@@ -0,0 +1 @@
1
+ import from .helper { help_func }
@@ -0,0 +1,3 @@
1
+ def help_func() {
2
+ return 'Helper function called' ;
3
+ }
@@ -0,0 +1,3 @@
1
+ def tool_func() {
2
+ return 'Tool function executed' ;
3
+ }
@@ -0,0 +1,5 @@
1
+ from jaclang import JacMachineInterface as _
2
+
3
+ from .tools import tool_func
4
+
5
+ glob_var_lib = "pkg_import_lib_py.glob_var_lib"
@@ -0,0 +1,3 @@
1
+ from jaclang import JacMachineInterface as _
2
+
3
+ from .helper import help_func
@@ -0,0 +1,3 @@
1
+ def help_func() {
2
+ return 'Helper function called' ;
3
+ }
@@ -0,0 +1,3 @@
1
+ def tool_func() {
2
+ return 'Tool function executed' ;
3
+ }
@@ -0,0 +1,10 @@
1
+ import from pkg_import_lib { tool_func }
2
+ import from pkg_import_lib.sub { help_func }
3
+
4
+ with entry {
5
+ print('Main Execution:\n') ;
6
+ print('Calling from tools.jac...') ;
7
+ print('Tool says:', tool_func()) ;
8
+ print('\nCalling from helper.jac...') ;
9
+ print('Helper says:', help_func()) ;
10
+ }
@@ -0,0 +1,11 @@
1
+ import from pkg_import_lib_py { tool_func,glob_var_lib }
2
+ import from pkg_import_lib_py.sub { help_func }
3
+
4
+ with entry {
5
+ print('Main Execution:\n') ;
6
+ print('Calling from tools.jac...') ;
7
+ print('Tool says:', tool_func()) ;
8
+ print('\nCalling from helper.jac...') ;
9
+ print('Helper says:', help_func()) ;
10
+ print('\nGlobal variable from lib:', glob_var_lib) ;
11
+ }
@@ -3,10 +3,10 @@
3
3
  import io
4
4
  import sys
5
5
 
6
- from jaclang import JacMachineInterface as Jac
6
+ from jaclang import JacMachine as Jac
7
7
  from jaclang.cli import cli
8
8
  from jaclang.compiler.program import JacProgram
9
- from jaclang.runtimelib.machine import JacMachineInterface, JacMachine
9
+ from jaclang.runtimelib.machine import JacMachineInterface
10
10
  from jaclang.utils.test import TestCase
11
11
 
12
12
 
@@ -15,29 +15,27 @@ class TestLoader(TestCase):
15
15
 
16
16
  def test_import_basic_python(self) -> None:
17
17
  """Test basic self loading."""
18
- mach = JacMachine(self.fixture_abs_path(__file__))
18
+ Jac.set_base_path(self.fixture_abs_path(__file__))
19
19
  JacMachineInterface.attach_program(
20
- mach,
21
20
  JacProgram(),
22
21
  )
23
- (h,) = Jac.jac_import(mach, "fixtures.hello_world", base_path=__file__)
22
+ (h,) = Jac.jac_import("fixtures.hello_world", base_path=__file__)
24
23
  self.assertEqual(h.hello(), "Hello World!") # type: ignore
25
24
 
26
25
  def test_modules_correct(self) -> None:
27
26
  """Test basic self loading."""
28
- mach = JacMachine(self.fixture_abs_path(__file__))
27
+ Jac.set_base_path(self.fixture_abs_path(__file__))
29
28
  JacMachineInterface.attach_program(
30
- mach,
31
29
  JacProgram(),
32
30
  )
33
- Jac.jac_import(mach, "fixtures.hello_world", base_path=__file__)
31
+ Jac.jac_import("fixtures.hello_world", base_path=__file__)
34
32
  self.assertIn(
35
33
  "module 'fixtures.hello_world'",
36
- str(mach.loaded_modules),
34
+ str(Jac.loaded_modules),
37
35
  )
38
36
  self.assertIn(
39
37
  "/tests/fixtures/hello_world.jac",
40
- str(mach.loaded_modules).replace("\\\\", "/"),
38
+ str(Jac.loaded_modules).replace("\\\\", "/"),
41
39
  )
42
40
 
43
41
  def test_jac_py_import(self) -> None:
@@ -92,12 +90,11 @@ class TestLoader(TestCase):
92
90
  sys.stdout = captured_output
93
91
 
94
92
  try:
95
- mach = JacMachine(self.fixture_abs_path(__file__))
93
+ Jac.set_base_path(self.fixture_abs_path(__file__))
96
94
  JacMachineInterface.attach_program(
97
- mach,
98
95
  JacProgram(),
99
96
  )
100
- Jac.jac_import(mach, module_name, base_path=__file__)
97
+ Jac.jac_import(module_name, base_path=__file__)
101
98
  cli.run(jac_file_path)
102
99
 
103
100
  # Reset stdout and get the output
@@ -111,3 +108,23 @@ class TestLoader(TestCase):
111
108
 
112
109
  os.environ.pop("JACPATH", None)
113
110
  jacpath_dir.cleanup()
111
+
112
+ def test_importer_with_submodule_jac(self) -> None:
113
+ """Test basic self loading."""
114
+ captured_output = io.StringIO()
115
+ sys.stdout = captured_output
116
+ cli.run(self.fixture_abs_path("pkg_import_main.jac"))
117
+ sys.stdout = sys.__stdout__
118
+ stdout_value = captured_output.getvalue()
119
+ self.assertIn("Helper function called", stdout_value)
120
+ self.assertIn("Tool function executed", stdout_value)
121
+
122
+ def test_importer_with_submodule_py(self) -> None:
123
+ captured_output = io.StringIO()
124
+ sys.stdout = captured_output
125
+ cli.run(self.fixture_abs_path("pkg_import_main_py.jac"))
126
+ sys.stdout = sys.__stdout__
127
+ stdout_value = captured_output.getvalue()
128
+ self.assertIn("Helper function called", stdout_value)
129
+ self.assertIn("Tool function executed", stdout_value)
130
+ self.assertIn("pkg_import_lib_py.glob_var_lib", stdout_value)
@@ -111,6 +111,7 @@ class TestLarkParser(TestCaseMicroSuite):
111
111
  "consume_token",
112
112
  "match_many",
113
113
  "consume_many",
114
+ "extract_from_list",
114
115
  ]:
115
116
  continue
116
117
  self.assertIn(fn, rules)