jaclang 0.7.23__py3-none-any.whl → 0.7.26__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 (68) hide show
  1. jaclang/cli/cli.py +46 -29
  2. jaclang/compiler/__init__.py +2 -2
  3. jaclang/compiler/absyntree.py +114 -66
  4. jaclang/compiler/codeloc.py +7 -2
  5. jaclang/compiler/compile.py +10 -3
  6. jaclang/compiler/jac.lark +4 -1
  7. jaclang/compiler/parser.py +63 -43
  8. jaclang/compiler/passes/ir_pass.py +2 -2
  9. jaclang/compiler/passes/main/def_impl_match_pass.py +83 -0
  10. jaclang/compiler/passes/main/def_use_pass.py +1 -2
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
  12. jaclang/compiler/passes/main/import_pass.py +6 -2
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +46 -20
  14. jaclang/compiler/passes/main/pyast_load_pass.py +56 -41
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
  16. jaclang/compiler/passes/main/registry_pass.py +3 -12
  17. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -2
  18. jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
  19. jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
  20. jaclang/compiler/passes/main/tests/fixtures/uninitialized_hasvars.jac +26 -0
  21. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +66 -0
  22. jaclang/compiler/passes/main/tests/test_def_use_pass.py +3 -3
  23. jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
  24. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  25. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
  26. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +3 -3
  27. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  28. jaclang/compiler/passes/transform.py +27 -3
  29. jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
  30. jaclang/compiler/symtable.py +6 -0
  31. jaclang/compiler/tests/test_importer.py +2 -2
  32. jaclang/compiler/tests/test_parser.py +7 -1
  33. jaclang/langserve/engine.py +14 -12
  34. jaclang/langserve/server.py +7 -2
  35. jaclang/langserve/tests/test_server.py +1 -1
  36. jaclang/langserve/utils.py +17 -3
  37. jaclang/plugin/default.py +80 -43
  38. jaclang/plugin/feature.py +12 -2
  39. jaclang/plugin/plugin.md +471 -0
  40. jaclang/plugin/spec.py +14 -1
  41. jaclang/plugin/tests/fixtures/graph_purger.jac +101 -0
  42. jaclang/plugin/tests/fixtures/other_root_access.jac +9 -0
  43. jaclang/plugin/tests/test_jaseci.py +126 -6
  44. jaclang/runtimelib/architype.py +12 -1
  45. jaclang/runtimelib/context.py +2 -0
  46. jaclang/runtimelib/importer.py +7 -2
  47. jaclang/runtimelib/machine.py +21 -6
  48. jaclang/runtimelib/memory.py +5 -1
  49. jaclang/settings.py +3 -0
  50. jaclang/tests/fixtures/architype_def_bug.jac +17 -0
  51. jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
  52. jaclang/tests/fixtures/decl_defn_param_name.jac +19 -0
  53. jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
  54. jaclang/tests/fixtures/expr_type.jac +54 -0
  55. jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
  56. jaclang/tests/fixtures/multi_dim_array_split.jac +19 -0
  57. jaclang/tests/fixtures/registry.jac +20 -8
  58. jaclang/tests/foo/__init__.jac +0 -0
  59. jaclang/tests/main.jac +2 -0
  60. jaclang/tests/test_cli.py +86 -4
  61. jaclang/tests/test_language.py +104 -27
  62. jaclang/utils/helpers.py +92 -14
  63. jaclang/utils/lang_tools.py +6 -2
  64. jaclang/utils/treeprinter.py +4 -2
  65. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/METADATA +2 -1
  66. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/RECORD +68 -57
  67. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/WHEEL +1 -1
  68. {jaclang-0.7.23.dist-info → jaclang-0.7.26.dist-info}/entry_points.txt +0 -0
