jaclang 0.7.23__py3-none-any.whl → 0.7.25__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 (50) hide show
  1. jaclang/cli/cli.py +46 -29
  2. jaclang/compiler/__init__.py +2 -2
  3. jaclang/compiler/absyntree.py +87 -48
  4. jaclang/compiler/codeloc.py +7 -2
  5. jaclang/compiler/compile.py +10 -3
  6. jaclang/compiler/parser.py +26 -23
  7. jaclang/compiler/passes/ir_pass.py +2 -2
  8. jaclang/compiler/passes/main/def_impl_match_pass.py +46 -0
  9. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +146 -123
  10. jaclang/compiler/passes/main/import_pass.py +6 -2
  11. jaclang/compiler/passes/main/pyast_load_pass.py +36 -35
  12. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +7 -7
  13. jaclang/compiler/passes/main/registry_pass.py +3 -12
  14. jaclang/compiler/passes/main/tests/fixtures/defn_decl_mismatch.jac +19 -0
  15. jaclang/compiler/passes/main/tests/fixtures/fstrings.jac +2 -0
  16. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +59 -0
  17. jaclang/compiler/passes/main/tests/test_registry_pass.py +2 -10
  18. jaclang/compiler/passes/main/tests/test_type_check_pass.py +1 -1
  19. jaclang/compiler/passes/transform.py +27 -3
  20. jaclang/compiler/passes/utils/mypy_ast_build.py +246 -26
  21. jaclang/compiler/symtable.py +6 -0
  22. jaclang/compiler/tests/test_importer.py +2 -2
  23. jaclang/langserve/engine.py +14 -12
  24. jaclang/langserve/server.py +7 -2
  25. jaclang/langserve/tests/test_server.py +1 -1
  26. jaclang/langserve/utils.py +17 -3
  27. jaclang/plugin/default.py +32 -32
  28. jaclang/plugin/feature.py +2 -2
  29. jaclang/plugin/plugin.md +471 -0
  30. jaclang/plugin/spec.py +2 -1
  31. jaclang/runtimelib/context.py +2 -0
  32. jaclang/runtimelib/importer.py +7 -2
  33. jaclang/runtimelib/machine.py +21 -6
  34. jaclang/settings.py +3 -0
  35. jaclang/tests/fixtures/builtin_dotgen.jac +6 -6
  36. jaclang/tests/fixtures/enum_inside_archtype.jac +16 -11
  37. jaclang/tests/fixtures/expr_type.jac +54 -0
  38. jaclang/tests/fixtures/glob_multivar_statement.jac +15 -0
  39. jaclang/tests/fixtures/registry.jac +20 -8
  40. jaclang/tests/foo/__init__.jac +0 -0
  41. jaclang/tests/main.jac +2 -0
  42. jaclang/tests/test_cli.py +68 -4
  43. jaclang/tests/test_language.py +60 -27
  44. jaclang/utils/helpers.py +92 -14
  45. jaclang/utils/lang_tools.py +6 -2
  46. jaclang/utils/treeprinter.py +4 -2
  47. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/METADATA +2 -1
  48. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/RECORD +50 -44
  49. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/WHEEL +1 -1
  50. {jaclang-0.7.23.dist-info → jaclang-0.7.25.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,54 @@
1
+ with entry {
2
+ a = 4;
3
+ b = 7;
4
+ c = a + b; # OpExpr.
5
+ d = a + b + c;
6
+
7
+ h = float(a); # CallExpr.
8
+
9
+ (1 < 2); # ComparisonExpr.
10
+ ('a' + 'b').upper(); # CallExpr.
11
+ [1,2][0]; # IndexExpr.
12
+ not False; # UnaryExpr.
13
+ "a" if True else "b"; # ConditionalExpr.
14
+ [i for i in range(10)]; # ListComprehension.
15
+ }
16
+
17
+ # Remaining expressions to test:
18
+ # AssertTypeExpr,
19
+ # AssignmentExpr,
20
+ # AwaitExpr,
21
+ # BytesExpr,
22
+ # CastExpr,
23
+ # ComplexExpr,
24
+ # DictionaryComprehension,
25
+ # DictExpr,
26
+ # EllipsisExpr,
27
+ # EnumCallExpr,
28
+ # Expression,
29
+ # FloatExpr,
30
+ # GeneratorExpr,
31
+ # IntExpr,
32
+ # LambdaExpr,
33
+ # ListExpr,
34
+ # MemberExpr,
35
+ # NamedTupleExpr,
36
+ # NameExpr,
37
+ # NewTypeExpr,
38
+ # ParamSpecExpr,
39
+ # PromoteExpr,
40
+ # RefExpr,
41
+ # RevealExpr,
42
+ # SetComprehension,
43
+ # SetExpr,
44
+ # SliceExpr,
45
+ # StarExpr,
46
+ # StrExpr,
47
+ # SuperExpr,
48
+ # TupleExpr,
49
+ # TypeAliasExpr,
50
+ # TypedDictExpr,
51
+ # TypeVarExpr,
52
+ # TypeVarTupleExpr,
53
+ # YieldExpr,
54
+ # YieldFromExpr,
@@ -0,0 +1,15 @@
1
+ glob a: str, b: str;
2
+ glob c: str;
3
+
4
+ can do() {
5
+ :g: a, b, c ;
6
+
7
+ (a, b, c) = ("Welcome", "to", "Jaseci!");
8
+ }
9
+
10
+ with entry {
11
+ (a, b, c) = ("Hello", "World", "!");
12
+ print(a, b, c);
13
+ do();
14
+ print(a, b, c);
15
+ }
@@ -13,16 +13,16 @@ Person {
13
13
 
14
14
  enum 'Personality of the Person'
15
15
  Personality {
16
- INTROVERT: 'Person who is shy and reticent' = 9,
17
- EXTROVERT: 'Person who is outgoing and socially confident'
16
+ INTROVERT: 'Person who is shy and reticent' = 9,
17
+ EXTROVERT: 'Person who is outgoing and socially confident'
18
18
  }
19
19
 
20
- glob personality_examples: 'Personality Information of Famous People': dict[str, Personality|None] = {
20
+ glob personality_examples: 'Personality Information of Famous People': dict[str, Personality | None] = {
21
21
  'Albert Einstein': Personality.INTROVERT,
22
22
  'Barack Obama': Personality.EXTROVERT
23
23
  };
24
24
 
25
- glob person_value : list[tuple[dict[str, Personality], int]] =(-90);
25
+ glob person_value: list[tuple[dict[str, Personality], int]] = (-90);
26
26
 
27
27
  can 'GenAI ability'
28
28
  genai_ability(x: 'Something': str) -> 'Something Else': str by llm();
@@ -34,13 +34,25 @@ normal_ability(x: 'Something': str) -> 'Something Else': str {
34
34
  }
35
35
 
36
36
  can foo() {
37
- person_value=22;
38
- can bar() {
39
- person_value=33;
40
- }
37
+ person_value = 22;
38
+ can bar() {
39
+ person_value = 33;
40
+ }
41
41
  }
42
42
  with entry {
43
43
  einstein_age: int = 75;
44
44
  einstein_age += 1;
45
45
  einstein = Person('Albert Einstein', einstein_age);
46
46
  }
47
+
48
+ import from jaclang.runtimelib.machine { JacMachine }
49
+
50
+ with entry {
51
+ registry = JacMachine.get().jac_program.sem_ir;
52
+
53
+ print(len(registry.registry));
54
+ print(len(list(registry.registry.items())[0][1]));
55
+ print(list(registry.registry.items())[3][0].scope);
56
+ (_, sem_info) = registry.lookup(name="normal_ability");
57
+ print(len(sem_info.get_children(registry)));
58
+ }
File without changes
jaclang/tests/main.jac ADDED
@@ -0,0 +1,2 @@
1
+ import foo;
2
+
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)
@@ -217,6 +215,42 @@ class JacCliTests(TestCase):
217
215
  r"13\:12 \- 13\:18.*Name - append - .*SymbolPath: builtins_test.builtins.list.append",
218
216
  )
219
217
 
218
+ def test_expr_types(self) -> None:
219
+ """Testing for print AstTool."""
220
+ captured_output = io.StringIO()
221
+ sys.stdout = captured_output
222
+
223
+ cli.tool("ir", ["ast", f"{self.fixture_abs_path('expr_type.jac')}"])
224
+
225
+ sys.stdout = sys.__stdout__
226
+ stdout_value = captured_output.getvalue()
227
+
228
+ self.assertRegex(
229
+ stdout_value, r"4\:9 \- 4\:14.*BinaryExpr \- Type\: builtins.int"
230
+ )
231
+ self.assertRegex(
232
+ stdout_value, r"7\:9 \- 7\:17.*FuncCall \- Type\: builtins.float"
233
+ )
234
+ self.assertRegex(
235
+ stdout_value, r"9\:6 \- 9\:11.*CompareExpr \- Type\: builtins.bool"
236
+ )
237
+ self.assertRegex(
238
+ stdout_value, r"10\:6 - 10\:15.*BinaryExpr \- Type\: builtins.str"
239
+ )
240
+ self.assertRegex(
241
+ stdout_value, r"11\:5 \- 11\:13.*AtomTrailer \- Type\: builtins.int"
242
+ )
243
+ self.assertRegex(
244
+ stdout_value, r"12\:5 \- 12\:14.*UnaryExpr \- Type\: builtins.bool"
245
+ )
246
+ self.assertRegex(
247
+ stdout_value, r"13\:5 \- 13\:25.*IfElseExpr \- Type\: Literal\['a']\?"
248
+ )
249
+ self.assertRegex(
250
+ stdout_value,
251
+ r"14\:5 \- 14\:27.*ListCompr - \[ListCompr] \- Type\: builtins.list\[builtins.int]",
252
+ )
253
+
220
254
  def test_ast_dotgen(self) -> None:
221
255
  """Testing for print AstTool."""
222
256
  captured_output = io.StringIO()
@@ -247,6 +281,8 @@ class JacCliTests(TestCase):
247
281
  self.assertEqual(stdout_value.count("type_info.ServerWrapper"), 7)
248
282
  self.assertEqual(stdout_value.count("builtins.int"), 3)
249
283
  self.assertEqual(stdout_value.count("builtins.str"), 10)
284
+ self.assertIn("Literal['test_server']", stdout_value)
285
+ self.assertIn("Literal['1']", stdout_value)
250
286
 
251
287
  def test_build_and_run(self) -> None:
252
288
  """Testing for print AstTool."""
@@ -368,3 +404,31 @@ class JacCliTests(TestCase):
368
404
  sys.stdout = sys.__stdout__
369
405
  stdout_value = captured_output.getvalue()
370
406
  self.assertIn("can my_print(x: object) -> None", stdout_value)
407
+
408
+ def test_caching_issue(self) -> None:
409
+ """Test for Caching Issue."""
410
+ test_file = self.fixture_abs_path("test_caching_issue.jac")
411
+ test_cases = [(10, True), (11, False)]
412
+ for x, is_passed in test_cases:
413
+ with open(test_file, "w") as f:
414
+ f.write(
415
+ f"""
416
+ test mytest{{
417
+ check 10 == {x};
418
+ }}
419
+ """
420
+ )
421
+ process = subprocess.Popen(
422
+ ["jac", "test", test_file],
423
+ stdout=subprocess.PIPE,
424
+ stderr=subprocess.PIPE,
425
+ text=True,
426
+ )
427
+ stdout, stderr = process.communicate()
428
+ if is_passed:
429
+ self.assertIn("Passed successfully.", stdout)
430
+ self.assertIn(".", stderr)
431
+ else:
432
+ self.assertNotIn("Passed successfully.", stdout)
433
+ self.assertIn("F", stderr)
434
+ 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
 
@@ -209,8 +208,10 @@ class JacLanguageTests(TestCase):
209
208
  """Test semstring."""
210
209
  captured_output = io.StringIO()
211
210
  sys.stdout = captured_output
211
+ sys.stderr = captured_output
212
212
  jac_import("semstr", base_path=self.fixture_abs_path("./"))
213
213
  sys.stdout = sys.__stdout__
214
+ sys.stderr = sys.__stderr__
214
215
  stdout_value = captured_output.getvalue()
215
216
  self.assertNotIn("Error", stdout_value)
216
217
 
@@ -237,6 +238,7 @@ class JacLanguageTests(TestCase):
237
238
  self.assertEqual(stdout_value.split("\n")[0], "11 13 12 12 11 12 12")
238
239
  self.assertEqual(stdout_value.split("\n")[1], '12 12 """hello""" 18 18')
239
240
  self.assertEqual(stdout_value.split("\n")[2], "11 12 11 12 11 18 23")
241
+ self.assertEqual(stdout_value.split("\n")[3], 'hello klkl"""')
240
242
 
241
243
  def test_deep_imports(self) -> None:
242
244
  """Parse micro jac file."""
@@ -465,24 +467,22 @@ class JacLanguageTests(TestCase):
465
467
  """Test Jac registry feature."""
466
468
  captured_output = io.StringIO()
467
469
  sys.stdout = captured_output
470
+ sys.stderr = captured_output
468
471
  jac_import("registry", base_path=self.fixture_abs_path("./"))
469
472
  sys.stdout = sys.__stdout__
473
+ sys.stderr = sys.__stderr__
470
474
  stdout_value = captured_output.getvalue()
471
475
  self.assertNotIn("Error", stdout_value)
472
476
 
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)
477
+ output_lines = stdout_value.strip().split("\n")
478
+ outputs = [
479
+ int(output_lines[i]) if i != 2 else output_lines[i] for i in range(4)
480
+ ]
480
481
 
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)
482
+ self.assertEqual(outputs[0], 9)
483
+ self.assertEqual(outputs[1], 2)
484
+ self.assertEqual(outputs[2], "Person")
485
+ self.assertEqual(outputs[3], 2)
486
486
 
