jaclang 0.8.7__py3-none-any.whl → 0.8.9__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 (99) hide show
  1. jaclang/cli/cli.py +77 -29
  2. jaclang/cli/cmdreg.py +44 -0
  3. jaclang/compiler/constant.py +6 -2
  4. jaclang/compiler/jac.lark +37 -47
  5. jaclang/compiler/larkparse/jac_parser.py +2 -2
  6. jaclang/compiler/parser.py +356 -61
  7. jaclang/compiler/passes/main/__init__.py +2 -4
  8. jaclang/compiler/passes/main/def_use_pass.py +1 -4
  9. jaclang/compiler/passes/main/predynamo_pass.py +221 -0
  10. jaclang/compiler/passes/main/pyast_gen_pass.py +221 -135
  11. jaclang/compiler/passes/main/pyast_load_pass.py +54 -20
  12. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  13. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym.jac +2 -0
  14. jaclang/compiler/passes/main/tests/fixtures/checker/import_sym_test.jac +6 -0
  15. jaclang/compiler/passes/main/tests/fixtures/checker/imported_sym.jac +5 -0
  16. jaclang/compiler/passes/main/tests/fixtures/checker_arg_param_match.jac +37 -0
  17. jaclang/compiler/passes/main/tests/fixtures/checker_arity.jac +18 -0
  18. jaclang/compiler/passes/main/tests/fixtures/checker_cat_is_animal.jac +18 -0
  19. jaclang/compiler/passes/main/tests/fixtures/checker_float.jac +7 -0
  20. jaclang/compiler/passes/main/tests/fixtures/checker_param_types.jac +11 -0
  21. jaclang/compiler/passes/main/tests/fixtures/checker_self_type.jac +9 -0
  22. jaclang/compiler/passes/main/tests/fixtures/checker_sym_inherit.jac +42 -0
  23. jaclang/compiler/passes/main/tests/fixtures/predynamo_fix3.jac +43 -0
  24. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_assign.jac +13 -0
  25. jaclang/compiler/passes/main/tests/fixtures/predynamo_where_return.jac +11 -0
  26. jaclang/compiler/passes/main/tests/test_checker_pass.py +190 -0
  27. jaclang/compiler/passes/main/tests/test_predynamo_pass.py +56 -0
  28. jaclang/compiler/passes/main/type_checker_pass.py +29 -73
  29. jaclang/compiler/passes/tool/doc_ir_gen_pass.py +302 -58
  30. jaclang/compiler/passes/tool/jac_formatter_pass.py +119 -69
  31. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  32. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +4 -5
  33. jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +7 -1
  34. jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +276 -10
  35. jaclang/compiler/passes/transform.py +12 -8
  36. jaclang/compiler/program.py +19 -7
  37. jaclang/compiler/tests/fixtures/jac_import_py_files.py +4 -0
  38. jaclang/compiler/tests/fixtures/jac_module.jac +3 -0
  39. jaclang/compiler/tests/fixtures/multiple_syntax_errors.jac +10 -0
  40. jaclang/compiler/tests/fixtures/python_module.py +1 -0
  41. jaclang/compiler/tests/test_importer.py +39 -0
  42. jaclang/compiler/tests/test_parser.py +49 -0
  43. jaclang/compiler/type_system/type_evaluator.jac +959 -0
  44. jaclang/compiler/type_system/type_utils.py +246 -0
  45. jaclang/compiler/type_system/types.py +58 -2
  46. jaclang/compiler/unitree.py +102 -107
  47. jaclang/langserve/engine.jac +138 -159
  48. jaclang/langserve/server.jac +25 -1
  49. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  50. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  51. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  52. jaclang/langserve/tests/fixtures/completion_test_err.jac +10 -0
  53. jaclang/langserve/tests/server_test/circle_template.jac +80 -0
  54. jaclang/langserve/tests/server_test/glob_template.jac +4 -0
  55. jaclang/langserve/tests/server_test/test_lang_serve.py +154 -309
  56. jaclang/langserve/tests/server_test/utils.py +153 -116
  57. jaclang/langserve/tests/test_server.py +21 -84
  58. jaclang/langserve/utils.jac +12 -15
  59. jaclang/lib.py +17 -0
  60. jaclang/runtimelib/archetype.py +25 -25
  61. jaclang/runtimelib/constructs.py +2 -2
  62. jaclang/runtimelib/machine.py +63 -46
  63. jaclang/runtimelib/meta_importer.py +27 -1
  64. jaclang/runtimelib/tests/fixtures/custom_access_validation.jac +1 -1
  65. jaclang/runtimelib/tests/fixtures/savable_object.jac +2 -2
  66. jaclang/settings.py +19 -16
  67. jaclang/tests/fixtures/abc_check.jac +3 -3
  68. jaclang/tests/fixtures/arch_rel_import_creation.jac +12 -12
  69. jaclang/tests/fixtures/attr_pattern_case.jac +18 -0
  70. jaclang/tests/fixtures/chandra_bugs2.jac +3 -3
  71. jaclang/tests/fixtures/create_dynamic_archetype.jac +13 -13
  72. jaclang/tests/fixtures/funccall_genexpr.jac +7 -0
  73. jaclang/tests/fixtures/funccall_genexpr.py +5 -0
  74. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  75. jaclang/tests/fixtures/params/param_syntax_err.jac +9 -0
  76. jaclang/tests/fixtures/params/test_complex_params.jac +42 -0
  77. jaclang/tests/fixtures/params/test_failing_kwonly.jac +207 -0
  78. jaclang/tests/fixtures/params/test_failing_posonly.jac +116 -0
  79. jaclang/tests/fixtures/params/test_failing_varargs.jac +300 -0
  80. jaclang/tests/fixtures/params/test_kwonly_params.jac +29 -0
  81. jaclang/tests/fixtures/py2jac_params.py +8 -0
  82. jaclang/tests/fixtures/run_test.jac +4 -4
  83. jaclang/tests/test_cli.py +159 -7
  84. jaclang/tests/test_language.py +213 -38
  85. jaclang/tests/test_reference.py +3 -1
  86. jaclang/utils/helpers.py +67 -6
  87. jaclang/utils/module_resolver.py +10 -0
  88. jaclang/utils/test.py +8 -0
  89. jaclang/utils/tests/test_lang_tools.py +4 -15
  90. jaclang/utils/treeprinter.py +0 -18
  91. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/METADATA +1 -2
  92. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/RECORD +95 -65
  93. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/WHEEL +1 -1
  94. jaclang/compiler/passes/main/inheritance_pass.py +0 -131
  95. jaclang/compiler/type_system/type_evaluator.py +0 -560
  96. jaclang/langserve/dev_engine.jac +0 -645
  97. jaclang/langserve/dev_server.jac +0 -201
  98. /jaclang/{langserve/tests/server_test/code_test.py → tests/fixtures/py2jac_empty.py} +0 -0
  99. {jaclang-0.8.7.dist-info → jaclang-0.8.9.dist-info}/entry_points.txt +0 -0
