jaclang 0.8.6__py3-none-any.whl → 0.8.8__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 (103) hide show
  1. jaclang/cli/cli.md +3 -3
  2. jaclang/cli/cli.py +37 -37
  3. jaclang/cli/cmdreg.py +45 -140
  4. jaclang/compiler/constant.py +0 -1
  5. jaclang/compiler/jac.lark +3 -6
  6. jaclang/compiler/larkparse/jac_parser.py +2 -2
  7. jaclang/compiler/parser.py +213 -34
  8. jaclang/compiler/passes/main/__init__.py +2 -4
  9. jaclang/compiler/passes/main/def_use_pass.py +0 -4
  10. jaclang/compiler/passes/main/predynamo_pass.py +221 -0
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +83 -55
  12. jaclang/compiler/passes/main/pyast_load_pass.py +66 -40
  13. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  14. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_binary_op.jac +21 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_call_expr_class.jac +12 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
  22. jaclang/compiler/passes/main/tests/fixtures/checker_cyclic_symbol.jac +4 -0
  23. jaclang/compiler/passes/main/tests/fixtures/checker_expr_call.jac +9 -0
  24. jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
  25. jaclang/compiler/passes/main/tests/fixtures/checker_import_missing_module.jac +13 -0
  26. jaclang/compiler/passes/main/tests/fixtures/checker_magic_call.jac +17 -0
  27. jaclang/compiler/passes/main/tests/fixtures/checker_mod_path.jac +8 -0
  28. jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
  29. jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
  30. jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
  31. jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
  32. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
  33. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
  34. jaclang/compiler/passes/main/tests/test_checker_pass.py +265 -0
  35. jaclang/compiler/passes/main/tests/test_predynamo_pass.py +57 -0
  36. jaclang/compiler/passes/main/type_checker_pass.py +36 -61
  37. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +204 -44
  38. jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
  39. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  40. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
  41. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +171 -11
  42. jaclang/compiler/passes/transform.py +12 -8
  43. jaclang/compiler/program.py +14 -6
  44. jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
  45. jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
  46. jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
  47. jaclang/compiler/tests/fixtures/python_module.py +1 -0
  48. jaclang/compiler/tests/test_importer.py +39 -0
  49. jaclang/compiler/tests/test_parser.py +49 -0
  50. jaclang/compiler/type_system/operations.py +104 -0
  51. jaclang/compiler/type_system/type_evaluator.py +470 -47
  52. jaclang/compiler/type_system/type_utils.py +246 -0
  53. jaclang/compiler/type_system/types.py +58 -2
  54. jaclang/compiler/unitree.py +79 -94
  55. jaclang/langserve/engine.jac +253 -230
  56. jaclang/langserve/server.jac +46 -15
  57. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  58. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  59. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  60. jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
  61. jaclang/langserve/tests/server_test/circle_template.jac +80 -0
  62. jaclang/langserve/tests/server_test/glob_template.jac +4 -0
  63. jaclang/langserve/tests/server_test/test_lang_serve.py +154 -312
  64. jaclang/langserve/tests/server_test/utils.py +153 -116
  65. jaclang/langserve/tests/test_dev_server.py +1 -1
  66. jaclang/langserve/tests/test_server.py +30 -86
  67. jaclang/langserve/utils.jac +56 -63
  68. jaclang/runtimelib/machine.py +7 -0
  69. jaclang/runtimelib/meta_importer.py +27 -1
  70. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  71. jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
  72. jaclang/settings.py +18 -14
  73. jaclang/tests/fixtures/abc_check.jac +3 -3
  74. jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
  75. jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
  76. jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
  77. jaclang/tests/fixtures/jac_run_py_bugs.py +18 -0
  78. jaclang/tests/fixtures/jac_run_py_import.py +13 -0
  79. jaclang/tests/fixtures/lambda_arg_annotation.jac +15 -0
  80. jaclang/tests/fixtures/lambda_self.jac +18 -0
  81. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  82. jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
  83. jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
  84. jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
  85. jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
  86. jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
  87. jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
  88. jaclang/tests/fixtures/py2jac_params.py +8 -0
  89. jaclang/tests/fixtures/run_test.jac +4 -4
  90. jaclang/tests/test_cli.py +103 -18
  91. jaclang/tests/test_language.py +74 -16
  92. jaclang/utils/helpers.py +47 -2
  93. jaclang/utils/module_resolver.py +11 -1
  94. jaclang/utils/test.py +8 -0
  95. jaclang/utils/treeprinter.py +0 -18
  96. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/METADATA +3 -3
  97. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/RECORD +99 -62
  98. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/WHEEL +1 -1
  99. jaclang/compiler/passes/main/inheritance_pass.py +0 -131
  100. jaclang/langserve/dev_engine.jac +0 -645
  101. jaclang/langserve/dev_server.jac +0 -201
  102. jaclang/langserve/tests/server_test/code_test.py +0 -0
  103. {jaclang-0.8.6.dist-info → jaclang-0.8.8.dist-info}/entry_points.txt +0 -0
@@ -1000,37 +1000,45 @@ class PyastGenPass(UniPass):
1000
1000
  pass
1001
1001
 
1002
1002
  def exit_func_signature(self, node: uni.FuncSignature) -> None:
1003
+ posonlyargs = [i.gen.py_ast[0] for i in node.posonly_params]
1004
+ vararg = node.varargs.gen.py_ast[0] if node.varargs else None
1005
+ kwarg = node.kwargs.gen.py_ast[0] if node.kwargs else None
1003
1006
  params = (
1004
1007
  [self.sync(ast3.arg(arg="self", annotation=None))]
1005
- if (abl := node.find_parent_of_type(uni.Ability))
1008
+ if (abl := node.parent)
1009
+ and isinstance(abl, uni.Ability)
1006
1010
  and abl.is_method
1007
1011
  and not node.is_static
1008
1012
  and not node.is_in_py_class
1009
1013
  else []
1010
1014
  )
1011
- vararg = None
1012
- kwarg = None
1013
- for i in node.params:
1014
- if i.unpack and i.unpack.value == "*":
1015
- vararg = i.gen.py_ast[0]
1016
- elif i.unpack and i.unpack.value == "**":
1017
- kwarg = i.gen.py_ast[0]
1015
+ if posonlyargs:
1016
+ posonlyargs = params + posonlyargs
1017
+ params = [i.gen.py_ast[0] for i in node.params]
1018
+ else:
1019
+ params = params + [i.gen.py_ast[0] for i in node.params]
1020
+ defaults = []
1021
+ for i in [*node.posonly_params, *node.params]:
1022
+ if i.value:
1023
+ defaults.append(cast(ast3.expr, i.value.gen.py_ast[0]))
1024
+ kwonly_args = [i.gen.py_ast[0] for i in node.kwonlyargs]
1025
+ # kw_defaults must be the same length as kwonlyargs
1026
+ # it will have None for args that don't have defaults
1027
+ kw_defaults: list[ast3.expr | None] = []
1028
+ for i in node.kwonlyargs:
1029
+ if i.value:
1030
+ kw_defaults.append(cast(ast3.expr, i.value.gen.py_ast[0]))
1018
1031
  else:
1019
- (
1020
- params.append(i.gen.py_ast[0])
1021
- if isinstance(i.gen.py_ast[0], ast3.arg)
1022
- else self.ice("This list should only be Args")
1023
- )
1024
- defaults = [x.value.gen.py_ast[0] for x in node.params if x.value]
1032
+ kw_defaults.append(None)
1025
1033
  node.gen.py_ast = [
1026
1034
  self.sync(
1027
1035
  ast3.arguments(
1028
- posonlyargs=[],
1036
+ posonlyargs=[cast(ast3.arg, param) for param in posonlyargs],
1029
1037
  args=[cast(ast3.arg, param) for param in params],
1030
- kwonlyargs=[],
1038
+ kwonlyargs=kwonly_args,
1031
1039
  vararg=cast(ast3.arg, vararg) if vararg else None,
1032
1040
  kwarg=cast(ast3.arg, kwarg) if kwarg else None,
1033
- kw_defaults=[],
1041
+ kw_defaults=kw_defaults,
1034
1042
  defaults=[cast(ast3.expr, default) for default in defaults],
1035
1043
  )
1036
1044
  )
@@ -1466,20 +1474,23 @@ class PyastGenPass(UniPass):
1466
1474
  ]
1467
1475
 
1468
1476
  def exit_assert_stmt(self, node: uni.AssertStmt) -> None:
1469
- node.gen.py_ast = [
1470
- self.sync(
1471
- ast3.Assert(
1472
- test=cast(ast3.expr, node.condition.gen.py_ast[0]),
1473
- msg=(
1474
- cast(ast3.expr, node.error_msg.gen.py_ast[0])
1475
- if node.error_msg
1476
- else None
1477
- ),
1477
+ if isinstance(node.parent, uni.Test):
1478
+ self.assert_helper(node)
1479
+ else:
1480
+ node.gen.py_ast = [
1481
+ self.sync(
1482
+ ast3.Assert(
1483
+ test=cast(ast3.expr, node.condition.gen.py_ast[0]),
1484
+ msg=(
1485
+ cast(ast3.expr, node.error_msg.gen.py_ast[0])
1486
+ if node.error_msg
1487
+ else None
1488
+ ),
1489
+ )
1478
1490
  )
1479
- )
1480
- ]
1491
+ ]
1481
1492
 
1482
- def exit_check_stmt(self, node: uni.CheckStmt) -> None:
1493
+ def assert_helper(self, node: uni.AssertStmt) -> None:
1483
1494
  """Sub objects.
1484
1495
 
1485
1496
  target: ExprType,
@@ -1535,16 +1546,16 @@ class PyastGenPass(UniPass):
1535
1546
 
1536
1547
  # By default the check expression will become assertTrue(<expr>), unless any pattern detected.
1537
1548
  assert_func_name = "assertTrue"
1538
- assert_args_list = node.target.gen.py_ast
1549
+ assert_args_list = node.condition.gen.py_ast
1539
1550
 
1540
1551
  # Compare operations. Note that We're only considering the compare
1541
1552
  # operation with a single operation ie. a < b < c is ignored here.
1542
1553
  if (
1543
- isinstance(node.target, uni.CompareExpr)
1544
- and isinstance(node.target.gen.py_ast[0], ast3.Compare)
1545
- and len(node.target.ops) == 1
1554
+ isinstance(node.condition, uni.CompareExpr)
1555
+ and isinstance(node.condition.gen.py_ast[0], ast3.Compare)
1556
+ and len(node.condition.ops) == 1
1546
1557
  ):
1547
- expr: uni.CompareExpr = node.target
1558
+ expr: uni.CompareExpr = node.condition
1548
1559
  opty: uni.Token = expr.ops[0]
1549
1560
 
1550
1561
  optype2fn = {
@@ -1578,10 +1589,10 @@ class PyastGenPass(UniPass):
1578
1589
  assert_args_list.pop()
1579
1590
 
1580
1591
  # Check if 'isinstance' is called.
1581
- elif isinstance(node.target, uni.FuncCall) and isinstance(
1582
- node.target.gen.py_ast[0], ast3.Call
1592
+ elif isinstance(node.condition, uni.FuncCall) and isinstance(
1593
+ node.condition.gen.py_ast[0], ast3.Call
1583
1594
  ):
1584
- res = check_node_isinstance_call(node.target)
1595
+ res = check_node_isinstance_call(node.condition)
1585
1596
  if res.isit:
1586
1597
  # These assertions will make mypy happy.
1587
1598
  assert isinstance(res.inst, ast3.AST)
@@ -1591,12 +1602,12 @@ class PyastGenPass(UniPass):
1591
1602
 
1592
1603
  # Check if 'not isinstance(<expr>, <expr>)' is called.
1593
1604
  elif (
1594
- isinstance(node.target, uni.UnaryExpr)
1595
- and isinstance(node.target, uni.UnaryExpr)
1596
- and isinstance(node.target.operand, uni.FuncCall)
1597
- and isinstance(node.target.operand, uni.UnaryExpr)
1605
+ isinstance(node.condition, uni.UnaryExpr)
1606
+ and isinstance(node.condition, uni.UnaryExpr)
1607
+ and isinstance(node.condition.operand, uni.FuncCall)
1608
+ and isinstance(node.condition.operand, uni.UnaryExpr)
1598
1609
  ):
1599
- res = check_node_isinstance_call(node.target.operand)
1610
+ res = check_node_isinstance_call(node.condition.operand)
1600
1611
  if res.isit:
1601
1612
  # These assertions will make mypy happy.
1602
1613
  assert isinstance(res.inst, ast3.AST)
@@ -1609,14 +1620,14 @@ class PyastGenPass(UniPass):
1609
1620
  # the almost equal functionality (snice there is no almost equal operator in jac and never needed ig.).
1610
1621
 
1611
1622
  # Check if 'almostEqual' is called.
1612
- if isinstance(node.target, uni.FuncCall) and isinstance(
1613
- node.target.gen.py_ast[0], ast3.Call
1623
+ if isinstance(node.condition, uni.FuncCall) and isinstance(
1624
+ node.condition.gen.py_ast[0], ast3.Call
1614
1625
  ):
1615
- func = node.target.target
1626
+ func = node.condition.target
1616
1627
  if isinstance(func, uni.Name) and func.value == "almostEqual":
1617
1628
  assert_func_name = "assertAlmostEqual"
1618
1629
  assert_args_list = []
1619
- for param in node.target.params:
1630
+ for param in node.condition.params:
1620
1631
  assert_args_list.append(param.gen.py_ast[0])
1621
1632
 
1622
1633
  # assert_func_expr = "Con.JAC_CHECK.value.assertXXX"
@@ -2123,6 +2134,10 @@ class PyastGenPass(UniPass):
2123
2134
  ]
2124
2135
 
2125
2136
  def exit_lambda_expr(self, node: uni.LambdaExpr) -> None:
2137
+ # Python lambda expressions don't support type annotations
2138
+ if node.signature:
2139
+ self._remove_lambda_param_annotations(node.signature)
2140
+
2126
2141
  node.gen.py_ast = [
2127
2142
  self.sync(
2128
2143
  ast3.Lambda(
@@ -2144,6 +2159,11 @@ class PyastGenPass(UniPass):
2144
2159
  )
2145
2160
  ]
2146
2161
 
2162
+ def _remove_lambda_param_annotations(self, signature: uni.FuncSignature) -> None:
2163
+ for param in signature.params:
2164
+ if param.gen.py_ast and isinstance(param.gen.py_ast[0], ast3.arg):
2165
+ param.gen.py_ast[0].annotation = None
2166
+
2147
2167
  def exit_unary_expr(self, node: uni.UnaryExpr) -> None:
2148
2168
  op_cls = UNARY_OP_MAP.get(node.op.name)
2149
2169
  if op_cls:
@@ -2400,7 +2420,7 @@ class PyastGenPass(UniPass):
2400
2420
  self.sync(
2401
2421
  ast3.Attribute(
2402
2422
  value=cast(ast3.expr, node.target.gen.py_ast[0]),
2403
- attr=(node.right.sym_name),
2423
+ attr=node.right.sym_name,
2404
2424
  ctx=cast(ast3.expr_context, node.right.py_ctx_func()),
2405
2425
  )
2406
2426
  )
@@ -2708,14 +2728,22 @@ class PyastGenPass(UniPass):
2708
2728
  keywords=[],
2709
2729
  )
2710
2730
  )
2711
-
2712
- pynode = self.sync(
2713
- ast3.Call(
2714
- func=self.jaclib_obj("refs"),
2715
- args=[pynode],
2716
- keywords=[],
2731
+ if node.is_async:
2732
+ pynode = self.sync(
2733
+ ast3.Call(
2734
+ func=self.jaclib_obj("arefs"),
2735
+ args=[pynode],
2736
+ keywords=[],
2737
+ )
2738
+ )
2739
+ else:
2740
+ pynode = self.sync(
2741
+ ast3.Call(
2742
+ func=self.jaclib_obj("refs"),
2743
+ args=[pynode],
2744
+ keywords=[],
2745
+ )
2717
2746
  )
2718
- )
2719
2747
 
2720
2748
  node.gen.py_ast = [pynode]
2721
2749
 
@@ -2997,7 +3025,7 @@ class PyastGenPass(UniPass):
2997
3025
  node.gen.py_ast = [self.sync(op_cls())]
2998
3026
 
2999
3027
  def exit_name(self, node: uni.Name) -> None:
3000
- name = node.sym_name[2:] if node.sym_name.startswith("<>") else node.sym_name
3028
+ name = node.sym_name
3001
3029
  node.gen.py_ast = [self.sync(ast3.Name(id=name, ctx=node.py_ctx_func()))]
3002
3030
 
3003
3031
  def exit_float(self, node: uni.Float) -> None:
@@ -16,7 +16,7 @@ from __future__ import annotations
16
16
 
17
17
  import ast as py_ast
18
18
  import os
19
- from typing import Optional, Sequence, TYPE_CHECKING, TypeAlias, TypeVar
19
+ from typing import Optional, Sequence, TYPE_CHECKING, TypeAlias, TypeVar, cast
20
20
 
21
21
  import jaclang.compiler.unitree as uni
22
22
  from jaclang.compiler.constant import Tokens as Tok
@@ -141,17 +141,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
141
141
 
142
142
  reserved_keywords = [v for _, v in TOKEN_MAP.items()]
143
143
 
144
- value = node.name if node.name not in reserved_keywords else f"<>{node.name}"
145
144
  name = uni.Name(
146
145
  orig_src=self.orig_src,
147
146
  name=Tok.NAME,
148
- value=value,
147
+ value=node.name,
149
148
  line=node.lineno,
150
149
  end_line=node.end_lineno if node.end_lineno else node.lineno,
151
150
  col_start=node.col_offset,
152
151
  col_end=node.col_offset + len(node.name),
153
152
  pos_start=0,
154
153
  pos_end=0,
154
+ is_kwesc=(node.name in reserved_keywords),
155
155
  )
156
156
  body = [self.convert(i) for i in node.body]
157
157
  valid = [i for i in body if isinstance(i, (uni.CodeBlockStmt))]
@@ -285,8 +285,8 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
285
285
  and body_stmt.signature.params
286
286
  ):
287
287
  for param in body_stmt.signature.params:
288
- if param.name.value == "self":
289
- param.type_tag = uni.SubTag[uni.Expr](name, kid=[name])
288
+ if param.name.value == "self" and param.type_tag:
289
+ param.type_tag.tag.value = name.value
290
290
  doc = (
291
291
  body[0].expr
292
292
  if isinstance(body[0], uni.ExprStmt)
@@ -748,17 +748,14 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
748
748
  attribute = uni.Name(
749
749
  orig_src=self.orig_src,
750
750
  name=Tok.NAME,
751
- value=(
752
- ("<>" + node.attr)
753
- if node.attr == "init"
754
- else "init" if node.attr == "__init__" else node.attr
755
- ),
751
+ value="init" if node.attr == "__init__" else node.attr,
756
752
  line=node.lineno,
757
753
  end_line=node.end_lineno if node.end_lineno else node.lineno,
758
754
  col_start=node.col_offset,
759
755
  col_end=node.col_offset + len(node.attr),
760
756
  pos_start=0,
761
757
  pos_end=0,
758
+ is_kwesc=node.attr == "init",
762
759
  )
763
760
  if isinstance(value, uni.Expr):
764
761
  return uni.AtomTrailer(
@@ -1680,18 +1677,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
1680
1677
  for _, v in TOKEN_MAP.items()
1681
1678
  if v not in ["float", "int", "str", "bool", "self"]
1682
1679
  ]
1683
-
1684
- value = node.id if node.id not in reserved_keywords else f"<>{node.id}"
1685
1680
  ret = uni.Name(
1686
1681
  orig_src=self.orig_src,
1687
1682
  name=Tok.NAME,
1688
- value=value,
1683
+ value=node.id,
1689
1684
  line=node.lineno,
1690
1685
  end_line=node.end_lineno if node.end_lineno else node.lineno,
1691
1686
  col_start=node.col_offset,
1692
1687
  col_end=node.col_offset + len(node.id),
1693
1688
  pos_start=0,
1694
1689
  pos_end=0,
1690
+ is_kwesc=(node.id in reserved_keywords),
1695
1691
  )
1696
1692
  return ret
1697
1693
 
@@ -1735,18 +1731,18 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
1735
1731
 
1736
1732
  names: list[uni.NameAtom] = []
1737
1733
  for name in node.names:
1738
- value = name if name not in reserved_keywords else f"<>{name}"
1739
1734
  names.append(
1740
1735
  uni.Name(
1741
1736
  orig_src=self.orig_src,
1742
1737
  name=Tok.NAME,
1743
- value=value,
1738
+ value=name,
1744
1739
  line=node.lineno,
1745
1740
  end_line=node.end_lineno if node.end_lineno else node.lineno,
1746
1741
  col_start=node.col_offset,
1747
1742
  col_end=node.col_offset + len(name),
1748
1743
  pos_start=0,
1749
1744
  pos_end=0,
1745
+ is_kwesc=(name in reserved_keywords),
1750
1746
  )
1751
1747
  )
1752
1748
  return uni.NonLocalStmt(target=names, kid=names)
@@ -2056,17 +2052,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2056
2052
  if v not in ["float", "int", "str", "bool", "self"]
2057
2053
  ]
2058
2054
 
2059
- value = node.arg if node.arg not in reserved_keywords else f"<>{node.arg}"
2060
2055
  name = uni.Name(
2061
2056
  orig_src=self.orig_src,
2062
2057
  name=Tok.NAME,
2063
- value=value,
2058
+ value=node.arg,
2064
2059
  line=node.lineno,
2065
2060
  end_line=node.end_lineno if node.end_lineno else node.lineno,
2066
2061
  col_start=node.col_offset,
2067
2062
  col_end=node.col_offset + len(node.arg),
2068
2063
  pos_start=0,
2069
2064
  pos_end=0,
2065
+ is_kwesc=(node.arg in reserved_keywords),
2070
2066
  )
2071
2067
  ann_expr = (
2072
2068
  self.convert(node.annotation)
@@ -2095,6 +2091,7 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2095
2091
  """Process python node.
2096
2092
 
2097
2093
  class arguments(AST):
2094
+ posonlyargs: list[arg]
2098
2095
  args: list[arg]
2099
2096
  vararg: arg | None
2100
2097
  kwonlyargs: list[arg]
@@ -2102,9 +2099,23 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2102
2099
  kwarg: arg | None
2103
2100
  defaults: list[expr]
2104
2101
  """
2105
- args = [self.convert(arg) for arg in node.args]
2102
+
2103
+ def _apply_kind(params: list, kind: uni.ParamKind) -> list:
2104
+ for param in params:
2105
+ cast(uni.ParamVar, param).param_kind = kind
2106
+ return params
2107
+
2108
+ posonlyargs = _apply_kind(
2109
+ [self.convert(arg) for arg in node.posonlyargs], uni.ParamKind.POSONLY
2110
+ )
2111
+ args = _apply_kind(
2112
+ [self.convert(arg) for arg in node.args], uni.ParamKind.NORMAL
2113
+ )
2114
+
2106
2115
  vararg = self.convert(node.vararg) if node.vararg else None
2116
+
2107
2117
  if vararg and isinstance(vararg, uni.ParamVar):
2118
+ vararg.param_kind = uni.ParamKind.VARARG
2108
2119
  vararg.unpack = uni.Token(
2109
2120
  orig_src=self.orig_src,
2110
2121
  name=Tok.STAR_MUL,
@@ -2117,7 +2128,10 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2117
2128
  pos_end=0,
2118
2129
  )
2119
2130
  vararg.add_kids_left([vararg.unpack])
2120
- kwonlyargs = [self.convert(arg) for arg in node.kwonlyargs]
2131
+
2132
+ kwonlyargs = _apply_kind(
2133
+ [self.convert(arg) for arg in node.kwonlyargs], uni.ParamKind.KWONLY
2134
+ )
2121
2135
  for i in range(len(kwonlyargs)):
2122
2136
  kwa = kwonlyargs[i]
2123
2137
  kwd = node.kw_defaults[i]
@@ -2131,6 +2145,7 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2131
2145
  kwa.add_kids_right([kwa.value])
2132
2146
  kwarg = self.convert(node.kwarg) if node.kwarg else None
2133
2147
  if kwarg and isinstance(kwarg, uni.ParamVar):
2148
+ kwarg.param_kind = uni.ParamKind.KWARG
2134
2149
  kwarg.unpack = uni.Token(
2135
2150
  orig_src=self.orig_src,
2136
2151
  name=Tok.STAR_POW,
@@ -2144,29 +2159,42 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2144
2159
  )
2145
2160
  kwarg.add_kids_left([kwarg.unpack])
2146
2161
  defaults = [self.convert(expr) for expr in node.defaults]
2147
- params = [*args]
2148
- for param, default in zip(params[::-1], defaults[::-1]):
2149
- if isinstance(default, uni.Expr) and isinstance(param, uni.ParamVar):
2150
- param.value = default
2151
- param.add_kids_right([default])
2152
- if vararg:
2153
- params.append(vararg)
2154
- params += kwonlyargs
2155
- if kwarg:
2156
- params.append(kwarg)
2157
- params += defaults
2158
-
2159
- valid_params = [param for param in params if isinstance(param, uni.ParamVar)]
2160
- if valid_params:
2161
- fs_params = valid_params
2162
+ # iterate reverse to match from the end
2163
+ for para in [*posonlyargs, *args][::-1]:
2164
+ if not defaults:
2165
+ break
2166
+ default = defaults.pop()
2167
+ if (
2168
+ default
2169
+ and isinstance(para, uni.ParamVar)
2170
+ and isinstance(default, uni.Expr)
2171
+ ):
2172
+ para.value = default
2173
+ para.add_kids_right([para.value])
2174
+
2175
+ if kwonlyargs or args or posonlyargs or vararg or kwarg:
2176
+ kids = []
2177
+ kids.extend(posonlyargs) if posonlyargs else None
2178
+ kids.extend(args) if args else None
2179
+ kids.append(vararg) if vararg else None
2180
+ kids.extend(kwonlyargs) if kwonlyargs else None
2181
+ kids.append(kwarg) if kwarg else None
2162
2182
  return uni.FuncSignature(
2163
- params=fs_params,
2183
+ posonly_params=posonlyargs,
2184
+ params=args,
2185
+ varargs=vararg,
2186
+ kwonlyargs=kwonlyargs,
2187
+ kwargs=kwarg,
2164
2188
  return_type=None,
2165
- kid=fs_params,
2189
+ kid=kids,
2166
2190
  )
2167
2191
  else:
2168
2192
  return uni.FuncSignature(
2193
+ posonly_params=posonlyargs,
2169
2194
  params=[],
2195
+ varargs=vararg,
2196
+ kwonlyargs=kwonlyargs,
2197
+ kwargs=kwarg,
2170
2198
  return_type=None,
2171
2199
  kid=[self.operator(Tok.LPAREN, "("), self.operator(Tok.RPAREN, ")")],
2172
2200
  )
@@ -2343,19 +2371,17 @@ class PyastBuildPass(Transform[uni.PythonModuleAst, uni.Module]):
2343
2371
  from jaclang.compiler import TOKEN_MAP
2344
2372
 
2345
2373
  reserved_keywords = [v for _, v in TOKEN_MAP.items()]
2346
- arg_value = (
2347
- node.arg if node.arg not in reserved_keywords else f"<>{node.arg}"
2348
- )
2349
2374
  arg = uni.Name(
2350
2375
  orig_src=self.orig_src,
2351
2376
  name=Tok.NAME,
2352
- value=arg_value,
2377
+ value=node.arg,
2353
2378
  line=node.lineno,
2354
2379
  end_line=node.end_lineno if node.end_lineno else node.lineno,
2355
2380
  col_start=node.col_offset,
2356
2381
  col_end=node.col_offset + len(node.arg if node.arg else "_"),
2357
2382
  pos_start=0,
2358
2383
  pos_end=0,
2384
+ is_kwesc=(node.arg in reserved_keywords),
2359
2385
  )
2360
2386
  value = self.convert(node.value)
2361
2387
  if isinstance(value, uni.Expr):
@@ -75,7 +75,7 @@ class SymTabBuildPass(UniPass):
75
75
  def exit_module_path(self, node: uni.ModulePath) -> None:
76
76
  if node.alias:
77
77
  node.alias.sym_tab.def_insert(node.alias, single_decl="import")
78
- elif node.path and isinstance(node.path[0], uni.Name):
78
+ elif node.path:
79
79
  if node.parent_of_type(uni.Import) and not (
80
80
  node.parent_of_type(uni.Import).from_loc
81
81
  and node.parent_of_type(uni.Import).is_jac
@@ -0,0 +1,2 @@
1
+
2
+ import from imported_sym { foo }
@@ -0,0 +1,6 @@
1
+ import from import_sym { foo }
2
+
3
+ with entry {
4
+ a: str = foo(); # <-- Ok
5
+ b: int = foo(); # <-- Error
6
+ }
@@ -0,0 +1,5 @@
1
+
2
+
3
+ def foo() -> str {
4
+ return "foo";
5
+ }
@@ -0,0 +1,37 @@
1
+
2
+ class Foo {
3
+ def bar(self: Foo, a:int) -> None {}
4
+ static def baz(self: int, a: int) -> None {}
5
+ }
6
+
7
+ def foo(a: int, b: int, /, c:int, d:int, *args:int, e:int, f:int, **kwargs:int) -> None {}
8
+ def bar(a: int, b: int, /, c:int, d:int, e:int, f:int) -> None {}
9
+ def baz(a: int, *, b:int) -> None {}
10
+
11
+ with entry {
12
+ f = Foo();
13
+
14
+ f.bar();
15
+ f.bar(1);
16
+ f.bar(1, 2);
17
+
18
+ f.baz();
19
+ f.baz(1);
20
+ f.baz(1, 2);
21
+
22
+ foo(1, 2, 3, d=4, e=5, f=6, g=7, h=8); # c is positional and d is named
23
+ foo(1, 2, 3, 4, 5, 6, 7, 8, e=5, f=6); # marching extra with *args
24
+ foo(1, 2, d=3, e=4, f=5, c=4); # order does not matter for named
25
+
26
+ foo(1, 2, 3, d=4, e=5, g=7, h=8); # missing argument 'f'
27
+ foo(1, b=2, c=3, d=4, e=5, f=6); # b is positional only
28
+
29
+ bar(1, 2, 3, 4, 5, f=6);
30
+ bar(1, 2, 3, 4, 5, 6, 7, 8, 9); # too many args
31
+ bar(1, 2, 3, 4, 5, 6, c=3); # already matched
32
+ bar(1, 2, 3, 4, 5, 6, h=1); # h is not matched
33
+
34
+ baz(a=1, b=2);
35
+ baz(1, b=2); # a can be both positional and keyword
36
+ baz(1, 2); # 'b' can only be keyword arg
37
+ }
@@ -0,0 +1,18 @@
1
+
2
+ class Foo {
3
+ def first_is_self(self: Foo) -> None {}
4
+
5
+ def with_default_args(self: Foo, a:int, b:int=42) -> None {}
6
+ }
7
+
8
+
9
+ with entry {
10
+ f = Foo();
11
+ f.first_is_self(); # <-- Ok
12
+ f.first_is_self(f); # <-- Error
13
+
14
+ f.with_default_args(1); # <-- Ok
15
+ f.with_default_args(1, 2); # <-- Ok
16
+ f.with_default_args(1, 2, 3); # <-- Error
17
+ f.with_default_args(); # <-- Error
18
+ }
@@ -0,0 +1,21 @@
1
+ node B {
2
+ def __mul__(other: B) -> int {
3
+ return 0;
4
+ }
5
+ }
6
+
7
+ node A {
8
+ def __add__(other: A) -> B {
9
+ return B();
10
+ }
11
+ }
12
+
13
+ with entry {
14
+ a: A = A();
15
+
16
+ r1: B = a + a; # <-- Ok
17
+ r2: A = a + a; # <-- Error
18
+
19
+ r3: int = (a+a) * B(); # <-- Ok
20
+ r4: str = (a+a) * B(); # <-- Error
21
+ }
@@ -0,0 +1,12 @@
1
+
2
+ node Foo {
3
+ has i: int = 0;
4
+ }
5
+
6
+ with entry {
7
+ cls = Foo;
8
+ inst = cls(); # <-- Call expression target of class type
9
+
10
+ inst.i = 42; # <-- Ok
11
+ inst.i = 'str'; # <-- Error
12
+ }
@@ -0,0 +1,18 @@
1
+
2
+ obj Animal {}
3
+ obj Cat(Animal) {}
4
+ obj Lion(Cat) {}
5
+
6
+ obj NotAnimal {}
7
+
8
+ def animal_func(a: Animal) -> None {}
9
+
10
+ with entry {
11
+ cat: Cat = Cat();
12
+ lion: Lion = Lion();
13
+ not_animal: NotAnimal = NotAnimal();
14
+
15
+ animal_func(cat); # <-- Ok
16
+ animal_func(lion); # <-- Ok
17
+ animal_func(not_animal); # <-- Error
18
+ }
@@ -0,0 +1,4 @@
1
+
2
+ with entry {
3
+ x = x;
4
+ }
@@ -0,0 +1,9 @@
1
+
2
+ def foo() -> int {
3
+ return 42;
4
+ }
5
+
6
+ with entry {
7
+ i: int = foo(); # <-- Ok
8
+ s: str = foo(); # <-- Error
9
+ }
@@ -0,0 +1,7 @@
1
+
2
+
3
+ with entry {
4
+ pi = 3.14; # <-- infer the type
5
+ f: float = pi; # <-- OK
6
+ s: str = pi; # <-- Error
7
+ }
@@ -0,0 +1,13 @@
1
+ import from scipy { stats, optimize }
2
+ import from utils.fake_helpers { helper_func }
3
+ import from non_existent_module { foo }
4
+ import nonexistent_module as nm;
5
+
6
+
7
+ with entry {
8
+ a: int = stats.norm.cdf(0);
9
+ d: float = optimize.minimize_scalar(lambda x: int: x ** 2).fun;
10
+ result = helper_func();
11
+ b: int = foo();
12
+ c = nm.some_func();
13
+ }