jaclang 0.7.25__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 (32) hide show
  1. jaclang/compiler/absyntree.py +27 -18
  2. jaclang/compiler/jac.lark +4 -1
  3. jaclang/compiler/parser.py +37 -20
  4. jaclang/compiler/passes/main/def_impl_match_pass.py +50 -13
  5. jaclang/compiler/passes/main/def_use_pass.py +1 -2
  6. jaclang/compiler/passes/main/pyast_gen_pass.py +46 -20
  7. jaclang/compiler/passes/main/pyast_load_pass.py +20 -6
  8. jaclang/compiler/passes/main/sym_tab_build_pass.py +1 -2
  9. jaclang/compiler/passes/main/tests/fixtures/uninitialized_hasvars.jac +26 -0
  10. jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +36 -29
  11. jaclang/compiler/passes/main/tests/test_def_use_pass.py +3 -3
  12. jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -2
  13. jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +3 -3
  14. jaclang/compiler/passes/tool/tests/fixtures/corelib_fmt.jac +3 -3
  15. jaclang/compiler/tests/test_parser.py +7 -1
  16. jaclang/plugin/default.py +48 -11
  17. jaclang/plugin/feature.py +10 -0
  18. jaclang/plugin/spec.py +12 -0
  19. jaclang/plugin/tests/fixtures/graph_purger.jac +101 -0
  20. jaclang/plugin/tests/fixtures/other_root_access.jac +9 -0
  21. jaclang/plugin/tests/test_jaseci.py +126 -6
  22. jaclang/runtimelib/architype.py +12 -1
  23. jaclang/runtimelib/memory.py +5 -1
  24. jaclang/tests/fixtures/architype_def_bug.jac +17 -0
  25. jaclang/tests/fixtures/decl_defn_param_name.jac +19 -0
  26. jaclang/tests/fixtures/multi_dim_array_split.jac +19 -0
  27. jaclang/tests/test_cli.py +18 -0
  28. jaclang/tests/test_language.py +44 -0
  29. {jaclang-0.7.25.dist-info → jaclang-0.7.26.dist-info}/METADATA +1 -1
  30. {jaclang-0.7.25.dist-info → jaclang-0.7.26.dist-info}/RECORD +32 -27
  31. {jaclang-0.7.25.dist-info → jaclang-0.7.26.dist-info}/WHEEL +0 -0
  32. {jaclang-0.7.25.dist-info → jaclang-0.7.26.dist-info}/entry_points.txt +0 -0
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import ast as ast3
6
6
  import builtins
7
7
  import os
8
+ from dataclasses import dataclass
8
9
  from hashlib import md5
9
10
  from types import EllipsisType