487
487
  def test_enum_inside_arch(self) -> None:
488
488
  """Test Enum as member stmt."""
@@ -491,7 +491,7 @@ class JacLanguageTests(TestCase):
491
491
  jac_import("enum_inside_archtype", base_path=self.fixture_abs_path("./"))
492
492
  sys.stdout = sys.__stdout__
493
493
  stdout_value = captured_output.getvalue()
494
- self.assertEqual("2\n", stdout_value)
494
+ self.assertIn("2 Accessing privileged Data", stdout_value)
495
495
 
496
496
  def test_needs_import_1(self) -> None:
497
497
  """Test py ast to Jac ast conversion output."""
@@ -503,10 +503,13 @@ class JacLanguageTests(TestCase):
503
503
  import jaclang.compiler.absyntree as ast
504
504
 
505
505
  with open(file_name, "r") as f:
506
- parsed_ast = py_ast.parse(f.read())
506
+ file_source = f.read()
507
+ parsed_ast = py_ast.parse(file_source)
507
508
  try:
508
509
  py_ast_build_pass = PyastBuildPass(
509
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
510
+ input_ir=ast.PythonModuleAst(
511
+ parsed_ast, orig_src=ast.JacSource(file_source, file_name)
512
+ ),
510
513
  )
511
514
  except Exception as e:
512
515
  return f"Error While Jac to Py AST conversion: {e}"
@@ -528,9 +531,11 @@ class JacLanguageTests(TestCase):
528
531
 
529
532
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_1.py")
530
533
  with open(py_out_path) as f:
534
+ file_source = f.read()
531
535
  output = PyastBuildPass(
532
536
  input_ir=ast.PythonModuleAst(
533
- py_ast.parse(f.read()), mod_path=py_out_path
537
+ py_ast.parse(file_source),
538
+ orig_src=ast.JacSource(file_source, py_out_path),
534
539
  ),
535
540
  ).ir.unparse()
536
541
  # print(output)
@@ -559,10 +564,14 @@ class JacLanguageTests(TestCase):
559
564
  import jaclang.compiler.absyntree as ast
560
565
 
561
566
  with open(file_name, "r") as f:
562
- parsed_ast = py_ast.parse(f.read())
567
+ file_source = f.read()
568
+ parsed_ast = py_ast.parse(file_source)
563
569
  try:
564
570
  py_ast_build_pass = PyastBuildPass(
565
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
571
+ input_ir=ast.PythonModuleAst(
572
+ parsed_ast,
573
+ orig_src=ast.JacSource(file_source, file_name),
574
+ ),
566
575
  )
567
576
  except Exception as e:
568
577
  return f"Error While Jac to Py AST conversion: {e}"
@@ -587,9 +596,11 @@ class JacLanguageTests(TestCase):
587
596
 
588
597
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_2.py")
589
598
  with open(py_out_path) as f:
599
+ file_source = f.read()
590
600
  output = PyastBuildPass(
591
601
  input_ir=ast.PythonModuleAst(
592
- py_ast.parse(f.read()), mod_path=py_out_path
602
+ py_ast.parse(file_source),
603
+ orig_src=ast.JacSource(file_source, py_out_path),
593
604
  ),
594
605
  ).ir.unparse()
595
606
  self.assertIn("class X {\n with entry {\n\n a_b = 67;", output)
@@ -607,10 +618,14 @@ class JacLanguageTests(TestCase):
607
618
  import jaclang.compiler.absyntree as ast
608
619
 
609
620
  with open(file_name, "r") as f:
610
- parsed_ast = py_ast.parse(f.read())
621
+ file_source = f.read()
622
+ parsed_ast = py_ast.parse(file_source)
611
623
  try:
612
624
  py_ast_build_pass = PyastBuildPass(
613
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
625
+ input_ir=ast.PythonModuleAst(
626
+ parsed_ast,
627
+ orig_src=ast.JacSource(file_source, file_name),
628
+ ),
614
629
  )
