jaclang 0.5.18__py3-none-any.whl → 0.6.1__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 (57) hide show
  1. jaclang/cli/cli.py +94 -5
  2. jaclang/cli/cmdreg.py +18 -6
  3. jaclang/compiler/__init__.py +12 -5
  4. jaclang/compiler/absyntree.py +4 -5
  5. jaclang/compiler/generated/jac_parser.py +2 -2
  6. jaclang/compiler/jac.lark +2 -2
  7. jaclang/compiler/parser.py +48 -8
  8. jaclang/compiler/passes/main/__init__.py +3 -2
  9. jaclang/compiler/passes/main/access_modifier_pass.py +173 -0
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +4 -1
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +10 -7
  12. jaclang/compiler/passes/main/import_pass.py +70 -40
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +47 -83
  14. jaclang/compiler/passes/main/pyast_load_pass.py +136 -73
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +218 -0
  16. jaclang/compiler/passes/main/pyout_pass.py +14 -13
  17. jaclang/compiler/passes/main/registry_pass.py +8 -3
  18. jaclang/compiler/passes/main/schedules.py +7 -3
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +32 -29
  20. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -2
  21. jaclang/compiler/passes/tool/jac_formatter_pass.py +83 -21
  22. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -4
  23. jaclang/compiler/passes/transform.py +2 -0
  24. jaclang/compiler/symtable.py +10 -3
  25. jaclang/compiler/tests/test_importer.py +9 -0
  26. jaclang/compiler/workspace.py +17 -5
  27. jaclang/core/aott.py +43 -63
  28. jaclang/core/construct.py +157 -21
  29. jaclang/core/importer.py +77 -65
  30. jaclang/core/llms/__init__.py +20 -0
  31. jaclang/core/llms/anthropic.py +61 -0
  32. jaclang/core/llms/base.py +206 -0
  33. jaclang/core/llms/groq.py +67 -0
  34. jaclang/core/llms/huggingface.py +73 -0
  35. jaclang/core/llms/ollama.py +78 -0
  36. jaclang/core/llms/openai.py +61 -0
  37. jaclang/core/llms/togetherai.py +60 -0
  38. jaclang/core/llms/utils.py +9 -0
  39. jaclang/core/memory.py +48 -0
  40. jaclang/core/shelve_storage.py +55 -0
  41. jaclang/core/utils.py +16 -1
  42. jaclang/plugin/__init__.py +1 -2
  43. jaclang/plugin/builtin.py +1 -1
  44. jaclang/plugin/default.py +134 -18
  45. jaclang/plugin/feature.py +35 -13
  46. jaclang/plugin/spec.py +52 -10
  47. jaclang/plugin/tests/test_jaseci.py +219 -0
  48. jaclang/settings.py +1 -1
  49. jaclang/utils/helpers.py +6 -2
  50. jaclang/utils/treeprinter.py +14 -6
  51. jaclang-0.6.1.dist-info/METADATA +17 -0
  52. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/RECORD +55 -42
  53. jaclang/core/llms.py +0 -111
  54. jaclang-0.5.18.dist-info/METADATA +0 -7
  55. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/WHEEL +0 -0
  56. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/entry_points.txt +0 -0
  57. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/top_level.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  import ast as ast3
4
4
  import importlib
5
+ import inspect
5
6
  import marshal
6
7
  import os
7
8
  import pickle
8
9
  import shutil
9
10
  import types
10
11
  from typing import Optional
12
+ from uuid import UUID
11
13
 
12
14
  import jaclang.compiler.absyntree as ast
13
15
  from jaclang import jac_import
@@ -17,6 +19,7 @@ from jaclang.compiler.constant import Constants
17
19
  from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
18
20
  from jaclang.compiler.passes.main.schedules import py_code_gen_typed
19
21
  from jaclang.compiler.passes.tool.schedules import format_pass
22
+ from jaclang.core.construct import Architype
20
23
  from jaclang.plugin.builtin import dotgen
21
24
  from jaclang.plugin.feature import JacCmd as Cmd
22
25
  from jaclang.plugin.feature import JacFeature as Jac
@@ -63,13 +66,33 @@ def format(path: str, outfile: str = "", debug: bool = False) -> None:
63
66
 
64
67
 
65
68
  @cmd_registry.register
66
- def run(filename: str, main: bool = True, cache: bool = True) -> None:
69
+ def run(
70
+ filename: str,
71
+ session: str = "",
72
+ main: bool = True,
73
+ cache: bool = True,
74
+ walker: str = "",
75
+ node: str = "",
76
+ ) -> None:
67
77
  """Run the specified .jac file."""
78
+ # if no session specified, check if it was defined when starting the command shell
79
+ # otherwise default to jaclang.session
80
+ if session == "":
81
+ session = (
82
+ cmd_registry.args.session
83
+ if hasattr(cmd_registry, "args")
84
+ and hasattr(cmd_registry.args, "session")
85
+ and cmd_registry.args.session
86
+ else ""
87
+ )
88
+
89
+ Jac.context().init_memory(session)
90
+
68
91
  base, mod = os.path.split(filename)
69
92
  base = base if base else "./"
70
93
  mod = mod[:-4]
71
94
  if filename.endswith(".jac"):
72
- jac_import(
95
+ loaded_mod = jac_import(
73
96
  target=mod,
74
97
  base_path=base,
75
98
  cachable=cache,
@@ -78,7 +101,7 @@ def run(filename: str, main: bool = True, cache: bool = True) -> None:
78
101
  elif filename.endswith(".jir"):
79
102
  with open(filename, "rb") as f:
80
103
  ir = pickle.load(f)
81
- jac_import(
104
+ loaded_mod = jac_import(
82
105
  target=mod,
83
106
  base_path=base,
84
107
  cachable=cache,
@@ -87,6 +110,49 @@ def run(filename: str, main: bool = True, cache: bool = True) -> None:
87
110
  )
88
111
  else:
89
112
  print("Not a .jac file.")
113
+ return
114
+
115
+ if not node or node == "root":
116
+ entrypoint: Architype = Jac.get_root()
117
+ else:
118
+ obj = Jac.context().get_obj(UUID(node))
119
+ if obj is None:
120
+ print(f"Entrypoint {node} not found.")
121
+ return
122
+ entrypoint = obj
123
+
124
+ # TODO: handle no override name
125
+ if walker:
126
+ walker_module = dict(inspect.getmembers(loaded_mod)).get(walker)
127
+ if walker_module:
128
+ Jac.spawn_call(entrypoint, walker_module())
129
+ else:
130
+ print(f"Walker {walker} not found.")
131
+
132
+ Jac.reset_context()
133
+
134
+
135
+ @cmd_registry.register
136
+ def get_object(id: str, session: str = "") -> dict:
137
+ """Get the object with the specified id."""
138
+ if session == "":
139
+ session = cmd_registry.args.session if "session" in cmd_registry.args else ""
140
+
141
+ Jac.context().init_memory(session)
142
+
143
+ if id == "root":
144
+ id_uuid = UUID(int=0)
145
+ else:
146
+ id_uuid = UUID(id)
147
+
148
+ obj = Jac.context().get_obj(id_uuid)
149
+ if obj is None:
150
+ print(f"Object with id {id} not found.")
151
+ Jac.reset_context()
152
+ return {}
153
+ else:
154
+ Jac.reset_context()
155
+ return obj.__getstate__()
90
156
 
91
157
 
92
158
  @cmd_registry.register
@@ -106,7 +172,7 @@ def build(filename: str) -> None:
106
172
 
107
173
 
108
174
  @cmd_registry.register
109
- def check(filename: str) -> None:
175
+ def check(filename: str, print_errs: bool = True) -> None:
110
176
  """Run type checker for a specified .jac file.
111
177
 
112
178
  :param filename: The path to the .jac file.
@@ -119,7 +185,9 @@ def check(filename: str) -> None:
119
185
 
120
186
  errs = len(out.errors_had)
121
187
  warnings = len(out.warnings_had)
122
-
188
+ if print_errs:
189
+ for e in out.errors_had:
190
+ print("Error:", e)
123
191
  print(f"Errors: {errs}, Warnings: {warnings}")
124
192
  else:
125
193
  print("Not a .jac file.")
@@ -240,6 +308,7 @@ def debug(filename: str, main: bool = True, cache: bool = False) -> None:
240
308
  @cmd_registry.register
241
309
  def dot(
242
310
  filename: str,
311
+ session: str = "",
243
312
  initial: str = "",
244
313
  depth: int = -1,
245
314
  traverse: bool = False,
@@ -261,6 +330,17 @@ def dot(
261
330
  :param node_limit: The maximum number of nodes allowed in the graph.
262
331
  :param saveto: Path to save the generated graph.
263
332
  """
333
+ if session == "":
334
+ session = (
335
+ cmd_registry.args.session
336
+ if hasattr(cmd_registry, "args")
337
+ and hasattr(cmd_registry.args, "session")
338
+ and cmd_registry.args.session
339
+ else ""
340
+ )
341
+
342
+ Jac.context().init_memory(session)
343
+
264
344
  base, mod = os.path.split(filename)
265
345
  base = base if base else "./"
266
346
  mod = mod[:-4]
@@ -284,6 +364,10 @@ def dot(
284
364
  )
285
365
  except Exception as e:
286
366
  print(f"Error while generating graph: {e}")
367
+ import traceback
368
+
369
+ traceback.print_exc()
370
+ Jac.reset_context()
287
371
  return
288
372
  file_name = saveto if saveto else f"{mod}.dot"
289
373
  with open(file_name, "w") as file:
@@ -292,6 +376,8 @@ def dot(
292
376
  else:
293
377
  print("Not a .jac file.")
294
378
 
379
+ Jac.reset_context()
380
+
295
381
 
296
382
  @cmd_registry.register
297
383
  def py_to_jac(filename: str, tree: bool = False) -> None:
@@ -319,10 +405,13 @@ def start_cli() -> None:
319
405
  """
320
406
  parser = cmd_registry.parser
321
407
  args = parser.parse_args()
408
+ cmd_registry.args = args
322
409
  command = cmd_registry.get(args.command)
323
410
  if command:
324
411
  args_dict = vars(args)
325
412
  args_dict.pop("command")
413
+ if command not in ["run"]:
414
+ args_dict.pop("session")
326
415
  ret = command.call(**args_dict)
327
416
  if ret:
328
417
  print(ret)
jaclang/cli/cmdreg.py CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import argparse
6
6
  import cmd
7
7
  import inspect
8
+ import pprint
8
9
  from typing import Callable, Optional
9
10
 
10
11
 
@@ -30,12 +31,17 @@ class CommandRegistry:
30
31
  registry: dict[str, Command]
31
32
  sub_parsers: argparse._SubParsersAction
32
33
  parser: argparse.ArgumentParser
34
+ args: argparse.Namespace
33
35
 
34
36
  def __init__(self) -> None:
35
37
  """Initialize a CommandRegistry instance."""
36
38
  self.registry = {}
37
- self.parser = argparse.ArgumentParser(prog="CLI")
39
+ self.parser = argparse.ArgumentParser(prog="jac")
40
+ self.parser.add_argument(
41
+ "--session", help="Session file path", nargs="?", default=""
42
+ )
38
43
  self.sub_parsers = self.parser.add_subparsers(title="commands", dest="command")
44
+ self.args = argparse.Namespace()
39
45
 
40
46
  def register(self, func: Callable) -> Callable:
41
47
  """Register a command in the registry."""
@@ -48,6 +54,11 @@ class CommandRegistry:
48
54
  first = True
49
55
  for param_name, param in cmd.sig.parameters.items():
50
56
  arg_msg = f"type: {param.annotation.__name__}"
57
+ # shorthand is first character by default,
58
+ # If already taken, use the first 2 characters
59
+ shorthand = param_name[:1]
60
+ if f"-{shorthand}" in cmd_parser._option_string_actions:
61
+ shorthand = param_name[:2]
51
62
  if param_name == "args":
52
63
  cmd_parser.add_argument("args", nargs=argparse.REMAINDER, help=arg_msg)
53
64
  elif param_name == "filepath":
@@ -76,7 +87,7 @@ class CommandRegistry:
76
87
  )
77
88
  else:
78
89
  cmd_parser.add_argument(
79
- f"-{param_name[:1]}",
90
+ f"-{shorthand}",
80
91
  f"--{param_name}",
81
92
  required=True,
82
93
  type=(
@@ -99,14 +110,14 @@ class CommandRegistry:
99
110
  arg_msg += f", default: {param.default}"
100
111
  if param.annotation == bool:
101
112
  cmd_parser.add_argument(
102
- f"-{param_name[:1]}",
113
+ f"-{shorthand}",
103
114
  f"--{param_name}",
104
115
  default=param.default,
105
116
  action="store_true",
106
117
  help=arg_msg,
107
118
  )
108
119
  cmd_parser.add_argument(
109
- f"-n{param_name[:1]}",
120
+ f"-n{shorthand}",
110
121
  f"--no-{param_name}",
111
122
  dest=param_name,
112
123
  action="store_false",
@@ -114,7 +125,7 @@ class CommandRegistry:
114
125
  )
115
126
  else:
116
127
  cmd_parser.add_argument(
117
- f"-{param_name[:1]}",
128
+ f"-{shorthand}",
118
129
  f"--{param_name}",
119
130
  default=param.default,
120
131
  help=arg_msg,
@@ -168,7 +179,8 @@ class CommandShell(cmd.Cmd):
168
179
  args.pop("command")
169
180
  ret = command.call(**args)
170
181
  if ret:
171
- self.stdout.write(ret + "\n")
182
+ ret_str = pprint.pformat(ret, indent=2)
183
+ self.stdout.write(f"{ret_str}\n")
172
184
  except Exception as e:
173
185
  print(e)
174
186
 
@@ -86,17 +86,24 @@ TOKEN_MAP.update(
86
86
  "A_PIPE_FWD": ":>",
87
87
  "A_PIPE_BKWD": "<:",
88
88
  "DOT_FWD": ".>",
89
+ "STAR_POW": "**",
90
+ "STAR_MUL": "*",
91
+ "FLOOR_DIV": "//",
92
+ "DIV": "/",
93
+ "PYNLINE": "::py::",
94
+ "ADD_EQ": "+=",
95
+ "SUB_EQ": "-=",
89
96
  "STAR_POW_EQ": "**=",
90
97
  "MUL_EQ": "*=",
91
98
  "FLOOR_DIV_EQ": "//=",
92
99
  "DIV_EQ": "/=",
100
+ "MOD_EQ": "%=",
101
+ "BW_AND_EQ": "&=",
93
102
  "BW_OR_EQ": "|=",
94
103
  "BW_XOR_EQ": "^=",
95
- "STAR_POW": "**",
96
- "STAR_MUL": "*",
97
- "FLOOR_DIV": "//",
98
- "DIV": "/",
99
- "PYNLINE": "::py::",
104
+ "BW_NOT_EQ": "~=",
105
+ "LSHIFT_EQ": "<<=",
106
+ "RSHIFT_EQ": ">>=",
100
107
  }
101
108
  )
102
109
 
@@ -194,10 +194,10 @@ class AstAccessNode(AstNode):
194
194
  """Get access spec."""
195
195
  return (
196
196
  SymbolAccess.PRIVATE
197
- if self.access and self.access.tag.value == Tok.KW_PRIV
197
+ if self.access and self.access.tag.name == Tok.KW_PRIV
198
198
  else (
199
199
  SymbolAccess.PROTECTED
200
- if self.access and self.access.tag.value == Tok.KW_PROT
200
+ if self.access and self.access.tag.name == Tok.KW_PROT
201
201
  else SymbolAccess.PUBLIC
202
202
  )
203
203
  )
@@ -391,7 +391,6 @@ class Module(AstDocNode):
391
391
  body: Sequence[ElementStmt | String | EmptyToken],
392
392
  is_imported: bool,
393
393
  kid: Sequence[AstNode],
394
- impl_mod: Optional[Module] = None,
395
394
  test_mod: Optional[Module] = None,
396
395
  registry: Optional[SemRegistry] = None,
397
396
  ) -> None:
@@ -400,7 +399,7 @@ class Module(AstDocNode):
400
399
  self.source = source
401
400
  self.body = body
402
401
  self.is_imported = is_imported
403
- self.impl_mod = impl_mod
402
+ self.impl_mod: list[Module] = []
404
403
  self.test_mod = test_mod
405
404
  self.mod_deps: dict[str, Module] = {}
406
405
  self.registry = registry
@@ -3716,7 +3715,7 @@ class MatchArch(MatchPattern):
3716
3715
 
3717
3716
  def __init__(
3718
3717
  self,
3719
- name: NameSpec,
3718
+ name: AtomTrailer | NameSpec,
3720
3719
  arg_patterns: Optional[SubNodeList[MatchPattern]],
3721
3720
  kw_patterns: Optional[SubNodeList[MatchKVPair]],
3722
3721
  kid: Sequence[AstNode],