jaclang/tests/test_cli.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Test Jac cli module."""
2
2
 
3
+ import contextlib
3
4
  import inspect
4
5
  import io
5
6
  import os
@@ -55,10 +56,8 @@ class JacCliTests(TestCase):
55
56
  sys.stdout = captured_output
56
57
  sys.stderr = captured_output
57
58
 
58
- try:
59
+ with contextlib.suppress(Exception):
59
60
  cli.run(self.fixture_abs_path("err_runtime.jac"))
60
- except Exception as e:
61
- print(f"Error: {e}")
62
61
 
63
62
  sys.stdout = sys.__stdout__
64
63
  sys.stderr = sys.__stderr__
@@ -71,7 +70,6 @@ class JacCliTests(TestCase):
71
70
  " at foo() ",
72
71
  " at <module> ",
73
72
  )
74
-
75
73
  logger_capture = "\n".join([rec.message for rec in self.caplog.records])
76
74
  for exp in expected_stdout_values:
77
75
  self.assertIn(exp, logger_capture)
@@ -96,6 +94,24 @@ class JacCliTests(TestCase):
96
94
  path_to_file = self.fixture_abs_path("err.impl.jac")
97
95
  self.assertIn(f'"{path_to_file}", line 2', stdout_value)
98
96
 
97
+ def test_param_name_diff(self) -> None:
98
+ """Test when parameter name from definitinon and declaration are mismatched."""
99
+ captured_output = io.StringIO()
100
+ sys.stdout = captured_output
101
+ sys.stderr = captured_output
102
+ with contextlib.suppress(Exception):
103
+ cli.run(self.fixture_abs_path("decl_defn_param_name.jac"))
104
+ sys.stdout = sys.__stdout__
105
+ sys.stderr = sys.__stderr__
106
+
107
+ expected_stdout_values = (
108
+ "short_name = 42",
109
+ "p1 = 64 , p2 = foobar",
110
+ )
111
+ output = captured_output.getvalue()
112
+ for exp in expected_stdout_values:
113
+ self.assertIn(exp, output)
114
+
99
115
  def test_jac_test_err(self) -> None:
100
116
  """Basic test for pass."""
101
117
  captured_output = io.StringIO()
@@ -217,6 +233,42 @@ class JacCliTests(TestCase):
217
233
  r"13\:12 \- 13\:18.*Name - append - .*SymbolPath: builtins_test.builtins.list.append",
218
234
  )
219
235
 
236
+ def test_expr_types(self) -> None:
237
+ """Testing for print AstTool."""
238
+ captured_output = io.StringIO()
239
+ sys.stdout = captured_output
240
+
241
+ cli.tool("ir", ["ast", f"{self.fixture_abs_path('expr_type.jac')}"])
242
+
243
+ sys.stdout = sys.__stdout__
244
+ stdout_value = captured_output.getvalue()
245
+
246
+ self.assertRegex(
247
+ stdout_value, r"4\:9 \- 4\:14.*BinaryExpr \- Type\: builtins.int"
248
+ )
249
+ self.assertRegex(
250
+ stdout_value, r"7\:9 \- 7\:17.*FuncCall \- Type\: builtins.float"
251
+ )
252
+ self.assertRegex(
253
+ stdout_value, r"9\:6 \- 9\:11.*CompareExpr \- Type\: builtins.bool"
254
+ )
255
+ self.assertRegex(
256
+ stdout_value, r"10\:6 - 10\:15.*BinaryExpr \- Type\: builtins.str"
257
+ )
258
+ self.assertRegex(
259
+ stdout_value, r"11\:5 \- 11\:13.*AtomTrailer \- Type\: builtins.int"
260
+ )
261
+ self.assertRegex(
262
+ stdout_value, r"12\:5 \- 12\:14.*UnaryExpr \- Type\: builtins.bool"
263
+ )
264
+ self.assertRegex(
265
+ stdout_value, r"13\:5 \- 13\:25.*IfElseExpr \- Type\: Literal\['a']\?"
266
+ )
267
+ self.assertRegex(
268
+ stdout_value,
269
+ r"14\:5 \- 14\:27.*ListCompr - \[ListCompr] \- Type\: builtins.list\[builtins.int]",
270
+ )
271
+
220
272
  def test_ast_dotgen(self) -> None:
221
273
  """Testing for print AstTool."""
222
274
  captured_output = io.StringIO()
@@ -247,6 +299,8 @@ class JacCliTests(TestCase):
247
299
  self.assertEqual(stdout_value.count("type_info.ServerWrapper"), 7)
248
300
  self.assertEqual(stdout_value.count("builtins.int"), 3)
249
301
  self.assertEqual(stdout_value.count("builtins.str"), 10)
302
+ self.assertIn("Literal['test_server']", stdout_value)
303
+ self.assertIn("Literal['1']", stdout_value)
250
304
 
251
305
  def test_build_and_run(self) -> None:
252
306
  """Testing for print AstTool."""
@@ -368,3 +422,31 @@ class JacCliTests(TestCase):
368
422
  sys.stdout = sys.__stdout__
369
423
  stdout_value = captured_output.getvalue()
370
424
  self.assertIn("can my_print(x: object) -> None", stdout_value)
425
+
426
+ def test_caching_issue(self) -> None:
427
+ """Test for Caching Issue."""
428
+ test_file = self.fixture_abs_path("test_caching_issue.jac")
429
+ test_cases = [(10, True), (11, False)]
430
+ for x, is_passed in test_cases:
431
+ with open(test_file, "w") as f:
432
+ f.write(
433
+ f"""
434
+ test mytest{{
435
+ check 10 == {x};
436
+ }}
437
+ """
438
+ )
439
+ process = subprocess.Popen(
440
+ ["jac", "test", test_file],
441
+ stdout=subprocess.PIPE,
442
+ stderr=subprocess.PIPE,
443
+ text=True,
444
+ )
445
+ stdout, stderr = process.communicate()
446
+ if is_passed:
447
+ self.assertIn("Passed successfully.", stdout)
448
+ self.assertIn(".", stderr)
449
+ else:
450
+ self.assertNotIn("Passed successfully.", stdout)
451
+ self.assertIn("F", stderr)
452
+ os.remove(test_file)
@@ -2,7 +2,6 @@
2
2
 
3
3
  import io
4
4
  import os
5
- import pickle
6
5
  import sys
7
6
  import sysconfig
8
7
 
@@ -24,7 +23,7 @@ class JacLanguageTests(TestCase):
24
23
  """Set up test."""
25
24
  SUPER_ROOT_ANCHOR.edges.clear()
26
25
  JacMachine(self.fixture_abs_path("./")).attach_program(
27
- JacProgram(mod_bundle=None, bytecode=None)
26
+ JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
28
27
  )
29
28
  return super().setUp()
30
29
 
@@ -104,6 +103,40 @@ class JacLanguageTests(TestCase):
104
103
  "Too high!\nToo low!\nToo high!\nCongratulations! You guessed correctly.\n",
105
104
  )
106
105
 
106
+ def test_multi_dim_arr_slice(self) -> None:
107
+ """Parse micro jac file."""
108
+ captured_output = io.StringIO()
109
+ sys.stdout = captured_output
110
+ cli.tool(
111
+ "ir",
112
+ [
113
+ "ast",
114
+ self.fixture_abs_path("multi_dim_array_split.jac"),
115
+ ],
116
+ )
117
+ sys.stdout = sys.__stdout__
118
+ stdout_value = captured_output.getvalue()
119
+
120
+ # print(arr[1:3, 1::2]);
121
+ expected_outputs = [
122
+ "+-- AtomTrailer - Type: Any",
123
+ " +-- Name - arr - Type: Any, SymbolTable: None",
124
+ " +-- IndexSlice - [IndexSlice] - Type: builtins.slice, SymbolTable: None",
125
+ " +-- Token - [,",
126
+ " +-- Int - 1 - Type: Literal[1]?, SymbolTable: None",
127
+ " +-- Token - :,",
128
+ " +-- Int - 3 - Type: Literal[3]?, SymbolTable: None",
129
+ " +-- Token - ,,",
130
+ " +-- Int - 1 - Type: Literal[1]?, SymbolTable: None",
131
+ " +-- Token - :,",
132
+ " +-- Token - :,",
133
+ " +-- Int - 2 - Type: Literal[2]?, SymbolTable: None",
134
+ " +-- Token - ],",
135
+ ]
136
+
137
+ for expected in expected_outputs:
138
+ self.assertIn(expected, stdout_value)
139
+
107
140
  def test_chandra_bugs(self) -> None:
108
141
  """Parse micro jac file."""
109
142
  captured_output = io.StringIO()
@@ -209,8 +242,10 @@ class JacLanguageTests(TestCase):
209
242
  """Test semstring."""
210
243
  captured_output = io.StringIO()
211
244
  sys.stdout = captured_output
245
+ sys.stderr = captured_output
212
246
  jac_import("semstr", base_path=self.fixture_abs_path("./"))
213
247
  sys.stdout = sys.__stdout__
248
+ sys.stderr = sys.__stderr__
214
249
  stdout_value = captured_output.getvalue()
215
250
  self.assertNotIn("Error", stdout_value)
216
251
 
@@ -237,6 +272,7 @@ class JacLanguageTests(TestCase):
237
272
  self.assertEqual(stdout_value.split("\n")[0], "11 13 12 12 11 12 12")
238
273
  self.assertEqual(stdout_value.split("\n")[1], '12 12 """hello""" 18 18')
239
274
  self.assertEqual(stdout_value.split("\n")[2], "11 12 11 12 11 18 23")
275
+ self.assertEqual(stdout_value.split("\n")[3], 'hello klkl"""')
240
276
 
