jaclang 0.7.16__py3-none-any.whl → 0.7.17__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 (77) hide show
  1. jaclang/cli/cli.py +140 -75
  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 +21 -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 +11 -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 +39 -0
  32. jaclang/langserve/server.py +16 -1
  33. jaclang/langserve/tests/fixtures/rename.jac +30 -0
  34. jaclang/langserve/tests/test_server.py +216 -2
  35. jaclang/langserve/utils.py +21 -2
  36. jaclang/plugin/default.py +78 -70
  37. jaclang/plugin/feature.py +7 -17
  38. jaclang/plugin/spec.py +6 -19
  39. jaclang/plugin/tests/fixtures/other_root_access.jac +82 -0
  40. jaclang/plugin/tests/test_jaseci.py +414 -42
  41. jaclang/runtimelib/architype.py +481 -333
  42. jaclang/runtimelib/constructs.py +5 -8
  43. jaclang/runtimelib/context.py +89 -69
  44. jaclang/runtimelib/importer.py +15 -15
  45. jaclang/runtimelib/machine.py +66 -2
  46. jaclang/runtimelib/memory.py +134 -75
  47. jaclang/runtimelib/utils.py +17 -10
  48. jaclang/settings.py +2 -4
  49. jaclang/tests/fixtures/access_checker.jac +12 -17
  50. jaclang/tests/fixtures/access_modifier.jac +88 -33
  51. jaclang/tests/fixtures/baddy.jac +3 -0
  52. jaclang/tests/fixtures/bar.jac +34 -0
  53. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  54. jaclang/tests/fixtures/edge_ops.jac +1 -1
  55. jaclang/tests/fixtures/edges_walk.jac +1 -1
  56. jaclang/tests/fixtures/foo.jac +43 -0
  57. jaclang/tests/fixtures/game1.jac +1 -1
  58. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  59. jaclang/tests/fixtures/import.jac +9 -0
  60. jaclang/tests/fixtures/index_slice.jac +30 -0
  61. jaclang/tests/fixtures/pyfunc_1.py +1 -1
  62. jaclang/tests/fixtures/pyfunc_2.py +2 -2
  63. jaclang/tests/fixtures/pygame_mock/__init__.py +3 -0
  64. jaclang/tests/fixtures/pygame_mock/color.py +3 -0
  65. jaclang/tests/fixtures/pygame_mock/constants.py +5 -0
  66. jaclang/tests/fixtures/pygame_mock/display.py +2 -0
  67. jaclang/tests/fixtures/pygame_mock/inner/__init__.py +0 -0
  68. jaclang/tests/fixtures/pygame_mock/inner/iner_mod.py +2 -0
  69. jaclang/tests/test_cli.py +49 -6
  70. jaclang/tests/test_language.py +113 -78
  71. jaclang/tests/test_reference.py +2 -9
  72. jaclang/utils/treeprinter.py +30 -3
  73. {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/METADATA +1 -1
  74. {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/RECORD +77 -56
  75. /jaclang/tests/fixtures/{err.test.jac → baddy.test.jac} +0 -0
  76. {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/WHEEL +0 -0
  77. {jaclang-0.7.16.dist-info → jaclang-0.7.17.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import ast as ast3
4
4
  import importlib
5
- import inspect
6
5
  import marshal
7
6
  import os
8
7
  import pickle
@@ -22,8 +21,9 @@ from jaclang.compiler.passes.tool.schedules import format_pass
22
21
  from jaclang.plugin.builtin import dotgen
23
22
  from jaclang.plugin.feature import JacCmd as Cmd
24
23
  from jaclang.plugin.feature import JacFeature as Jac
25
- from jaclang.runtimelib.constructs import Architype
26
- from jaclang.runtimelib.machine import JacProgram
24
+ from jaclang.runtimelib.constructs import WalkerArchitype
25
+ from jaclang.runtimelib.context import ExecutionContext
26
+ from jaclang.runtimelib.machine import JacMachine, JacProgram
27
27
  from jaclang.utils.helpers import debugger as db
28
28
  from jaclang.utils.lang_tools import AstTool
29
29
 
@@ -68,12 +68,7 @@ def format(path: str, outfile: str = "", debug: bool = False) -> None:
68
68
 
69
69
  @cmd_registry.register
70
70
  def run(
71
- filename: str,
72
- session: str = "",
73
- main: bool = True,
74
- cache: bool = True,
75
- walker: str = "",
76
- node: str = "",
71
+ filename: str, session: str = "", main: bool = True, cache: bool = True
77
72
  ) -> None:
78
73
  """Run the specified .jac file."""
79
74
  # if no session specified, check if it was defined when starting the command shell
@@ -90,78 +85,90 @@ def run(
90
85
  base, mod = os.path.split(filename)
91
86
  base = base if base else "./"
92
87
  mod = mod[:-4]
93
- Jac.context().init_memory(base_path=base, session=session)
88
+
89
+ jctx = ExecutionContext.create(session=session)
90
+
94
91
  if filename.endswith(".jac"):
95
- ret_module = jac_import(
92
+ jac_import(
96
93
  target=mod,
97
94
  base_path=base,
98
95
  cachable=cache,
99
96
  override_name="__main__" if main else None,
100
97
  )
101
- if ret_module is None:
102
- loaded_mod = None
103
- else:
104
- (loaded_mod,) = ret_module
105
98
  elif filename.endswith(".jir"):
106
99
  with open(filename, "rb") as f:
107
- ir = pickle.load(f)
108
- jac_program = JacProgram(mod_bundle=ir, bytecode=None)
109
- Jac.context().jac_machine.attach_program(jac_program)
110
- ret_module = jac_import(
100
+ JacMachine(base).attach_program(
101
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
102
+ )
103
+ jac_import(
111
104
  target=mod,
112
105
  base_path=base,
113
106
  cachable=cache,
114
107
  override_name="__main__" if main else None,
115
108
  )
116
- if ret_module is None:
117
- loaded_mod = None
118
- else:
119
- (loaded_mod,) = ret_module
120
109
  else:
121
- print("Not a .jac file.")
122
- return
123
-
124
- if not node or node == "root":
125
- entrypoint: Architype = Jac.get_root()
126
- else:
127
- obj = Jac.context().get_obj(UUID(node))
128
- if obj is None:
129
- print(f"Entrypoint {node} not found.")
130
- return
131
- entrypoint = obj
132
-
133
- # TODO: handle no override name
134
- if walker:
135
- walker_module = dict(inspect.getmembers(loaded_mod)).get(walker)
136
- if walker_module:
137
- Jac.spawn_call(entrypoint, walker_module())
138
- else:
139
- print(f"Walker {walker} not found.")
110
+ jctx.close()
111
+ JacMachine.detach()
112
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
140
113
 
141
- Jac.reset_context()
114
+ jctx.close()
115
+ JacMachine.detach()
142
116
 
143
117
 
144
118
  @cmd_registry.register
145
- def get_object(id: str, session: str = "") -> dict:
119
+ def get_object(
120
+ filename: str, id: str, session: str = "", main: bool = True, cache: bool = True
121
+ ) -> dict:
146
122
  """Get the object with the specified id."""
147
123
  if session == "":
148
- session = cmd_registry.args.session if "session" in cmd_registry.args else ""
124
+ session = (
125
+ cmd_registry.args.session
126
+ if hasattr(cmd_registry, "args")
127
+ and hasattr(cmd_registry.args, "session")
128
+ and cmd_registry.args.session
129
+ else ""
130
+ )
149
131
 
150
- Jac.context().init_memory(session=session)
132
+ base, mod = os.path.split(filename)
133
+ base = base if base else "./"
134
+ mod = mod[:-4]
151
135
 
152
- if id == "root":
153
- id_uuid = UUID(int=0)
136
+ jctx = ExecutionContext.create(session=session)
137
+
138
+ if filename.endswith(".jac"):
139
+ jac_import(
140
+ target=mod,
141
+ base_path=base,
142
+ cachable=cache,
143
+ override_name="__main__" if main else None,
144
+ )
145
+ elif filename.endswith(".jir"):
146
+ with open(filename, "rb") as f:
147
+ JacMachine(base).attach_program(
148
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
149
+ )
150
+ jac_import(
151
+ target=mod,
152
+ base_path=base,
153
+ cachable=cache,
154
+ override_name="__main__" if main else None,
155
+ )
154
156
  else:
155
- id_uuid = UUID(id)
157
+ jctx.close()
158
+ JacMachine.detach()
159
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
156
160
 
157
- obj = Jac.context().get_obj(id_uuid)
158
- if obj is None:
159
- print(f"Object with id {id} not found.")
160
- Jac.reset_context()
161
- return {}
161
+ data = {}
162
+ if id == "root":
163
+ data = jctx.root.__getstate__()
164
+ elif obj := jctx.mem.find_by_id(UUID(id)):
165
+ data = obj.__getstate__()
162
166
  else:
163
- Jac.reset_context()
164
- return obj.__getstate__()
167
+ print(f"Object with id {id} not found.")
168
+
169
+ jctx.close()
170
+ JacMachine.detach()
171
+ return data
165
172
 
166
173
 
167
174
  @cmd_registry.register
@@ -211,25 +218,78 @@ def lsp() -> None:
211
218
 
212
219
 
213
220
  @cmd_registry.register
214
- def enter(filename: str, entrypoint: str, args: list) -> None:
215
- """Run the specified entrypoint function in the given .jac file.
221
+ def enter(
222
+ filename: str,
223
+ entrypoint: str,
224
+ args: list,
225
+ session: str = "",
226
+ main: bool = True,
227
+ cache: bool = True,
228
+ root: str = "",
229
+ node: str = "",
230
+ ) -> None:
231
+ """
232
+ Run the specified entrypoint function in the given .jac file.
216
233
 
217
234
  :param filename: The path to the .jac file.
218
235
  :param entrypoint: The name of the entrypoint function.
219
236
  :param args: Arguments to pass to the entrypoint function.
237
+ :param session: shelve.Shelf file path.
238
+ :param root: root executor.
239
+ :param node: starting node.
220
240
  """
241
+ if session == "":
242
+ session = (
243
+ cmd_registry.args.session
244
+ if hasattr(cmd_registry, "args")
245
+ and hasattr(cmd_registry.args, "session")
246
+ and cmd_registry.args.session
247
+ else ""
248
+ )
249
+
250
+ base, mod = os.path.split(filename)
251
+ base = base if base else "./"
252
+ mod = mod[:-4]
253
+
254
+ jctx = ExecutionContext.create(session=session, root=root)
255
+
221
256
  if filename.endswith(".jac"):
222
- base, mod_name = os.path.split(filename)
223
- base = base if base else "./"
224
- mod_name = mod_name[:-4]
225
- (mod,) = jac_import(target=mod_name, base_path=base)
226
- if not mod:
257
+ ret_module = jac_import(
258
+ target=mod,
259
+ base_path=base,
260
+ cachable=cache,
261
+ override_name="__main__" if main else None,
262
+ )
263
+ elif filename.endswith(".jir"):
264
+ with open(filename, "rb") as f:
265
+ JacMachine(base).attach_program(
266
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
267
+ )
268
+ ret_module = jac_import(
269
+ target=mod,
270
+ base_path=base,
271
+ cachable=cache,
272
+ override_name="__main__" if main else None,
273
+ )
274
+ else:
275
+ jctx.close()
276
+ JacMachine.detach()
277
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
278
+
279
+ if ret_module:
280
+ (loaded_mod,) = ret_module
281
+ if not loaded_mod:
227
282
  print("Errors occurred while importing the module.")
228
- return
229
283
  else:
230
- getattr(mod, entrypoint)(*args)
231
- else:
232
- print("Not a .jac file.")
284
+ architype = getattr(loaded_mod, entrypoint)(*args)
285
+
286
+ jctx.set_entry_node(node)
287
+
288
+ if isinstance(architype, WalkerArchitype) and jctx.validate_access():
289
+ Jac.spawn_call(jctx.entry_node.architype, architype)
290
+
291
+ jctx.close()
292
+ JacMachine.detach()
233
293
 
234
294
 
235
295
  @cmd_registry.register
@@ -252,6 +312,8 @@ def test(
252
312
 
253
313
  jac test => jac test -d .
254
314
  """
315
+ jctx = ExecutionContext.create()
316
+
255
317
  failcount = Jac.run_test(
256
318
  filepath=filepath,
257
319
  filter=filter,
@@ -260,6 +322,9 @@ def test(
260
322
  directory=directory,
261
323
  verbose=verbose,
262
324
  )
325
+
326
+ jctx.close()
327
+
263
328
  if failcount:
264
329
  raise SystemExit(f"Tests failed: {failcount}")
265
330
 
@@ -361,13 +426,13 @@ def dot(
361
426
  base, mod = os.path.split(filename)
362
427
  base = base if base else "./"
363
428
  mod = mod[:-4]
364
- Jac.context().init_memory(base_path=base, session=session)
429
+
430
+ jctx = ExecutionContext.create(session=session)
431
+
365
432
  if filename.endswith(".jac"):
366
- jac_import(
367
- target=mod,
368
- base_path=base,
369
- )
370
- module = importlib.import_module(mod)
433
+ jac_machine = JacMachine(base)
434
+ jac_import(target=mod, base_path=base)
435
+ module = jac_machine.loaded_modules.get(mod)
371
436
  globals().update(vars(module))
372
437
  try:
373
438
  node = globals().get(initial, eval(initial)) if initial else None
@@ -385,7 +450,7 @@ def dot(
385
450
  import traceback
386
451
 
387
452
  traceback.print_exc()
388
- Jac.reset_context()
453
+ jctx.close()
389
454
  return
390
455
  file_name = saveto if saveto else f"{mod}.dot"
391
456
  with open(file_name, "w") as file:
@@ -394,7 +459,7 @@ def dot(
394
459
  else:
395
460
  print("Not a .jac file.")
396
461
 
397
- Jac.reset_context()
462
+ jctx.close()
398
463
 
399
464
 
400
465
  @cmd_registry.register
@@ -630,8 +630,11 @@ class Module(AstDocNode):
630
630
  self.impl_mod: list[Module] = []
631
631
  self.test_mod: list[Module] = []
632
632
  self.mod_deps: dict[str, Module] = {}
633
+ self.py_mod_dep_map: dict[str, str] = {}
634
+ self.py_raise_map: dict[str, str] = {}
633
635
  self.registry = registry
634
636
  self.terminals: list[Token] = terminals
637
+ self.is_raised_from_py: bool = False
635
638
  AstNode.__init__(self, kid=kid)
636
639
  AstDocNode.__init__(self, doc=doc)
637
640
 
@@ -956,6 +959,7 @@ class ModulePath(AstSymbolNode):
956
959
  self.level = level
957
960
  self.alias = alias
958
961
  self.sub_module: Optional[Module] = None
962
+ self.abs_path: Optional[str] = None
959
963
 
960
964
  name_spec = alias if alias else path[0] if path else None
961
965
 
@@ -977,7 +981,7 @@ class ModulePath(AstSymbolNode):
977
981
  )
978
982
 
979
983
  @property
980
- def path_str(self) -> str:
984
+ def dot_path_str(self) -> str:
981
985
  """Get path string."""
982
986
  return ("." * self.level) + ".".join(
983
987
  [p.value for p in self.path] if self.path else [self.name_spec.sym_name]
@@ -985,7 +989,7 @@ class ModulePath(AstSymbolNode):
985
989
 
986
990
  def resolve_relative_path(self, target_item: Optional[str] = None) -> str:
987
991
  """Convert an import target string into a relative file path."""
988
- target = self.path_str
992
+ target = self.dot_path_str
989
993
  if target_item:
990
994
  target += f".{target_item}"
991
995
  base_path = os.path.dirname(self.loc.mod_path)
@@ -1048,6 +1052,7 @@ class ModuleItem(AstSymbolNode):
1048
1052
  name_spec=alias if alias else name,
1049
1053
  sym_category=SymbolType.MOD_VAR,
1050
1054
  )
1055
+ self.abs_path: Optional[str] = None
1051
1056
 
1052
1057
  @property
1053
1058
  def from_parent(self) -> Import:
@@ -4313,11 +4318,11 @@ class Ellipsis(Literal):
4313
4318
  class EmptyToken(Token):
4314
4319
  """EmptyToken node type for Jac Ast."""
4315
4320
 
4316
- def __init__(self) -> None:
4321
+ def __init__(self, file_path: str = "") -> None:
4317
4322
  """Initialize empty token."""
4318
4323
  super().__init__(
4319
4324
  name="EmptyToken",
4320
- file_path="",
4325
+ file_path=file_path,
4321
4326
  value="",
4322
4327
  line=0,
4323
4328
  end_line=0,
@@ -94,18 +94,18 @@ class Constants(StrEnum):
94
94
  HERE = "_jac_here_"
95
95
  JAC_FEATURE = "_Jac"
96
96
  ROOT = f"{JAC_FEATURE}.get_root()"
97
- EDGES_TO_NODE = "_jac_.edges_to_nodes"
98
- EDGE_REF = "_jac_.edge_ref"
99
- CONNECT_NODE = "_jac_.connect_node"
100
- DISCONNECT_NODE = "_jac_.disconnect_node"
101
- WALKER_VISIT = "_jac_.visit_node"
102
- WALKER_IGNORE = "_jac_.ignore_node"
103
- DISENGAGE = "_jac_.disengage_now"
97
+ EDGES_TO_NODE = "__jac__.edges_to_nodes"
98
+ EDGE_REF = "__jac__.edge_ref"
99
+ CONNECT_NODE = "__jac__.connect_node"
100
+ DISCONNECT_NODE = "__jac__.disconnect_node"
101
+ WALKER_VISIT = "__jac__.visit_node"
102
+ WALKER_IGNORE = "__jac__.ignore_node"
103
+ DISENGAGE = "__jac__.disengage_now"
104
104
  OBJECT_CLASS = "_jac_Object_"
105
105
  NODE_CLASS = "_jac_Node_"
106
106
  EDGE_CLASS = "_jac_Edge_"
107
107
  WALKER_CLASS = "_jac_Walker_"
108
- WITH_DIR = "_jac_.apply_dir"
108
+ WITH_DIR = "__jac__.apply_dir"
109
109
  EDGE_DIR = "_jac_Edge_Dir"
110
110
  ON_ENTRY = "_jac_ds_.on_entry"
111
111
  ON_EXIT = "_jac_ds_.on_exit"
@@ -163,7 +163,11 @@ class JacParser(Pass):
163
163
  body=body,
164
164
  is_imported=False,
165
165
  terminals=self.terminals,
166
- kid=kid if len(kid) else [ast.EmptyToken()],
166
+ kid=(
167
+ kid
168
+ if len(kid)
169
+ else [ast.EmptyToken(file_path=self.parse_ref.mod_path)]
170
+ ),
167
171
  )
168
172
  return self.nu(mod)
169
173
 
@@ -1003,7 +1007,11 @@ class JacParser(Pass):
1003
1007
  semstr=semstr,
1004
1008
  params=params,
1005
1009
  return_type=return_spec,
1006
- kid=kid if len(kid) else [ast.EmptyToken()],
1010
+ kid=(
1011
+ kid
1012
+ if len(kid)
1013
+ else [ast.EmptyToken(file_path=self.parse_ref.mod_path)]
1014
+ ),
1007
1015
  )
1008
1016
  )
1009
1017
  else:
@@ -1,8 +1,8 @@
1
1
  """Collection of passes for Jac IR."""
2
2
 
3
3
  from .sub_node_tab_pass import SubNodeTabPass
4
- from .import_pass import JacImportPass, PyImportPass # noqa: I100
5
4
  from .sym_tab_build_pass import SymTabBuildPass # noqa: I100
5
+ from .import_pass import JacImportPass, PyImportPass # noqa: I100
6
6
  from .def_impl_match_pass import DeclImplMatchPass # noqa: I100
7
7
  from .def_use_pass import DefUsePass # noqa: I100
8
8
  from .pyout_pass import PyOutPass # noqa: I100