jaclang/tests/test_cli.py CHANGED
@@ -7,6 +7,7 @@ import os
7
7
  import re
8
8
  import subprocess
9
9
  import sys
10
+ import tempfile
10
11
  import traceback
11
12
  import unittest
12
13
  from jaclang.cli import cli
@@ -127,12 +128,15 @@ class JacCliTests(TestCase):
127
128
  sys.stdout = captured_output
128
129
  sys.stderr = captured_output
129
130
 
130
- with contextlib.suppress(Exception):
131
+ with self.assertRaises(SystemExit) as cm:
131
132
  cli.run(self.fixture_abs_path("err_runtime.jac"))
132
133
 
133
134
  sys.stdout = sys.__stdout__
134
135
  sys.stderr = sys.__stderr__
135
136
 
137
+ # Verify exit code is 1
138
+ self.assertEqual(cm.exception.code, 1)
139
+
136
140
  expected_stdout_values = (
137
141
  "Error: list index out of range",
138
142
  " print(some_list[invalid_index]);",
@@ -385,13 +389,13 @@ class JacCliTests(TestCase):
385
389
  """Test for graph CLI cmd."""
386
390
  captured_output = io.StringIO()
387
391
  sys.stdout = captured_output
388
- cli.dot(f"{self.examples_abs_path('reference/connect_expressions.jac')}")
392
+ cli.dot(f"{self.examples_abs_path('reference/connect_expressions_(osp).jac')}")
389
393
  sys.stdout = sys.__stdout__
390
394
  stdout_value = captured_output.getvalue()
391
- if os.path.exists("connect_expressions.dot"):
392
- os.remove("connect_expressions.dot")
393
- self.assertIn("11\n13\n15\n>>> Graph content saved to", stdout_value)
394
- self.assertIn("connect_expressions.dot\n", stdout_value)
395
+ if os.path.exists("connect_expressions_(osp).dot"):
396
+ os.remove("connect_expressions_(osp).dot")
397
+ self.assertIn(">>> Graph content saved to", stdout_value)
398
+ self.assertIn("connect_expressions_(osp).dot\n", stdout_value)
395
399
 
396
400
  def test_py_to_jac(self) -> None:
397
401
  """Test for graph CLI cmd."""
@@ -432,6 +436,53 @@ class JacCliTests(TestCase):
432
436
  "sorted(users, key=lambda x: x['email'], reverse=True)", stdout_value
433
437
  )