241
277
  def test_deep_imports(self) -> None:
242
278
  """Parse micro jac file."""
@@ -465,24 +501,22 @@ class JacLanguageTests(TestCase):
465
501
  """Test Jac registry feature."""
466
502
  captured_output = io.StringIO()
467
503
  sys.stdout = captured_output
504
+ sys.stderr = captured_output
468
505
  jac_import("registry", base_path=self.fixture_abs_path("./"))
469
506
  sys.stdout = sys.__stdout__
507
+ sys.stderr = sys.__stderr__
470
508
  stdout_value = captured_output.getvalue()
471
509
  self.assertNotIn("Error", stdout_value)
472
510
 
473
- with open(
474
- os.path.join(
475
- self.fixture_abs_path("./"), "__jac_gen__", "registry.registry.pkl"
476
- ),
477
- "rb",
478
- ) as f:
479
- registry = pickle.load(f)
511
+ output_lines = stdout_value.strip().split("\n")
512
+ outputs = [
513
+ int(output_lines[i]) if i != 2 else output_lines[i] for i in range(4)
514
+ ]
480
515
 
481
- self.assertEqual(len(registry.registry), 9)
482
- self.assertEqual(len(list(registry.registry.items())[0][1]), 2)
483
- self.assertEqual(list(registry.registry.items())[3][0].scope, "Person")
484
- _, sem_info = registry.lookup(name="normal_ability")
485
- self.assertEqual(len(sem_info.get_children(registry)), 2)
516
+ self.assertEqual(outputs[0], 9)
517
+ self.assertEqual(outputs[1], 2)
518
+ self.assertEqual(outputs[2], "Person")
519
+ self.assertEqual(outputs[3], 2)
486
520
 
