jaclang 0.7.16__py3-none-any.whl → 0.7.18__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 (81) hide show
  1. jaclang/cli/cli.py +140 -77
  2. jaclang/compiler/absyntree.py +9 -4
  3. jaclang/compiler/constant.py +8 -8
  4. jaclang/compiler/parser.py +10 -2
  5. jaclang/compiler/passes/main/__init__.py +1 -1
  6. jaclang/compiler/passes/main/access_modifier_pass.py +96 -147
  7. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +152 -50
  8. jaclang/compiler/passes/main/import_pass.py +88 -59
  9. jaclang/compiler/passes/main/py_collect_dep_pass.py +70 -0
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +46 -6
  11. jaclang/compiler/passes/main/pyast_load_pass.py +1 -0
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -0
  13. jaclang/compiler/passes/main/schedules.py +9 -2
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +9 -5
  15. jaclang/compiler/passes/main/tests/fixtures/autoimpl.empty.impl.jac +0 -0
  16. jaclang/compiler/passes/main/tests/fixtures/autoimpl.jac +1 -1
  17. jaclang/compiler/passes/main/tests/fixtures/py_imp_test.jac +29 -0
  18. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -0
  19. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/color.py +3 -0
  20. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/constants.py +5 -0
  21. jaclang/compiler/passes/main/tests/fixtures/pygame_mock/display.py +2 -0
  22. jaclang/compiler/passes/main/tests/test_import_pass.py +72 -13
  23. jaclang/compiler/passes/main/type_check_pass.py +15 -5
  24. jaclang/compiler/passes/tool/jac_formatter_pass.py +13 -3
  25. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +37 -41
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +37 -41
  27. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/access_mod_check.jac +27 -0
  28. jaclang/compiler/passes/utils/mypy_ast_build.py +45 -0
  29. jaclang/compiler/symtable.py +16 -11
  30. jaclang/compiler/tests/test_importer.py +17 -9
  31. jaclang/langserve/engine.py +64 -16
  32. jaclang/langserve/server.py +16 -1
  33. jaclang/langserve/tests/fixtures/import_include_statements.jac +3 -3
  34. jaclang/langserve/tests/fixtures/rename.jac +30 -0
  35. jaclang/langserve/tests/test_server.py +224 -6
  36. jaclang/langserve/utils.py +28 -98
  37. jaclang/plugin/builtin.py +8 -4
  38. jaclang/plugin/default.py +86 -64
  39. jaclang/plugin/feature.py +13 -13
  40. jaclang/plugin/spec.py +10 -11
  41. jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
  42. jaclang/plugin/tests/test_jaseci.py +414 -42
  43. jaclang/runtimelib/architype.py +481 -333
  44. jaclang/runtimelib/constructs.py +5 -8
  45. jaclang/runtimelib/context.py +89 -69
  46. jaclang/runtimelib/importer.py +16 -15
  47. jaclang/runtimelib/machine.py +66 -2
  48. jaclang/runtimelib/memory.py +134 -75
  49. jaclang/runtimelib/utils.py +17 -10
  50. jaclang/settings.py +2 -4
  51. jaclang/tests/fixtures/access_checker.jac +12 -17
  52. jaclang/tests/fixtures/access_modifier.jac +88 -33
  53. jaclang/tests/fixtures/baddy.jac +3 -0
  54. jaclang/tests/fixtures/bar.jac +34 -0
  55. jaclang/tests/fixtures/builtin_dotgen.jac +1 -0
  56. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  57. jaclang/tests/fixtures/edge_ops.jac +1 -1
  58. jaclang/tests/fixtures/edges_walk.jac +1 -1
  59. jaclang/tests/fixtures/foo.jac +43 -0
  60. jaclang/tests/fixtures/game1.jac +1 -1
  61. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  62. jaclang/tests/fixtures/import.jac +9 -0
  63. jaclang/tests/fixtures/index_slice.jac +30 -0
  64. jaclang/tests/fixtures/objref.jac +12 -0
  65. jaclang/tests/fixtures/pyfunc_1.py +1 -1
  66. jaclang/tests/fixtures/pyfunc_2.py +2 -2
  67. jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
  68. jaclang/tests/fixtures/pygame_mock/color.py +3 -0
  69. jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
  70. jaclang/tests/fixtures/pygame_mock/display.py +2 -0
  71. jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
  72. jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
  73. jaclang/tests/test_cli.py +49 -6
  74. jaclang/tests/test_language.py +126 -80
  75. jaclang/tests/test_reference.py +2 -9
  76. jaclang/utils/treeprinter.py +30 -3
  77. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/METADATA +3 -1
  78. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/RECORD +81 -59
  79. /jaclang/tests/fixtures/{err.test.jac → baddy.test.jac} +0 -0
  80. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/WHEEL +0 -0
  81. {jaclang-0.7.16.dist-info → jaclang-0.7.18.dist-info}/entry_points.txt +0 -0
