jaclang 0.5.18__py3-none-any.whl → 0.6.1__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 (57) hide show
  1. jaclang/cli/cli.py +94 -5
  2. jaclang/cli/cmdreg.py +18 -6
  3. jaclang/compiler/__init__.py +12 -5
  4. jaclang/compiler/absyntree.py +4 -5
  5. jaclang/compiler/generated/jac_parser.py +2 -2
  6. jaclang/compiler/jac.lark +2 -2
  7. jaclang/compiler/parser.py +48 -8
  8. jaclang/compiler/passes/main/__init__.py +3 -2
  9. jaclang/compiler/passes/main/access_modifier_pass.py +173 -0
  10. jaclang/compiler/passes/main/def_impl_match_pass.py +4 -1
  11. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +10 -7
  12. jaclang/compiler/passes/main/import_pass.py +70 -40
  13. jaclang/compiler/passes/main/pyast_gen_pass.py +47 -83
  14. jaclang/compiler/passes/main/pyast_load_pass.py +136 -73
  15. jaclang/compiler/passes/main/pyjac_ast_link_pass.py +218 -0
  16. jaclang/compiler/passes/main/pyout_pass.py +14 -13
  17. jaclang/compiler/passes/main/registry_pass.py +8 -3
  18. jaclang/compiler/passes/main/schedules.py +7 -3
  19. jaclang/compiler/passes/main/sym_tab_build_pass.py +32 -29
  20. jaclang/compiler/passes/main/tests/test_import_pass.py +13 -2
  21. jaclang/compiler/passes/tool/jac_formatter_pass.py +83 -21
  22. jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +11 -4
  23. jaclang/compiler/passes/transform.py +2 -0
  24. jaclang/compiler/symtable.py +10 -3
  25. jaclang/compiler/tests/test_importer.py +9 -0
  26. jaclang/compiler/workspace.py +17 -5
  27. jaclang/core/aott.py +43 -63
  28. jaclang/core/construct.py +157 -21
  29. jaclang/core/importer.py +77 -65
  30. jaclang/core/llms/__init__.py +20 -0
  31. jaclang/core/llms/anthropic.py +61 -0
  32. jaclang/core/llms/base.py +206 -0
  33. jaclang/core/llms/groq.py +67 -0
  34. jaclang/core/llms/huggingface.py +73 -0
  35. jaclang/core/llms/ollama.py +78 -0
  36. jaclang/core/llms/openai.py +61 -0
  37. jaclang/core/llms/togetherai.py +60 -0
  38. jaclang/core/llms/utils.py +9 -0
  39. jaclang/core/memory.py +48 -0
  40. jaclang/core/shelve_storage.py +55 -0
  41. jaclang/core/utils.py +16 -1
  42. jaclang/plugin/__init__.py +1 -2
  43. jaclang/plugin/builtin.py +1 -1
  44. jaclang/plugin/default.py +134 -18
  45. jaclang/plugin/feature.py +35 -13
  46. jaclang/plugin/spec.py +52 -10
  47. jaclang/plugin/tests/test_jaseci.py +219 -0
  48. jaclang/settings.py +1 -1
  49. jaclang/utils/helpers.py +6 -2
  50. jaclang/utils/treeprinter.py +14 -6
  51. jaclang-0.6.1.dist-info/METADATA +17 -0
  52. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/RECORD +55 -42
  53. jaclang/core/llms.py +0 -111
  54. jaclang-0.5.18.dist-info/METADATA +0 -7
  55. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/WHEEL +0 -0
  56. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/entry_points.txt +0 -0
  57. {jaclang-0.5.18.dist-info → jaclang-0.6.1.dist-info}/top_level.txt +0 -0
jaclang/compiler/jac.lark CHANGED
@@ -195,8 +195,8 @@ list_inner_pattern: (pattern_seq | STAR_MUL NAME)
195
195
  dict_inner_pattern: (literal_pattern COLON pattern_seq | STAR_POW NAME)
196
196
 
197
197
  // Match class patterns
198
- class_pattern: NAME LPAREN kw_pattern_list? RPAREN
199
- | NAME LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN
198
+ class_pattern: NAME (DOT NAME)* LPAREN kw_pattern_list? RPAREN
199
+ | NAME (DOT NAME)* LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN
200
200
 