487
521
  def test_enum_inside_arch(self) -> None:
488
522
  """Test Enum as member stmt."""
@@ -491,7 +525,7 @@ class JacLanguageTests(TestCase):
491
525
  jac_import("enum_inside_archtype", base_path=self.fixture_abs_path("./"))
492
526
  sys.stdout = sys.__stdout__
493
527
  stdout_value = captured_output.getvalue()
494
- self.assertEqual("2\n", stdout_value)
528
+ self.assertIn("2 Accessing privileged Data", stdout_value)
495
529
 
496
530
  def test_needs_import_1(self) -> None:
497
531
  """Test py ast to Jac ast conversion output."""
@@ -503,10 +537,13 @@ class JacLanguageTests(TestCase):
503
537
  import jaclang.compiler.absyntree as ast
504
538
 
505
539
  with open(file_name, "r") as f:
506
- parsed_ast = py_ast.parse(f.read())
540
+ file_source = f.read()
541
+ parsed_ast = py_ast.parse(file_source)
507
542
  try:
508
543
  py_ast_build_pass = PyastBuildPass(
509
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
544
+ input_ir=ast.PythonModuleAst(
545
+ parsed_ast, orig_src=ast.JacSource(file_source, file_name)
546
+ ),
510
547
  )
511
548
  except Exception as e:
512
549
  return f"Error While Jac to Py AST conversion: {e}"
@@ -528,9 +565,11 @@ class JacLanguageTests(TestCase):
528
565
 
529
566
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_1.py")
530
567
  with open(py_out_path) as f:
568
+ file_source = f.read()
531
569
  output = PyastBuildPass(
532
570
  input_ir=ast.PythonModuleAst(
533
- py_ast.parse(f.read()), mod_path=py_out_path
571
+ py_ast.parse(file_source),
572
+ orig_src=ast.JacSource(file_source, py_out_path),
534
573
  ),
535
574
  ).ir.unparse()
536
575
  # print(output)
@@ -559,10 +598,14 @@ class JacLanguageTests(TestCase):
559
598
  import jaclang.compiler.absyntree as ast
560
599
 
561
600
  with open(file_name, "r") as f:
562
- parsed_ast = py_ast.parse(f.read())
601
+ file_source = f.read()
602
+ parsed_ast = py_ast.parse(file_source)
563
603
  try:
564
604
  py_ast_build_pass = PyastBuildPass(
565
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
605
+ input_ir=ast.PythonModuleAst(
606
+ parsed_ast,
607
+ orig_src=ast.JacSource(file_source, file_name),
608
+ ),
566
609
  )
567
610
  except Exception as e:
568
611
  return f"Error While Jac to Py AST conversion: {e}"
@@ -587,9 +630,11 @@ class JacLanguageTests(TestCase):
587
630
 
588
631
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_2.py")
589
632
  with open(py_out_path) as f:
633
+ file_source = f.read()
590
634
  output = PyastBuildPass(
591
635
  input_ir=ast.PythonModuleAst(
592
- py_ast.parse(f.read()), mod_path=py_out_path
636
+ py_ast.parse(file_source),
637
+ orig_src=ast.JacSource(file_source, py_out_path),
593
638
  ),
594
639
  ).ir.unparse()
595
640
  self.assertIn("class X {\n with entry {\n\n a_b = 67;", output)
@@ -607,10 +652,14 @@ class JacLanguageTests(TestCase):
607
652
  import jaclang.compiler.absyntree as ast
608
653
 
609
654
  with open(file_name, "r") as f:
610
- parsed_ast = py_ast.parse(f.read())
655
+ file_source = f.read()
656
+ parsed_ast = py_ast.parse(file_source)
611
657
  try:
612
658
  py_ast_build_pass = PyastBuildPass(
613
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
659
+ input_ir=ast.PythonModuleAst(
660
+ parsed_ast,
661
+ orig_src=ast.JacSource(file_source, file_name),
662
+ ),
614
663
  )
615
664
  except Exception as e:
616
665
  return f"Error While Jac to Py AST conversion: {e}"
@@ -634,9 +683,11 @@ class JacLanguageTests(TestCase):
634
683
 
635
684
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_3.py")
636
685
  with open(py_out_path) as f:
686
+ file_source = f.read()
637
687
  output = PyastBuildPass(
638
688
  input_ir=ast.PythonModuleAst(
639
- py_ast.parse(f.read()), mod_path=py_out_path
689
+ py_ast.parse(file_source),
690
+ orig_src=ast.JacSource(file_source, py_out_path),
640
691
  ),
641
692
  ).ir.unparse()
642
693
  self.assertIn("if 0 <= x<= 5 {", output)