@@ -6,19 +6,16 @@ symbols are available for matching.
6
6
  """
7
7
 
8
8
  import ast as py_ast
9
- import importlib.util
10
9
  import os
11
- import sys
12
10
  from typing import Optional
13
11
 
14
12
 
15
13
  import jaclang.compiler.absyntree as ast
16
14
  from jaclang.compiler.passes import Pass
17
- from jaclang.compiler.passes.main import SubNodeTabPass
18
- from jaclang.settings import settings
19
- from jaclang.utils.helpers import is_standard_lib_module
15
+ from jaclang.compiler.passes.main import SubNodeTabPass, SymTabBuildPass
20
16
  from jaclang.utils.log import logging
21
17
 
18
+
22
19
  logger = logging.getLogger(__name__)
23
20
 
24
21
 
@@ -28,37 +25,29 @@ class JacImportPass(Pass):
28
25
  def before_pass(self) -> None:
29
26
  """Run once before pass."""
30
27
  self.import_table: dict[str, ast.Module] = {}
31
- self.__py_imports: set[str] = set()
32
- self.py_resolve_list: set[str] = set()
33
28
 
34
29
  def enter_module(self, node: ast.Module) -> None:
35
30
  """Run Importer."""
36
31
  self.cur_node = node
37
32
  self.import_table[node.loc.mod_path] = node
38
- self.__py_imports.clear()
39
- self.__annex_impl(node)
33
+ self.annex_impl(node)
40
34
  self.terminate() # Turns off auto traversal for deliberate traversal
41
35
  self.run_again = True
42
36
  while self.run_again:
43
37
  self.run_again = False
44
38
  all_imports = self.get_all_sub_nodes(node, ast.ModulePath)
45
39
  for i in all_imports:
46
- self.process_import(node, i)
40
+ self.process_import(i)
47
41
  self.enter_module_path(i)
48
42
  SubNodeTabPass(prior=self, input_ir=node)
49
43
 
50
- for i in self.get_all_sub_nodes(node, ast.AtomTrailer):
51
- self.enter_atom_trailer(i)
52
-
53
- node.mod_deps = self.import_table
44
+ node.mod_deps.update(self.import_table)
54
45
 
55
- def process_import(self, node: ast.Module, i: ast.ModulePath) -> None:
46
+ def process_import(self, i: ast.ModulePath) -> None:
56
47
  """Process an import."""
57
48
  imp_node = i.parent_of_type(ast.Import)
58
49
  if imp_node.is_jac and not i.sub_module:
59
50
  self.import_jac_module(node=i)
60
- elif imp_node.is_py:
61
- self.__py_imports.add(i.path_str)
62
51
 
63
52
  def attach_mod_to_node(
64
53
  self, node: ast.ModulePath | ast.ModuleItem, mod: ast.Module | None
@@ -67,10 +56,11 @@ class JacImportPass(Pass):
67
56
  if mod:
68
57
  self.run_again = True
69
58
  node.sub_module = mod
70
- self.__annex_impl(mod)
59
+ self.annex_impl(mod)
71
60
  node.add_kids_right([mod], pos_update=False)
61
+ mod.parent = node
72
62
 
73
- def __annex_impl(self, node: ast.Module) -> None:
63
+ def annex_impl(self, node: ast.Module) -> None:
74
64
  """Annex impl and test modules."""
75
65
  if node.stub_only:
76
66
  return
@@ -131,11 +121,6 @@ class JacImportPass(Pass):
131
121
  node.sub_module.name = node.alias.value
132
122
  # Items matched during def/decl pass
133
123
 
134
- def enter_atom_trailer(self, node: ast.AtomTrailer) -> None:
135
- """Iterate on AtomTrailer nodes to get python paths to resolve."""
136
- if node.as_attr_list[0].sym_name in self.__py_imports:
137
- self.py_resolve_list.add(".".join([i.sym_name for i in node.as_attr_list]))
138
-
139
124
  def import_jac_module(self, node: ast.ModulePath) -> None:
140
125
  """Import a module."""
141
126
  self.cur_node = node # impacts error reporting
@@ -214,58 +199,102 @@ class PyImportPass(JacImportPass):
214
199
  def before_pass(self) -> None:
215
200
  """Only run pass if settings are set to raise python."""
216
201
  super().before_pass()
217
- if not settings.py_raise:
218
- self.terminate()
219
202
 
220
- def process_import(self, node: ast.Module, i: ast.ModulePath) -> None:
203
+ def __get_current_module(self, node: ast.AstNode) -> str:
204
+ parent = node.find_parent_of_type(ast.Module)
205
+ mod_list = []
206
+ while parent is not None:
207
+ mod_list.append(parent)
208
+ parent = parent.find_parent_of_type(ast.Module)
209
+ mod_list.reverse()
210
+ return ".".join(p.name for p in mod_list)
211
+
212
+ def process_import(self, i: ast.ModulePath) -> None:
221
213
  """Process an import."""
214
+ # Process import is orginally implemented to handle ModulePath in Jaclang
215
+ # This won't work with py imports as this will fail to import stuff in form of
216
+ # from a import b
217
+ # from a import (c, d, e)
218
+ # Solution to that is to get the import node and check the from loc then
219
+ # handle it based on if there a from loc or not
222
220
  imp_node = i.parent_of_type(ast.Import)
223
- if (
224
- imp_node.is_py
225
- and not i.sub_module
226
- and not is_standard_lib_module(i.path_str)
227
- ):
228
- mod = self.import_py_module(node=i, mod_path=node.loc.mod_path)
229
- if mod:
230
- i.sub_module = mod
231
- i.add_kids_right([mod], pos_update=False)
232
- if settings.py_raise_deep:
233
- self.run_again = True
221
+ if imp_node.is_py and not i.sub_module:
222
+ if imp_node.from_loc:
223
+ for j in imp_node.items.items:
224
+ assert isinstance(j, ast.ModuleItem)
225
+ mod_path = f"{imp_node.from_loc.dot_path_str}.{j.name.sym_name}"
226
+ self.import_py_module(
227
+ parent_node=j,
228
+ mod_path=mod_path,
229
+ imported_mod_name=(
230
+ j.name.sym_name if not j.alias else j.alias.sym_name
231
+ ),
232
+ )
233
+ else:
234
+ for j in imp_node.items.items:
235
+ assert isinstance(j, ast.ModulePath)
236
+ self.import_py_module(
237
+ parent_node=j,
238
+ mod_path=j.dot_path_str,
239
+ imported_mod_name=(
240
+ j.dot_path_str.replace(".", "")
241
+ if not j.alias
242
+ else j.alias.sym_name
243
+ ),
244
+ )
234
245
 
235
246
  def import_py_module(
236
- self, node: ast.ModulePath, mod_path: str
247
+ self,
248
+ parent_node: ast.ModulePath | ast.ModuleItem,
249
+ imported_mod_name: str,
250
+ mod_path: str,
237
251
  ) -> Optional[ast.Module]:
238
252
  """Import a module."""
239
253
  from jaclang.compiler.passes.main import PyastBuildPass
240
254
 
241
- base_dir = os.path.dirname(mod_path)
242
- sys.path.append(base_dir)
255
+ assert isinstance(self.ir, ast.Module)
256
+
257
+ python_raise_map = self.ir.py_raise_map
258
+ file_to_raise = None
259
+
260
+ if mod_path in python_raise_map:
261
+ file_to_raise = python_raise_map[mod_path]
262
+ else:
263
+ resolved_mod_path = (
264
+ f"{self.__get_current_module(parent_node)}.{imported_mod_name}"
265
+ )
266
+ assert isinstance(self.ir, ast.Module)
267
+ resolved_mod_path = resolved_mod_path.replace(f"{self.ir.name}.", "")
268
+ file_to_raise = python_raise_map.get(resolved_mod_path)
269
+
270
+ if file_to_raise is None:
271
+ return None
272
+
243
273
  try:
244
- # Dynamically import the module
245
- spec = importlib.util.find_spec(node.path_str)
246
- sys.path.remove(base_dir)
247
- if spec and spec.origin and spec.origin not in {None, "built-in", "frozen"}:
248
- if spec.origin in self.import_table:
249
- return self.import_table[spec.origin]
250
- with open(spec.origin, "r", encoding="utf-8") as f:
274
+ if file_to_raise not in {None, "built-in", "frozen"}:
275
+ if file_to_raise in self.import_table:
276
+ return self.import_table[file_to_raise]
277
+
278
+ with open(file_to_raise, "r", encoding="utf-8") as f:
251
279
  mod = PyastBuildPass(
252
280
  input_ir=ast.PythonModuleAst(
253
- py_ast.parse(f.read()), mod_path=spec.origin
281
+ py_ast.parse(f.read()), mod_path=file_to_raise
254
282
  ),
255
283
  ).ir
284
+ SubNodeTabPass(input_ir=mod, prior=self)
256
285
  if mod:
257
- self.import_table[spec.origin] = mod
286
+ mod.name = imported_mod_name
287
+ self.import_table[file_to_raise] = mod
288
+ self.attach_mod_to_node(parent_node, mod)
289
+ SymTabBuildPass(input_ir=mod, prior=self)
258
290
  return mod
259
291
  else:
260
- raise self.ice(
261
- f"Failed to import python module {node.path_str}: {spec.origin}"
262
- )
292
+ raise self.ice(f"Failed to import python module {mod_path}")
263
293
  except Exception as e:
264
- if "Empty kid for Token ModulePath" in str(e) or "utf-8" in str(e): # FIXME
265
- return None
266
- self.error(
267
- f"Failed to import python module {node.path_str}: {e}",
268
- node_override=node,
269
- )
294
+ self.error(f"Failed to import python module {mod_path}")
270
295
  raise e
271
296
  return None
297
+
298
+ def annex_impl(self, node: ast.Module) -> None:
299
+ """Annex impl and test modules."""
300
+ return None
@@ -0,0 +1,70 @@
1
+ """Collect Python dependencies based on reference sourced from Jac.
2
+
3
+ This pass will use mypy to calculate the python package/module dependencies
4
+ that are only relevant to actual references source from Jac code.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+
10
+ import jaclang.compiler.absyntree as ast
11
+ from jaclang.compiler.passes import Pass
12
+ from jaclang.settings import settings
13
+
14
+ import mypy.nodes as MypyNodes # noqa N812
15
+
16
+
17
+ class PyCollectDepsPass(Pass):
18
+ """Python and bytecode file self.__debug_printing pass."""
19
+
20
+ def __debug_print(self, msg: str) -> None:
21
+ if settings.collect_py_dep_debug:
22
+ self.log_info("CollectPythonDependencies::" + msg)
23
+
24
+ def enter_node(self, node: ast.AstNode) -> None:
25
+ """Collect python dependencies from all Jac Nodes."""
26
+ assert isinstance(self.ir, ast.Module)
27
+
28
+ if not isinstance(node, ast.AstSymbolNode):
29
+ return
30
+
31
+ path: str = ""
32
+ if isinstance(node, ast.ModulePath):
33
+ if node.path:
34
+ path = ".".join([i.value for i in node.path])
35
+ node.abs_path = self.ir.py_mod_dep_map.get(path)
36
+ elif isinstance(node, ast.ModuleItem):
37
+ imp = node.parent_of_type(ast.Import)
38
+ mod_path_node = imp.get_all_sub_nodes(ast.ModulePath)[0]
39
+ if mod_path_node.path:
40
+ path = ".".join([i.value for i in mod_path_node.path])
41
+ path += f".{node.name.value}"
42
+ node.abs_path = self.ir.py_mod_dep_map.get(path)
43
+
44
+ if len(node.gen.mypy_ast) == 0:
45
+ return
46
+
47
+ mypy_node = node.gen.mypy_ast[0]
48
+
49
+ if isinstance(mypy_node, MypyNodes.RefExpr) and mypy_node.node:
50
+ node_full_name = mypy_node.node.fullname
51
+ if "." in node_full_name:
52
+ mod_name = node_full_name[: node_full_name.rindex(".")]
53
+ else:
54
+ mod_name = node_full_name
55
+
56
+ if mod_name not in self.ir.py_mod_dep_map:
57
+ self.__debug_print(
58
+ f"Can't find a python file associated with {type(node)}::{node.loc}"
59
+ )
60
+ return
61
+
62
+ mode_path = self.ir.py_mod_dep_map[mod_name]
63
+ if mode_path.endswith(".jac"):
64
+ return
65
+
66
+ self.ir.py_raise_map[mod_name] = mode_path
67
+ else:
68
+ self.__debug_print(
69
+ f"Collect python dependencies is not supported in {type(node)}::{node.loc}"
70
+ )
@@ -529,7 +529,7 @@ class PyastGenPass(Pass):
529
529
  sub_module: Optional[Module],