434
438
 
439
+ def test_param_arg(self) -> None:
440
+ """Test for lambda argument annotation."""
441
+ captured_output = io.StringIO()
442
+ sys.stdout = captured_output
443
+ from jaclang.compiler.program import JacProgram
444
+
445
+ filename = self.fixture_abs_path(
446
+ "../../tests/fixtures/params/test_complex_params.jac"
447
+ )
448
+ cli.jac2py(
449
+ f"{self.fixture_abs_path('../../tests/fixtures/params/test_complex_params.jac')}"
450
+ )
451
+ py_code = JacProgram().compile(file_path=filename).gen.py
452
+
453
+ # Create temporary Python file
454
+ with tempfile.NamedTemporaryFile(
455
+ mode="w", suffix=".py", delete=False
456
+ ) as temp_file:
457
+ temp_file.write(py_code)
458
+ py_file_path = temp_file.name
459
+
460
+ try:
461
+ jac_code = (
462
+ JacProgram().compile(use_str=py_code, file_path=py_file_path).unparse()
463
+ )
464
+ # Create temporary Jac file
465
+ with tempfile.NamedTemporaryFile(
466
+ mode="w", suffix=".jac", delete=False
467
+ ) as temp_file:
468
+ temp_file.write(jac_code)
469
+ jac_file_path = temp_file.name
470
+ cli.run(jac_file_path)
471
+ finally:
472
+ os.remove(py_file_path)
473
+ os.remove(jac_file_path)
474
+
475
+ sys.stdout = sys.__stdout__
476
+ stdout_value = captured_output.getvalue().split("\n")
477
+ self.assertEqual("ULTIMATE_MIN: 1|def|2.5|0|test|100|0", stdout_value[-7])
478
+ self.assertEqual("ULTIMATE_FULL: 1|custom|3.14|3|req|200|1", stdout_value[-6])
479
+ self.assertEqual("SEPARATORS: 42", stdout_value[-5])
480
+ self.assertEqual("EDGE_MIX: 1-test-2-True-1", stdout_value[-4])
481
+ self.assertEqual("RECURSIVE: 7 11", stdout_value[-3])
482
+ self.assertEqual(
483
+ "VALIDATION: x:1,y:2.5,z:10,args:1,w:True,kwargs:1", stdout_value[-2]
484
+ )
485
+
435
486
  def test_caching_issue(self) -> None:
436
487
  """Test for Caching Issue."""
437
488
  test_file = self.fixture_abs_path("test_caching_issue.jac")
@@ -441,7 +492,7 @@ class JacCliTests(TestCase):
441
492
  f.write(
442
493
  f"""
443
494
  test mytest{{
444
- check 10 == {x};
495
+ assert 10 == {x};
445
496
  }}
446
497
  """
447
498
  )
@@ -609,3 +660,104 @@ class JacCliTests(TestCase):
609
660
  )
610
661
  stdout, stderr = process.communicate()
611
662
  self.assertIn("Hello World!", stdout)