@@ -761,9 +812,11 @@ class JacLanguageTests(TestCase):
761
812
  module_path + ".py",
762
813
  )
763
814
  with open(file_path) as f:
815
+ file_source = f.read()
764
816
  jac_ast = PyastBuildPass(
765
817
  input_ir=ast.PythonModuleAst(
766
- py_ast.parse(f.read()), mod_path=file_path
818
+ py_ast.parse(file_source),
819
+ orig_src=ast.JacSource(file_source, file_path),
767
820
  )
768
821
  )
769
822
  settings.print_py_raised_ast = True
@@ -786,11 +839,13 @@ class JacLanguageTests(TestCase):
786
839
  """Test for access tags working."""
787
840
  captured_output = io.StringIO()
788
841
  sys.stdout = captured_output
842
+ sys.stderr = captured_output
789
843
  cli.check(
790
844
  self.fixture_abs_path("../../tests/fixtures/access_modifier.jac"),
791
845
  print_errs=True,
792
846
  )
793
847
  sys.stdout = sys.__stdout__
848
+ sys.stderr = sys.__stderr__
794
849
  stdout_value = captured_output.getvalue()
795
850
  self.assertEqual(stdout_value.count("Invalid access"), 18)
796
851
 
@@ -808,10 +863,12 @@ class JacLanguageTests(TestCase):
808
863
  parsed_ast = py_ast.parse(f.read())
809
864
  try:
810
865
  py_ast_build_pass = PyastBuildPass(
811
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
866
+ input_ir=ast.PythonModuleAst(
867
+ parsed_ast, orig_src=ast.JacSource(f.read(), file_name)
868
+ )
812
869
  )
813
870
  except Exception as e:
814
- return f"Error While Jac to Py AST conversion: {e}"
871
+ raise Exception(f"Error While Jac to Py AST conversion: {e}")
815
872
 
816
873
  settings.print_py_raised_ast = True
817
874
  ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
@@ -1156,3 +1213,23 @@ class JacLanguageTests(TestCase):
1156
1213
  sys.stdout = sys.__stdout__
1157
1214
  stdout_value = captured_output.getvalue()
1158
1215
  self.assertEqual("[MyNode(Name='End'), MyNode(Name='Middle')]\n", stdout_value)
1216
+
1217
+ def test_global_multivar(self) -> None:
1218
+ """Test supporting multiple global variable in a statement."""
1219
+ captured_output = io.StringIO()
1220
+ sys.stdout = captured_output
1221
+ jac_import("glob_multivar_statement", base_path=self.fixture_abs_path("./"))
1222
+ sys.stdout = sys.__stdout__
1223
+ stdout_value = captured_output.getvalue().split("\n")
1224
+ self.assertIn("Hello World !", stdout_value[0])
1225
+ self.assertIn("Welcome to Jaseci!", stdout_value[1])
1226
+
1227
+ def test_architype_def(self) -> None:
1228
+ """Test architype definition bug."""
1229
+ captured_output = io.StringIO()
1230
+ sys.stdout = captured_output
1231
+ jac_import("architype_def_bug", base_path=self.fixture_abs_path("./"))
1232
+ sys.stdout = sys.__stdout__
1233
+ stdout_value = captured_output.getvalue().split("\n")
1234
+ self.assertIn("MyNode", stdout_value[0])
1235
+ self.assertIn("MyWalker", stdout_value[1])
jaclang/utils/helpers.py CHANGED
@@ -147,7 +147,7 @@ def dump_traceback(e: Exception) -> str:
147
147
  return len(string.encode("utf-8")[:offset].decode("utf-8", errors="replace"))
148
148
 
149
149
  tb = TracebackException(type(e), e, e.__traceback__, limit=None, compact=True)
150
- trace_dump += f"Error: {str(e)}"
150
+ trace_dump += f"Error: {str(e)}\n"
151
151
 
152
152
  # The first frame is the call the to the above `exec` function, not usefull to the enduser,
153
153
  # and Make the most recent call first.
