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
jaclang/cli/cli.py CHANGED
@@ -2,14 +2,12 @@
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
9
8
  import shutil
10
9
  import types
11
10
  from typing import Optional
12
- from uuid import UUID
13
11
 
14
12
  import jaclang.compiler.absyntree as ast
15
13
  from jaclang import jac_import
@@ -22,8 +20,9 @@ from jaclang.compiler.passes.tool.schedules import format_pass
22
20
  from jaclang.plugin.builtin import dotgen
23
21
  from jaclang.plugin.feature import JacCmd as Cmd
24
22
  from jaclang.plugin.feature import JacFeature as Jac
25
- from jaclang.runtimelib.constructs import Architype
26
- from jaclang.runtimelib.machine import JacProgram
23
+ from jaclang.runtimelib.constructs import WalkerArchitype
24
+ from jaclang.runtimelib.context import ExecutionContext
25
+ from jaclang.runtimelib.machine import JacMachine, JacProgram
27
26
  from jaclang.utils.helpers import debugger as db
28
27
  from jaclang.utils.lang_tools import AstTool
29
28
 
@@ -68,12 +67,7 @@ def format(path: str, outfile: str = "", debug: bool = False) -> None:
68
67
 
69
68
  @cmd_registry.register
70
69
  def run(
71
- filename: str,
72
- session: str = "",
73
- main: bool = True,
74
- cache: bool = True,
75
- walker: str = "",
76
- node: str = "",
70
+ filename: str, session: str = "", main: bool = True, cache: bool = True
77
71
  ) -> None:
78
72
  """Run the specified .jac file."""
79
73
  # if no session specified, check if it was defined when starting the command shell