530
530
  """
531
531
  path_alias: dict[str, Optional[str]] = (
532
- {node.from_loc.path_str: None} if node.from_loc else {}
532
+ {node.from_loc.dot_path_str: None} if node.from_loc else {}
533
533
  )
534
534
  imp_from = {}
535
535
  if node.items:
@@ -539,7 +539,7 @@ class PyastGenPass(Pass):
539
539
  item.alias.sym_name if item.alias else None
540
540
  )
541
541
  elif isinstance(item, ast.ModulePath):
542
- path_alias[item.path_str] = (
542
+ path_alias[item.dot_path_str] = (
543
543
  item.alias.sym_name if item.alias else None
544
544
  )
545
545
 
@@ -828,7 +828,7 @@ class PyastGenPass(Pass):
828
828
  typecheck_nodes.append(
829
829
  self.sync(
830
830
  py_node=ast3.ImportFrom(
831
- module=(source.path_str.lstrip(".") if source else None),
831
+ module=(source.dot_path_str.lstrip(".") if source else None),
832
832
  names=[self.sync(ast3.alias(name="*"), node)],
833
833
  level=0,
834
834
  ),
@@ -842,7 +842,7 @@ class PyastGenPass(Pass):
842
842
  self.sync(
843
843
  ast3.ImportFrom(
844
844
  module=(
845
- node.from_loc.path_str.lstrip(".")
845
+ node.from_loc.dot_path_str.lstrip(".")
846
846
  if node.from_loc
847
847
  else None
848
848
  ),
@@ -879,7 +879,7 @@ class PyastGenPass(Pass):
879
879
  node.gen.py_ast = [
880
880
  self.sync(
881
881
  ast3.alias(
882
- name=f"{node.path_str}",
882
+ name=f"{node.dot_path_str}",
883
883
  asname=node.alias.sym_name if node.alias else None,
884
884
  )
885
885
  )
@@ -2367,7 +2367,22 @@ class PyastGenPass(Pass):
2367
2367
  node.left.gen.py_ast[0],
2368
2368
  node.right.gen.py_ast[0],
2369
2369
  self.sync(
2370
- ast3.Constant(value=node.op.edge_spec.edge_dir.name)
2370
+ ast3.Attribute(
2371
+ value=self.sync(
2372
+ ast3.Attribute(
2373
+ value=self.sync(
2374
+ ast3.Name(
2375
+ id=Con.JAC_FEATURE.value,
2376
+ ctx=ast3.Load(),
2377
+ )
2378
+ ),
2379
+ attr="EdgeDir",
2380
+ ctx=ast3.Load(),
2381
+ )
2382
+ ),
2383
+ attr=node.op.edge_spec.edge_dir.name,
2384
+ ctx=ast3.Load(),
2385
+ )
2371
2386
  ),
2372
2387
  (
2373
2388
  node.op.edge_spec.filter_cond.gen.py_ast[0]
@@ -2626,6 +2641,31 @@ class PyastGenPass(Pass):
2626
2641
  ]
2627
2642
  elif node.op.name in [Tok.STAR_POW]:
2628
2643
  node.gen.py_ast = node.operand.gen.py_ast
2644
+ elif node.op.name in [Tok.BW_AND]:
2645
+ node.gen.py_ast = [
2646
+ self.sync(
2647
+ ast3.Call(
2648
+ func=self.sync(
2649
+ ast3.Attribute(
2650
+ value=self.sync(
2651
+ ast3.Name(id=Con.JAC_FEATURE.value, ctx=ast3.Load())
2652
+ ),
2653
+ attr="get_object",
2654
+ ctx=ast3.Load(),
2655
+ )
2656
+ ),
2657
+ args=[],
2658
+ keywords=[
2659
+ self.sync(
2660
+ ast3.keyword(
2661
+ arg="id",
2662
+ value=node.operand.gen.py_ast[0],
2663
+ )
2664
+ ),
2665
+ ],
2666
+ )
2667
+ )
2668
+ ]
2629
2669
  else:
2630
2670
  self.ice(f"Unknown Unary operator {node.op.value}")
2631
2671
 
@@ -128,6 +128,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
128
128
  is_imported=False,
129
129
  kid=valid,
130
130
  )
131
+ ret.is_raised_from_py = True
131
132
  return self.nu(ret)
132
133
 
133
134
  def proc_function_def(
@@ -162,6 +162,13 @@ class PyJacAstLinkPass(Pass):
162
162
  py_nodes=node.parent.signature.return_type.gen.py_ast,
163
163
  )
164
164
 
165
+ if isinstance(node.decl_link, ast.Ability) and isinstance(
166
+ node.target, ast.ArchRefChain
167
+ ):
168
+ for arch in node.target.archs:
169
+ if arch.arch_name.sym:
170
+ arch.arch_name.sym.add_use(arch.arch_name)
171
+
165
172
  def exit_param_var(self, node: ast.ParamVar) -> None:
166
173
  """Sub objects.