@@ -155,33 +155,111 @@ def dump_traceback(e: Exception) -> str:
155
155
  tb.stack.reverse()
156
156
 
157
157
  # FIXME: should be some settings, we should replace to ensure the anchors length match.
158
- dump_tab_width = 4
158
+ dump_tab_width = 2
159
159
 
160
160
  for idx, frame in enumerate(tb.stack):
161
161
  func_signature = frame.name + ("()" if frame.name.isidentifier() else "")
162
162
 
163
163
  # Pretty print the most recent call's location.
164
- if idx == 0 and (frame.line and frame.line.strip() != ""):
164
+ if idx == 0 and (
165
+ (frame.lineno is not None) and frame.line and frame.line.strip() != ""
166
+ ):
167
+
165
168
  line_o = frame._original_line.rstrip() # type: ignore [attr-defined]
166
- line_s = frame.line.rstrip() if frame.line else ""
167
- stripped_chars = len(line_o) - len(line_s)
168
- trace_dump += f'\n{" " * (dump_tab_width * 2)}{line_s}'
169
169
  if frame.colno is not None and frame.end_colno is not None:
170
- off_start = byte_offset_to_char_offset(line_o, frame.colno)
171
- off_end = byte_offset_to_char_offset(line_o, frame.end_colno)
172
-
173
- # A bunch of caret '^' characters under the error location.
174
- anchors = (" " * (off_start - stripped_chars - 1)) + "^" * len(
175
- line_o[off_start:off_end].replace("\t", " " * dump_tab_width)
170
+ off_start = byte_offset_to_char_offset(line_o, frame.colno) - 1
171
+ off_end = byte_offset_to_char_offset(line_o, frame.end_colno) - 1
172
+
173
+ # Get the source.
174
+ file_source = None
175
+ with open(frame.filename, "r") as file:
176
+ file_source = file.read()
177
+
178
+ # Get the source offset.
179
+ lines = file_source.split("\n")
180
+ for i in range(frame.lineno - 1):
181
+ off_start += len(lines[i]) + 1
182
+ off_end += len(lines[i]) + 1
183
+
184
+ trace_dump += pretty_print_source_location(
185
+ frame.filename, file_source, frame.lineno, off_start, off_end
176
186
  )
177
187
 
178
- trace_dump += f'\n{" " * (dump_tab_width * 2)}{anchors}'
179
-
180
188
  trace_dump += f'\n{" " * dump_tab_width}at {func_signature} {frame.filename}:{frame.lineno}'
181
189
 
182
190
  return trace_dump
183
191
 
184
192
 
193
+ # TODO: After implementing the TextRange (or simillar named) class to mark a text range
194
+ # refactor the parameter to accept an instace of that text range object.
195
+ def pretty_print_source_location(
196
+ file_path: str,
197
+ file_source: str,
198
+ error_line: int,
199
+ pos_start: int,
200
+ pos_end: int,
201
+ ) -> str:
202
+ """Pretty print internal method for the pretty_print method."""
203
+ # NOTE: The Line numbers and the column numbers are starts with 1.
204
+ # We print totally 5 lines (error line and above 2 and bellow 2).
205
+
206
+ # The width of the line number we'll be printing (more of a settings).
207
+ line_num_width: int = 5
208
+
209
+ idx: int = pos_start # Pointer for the current character.
210
+
211
+ if file_source == "" or file_path == "":
212
+ return ""
213
+
214
+ start_line: int = error_line - 2
215
+ if start_line < 1:
216
+ start_line = 1
217
+ end_line: int = start_line + 5 # Index is exclusive.
218
+
219
+ # Get the first character of the [start_line].
220
+ file_source.splitlines(True)[start_line - 1]
221
+ curr_line: int = error_line
222
+ while idx >= 0 and curr_line >= start_line:
223
+ idx -= 1
224
+ if idx < 0:
225
+ break
226
+ if file_source[idx] == "\n":
227
+ curr_line -= 1
228
+
229
+ idx += 1 # Enter the line.
230
+ assert idx == 0 or file_source[idx - 1] == "\n"
231
+
232
+ pretty_dump = ""
233
+
234
+ # Print each lines.
235
+ curr_line = start_line
236
+ while curr_line < end_line:
237
+ pretty_dump += f"%{line_num_width}d | " % curr_line
238
+
239
+ idx_line_start = idx
240
+ while idx < len(file_source) and file_source[idx] != "\n":
241
+ idx += 1 # Run to the line end.
242
+ pretty_dump += file_source[idx_line_start:idx]
243
+ pretty_dump += "\n"
244
+
245
+ if curr_line == error_line: # Print the current line with indicator.
246
+ pretty_dump += f"%{line_num_width}s | " % " "
247
+
248
+ spaces = ""
249
+ for idx_pre in range(idx_line_start, pos_start):
250
+ spaces += "\t" if file_source[idx_pre] == "\t" else " "
251
+
252
+ err_token_len = pos_end - pos_start
253
+ pretty_dump += spaces + ("^" * err_token_len) + "\n"
254
+
255
+ if idx == len(file_source):
256
+ break
257
+ curr_line += 1
258
+ idx += 1
259
+
260
+ return pretty_dump[:-1] # Get rid of the last newline (of the last line).
261
+
262
+
185
263
  class Jdb(pdb.Pdb):
186
264
  """Jac debugger."""
187
265
 
@@ -215,12 +215,16 @@ class AstTool:
215
215
 
216
216
  if file_name.endswith(".py"):
217
217
  with open(file_name, "r") as f:
218
- parsed_ast = py_ast.parse(f.read())
218
+ file_source = f.read()
219
+ parsed_ast = py_ast.parse(file_source)
219
220
  if output == "pyast":
220
221
  return f"\n{py_ast.dump(parsed_ast, indent=2)}"
221
222
  try:
222
223
  rep = PyastBuildPass(
223
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
224
+ input_ir=ast.PythonModuleAst(
225
+ parsed_ast,
226
+ orig_src=ast.JacSource(file_source, file_name),
227
+ ),
224
228
  ).ir
225
229
 
226
230
  schedule = py_code_gen_typed
@@ -105,7 +105,7 @@ def print_ast_tree(
105
105
  if isinstance(node, Token) and isinstance(node, AstSymbolNode):
106
106
  out = (
107
107
  f"{node.__class__.__name__} - {node.value} - "
108
- f"Type: {node.sym_type}, {access} {sym_table_link}"
108
+ f"Type: {node.expr_type}, {access} {sym_table_link}"
109
109
  )
110
110
  if settings.ast_symbol_info_detailed:
111
111
  symbol = (
@@ -133,7 +133,7 @@ def print_ast_tree(
133
133
  elif isinstance(node, AstSymbolNode):
134
134
  out = (
135
135
  f"{node.__class__.__name__} - {node.sym_name} - "
136
- f"Type: {node.sym_type}, {access} {sym_table_link}"
136
+ f"Type: {node.expr_type}, {access} {sym_table_link}"
137
137
  )
138
138
  if settings.ast_symbol_info_detailed:
139
139
  symbol = (
@@ -143,6 +143,8 @@ def print_ast_tree(
143
143
  )
144
144
  out += f" SymbolPath: {symbol}"
145
145
  return out
146
+ elif isinstance(node, ast.Expr):
147
+ return f"{node.__class__.__name__} - Type: {node.expr_type}"
146
148
  else:
147
149
  return f"{node.__class__.__name__}, {access}"
148
150
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaclang
3
- Version: 0.7.23
3
+ Version: 0.7.26
4
4
  Summary: Jac is a unique and powerful programming language that runs on top of Python, offering an unprecedented level of intelligence and intuitive understanding.
5
5
  Home-page: https://jaseci.org
6
6
  License: MIT
@@ -14,6 +14,7 @@ Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Programming Language :: Python :: 3
15
15
  Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
17
18
  Provides-Extra: all
18
19
  Provides-Extra: llm
19
20
  Provides-Extra: streamlit