@@ -90,78 +84,89 @@ def run(
90
84
  base, mod = os.path.split(filename)
91
85
  base = base if base else "./"
92
86
  mod = mod[:-4]
93
- Jac.context().init_memory(base_path=base, session=session)
87
+
88
+ jctx = ExecutionContext.create(session=session)
89
+
94
90
  if filename.endswith(".jac"):
95
- ret_module = jac_import(
91
+ jac_import(
96
92
  target=mod,
97
93
  base_path=base,
98
94
  cachable=cache,
99
95
  override_name="__main__" if main else None,
100
96
  )
101
- if ret_module is None:
102
- loaded_mod = None
103
- else:
104
- (loaded_mod,) = ret_module
105
97
  elif filename.endswith(".jir"):
106
98
  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(
99
+ JacMachine(base).attach_program(
100
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
101
+ )
102
+ jac_import(
111
103
  target=mod,
112
104
  base_path=base,
113
105
  cachable=cache,
114
106
  override_name="__main__" if main else None,
115
107
  )
116
- if ret_module is None:
117
- loaded_mod = None
118
- else:
119
- (loaded_mod,) = ret_module
120
108
  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.")
109
+ jctx.close()
110
+ JacMachine.detach()
111
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
140
112
 
141
- Jac.reset_context()
113
+ jctx.close()
114
+ JacMachine.detach()
142
115
 
143
116
 
144
117
  @cmd_registry.register
145
- def get_object(id: str, session: str = "") -> dict:
118
+ def get_object(
119
+ filename: str, id: str, session: str = "", main: bool = True, cache: bool = True
120
+ ) -> dict:
146
121
  """Get the object with the specified id."""
147
122
  if session == "":
148
- session = cmd_registry.args.session if "session" in cmd_registry.args else ""
123
+ session = (
124
+ cmd_registry.args.session
125
+ if hasattr(cmd_registry, "args")
126
+ and hasattr(cmd_registry.args, "session")
127
+ and cmd_registry.args.session
128
+ else ""
129
+ )
149
130
 
150
- Jac.context().init_memory(session=session)
131
+ base, mod = os.path.split(filename)
132
+ base = base if base else "./"
133
+ mod = mod[:-4]
151
134
 
152
- if id == "root":
153
- id_uuid = UUID(int=0)
154
- else:
155
- id_uuid = UUID(id)
135
+ jctx = ExecutionContext.create(session=session)
156
136
 
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 {}
137
+ if filename.endswith(".jac"):
138
+ jac_import(
139
+ target=mod,
140
+ base_path=base,
141
+ cachable=cache,
142
+ override_name="__main__" if main else None,
143
+ )
144
+ elif filename.endswith(".jir"):
145
+ with open(filename, "rb") as f:
146
+ JacMachine(base).attach_program(
147
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
148
+ )
149
+ jac_import(
150
+ target=mod,
151
+ base_path=base,
152
+ cachable=cache,
153
+ override_name="__main__" if main else None,
154
+ )
155
+ else:
156
+ jctx.close()
157
+ JacMachine.detach()
158
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
159
+
160
+ data = {}
161
+ obj = Jac.get_object(id)
162
+ if obj:
163
+ data = obj.__jac__.__getstate__()
162
164
  else:
163
- Jac.reset_context()
164
- return obj.__getstate__()
165
+ print(f"Object with id {id} not found.")
166
+
167
+ jctx.close()
168
+ JacMachine.detach()
169
+ return data
165
170
 
166
171
 
167
172
  @cmd_registry.register
@@ -211,25 +216,78 @@ def lsp() -> None:
211
216
 
212
217
 
213
218
  @cmd_registry.register
214
- def enter(filename: str, entrypoint: str, args: list) -> None:
215
- """Run the specified entrypoint function in the given .jac file.
219
+ def enter(
220
+ filename: str,
221
+ entrypoint: str,
222
+ args: list,
223
+ session: str = "",
224
+ main: bool = True,
225
+ cache: bool = True,
226
+ root: str = "",
227
+ node: str = "",
228
+ ) -> None:
229
+ """
230
+ Run the specified entrypoint function in the given .jac file.
216
231
 
217
232
  :param filename: The path to the .jac file.
218
233
  :param entrypoint: The name of the entrypoint function.
219
234
  :param args: Arguments to pass to the entrypoint function.
235
+ :param session: shelve.Shelf file path.
236
+ :param root: root executor.
237
+ :param node: starting node.
220
238
  """
239
+ if session == "":
240
+ session = (
241
+ cmd_registry.args.session
242
+ if hasattr(cmd_registry, "args")
243
+ and hasattr(cmd_registry.args, "session")
244
+ and cmd_registry.args.session
245
+ else ""
246
+ )
247
+
248
+ base, mod = os.path.split(filename)
249
+ base = base if base else "./"
250
+ mod = mod[:-4]
251
+
252
+ jctx = ExecutionContext.create(session=session, root=root)
253
+
221
254
  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:
255
+ ret_module = jac_import(
256
+ target=mod,
257
+ base_path=base,
258
+ cachable=cache,
259
+ override_name="__main__" if main else None,
260
+ )
261
+ elif filename.endswith(".jir"):
262
+ with open(filename, "rb") as f:
263
+ JacMachine(base).attach_program(
264
+ JacProgram(mod_bundle=pickle.load(f), bytecode=None)
265
+ )
266
+ ret_module = jac_import(
267
+ target=mod,
268
+ base_path=base,
269
+ cachable=cache,
270
+ override_name="__main__" if main else None,
271
+ )
272
+ else:
273
+ jctx.close()
274
+ JacMachine.detach()
275
+ raise ValueError("Not a valid file!\nOnly supports `.jac` and `.jir`")
276
+
277
+ if ret_module:
278
+ (loaded_mod,) = ret_module
279
+ if not loaded_mod:
227
280
  print("Errors occurred while importing the module.")
228
- return
229
281
  else:
230
- getattr(mod, entrypoint)(*args)
231
- else:
232
- print("Not a .jac file.")
282
+ architype = getattr(loaded_mod, entrypoint)(*args)
283
+
284
+ jctx.set_entry_node(node)
285
+
286
+ if isinstance(architype, WalkerArchitype) and jctx.validate_access():
287
+ Jac.spawn_call(jctx.entry_node.architype, architype)
288
+
289
+ jctx.close()
290
+ JacMachine.detach()
233
291
 
234
292
 
235
293
  @cmd_registry.register
@@ -252,6 +310,8 @@ def test(
252
310
 
253
311
  jac test => jac test -d .
254
312
  """
313
+ jctx = ExecutionContext.create()
314
+
255
315
  failcount = Jac.run_test(
256
316
  filepath=filepath,
257
317
  filter=filter,
@@ -260,6 +320,9 @@ def test(
260
320
  directory=directory,
261
321
  verbose=verbose,
262
322
  )
323
+
324
+ jctx.close()
325
+
263
326
  if failcount:
264
327
  raise SystemExit(f"Tests failed: {failcount}")
265
328
 
@@ -361,13 +424,13 @@ def dot(
361
424
  base, mod = os.path.split(filename)
362
425
  base = base if base else "./"
363
426
  mod = mod[:-4]
364
- Jac.context().init_memory(base_path=base, session=session)
427
+
428
+ jctx = ExecutionContext.create(session=session)
429
+
365
430
  if filename.endswith(".jac"):
366
- jac_import(
367
- target=mod,
368
- base_path=base,
369
- )
370
- module = importlib.import_module(mod)
431
+ jac_machine = JacMachine(base)
432
+ jac_import(target=mod, base_path=base)
433
+ module = jac_machine.loaded_modules.get(mod)
371
434
  globals().update(vars(module))
372
435
  try:
373
436
  node = globals().get(initial, eval(initial)) if initial else None
@@ -385,7 +448,7 @@ def dot(
385
448
  import traceback
386
449
 
387
450
  traceback.print_exc()
388
- Jac.reset_context()
451
+ jctx.close()
389
452
  return
390
453
  file_name = saveto if saveto else f"{mod}.dot"
391
454
  with open(file_name, "w") as file:
@@ -394,7 +457,7 @@ def dot(
394
457
  else:
395
458
  print("Not a .jac file.")
396
459
 
397
- Jac.reset_context()
460
+ jctx.close()
398
461
 
399
462
 
400
463
  @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