jaclang 0.5.8__py3-none-any.whl → 0.5.9__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.

@@ -1772,6 +1772,7 @@ class JacParser(Pass):
1772
1772
  type_tag = chomp[-1] if isinstance(chomp[-1], ast.SubTag) else None
1773
1773
  if not value:
1774
1774
  semstr = chomp[2] if len(chomp) > 2 else None
1775
+ chomp = chomp[:-2] if semstr else chomp
1775
1776
  else:
1776
1777
  if type_tag:
1777
1778
  chomp = chomp[:-1]
@@ -1782,6 +1783,7 @@ class JacParser(Pass):
1782
1783
  )
1783
1784
  chomp = chomp[:-2] if semstr else chomp
1784
1785
  else:
1786
+ semstr = None
1785
1787
  if (
1786
1788
  isinstance(chomp[1], ast.Token)
1787
1789
  and chomp[1].name != Tok.EQ
@@ -1827,6 +1829,7 @@ class JacParser(Pass):
1827
1829
  value=value,
1828
1830
  mutable=is_frozen,
1829
1831
  kid=kid,
1832
+ semstr=semstr if isinstance(semstr, ast.String) else None,
1830
1833
  )
1831
1834
  )
1832
1835
 
@@ -68,6 +68,24 @@ class Pass(Transform[ast.T]):
68
68
  result.extend(Pass.get_all_sub_nodes(i, typ, brute_force))
69
69
  return result
70
70
 
71
+ @staticmethod
72
+ def has_parent_of_type(node: ast.AstNode, typ: Type[ast.T]) -> Optional[ast.T]:
73
+ """Check if node has parent of type."""
74
+ while node.parent:
75
+ if isinstance(node.parent, typ):
76
+ return node.parent
77
+ node = node.parent
78
+ return None
79
+
80
+ @staticmethod
81
+ def has_parent_of_node(node: ast.AstNode, parent: ast.AstNode) -> bool:
82
+ """Check if node has parent of type."""
83
+ while node.parent:
84
+ if node.parent == parent:
85
+ return True
86
+ node = node.parent
87
+ return False
88
+
71
89
  def recalculate_parents(self, node: ast.AstNode) -> None:
72
90
  """Recalculate parents."""
73
91
  if not node:
@@ -10,6 +10,7 @@ from .pyast_load_pass import PyastBuildPass # type: ignore # noqa: I100
10
10
  from .pyast_gen_pass import PyastGenPass # noqa: I100
11
11
  from .schedules import py_code_gen # noqa: I100
12
12
  from .type_check_pass import JacTypeCheckPass # noqa: I100
13
+ from .registry_pass import RegistryPass # noqa: I100
13
14
 
14
15
 
15
16
  pass_schedule = py_code_gen
@@ -24,4 +25,5 @@ __all__ = [
24
25
  "PyastBuildPass",
25
26
  "PyastGenPass",
26
27
  "JacTypeCheckPass",
28
+ "RegistryPass",
27
29
  ]
@@ -11,6 +11,7 @@ from typing import Optional, Sequence, TypeVar
11
11
  import jaclang.compiler.absyntree as ast
12
12
  from jaclang.compiler.constant import Constants as Con, EdgeDir, Tokens as Tok
13
13
  from jaclang.compiler.passes import Pass
14
+ from jaclang.core.utils import get_sem_scope
14
15
 
15
16
  T = TypeVar("T", bound=ast3.AST)
16
17
 
@@ -208,8 +209,16 @@ class PyastGenPass(Pass):
208
209
  if isinstance(i, ast3.AST):
209
210
  i.lineno = jac_node.loc.first_line
210
211
  i.col_offset = jac_node.loc.col_start
211
- i.end_lineno = jac_node.loc.last_line
212
- i.end_col_offset = jac_node.loc.col_end
212
+ i.end_lineno = (
213
+ jac_node.loc.last_line
214
+ if jac_node.loc.last_line
215
+ else jac_node.loc.first_line
216
+ )
217
+ i.end_col_offset = (
218
+ jac_node.loc.col_end
219
+ if jac_node.loc.col_end
220
+ else jac_node.loc.col_start
221
+ )
213
222
  i.jac_link: list[ast3.AST] = [jac_node] # type: ignore
