jaclang 0.8.4__py3-none-any.whl → 0.8.5__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 (53) hide show
  1. jaclang/cli/cli.py +74 -22
  2. jaclang/compiler/jac.lark +3 -3
  3. jaclang/compiler/larkparse/jac_parser.py +2 -2
  4. jaclang/compiler/parser.py +14 -21
  5. jaclang/compiler/passes/main/__init__.py +3 -1
  6. jaclang/compiler/passes/main/binder_pass.py +594 -0
  7. jaclang/compiler/passes/main/import_pass.py +8 -256
  8. jaclang/compiler/passes/main/inheritance_pass.py +2 -2
  9. jaclang/compiler/passes/main/pyast_gen_pass.py +35 -69
  10. jaclang/compiler/passes/main/pyast_load_pass.py +24 -13
  11. jaclang/compiler/passes/main/sem_def_match_pass.py +1 -1
  12. jaclang/compiler/passes/main/tests/fixtures/M1.jac +3 -0
  13. jaclang/compiler/passes/main/tests/fixtures/sym_binder.jac +47 -0
  14. jaclang/compiler/passes/main/tests/test_binder_pass.py +111 -0
  15. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +13 -13
  16. jaclang/compiler/passes/main/tests/test_sem_def_match_pass.py +6 -6
  17. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +2 -0
  18. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +6 -0
  19. jaclang/compiler/program.py +15 -8
  20. jaclang/compiler/tests/test_sr_errors.py +32 -0
  21. jaclang/compiler/unitree.py +21 -15
  22. jaclang/langserve/engine.jac +23 -4
  23. jaclang/langserve/tests/test_server.py +13 -0
  24. jaclang/runtimelib/importer.py +33 -62
  25. jaclang/runtimelib/utils.py +29 -0
  26. jaclang/tests/fixtures/pyfunc_fmt.py +60 -0
  27. jaclang/tests/fixtures/pyfunc_fstr.py +25 -0
  28. jaclang/tests/fixtures/pyfunc_kwesc.py +33 -0
  29. jaclang/tests/fixtures/python_run_test.py +19 -0
  30. jaclang/tests/test_cli.py +67 -0
  31. jaclang/tests/test_language.py +96 -1
  32. jaclang/utils/lang_tools.py +3 -3
  33. jaclang/utils/module_resolver.py +90 -0
  34. jaclang/utils/symtable_test_helpers.py +125 -0
  35. jaclang/utils/test.py +3 -4
  36. jaclang/vendor/interegular/__init__.py +34 -0
  37. jaclang/vendor/interegular/comparator.py +163 -0
  38. jaclang/vendor/interegular/fsm.py +1015 -0
  39. jaclang/vendor/interegular/patterns.py +732 -0
  40. jaclang/vendor/interegular/py.typed +0 -0
  41. jaclang/vendor/interegular/utils/__init__.py +15 -0
  42. jaclang/vendor/interegular/utils/simple_parser.py +165 -0
  43. jaclang/vendor/interegular-0.3.3.dist-info/INSTALLER +1 -0
  44. jaclang/vendor/interegular-0.3.3.dist-info/LICENSE.txt +21 -0
  45. jaclang/vendor/interegular-0.3.3.dist-info/METADATA +64 -0
  46. jaclang/vendor/interegular-0.3.3.dist-info/RECORD +20 -0
  47. jaclang/vendor/interegular-0.3.3.dist-info/REQUESTED +0 -0
  48. jaclang/vendor/interegular-0.3.3.dist-info/WHEEL +5 -0
  49. jaclang/vendor/interegular-0.3.3.dist-info/top_level.txt +1 -0
  50. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/METADATA +1 -1
  51. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/RECORD +53 -29
  52. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/WHEEL +0 -0
  53. {jaclang-0.8.4.dist-info → jaclang-0.8.5.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.py CHANGED
@@ -21,6 +21,7 @@ from jaclang.runtimelib.machine import (
21
21
  JacMachine as Jac,
22
22
  JacMachineInterface as JacInterface,
23
23
  )
24
+ from jaclang.runtimelib.utils import read_file_with_encoding
24
25
  from jaclang.utils.helpers import debugger as db
25
26
  from jaclang.utils.lang_tools import AstTool
26
27
 
@@ -98,7 +99,15 @@ def proc_file_sess(
98
99
  )
99
100
  base, mod = os.path.split(filename)
100
101
  base = base if base else "./"
101
- mod = mod[:-4]
102
+ if filename.endswith(".jac") or filename.endswith(".jir"):
103
+ mod = mod[:-4]
104
+ elif filename.endswith(".py"):
105
+ mod = mod[:-3]
106
+ else:
107
+ print(
108
+ "Not a valid file!\nOnly supports `.jac`, `.jir`, and `.py`",
109
+ file=sys.stderr,
110
+ )
102
111
  mach = ExecutionContext(session=session, root=root)
103
112
  Jac.set_context(mach)
104
113
  return base, mod, mach
@@ -111,19 +120,20 @@ def run(
111
120
  main: bool = True,
112
121
  cache: bool = True,
113
122
  ) -> None:
114
- """Run the specified .jac file.
123
+ """Run the specified .jac, .jir, or .py file.
115
124
 
116
- Executes a Jac program file, loading it into the Jac runtime environment
117
- and running its code. This is the primary way to execute Jac programs.
125
+ Executes a Jac program file or Python file, loading it into the Jac runtime environment
126
+ and running its code. Python files are converted to Jac AST for execution.
118
127
 
119
128
  Args:
120
- filename: Path to the .jac or .jir file to run
129
+ filename: Path to the .jac, .jir, or .py file to run
121
130
  session: Optional session identifier for persistent state
122
131
  main: Treat the module as __main__ (default: True)
123
132
  cache: Use cached compilation if available (default: True)
124
133
 
125
134
  Examples:
126
135
  jac run myprogram.jac
136
+ jac run myscript.py
127
137
  jac run myprogram.jac --session mysession
128
138
  jac run myprogram.jac --no-main
129
139
  """
@@ -132,7 +142,7 @@ def run(
132
142
  base, mod, mach = proc_file_sess(filename, session)
133
143
  Jac.set_base_path(base)
134
144
 
135
- if filename.endswith(".jac"):
145
+ if filename.endswith((".jac", ".py")):
136
146
  try:
137
147
  Jac.jac_import(
138
148
  target=mod,
@@ -140,7 +150,7 @@ def run(
140
150
  override_name="__main__" if main else None,
141
151
  )
142
152
  except Exception as e:
143
- print(e, file=sys.stderr)
153
+ print(f"Error running {filename}: {e}", file=sys.stderr)
144
154
  elif filename.endswith(".jir"):
145
155
  try:
146
156
  with open(filename, "rb") as f:
@@ -151,10 +161,13 @@ def run(
151
161
  override_name="__main__" if main else None,
152
162
  )
153
163
  except Exception as e:
154
- print(e, file=sys.stderr)
155
-
164
+ print(f"Error running {filename}: {e}", file=sys.stderr)
156
165
  else:
157
- print("Not a valid file!\nOnly supports `.jac` and `.jir`")
166
+ print(
167
+ "Not a valid file!\nOnly supports `.jac`, `.jir`, and `.py`",
168
+ file=sys.stderr,
169
+ )
170
+
158
171
  mach.close()
159
172
 
160
173
 
@@ -231,6 +244,41 @@ def build(filename: str) -> None:
231
244
  print("Not a .jac file.", file=sys.stderr)
232
245
 
233
246
 
247
+ @cmd_registry.register
248
+ def bind(filename: str, typecheck: bool = False) -> None:
249
+ """Bind the specified .jac file.
250
+
251
+ Parses and binds a Jac source file, resolving symbols and preparing it for execution.
252
+ This step is necessary before running the program, as it ensures all references
253
+ are correctly linked and the program structure is validated.
254
+ TODO: performs type checking.
255
+
256
+ Args:
257
+ filename: Path to the .jac file to bind
258
+ typecheck: Print the symbol table after binding (default: False)
259
+
260
+ Examples:
261
+ jac bind myprogram.jac
262
+ jac bind myprogram.jac -t
263
+ """
264
+ if filename.endswith((".jac", ".py")):
265
+ (out := JacProgram()).bind(file_path=filename)
266
+ errs = len(out.errors_had)
267
+ warnings = len(out.warnings_had)
268
+ if typecheck:
269
+ for mods in out.mod.hub.values():
270
+ if mods.name == "builtins":
271
+ continue
272
+ header = (
273
+ f"{'=' * 6} SymTable({mods.name}) {'=' * (22 - len(mods.name))}"
274
+ )
275
+ divider = "=" * 40
276
+ print(f"{divider}\n{header}\n{divider}\n{mods.sym_tab.sym_pp()}")
277
+ print(f"Errors: {errs}, Warnings: {warnings}")
278
+ else:
279
+ print("Not a .jac/.py file.", file=sys.stderr)
280
+
281
+
234
282
  @cmd_registry.register
235
283
  def check(filename: str, print_errs: bool = True) -> None:
236
284
  """Run type checker for a specified .jac file.
@@ -546,16 +594,21 @@ def py2jac(filename: str) -> None:
546
594
  jac py2jac myscript.py > converted.jac
547
595
  """
548
596
  if filename.endswith(".py"):
549
- with open(filename, "r") as f:
550
- file_source = f.read()
551
- code = PyastBuildPass(
552
- ir_in=uni.PythonModuleAst(
553
- ast3.parse(file_source),
554
- orig_src=uni.Source(file_source, filename),
555
- ),
556
- prog=JacProgram(),
557
- ).ir_out.unparse()
558
- print(code)
597
+ file_source = read_file_with_encoding(filename)
598
+ code = PyastBuildPass(
599
+ ir_in=uni.PythonModuleAst(
600
+ ast3.parse(file_source),
601
+ orig_src=uni.Source(file_source, filename),
602
+ ),
603
+ prog=JacProgram(),
604
+ ).ir_out.unparse(requires_format=False)
605
+ formatted_code = JacProgram().jac_str_formatter(
606
+ source_str=code, file_path=filename
607
+ )
608
+ if formatted_code:
609
+ print(formatted_code)
610
+ else:
611
+ print("Error converting Python code to Jac.", file=sys.stderr)
559
612
  else:
560
613
  print("Not a .py file.")
561
614
 
@@ -575,8 +628,7 @@ def jac2py(filename: str) -> None:
575
628
  jac jac2py myprogram.jac > converted.py
576
629
  """
577
630
  if filename.endswith(".jac"):
578
- with open(filename, "r"):
579
- code = JacProgram().compile(file_path=filename).gen.py
631
+ code = JacProgram().compile(file_path=filename).gen.py
580
632
  print(code)
581
633
  else:
582
634
  print("Not a .jac file.", file=sys.stderr)
jaclang/compiler/jac.lark CHANGED
@@ -62,7 +62,7 @@ ability: decorators? KW_ASYNC? (ability_decl | function_decl)
62
62
 
63
63
  function_decl: KW_OVERRIDE? KW_STATIC? KW_DEF access_tag? named_ref func_decl? (block_tail | KW_ABSTRACT? SEMI)
64
64
  ability_decl: KW_OVERRIDE? KW_STATIC? KW_CAN access_tag? named_ref event_clause (block_tail | KW_ABSTRACT? SEMI)
65
- block_tail: code_block | KW_BY atomic_call SEMI
65
+ block_tail: code_block | KW_BY expression SEMI
66
66
  event_clause: KW_WITH expression? (KW_EXIT | KW_ENTRY)
67
67
 
68
68
  func_decl: (LPAREN func_decl_params? RPAREN) (RETURN_HINT expression)?
@@ -331,9 +331,9 @@ index_slice: LSQUARE
331
331
  | list_val
332
332
 
333
333
  // [Heading]: Function calls.
334
- atomic_call: atomic_chain LPAREN param_list? by_call? RPAREN by_call?
334
+ atomic_call: atomic_chain LPAREN param_list? by_llm? RPAREN
335
335
 
336
- by_call: KW_BY expression
336
+ by_llm: KW_BY expression
337
337
 
338
338
  param_list: expr_list COMMA kw_expr_list COMMA?
339
339
  | kw_expr_list COMMA?