167
174
 
@@ -19,11 +19,11 @@ from .type_check_pass import JacTypeCheckPass # noqa: I100
19
19
  from .fuse_typeinfo_pass import FuseTypeInfoPass # noqa: I100
20
20
  from .registry_pass import RegistryPass # noqa: I100
21
21
  from .access_modifier_pass import AccessCheckPass # noqa: I100
22
+ from .py_collect_dep_pass import PyCollectDepsPass # noqa: I100
22
23
 
23
24
  py_code_gen = [
24
25
  SubNodeTabPass,
25
26
  JacImportPass,
26
- PyImportPass,
27
27
  SymTabBuildPass,
28
28
  DeclImplMatchPass,
29
29
  DefUsePass,
@@ -33,6 +33,13 @@ py_code_gen = [
33
33
  PyBytecodeGenPass,
34
34
  ]
35
35
 
36
- type_checker_sched = [JacTypeCheckPass, FuseTypeInfoPass, AccessCheckPass]
36
+ type_checker_sched = [
37
+ JacTypeCheckPass,
38
+ PyCollectDepsPass,
39
+ PyImportPass,
40
+ DefUsePass,
41
+ FuseTypeInfoPass,
42
+ AccessCheckPass,
43
+ ]
37
44
  py_code_gen_typed = [*py_code_gen, *type_checker_sched]
38
45
  py_compiler = [*py_code_gen, PyOutPass]
@@ -19,12 +19,16 @@ class SymTabBuildPass(Pass):
19
19
  """Before pass."""
20
20
  self.cur_sym_tab: list[SymbolTable] = []
21
21
 
22
- def push_scope(self, name: str, key_node: ast.AstNode, fresh: bool = False) -> None:
22
+ def push_scope(self, name: str, key_node: ast.AstNode) -> None:
23
23
  """Push scope."""
24
- if fresh:
24
+ inherit = key_node.parent
25
+ if not len(self.cur_sym_tab) and not inherit:
25
26
  self.cur_sym_tab.append(SymbolTable(name, key_node))
27
+ elif not len(self.cur_sym_tab) and inherit:
28
+ self.cur_sym_tab.append(inherit.sym_tab)
29
+ self.cur_sym_tab.append(self.cur_scope.push_kid_scope(name, key_node))
26
30
  else:
27
- self.cur_sym_tab.append(self.cur_scope.push_scope(name, key_node))
31
+ self.cur_sym_tab.append(self.cur_scope.push_kid_scope(name, key_node))
28
32
 
29
33
  def pop_scope(self) -> SymbolTable:
30
34
  """Pop scope."""
@@ -48,7 +52,7 @@ class SymTabBuildPass(Pass):
48
52
  mod_path: str,
49
53
  is_imported: bool,
50
54
  """
51
- self.push_scope(node.name, node, fresh=(node == self.ir))
55
+ self.push_scope(node.name, node)
52
56
  self.sync_node_to_scope(node)
53
57
  for obj in dir(builtins):
54
58
  builtin = ast.Name(
@@ -197,7 +201,7 @@ class SymTabBuildPass(Pass):
197
201
  source = node.items.items[0]
198
202
  if not isinstance(source, ast.ModulePath) or not source.sub_module:
199
203
  self.error(
200
- f"Module {node.from_loc.path_str if node.from_loc else 'from location'}"
204
+ f"Module {node.from_loc.dot_path_str if node.from_loc else 'from location'}"
201
205
  f" not found to include *, or ICE occurred!"
202
206
  )
203
207
  else:
@@ -6,4 +6,4 @@ with entry {
6
6
  foo();
7
7
  bar();
8
8
  baz();
9
- }
9
+ }
@@ -0,0 +1,29 @@
1
+ import:py math;
2
+ import:py argparse;
3
+ import:py from pygame_mock { color, display }
4
+ import:py pygame_mock;
5
+ import:py os;
6
+
7
+ can fool_me -> `Type[pygame_mock.constants.CL] {
8
+ return pygame_mock.constants.CL;
9
+ }
10
+
11
+ obj kk {
12
+ can fool_me -> `Type[pygame_mock.constants.CL] {
13
+ return pygame_mock.constants.CL;
14
+ }
15
+ }
16
+
17
+ with entry {
18
+ b = math.floor(1.7);
19
+ c: color.Color = color.Color(pygame_mock.constants.CONST_VALUE);
20
+ c2: pygame_mock.color.Color = color.Color(pygame_mock.constants.CL.CONST_VALUE2);
21
+ c3: pygame_mock.color.Color = color.Color(fool_me().CONST_VALUE2);
22
+ c4: pygame_mock.color.Color = color.Color(kk().fool_me().CONST_VALUE2);
23
+ g = fool_me();
24
+ c4: pygame_mock.color.Color = color.Color(g.CONST_VALUE2);
25
+ a: argparse.ArgumentParser = argparse.ArgumentParser();
26
+ print("Hello", 1, b);
27
+ pygame_mock.display.set_mode(WIN_WIDTH, WIN_HEIGHT);
28
+ print(os.path.isfile("/jj"));
29
+ }
@@ -0,0 +1,3 @@
1
+ from .display import *
2
+ from .color import *
3
+ from .constants import *
@@ -0,0 +1,3 @@
1
+ class Color:
2
+ def __init__(self, value: int | str) -> None:
3
+ pass
@@ -0,0 +1,5 @@
1
+ CONST_VALUE: int = 0
2
+
3
+
4
+ class CL:
5
+ CONST_VALUE2: str = "h"
@@ -0,0 +1,2 @@
1
+ def set_mode(a, b):
2
+ pass
@@ -1,8 +1,15 @@
1
1
  """Test pass module."""
2
2
 
3
+ import io
4
+ import re
5
+ import sys
6
+
3
7
  import jaclang.compiler.absyntree as ast
8
+ from jaclang.cli import cli
4
9
  from jaclang.compiler.compile import jac_file_to_pass
5
10
  from jaclang.compiler.passes.main import JacImportPass
11
+ from jaclang.compiler.passes.main.fuse_typeinfo_pass import FuseTypeInfoPass
12
+ from jaclang.compiler.passes.main.schedules import py_code_gen_typed
6
13
  from jaclang.utils.test import TestCase
7
14
 
8
15
 
@@ -24,7 +31,7 @@ class ImportPassPassTests(TestCase):
24
31
  state = jac_file_to_pass(self.fixture_abs_path("autoimpl.jac"), JacImportPass)
25
32
  num_modules = len(state.ir.get_all_sub_nodes(ast.Module))
26
33
  mod_names = [i.name for i in state.ir.get_all_sub_nodes(ast.Module)]
27
- self.assertEqual(num_modules, 3)
34
+ self.assertEqual(num_modules, 4)
28
35
  self.assertIn("getme.impl", mod_names)
29
36
  self.assertIn("autoimpl.impl", mod_names)
30
37
  self.assertIn("autoimpl.something.else.impl", mod_names)
@@ -36,7 +43,7 @@ class ImportPassPassTests(TestCase):
36
43
  )
37
44
  num_modules = len(state.ir.get_all_sub_nodes(ast.Module))
38
45
  mod_names = [i.name for i in state.ir.get_all_sub_nodes(ast.Module)]
39
- self.assertEqual(num_modules, 4)
46
+ self.assertEqual(num_modules, 5)
40
47
  self.assertIn("getme.impl", mod_names)
41
48
  self.assertIn("autoimpl", mod_names)
42
49
  self.assertIn("autoimpl.impl", mod_names)
@@ -52,17 +59,69 @@ class ImportPassPassTests(TestCase):
52
59
  if i.name != "autoimpl":
53
60
  count += 1
54
61
  self.assertEqual(i.annexable_by, self.fixture_abs_path("autoimpl.jac"))
55
- self.assertEqual(count, 3)
62
+ self.assertEqual(count, 4)
63
+
64
+ def test_py_raise_map(self) -> None:
65
+ """Basic test for pass."""
66
+ build = jac_file_to_pass(
67
+ self.fixture_abs_path("py_imp_test.jac"),
68
+ FuseTypeInfoPass,
69
+ schedule=py_code_gen_typed,
70
+ )
71
+ assert isinstance(build.ir, ast.Module)
72
+ p = {
73
+ "math": "jaclang/jaclang/vendor/mypy/typeshed/stdlib/math.pyi",
74
+ "pygame_mock": "pygame_mock/__init__.py",
75
+ "pygame_mock.color": "pygame_mock/color.py",
76
+ "pygame_mock.constants": "pygame_mock/constants.py",
77
+ "argparse": "jaclang/vendor/mypy/typeshed/stdlib/argparse.pyi",
78
+ "builtins": "jaclang/vendor/mypy/typeshed/stdlib/builtins.pyi",
79
+ "pygame_mock.display": "pygame_mock/display.py",
80
+ "os": "jaclang/vendor/mypy/typeshed/stdlib/os/__init__.pyi",
81
+ "genericpath": "jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi",
82
+ }
83
+ for i in p:
84
+ self.assertIn(i, build.ir.py_raise_map)
85
+ self.assertIn(p[i], re.sub(r".*fixtures/", "", build.ir.py_raise_map[i]))
56
86
 
57
- def test_py_resolve_list(self) -> None:
87
+ def test_py_raised_mods(self) -> None:
58
88
  """Basic test for pass."""
59
- state: JacImportPass = jac_file_to_pass(
60
- self.examples_abs_path("rpg_game/jac_impl/jac_impl_5/main.jac"),
61
- JacImportPass,
89
+ state = jac_file_to_pass(
90
+ self.fixture_abs_path("py_imp_test.jac"), schedule=py_code_gen_typed
91
+ )
92
+ self.assertEqual(
93
+ len(
94
+ list(
95
+ filter(
96
+ lambda x: x.is_raised_from_py,
97
+ state.ir.get_all_sub_nodes(ast.Module),
98
+ )
99
+ )
100
+ ),
101
+ 7,
62
102
  )
63
- self.assertGreater(len(state.py_resolve_list), 20)
64
- self.assertIn("pygame.sprite.Sprite.__init__", state.py_resolve_list)
65
- self.assertIn("pygame.mouse.get_pressed", state.py_resolve_list)
66
- self.assertIn("pygame.K_SPACE", state.py_resolve_list)
67
- self.assertIn("random.randint", state.py_resolve_list)
68
- self.assertIn("pygame.font.Font", state.py_resolve_list)
103
+
104
+ # def test_py_resolve_list(self) -> None:
105
+ # """Basic test for pass."""
106
+ # state: JacImportPass = jac_file_to_pass(
107
+ # self.examples_abs_path("rpg_game/jac_impl/jac_impl_5/main.jac"),
108
+ # JacImportPass,
109
+ # )
110
+ # self.assertGreater(len(state.py_resolve_list), 20)
111
+ # self.assertIn("pygame.sprite.Sprite.__init__", state.py_resolve_list)
112
+ # self.assertIn("pygame.mouse.get_pressed", state.py_resolve_list)
113
+ # self.assertIn("pygame.K_SPACE", state.py_resolve_list)
114
+ # self.assertIn("random.randint", state.py_resolve_list)
115
+ # self.assertIn("pygame.font.Font", state.py_resolve_list)
116
+
117
+ def test_double_empty_anx(self) -> None:
118
+ """Test importing python."""
119
+ captured_output = io.StringIO()
120
+ sys.stdout = captured_output
121
+ cli.run(self.fixture_abs_path("autoimpl.jac"))
122
+ cli.run(self.fixture_abs_path("autoimpl.jac"))
123
+ sys.stdout = sys.__stdout__
124
+ stdout_value = captured_output.getvalue()
125
+ self.assertIn("foo", stdout_value)
126
+ self.assertIn("bar", stdout_value)
127
+ self.assertIn("baz", stdout_value)