615
630
  except Exception as e:
616
631
  return f"Error While Jac to Py AST conversion: {e}"
@@ -634,9 +649,11 @@ class JacLanguageTests(TestCase):
634
649
 
635
650
  py_out_path = os.path.join(self.fixture_abs_path("./"), "pyfunc_3.py")
636
651
  with open(py_out_path) as f:
652
+ file_source = f.read()
637
653
  output = PyastBuildPass(
638
654
  input_ir=ast.PythonModuleAst(
639
- py_ast.parse(f.read()), mod_path=py_out_path
655
+ py_ast.parse(file_source),
656
+ orig_src=ast.JacSource(file_source, py_out_path),
640
657
  ),
641
658
  ).ir.unparse()
642
659
  self.assertIn("if 0 <= x<= 5 {", output)
@@ -761,9 +778,11 @@ class JacLanguageTests(TestCase):
761
778
  module_path + ".py",
762
779
  )
763
780
  with open(file_path) as f:
781
+ file_source = f.read()
764
782
  jac_ast = PyastBuildPass(
765
783
  input_ir=ast.PythonModuleAst(
766
- py_ast.parse(f.read()), mod_path=file_path
784
+ py_ast.parse(file_source),
785
+ orig_src=ast.JacSource(file_source, file_path),
767
786
  )
768
787
  )
769
788
  settings.print_py_raised_ast = True
@@ -786,11 +805,13 @@ class JacLanguageTests(TestCase):
786
805
  """Test for access tags working."""
787
806
  captured_output = io.StringIO()
788
807
  sys.stdout = captured_output
808
+ sys.stderr = captured_output
789
809
  cli.check(
790
810
  self.fixture_abs_path("../../tests/fixtures/access_modifier.jac"),
791
811
  print_errs=True,
792
812
  )
793
813
  sys.stdout = sys.__stdout__
814
+ sys.stderr = sys.__stderr__
794
815
  stdout_value = captured_output.getvalue()
795
816
  self.assertEqual(stdout_value.count("Invalid access"), 18)
796
817
 
@@ -808,10 +829,12 @@ class JacLanguageTests(TestCase):
808
829
  parsed_ast = py_ast.parse(f.read())
809
830
  try:
810
831
  py_ast_build_pass = PyastBuildPass(
811
- input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
832
+ input_ir=ast.PythonModuleAst(
833
+ parsed_ast, orig_src=ast.JacSource(f.read(), file_name)
834
+ )
812
835
  )
813
836
  except Exception as e:
814
- return f"Error While Jac to Py AST conversion: {e}"
837
+ raise Exception(f"Error While Jac to Py AST conversion: {e}")
815
838
 
816
839
  settings.print_py_raised_ast = True
817
840
  ir = jac_pass_to_pass(py_ast_build_pass, schedule=py_code_gen_typed).ir
@@ -1156,3 +1179,13 @@ class JacLanguageTests(TestCase):
1156
1179
  sys.stdout = sys.__stdout__
1157
1180
  stdout_value = captured_output.getvalue()
1158
1181
  self.assertEqual("[MyNode(Name='End'), MyNode(Name='Middle')]\n", stdout_value)
1182
+
1183
+ def test_global_multivar(self) -> None:
1184
+ """Test supporting multiple global variable in a statement."""
1185
+ captured_output = io.StringIO()
1186
+ sys.stdout = captured_output
1187
+ jac_import("glob_multivar_statement", base_path=self.fixture_abs_path("./"))
1188
+ sys.stdout = sys.__stdout__
1189
+ stdout_value = captured_output.getvalue().split("\n")
1190
+ self.assertIn("Hello World !", stdout_value[0])
1191
+ self.assertIn("Welcome to Jaseci!", 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.25
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