10
11
  from typing import (
@@ -3401,18 +3402,22 @@ class FuncCall(Expr):
3401
3402
  class IndexSlice(AtomExpr):
3402
3403
  """IndexSlice node type for Jac Ast."""
3403
3404
 
3405
+ @dataclass
3406
+ class Slice:
3407
+ """Slice node for index slice."""
3408
+
3409
+ start: Optional[Expr]
3410
+ stop: Optional[Expr]
3411
+ step: Optional[Expr]
3412
+
3404
3413
  def __init__(
3405
3414
  self,
3406
- start: Optional[Expr],
3407
- stop: Optional[Expr],
3408
- step: Optional[Expr],
3415
+ slices: list[Slice],
3409
3416
  is_range: bool,
3410
3417
  kid: Sequence[AstNode],
3411
3418
  ) -> None:
3412
3419
  """Initialize index slice expression node."""
3413
- self.start = start
3414
- self.stop = stop
3415
- self.step = step
3420
+ self.slices = slices
3416
3421
  self.is_range = is_range
3417
3422
  AstNode.__init__(self, kid=kid)
3418
3423
  Expr.__init__(self)
@@ -3422,22 +3427,26 @@ class IndexSlice(AtomExpr):
3422
3427
  """Normalize ast node."""
3423
3428
  res = True
3424
3429
  if deep:
3425
- res = self.start.normalize(deep) if self.start else res
3426
- res = res and self.stop.normalize(deep) if self.stop else res
3427
- res = res and self.step.normalize(deep) if self.step else res
3430
+ for slice in self.slices:
3431
+ res = slice.start.normalize(deep) if slice.start else res
3432
+ res = res and slice.stop.normalize(deep) if slice.stop else res
3433
+ res = res and slice.step.normalize(deep) if slice.step else res
3428
3434
  new_kid: list[AstNode] = []
3429
3435
  new_kid.append(self.gen_token(Tok.LSQUARE))
3430
3436
  if self.is_range:
3431
- if self.start:
3432
- new_kid.append(self.start)
3433
- if self.stop:
3437
+ for i, slice in enumerate(self.slices):
3438
+ if i > 0:
3439
+ new_kid.append(self.gen_token(Tok.COMMA))
3440
+ if slice.start:
3441
+ new_kid.append(slice.start)
3434
3442
  new_kid.append(self.gen_token(Tok.COLON))
3435
- new_kid.append(self.stop)
3436
- if self.step:
3437
- new_kid.append(self.gen_token(Tok.COLON))
3438
- new_kid.append(self.step)
3439
- elif self.start:
3440
- new_kid.append(self.start)
3443
+ if slice.stop:
3444
+ new_kid.append(slice.stop)
3445
+ if slice.step:
3446
+ new_kid.append(self.gen_token(Tok.COLON))
3447
+ new_kid.append(slice.step)
3448
+ elif len(self.slices) == 1 and self.slices[0].start:
3449
+ new_kid.append(self.slices[0].start)
3441
3450
  else:
3442
3451
  res = False
3443
3452
  new_kid.append(self.gen_token(Tok.RSQUARE))
jaclang/compiler/jac.lark CHANGED
@@ -358,7 +358,10 @@ atomic_chain: atomic_chain NULL_OK? (filter_compr | assign_compr | index_slice)
358
358
  | atomic_chain NULL_OK? (DOT_BKWD | DOT_FWD | DOT) named_ref
359
359
  | (atomic_call | atom | edge_ref_chain)
360
360
 
361
- index_slice: LSQUARE expression? COLON expression? (COLON expression?)? RSQUARE
361
+ index_slice: LSQUARE \
362
+ expression? COLON expression? (COLON expression?)? \
363
+ (COMMA expression? COLON expression? (COLON expression?)?)* \
364
+ RSQUARE
362
365
  | list_val
363
366
 
364
367
  // Function calls
@@ -2436,8 +2436,11 @@ class JacParser(Pass):
2436
2436
  def index_slice(self, kid: list[ast.AstNode]) -> ast.IndexSlice:
2437
2437
  """Grammar rule.
2438
2438
 
2439
- index_slice: LSQUARE expression? COLON expression? (COLON expression?)? RSQUARE
2440
- | list_val
2439
+ index_slice: LSQUARE \
2440
+ expression? COLON expression? (COLON expression?)? \
2441
+ (COMMA expression? COLON expression? (COLON expression?)?)* \
2442
+ RSQUARE
2443
+ | list_val
2441
2444
  """
2442
2445
  if len(kid) == 1:
2443
2446
  index = kid[0]
@@ -2454,9 +2457,9 @@ class JacParser(Pass):
2454
2457
  kid = [expr]
2455
2458
  return self.nu(
2456
2459
  ast.IndexSlice(
2457
- start=expr,
2458
- stop=None,
2459
- step=None,
2460
+ slices=[
2461
+ ast.IndexSlice.Slice(start=expr, stop=None, step=None)
2462
+ ],
2460
2463
  is_range=False,
2461
2464
  kid=kid,
2462
2465
  )
@@ -2464,25 +2467,39 @@ class JacParser(Pass):
2464
2467
  else:
2465
2468
  raise self.ice()
2466
2469
  else:
2467
- expr1 = expr2 = expr3 = None
2470
+ slices: list[ast.IndexSlice.Slice] = []
2468
2471
  chomp = kid[1:]
2469
- if isinstance(chomp[0], ast.Expr):
2470
- expr1 = chomp[0]
2471
- chomp = chomp[1:]
2472
- chomp = chomp[1:]
2473
- if isinstance(chomp[0], ast.Expr):
2474
- expr2 = chomp[0]
2475
- chomp = chomp[1:]
2476
- if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COLON:
2477
- chomp = chomp[1:]
2472
+
2473
+ while not (
2474
+ isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.RSQUARE
2475
+ ):
2476
+ expr1 = expr2 = expr3 = None
2477
+
2478
2478
  if isinstance(chomp[0], ast.Expr):
2479
- expr3 = chomp[0]
2480
- chomp = chomp[1:]
2479
+ expr1 = chomp[0]
2480
+ chomp.pop(0)
2481
+ chomp.pop(0)
2482
+
2483
+ if isinstance(chomp[0], ast.Expr):
2484
+ expr2 = chomp[0]
2485
+ chomp.pop(0)
2486
+
2487
+ if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COLON:
2488
+ chomp.pop(0)
2489
+ if isinstance(chomp[0], ast.Expr):
2490
+ expr3 = chomp[0]
2491
+ chomp.pop(0)
2492
+
2493
+ if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.COMMA:
2494
+ chomp.pop(0)
2495
+
2496
+ slices.append(
2497
+ ast.IndexSlice.Slice(start=expr1, stop=expr2, step=expr3)
2498
+ )
2499
+
2481
2500
  return self.nu(
2482
2501
  ast.IndexSlice(
2483
- start=expr1,
2484
- stop=expr2,
2485
- step=expr3,
2502
+ slices=slices,
2486
2503
  is_range=True,
2487
2504
  kid=kid,
2488
2505
  )
@@ -7,6 +7,7 @@ body field.
7
7
  """
8
8
 
9
9
  import jaclang.compiler.absyntree as ast
10
+ from jaclang.compiler.constant import Tokens as Tok
10
11
  from jaclang.compiler.passes import Pass
11
12
  from jaclang.compiler.passes.main import SubNodeTabPass
12
13
  from jaclang.compiler.symtable import Symbol, SymbolTable
@@ -129,19 +130,55 @@ class DeclImplMatchPass(Pass):
129
130
  valid_decl.name_spec,
130
131
  )
131
132
  else:
133
+ # Copy the parameter names from the declaration to the definition.
132
134
  for idx in range(len(params_defn.items)):
133
- # Check if all the parameter names are matched.
134
- # TODO: This shouldn't be an issue however if the names are not matched, it doesn't
135
- # work as expected like in C++, for now I'm adding this validation, however this
136
- # needs to be fixed to have a C++ style.
137
- param_name_decl = params_decl.items[idx].name.value
138
- param_name_defn = params_defn.items[idx].name.value
139
- if param_name_defn != param_name_decl:
140
- self.error(
141
- f"Parameter name mismatch for ability {sym.sym_name}.",
142
- params_defn.items[idx].name,
143
- )
135
+ params_decl.items[idx] = params_defn.items[idx]
136
+ for idx in range(len(params_defn.kid)):
137
+ params_decl.kid[idx] = params_defn.kid[idx]
138
+
139
+ def exit_architype(self, node: ast.Architype) -> None:
140
+ """Exit Architype."""
141
+ if node.arch_type.name == Tok.KW_OBJECT and isinstance(
142
+ node.body, ast.SubNodeList
143
+ ):
144
+
145
+ found_default_init = False
146
+ for stmnt in node.body.items:
147
+ if not isinstance(stmnt, ast.ArchHas):
148
+ continue
149
+ for var in stmnt.vars.items:
150
+ if (var.value is not None) or (var.defer):
151
+ found_default_init = True
152
+ else:
153
+ if found_default_init:
144
154
  self.error(
145
- f"From the declaration of {valid_decl.name_spec.sym_name}.",
146
- params_decl.items[idx].name,
155
+ f"Non default attribute '{var.name.value}' follows default attribute",
156
+ node_override=var.name,
147
157
  )
158
+ break
159
+
160
+ post_init_vars: list[ast.HasVar] = []
161
+ postinit_method: ast.Ability | None = None
162
+
163
+ for item in node.body.items:
164
+
165
+ if isinstance(item, ast.ArchHas):
166
+ for var in item.vars.items:
167
+ if var.defer:
168
+ post_init_vars.append(var)
169
+
170
+ elif isinstance(item, ast.Ability):
171
+ if item.is_abstract:
172
+ continue
173
+ if (
174
+ isinstance(item.name_ref, ast.SpecialVarRef)
175
+ and item.name_ref.name == "KW_POST_INIT"
176
+ ):
177
+ postinit_method = item
178
+
179
+ # Check if postinit needed and not provided.
180
+ if len(post_init_vars) != 0 and (postinit_method is None):
181
+ self.error(
182
+ 'Missing "postinit" method required by un initialized attribute(s).',
183
+ node_override=post_init_vars[0].name_spec,
184
+ ) # We show the error on the first uninitialized var.
@@ -156,8 +156,7 @@ class DefUsePass(Pass):
156
156
  def enter_index_slice(self, node: ast.IndexSlice) -> None:
157
157
  """Sub objects.
158
158
 
159
- start: Optional[ExprType],
160
- stop: Optional[ExprType],
159
+ slices: list[Slice],
161
160
  is_range: bool,
162
161
  """
163
162
 
@@ -1055,14 +1055,7 @@ class PyastGenPass(Pass):
1055
1055
  ctx=ast3.Load(),
1056
1056
  )
1057
1057
  ),
1058
- args=[
1059
- self.sync(ast3.Constant(value=i.sym_name)),
1060
- (
1061
- i.signature.arch_tag_info.gen.py_ast[0]
1062
- if i.signature.arch_tag_info
1063
- else self.sync(ast3.Constant(value=None))
1064
- ),
1065
- ],
1058
+ args=[self.sync(ast3.Constant(value=i.sym_name))],
1066
1059
  keywords=[],
1067
1060
  )
1068
1061
  )
@@ -3081,23 +3074,56 @@ class PyastGenPass(Pass):
3081
3074
  def exit_index_slice(self, node: ast.IndexSlice) -> None:
3082
3075
  """Sub objects.
3083
3076
 
3084
- start: Optional[ExprType],
3085
- stop: Optional[ExprType],
3086
- step: Optional[ExprType],
3077
+ slices: list[IndexSlice.Slice],
3087
3078
  is_range: bool,
3088
3079
  """
3089
3080
  if node.is_range:
3090
- node.gen.py_ast = [
3091
- self.sync(
3092
- ast3.Slice(
3093
- lower=node.start.gen.py_ast[0] if node.start else None,
3094
- upper=node.stop.gen.py_ast[0] if node.stop else None,
3095
- step=node.step.gen.py_ast[0] if node.step else None,
3081
+ if len(node.slices) > 1: # Multiple slices. Example arr[a:b, c:d]
3082
+ node.gen.py_ast = [
3083
+ self.sync(
3084
+ ast3.Tuple(
3085
+ elts=[
3086
+ self.sync(
3087
+ ast3.Slice(
3088
+ lower=(
3089
+ slice.start.gen.py_ast[0]
3090
+ if slice.start
3091
+ else None
3092
+ ),
3093
+ upper=(
3094
+ slice.stop.gen.py_ast[0]
3095
+ if slice.stop
3096
+ else None
3097
+ ),
3098
+ step=(
3099
+ slice.step.gen.py_ast[0]
3100
+ if slice.step
3101
+ else None
3102
+ ),
3103
+ )
3104
+ )
3105
+ for slice in node.slices
3106
+ ],
3107
+ ctx=ast3.Load(),
3108
+ )
3096
3109
  )
3097
- )
3098
- ]
3110
+ ]
3111
+ elif len(node.slices) == 1: # Single slice. Example arr[a]
3112
+ slice = node.slices[0]
3113
+ node.gen.py_ast = [
3114
+ self.sync(
3115
+ ast3.Slice(
3116
+ lower=slice.start.gen.py_ast[0] if slice.start else None,
3117
+ upper=slice.stop.gen.py_ast[0] if slice.stop else None,
3118
+ step=slice.step.gen.py_ast[0] if slice.step else None,
3119
+ )
3120
+ )
3121
+ ]
3099
3122
  else:
3100
- node.gen.py_ast = node.start.gen.py_ast if node.start else []
3123
+ if len(node.slices) > 0 and node.slices[0].start is not None:
3124
+ node.gen.py_ast = node.slices[0].start.gen.py_ast
3125
+ else:
3126
+ node.gen.py_ast = []
3101
3127
 
3102
3128
  def exit_special_var_ref(self, node: ast.SpecialVarRef) -> None:
3103
3129
  """Sub objects.
@@ -2026,9 +2026,7 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2026
2026
  and (isinstance(step, ast.Expr) or step is None)
2027
2027
  ):
2028
2028
  return ast.IndexSlice(
2029
- start=lower,
2030
- stop=upper,
2031
- step=step,
2029
+ slices=[ast.IndexSlice.Slice(lower, upper, step)],
2032
2030
  is_range=True,
2033
2031
  kid=valid_kid,
2034
2032
  )
@@ -2061,12 +2059,28 @@ class PyastBuildPass(Pass[ast.PythonModuleAst]):
2061
2059
  slice = self.convert(node.slice)
2062
2060
  if not isinstance(slice, ast.IndexSlice) and isinstance(slice, ast.Expr):
2063
2061
  slice = ast.IndexSlice(
2064
- start=slice,
2065
- stop=None,
2066
- step=None,
2062
+ slices=[ast.IndexSlice.Slice(slice, None, None)],
2067
2063
  is_range=False,
2068
2064
  kid=[slice],
2069
2065
  )
2066
+ if (
2067
+ not isinstance(slice, ast.IndexSlice)
2068
+ and isinstance(slice, ast.TupleVal)
2069
+ and slice.values is not None
2070
+ ):
2071
+
2072
+ slices: list[ast.IndexSlice.Slice] = []
2073
+ for index_slice in slice.values.items:
2074
+ if not isinstance(index_slice, ast.IndexSlice):
2075
+ raise self.ice()
2076
+ slices.append(index_slice.slices[0])
2077
+
2078
+ slice = ast.IndexSlice(
2079
+ slices=slices,
2080
+ is_range=True,
2081
+ kid=[slice],
2082
+ )
2083
+
2070
2084
  if isinstance(value, ast.Expr) and isinstance(slice, ast.IndexSlice):
2071
2085
  return ast.AtomTrailer(
2072
2086
  target=value,
@@ -995,8 +995,7 @@ class SymTabBuildPass(Pass):
995
995
  def enter_index_slice(self, node: ast.IndexSlice) -> None:
996
996
  """Sub objects.
997
997
 
998
- start: Optional[ExprType],
999
- stop: Optional[ExprType],
998
+ slices: list[Slice],
1000
999
  is_range: bool,
1001
1000
  """
1002
1001
  self.sync_node_to_scope(node)
@@ -0,0 +1,26 @@
1
+
2
+ # 1. Test initialization order.
3
+ obj Test1 {
4
+ has var1: int;
5
+ has var2: int = 42;
6
+ has var3: int; # <-- This should be syntax error.
7
+ }
8
+
9
+
10
+ # 2. Test if postinit is needed but not provided.
11
+ obj Test2 {
12
+ has var1: str;
13
+ has var2: int by postinit;
14
+ }
15
+
16
+ # 3. Postinit should be considered as has default initialization.
17
+ obj Test3 {
18
+ has var1: int;
19
+ has var2: int = 42;
20
+ has var3: int by postinit; # <-- This is fine.
21
+ has var4: int; # <-- This should be syntax error.
22
+
23
+ can postinit() {
24
+ self.var3 = 3;
25
+ }
26
+ }
@@ -43,35 +43,6 @@ class DeclImplMatchPassTests(TestCase):
43
43
  for exp in expected_stdout_values:
44
44
  self.assertIn(exp, errors_output)
45
45
 
46
- def test_parameter_name_mismatch(self) -> None:
47
- """Basic test for pass."""
48
- state = jac_file_to_pass(
49
- self.fixture_abs_path("defn_decl_mismatch.jac"), DeclImplMatchPass
50
- )
51
-
52
- expected_stdout_values = (
53
- "Parameter name mismatch for ability (o)SomeObj.(c)bar.",
54
- " 14 |",
55
- " 15 | # Mis matching parameter name.",
56
- " 16 | :obj:SomeObj:can:bar(param1: str, praam2:int) -> str {",
57
- " | ^^^^^^",
58
- ' 17 | return "bar";',
59
- " 18 | }",
60
- "From the declaration of bar.",
61
- " 3 | obj SomeObj {",
62
- " 4 | can foo(param1: str, param2:int) -> str;",
63
- " 5 | can bar(param1: str, param2:int) -> str;",
64
- " | ^^^^^^",
65
- " 6 | }",
66
- )
67
-
68
- errors_output = ""
69
- for error in state.errors_had:
70
- errors_output += error.pretty_print() + "\n"
71
-
72
- for exp in expected_stdout_values:
73
- self.assertIn(exp, errors_output)
74
-
75
46
  def test_ability_connected_to_decl(self) -> None:
76
47
  """Basic test for pass."""
77
48
  state = jac_file_to_pass(self.fixture_abs_path("base.jac"), DeclImplMatchPass)
@@ -105,3 +76,39 @@ class DeclImplMatchPassTests(TestCase):
105
76
  )
106
77
  for i in state.ir.get_all_sub_nodes(ast.ArchRef):
107
78
  self.assertIsNotNone(i.sym)
79
+
80
+ def test_obj_hasvar_initialization(self) -> None:
81
+ """Basic test for pass."""
82
+ state = jac_file_to_pass(
83
+ self.fixture_abs_path("uninitialized_hasvars.jac"), DeclImplMatchPass
84
+ )
85
+ self.assertTrue(state.errors_had)
86
+
87
+ expected_stdout_values = (
88
+ "Non default attribute 'var3' follows default attribute",
89
+ " 4 | has var1: int;",
90
+ " 5 | has var2: int = 42;",
91
+ " 6 | has var3: int; # <-- This should be syntax error.",
92
+ " | ^^^^",
93
+ " 7 | }",
94
+ 'Missing "postinit" method required by un initialized attribute(s).',
95
+ " 11 | obj Test2 {",
96
+ " 12 | has var1: str;",
97
+ " 13 | has var2: int by postinit;",
98
+ " | ^^^^",
99
+ " 14 | }",
100
+ "Non default attribute 'var4' follows default attribute",
101
+ " 19 | has var2: int = 42;",
102
+ " 20 | has var3: int by postinit; # <-- This is fine.",
103
+ " 21 | has var4: int; # <-- This should be syntax error.",
104
+ " | ^^^^",
105
+ " 22 |",
106
+ " 23 | can postinit() {",
107
+ )
108
+
109
+ errors_output = ""
110
+ for error in state.errors_had:
111
+ errors_output += error.pretty_print() + "\n"
112
+
113
+ for exp in expected_stdout_values:
114
+ self.assertIn(exp, errors_output)
@@ -19,7 +19,7 @@ class DefUsePassTests(TestCase):
19
19
  target=DefUsePass,
20
20
  )
21
21
  uses = [i.uses for i in state.ir.sym_tab.kid[0].tab.values()]
22
+ self.assertEqual(len(uses[0]), 1)
22
23
  self.assertEqual(len(uses[1]), 1)
23
- self.assertEqual(len(uses[2]), 1)
24
- self.assertIn("output", [uses[1][0].sym_name, uses[2][0].sym_name])
25
- self.assertIn("message", [uses[1][0].sym_name, uses[2][0].sym_name])
24
+ self.assertIn("output", [uses[0][0].sym_name, uses[1][0].sym_name])
25
+ self.assertIn("message", [uses[0][0].sym_name, uses[1][0].sym_name])
@@ -1640,8 +1640,8 @@ class JacFormatPass(Pass):
1640
1640
  def exit_index_slice(self, node: ast.IndexSlice) -> None:
1641
1641
  """Sub objects.
1642
1642
 
1643
- start: ExprType,
1644
- stop: Optional[ExprType],
1643
+ slices: list[Slice],
1644
+ is_range: bool,
1645
1645
  """
1646
1646
  for i in node.kid:
1647
1647
  self.emit(node, i.gen.jac)
@@ -34,6 +34,8 @@ glob exec_ctx = ExecutionContext();
34
34
 
35
35
  obj Anchor :ArchitypeProtocol: {
36
36
  has ob: object,
37
+ ds_entry_funcs: list[DSFunc],
38
+ ds_exit_funcs: list[DSFunc],
37
39
  jid: UUID = :> uuid4,
38
40
  timestamp: datetime = :> datetime.now,
39
41
  persist: bool = False,
@@ -41,9 +43,7 @@ obj Anchor :ArchitypeProtocol: {
41
43
  rw_access: set = :> set,
42
44
  ro_access: set = :> set,
43
45
  owner_id: UUID = exec_ctx.master,
44
- mem: Memory = exec_ctx.memory,
45
- ds_entry_funcs: list[DSFunc],
46
- ds_exit_funcs: list[DSFunc];
46
+ mem: Memory = exec_ctx.memory;
47
47
 
48
48
  static can on_entry(cls: type, triggers: list[type]);
49
49
  static can on_exit(cls: type, triggers: list[type]);
@@ -33,6 +33,8 @@ glob exec_ctx = ExecutionContext();
33
33
 
34
34
  obj Anchor :ArchitypeProtocol: {
35
35
  has ob: object,
36
+ ds_entry_funcs: list[DSFunc],
37
+ ds_exit_funcs: list[DSFunc],
36
38
  jid: UUID = :> uuid4,
37
39
  timestamp: datetime = :> datetime.now,
38
40
  persist: bool = False,
@@ -40,9 +42,7 @@ obj Anchor :ArchitypeProtocol: {
40
42
  rw_access: set = :> set,
41
43
  ro_access: set = :> set,
42
44
  owner_id: UUID = exec_ctx.master,
43
- mem: Memory = exec_ctx.memory,
44
- ds_entry_funcs: list[DSFunc],
45
- ds_exit_funcs: list[DSFunc];
45
+ mem: Memory = exec_ctx.memory;
46
46
 
47
47
  static can on_entry(cls: type, triggers: list[type]);
48
48
  static can on_exit(cls: type, triggers: list[type]);
@@ -1,6 +1,7 @@
1
1
  """Tests for Jac parser."""
2
2
 
3
3
  import inspect
4
+ import os
4
5
 
5
6
  from jaclang.compiler import jac_lark as jl
6
7
  from jaclang.compiler.absyntree import JacSource
@@ -27,7 +28,12 @@ class TestLarkParser(TestCaseMicroSuite):
27
28
  prse = JacParser(
28
29
  input_ir=JacSource(self.file_to_str(filename), mod_path=filename),
29
30
  )
30
- self.assertFalse(prse.errors_had)
31
+ # A list of files where the errors are expected.
32
+ files_expected_errors = [
33
+ "uninitialized_hasvars.jac",
34
+ ]
35
+ if os.path.basename(filename) not in files_expected_errors:
36
+ self.assertFalse(prse.errors_had)
31
37
 
32
38
  def test_parser_fam(self) -> None:
33
39
  """Parse micro jac file."""