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.
- jaclang/cli/cli.py +58 -0
- jaclang/compiler/__init__.py +53 -0
- jaclang/compiler/absyntree.py +218 -174
- jaclang/compiler/parser.py +3 -0
- jaclang/compiler/passes/ir_pass.py +18 -0
- jaclang/compiler/passes/main/__init__.py +2 -0
- jaclang/compiler/passes/main/pyast_gen_pass.py +239 -34
- jaclang/compiler/passes/main/registry_pass.py +126 -0
- jaclang/compiler/passes/main/schedules.py +2 -0
- jaclang/compiler/passes/main/tests/test_registry_pass.py +39 -0
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +28 -6
- jaclang/core/aott.py +193 -28
- jaclang/core/construct.py +7 -2
- jaclang/core/registry.py +115 -0
- jaclang/core/utils.py +25 -0
- jaclang/plugin/default.py +57 -13
- jaclang/plugin/feature.py +6 -2
- jaclang/plugin/spec.py +4 -2
- jaclang/utils/helpers.py +41 -3
- jaclang/utils/lang_tools.py +2 -37
- {jaclang-0.5.8.dist-info → jaclang-0.5.9.dist-info}/METADATA +1 -1
- {jaclang-0.5.8.dist-info → jaclang-0.5.9.dist-info}/RECORD +25 -24
- jaclang/compiler/__jac_gen__/__init__.py +0 -0
- jaclang/compiler/__jac_gen__/jac_parser.py +0 -4069
- {jaclang-0.5.8.dist-info → jaclang-0.5.9.dist-info}/WHEEL +0 -0
- {jaclang-0.5.8.dist-info → jaclang-0.5.9.dist-info}/entry_points.txt +0 -0
- {jaclang-0.5.8.dist-info → jaclang-0.5.9.dist-info}/top_level.txt +0 -0
jaclang/compiler/parser.py
CHANGED
|
@@ -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 =
|
|
212
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
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.
|
|
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(
|
|
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.
|
|
988
|
-
|
|
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.
|
|
996
|
-
|
|
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
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
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
|
-
),
|
|
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(
|
|
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()))
|