663
+
664
+ def test_cli_error_exit_codes(self) -> None:
665
+ """Test that CLI commands return non-zero exit codes on errors."""
666
+ # Test run command with syntax error
667
+ process = subprocess.Popen(
668
+ ["jac", "run", self.fixture_abs_path("err2.jac")],
669
+ stdout=subprocess.PIPE,
670
+ stderr=subprocess.PIPE,
671
+ text=True,
672
+ )
673
+ stdout, stderr = process.communicate()
674
+ self.assertEqual(
675
+ process.returncode, 1, "run command should exit with code 1 on syntax error"
676
+ )
677
+ self.assertIn("Error running", stderr)
678
+
679
+ # Test build command with syntax error
680
+ process = subprocess.Popen(
681
+ ["jac", "build", self.fixture_abs_path("err2.jac")],
682
+ stdout=subprocess.PIPE,
683
+ stderr=subprocess.PIPE,
684
+ text=True,
685
+ )
686
+ stdout, stderr = process.communicate()
687
+ self.assertEqual(
688
+ process.returncode,
689
+ 1,
690
+ "build command should exit with code 1 on compilation error",
691
+ )
692
+
693
+ # Test check command with syntax error
694
+ process = subprocess.Popen(
695
+ ["jac", "check", self.fixture_abs_path("err2.jac")],
696
+ stdout=subprocess.PIPE,
697
+ stderr=subprocess.PIPE,
698
+ text=True,
699
+ )
700
+ stdout, stderr = process.communicate()
701
+ self.assertEqual(
702
+ process.returncode,
703
+ 1,
704
+ "check command should exit with code 1 on type check error",
705
+ )
706
+
707
+ # Test format command with non-existent file
708
+ process = subprocess.Popen(
709
+ ["jac", "format", "/nonexistent.jac"],
710
+ stdout=subprocess.PIPE,
711
+ stderr=subprocess.PIPE,
712
+ text=True,
713
+ )
714
+ stdout, stderr = process.communicate()
715
+ self.assertEqual(
716
+ process.returncode,
717
+ 1,
718
+ "format command should exit with code 1 on missing file",
719
+ )
720
+ self.assertIn("does not exist", stderr)
721
+
722
+ # Test check command with invalid file type
723
+ process = subprocess.Popen(
724
+ ["jac", "check", "/nonexistent.txt"],
725
+ stdout=subprocess.PIPE,
726
+ stderr=subprocess.PIPE,
727
+ text=True,
728
+ )
729
+ stdout, stderr = process.communicate()
730
+ self.assertEqual(
731
+ process.returncode,
732
+ 1,
733
+ "check command should exit with code 1 on invalid file type",
734
+ )
735
+ self.assertIn("Not a .jac file", stderr)
736
+
737
+ # Test tool command with non-existent tool
738
+ process = subprocess.Popen(
739
+ ["jac", "tool", "nonexistent_tool"],
740
+ stdout=subprocess.PIPE,
741
+ stderr=subprocess.PIPE,
742
+ text=True,
743
+ )
744
+ stdout, stderr = process.communicate()
745
+ self.assertEqual(
746
+ process.returncode,
747
+ 1,
748
+ "tool command should exit with code 1 on non-existent tool",
749
+ )
750
+ self.assertIn("not found", stderr)
751
+
752
+ # Test successful run returns exit code 0
753
+ process = subprocess.Popen(
754
+ ["jac", "run", self.fixture_abs_path("hello.jac")],
755
+ stdout=subprocess.PIPE,
756
+ stderr=subprocess.PIPE,
757
+ text=True,
758
+ )
759
+ stdout, stderr = process.communicate()
760
+ self.assertEqual(
761
+ process.returncode, 0, "run command should exit with code 0 on success"
762
+ )
763
+ self.assertIn("Hello World!", stdout)
@@ -3,7 +3,7 @@
3
3
  import io
4
4
  import os
5
5
  import sys
6
- import sysconfig
6
+ import pytest
7
7
  import tempfile
8
8
  import subprocess
9
9
  from pathlib import Path
@@ -133,8 +133,17 @@ class JacLanguageTests(TestCase):
133
133
 
134
134
  for edge in edges:
135
135
  label = edge["label"]
136
- self.assertIn(label, ["E(val=1)", "E(val=1)", "E(val=1)", "E(val=0)", "E(val=0)", "E(val=0)"])
137
-
136
+ self.assertIn(
137
+ label,
138
+ [
139
+ "E(val=1)",
140
+ "E(val=1)",
141
+ "E(val=1)",
142
+ "E(val=0)",
143
+ "E(val=0)",
144
+ "E(val=0)",
145
+ ],
146
+ )
138
147
 
139
148
  def test_printgraph_mermaid(self) -> None:
140
149
  """Test the mermaid gen of builtin function."""
@@ -201,11 +210,26 @@ class JacLanguageTests(TestCase):
201
210
  )
202
211
  captured_output = io.StringIO()
203
212
  sys.stdout = captured_output
204
- exec(compile(prog.gen.py_ast[0], "test.py", "exec"))
213
+ exec(compile(prog.gen.py_ast[0], "test.jac", "exec"))
205
214
  sys.stdout = sys.__stdout__
206
215
  stdout_value = captured_output.getvalue()
207
216
  self.assertEqual(stdout_value, "-5\n")
208
217
 
218
+ def test_assignment_list_no_infinite_loop(self) -> None:
219
+ """Test that assignment list parsing doesn't cause infinite loop."""
220
+ # This syntax previously caused an infinite loop in two places:
221
+ # 1. Grammar: assignment_list: (assignment_list COMMA)? (assignment | named_ref)
222
+ # Fixed by: assignment_list: (assignment | named_ref) (COMMA (assignment | named_ref))* COMMA?
223
+ # 2. Error recovery: feed_current_token() had unbounded while loop
224
+ # Fixed by: adding max_attempts limit in parser.py
225
+ code = "with entry { p1, p2 = (10, 20); }"
226
+ # Compilation should complete quickly (even though syntax is invalid)
227
+ jac_prog = JacProgram()
228
+ result = jac_prog.compile(use_str=code, file_path="test.jac")
229
+ # Should have errors (invalid syntax) but not hang
230
+ self.assertIsNotNone(result) # Returns a Module object
231
+ self.assertGreater(len(jac_prog.errors_had), 0) # Check errors on program
232
+
209
233
  def test_need_import(self) -> None:
210
234
  """Test importing python."""
211
235
  captured_output = io.StringIO()
@@ -215,18 +239,6 @@ class JacLanguageTests(TestCase):
215
239
  stdout_value = captured_output.getvalue()
216
240
  self.assertIn("<module 'pyfunc' from", stdout_value)
217
241
 
218
- def test_filter_compr(self) -> None:
219
- """Testing filter comprehension."""
220
- captured_output = io.StringIO()
221
- sys.stdout = captured_output
222
- Jac.jac_import(
223
- "reference.special_comprehensions",
224
- base_path=self.examples_abs_path(""),
225
- )
226
- sys.stdout = sys.__stdout__
227
- stdout_value = captured_output.getvalue()
228
- self.assertIn("True", stdout_value)
229
-
230
242
  def test_gen_dot_bubble(self) -> None:
231
243
  """Test the dot gen of nodes and edges of bubblesort."""
232
244
  captured_output = io.StringIO()
@@ -514,14 +526,13 @@ class JacLanguageTests(TestCase):
514
526
  ),
515
527
  prog=JacProgram(),
516
528
  ).ir_out.unparse()
517
- self.assertIn("def greet2(**kwargs: Any)", output)
529
+ self.assertIn("def greet2( **kwargs: Any) {", output)
518
530
  self.assertEqual(output.count("with entry {"), 14)
519
- self.assertIn("assert (x == 5) , 'x should be equal to 5' ;", output)
531
+ self.assertIn("assert (x == 5) , 'x should be equal to 5';", output)
520
532
  self.assertIn("if not (x == y) {", output)
521
- self.assertIn("def greet2(**kwargs: Any) {", output)
522
- self.assertIn("squares_dict = { x : (x ** 2) for x in numbers };", output)
533
+ self.assertIn("squares_dict = {x : (x ** 2) for x in numbers};", output)
523
534
  self.assertIn(
524
- '\n\n"""Say hello"""\n@ my_decorator\n\n def say_hello() {', output
535
+ '\n\n"""Say hello"""\n@my_decorator\n\n def say_hello() {', output
525
536
  )
526
537
 
527
538
  def test_pyfunc_2(self) -> None:
@@ -589,6 +600,52 @@ class JacLanguageTests(TestCase):
589
600
  self.assertIn("case Container(inner = Inner(x = a, y = b)):\n", output)
590
601
  self.assertIn("case _:\n", output)
591
602
 
603
+ def test_py2jac_params(self) -> None:
604
+ """Test py ast to Jac ast conversion."""
605
+ from jaclang.compiler.passes.main import PyastBuildPass
606
+ import jaclang.compiler.unitree as ast
607
+ import ast as py_ast
608
+
609
+ py_out_path = os.path.join(self.fixture_abs_path("./"), "py2jac_params.py")
610
+ with open(py_out_path) as f:
611
+ file_source = f.read()
612
+ output = PyastBuildPass(
613
+ ir_in=ast.PythonModuleAst(
614
+ py_ast.parse(file_source),
615
+ orig_src=ast.Source(file_source, py_out_path),
616
+ ),
617
+ prog=None,
618
+ ).ir_out.unparse()
619
+ self.assertIn(
620
+ "def isinstance( <>obj: object , class_or_tuple: _ClassInfo , /) -> bool {",
621
+ output,
622
+ )
623
+ self.assertIn(
624
+ "def len(<>obj: Sized, astt: Any, /, z: int, j: str, a: Any = 90) -> int {",
625
+ output,
626
+ )
627
+
628
+ def test_py2jac_empty_file(self) -> None:
629
+ """Test py ast to Jac ast conversion."""
630
+ from jaclang.compiler.passes.main import PyastBuildPass
631
+ import jaclang.compiler.unitree as ast
632
+ import ast as py_ast
633
+
634
+ py_out_path = os.path.join(self.fixture_abs_path("./"), "py2jac_empty.py")
635
+ with open(py_out_path) as f:
636
+ file_source = f.read()
637
+ converted_ast = PyastBuildPass(
638
+ ir_in=ast.PythonModuleAst(
639
+ py_ast.parse(file_source),
640
+ orig_src=ast.Source(file_source, py_out_path),
641
+ ),
642
+ prog=None,
643
+ ).ir_out
644
+ self.assertIsInstance(
645
+ converted_ast,
646
+ ast.Module
647
+ )
648
+
592
649
  def test_refs_target(self) -> None:
593
650
  """Test py ast to Jac ast conversion output."""
594
651
  captured_output = io.StringIO()
@@ -712,6 +769,7 @@ class JacLanguageTests(TestCase):
712
769
  mypass = JacProgram().compile(self.fixture_abs_path("byllmissue.jac"))
713
770
  self.assertIn("2:5 - 4:8", mypass.pp())
714
771
 
772
+ @pytest.mark.xfail(reason="TODO: Support symtable for inheritance")
715
773
  def test_inherit_baseclass_sym(self) -> None:
716
774
  """Basic test for symtable support for inheritance."""
717
775
  mypass = JacProgram().compile(
@@ -746,6 +804,53 @@ class JacLanguageTests(TestCase):
746
804
  stdout_value = captured_output.getvalue()
747
805
  self.assertIn("i work", stdout_value)
748
806
 
807
+ def test_kwonly_params(self) -> None:
808
+ """Test importing python."""
809
+ captured_output = io.StringIO()
810
+ sys.stdout = captured_output
811
+ Jac.jac_import(
812
+ "test_kwonly_params", base_path=self.fixture_abs_path("./params")
813
+ )
814
+ sys.stdout = sys.__stdout__
815
+ stdout_value = captured_output.getvalue().split("\n")
816
+ self.assertEqual("KW_SIMPLE: 42", stdout_value[0])
817
+ self.assertEqual("KW_DEF: 10-def 20-def", stdout_value[1])
818
+ self.assertEqual("REG_KW: 10|test", stdout_value[2])
819
+ self.assertEqual("MIXED_KW: 1-def-2.5-True 2-custom-3.5-False", stdout_value[3])
820
+ self.assertEqual("ALL_KW: 100:test:1.0 200:hi:9.9", stdout_value[4])
821
+
822
+ def test_complex_params(self) -> None:
823
+ """Test importing python."""
824
+ captured_output = io.StringIO()
825
+ sys.stdout = captured_output
826
+ Jac.jac_import(
827
+ "test_complex_params", base_path=self.fixture_abs_path("./params")
828
+ )
829
+ sys.stdout = sys.__stdout__
830
+ stdout_value = captured_output.getvalue().split("\n")
831
+ self.assertEqual("ULTIMATE_MIN: 1|def|2.5|0|test|100|0", stdout_value[0])
832
+ self.assertEqual("ULTIMATE_FULL: 1|custom|3.14|3|req|200|1", stdout_value[1])
833
+ self.assertEqual("SEPARATORS: 42", stdout_value[2])
834
+ self.assertEqual("EDGE_MIX: 1-test-2-True-1", stdout_value[3])
835
+ self.assertEqual("RECURSIVE: 7 11", stdout_value[4])
836
+ self.assertEqual(
837
+ "VALIDATION: x:1,y:2.5,z:10,args:1,w:True,kwargs:1", stdout_value[5]
838
+ )
839
+
840
+ def test_param_failing(self) -> None:
841
+ """Test importing python."""
842
+ captured_output = io.StringIO()
843
+ sys.stdout = captured_output
844
+ for i in [
845
+ "test_failing_posonly",
846
+ "test_failing_kwonly",
847
+ "test_failing_varargs",
848
+ ]:
849
+ Jac.jac_import(i, base_path=self.fixture_abs_path("./params"))
850
+ sys.stdout = sys.__stdout__
851
+ stdout_value = captured_output.getvalue()
852
+ self.assertNotIn("FAILED", stdout_value)
853
+
749
854
  def test_double_import_exec(self) -> None:
750
855
  """Test importing python."""
751
856
  captured_output = io.StringIO()
@@ -1238,9 +1343,9 @@ class JacLanguageTests(TestCase):
1238
1343
  ).ir_out.unparse()
1239
1344
  self.assertIn("(prev_token_index is None)", output)
1240
1345
  self.assertIn("(next_token_index is None)", output)
1241
- self.assertIn("(tok[ 0 ] > change_end_line)", output)
1242
- self.assertIn("(tok[ 0 ] == change_end_line)", output)
1243
- self.assertIn("(tok[ 1 ] > change_end_char)", output)
1346
+ self.assertIn("(tok[0] > change_end_line)", output)
1347
+ self.assertIn("(tok[0] == change_end_line)", output)
1348
+ self.assertIn("(tok[1] > change_end_char)", output)
1244
1349
 
1245
1350
  def test_here_visitor_usage(self) -> None:
1246
1351
  """Test visitor, here keyword usage in jaclang."""
@@ -1257,9 +1362,11 @@ class JacLanguageTests(TestCase):
1257
1362
  captured_output = io.StringIO()
1258
1363
  sys.stdout = captured_output
1259
1364
  sys.stderr = captured_output
1260
- cli.run(self.fixture_abs_path("here_usage_error.jac"))
1365
+ with self.assertRaises(SystemExit) as cm:
1366
+ cli.run(self.fixture_abs_path("here_usage_error.jac"))
1261
1367
  sys.stdout = sys.__stdout__
1262
1368
  sys.stderr = sys.__stderr__
1369
+ self.assertEqual(cm.exception.code, 1)
1263
1370
  stdout_value = captured_output.getvalue()
1264
1371
  self.assertIn("'here' is not defined", stdout_value)
1265
1372
 
@@ -1374,11 +1481,11 @@ class JacLanguageTests(TestCase):
1374
1481
 
1375
1482
  def test_read_file_with_encoding_utf8(self) -> None:
1376
1483
  """Test reading UTF-8 encoded file."""
1377
- with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', delete=False) as f:
1484
+ with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as f:
1378
1485
  test_content = "Hello, 世界! 🌍 Testing UTF-8 encoding."
1379
1486
  f.write(test_content)
1380
1487
  temp_path = f.name
1381
-
1488
+
1382
1489
  try:
1383
1490
  result = read_file_with_encoding(temp_path)
1384
1491
  self.assertEqual(result, test_content)
@@ -1387,11 +1494,13 @@ class JacLanguageTests(TestCase):
1387
1494
 
1388
1495
  def test_read_file_with_encoding_utf16(self) -> None:
1389
1496
  """Test reading UTF-16 encoded file when UTF-8 fails."""
1390
- with tempfile.NamedTemporaryFile(delete=False, mode="w", encoding="utf-16") as f:
1497
+ with tempfile.NamedTemporaryFile(
1498
+ delete=False, mode="w", encoding="utf-16"
1499
+ ) as f:
1391
1500
  test_content = "Hello, 世界! UTF-16 encoding test."
1392
1501
  f.write(test_content)
1393
1502
  temp_path = f.name
1394
-
1503
+
1395
1504
  try:
1396
1505
  result = read_file_with_encoding(temp_path)
1397
1506
  self.assertEqual(result, test_content)
@@ -1400,11 +1509,13 @@ class JacLanguageTests(TestCase):
1400
1509
 
1401
1510
  def test_read_file_with_encoding_utf8_bom(self) -> None:
1402
1511
  """Test reading UTF-8 with BOM encoded file."""
1403
- with tempfile.NamedTemporaryFile(delete=False, mode='w', encoding='utf-8-sig') as f:
1512
+ with tempfile.NamedTemporaryFile(
1513
+ delete=False, mode="w", encoding="utf-8-sig"
1514
+ ) as f:
1404
1515
  test_content = "Hello, UTF-8 BOM test! 🚀"
1405
1516
  f.write(test_content)
1406
1517
  temp_path = f.name
1407
-
1518
+
1408
1519
  try:
1409
1520
  result = read_file_with_encoding(temp_path)
1410
1521
  self.assertEqual(result, test_content)
@@ -1431,9 +1542,9 @@ class JacLanguageTests(TestCase):
1431
1542
  with tempfile.NamedTemporaryFile(delete=False) as f:
1432
1543
  binary_data = bytes([0xFF, 0xFE, 0x00, 0x48, 0x65, 0x6C, 0x6C, 0x6F])
1433
1544
  f.write(binary_data)
1434
- f.flush()
1545
+ f.flush()
1435
1546
  temp_path = f.name
1436
-
1547
+
1437
1548
  try:
1438
1549
  result = read_file_with_encoding(temp_path)
1439
1550
  self.assertIsInstance(result, str)
@@ -1443,18 +1554,18 @@ class JacLanguageTests(TestCase):
1443
1554
 
1444
1555
  def test_read_file_with_encoding_special_characters(self) -> None:
1445
1556
  """Test reading file with various special characters."""
1446
- with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', delete=False) as f:
1557
+ with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", delete=False) as f:
1447
1558
  test_content = (
1448
1559
  "Special chars: åäö ñ ü ç é\n"
1449
- "Symbols: ©®™ §¶†‡•\n"
1560
+ "Symbols: ©®™ §¶†‡•\n"
1450
1561
  "Math: ∑∏∫√±≤≥≠\n"
1451
1562
  "Arrows: ←→↑↓↔\n"
1452
1563
  "Emoji: 😀😍🎉🔥💯\n"
1453
1564
  )
1454
1565
  f.write(test_content)
1455
- f.flush()
1566
+ f.flush()
1456
1567
  temp_path = f.name
1457
-
1568
+
1458
1569
  try:
1459
1570
  result = read_file_with_encoding(temp_path)
1460
1571
 
@@ -1464,4 +1575,68 @@ class JacLanguageTests(TestCase):
1464
1575
  self.assertIn("∑∏∫", result)
1465
1576
  self.assertIn("😀😍", result)
