jaclang 0.7.30__py3-none-any.whl → 0.7.32__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 (35) hide show
  1. jaclang/__init__.py +419 -3
  2. jaclang/compiler/absyntree.py +3 -3
  3. jaclang/compiler/constant.py +4 -4
  4. jaclang/compiler/jac.lark +226 -175
  5. jaclang/compiler/parser.py +1772 -2422
  6. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +2 -2
  7. jaclang/compiler/passes/main/import_pass.py +2 -1
  8. jaclang/compiler/passes/main/inheritance_pass.py +20 -1
  9. jaclang/compiler/passes/main/pyast_gen_pass.py +565 -723
  10. jaclang/compiler/passes/main/tests/test_type_check_pass.py +6 -3
  11. jaclang/compiler/tests/test_parser.py +13 -5
  12. jaclang/plugin/builtin.py +11 -0
  13. jaclang/plugin/default.py +64 -10
  14. jaclang/plugin/feature.py +14 -0
  15. jaclang/plugin/spec.py +16 -0
  16. jaclang/plugin/tests/fixtures/graph_purger.jac +2 -0
  17. jaclang/plugin/tests/fixtures/other_root_access.jac +1 -0
  18. jaclang/plugin/tests/fixtures/savable_object.jac +2 -0
  19. jaclang/plugin/tests/fixtures/traversing_save.jac +17 -0
  20. jaclang/plugin/tests/test_jaseci.py +34 -1
  21. jaclang/runtimelib/architype.py +9 -19
  22. jaclang/runtimelib/context.py +25 -9
  23. jaclang/settings.py +2 -0
  24. jaclang/tests/fixtures/base_class_complex_expr.jac +38 -0
  25. jaclang/tests/fixtures/create_dynamic_architype.jac +1 -1
  26. jaclang/tests/fixtures/nested_impls.jac +55 -0
  27. jaclang/tests/test_cli.py +21 -0
  28. jaclang/tests/test_language.py +27 -13
  29. jaclang/tests/test_reference.py +2 -2
  30. jaclang/utils/helpers.py +4 -3
  31. jaclang/utils/profiler.py +62 -0
  32. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/METADATA +1 -1
  33. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/RECORD +35 -31
  34. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/WHEEL +1 -1
  35. {jaclang-0.7.30.dist-info → jaclang-0.7.32.dist-info}/entry_points.txt +0 -0
@@ -70,19 +70,22 @@ class MypyTypeCheckPassTests(TestCase):
70
70
  )
71
71
  self.assertRegex(
72
72
  out,
73
- r"129:24 - 129:28.*SpecialVarRef - _Jac.get_root\(\) \- Type\: jaclang.runtimelib.architype.Root",
73
+ r"129:24 - 129:28.*SpecialVarRef - Jac.get_root\(\) \- Type\: jaclang.Root",
74
74
  )
75
+
75
76
  self.assertRegex(out, r"129:11 - 129:29.*FuncCall \- Type\: builtins\.str")
76
77
  self.assertRegex(
77
78
  out,
78
79
  r"129:15 - 129:23.*Name \- node_dot \- Type\: builtins.str, SymbolTable\: str",
79
80
  )
81
+
80
82
  self.assertRegex(
81
83
  out,
82
- r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.runtimelib.architype.WalkerArchitype",
84
+ r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.Walker",
83
85
  )
84
86
  self.assertRegex(
85
87
  out,
86
- r"48:11 - 48:28.*EdgeRefTrailer \- Type\: builtins.list\[data_spatial_types.A\]",
88
+ r"48:11 - 48:28.*EdgeRefTrailer \- Type\: jaclang.JacList\[data_spatial_types.A\]",
87
89
  )
90
+
88
91
  self.assertRegex(out, r"24:5 - 24:25.*BinaryExpr \- Type\: builtins.bool", out)
@@ -89,12 +89,20 @@ class TestLarkParser(TestCaseMicroSuite):
89
89
  JacParser.TreeToAST.__base__, value.__name__, False
90
90
  ):
91
91
  parse_funcs.append(name)
92
- for i in rules:
93
- self.assertIn(i, parse_funcs)
94
- for i in parse_funcs:
95
- if i in ["binary_expr_unwind", "ice", "nu"]:
92
+ for rule in rules:
93
+ self.assertIn(rule, parse_funcs)
94
+ for fn in parse_funcs:
95
+ if fn.startswith("_") or fn in [
96
+ "ice",
97
+ "match",
98
+ "consume",
99
+ "match_token",
100
+ "consume_token",
101
+ "match_many",
102
+ "consume_many",
103
+ ]:
96
104
  continue
97
- self.assertIn(i, rules)
105
+ self.assertIn(fn, rules)
98
106
 
99
107
  def test_all_ast_has_normalize(self) -> None:
100
108
  """Test for enter/exit name diffs with parser."""
jaclang/plugin/builtin.py CHANGED
@@ -7,6 +7,12 @@ from typing import Optional
7
7
  from jaclang.plugin.feature import JacFeature as Jac
8
8
  from jaclang.runtimelib.constructs import Architype, NodeArchitype
9
9
 
10
+ __all__ = [
11
+ "dotgen",
12
+ "jid",
13
+ "jobj",
14
+ ]
15
+
10
16
 
11
17
  def dotgen(
12
18
  node: Optional[NodeArchitype] = None,
@@ -44,3 +50,8 @@ def dotgen(
44
50
  def jid(obj: Architype) -> str:
45
51
  """Get the id of the object."""
46
52
  return Jac.object_ref(obj)
53
+
54
+
55
+ def jobj(id: str) -> Architype | None:
56
+ """Get the object from the id."""
57
+ return Jac.get_object(id)
jaclang/plugin/default.py CHANGED
@@ -660,11 +660,15 @@ class JacFeatureImpl(
660
660
  if not hasattr(cls, "_jac_entry_funcs_") or not hasattr(
661
661
  cls, "_jac_exit_funcs_"
662
662
  ):
663
- # Saving the module path and reassign it after creating cls
664
- # So the jac modules are part of the correct module
665
- cur_module = cls.__module__
666
- cls = type(cls.__name__, (cls, arch_base), {})
667
- cls.__module__ = cur_module
663
+ # If a class only inherit from object (ie. Doesn't inherit from a class), we cannot modify
664
+ # the __bases__ property of it, so it's necessary to make sure the class is not a direct child of object.
665
+ assert cls.__bases__ != (object,)
666
+ bases = (
667
+ (cls.__bases__ + (arch_base,))
668
+ if arch_base not in cls.__bases__
669
+ else cls.__bases__
670
+ )
671
+ cls.__bases__ = bases
668
672
  cls._jac_entry_funcs_ = on_entry # type: ignore
669
673
  cls._jac_exit_funcs_ = on_exit # type: ignore
670
674
  else:
@@ -724,6 +728,22 @@ class JacFeatureImpl(
724
728
 
725
729
  return decorator
726
730
 
731
+ @staticmethod
732
+ @hookimpl
733
+ def make_root(
734
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
735
+ ) -> Callable[[type], type]:
736
+ """Create a obj architype."""
737
+
738
+ def decorator(cls: Type[Architype]) -> Type[Architype]:
739
+ """Decorate class."""
740
+ cls = Jac.make_architype(
741
+ cls=cls, arch_base=Root, on_entry=on_entry, on_exit=on_exit
742
+ )
743
+ return cls
744
+
745
+ return decorator
746
+
727
747
  @staticmethod
728
748
  @hookimpl
729
749
  def make_edge(
@@ -740,6 +760,25 @@ class JacFeatureImpl(
740
760
 
741
761
  return decorator
742
762
 
763
+ @staticmethod
764
+ @hookimpl
765
+ def make_generic_edge(
766
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
767
+ ) -> Callable[[type], type]:
768
+ """Create a edge architype."""
769
+
770
+ def decorator(cls: Type[Architype]) -> Type[Architype]:
771
+ """Decorate class."""
772
+ cls = Jac.make_architype(
773
+ cls=cls,
774
+ arch_base=GenericEdge,
775
+ on_entry=on_entry,
776
+ on_exit=on_exit,
777
+ )
778
+ return cls
779
+
780
+ return decorator
781
+
743
782
  @staticmethod
744
783
  @hookimpl
745
784
  def make_walker(
@@ -1061,7 +1100,9 @@ class JacFeatureImpl(
1061
1100
  @hookimpl
1062
1101
  def get_root_type() -> Type[Root]:
1063
1102
  """Jac's root getter."""
1064
- return Root
1103
+ from jaclang import Root as JRoot
1104
+
1105
+ return cast(Type[Root], JRoot)
1065
1106
 
1066
1107
  @staticmethod
1067
1108
  @hookimpl
@@ -1071,10 +1112,12 @@ class JacFeatureImpl(
1071
1112
  conn_assign: Optional[tuple[tuple, tuple]],
1072
1113
  ) -> Callable[[NodeAnchor, NodeAnchor], EdgeArchitype]:
1073
1114
  """Jac's root getter."""
1074
- conn_type = conn_type if conn_type else GenericEdge
1115
+ from jaclang import GenericEdge
1116
+
1117
+ ct = conn_type if conn_type else GenericEdge
1075
1118
 
1076
1119
  def builder(source: NodeAnchor, target: NodeAnchor) -> EdgeArchitype:
1077
- edge = conn_type() if isinstance(conn_type, type) else conn_type
1120
+ edge = ct() if isinstance(ct, type) else ct
1078
1121
 
1079
1122
  eanch = edge.__jac__ = EdgeAnchor(
1080
1123
  architype=edge,
@@ -1093,8 +1136,6 @@ class JacFeatureImpl(
1093
1136
  raise ValueError(f"Invalid attribute: {fld}")
1094
1137
  if source.persistent or target.persistent:
1095
1138
  Jac.save(eanch)
1096
- Jac.save(target)
1097
- Jac.save(source)
1098
1139
  return edge
1099
1140
 
1100
1141
  return builder
@@ -1112,6 +1153,19 @@ class JacFeatureImpl(
1112
1153
 
1113
1154
  jctx.mem.set(anchor.id, anchor)
1114
1155
 
1156
+ match anchor:
1157
+ case NodeAnchor():
1158
+ for ed in anchor.edges:
1159
+ if ed.is_populated() and not ed.persistent:
1160
+ Jac.save(ed)
1161
+ case EdgeAnchor():
1162
+ if (src := anchor.source) and src.is_populated() and not src.persistent:
1163
+ Jac.save(src)
1164
+ if (trg := anchor.target) and trg.is_populated() and not trg.persistent:
1165
+ Jac.save(trg)
1166
+ case _:
1167
+ pass
1168
+
1115
1169
  @staticmethod
1116
1170
  @hookimpl
1117
1171
  def destroy(obj: Architype | Anchor) -> None:
jaclang/plugin/feature.py CHANGED
@@ -305,6 +305,13 @@ class JacFeature(
305
305
  """Create a node architype."""
306
306
  return plugin_manager.hook.make_node(on_entry=on_entry, on_exit=on_exit)
307
307
 
308
+ @staticmethod
309
+ def make_root(
310
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
311
+ ) -> Callable[[type], type]:
312
+ """Create a root node architype."""
313
+ return plugin_manager.hook.make_root(on_entry=on_entry, on_exit=on_exit)
314
+
308
315
  @staticmethod
309
316
  def make_edge(
310
317
  on_entry: list[DSFunc], on_exit: list[DSFunc]
@@ -312,6 +319,13 @@ class JacFeature(
312
319
  """Create a edge architype."""
313
320
  return plugin_manager.hook.make_edge(on_entry=on_entry, on_exit=on_exit)
314
321
 
322
+ @staticmethod
323
+ def make_generic_edge(
324
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
325
+ ) -> Callable[[type], type]:
326
+ """Create a edge architype."""
327
+ return plugin_manager.hook.make_generic_edge(on_entry=on_entry, on_exit=on_exit)
328
+
315
329
  @staticmethod
316
330
  def make_walker(
317
331
  on_entry: list[DSFunc], on_exit: list[DSFunc]
jaclang/plugin/spec.py CHANGED
@@ -295,6 +295,14 @@ class JacFeatureSpec(
295
295
  """Create a node architype."""
296
296
  raise NotImplementedError
297
297
 
298
+ @staticmethod
299
+ @hookspec(firstresult=True)
300
+ def make_root(
301
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
302
+ ) -> Callable[[type], type]:
303
+ """Create a root node architype."""
304
+ raise NotImplementedError
305
+
298
306
  @staticmethod
299
307
  @hookspec(firstresult=True)
300
308
  def make_edge(
@@ -303,6 +311,14 @@ class JacFeatureSpec(
303
311
  """Create a edge architype."""
304
312
  raise NotImplementedError
305
313
 
314
+ @staticmethod
315
+ @hookspec(firstresult=True)
316
+ def make_generic_edge(
317
+ on_entry: list[DSFunc], on_exit: list[DSFunc]
318
+ ) -> Callable[[type], type]:
319
+ """Create a generic edge architype."""
320
+ raise NotImplementedError
321
+
306
322
  @staticmethod
307
323
  @hookspec(firstresult=True)
308
324
  def make_walker(
@@ -1,3 +1,5 @@
1
+ import:py from jaclang.plugin.feature {JacFeature as Jac}
2
+
1
3
  node A {
2
4
  has id: int;
3
5
  }
@@ -1,3 +1,4 @@
1
+ import:py from jaclang.plugin.feature {JacFeature as Jac}
1
2
  import:py from jaclang.runtimelib.architype {Anchor}
2
3
  import:py from uuid {UUID}
3
4
 
@@ -1,3 +1,5 @@
1
+ import:py from jaclang.plugin.feature {JacFeature as Jac}
2
+
1
3
  enum Enum {
2
4
  A = "a",
3
5
  B = "b",
@@ -0,0 +1,17 @@
1
+ node A {}
2
+ node B {}
3
+
4
+ walker build {
5
+ can run with `root entry {
6
+ a = A();
7
+ a ++> B(); # connecting two non persistent nodes
8
+
9
+ here ++> a;
10
+ }
11
+ }
12
+
13
+ walker view {
14
+ can run with `root entry {
15
+ print(dotgen(here));
16
+ }
17
+ }
@@ -748,7 +748,7 @@ class TestJaseciPlugin(TestCase):
748
748
  def test_savable_object(self) -> None:
749
749
  """Test ObjectAnchor save."""
750
750
  global session
751
- session = self.fixture_abs_path("other_root_access.session")
751
+ session = self.fixture_abs_path("savable_object.session")
752
752
 
753
753
  self._output2buffer()
754
754
 
@@ -816,3 +816,36 @@ class TestJaseciPlugin(TestCase):
816
816
  session=session,
817
817
  )
818
818
  self.assertEqual("None", self.capturedOutput.getvalue().strip())
819
+
820
+ def test_traversing_save(self) -> None:
821
+ """Test traversing save."""
822
+ global session
823
+ session = self.fixture_abs_path("traversing_save.session")
824
+
825
+ self._output2buffer()
826
+ cli.enter(
827
+ filename=self.fixture_abs_path("traversing_save.jac"),
828
+ entrypoint="build",
829
+ args=[],
830
+ session=session,
831
+ )
832
+
833
+ cli.enter(
834
+ filename=self.fixture_abs_path("traversing_save.jac"),
835
+ entrypoint="view",
836
+ args=[],
837
+ session=session,
838
+ )
839
+
840
+ self.assertEqual(
841
+ "digraph {\n"
842
+ 'node [style="filled", shape="ellipse", fillcolor="invis", fontcolor="black"];\n'
843
+ '0 -> 1 [label=""];\n'
844
+ '1 -> 2 [label=""];\n'
845
+ '0 [label="Root()"fillcolor="#FFE9E9"];\n'
846
+ '1 [label="A()"fillcolor="#F0FFF0"];\n'
847
+ '2 [label="B()"fillcolor="#F5E5FF"];\n}',
848
+ self.capturedOutput.getvalue().strip(),
849
+ )
850
+
851
+ self._del_session(session)
@@ -12,6 +12,7 @@ from types import UnionType
12
12
  from typing import Any, Callable, ClassVar, Optional, TypeVar
13
13
  from uuid import UUID, uuid4
14
14
 
15
+
15
16
  logger = getLogger(__name__)
16
17
 
17
18
  TARCH = TypeVar("TARCH", bound="Architype")
@@ -285,21 +286,13 @@ class ObjectArchitype(Architype):
285
286
  self.__jac__ = ObjectAnchor(architype=self)
286
287
 
287
288
 
288
- @dataclass(eq=False)
289
289
  class GenericEdge(EdgeArchitype):
290
- """Generic Root Node."""
291
-
292
- _jac_entry_funcs_: ClassVar[list[DSFunc]] = []
293
- _jac_exit_funcs_: ClassVar[list[DSFunc]] = []
290
+ """Generic Edge."""
294
291
 
295
292
 
296
- @dataclass(eq=False)
297
293
  class Root(NodeArchitype):
298
294
  """Generic Root Node."""
299
295
 
300
- _jac_entry_funcs_: ClassVar[list[DSFunc]] = []
301
- _jac_exit_funcs_: ClassVar[list[DSFunc]] = []
302
-
303
296
  def __init__(self) -> None:
304
297
  """Create root node."""
305
298
  self.__jac__ = NodeAnchor(architype=self, persistent=True, edges=[])
@@ -315,16 +308,13 @@ class DSFunc:
315
308
  @cached_property
316
309
  def trigger(self) -> type | UnionType | tuple[type | UnionType, ...] | None:
317
310
  """Get function parameter annotations."""
318
- t = (
319
- (
320
- inspect.signature(self.func, eval_str=True)
321
- .parameters["_jac_here_"]
322
- .annotation
323
- )
324
- if self.func
325
- else None
326
- )
327
- return None if t is inspect._empty else t
311
+ if self.func:
312
+ parameters = inspect.signature(self.func, eval_str=True).parameters
313
+ if len(parameters) >= 2:
314
+ second_param = list(parameters.values())[1]
315
+ ty = second_param.annotation
316
+ return ty if ty != inspect._empty else None
317
+ return None
328
318
 
329
319
  def resolve(self, cls: type) -> None:
330
320
  """Resolve the function."""
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import unittest
6
6
  from contextvars import ContextVar
7
7
  from dataclasses import MISSING
8
- from typing import Any, Callable, Optional, cast
8
+ from typing import Any, Callable, ClassVar, Optional, cast
9
9
  from uuid import UUID
10
10
 
11
11
  from .architype import NodeAnchor, Root
@@ -13,13 +13,7 @@ from .memory import Memory, ShelfStorage
13
13
 
14
14
 
15
15
  EXECUTION_CONTEXT = ContextVar[Optional["ExecutionContext"]]("ExecutionContext")
16
-
17
16
  SUPER_ROOT_UUID = UUID("00000000-0000-0000-0000-000000000000")
18
- SUPER_ROOT_ARCHITYPE = object.__new__(Root)
19
- SUPER_ROOT_ANCHOR = NodeAnchor(
20
- id=SUPER_ROOT_UUID, architype=SUPER_ROOT_ARCHITYPE, persistent=False, edges=[]
21
- )
22
- SUPER_ROOT_ARCHITYPE.__jac__ = SUPER_ROOT_ANCHOR
23
17
 
24
18
 
25
19
  class ExecutionContext:
@@ -32,6 +26,9 @@ class ExecutionContext:
32
26
  root: NodeAnchor
33
27
  entry_node: NodeAnchor
34
28
 
29
+ # A context change event subscription list, those who want to listen ctx change will register here.
30
+ on_ctx_change: ClassVar[list[Callable[[ExecutionContext | None], None]]] = []
31
+
35
32
  def init_anchor(
36
33
  self,
37
34
  anchor_id: str | None,
@@ -52,6 +49,8 @@ class ExecutionContext:
52
49
  """Close current ExecutionContext."""
53
50
  self.mem.close()
54
51
  EXECUTION_CONTEXT.set(None)
52
+ for func in ExecutionContext.on_ctx_change:
53
+ func(EXECUTION_CONTEXT.get(None))
55
54
 
56
55
  @staticmethod
57
56
  def create(
@@ -60,6 +59,8 @@ class ExecutionContext:
60
59
  auto_close: bool = True,
61
60
  ) -> ExecutionContext:
62
61
  """Create ExecutionContext."""
62
+ from jaclang import Root
63
+
63
64
  ctx = ExecutionContext()
64
65
  ctx.mem = ShelfStorage(session)
65
66
  ctx.reports = []
@@ -67,7 +68,7 @@ class ExecutionContext:
67
68
  if not isinstance(
68
69
  system_root := ctx.mem.find_by_id(SUPER_ROOT_UUID), NodeAnchor
69
70
  ):
70
- system_root = Root().__jac__
71
+ system_root = cast(NodeAnchor, Root().__jac__) # type: ignore[attr-defined]
71
72
  system_root.id = SUPER_ROOT_UUID
72
73
  ctx.mem.set(system_root.id, system_root)
73
74
 
@@ -79,6 +80,8 @@ class ExecutionContext:
79
80
  old_ctx.close()
80
81
 
81
82
  EXECUTION_CONTEXT.set(ctx)
83
+ for func in ExecutionContext.on_ctx_change:
84
+ func(EXECUTION_CONTEXT.get(None))
82
85
 
83
86
  return ctx
84
87
 
@@ -95,7 +98,20 @@ class ExecutionContext:
95
98
  if ctx := EXECUTION_CONTEXT.get(None):
96
99
  return cast(Root, ctx.root.architype)
97
100
 
98
- return SUPER_ROOT_ARCHITYPE
101
+ return cast(Root, ExecutionContext.global_system_root().architype)
102
+
103
+ @staticmethod
104
+ def global_system_root() -> NodeAnchor:
105
+ """Get global system root."""
106
+ from jaclang import Root
107
+
108
+ if not (sr_anch := getattr(ExecutionContext, "system_root", None)):
109
+ sr_arch = Root()
110
+ sr_anch = sr_arch.__jac__ # type: ignore[attr-defined]
111
+ sr_anch.id = SUPER_ROOT_UUID
112
+ sr_anch.persistent = False
113
+ ExecutionContext.system_root = sr_anch
114
+ return sr_anch
99
115
 
100
116
 
101
117
  class JacTestResult(unittest.TextTestResult):
jaclang/settings.py CHANGED
@@ -23,6 +23,8 @@ class Settings:
23
23
  disable_mtllm: bool = False
24
24
  ignore_test_annex: bool = False
25
25
  allow_import_from: bool = False
26
+ pyout_jaclib_import_all: bool = True
27
+ pyout_jaclib_alias = "jl"
26
28
 
27
29
  # Formatter configuration
28
30
  max_line_length: int = 88
@@ -0,0 +1,38 @@
1
+ class Apple {
2
+ with entry {
3
+ a = 1;
4
+ }
5
+ }
6
+
7
+ class Orange {
8
+ with entry {
9
+ b = 2;
10
+ }
11
+ }
12
+
13
+ with entry {
14
+ mm = [Apple, Orange];
15
+ }
16
+
17
+ class Banana :mm[1]: {
18
+ with entry {
19
+ c = 3;
20
+ }
21
+ }
22
+
23
+ can return_class() -> `Type[Apple] {
24
+ print('Returning Apple');
25
+ return Apple;
26
+ }
27
+
28
+ class Kiwi :return_class(): {
29
+ with entry {
30
+ d = 4;
31
+ ;
32
+ }
33
+ }
34
+
35
+ with entry {
36
+ a = Kiwi();
37
+ print(Kiwi.d);
38
+ }
@@ -13,7 +13,7 @@ print("Dynamic Node Value:", f'{self.value}');
13
13
  glob walker_code = """
14
14
  walker dynamic_walker {
15
15
  can visit_nodes with entry {
16
- visit [-->](`?dynamic_node);
16
+ visit [-->];
17
17
  }
18
18
  }
19
19
  """;
@@ -0,0 +1,55 @@
1
+ obj mainObject;
2
+
3
+ :obj:mainObject{
4
+ can greet;
5
+ obj subObject;
6
+ }
7
+ can foo{
8
+ obj ObjInsideFunction;
9
+ return ObjInsideFunction();
10
+ }
11
+ :can:foo:obj:ObjInsideFunction{
12
+ can bar{
13
+ print("Hello,from bar in kk");
14
+ }
15
+ }
16
+
17
+ with entry{
18
+ foo().bar();
19
+ }
20
+ :obj:mainObject:can:greet{
21
+ print("Greeting: Hello, World!");
22
+ }
23
+
24
+ :obj:mainObject:obj:subObject{
25
+ can displayMessage;
26
+ can shortMessage{
27
+ print("Hello, World!");
28
+ }
29
+ obj nestedObject;
30
+ }
31
+ :obj:mainObject:obj:subObject:can:displayMessage{
32
+ print("Repeated: Hello!");
33
+ }
34
+
35
+ :obj:mainObject:obj:subObject:obj:nestedObject{
36
+ can lastMessage;
37
+ can finalMessage{
38
+ print("Final message:!");
39
+ }
40
+ }
41
+
42
+ :obj:mainObject:obj:subObject:obj:nestedObject:can:lastMessage{
43
+ # impl mainObject.subObject.nestedObject{ # TODO
44
+ print("Last message:!");
45
+
46
+ }
47
+
48
+
49
+ with entry{
50
+ mainObject().greet();
51
+ mainObject().subObject().displayMessage();
52
+ mainObject().subObject().shortMessage();
53
+ mainObject().subObject().nestedObject().lastMessage();
54
+ mainObject().subObject().nestedObject().finalMessage();
55
+ }
jaclang/tests/test_cli.py CHANGED
@@ -294,6 +294,27 @@ class JacCliTests(TestCase):
294
294
  r"10:7 - 10:12.*Name - start - Type.*SymbolPath: base_class2.B.start",
295
295
  )
296
296
 
297
+ def test_base_class_complex_expr(self) -> None:
298
+ """Testing for print AstTool."""
299
+ from jaclang.settings import settings
300
+
301
+ # settings.ast_symbol_info_detailed = True
302
+ captured_output = io.StringIO()
303
+ sys.stdout = captured_output
304
+
305
+ cli.tool(
306
+ "ir", ["ast", f"{self.fixture_abs_path('base_class_complex_expr.jac')}"]
307
+ )
308
+
309
+ sys.stdout = sys.__stdout__
310
+ stdout_value = captured_output.getvalue()
311
+ settings.ast_symbol_info_detailed = False
312
+
313
+ self.assertRegex(
314
+ stdout_value,
315
+ r"36\:9 \- 36\:13.*Name \- Kiwi \- Type\: base_class_complex_expr.Kiwi, SymbolTable\: Kiwi",
316
+ )
317
+
297
318
  def test_expr_types(self) -> None:
298
319
  """Testing for print AstTool."""
299
320
  captured_output = io.StringIO()