201
201
  pattern_list: (pattern_list COMMA)? pattern_seq
202
202
  kw_pattern_list: (kw_pattern_list COMMA)? named_ref EQ pattern_seq
@@ -140,7 +140,7 @@ class JacParser(Pass):
140
140
  body = kid[1:] if doc else kid
141
141
  body = [i for i in body if isinstance(i, ast.ElementStmt)]
142
142
  mod = ast.Module(
143
- name=self.parse_ref.mod_path.split(os.path.sep)[-1].split(".")[0],
143
+ name=self.parse_ref.mod_path.split(os.path.sep)[-1].rstrip(".jac"),
144
144
  source=self.parse_ref.source,
145
145
  doc=doc,
146
146
  body=body,
@@ -3739,12 +3739,43 @@ class JacParser(Pass):
3739
3739
  def class_pattern(self, kid: list[ast.AstNode]) -> ast.MatchArch:
3740
3740
  """Grammar rule.
3741
3741
 
3742
- class_pattern: NAME LPAREN kw_pattern_list? RPAREN
3743
- | NAME LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN
3742
+ class_pattern: NAME (DOT NAME)* LPAREN kw_pattern_list? RPAREN
3743
+ | NAME (DOT NAME)* LPAREN pattern_list (COMMA kw_pattern_list)? RPAREN
3744
3744
  """
3745
- name = kid[0]
3746
- first = kid[2]
3747
- second = kid[4] if len(kid) > 4 else None
3745
+ chomp = [*kid]
3746
+ cur_element = chomp[0]
3747
+ chomp = chomp[1:]
3748
+ while not (isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.LPAREN):
3749
+ if isinstance(chomp[0], ast.Token) and chomp[0].name == Tok.DOT:
3750
+ target_ = cur_element
3751
+ right_ = chomp[1]
3752
+ if isinstance(right_, (ast.Expr, ast.AtomExpr)) and isinstance(
3753
+ target_, ast.Expr
3754
+ ):
3755
+ cur_element = ast.AtomTrailer(
3756
+ target=target_,
3757
+ right=right_,
3758
+ is_attr=True,
3759
+ is_null_ok=False,
3760
+ kid=[target_, chomp[0], right_],
3761
+ )
3762
+ chomp = chomp[2:]
3763
+ else:
3764
+ raise self.ice()
3765
+ elif isinstance(cur_element, ast.NameSpec):
3766
+ chomp = chomp[1:]
3767
+ else:
3768
+ break
3769
+ name = cur_element
3770
+ lparen = chomp[0]
3771
+ rapren = chomp[-1]
3772
+ first = chomp[1]
3773
+ if len(chomp) > 4:
3774
+ second = chomp[3]
3775
+ comma = chomp[2]
3776
+ else:
3777
+ second = None
3778
+ comma = None
3748
3779
  arg = (
3749
3780
  first
3750
3781
  if isinstance(first, ast.SubNodeList)
@@ -3762,13 +3793,22 @@ class JacParser(Pass):
3762
3793
  else None
3763
3794
  )
3764
3795
  )
3765
- if isinstance(name, ast.NameSpec):
3796
+ if isinstance(name, (ast.NameSpec, ast.AtomTrailer)):
3797
+ kid_nodes = [name, lparen]
3798
+ if arg:
3799
+ kid_nodes.append(arg)
3800
+ if kw:
3801
+ kid_nodes.extend([comma, kw]) if comma else kid_nodes.append(kw)
3802
+ elif kw:
3803
+ kid_nodes.append(kw)
3804
+ kid_nodes.append(rapren)
3805
+
3766
3806
  return self.nu(
3767
3807
  ast.MatchArch(
3768
3808
  name=name,
3769
3809
  arg_patterns=arg,
3770
3810
  kw_patterns=kw,
3771
- kid=kid,
3811
+ kid=kid_nodes,
3772
3812
  )
3773
3813
  )
3774
3814
  else:
@@ -1,7 +1,7 @@
1
1
  """Collection of passes for Jac IR."""
2
2
 
3
3
  from .sub_node_tab_pass import SubNodeTabPass
4
- from .import_pass import ImportPass # noqa: I100
4
+ from .import_pass import JacImportPass, PyImportPass # noqa: I100
5
5
  from .sym_tab_build_pass import SymTabBuildPass # noqa: I100
6
6
  from .def_impl_match_pass import DeclDefMatchPass # noqa: I100
7
7
  from .def_use_pass import DefUsePass # noqa: I100
@@ -17,7 +17,8 @@ pass_schedule = py_code_gen
17
17
 
18
18
  __all__ = [
19
19
  "SubNodeTabPass",
20
- "ImportPass",
20
+ "JacImportPass",
21
+ "PyImportPass",
21
22
  "SymTabBuildPass",
22
23
  "DeclDefMatchPass",
23
24
  "DefUsePass",
@@ -0,0 +1,173 @@
1
+ """Access check pass for the Jac compiler.
2
+
3
+ This pass checks for access to attributes in the Jac language.
4
+ """
5
+
6
+ import os
7
+ from typing import Optional
8
+
9
+ import jaclang.compiler.absyntree as ast
10
+ from jaclang.compiler.passes.main.sym_tab_build_pass import SymTabPass, SymbolAccess
11
+
12
+
13
+ class AccessCheckPass(SymTabPass):
14
+ """Jac Ast Access Check pass."""
15
+
16
+ def after_pass(self) -> None:
17
+ """After pass."""
18
+ pass
19
+
20
+ def access_check(self, node: ast.Name) -> None:
21
+ """Access check."""
22
+ node_info = (
23
+ node.sym_tab.lookup(node.sym_name)
24
+ if isinstance(node.sym_tab, ast.SymbolTable)
25
+ else None
26
+ )
27
+
28
+ if node.sym_link:
29
+ decl_package_path = os.path.dirname(
30
+ os.path.abspath(node.sym_link.defn[-1].loc.mod_path)
31
+ )
32
+ use_package_path = os.path.dirname(os.path.abspath(node.loc.mod_path))
33
+ else:
34
+ decl_package_path = use_package_path = ""
35
+
36
+ if (
37
+ node_info
38
+ and node.sym_link
39
+ and node_info.access == SymbolAccess.PROTECTED
40
+ and decl_package_path != use_package_path
41
+ ):
42
+ return self.error(
43
+ f'Can not access protected variable "{node.sym_name}" from {decl_package_path}'
44
+ f" to {use_package_path}."
45
+ )
46
+
47
+ if (
48
+ node_info
49
+ and node.sym_link
50
+ and node_info.access == SymbolAccess.PRIVATE
51
+ and node.sym_link.defn[-1].loc.mod_path != node.loc.mod_path
52
+ ):
53
+ return self.error(
54
+ f'Can not access private variable "{node.sym_name}" from {node.sym_link.defn[-1].loc.mod_path}'
55
+ f" to {node.loc.mod_path}."
56
+ )
57
+
58
+ def access_register(
59
+ self, node: ast.AstSymbolNode, acc_tag: Optional[SymbolAccess] = None
60
+ ) -> None:
61
+ """Access register."""
62
+ node.sym_info.acc_tag = acc_tag
63
+
64
+ def enter_global_vars(self, node: ast.GlobalVars) -> None:
65
+ """Sub objects.
66
+
67
+ access: Optional[SubTag[Token]],
68
+ assignments: SubNodeList[Assignment],
69
+ is_frozen: bool,
70
+ """
71
+ pass
72
+
73
+ def enter_module(self, node: ast.Module) -> None:
74
+ """Sub objects.
75
+
76
+ name: str,
77
+ doc: Token,
78
+ body: Optional['Elements'],
79
+ mod_path: str,
80
+ is_imported: bool,
81
+ """
82
+
83
+ def enter_architype(self, node: ast.Architype) -> None:
84
+ """Sub objects.
85
+
86
+ name: Name,
87
+ arch_type: Token,
88
+ access: Optional[SubTag[Token]],
89
+ base_classes: Optional[SubNodeList[Expr]],
90
+ body: Optional[SubNodeList[ArchBlockStmt] | ArchDef],
91
+ decorators: Optional[SubNodeList[Expr]] = None,
92
+ """
93
+ pass
94
+
95
+ def enter_enum(self, node: ast.Enum) -> None:
96
+ """Sub objects.
97
+
98
+ name: Name,
99
+ access: Optional[SubTag[Token]],
100
+ base_classes: Optional[SubNodeList[Expr]],
101
+ body: Optional[SubNodeList[EnumBlockStmt] | EnumDef],
102
+ decorators: Optional[SubNodeList[Expr]] = None,
103
+ """
104
+ pass
105
+
106
+ def enter_ability(self, node: ast.Ability) -> None:
107
+ """Sub objects.
108
+
109
+ name_ref: NameSpec,
110
+ is_func: bool,
111
+ is_async: bool,
112
+ is_override: bool,
113
+ is_static: bool,
114
+ is_abstract: bool,
115
+ access: Optional[SubTag[Token]],
116
+ signature: Optional[FuncSignature | EventSignature],
117
+ body: Optional[SubNodeList[CodeBlockStmt] | AbilityDef],
118
+ decorators: Optional[SubNodeList[Expr]] = None,
119
+ """
120
+ pass
121
+
122
+ def enter_sub_node_list(self, node: ast.SubNodeList) -> None:
123
+ """Sub objects.
124
+
125
+ items: list[T]
126
+ """
127
+
128
+ def enter_arch_has(self, node: ast.ArchHas) -> None:
129
+ """Sub objects.
130
+
131
+ is_static: bool,
132
+ access: Optional[SubTag[Token]],
133
+ vars: SubNodeList[HasVar],
134
+ is_frozen: bool,
135
+ """
136
+ pass
137
+
138
+ def enter_atom_trailer(self, node: ast.AtomTrailer) -> None:
139
+ """Sub objects.
140
+
141
+ access: Optional[SubTag[Token]],
142
+ """
143
+ pass
144
+
145
+ def enter_func_call(self, node: ast.FuncCall) -> None:
146
+ """Sub objects.
147
+
148
+ target: Expr,
149
+ params: Optional[SubNodeList[Expr | KWPair]],
150
+ genai_call: Optional[FuncCall],
151
+ kid: Sequence[AstNode],
152
+ """
153
+ pass
154
+
155
+ def enter_name(self, node: ast.Name) -> None:
156
+ """Sub objects.
157
+
158
+ name: str,
159
+ value: str,
160
+ col_start: int,
161
+ col_end: int,
162
+ pos_start: int,
163
+ pos_end: int,
164
+ """
165
+ from jaclang.compiler.passes import Pass
166
+
167
+ if isinstance(node.parent, ast.FuncCall):
168
+ self.access_check(node)
169
+
170
+ if node.sym_link and Pass.has_parent_of_type(
171
+ node=node.sym_link.defn[-1], typ=ast.GlobalVars
172
+ ):
173
+ self.access_check(node)
@@ -72,7 +72,10 @@ class DeclDefMatchPass(Pass):
72
72
  continue
73
73
  decl_node.body = sym.decl # type: ignore
74
74
  sym.decl.decl_link = decl_node # type: ignore
75
- decl_node.add_kids_right([sym.decl], pos_update=False) # type: ignore
75
+ source_node = sym.decl.parent
76
+ decl_node.add_kids_right([sym.decl]) # type: ignore
77
+ if source_node and sym.decl in source_node.kid:
78
+ source_node.kid.remove(sym.decl)
76
79
  decl_node.sym_tab.tab = sym.decl.sym_tab.tab # type: ignore
77
80
  for i in sym_tab.kid:
78
81
  self.connect_def_impl(i)
@@ -48,8 +48,16 @@ class FuseTypeInfoPass(Pass):
48
48
  def __set_sym_table_link(self, node: ast.AstSymbolNode) -> None:
49
49
  typ = node.sym_info.typ.split(".")
50
50
  typ_sym_table = self.ir.sym_tab
51
- if typ_sym_table and typ[0] == typ_sym_table.name:
52
- for i in typ[1:]:
51
+
52
+ if typ[0] == "builtins":
53
+ return
54
+
55
+ assert isinstance(self.ir, ast.Module)
56
+
57
+ if typ_sym_table:
58
+ for i in typ:
59
+ if i == self.ir.name:
60
+ continue
53
61
  f = typ_sym_table.find_scope(i)
54
62
  if f:
55
63
  typ_sym_table = f
@@ -159,11 +167,6 @@ class FuseTypeInfoPass(Pass):
159
167
  type(mypy_node),
160
168
  )
161
169
 
162
- def enter_import(self, node: ast.Import) -> None:
163
- """Pass handler for import nodes."""
164
- # Pruning the import nodes
165
- self.prune()
166
-
167
170
  @__handle_node
168
171
  def enter_name(self, node: ast.NameSpec) -> None:
169
172
  """Pass handler for name nodes."""
@@ -7,8 +7,8 @@ symbols are available for matching.
7
7
 
8
8
  import ast as py_ast
9
9
  import importlib.util
10
+ import os
10
11
  import sys
11
- from os import path
12
12
  from typing import Optional
13
13
 
14
14
 
@@ -19,8 +19,8 @@ from jaclang.settings import settings
19
19
  from jaclang.utils.helpers import import_target_to_relative_path
20
20
 
21
21
 
22
- class ImportPass(Pass):
23
- """Jac statically imports all modules."""
22
+ class JacImportPass(Pass):
23
+ """Jac statically imports Jac modules."""
24
24
 
25
25
  def before_pass(self) -> None:
26
26
  """Run once before pass."""
@@ -29,6 +29,7 @@ class ImportPass(Pass):
29
29
  def enter_module(self, node: ast.Module) -> None:
30
30
  """Run Importer."""
31
31
  self.cur_node = node
32
+ self.import_table[node.loc.mod_path] = node
32
33
  self.annex_impl(node)
33
34
  self.terminate() # Turns off auto traversal for deliberate traversal
34
35
  self.run_again = True
@@ -36,48 +37,63 @@ class ImportPass(Pass):
36
37
  self.run_again = False
37
38
  all_imports = self.get_all_sub_nodes(node, ast.ModulePath)
38
39
  for i in all_imports:
39
- lang = i.parent_of_type(ast.Import).hint.tag.value
40
- if lang == "jac" and not i.sub_module:
41
- self.run_again = True
42
- mod = self.import_module(
43
- node=i,
44
- mod_path=node.loc.mod_path,
45
- )
46
- if not mod:
47
- self.run_again = False
48
- continue
49
- self.annex_impl(mod)
50
- i.sub_module = mod
51
- i.add_kids_right([mod], pos_update=False)
52
- elif lang == "py" and settings.jac_proc_debug:
53
- mod = self.import_py_module(node=i, mod_path=node.loc.mod_path)
54
- i.sub_module = mod
55
- i.add_kids_right([mod], pos_update=False)
40
+ self.process_import(node, i)
56
41
  self.enter_module_path(i)
57
42
  SubNodeTabPass(prior=self, input_ir=node)
58
- self.annex_impl(node)
59
43
  node.mod_deps = self.import_table
60
44
 
45
+ def process_import(self, node: ast.Module, i: ast.ModulePath) -> None:
46
+ """Process an import."""
47
+ lang = i.parent_of_type(ast.Import).hint.tag.value
48
+ if lang == "jac" and not i.sub_module:
49
+ mod = self.import_module(
50
+ node=i,
51
+ mod_path=node.loc.mod_path,
52
+ )
53
+ if mod:
54
+ self.run_again = True
55
+ i.sub_module = mod
56
+ i.add_kids_right([mod], pos_update=False)
57
+
61
58
  def annex_impl(self, node: ast.Module) -> None:
62
59
  """Annex impl and test modules."""
63
60
  if not node.loc.mod_path:
64
61
  self.error("Module has no path")
65
- if node.loc.mod_path.endswith(".jac") and path.exists(
66
- f"{node.loc.mod_path[:-4]}.impl.jac"
67
- ):
68
- mod = self.import_mod_from_file(f"{node.loc.mod_path[:-4]}.impl.jac")
69
- if mod:
70
- node.impl_mod = mod
71
- node.add_kids_left([mod], pos_update=False)
72
- mod.parent = node
73
- if node.loc.mod_path.endswith(".jac") and path.exists(
74
- f"{node.loc.mod_path[:-4]}.test.jac"
75
- ):
76
- mod = self.import_mod_from_file(f"{node.loc.mod_path[:-4]}.test.jac")
77
- if mod:
78
- node.test_mod = mod
79
- node.add_kids_right([mod], pos_update=False)
80
- mod.parent = node
62
+ if not node.loc.mod_path.endswith(".jac"):
63
+ return
64
+ base_path = node.loc.mod_path[:-4]
65
+ directory = os.path.dirname(node.loc.mod_path)
66
+ if not directory:
67
+ directory = os.getcwd()
68
+ base_path = os.path.join(directory, base_path)
69
+ impl_folder = base_path + ".impl"
70
+ search_files = [
71
+ os.path.join(directory, impl_file) for impl_file in os.listdir(directory)
72
+ ]
73
+ if os.path.exists(impl_folder):
74
+ search_files += [
75
+ os.path.join(impl_folder, impl_file)
76
+ for impl_file in os.listdir(impl_folder)
77
+ ]
78
+ for impl_file in search_files:
79
+ if node.loc.mod_path.endswith(impl_file):
80
+ continue
81
+ if (
82
+ impl_file.startswith(f"{base_path}.") or impl_folder in impl_file
83
+ ) and impl_file.endswith(".impl.jac"):
84
+ mod = self.import_mod_from_file(impl_file)
85
+ if mod:
86
+ node.impl_mod.append(mod)
87
+ node.add_kids_left([mod], pos_update=False)
88
+ mod.parent = node
89
+ if (
90
+ impl_file.startswith(f"{base_path}.") or impl_folder in impl_file
91
+ ) and impl_file.endswith(".test.jac"):
92
+ mod = self.import_mod_from_file(impl_file)
93
+ if mod:
94
+ node.test_mod = mod
95
+ node.add_kids_right([mod], pos_update=False)
96
+ mod.parent = node
81
97
 
82
98
  def enter_module_path(self, node: ast.ModulePath) -> None:
83
99
  """Sub objects.
@@ -97,7 +113,7 @@ class ImportPass(Pass):
97
113
  """Import a module."""
98
114
  self.cur_node = node # impacts error reporting
99
115
  target = import_target_to_relative_path(
100
- node.level, node.path_str, path.dirname(node.loc.mod_path)
116
+ node.level, node.path_str, os.path.dirname(node.loc.mod_path)
101
117
  )
102
118
  return self.import_mod_from_file(target)
103
119
 
@@ -106,7 +122,7 @@ class ImportPass(Pass):
106
122
  from jaclang.compiler.compile import jac_file_to_pass
107
123
  from jaclang.compiler.passes.main import SubNodeTabPass
108
124
 
109
- if not path.exists(target):
125
+ if not os.path.exists(target):
110
126
  self.error(f"Could not find module {target}")
111
127
  return None
112
128
  if target in self.import_table:
@@ -134,7 +150,7 @@ class ImportPass(Pass):
134
150
  """Import a module."""
135
151
  from jaclang.compiler.passes.main import PyastBuildPass
136
152
 
137
- base_dir = path.dirname(mod_path)
153
+ base_dir = os.path.dirname(mod_path)
138
154
  sys.path.append(base_dir)
139
155
 
140
156
  try:
@@ -165,3 +181,17 @@ class ImportPass(Pass):
165
181
  )
166
182
  raise e
167
183
  return None
184
+
185
+
186
+ class PyImportPass(JacImportPass):
187
+ """Jac statically imports Python modules."""
188
+
189
+ def process_import(self, node: ast.Module, i: ast.ModulePath) -> None:
190
+ """Process an import."""
191
+ lang = i.parent_of_type(ast.Import).hint.tag.value
192
+ if lang == "py" and not i.sub_module and settings.py_raise:
193
+ mod = self.import_py_module(node=i, mod_path=node.loc.mod_path)
194
+ if mod:
195
+ # self.run_again = True
196
+ i.sub_module = mod
197
+ i.add_kids_right([mod], pos_update=False)