1466
1577
  finally:
1467
- os.unlink(temp_path)
1578
+ os.unlink(temp_path)
1579
+
1580
+ def test_funccall_genexpr(self) -> None:
1581
+ """Test function call with generator expression in both Jac and py2jac."""
1582
+ # Test language support
1583
+ captured_output = io.StringIO()
1584
+ sys.stdout = captured_output
1585
+ Jac.jac_import("funccall_genexpr", base_path=self.fixture_abs_path("./"))
1586
+ sys.stdout = sys.__stdout__
1587
+ stdout_value = captured_output.getvalue().split("\n")
1588
+ self.assertIn("Result: 30", stdout_value[0])
1589
+
1590
+ # Test py2jac conversion
1591
+ py_file_path = f"{self.fixture_abs_path('../../tests/fixtures/funccall_genexpr.py')}"
1592
+ captured_output = io.StringIO()
1593
+ sys.stdout = captured_output
1594
+ cli.py2jac(py_file_path)
1595
+ sys.stdout = sys.__stdout__
1596
+ stdout_value = captured_output.getvalue()
1597
+ self.assertIn("result = total((x * x) for x in range(5));", stdout_value)
1598
+
1599
+ def test_attr_pattern_case(self) -> None:
1600
+ """Test attribute pattern matching."""
1601
+ captured_output = io.StringIO()
1602
+ sys.stdout = captured_output
1603
+ Jac.jac_import("attr_pattern_case", base_path=self.fixture_abs_path("./"))
1604
+ sys.stdout = sys.__stdout__
1605
+ stdout_value = captured_output.getvalue().split("\n")
1606
+ self.assertIn("Matched a.b.c Hello Jaseci!", stdout_value[0])
1607
+
1608
+ def test_known_builtins_matches_actual(self) -> None:
1609
+ """Test that KNOWN_BUILTINS in PyastGenPass matches actual builtins."""
1610
+ from jaclang.compiler.passes.main.pyast_gen_pass import PyastGenPass
1611
+ import jaclang.runtimelib.builtin as builtin_module
1612
+
1613
+ # Get actual builtins from the module (excluding private members)
1614
+ actual_builtins = {
1615
+ name for name in builtin_module.__all__
1616
+ if not name.startswith('_')
1617
+ }
1618
+
1619
+ # Exceptions: builtins that are imported from other sources
1620
+ # - Enum: imported via needs_enum() from standard library's enum module
1621
+ exceptions = {'Enum'}
1622
+ actual_builtins_to_check = actual_builtins - exceptions
1623
+
1624
+ # Get the KNOWN_BUILTINS set from PyastGenPass
1625
+ known_builtins = PyastGenPass.KNOWN_BUILTINS
1626
+
1627
+ # Find missing and extra builtins
1628
+ missing = actual_builtins_to_check - known_builtins
1629
+ extra = known_builtins - actual_builtins_to_check
1630
+
1631
+ # Build error message
1632
+ error_msg = []
1633
+ if missing:
1634
+ error_msg.append(f"Missing from KNOWN_BUILTINS: {sorted(missing)}")
1635
+ if extra:
1636
+ error_msg.append(f"Extra in KNOWN_BUILTINS (not in builtin module): {sorted(extra)}")
1637
+
1638
+ # Assert they match
1639
+ self.assertEqual(
1640
+ known_builtins, actual_builtins_to_check,
1641
+ "\n".join(error_msg) if error_msg else ""
1642
+ )
@@ -50,6 +50,8 @@ class JacReferenceTests(TestCase):
50
50
 
51
51
  def micro_suite_test(self, filename: str) -> None:
52
52
  """Test file."""
53
+ # Reset machine at the start of each test to ensure clean state
54
+ Jac.reset_machine()
53
55
 
54
56
  def execute_and_capture_output(code: str | bytes, filename: str = "") -> str:
55
57
  f = io.StringIO()
@@ -83,12 +85,12 @@ class JacReferenceTests(TestCase):
83
85
  # print(f"\nPython Output:\n{output_py}")
84
86
 
85
87
  self.assertGreater(len(output_py), 0)
86
- self.assertEqual(len(output_jac.split("\n")), len(output_py.split("\n")))
87
88
  # doing like below for concurrent_expressions.jac and other current tests
88
89
  for i in output_py.split("\n"):
89
90
  self.assertIn(i, output_jac)
90
91
  for i in output_jac.split("\n"):
91
92
  self.assertIn(i, output_py)
93
+ self.assertEqual(len(output_jac.split("\n")), len(output_py.split("\n")))
92
94
  # self.assertEqual(output_py, output_jac)
93
95
  except Exception as e:
94
96
  # print(f"\nJAC Output:\n{output_jac}")