jaclang 0.7.13__py3-none-any.whl → 0.7.16__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 (96) hide show
  1. jaclang/cli/cli.py +15 -10
  2. jaclang/cli/cmdreg.py +9 -12
  3. jaclang/compiler/__init__.py +19 -53
  4. jaclang/compiler/absyntree.py +95 -17
  5. jaclang/compiler/jac.lark +4 -3
  6. jaclang/compiler/parser.py +35 -23
  7. jaclang/compiler/passes/ir_pass.py +4 -13
  8. jaclang/compiler/passes/main/access_modifier_pass.py +1 -1
  9. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +4 -5
  10. jaclang/compiler/passes/main/import_pass.py +19 -23
  11. jaclang/compiler/passes/main/pyast_gen_pass.py +308 -567
  12. jaclang/compiler/passes/main/pyast_load_pass.py +33 -6
  13. jaclang/compiler/passes/main/registry_pass.py +37 -3
  14. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -1
  15. jaclang/compiler/passes/main/tests/__init__.py +1 -1
  16. jaclang/compiler/passes/main/tests/test_import_pass.py +5 -1
  17. jaclang/compiler/passes/main/type_check_pass.py +7 -0
  18. jaclang/compiler/passes/tool/fuse_comments_pass.py +14 -2
  19. jaclang/compiler/passes/tool/jac_formatter_pass.py +144 -94
  20. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +0 -1
  21. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/architype_test.jac +13 -0
  22. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comment_alignment.jac +11 -0
  23. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/comments.jac +13 -0
  24. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/decorator_stack.jac +37 -0
  25. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/esc_keywords.jac +5 -0
  26. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/long_names.jac +19 -0
  27. jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +6 -0
  28. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -0
  29. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +33 -39
  30. jaclang/compiler/passes/transform.py +4 -0
  31. jaclang/compiler/semtable.py +31 -7
  32. jaclang/compiler/tests/test_importer.py +12 -5
  33. jaclang/langserve/engine.py +82 -143
  34. jaclang/langserve/sem_manager.py +379 -0
  35. jaclang/langserve/server.py +8 -10
  36. jaclang/langserve/tests/fixtures/base_module_structure.jac +27 -6
  37. jaclang/langserve/tests/fixtures/circle.jac +3 -3
  38. jaclang/langserve/tests/fixtures/circle_err.jac +3 -3
  39. jaclang/langserve/tests/fixtures/circle_pure.test.jac +3 -3
  40. jaclang/langserve/tests/fixtures/import_include_statements.jac +1 -1
  41. jaclang/langserve/tests/test_sem_tokens.py +277 -0
  42. jaclang/langserve/tests/test_server.py +96 -16
  43. jaclang/langserve/utils.py +163 -96
  44. jaclang/plugin/builtin.py +1 -1
  45. jaclang/plugin/default.py +214 -24
  46. jaclang/plugin/feature.py +59 -11
  47. jaclang/plugin/spec.py +58 -6
  48. jaclang/{core → runtimelib}/architype.py +1 -1
  49. jaclang/{core → runtimelib}/context.py +8 -1
  50. jaclang/runtimelib/importer.py +361 -0
  51. jaclang/runtimelib/machine.py +94 -0
  52. jaclang/{core → runtimelib}/utils.py +13 -5
  53. jaclang/settings.py +4 -1
  54. jaclang/tests/fixtures/abc.jac +3 -3
  55. jaclang/tests/fixtures/blankwithentry.jac +3 -0
  56. jaclang/tests/fixtures/byllmissue.jac +1 -5
  57. jaclang/tests/fixtures/chandra_bugs2.jac +11 -10
  58. jaclang/tests/fixtures/cls_method.jac +41 -0
  59. jaclang/tests/fixtures/dblhello.jac +6 -0
  60. jaclang/tests/fixtures/deep/one_lev.jac +3 -3
  61. jaclang/tests/fixtures/deep/one_lev_dup.jac +2 -3
  62. jaclang/tests/fixtures/deep_import_mods.jac +13 -0
  63. jaclang/tests/fixtures/err.impl.jac +3 -0
  64. jaclang/tests/fixtures/err.jac +4 -2
  65. jaclang/tests/fixtures/err.test.jac +3 -0
  66. jaclang/tests/fixtures/err_runtime.jac +15 -0
  67. jaclang/tests/fixtures/game1.jac +1 -1
  68. jaclang/tests/fixtures/hello.jac +4 -0
  69. jaclang/tests/fixtures/impl_grab.impl.jac +2 -1
  70. jaclang/tests/fixtures/impl_grab.jac +4 -1
  71. jaclang/tests/fixtures/jp_importer_auto.jac +14 -0
  72. jaclang/tests/fixtures/maxfail_run_test.jac +4 -4
  73. jaclang/tests/fixtures/needs_import.jac +2 -2
  74. jaclang/tests/fixtures/pyfunc_2.py +3 -0
  75. jaclang/tests/fixtures/registry.jac +9 -0
  76. jaclang/tests/fixtures/run_test.jac +4 -4
  77. jaclang/tests/fixtures/semstr.jac +1 -4
  78. jaclang/tests/fixtures/simple_archs.jac +1 -1
  79. jaclang/tests/test_cli.py +65 -2
  80. jaclang/tests/test_language.py +83 -7
  81. jaclang/tests/test_man_code.py +17 -0
  82. jaclang/tests/test_reference.py +6 -0
  83. jaclang/utils/helpers.py +45 -21
  84. jaclang/utils/test.py +9 -0
  85. jaclang/utils/treeprinter.py +0 -4
  86. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/METADATA +3 -2
  87. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/RECORD +93 -77
  88. jaclang/core/importer.py +0 -344
  89. jaclang/tests/fixtures/aott_raise.jac +0 -25
  90. jaclang/tests/fixtures/package_import.jac +0 -6
  91. /jaclang/{core → runtimelib}/__init__.py +0 -0
  92. /jaclang/{core → runtimelib}/constructs.py +0 -0
  93. /jaclang/{core → runtimelib}/memory.py +0 -0
  94. /jaclang/{core → runtimelib}/test.py +0 -0
  95. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/WHEEL +0 -0
  96. {jaclang-0.7.13.dist-info → jaclang-0.7.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,94 @@
1
+ """Jac Machine module."""
2
+
3
+ import marshal
4
+ import os
5
+ import types
6
+ from typing import Optional
7
+
8
+ from jaclang.compiler.absyntree import Module
9
+ from jaclang.compiler.compile import compile_jac
10
+ from jaclang.compiler.constant import Constants as Con
11
+ from jaclang.utils.log import logging
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class JacMachine:
17
+ """JacMachine to handle the VM-related functionalities and loaded programs."""
18
+
19
+ def __init__(self, base_path: str = "") -> None:
20
+ """Initialize the JacMachine object."""
21
+ # self.loaded_modules: Dict[str, types.ModuleType] = {}
22
+ if not len(base_path):
23
+ base_path = os.getcwd()
24
+ self.base_path = base_path
25
+ self.base_path_dir = (
26
+ os.path.dirname(base_path)
27
+ if not os.path.isdir(base_path)
28
+ else os.path.abspath(base_path)
29
+ )
30
+ self.jac_program: Optional[JacProgram] = None
31
+
32
+ def attach_program(self, jac_program: "JacProgram") -> None:
33
+ """Attach a JacProgram to the machine."""
34
+ self.jac_program = jac_program
35
+
36
+ def get_mod_bundle(self) -> Optional[Module]:
37
+ """Retrieve the mod_bundle from the attached JacProgram."""
38
+ if self.jac_program:
39
+ return self.jac_program.mod_bundle
40
+ return None
41
+
42
+ def get_bytecode(
43
+ self,
44
+ module_name: str,
45
+ full_target: str,
46
+ caller_dir: str,
47
+ cachable: bool = True,
48
+ ) -> Optional[types.CodeType]:
49
+ """Retrieve bytecode from the attached JacProgram."""
50
+ if self.jac_program:
51
+ return self.jac_program.get_bytecode(
52
+ module_name, full_target, caller_dir, cachable
53
+ )
54
+ return None
55
+
56
+
57
+ class JacProgram:
58
+ """Class to hold the mod_bundle and bytecode for Jac modules."""
59
+
60
+ def __init__(
61
+ self, mod_bundle: Optional[Module], bytecode: Optional[dict[str, bytes]]
62
+ ) -> None:
63
+ """Initialize the JacProgram object."""
64
+ self.mod_bundle = mod_bundle
65
+ self.bytecode = bytecode or {}
66
+
67
+ def get_bytecode(
68
+ self,
69
+ module_name: str,
70
+ full_target: str,
71
+ caller_dir: str,
72
+ cachable: bool = True,
73
+ ) -> Optional[types.CodeType]:
74
+ """Get the bytecode for a specific module."""
75
+ if self.mod_bundle and isinstance(self.mod_bundle, Module):
76
+ codeobj = self.mod_bundle.mod_deps[full_target].gen.py_bytecode
77
+ return marshal.loads(codeobj) if isinstance(codeobj, bytes) else None
78
+ gen_dir = os.path.join(caller_dir, Con.JAC_GEN_DIR)
79
+ pyc_file_path = os.path.join(gen_dir, module_name + ".jbc")
80
+ if cachable and os.path.exists(pyc_file_path):
81
+ with open(pyc_file_path, "rb") as f:
82
+ return marshal.load(f)
83
+
84
+ result = compile_jac(full_target, cache_result=cachable)
85
+ if result.errors_had or not result.ir.gen.py_bytecode:
86
+ logger.error(
87
+ f"While importing {len(result.errors_had)} errors"
88
+ f" found in {full_target}"
89
+ )
90
+ return None
91
+ if result.ir.gen.py_bytecode is not None:
92
+ return marshal.loads(result.ir.gen.py_bytecode)
93
+ else:
94
+ return None
@@ -11,7 +11,7 @@ import jaclang.compiler.absyntree as ast
11
11
  from jaclang.compiler.semtable import SemScope
12
12
 
13
13
  if TYPE_CHECKING:
14
- from jaclang.core.constructs import NodeAnchor, NodeArchitype
14
+ from jaclang.runtimelib.constructs import NodeAnchor, NodeArchitype
15
15
 
16
16
 
17
17
  @contextmanager
@@ -113,18 +113,26 @@ def get_sem_scope(node: ast.AstNode) -> SemScope:
113
113
  a = (
114
114
  node.name
115
115
  if isinstance(node, ast.Module)
116
- else node.name.value if isinstance(node, (ast.Enum, ast.Architype)) else ""
116
+ else (
117
+ node.name.value
118
+ if isinstance(node, (ast.Enum, ast.Architype))
119
+ else node.name_ref.sym_name if isinstance(node, ast.Ability) else ""
120
+ )
117
121
  )
118
122
  if isinstance(node, ast.Module):
119
123
  return SemScope(a, "Module", None)
120
- elif isinstance(node, (ast.Enum, ast.Architype)):
124
+ elif isinstance(node, (ast.Enum, ast.Architype, ast.Ability)):
121
125
  node_type = (
122
126
  node.__class__.__name__
123
127
  if isinstance(node, ast.Enum)
124
- else node.arch_type.value
128
+ else ("Ability" if isinstance(node, ast.Ability) else node.arch_type.value)
125
129
  )
126
130
  if node.parent:
127
- return SemScope(a, node_type, get_sem_scope(node.parent))
131
+ return SemScope(
132
+ a,
133
+ node_type,
134
+ get_sem_scope(node.parent),
135
+ )
128
136
  else:
129
137
  if node.parent:
130
138
  return get_sem_scope(node.parent)
jaclang/settings.py CHANGED
@@ -1,4 +1,4 @@
1
- """Main settings of Jac lang."""
1
+ """Main settings of jac lang."""
2
2
 
3
3
  import configparser
4
4
  import os
@@ -19,6 +19,9 @@ class Settings:
19
19
  py_raise: bool = False
20
20
  py_raise_deep: bool = False
21
21
 
22
+ # Formatter configuration
23
+ max_line_length: int = 88
24
+
22
25
  # LSP configuration
23
26
  lsp_debug: bool = False
24
27
 
@@ -63,15 +63,15 @@ with entry:__main__ {
63
63
  glob expected_area = 78.53981633974483;
64
64
 
65
65
  test calc_area {
66
- check assertAlmostEqual(calculate_area(RAD), expected_area);
66
+ check almostEqual(calculate_area(RAD), expected_area);
67
67
  }
68
68
 
69
69
  test circle_area {
70
70
  c = Circle(RAD);
71
- check assertAlmostEqual(c.area(), expected_area);
71
+ check almostEqual(c.area(), expected_area);
72
72
  }
73
73
 
74
74
  test circle_type {
75
75
  c = Circle(RAD);
76
- check assertEqual(c.shape_type, ShapeType.CIRCLE);
76
+ check c.shape_type == ShapeType.CIRCLE;
77
77
  }
@@ -0,0 +1,3 @@
1
+ with entry:__main__ {}
2
+
3
+ with entry {print("i work");}
@@ -5,8 +5,4 @@ class Foo {
5
5
  can bar() {
6
6
  return 1;
7
7
  }
8
- }
9
-
10
- with entry {
11
- my_thing = YourThing(level=thingy by llm());
12
- }
8
+ }
@@ -1,10 +1,13 @@
1
1
  import:py re;
2
2
 
3
- glob a: int=5;
3
+ glob a: int = 5;
4
4
 
5
5
  with entry {
6
- arguments = {x:None for x in re.findall(r'\{([A-Za-z0-9_]+)\}', "Apple {apple} pineapple {pineapple}")};
7
- a: int=5;
6
+ arguments = {x: None for x in re.findall(
7
+ r'\{([A-Za-z0-9_]+)\}',
8
+ "Apple {apple} pineapple {pineapple}"
9
+ )};
10
+ a: int = 5;
8
11
  if False {
9
12
  with open(f"Apple{apple}.txt") as f { # Fix syntax highlighting
10
13
 
@@ -12,15 +15,13 @@ with entry {
12
15
  }
13
16
  }
14
17
  print(arguments);
15
- print(
16
- """This is a long
17
- line of code."""
18
- );
18
+ print("""This is a long
19
+ line of code.""");
19
20
  }
20
21
 
21
- with entry{
22
- a={"a":"apple", "b":"ball", "c":"cat"};
23
- y={**a, "d":"dog", "e":"elephant"};
22
+ with entry {
23
+ a = {"a": "apple", "b": "ball", "c": "cat"};
24
+ y = {**a, "d": "dog", "e": "elephant"};
24
25
  print(y);
25
26
  }
26
27
  # Use before def error would be nice
@@ -0,0 +1,41 @@
1
+ """Test file for class method."""
2
+
3
+ class MyClass {
4
+ can simple_method() -> str {
5
+ return "Hello, World1!";
6
+ }
7
+
8
+ @classmethod
9
+ can my_method(cls: Type[MyClass]) -> str {
10
+ x = cls.__name__;
11
+ print(x);
12
+ return "Hello, World2!";
13
+ }
14
+ }
15
+
16
+ with entry {
17
+ a = MyClass.simple_method();
18
+ b = MyClass.my_method();
19
+ print(a, b);
20
+ }
21
+
22
+ class MyClass2 {
23
+ can Ability_1(self: MyClass2) -> str;
24
+ @classmethod
25
+ can Ability_2(cls: Type[MyClass2]) -> str;
26
+ }
27
+
28
+ :obj:MyClass2:can:Ability_1
29
+ (self: MyClass2) -> str {
30
+ return "Hello, World!";
31
+ }
32
+
33
+ :obj:MyClass2:can:Ability_2 {
34
+ return "Hello, World22!";
35
+ }
36
+
37
+ with entry {
38
+ a = MyClass2().Ability_1();
39
+ b = MyClass2.Ability_2();
40
+ print(a, b);
41
+ }
@@ -0,0 +1,6 @@
1
+ import hello;
2
+ import hello;
3
+
4
+ with entry {
5
+ hello.still_there();
6
+ }
@@ -1,8 +1,8 @@
1
1
  import:jac from .deeper, snd_lev as snd_lev;
2
- import:jac from ..deep, deeper;
3
- import:jac from ., deeper as mydeeper;
2
+ # import:jac from ..deep, deeper;
3
+ # import:jac from ., deeper as mydeeper;
4
4
 
5
5
  can olprint -> str {
6
6
  # deeper.snd_lev.slprint(); FIXME:
7
7
  return "one level deeper" + snd_lev.slprint();
8
- }
8
+ }
@@ -1,6 +1,5 @@
1
- import:jac deeper.snd_lev as snd_lev;
1
+ import:jac from .deeper, snd_lev as snd_lev;
2
2
 
3
- can olprint ->str {
3
+ can olprint -> str {
4
4
  return "one level deeper" + snd_lev.slprint();
5
5
  }
6
-
@@ -0,0 +1,13 @@
1
+ import:py sys;
2
+
3
+ with entry {
4
+ before_mod = list(sys.modules.keys());
5
+ }
6
+
7
+ import:jac deep.one_lev as one_lev;
8
+ import:jac from deep.one_lev, olprint;
9
+
10
+ with entry {
11
+ after_mod = [m for m in sys.modules.keys() if m not in before_mod];
12
+ print(after_mod);
13
+ }
@@ -0,0 +1,3 @@
1
+ :o:HasFault:c:init {
2
+ print(5 / 0);
3
+ }
@@ -1,5 +1,7 @@
1
- """Demo"""
1
+ obj HasFault {
2
+ can init;
3
+ }
2
4
 
3
5
  can speak {
4
- "Hello" |> aprint;
6
+ HasFault();
5
7
  }
@@ -0,0 +1,3 @@
1
+ test baddy {
2
+ print(5 / 0);
3
+ }
@@ -0,0 +1,15 @@
1
+
2
+ can bar(some_list:list) {
3
+ invalid_index = 4;
4
+ print(some_list[invalid_index]); # This should fail.
5
+ }
6
+
7
+
8
+ can foo() {
9
+ bar([0, 1, 2, 3]);
10
+ }
11
+
12
+
13
+ with entry {
14
+ foo();
15
+ }
@@ -1,5 +1,5 @@
1
1
  import:py random;
2
- import:py from typing, Tuple;
2
+ import:py from typing { Tuple }
3
3
 
4
4
  obj Button {
5
5
  can is_pressed(pos: tuple, pressed: str) -> bool {
@@ -1,5 +1,9 @@
1
1
  """Hello World!"""
2
2
 
3
+ can still_there {
4
+ print("im still here");
5
+ }
6
+
3
7
  with entry {
4
8
  "Hello World!" |> print;
5
9
  }
@@ -1,4 +1,5 @@
1
1
  import:py math;
2
+
2
3
  :can:test_grab {
3
4
  return math.sqrt(2);
4
- }
5
+ }
@@ -1,2 +1,5 @@
1
1
  can test_grab;
2
- with entry {print(test_grab());}
2
+
3
+ with entry {
4
+ print(test_grab());
5
+ }
@@ -0,0 +1,14 @@
1
+ import from math { sin as s, cos, sqrt as sq }
2
+ include random;
3
+ import from ..test_cli, JacCliTests as Jac;
4
+ import from deep.mycode, code as c;
5
+ import hashcheck as h, assign_compr as a;
6
+ import from jacsamp, my_print as m;
7
+
8
+ with entry {
9
+ print(sq(4), s(30), cos(30));
10
+ print(randint(1, 10));
11
+ print(m("--->my_print<---"));
12
+ print(h.a, a.mvar);
13
+ print(c());
14
+ }
@@ -1,17 +1,17 @@
1
1
  glob x = 5, y = 2;
2
2
 
3
3
  test a {
4
- check assertAlmostEqual(5, x);
4
+ check almostEqual(5, x);
5
5
  }
6
6
 
7
7
  test b {
8
- check assertIn("l", "llm");
8
+ check "l" in "llm";
9
9
  }
10
10
 
11
11
  test c {
12
- check assertEqual(x - y, 3);
12
+ check x - y == 3;
13
13
  }
14
14
 
15
15
  test d {
16
- check assertEqual(1, 2);
16
+ check 1 == 2;
17
17
  }
@@ -3,7 +3,7 @@
3
3
  import:py os;
4
4
  import:py pyfunc;
5
5
  import:py random;
6
- import:py from pyfunc, my_print;
6
+ import:py from pyfunc { my_print }
7
7
 
8
8
  with entry {
9
9
  my_print(pyfunc);
@@ -11,7 +11,7 @@ with entry {
11
11
  }
12
12
 
13
13
  import:py circle_pysolo;
14
- import:py from circle_pysolo, calculate_area;
14
+ import:py from circle_pysolo { calculate_area }
15
15
 
16
16
  with entry {
17
17
  print(f"are {calculate_area(2.0)}");
@@ -277,3 +277,6 @@ def foo() -> None:
277
277
 
278
278
 
279
279
  foo()
280
+
281
+ node = 90
282
+ print(node)
@@ -24,6 +24,15 @@ glob personality_examples: 'Personality Information of Famous People': dict[str,
24
24
 
25
25
  glob person_value : list[tuple[dict[str, Personality], int]] =(-90);
26
26
 
27
+ can 'GenAI ability'
28
+ genai_ability(x: 'Something': str) -> 'Something Else': str by llm();
29
+
30
+ can 'Normal ability'
31
+ normal_ability(x: 'Something': str) -> 'Something Else': str {
32
+ y = 10;
33
+ return x;
34
+ }
35
+
27
36
  can foo() {
28
37
  person_value=22;
29
38
  can bar() {
@@ -1,17 +1,17 @@
1
1
  glob a = 5, b = 2;
2
2
 
3
3
  test t1 {
4
- check assertAlmostEqual(a, 6);
4
+ check almostEqual(a, 6);
5
5
  }
6
6
 
7
7
  test t2 {
8
- check assertTrue(a != b);
8
+ check a != b;
9
9
  }
10
10
 
11
11
  test t3 {
12
- check assertIn("d", "abc");
12
+ check "d" in "abc";
13
13
  }
14
14
 
15
15
  test t4 {
16
- check assertEqual(a - b, 3);
16
+ check a - b == 3;
17
17
  }
@@ -27,7 +27,4 @@ journal {
27
27
  can add() -> 'no of': int {}
28
28
 
29
29
  can 'update user mood'
30
- updateMood(* mood: 'Moo of the Person': str, something:'Something':str, something_else: 'Something Else': int = 5, without_semstr: float) -> 'mood selection': str {}
31
-
32
-
33
- can get_personality (person: 'Person Object': list[Person]) -> 'Personality of the Person': dict[Personality, PersonalityIndex] by llm(reason=True, incl_info=(personality_examples, self.diary_entries));
30
+ updateMood(* mood: 'Moo of the Person': str, something:'Something':str, something_else: 'Something Else': int = 5, without_semstr: float) -> 'mood selection': str {}
@@ -15,7 +15,7 @@ class SimpleClass {
15
15
  var2: int,
16
16
  var3: int = 0;
17
17
 
18
- can init {
18
+ can init(self: SimpleClass) {
19
19
  print(self.var3);
20
20
  }
21
21
  }
jaclang/tests/test_cli.py CHANGED
@@ -5,6 +5,7 @@ import io
5
5
  import os
6
6
  import subprocess
7
7
  import sys
8
+ import traceback
8
9
 
9
10
  from jaclang.cli import cli
10
11
  from jaclang.plugin.builtin import dotgen
@@ -38,7 +39,7 @@ class JacCliTests(TestCase):
38
39
  sys.stderr = captured_output
39
40
 
40
41
  try:
41
- cli.enter(self.fixture_abs_path("err2.jac"), entrypoint="speak", args=[]) # type: ignore
42
+ cli.enter(self.fixture_abs_path("err2.jac"), entrypoint="speak", args=[])
42
43
  except Exception as e:
43
44
  print(f"Error: {e}")
44
45
 
@@ -46,7 +47,69 @@ class JacCliTests(TestCase):
46
47
  sys.stderr = sys.__stderr__
47
48
  stdout_value = captured_output.getvalue()
48
49
  # print(stdout_value)
49
- self.assertIn("Syntax Error", stdout_value)
50
+ self.assertIn("Error", stdout_value)
51
+
52
+ def test_jac_cli_alert_based_runtime_err(self) -> None:
53
+ """Basic test for pass."""
54
+ captured_output = io.StringIO()
55
+ sys.stdout = captured_output
56
+ sys.stderr = captured_output
57
+
58
+ try:
59
+ cli.run(self.fixture_abs_path("err_runtime.jac"))
60
+ except Exception as e:
61
+ print(f"Error: {e}")
62
+
63
+ sys.stdout = sys.__stdout__
64
+ sys.stderr = sys.__stderr__
65
+
66
+ expected_stdout_values = (
67
+ "Error: list index out of range",
68
+ " print(some_list[invalid_index]);",
69
+ " ^^^^^^^^^^^^^^^^^^^^^^^^",
70
+ " at bar() ",
71
+ " at foo() ",
72
+ " at <module> ",
73
+ )
74
+
75
+ logger_capture = "\n".join([rec.message for rec in self.caplog.records])
76
+ for exp in expected_stdout_values:
77
+ self.assertIn(exp, logger_capture)
78
+
79
+ def test_jac_impl_err(self) -> None:
80
+ """Basic test for pass."""
81
+ if "jaclang.tests.fixtures.err" in sys.modules:
82
+ del sys.modules["jaclang.tests.fixtures.err"]
83
+ captured_output = io.StringIO()
84
+ sys.stdout = captured_output
85
+ sys.stderr = captured_output
86
+
87
+ try:
88
+ cli.enter(self.fixture_abs_path("err.jac"), entrypoint="speak", args=[])
89
+ except Exception:
90
+ traceback.print_exc()
91
+
92
+ sys.stdout = sys.__stdout__
93
+ sys.stderr = sys.__stderr__
94
+ stdout_value = captured_output.getvalue()
95
+ # print(stdout_value)
96
+ path_to_file = self.fixture_abs_path("err.impl.jac")
97
+ self.assertIn(f'"{path_to_file}", line 2', stdout_value)
98
+
99
+ def test_jac_test_err(self) -> None:
100
+ """Basic test for pass."""
101
+ if "jaclang.tests.fixtures.err" in sys.modules:
102
+ del sys.modules["jaclang.tests.fixtures.err"]
103
+ captured_output = io.StringIO()
104
+ sys.stdout = captured_output
105
+ sys.stderr = captured_output
106
+ cli.test(self.fixture_abs_path("err.jac"))
107
+ sys.stdout = sys.__stdout__
108
+ sys.stderr = sys.__stderr__
109
+ stdout_value = captured_output.getvalue()
110
+ # print(stdout_value)
111
+ path_to_file = self.fixture_abs_path("err.test.jac")
112
+ self.assertIn(f'"{path_to_file}", line 2,', stdout_value)
50
113
 
51
114
  def test_jac_ast_tool_pass_template(self) -> None:
52
115
  """Basic test for pass."""