214
223
  return py_node
215
224
 
@@ -248,14 +257,17 @@ class PyastGenPass(Pass):
248
257
  doc: Optional[ast.String] = None,
249
258
  ) -> list[ast3.AST]:
250
259
  """Unwind codeblock."""
260
+ valid_stmts = (
261
+ [i for i in node.items if not isinstance(i, ast.Semi)] if node else []
262
+ )
251
263
  ret: list[ast3.AST] = (
252
264
  [self.sync(ast3.Pass(), node)]
253
- if isinstance(node, ast.SubNodeList) and not node.items
265
+ if isinstance(node, ast.SubNodeList) and not valid_stmts
254
266
  else (
255
267
  self.flatten(
256
268
  [
257
269
  x.gen.py_ast
258
- for x in node.items
270
+ for x in valid_stmts
259
271
  if not isinstance(x, ast.AstImplOnlyNode)
260
272
  ]
261
273
  )
@@ -926,21 +938,88 @@ class PyastGenPass(Pass):
926
938
  if isinstance(node.body, ast.AbilityDef):
927
939
  self.link_jac_py_nodes(jac_node=node.body, py_nodes=node.gen.py_ast)
928
940
 
941
+ def bfs_collect_type(self, node: ast.AstNode) -> list[str]:
942
+ """Collect type information in assignment using bfs."""
943
+ extracted_type = []
944
+ if isinstance(node, (ast.BuiltinType, ast.Token)):
945
+ extracted_type.append(node.value)
946
+ for child in node.kid:
947
+ extracted_type.extend(self.bfs_collect_type(child))
948
+ return extracted_type
949
+
929
950
  def gen_llm_body(self, node: ast.Ability) -> list[ast3.AST]:
930
951
  """Generate llm body."""
931
952
  if isinstance(node.body, ast.FuncCall):
932
- model_params = (
933
- {
934
- param.key: param.value
935
- for param in node.body.params.items
936
- if isinstance(param, ast.KWPair)
937
- }
938
- if node.body.params
939
- else {}
953
+ model_params = {}
954
+ include_info = []
955
+ exclude_info = []
956
+ if node.body.params:
957
+ for param in node.body.params.items:
958
+ if isinstance(param, ast.KWPair) and isinstance(
959
+ param.key, ast.Name
960
+ ):
961
+ key = param.key.value
962
+ value = param.value
963
+ if key not in ["incl_info", "excl_info"]:
964
+ model_params[key] = value
965
+ elif key == "incl_info":
966
+ if isinstance(value, ast.AtomUnit):
967
+ var_name = (
968
+ value.value.right.value
969
+ if isinstance(value.value, ast.AtomTrailer)
970
+ and isinstance(value.value.right, ast.Name)
971
+ else (
972
+ value.value.value
973
+ if isinstance(value.value, ast.Name)
974
+ else ""
975
+ )
976
+ )
977
+ include_info.append((var_name, value.gen.py_ast[0]))
978
+ elif isinstance(value, ast.TupleVal) and value.values:
979
+ for i in value.values.items:
980
+ var_name = (
981
+ i.right.value
982
+ if isinstance(i, ast.AtomTrailer)
983
+ and isinstance(i.right, ast.Name)
984
+ else (
985
+ i.value if isinstance(i, ast.Name) else ""
986
+ )
987
+ )
988
+ include_info.append((var_name, i.gen.py_ast[0]))
989
+ elif key == "excl_info":
990
+ if isinstance(value, ast.AtomUnit):
991
+ var_name = (
992
+ value.value.right.value
993
+ if isinstance(value.value, ast.AtomTrailer)
994
+ and isinstance(value.value.right, ast.Name)
995
+ else (
996
+ value.value.value
997
+ if isinstance(value.value, ast.Name)
998
+ else ""
999
+ )
1000
+ )
1001
+ exclude_info.append((var_name, value.gen.py_ast[0]))
1002
+ elif isinstance(value, ast.TupleVal) and value.values:
1003
+ for i in value.values.items:
1004
+ var_name = (
1005
+ i.right.value
1006
+ if isinstance(i, ast.AtomTrailer)
1007
+ and isinstance(i.right, ast.Name)
1008
+ else (
1009
+ i.value if isinstance(i, ast.Name) else ""
1010
+ )
1011
+ )
1012
+ exclude_info.append((var_name, i.gen.py_ast[0]))
1013
+ extracted = (
1014
+ "".join(self.bfs_collect_type(node.signature.return_type))
1015
+ if isinstance(node.signature, ast.FuncSignature)
1016
+ and node.signature.return_type
1017
+ else None
940
1018
  )
941
1019
  return [
942
1020
  self.sync(
943
- ast3.Return(
1021
+ ast3.Assign(
1022
+ targets=[self.sync(ast3.Name(id="output", ctx=ast3.Store()))],
944
1023
  value=self.sync(
945
1024
  ast3.Call(
946
1025
  func=self.sync(
@@ -957,6 +1036,16 @@ class PyastGenPass(Pass):
957
1036
  ),
958
1037
  args=[],
959
1038
  keywords=[
1039
+ self.sync(
1040
+ ast3.keyword(
1041
+ arg="file_loc",
1042
+ value=self.sync(
1043
+ ast3.Name(
1044
+ id="__file__", ctx=ast3.Load()
1045
+ )
1046
+ ),
1047
+ )
1048
+ ),
960
1049
  self.sync(
961
1050
  ast3.keyword(
962
1051
  arg="model",
@@ -969,7 +1058,9 @@ class PyastGenPass(Pass):
969
1058
  value=self.sync(
970
1059
  ast3.Dict(
971
1060
  keys=[
972
- self.sync(ast3.Constant(value=key.value)) # type: ignore
1061
+ self.sync(
1062
+ ast3.Constant(value=key)
1063
+ )
973
1064
  for key in model_params.keys()
974
1065
  ],
975
1066
  values=[
@@ -980,21 +1071,69 @@ class PyastGenPass(Pass):
980
1071
  ),
981
1072
  )
982
1073
  ),
1074
+ self.sync(
1075
+ ast3.keyword(
1076
+ arg="scope",
1077
+ value=(
1078
+ self.sync(
1079
+ ast3.Constant(
1080
+ value=str(get_sem_scope(node))
1081
+ )
1082
+ )
1083
+ ),
1084
+ )
1085
+ ),
983
1086
  self.sync(
984
1087
  ast3.keyword(
985
1088
  arg="incl_info",
986
1089
  value=self.sync(
987
- ast3.Constant(value=None)
988
- ), # TODO: Add incl_info
1090
+ ast3.List(
1091
+ elts=[
1092
+ self.sync(
1093
+ ast3.Tuple(
1094
+ elts=[
1095
+ self.sync(
1096
+ ast3.Constant(
1097
+ value=key
1098
+ )
1099
+ ),
1100
+ value,
1101
+ ],
1102
+ ctx=ast3.Load(),
1103
+ )
1104
+ )
1105
+ for key, value in include_info
1106
+ ],
1107
+ ctx=ast3.Load(),
1108
+ )
1109
+ ),
989
1110
  )
990
1111
  ),
991
1112
  self.sync(
992
1113
  ast3.keyword(
993
1114
  arg="excl_info",
994
1115
  value=self.sync(
995
- ast3.Constant(value=None)
996
- ), # TODO: Add excl_info
997
- )
1116
+ ast3.List(
1117
+ elts=[
1118
+ self.sync(
1119
+ ast3.Tuple(
1120
+ elts=[
1121
+ self.sync(
1122
+ ast3.Constant(
1123
+ value=key
1124
+ )
1125
+ ),
1126
+ value,
1127
+ ],
1128
+ ctx=ast3.Load(),
1129
+ )
1130
+ )
1131
+ for key, value in exclude_info
1132
+ ],
1133
+ ctx=ast3.Load(),
1134
+ )
1135
+ ),
1136
+ ),
998
1137
  ),
999
1138
  self.sync(
1000
1139
  ast3.keyword(
@@ -1007,11 +1146,15 @@ class PyastGenPass(Pass):
1007
1146
  ast3.Tuple(
1008
1147
  elts=[
1009
1148
  (
1010
- param.semstr.gen.py_ast[
1011
- 0
1012
- ]
1013
- if param.semstr
1014
- else None
1149
+ self.sync(
1150
+ ast3.Constant(
1151
+ value=(
1152
+ param.semstr.lit_value
1153
+ if param.semstr
1154
+ else None
1155
+ )
1156
+ )
1157
+ )
1015
1158
  ),
1016
1159
  (
1017
1160
  param.type_tag.tag.gen.py_ast[
@@ -1057,11 +1200,15 @@ class PyastGenPass(Pass):
1057
1200
  elts=(
1058
1201
  [
1059
1202
  (
1060
- node.signature.semstr.gen.py_ast[
1061
- 0
1062
- ]
1063
- if node.signature.semstr
1064
- else None
1203
+ self.sync(
1204
+ ast3.Constant(
1205
+ value=(
1206
+ node.signature.semstr.lit_value
1207
+ if node.signature.semstr
1208
+ else None
1209
+ )
1210
+ )
1211
+ )
1065
1212
  ),
1066
1213
  (
1067
1214
  node.signature.return_type.gen.py_ast[
@@ -1070,6 +1217,15 @@ class PyastGenPass(Pass):
1070
1217
  if node.signature.return_type
1071
1218
  else None
1072
1219
  ),
1220
+ (
1221
+ self.sync(
1222
+ ast3.Constant(
1223
+ value=(
1224
+ extracted
1225
+ )
1226
+ )
1227
+ )
1228
+ ),
1073
1229
  ]
1074
1230
  if isinstance(
1075
1231
  node.signature,
@@ -1081,7 +1237,7 @@ class PyastGenPass(Pass):
1081
1237
  )
1082
1238
  ),
1083
1239
  )
1084
- ), # TODO: Add Meaning Types of Outputs
1240
+ ),
1085
1241
  self.sync(
1086
1242
  ast3.keyword(
1087
1243
  arg="action",
@@ -1094,9 +1250,55 @@ class PyastGenPass(Pass):
1094
1250
  ),
1095
1251
  ],
1096
1252
  )
1097
- )
1253
+ ),
1098
1254
  )
1099
- )
1255
+ ),
1256
+ self.sync(
1257
+ ast3.Try(
1258
+ body=[
1259
+ self.sync(
1260
+ ast3.Return(
1261
+ value=self.sync(
1262
+ ast3.Call(
1263
+ func=self.sync(
1264
+ ast3.Name(id="eval", ctx=ast3.Load())
1265
+ ),
1266
+ args=[
1267
+ self.sync(
1268
+ ast3.Name(
1269
+ id="output", ctx=ast3.Load()
1270
+ )
1271
+ )
1272
+ ],
1273
+ keywords=[],
1274
+ )
1275
+ )
1276
+ )
1277
+ )
1278
+ ],
1279
+ handlers=[
1280
+ self.sync(
1281
+ ast3.ExceptHandler(
1282
+ type=None,
1283
+ name=None,
1284
+ body=[
1285
+ self.sync(
1286
+ ast3.Return(
1287
+ value=self.sync(
1288
+ ast3.Name(
1289
+ id="output", ctx=ast3.Load()
1290
+ )
1291
+ )
1292
+ )
1293
+ )
1294
+ ],
1295
+ )
1296
+ )
1297
+ ],
1298
+ orelse=[],
1299
+ finalbody=[],
1300
+ )
1301
+ ),
1100
1302
  ]
1101
1303
  else:
1102
1304
  return []
@@ -1939,7 +2141,7 @@ class PyastGenPass(Pass):
1939
2141
  )
1940
2142
  )
1941
2143
  if node.is_enum_stmt
1942
- else self.ice()
2144
+ else None if node.type_tag else self.ice()
1943
2145
  )
1944
2146
  )
1945
2147
  if node.type_tag:
@@ -2269,7 +2471,10 @@ class PyastGenPass(Pass):
2269
2471
  elif node.op.name in [Tok.STAR_MUL]:
2270
2472
  node.gen.py_ast = [
2271
2473
  self.sync(
2272
- ast3.Starred(value=node.operand.gen.py_ast[0], ctx=ast3.Load())
2474
+ ast3.Starred(
2475
+ value=node.operand.gen.py_ast[0],
2476
+ ctx=ast3.Load(),
2477
+ )
2273
2478
  )
2274
2479
  ]
2275
2480
  elif node.op.name in [Tok.STAR_POW]:
@@ -0,0 +1,126 @@
1
+ """Jac Registry Pass.
2
+
3
+ This pass is responsible for creating object containing the senstring, scope,
4
+ type of different important nodes in the AST as we loose access to the
5
+ semstrings after PyASTGen pass. So we create those as a pickled file for
6
+ each module
7
+ """
8
+
9
+ import os
10
+ import pickle
11
+
12
+ import jaclang.compiler.absyntree as ast
13
+ from jaclang.compiler.constant import Constants as Con
14
+ from jaclang.compiler.passes import Pass
15
+ from jaclang.core.registry import SemInfo, SemRegistry
16
+ from jaclang.core.utils import get_sem_scope
17
+
18
+
19
+ class RegistryPass(Pass):
20
+ """Creates a registry for each module."""
21
+
22
+ modules_visited: list[ast.Module] = []
23
+
24
+ def enter_module(self, node: ast.Module) -> None:
25
+ """Create registry for each module."""
26
+ node.registry = SemRegistry()
27
+ self.modules_visited.append(node)
28
+
29
+ def exit_module(self, node: ast.Module) -> None:
30
+ """Save registry for each module."""
31
+ module_dir = os.path.join(
32
+ os.path.abspath(os.path.dirname(node.source.file_path)), Con.JAC_GEN_DIR
33
+ )
34
+ module_name = node.name
35
+ os.makedirs(module_dir, exist_ok=True)
36
+ with open(os.path.join(module_dir, f"{module_name}.registry.pkl"), "wb") as f:
37
+ pickle.dump(node.registry, f)
38
+ self.modules_visited.pop()
39
+
40
+ def exit_architype(self, node: ast.Architype) -> None:
41
+ """Save architype information."""
42
+ scope = get_sem_scope(node)
43
+ seminfo = SemInfo(
44
+ node.name.value,
45
+ node.arch_type.value,
46
+ node.semstr.lit_value if node.semstr else None,
47
+ )
48
+ if (
49
+ len(self.modules_visited)
50
+ and self.modules_visited[-1].registry
51
+ and scope.parent
52
+ ):
53
+ self.modules_visited[-1].registry.add(scope.parent, seminfo)
54
+
55
+ def exit_enum(self, node: ast.Enum) -> None:
56
+ """Save enum information."""
57
+ scope = get_sem_scope(node)
58
+ seminfo = SemInfo(
59
+ node.name.value, "Enum", node.semstr.lit_value if node.semstr else None
60
+ )
61
+ if (
62
+ len(self.modules_visited)
63
+ and self.modules_visited[-1].registry
64
+ and scope.parent
65
+ ):
66
+ self.modules_visited[-1].registry.add(scope.parent, seminfo)
67
+
68
+ def exit_has_var(self, node: ast.HasVar) -> None:
69
+ """Save variable information."""
70
+ extracted_type = (
71
+ "".join(self.extract_type(node.type_tag.kid[1:][0]))
72
+ if node.type_tag
73
+ else None
74
+ )
75
+ scope = get_sem_scope(node)
76
+ seminfo = SemInfo(
77
+ node.name.value,
78
+ extracted_type,
79
+ node.semstr.lit_value if node.semstr else None,
80
+ )
81
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
82
+ self.modules_visited[-1].registry.add(scope, seminfo)
83
+
84
+ def exit_assignment(self, node: ast.Assignment) -> None:
85
+ """Save assignment information."""
86
+ if node.aug_op:
87
+ return
88
+
89
+ extracted_type = (
90
+ "".join(self.extract_type(node.type_tag.kid[1:][0]))
91
+ if node.type_tag
92
+ else None
93
+ )
94
+ scope = get_sem_scope(node)
95
+ seminfo = SemInfo(
96
+ (
97
+ node.target.items[0].value
98
+ if isinstance(node.target.items[0], ast.Name)
99
+ else ""
100
+ ),
101
+ extracted_type,
102
+ node.semstr.lit_value if node.semstr else None,
103
+ )
104
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
105
+ self.modules_visited[-1].registry.add(scope, seminfo)
106
+
107
+ def exit_name(self, node: ast.Name) -> None:
108
+ """Save name information. for enum stmts."""
109
+ if (
110
+ node.parent
111
+ and node.parent.parent
112
+ and node.parent.parent.__class__.__name__ == "Enum"
113
+ ):
114
+ scope = get_sem_scope(node)
115
+ seminfo = SemInfo(node.value, None, None)
116
+ if len(self.modules_visited) and self.modules_visited[-1].registry:
117
+ self.modules_visited[-1].registry.add(scope, seminfo)
118
+
119
+ def extract_type(self, node: ast.AstNode) -> list[str]:
120
+ """Collect type information in assignment using bfs."""
121
+ extracted_type = []
122
+ if isinstance(node, (ast.BuiltinType, ast.Token)):
123
+ extracted_type.append(node.value)
124
+ for child in node.kid:
125
+ extracted_type.extend(self.extract_type(child))
126
+ return extracted_type
@@ -16,6 +16,7 @@ from .pybc_gen_pass import PyBytecodeGenPass # noqa: I100
16
16
  from .pyast_gen_pass import PyastGenPass # noqa: I100
17
17
  from .type_check_pass import JacTypeCheckPass # noqa: I100
18
18
  from .fuse_typeinfo_pass import FuseTypeInfoPass # noqa: I100
19
+ from .registry_pass import RegistryPass # noqa: I100
19
20
 
20
21
  py_code_gen = [
21
22
  SubNodeTabPass,
@@ -23,6 +24,7 @@ py_code_gen = [
23
24
  SymTabBuildPass,
24
25
  DeclDefMatchPass,
25
26
  DefUsePass,
27
+ RegistryPass,
26
28
  PyastGenPass,
27
29
  PyBytecodeGenPass,
28
30
  ]
@@ -0,0 +1,39 @@
1
+ """Test registry pass."""
2
+
3
+ import os
4
+
5
+ from jaclang.compiler.compile import jac_file_to_pass
6
+ from jaclang.compiler.passes.main import RegistryPass
7
+ from jaclang.utils.test import TestCase
8
+
9
+
10
+ class RegistryPassTests(TestCase):
11
+ """Test pass module."""
12
+
13
+ def setUp(self) -> None:
14
+ """Set up test."""
15
+ return super().setUp()
16
+
17
+ def test_registry_pass(self) -> None:
18
+ """Basic test for pass."""
19
+ state = jac_file_to_pass(self.fixture_abs_path("registry.jac"), RegistryPass)
20
+ self.assertFalse(state.errors_had)
21
+ self.assertTrue(
22
+ os.path.exists(
23
+ os.path.join(
24
+ os.path.dirname(self.fixture_abs_path("registry.jac")),
25
+ "__jac_gen__",
26
+ "registry.registry.pkl",
27
+ )
28
+ )
29
+ )
30
+ self.assertTrue(
31
+ os.path.exists(
32
+ os.path.join(
33
+ os.path.dirname(self.fixture_abs_path("registry.jac")),
34
+ "__jac_gen__",
35
+ "fstrings.registry.pkl",
36
+ )
37
+ )
38
+ )
39
+ self.assertIn("109", str(state.ir.to_dict()))