jaclang 0.8.5__py3-none-any.whl → 0.8.7__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 (70) hide show
  1. jaclang/cli/cli.md +4 -3
  2. jaclang/cli/cli.py +63 -29
  3. jaclang/cli/cmdreg.py +1 -140
  4. jaclang/compiler/passes/main/__init__.py +2 -0
  5. jaclang/compiler/passes/main/cfg_build_pass.py +21 -1
  6. jaclang/compiler/passes/main/inheritance_pass.py +8 -1
  7. jaclang/compiler/passes/main/pyast_gen_pass.py +70 -11
  8. jaclang/compiler/passes/main/pyast_load_pass.py +14 -20
  9. jaclang/compiler/passes/main/sym_tab_build_pass.py +4 -0
  10. jaclang/compiler/passes/main/tests/fixtures/cfg_has_var.jac +12 -0
  11. jaclang/compiler/passes/main/tests/fixtures/cfg_if_no_else.jac +11 -0
  12. jaclang/compiler/passes/main/tests/fixtures/cfg_return.jac +9 -0
  13. jaclang/compiler/passes/main/tests/fixtures/checker_binary_op.jac +21 -0
  14. jaclang/compiler/passes/main/tests/fixtures/checker_call_expr_class.jac +12 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker_cyclic_symbol.jac +4 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker_expr_call.jac +9 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_import_missing_module.jac +13 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_imported.jac +2 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_importer.jac +6 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_magic_call.jac +17 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_mod_path.jac +8 -0
  22. jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +1 -1
  23. jaclang/compiler/passes/main/tests/fixtures/import_symbol_type_infer.jac +11 -0
  24. jaclang/compiler/passes/main/tests/fixtures/infer_type_assignment.jac +5 -0
  25. jaclang/compiler/passes/main/tests/fixtures/member_access_type_inferred.jac +13 -0
  26. jaclang/compiler/passes/main/tests/fixtures/member_access_type_resolve.jac +11 -0
  27. jaclang/compiler/passes/main/tests/fixtures/type_annotation_assignment.jac +8 -0
  28. jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +62 -24
  29. jaclang/compiler/passes/main/tests/test_checker_pass.py +161 -0
  30. jaclang/compiler/passes/main/type_checker_pass.py +147 -0
  31. jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +1 -4
  32. jaclang/compiler/program.py +17 -3
  33. jaclang/compiler/type_system/__init__.py +1 -0
  34. jaclang/compiler/type_system/operations.py +104 -0
  35. jaclang/compiler/type_system/type_evaluator.py +560 -0
  36. jaclang/compiler/type_system/type_utils.py +41 -0
  37. jaclang/compiler/type_system/types.py +240 -0
  38. jaclang/compiler/unitree.py +15 -9
  39. jaclang/langserve/dev_engine.jac +645 -0
  40. jaclang/langserve/dev_server.jac +201 -0
  41. jaclang/langserve/engine.jac +135 -91
  42. jaclang/langserve/server.jac +21 -14
  43. jaclang/langserve/tests/server_test/test_lang_serve.py +2 -5
  44. jaclang/langserve/tests/test_dev_server.py +80 -0
  45. jaclang/langserve/tests/test_server.py +9 -2
  46. jaclang/langserve/utils.jac +44 -48
  47. jaclang/runtimelib/builtin.py +28 -39
  48. jaclang/runtimelib/importer.py +1 -1
  49. jaclang/runtimelib/machine.py +48 -64
  50. jaclang/runtimelib/memory.py +23 -5
  51. jaclang/runtimelib/tests/fixtures/savable_object.jac +10 -2
  52. jaclang/runtimelib/utils.py +13 -6
  53. jaclang/tests/fixtures/edge_node_walk.jac +1 -1
  54. jaclang/tests/fixtures/edges_walk.jac +1 -1
  55. jaclang/tests/fixtures/gendot_bubble_sort.jac +1 -1
  56. jaclang/tests/fixtures/jac_run_py_bugs.py +18 -0
  57. jaclang/tests/fixtures/jac_run_py_import.py +13 -0
  58. jaclang/tests/fixtures/lambda_arg_annotation.jac +15 -0
  59. jaclang/tests/fixtures/lambda_self.jac +18 -0
  60. jaclang/tests/fixtures/py_run.jac +8 -0
  61. jaclang/tests/fixtures/py_run.py +23 -0
  62. jaclang/tests/fixtures/pyfunc.py +2 -0
  63. jaclang/tests/test_cli.py +103 -14
  64. jaclang/tests/test_language.py +10 -4
  65. jaclang/utils/lang_tools.py +3 -0
  66. jaclang/utils/module_resolver.py +1 -1
  67. {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/METADATA +4 -2
  68. {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/RECORD +70 -37
  69. {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/WHEEL +1 -1
  70. {jaclang-0.8.5.dist-info → jaclang-0.8.7.dist-info}/entry_points.txt +0 -0
jaclang/cli/cli.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # **Jac Language Command Line Interface (CLI)**
2
2
 
3
- Jac Language CLI is with a variety of commands to facilitate users. Additionally, Jac language offers users the ability to define custom CLI commands through plugins. This document aims to provide an overview of each command along with clear usage instructions.
3
+ git Jac Language CLI provides a variety of commands to facilitate users. Additionally, Jac language offers users the ability to define custom CLI commands through plugins. This document aims to provide an overview of each command along with clear usage instructions.
4
4
 
5
5
  > [!TIP]
6
- > Type "help" on Jac CLI and see!
6
+ > Use `jac --help` to see available commands and usage.
7
7
 
8
8
  ### Click one of the default commands below and see the usage.
9
- - [tool](#tool) , [run](#run) , [clean](#clean) , [format](#format) , [check](#check) , [build](#build) , [enter](#enter) , [test](#test)
9
+ - [tool](#tool) , [run](#run) , [clean](#clean) , [format](#format) , [check](#check) , [build](#build) , [enter](#enter) , [test](#test)
10
10
 
11
11
 
12
12
 
@@ -36,6 +36,7 @@ Parameters to execute the tool command:
36
36
  - `sym.`: Generates a dot graph representation of the symbol table for the specified .jac file.
37
37
  - `ast`: Displays the Abstract Syntax Tree (AST) of the specified .jac file.
38
38
  - `ast.`: Generates a dot graph representation of the AST for the specified .jac file.
39
+ - `cfg.`: Generates a dot graph representatuin of the CFG(Control Flow Graph) for a specific .jac file
39
40
  - `pyast`: Generates the Python AST for a .py file or the relevant Python AST for the generated Python code from a .jac file.
40
41
  - `py`: Displays the relevant generated Python code for the respective Jac code in a .jac file.
41
42
  - `file_path`: Path to the .jac or .py file.
jaclang/cli/cli.py CHANGED
@@ -11,22 +11,17 @@ from pathlib import Path
11
11
  from typing import Optional
12
12
 
13
13
  import jaclang.compiler.unitree as uni
14
- from jaclang.cli.cmdreg import CommandShell, cmd_registry
14
+ from jaclang.cli.cmdreg import cmd_registry
15
15
  from jaclang.compiler.passes.main import PyastBuildPass
16
16
  from jaclang.compiler.program import JacProgram
17
17
  from jaclang.runtimelib.builtin import printgraph
18
18
  from jaclang.runtimelib.constructs import WalkerArchetype
19
- from jaclang.runtimelib.machine import (
20
- ExecutionContext,
21
- JacMachine as Jac,
22
- JacMachineInterface as JacInterface,
23
- )
19
+ from jaclang.runtimelib.machine import ExecutionContext, JacMachine as Jac
24
20
  from jaclang.runtimelib.utils import read_file_with_encoding
25
21
  from jaclang.utils.helpers import debugger as db
26
22
  from jaclang.utils.lang_tools import AstTool
27
23
 
28
-
29
- JacInterface.create_cmd()
24
+ Jac.create_cmd()
30
25
  Jac.setup()
31
26
 
32
27
 
@@ -137,9 +132,10 @@ def run(
137
132
  jac run myprogram.jac --session mysession
138
133
  jac run myprogram.jac --no-main
139
134
  """
140
- # if no session specified, check if it was defined when starting the command shell
135
+ # if no session specified, check if it was defined via global CLI args
141
136
  # otherwise default to jaclang.session
142
137
  base, mod, mach = proc_file_sess(filename, session)
138
+ lng = filename.split(".")[-1]
143
139
  Jac.set_base_path(base)
144
140
 
145
141
  if filename.endswith((".jac", ".py")):
@@ -148,6 +144,7 @@ def run(
148
144
  target=mod,
149
145
  base_path=base,
150
146
  override_name="__main__" if main else None,
147
+ lng=lng,
151
148
  )
152
149
  except Exception as e:
153
150
  print(f"Error running {filename}: {e}", file=sys.stderr)
@@ -159,6 +156,7 @@ def run(
159
156
  target=mod,
160
157
  base_path=base,
161
158
  override_name="__main__" if main else None,
159
+ lng=lng,
162
160
  )
163
161
  except Exception as e:
164
162
  print(f"Error running {filename}: {e}", file=sys.stderr)
@@ -219,7 +217,7 @@ def get_object(filename: str, id: str, session: str = "", main: bool = True) ->
219
217
 
220
218
 
221
219
  @cmd_registry.register
222
- def build(filename: str) -> None:
220
+ def build(filename: str, typecheck: bool = False) -> None:
223
221
  """Build the specified .jac file.
224
222
 
225
223
  Compiles a Jac source file into a Jac Intermediate Representation (.jir) file,
@@ -227,21 +225,25 @@ def build(filename: str) -> None:
227
225
 
228
226
  Args:
229
227
  filename: Path to the .jac file to build
230
- typecheck: Perform type checking during build (default: True)
228
+ typecheck: Perform type checking during build (default: False)
231
229
 
232
230
  Examples:
233
231
  jac build myprogram.jac
234
- jac build myprogram.jac --no-typecheck
232
+ jac build myprogram.jac --typecheck
235
233
  """
236
- if filename.endswith(".jac"):
237
- (out := JacProgram()).compile(file_path=filename)
238
- errs = len(out.errors_had)
239
- warnings = len(out.warnings_had)
240
- print(f"Errors: {errs}, Warnings: {warnings}")
241
- with open(filename[:-4] + ".jir", "wb") as f:
242
- pickle.dump(out, f)
243
- else:
234
+ if not filename.endswith(".jac"):
244
235
  print("Not a .jac file.", file=sys.stderr)
236
+ exit(1)
237
+ (out := JacProgram()).compile(file_path=filename, type_check=typecheck)
238
+ errs = len(out.errors_had)
239
+ warnings = len(out.warnings_had)
240
+ print(f"Errors: {errs}, Warnings: {warnings}")
241
+
242
+ for alrt in out.errors_had + out.warnings_had:
243
+ print(alrt.pretty_print(), file=sys.stderr)
244
+
245
+ with open(filename[:-4] + ".jir", "wb") as f:
246
+ pickle.dump(out, f)
245
247
 
246
248
 
247
249
  @cmd_registry.register
@@ -325,6 +327,24 @@ def lsp() -> None:
325
327
  run_lang_server()
326
328
 
327
329
 
330
+ @cmd_registry.register
331
+ def lsp_dev() -> None:
332
+ """Run Jac Language Server Protocol in Developer Mode.
333
+
334
+ Starts the experimental Jac Language Server with enhanced features
335
+ for development and testing. Used by editor extensions in developer mode.
336
+
337
+ Args:
338
+ This command takes no parameters.
339
+
340
+ Examples:
341
+ jac lsp_dev
342
+ """
343
+ from jaclang.langserve.dev_server import run_lang_server
344
+
345
+ run_lang_server()
346
+
347
+
328
348
  @cmd_registry.register
329
349
  def enter(
330
350
  filename: str,
@@ -642,6 +662,14 @@ def start_cli() -> None:
642
662
  - None
643
663
  """
644
664
  parser = cmd_registry.parser
665
+ # Default to `run` when a file is provided without a subcommand
666
+ raw_argv = sys.argv[1:]
667
+ if (
668
+ raw_argv
669
+ and not raw_argv[0].startswith("-")
670
+ and raw_argv[0].lower().endswith((".jac", ".jir", ".py"))
671
+ ):
672
+ sys.argv = [sys.argv[0], "run"] + raw_argv
645
673
  args = parser.parse_args()
646
674
  cmd_registry.args = args
647
675
 
@@ -651,16 +679,22 @@ def start_cli() -> None:
651
679
  print("Jac path:", __file__)
652
680
  return
653
681
 
682
+ if args.command is None:
683
+ parser.print_help()
684
+ return
685
+
654
686
  command = cmd_registry.get(args.command)
655
- if command:
656
- args_dict = vars(args)
657
- args_dict.pop("command")
658
- args_dict.pop("version", None)
659
- ret = command.call(**args_dict)
660
- if ret:
661
- print(ret)
662
- else:
663
- CommandShell(cmd_registry).cmdloop()
687
+ if not command:
688
+ print(f"Unknown command: {args.command}", file=sys.stderr)
689
+ parser.print_help()
690
+ return
691
+
692
+ args_dict = vars(args)
693
+ args_dict.pop("command")
694
+ args_dict.pop("version", None)
695
+ ret = command.call(**args_dict)
696
+ if ret:
697
+ print(ret)
664
698
 
665
699
 
666
700
  if __name__ == "__main__":
jaclang/cli/cmdreg.py CHANGED
@@ -3,9 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import argparse
6
- import cmd
7
6
  import inspect
8
- import pprint
9
7
  import re
10
8
  from typing import Callable, Dict, Optional
11
9
 
@@ -241,141 +239,4 @@ class CommandRegistry:
241
239
  cmd_registry = CommandRegistry()
242
240
 
243
241
 
244
- class CommandShell(cmd.Cmd):
245
- """Command shell for the command line interface."""
246
-
247
- intro = "Welcome to the Jac CLI!"
248
- prompt = "jac> "
249
- cmd_reg: CommandRegistry
250
-
251
- def __init__(self, cmd_reg: CommandRegistry) -> None:
252
- """Initialize a CommandShell instance."""
253
- self.cmd_reg = cmd_reg
254
- super().__init__()
255
-
256
- def do_exit(self, arg: list) -> bool:
257
- """Exit the command shell."""
258
- return True
259
-
260
- def default(self, line: str) -> None:
261
- """Process the command line input."""
262
- args = vars(self.cmd_reg.parser.parse_args(line.split()))
263
- command = self.cmd_reg.get(args["command"])
264
- if command:
265
- args.pop("command")
266
- ret = command.call(**args)
267
- if ret:
268
- ret_str = pprint.pformat(ret, indent=2)
269
- self.stdout.write(f"{ret_str}\n")
270
-
271
- def do_help(self, arg: str) -> None:
272
- """Jac CLI help implementation."""
273
-
274
- def get_info(name: str, doc: str, args: dict[str, inspect.Parameter]) -> None:
275
- """Format and display detailed command information."""
276
- # Format the command header
277
- self.stdout.write(f"\n{'=' * 80}\n")
278
- self.stdout.write(f"COMMAND: {name}\n")
279
- self.stdout.write(f"{'=' * 80}\n\n")
280
-
281
- # Format the command description
282
- doc_lines = doc.strip().split("\n")
283
- for line in doc_lines:
284
- self.stdout.write(f"{line}\n")
285
-
286
- # Format the command arguments
287
- if args:
288
- self.stdout.write("\nARGUMENTS:\n")
289
- for param_name, param in args.items():
290
- # Get parameter type
291
- type_name = (
292
- param.annotation.__name__
293
- if hasattr(param.annotation, "__name__")
294
- else str(param.annotation)
295
- )
296
-
297
- # Format default value if present
298
- default_str = ""
299
- if param.default is not param.empty:
300
- default_str = f" (default: {param.default})"
301
-
302
- # Format required/optional status
303
- req_str = (
304
- " [required]"
305
- if param.default is param.empty and param_name != "args"
306
- else " [optional]"
307
- )
308
-
309
- self.stdout.write(
310
- f" {param_name}: {type_name}{default_str}{req_str}\n"
311
- )
312
- else:
313
- self.stdout.write("\nNo arguments\n")
314
-
315
- # Format usage examples
316
- command_parser = self.cmd_reg.sub_parsers.choices[name]
317
- self.stdout.write(f"\nUSAGE:\n {command_parser.format_usage()[7:]}\n")
318
-
319
- # Extract and format examples from docstring if present
320
- if "Examples:" in doc:
321
- examples_section = doc.split("Examples:")[1].strip()
322
- example_lines = examples_section.split("\n")
323
- self.stdout.write("\nEXAMPLES:\n")
324
- for example in example_lines:
325
- if example.strip():
326
- self.stdout.write(f" {example.strip()}\n")
327
-
328
- self.stdout.write("\n")
329
-
330
- if arg == "all":
331
- # Display all commands with their details
332
- command_details = self.cmd_reg.get_all_commands()
333
- for name, (doc, args) in sorted(command_details.items()):
334
- get_info(name, doc, args)
335
-
336
- elif arg:
337
- # Display help for a specific command
338
- command = self.cmd_reg.get(arg)
339
- if command:
340
- doc = command.func.__doc__ or "No help available."
341
- args = command.sig.parameters
342
- get_info(arg, doc, args)
343
- else:
344
- self.stdout.write(f"\nUnknown command: '{arg}'\n")
345
- self.stdout.write("Type 'help' to see available commands.\n")
346
- else:
347
- # Display general help information
348
- self.stdout.write("\n")
349
- self.stdout.write("JAC PROGRAMMING LANGUAGE COMMAND LINE INTERFACE\n")
350
- self.stdout.write("=" * 50 + "\n\n")
351
-
352
- self.stdout.write("AVAILABLE COMMANDS:\n")
353
-
354
- # Get all command names and sort them alphabetically
355
- command_names = sorted(self.cmd_reg.registry.keys())
356
-
357
- # Get brief descriptions for each command
358
- command_descriptions: dict[str, str] = {}
359
- for name in command_names:
360
- command = self.cmd_reg.get(name)
361
- if command and command.func.__doc__:
362
- # Extract the first line of the docstring as a brief description
363
- brief = command.func.__doc__.split("\n")[0].strip()
364
- command_descriptions[name] = brief
365
- else:
366
- command_descriptions[name] = "No description available"
367
-
368
- # Display commands with their brief descriptions
369
- for name in command_names:
370
- self.stdout.write(
371
- f" {name.ljust(15)} - {command_descriptions[name]}\n"
372
- )
373
-
374
- self.stdout.write("\nFor detailed information on a specific command:\n")
375
- self.stdout.write(" help <command>\n")
376
-
377
- self.stdout.write("\nTo see detailed information for all commands:\n")
378
- self.stdout.write(" help all\n")
379
-
380
- self.stdout.write("\nTo exit the Jac CLI:\n")
381
- self.stdout.write(" exit\n\n")
242
+ # Shell mode removed; interactive cmd-based shell is no longer supported.
@@ -9,6 +9,7 @@ from .def_use_pass import DefUsePass # noqa: I100
9
9
  from .sem_def_match_pass import SemDefMatchPass # noqa: I100
10
10
  from .import_pass import JacImportDepsPass # noqa: I100
11
11
  from .def_impl_match_pass import DeclImplMatchPass # noqa: I100
12
+ from .type_checker_pass import TypeCheckPass # noqa: I100
12
13
  from .pyast_load_pass import PyastBuildPass # type: ignore # noqa: I100
13
14
  from .pyast_gen_pass import PyastGenPass # noqa: I100
14
15
  from .pybc_gen_pass import PyBytecodeGenPass # noqa: I100
@@ -25,6 +26,7 @@ __all__ = [
25
26
  "JacImportDepsPass",
26
27
  "PyImportDepsPass",
27
28
  "BinderPass",
29
+ "TypeCheckPass",
28
30
  "SymTabBuildPass",
29
31
  "SymTabLinkPass",
30
32
  "DeclImplMatchPass",
@@ -152,7 +152,7 @@ class CFGBuildPass(UniPass):
152
152
  """Exit BasicBlockStmt nodes."""
153
153
  if isinstance(node, uni.UniCFGNode) and not isinstance(node, uni.Semi):
154
154
  self.first_exit = True
155
- if not node.bb_out:
155
+ if not node.bb_out and not isinstance(node, (uni.ReturnStmt, uni.ArchHas)):
156
156
  self.to_connect.append(node)
157
157
  if (
158
158
  isinstance(node, (uni.InForStmt, uni.IterForStmt))
@@ -176,6 +176,8 @@ class CFGBuildPass(UniPass):
176
176
  if from_node in self.to_connect:
177
177
  self.to_connect.remove(from_node)
178
178
  self.ability_stack.pop()
179
+ elif isinstance(node, (uni.IfStmt, uni.ElseIf)) and not node.else_body:
180
+ self.to_connect.append(node)
179
181
 
180
182
  def after_pass(self) -> None:
181
183
  """After pass."""
@@ -299,3 +301,21 @@ class CoalesceBBPass(UniPass):
299
301
 
300
302
  dot += "}\n"
301
303
  return dot
304
+
305
+
306
+ def cfg_dot_from_file(file_name: str) -> str:
307
+ """Print the control flow graph."""
308
+ from jaclang.compiler.program import JacProgram
309
+
310
+ with open(file_name, "r") as f:
311
+ file_source = f.read()
312
+
313
+ ir = (prog := JacProgram()).compile(use_str=file_source, file_path=file_name)
314
+
315
+ cfg_pass = CoalesceBBPass(
316
+ ir_in=ir,
317
+ prog=prog,
318
+ )
319
+
320
+ dot = cfg_pass.printgraph_cfg()
321
+ return dot
@@ -62,9 +62,16 @@ class InheritancePass(Transform[uni.Module, uni.Module]):
62
62
 
63
63
  base_class_symbol_table = base_class_symbol.symbol_table
64
64
 
65
+ # FIXME: If the base class symbol is imported from another module, the symbol table
66
+ # will be None. The imported symbols were ignored and introduced in the typecheck
67
+ # for imported module items. This needs to be investigated to ensure that even imported
68
+ # classes should have a symbol table (unless the module is not parsed and decided not to).
69
+ if base_class_symbol_table is None:
70
+ return
71
+
65
72
  if self.is_missing_py_symbol_table(base_class_symbol, base_class_symbol_table):
66
73
  return
67
- assert base_class_symbol_table is not None
74
+
68
75
  node.sym_tab.inherit_sym_tab(base_class_symbol_table)
69
76
 
70
77
  def inherit_from_atom_trailer(
@@ -187,6 +187,15 @@ class PyastGenPass(UniPass):
187
187
  ),
188
188
  )
189
189
 
190
+ def needs_mtllm(self) -> None:
191
+ """Ensure byLLM is imported only once."""
192
+ self._add_preamble_once(
193
+ self.needs_mtllm.__name__,
194
+ ast3.Import(
195
+ names=[self.sync(ast3.alias(name="byllm"), jac_node=self.ir_out)]
196
+ ),
197
+ )
198
+
190
199
  def needs_enum(self) -> None:
191
200
  """Ensure Enum utilities are imported only once."""
192
201
  self._add_preamble_once(
@@ -735,17 +744,25 @@ class PyastGenPass(UniPass):
735
744
  self, model: ast3.expr, caller: ast3.expr, args: ast3.Dict
736
745
  ) -> ast3.Call:
737
746
  """Reusable method to codegen call_llm(model, caller, args)."""
738
- return self.sync(
747
+ self.needs_mtllm()
748
+ mtir_cls_ast = self.sync(
749
+ ast3.Attribute(
750
+ value=self.sync(ast3.Name(id="byllm", ctx=ast3.Load())),
751
+ attr="MTIR",
752
+ ctx=ast3.Load(),
753
+ )
754
+ )
755
+ mtir_ast = self.sync(
739
756
  ast3.Call(
740
- func=self.jaclib_obj("call_llm"),
757
+ func=self.sync(
758
+ ast3.Attribute(
759
+ value=mtir_cls_ast,
760
+ attr="factory",
761
+ ctx=ast3.Load(),
762
+ )
763
+ ),
741
764
  args=[],
742
765
  keywords=[
743
- self.sync(
744
- ast3.keyword(
745
- arg="model",
746
- value=model,
747
- )
748
- ),
749
766
  self.sync(
750
767
  ast3.keyword(
751
768
  arg="caller",
@@ -758,6 +775,38 @@ class PyastGenPass(UniPass):
758
775
  value=args,
759
776
  )
760
777
  ),
778
+ self.sync(
779
+ ast3.keyword(
780
+ arg="call_params",
781
+ value=self.sync(
782
+ ast3.Attribute(
783
+ value=model,
784
+ attr="call_params",
785
+ ctx=ast3.Load(),
786
+ ),
787
+ ),
788
+ )
789
+ ),
790
+ ],
791
+ )
792
+ )
793
+ return self.sync(
794
+ ast3.Call(
795
+ func=self.jaclib_obj("call_llm"),
796
+ args=[],
797
+ keywords=[
798
+ self.sync(
799
+ ast3.keyword(
800
+ arg="model",
801
+ value=model,
802
+ )
803
+ ),
804
+ self.sync(
805
+ ast3.keyword(
806
+ arg="mtir",
807
+ value=mtir_ast,
808
+ )
809
+ ),
761
810
  ],
762
811
  )
763
812
  )
@@ -953,7 +1002,8 @@ class PyastGenPass(UniPass):
953
1002
  def exit_func_signature(self, node: uni.FuncSignature) -> None:
954
1003
  params = (
955
1004
  [self.sync(ast3.arg(arg="self", annotation=None))]
956
- if (abl := node.find_parent_of_type(uni.Ability))
1005
+ if (abl := node.parent)
1006
+ and isinstance(abl, uni.Ability)
957
1007
  and abl.is_method
958
1008
  and not node.is_static
959
1009
  and not node.is_in_py_class
@@ -2074,6 +2124,10 @@ class PyastGenPass(UniPass):
2074
2124
  ]
2075
2125
 
2076
2126
  def exit_lambda_expr(self, node: uni.LambdaExpr) -> None:
2127
+ # Python lambda expressions don't support type annotations
2128
+ if node.signature:
2129
+ self._remove_lambda_param_annotations(node.signature)
2130
+
2077
2131
  node.gen.py_ast = [
2078
2132
  self.sync(
2079
2133
  ast3.Lambda(
@@ -2095,6 +2149,11 @@ class PyastGenPass(UniPass):
2095
2149
  )
2096
2150
  ]
2097
2151
 
2152
+ def _remove_lambda_param_annotations(self, signature: uni.FuncSignature) -> None:
2153
+ for param in signature.params:
2154
+ if param.gen.py_ast and isinstance(param.gen.py_ast[0], ast3.arg):
2155
+ param.gen.py_ast[0].annotation = None
2156
+
2098
2157
  def exit_unary_expr(self, node: uni.UnaryExpr) -> None:
2099
2158
  op_cls = UNARY_OP_MAP.get(node.op.name)
2100
2159
  if op_cls:
@@ -2351,7 +2410,7 @@ class PyastGenPass(UniPass):
2351
2410
  self.sync(
2352
2411
  ast3.Attribute(
2353
2412
  value=cast(ast3.expr, node.target.gen.py_ast[0]),
2354
- attr=(node.right.sym_name),
2413
+ attr=node.right.sym_name,
2355
2414
  ctx=cast(ast3.expr_context, node.right.py_ctx_func()),
2356
2415
  )
2357
2416
  )
@@ -2948,7 +3007,7 @@ class PyastGenPass(UniPass):
2948
3007
  node.gen.py_ast = [self.sync(op_cls())]
2949
3008
 
2950
3009
  def exit_name(self, node: uni.Name) -> None:
2951
- name = node.sym_name[2:] if node.sym_name.startswith("<>") else node.sym_name
3010
+ name = node.sym_name
2952
3011
  node.gen.py_ast = [self.sync(ast3.Name(id=name, ctx=node.py_ctx_func()))]
2953
3012
 
2954
3013
  def exit_float(self, node: uni.Float) -> None: