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
|
@@ -25,19 +25,41 @@ class JacUnparseTests(TestCaseMicroSuite, AstSyncTestMixin):
|
|
|
25
25
|
schedule=without_format,
|
|
26
26
|
)
|
|
27
27
|
before = ast3.dump(code_gen_pure.ir.gen.py_ast[0], indent=2)
|
|
28
|
+
x = code_gen_pure.ir.unparse()
|
|
29
|
+
# print(x)
|
|
30
|
+
# print(f"Testing {code_gen_pure.ir.name}")
|
|
31
|
+
# print(code_gen_pure.ir.pp())
|
|
28
32
|
code_gen_jac = jac_str_to_pass(
|
|
29
|
-
jac_str=
|
|
33
|
+
jac_str=x,
|
|
30
34
|
file_path=filename,
|
|
31
35
|
target=PyastGenPass,
|
|
32
36
|
schedule=without_format,
|
|
33
37
|
)
|
|
34
38
|
after = ast3.dump(code_gen_jac.ir.gen.py_ast[0], indent=2)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if "circle_clean_tests.jac" in filename:
|
|
40
|
+
self.assertEqual(
|
|
41
|
+
len(
|
|
42
|
+
[
|
|
43
|
+
i
|
|
44
|
+
for i in unified_diff(
|
|
45
|
+
before.splitlines(), after.splitlines(), n=0
|
|
46
|
+
)
|
|
47
|
+
if "test" not in i
|
|
48
|
+
]
|
|
49
|
+
),
|
|
50
|
+
5,
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
self.assertEqual(
|
|
54
|
+
len(
|
|
55
|
+
"\n".join(unified_diff(before.splitlines(), after.splitlines()))
|
|
56
|
+
),
|
|
57
|
+
0,
|
|
58
|
+
)
|
|
59
|
+
|
|
39
60
|
except Exception as e:
|
|
40
|
-
|
|
61
|
+
raise e
|
|
62
|
+
# self.skipTest(f"Test failed, but skipping instead of failing: {e}")
|
|
41
63
|
|
|
42
64
|
|
|
43
65
|
JacUnparseTests.self_attach_micro_tests()
|
jaclang/core/aott.py
CHANGED
|
@@ -4,65 +4,230 @@ AOTT: Automated Operational Type Transformation.
|
|
|
4
4
|
This has all the necessary functions to perform the AOTT operations.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import re
|
|
8
|
+
from enum import Enum
|
|
7
9
|
from typing import Any
|
|
8
10
|
|
|
11
|
+
from jaclang.core.registry import SemInfo, SemRegistry, SemScope
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
|
|
14
|
+
PROMPT_TEMPLATE = """
|
|
11
15
|
[System Prompt]
|
|
12
|
-
This is an operation you must perform and return the output values. Neither, the methodology,
|
|
13
|
-
|
|
16
|
+
This is an operation you must perform and return the output values. Neither, the methodology, extra sentences nor the code are not needed.
|
|
17
|
+
Input/Type formatting: Explanation of the Input (variable_name) (type) = value
|
|
14
18
|
|
|
15
19
|
[Information]
|
|
16
|
-
{
|
|
20
|
+
{information}
|
|
17
21
|
|
|
18
|
-
[Inputs
|
|
19
|
-
{
|
|
22
|
+
[Inputs Information]
|
|
23
|
+
{inputs_information}
|
|
20
24
|
|
|
21
|
-
[Output
|
|
22
|
-
{
|
|
25
|
+
[Output Information]
|
|
26
|
+
{output_information}
|
|
23
27
|
|
|
24
|
-
[
|
|
25
|
-
{
|
|
28
|
+
[Type Explanations]
|
|
29
|
+
{type_explanations}
|
|
26
30
|
|
|
27
31
|
[Action]
|
|
28
32
|
{action}
|
|
29
33
|
|
|
30
34
|
{reason_suffix}
|
|
31
|
-
"""
|
|
35
|
+
""" # noqa E501
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
WITH_REASON_SUFFIX = """
|
|
34
38
|
Reason and return the output result(s) only, adhering to the provided Type in the following format
|
|
35
39
|
|
|
36
40
|
[Reasoning] <Reason>
|
|
37
41
|
[Output] <Result>
|
|
38
42
|
"""
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
following format
|
|
44
|
+
WITHOUT_REASON_SUFFIX = """Generate and return the output result(s) only, adhering to the provided Type in the following format
|
|
42
45
|
|
|
43
46
|
[Output] <result>
|
|
44
|
-
"""
|
|
47
|
+
""" # noqa E501
|
|
45
48
|
|
|
46
49
|
|
|
47
50
|
def aott_raise(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
information: str,
|
|
52
|
+
inputs_information: str,
|
|
53
|
+
output_information: str,
|
|
54
|
+
type_explanations: str,
|
|
52
55
|
action: str,
|
|
53
56
|
reason: bool,
|
|
54
57
|
) -> str:
|
|
55
58
|
"""AOTT Raise uses the information (Meanings types values) provided to generate a prompt(meaning in)."""
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
return PROMPT_TEMPLATE.format(
|
|
60
|
+
information=information,
|
|
61
|
+
inputs_information=inputs_information,
|
|
62
|
+
output_information=output_information,
|
|
63
|
+
type_explanations=type_explanations,
|
|
61
64
|
action=action,
|
|
62
|
-
reason_suffix=
|
|
65
|
+
reason_suffix=WITH_REASON_SUFFIX if reason else WITHOUT_REASON_SUFFIX,
|
|
63
66
|
)
|
|
64
67
|
|
|
65
68
|
|
|
66
|
-
def
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
+
def get_reasoning_output(s: str) -> tuple:
|
|
70
|
+
"""Get the reasoning and output from the meaning out string."""
|
|
71
|
+
reasoning_match = re.search(r"\[Reasoning\](.*)\[Output\]", s)
|
|
72
|
+
output_match = re.search(r"\[Output\](.*)", s)
|
|
73
|
+
|
|
74
|
+
if reasoning_match and output_match:
|
|
75
|
+
reasoning = reasoning_match.group(1)
|
|
76
|
+
output = output_match.group(1)
|
|
77
|
+
return (reasoning.strip(), output.strip())
|
|
78
|
+
elif output_match:
|
|
79
|
+
output = output_match.group(1)
|
|
80
|
+
return (None, output.strip())
|
|
81
|
+
else:
|
|
82
|
+
return (None, None)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def get_info_types(
|
|
86
|
+
scope: SemScope, mod_registry: SemRegistry, incl_info: list[tuple[str, str]]
|
|
87
|
+
) -> tuple[str, list[str]]:
|
|
88
|
+
"""Filter the registry data based on the scope and return the info string."""
|
|
89
|
+
collected_types = []
|
|
90
|
+
avail_scopes = []
|
|
91
|
+
while True:
|
|
92
|
+
avail_scopes.append(str(scope))
|
|
93
|
+
if not scope.parent:
|
|
94
|
+
break
|
|
95
|
+
scope = scope.parent
|
|
96
|
+
|
|
97
|
+
filtered_registry = SemRegistry()
|
|
98
|
+
for _scope, sem_info_list in mod_registry.registry.items():
|
|
99
|
+
if str(_scope) in avail_scopes:
|
|
100
|
+
filtered_registry.registry[_scope] = sem_info_list
|
|
101
|
+
|
|
102
|
+
info_str = []
|
|
103
|
+
for incl in incl_info:
|
|
104
|
+
_, sem_info = filtered_registry.lookup(name=incl[0])
|
|
105
|
+
if sem_info and isinstance(sem_info, SemInfo):
|
|
106
|
+
(
|
|
107
|
+
collected_types.extend(extract_non_primary_type(sem_info.type))
|
|
108
|
+
if sem_info.type
|
|
109
|
+
else None
|
|
110
|
+
)
|
|
111
|
+
info_str.append(
|
|
112
|
+
f"{sem_info.semstr} ({sem_info.name}) ({sem_info.type}) = {get_object_string(incl[1])}"
|
|
113
|
+
)
|
|
114
|
+
return ("\n".join(info_str), collected_types)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def get_object_string(obj: Any) -> Any: # noqa: ANN401
|
|
118
|
+
"""Get the string representation of the input object."""
|
|
119
|
+
if isinstance(obj, str):
|
|
120
|
+
return f'"{obj}"'
|
|
121
|
+
elif isinstance(obj, (int, float, bool)):
|
|
122
|
+
return str(obj)
|
|
123
|
+
elif isinstance(obj, list):
|
|
124
|
+
return "[" + ", ".join(get_object_string(item) for item in obj) + "]"
|
|
125
|
+
elif isinstance(obj, tuple):
|
|
126
|
+
return "(" + ", ".join(get_object_string(item) for item in obj) + ")"
|
|
127
|
+
elif isinstance(obj, dict):
|
|
128
|
+
return (
|
|
129
|
+
"{"
|
|
130
|
+
+ ", ".join(
|
|
131
|
+
f"{get_object_string(key)}: {get_object_string(value)}"
|
|
132
|
+
for key, value in obj.items()
|
|
133
|
+
)
|
|
134
|
+
+ "}"
|
|
135
|
+
)
|
|
136
|
+
elif isinstance(obj, Enum):
|
|
137
|
+
return f"{obj.__class__.__name__}.{obj.name}"
|
|
138
|
+
elif hasattr(obj, "__dict__"):
|
|
139
|
+
args = ", ".join(
|
|
140
|
+
f"{key}={get_object_string(value)}"
|
|
141
|
+
for key, value in vars(obj).items()
|
|
142
|
+
if key != "_jac_"
|
|
143
|
+
)
|
|
144
|
+
return f"{obj.__class__.__name__}({args})"
|
|
145
|
+
else:
|
|
146
|
+
return str(obj)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_all_type_explanations(type_list: list, mod_registry: SemRegistry) -> dict:
|
|
150
|
+
"""Get all type explanations from the input type list."""
|
|
151
|
+
collected_type_explanations = {}
|
|
152
|
+
for type_item in type_list:
|
|
153
|
+
type_explanation = get_type_explanation(type_item, mod_registry)
|
|
154
|
+
if type_explanation is not None:
|
|
155
|
+
type_explanation_str, nested_types = type_explanation
|
|
156
|
+
if type_item not in collected_type_explanations:
|
|
157
|
+
collected_type_explanations[type_item] = type_explanation_str
|
|
158
|
+
if nested_types:
|
|
159
|
+
nested_collected_type_explanations = get_all_type_explanations(
|
|
160
|
+
list(nested_types), mod_registry
|
|
161
|
+
)
|
|
162
|
+
for k, v in nested_collected_type_explanations.items():
|
|
163
|
+
if k not in collected_type_explanations:
|
|
164
|
+
collected_type_explanations[k] = v
|
|
165
|
+
return collected_type_explanations
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_type_explanation(
|
|
169
|
+
type_str: str, mod_registry: SemRegistry
|
|
170
|
+
) -> tuple[str | None, set[str] | None]:
|
|
171
|
+
"""Get the type explanation of the input type string."""
|
|
172
|
+
scope, sem_info = mod_registry.lookup(name=type_str)
|
|
173
|
+
if isinstance(sem_info, SemInfo) and sem_info.type:
|
|
174
|
+
sem_info_scope = SemScope(sem_info.name, sem_info.type, scope)
|
|
175
|
+
_, type_info = mod_registry.lookup(scope=sem_info_scope)
|
|
176
|
+
type_info_str = []
|
|
177
|
+
type_info_types = []
|
|
178
|
+
if sem_info.type == "Enum" and isinstance(type_info, list):
|
|
179
|
+
for enum_item in type_info:
|
|
180
|
+
type_info_str.append(
|
|
181
|
+
f"{enum_item.semstr} (EnumItem) ({enum_item.name})"
|
|
182
|
+
)
|
|
183
|
+
elif sem_info.type in ["obj", "class", "node", "edge"] and isinstance(
|
|
184
|
+
type_info, list
|
|
185
|
+
):
|
|
186
|
+
for arch_item in type_info:
|
|
187
|
+
type_info_str.append(
|
|
188
|
+
f"{arch_item.semstr} ({arch_item.type}) ({arch_item.name})"
|
|
189
|
+
)
|
|
190
|
+
if arch_item.type and extract_non_primary_type(arch_item.type):
|
|
191
|
+
type_info_types.extend(extract_non_primary_type(arch_item.type))
|
|
192
|
+
return (
|
|
193
|
+
f"{sem_info.semstr} ({sem_info.type}) ({sem_info.name}) = {', '.join(type_info_str)}",
|
|
194
|
+
set(type_info_types),
|
|
195
|
+
)
|
|
196
|
+
return None, None
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def extract_non_primary_type(type_str: str) -> list:
|
|
200
|
+
"""Extract non-primary types from the type string."""
|
|
201
|
+
if not type_str:
|
|
202
|
+
return []
|
|
203
|
+
pattern = r"(?:\[|,\s*|\|)([a-zA-Z_][a-zA-Z0-9_]*)|([a-zA-Z_][a-zA-Z0-9_]*)"
|
|
204
|
+
matches = re.findall(pattern, type_str)
|
|
205
|
+
primary_types = [
|
|
206
|
+
"str",
|
|
207
|
+
"int",
|
|
208
|
+
"float",
|
|
209
|
+
"bool",
|
|
210
|
+
"list",
|
|
211
|
+
"dict",
|
|
212
|
+
"tuple",
|
|
213
|
+
"set",
|
|
214
|
+
"Any",
|
|
215
|
+
"None",
|
|
216
|
+
]
|
|
217
|
+
non_primary_types = [m for t in matches for m in t if m and m not in primary_types]
|
|
218
|
+
return non_primary_types
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def get_type_annotation(data: Any) -> str: # noqa: ANN401
|
|
222
|
+
"""Get the type annotation of the input data."""
|
|
223
|
+
if isinstance(data, dict):
|
|
224
|
+
class_name = next(
|
|
225
|
+
(value.__class__.__name__ for value in data.values() if value is not None),
|
|
226
|
+
None,
|
|
227
|
+
)
|
|
228
|
+
if class_name:
|
|
229
|
+
return f"dict[str, {class_name}]"
|
|
230
|
+
else:
|
|
231
|
+
return "dict[str, Any]"
|
|
232
|
+
else:
|
|
233
|
+
return str(type(data).__name__)
|
jaclang/core/construct.py
CHANGED
|
@@ -340,7 +340,7 @@ class JacTestResult(unittest.TextTestResult):
|
|
|
340
340
|
) -> None:
|
|
341
341
|
"""Initialize FailFastTestResult object."""
|
|
342
342
|
super().__init__(stream, descriptions, verbosity) # noqa
|
|
343
|
-
self.failures_count =
|
|
343
|
+
self.failures_count = JacTestCheck.failcount
|
|
344
344
|
self.max_failures = max_failures
|
|
345
345
|
|
|
346
346
|
def addFailure(self, test, err) -> None: # noqa
|
|
@@ -379,6 +379,7 @@ class JacTestCheck:
|
|
|
379
379
|
test_case = unittest.TestCase()
|
|
380
380
|
test_suite = unittest.TestSuite()
|
|
381
381
|
breaker = False
|
|
382
|
+
failcount = 0
|
|
382
383
|
|
|
383
384
|
@staticmethod
|
|
384
385
|
def reset() -> None:
|
|
@@ -395,7 +396,11 @@ class JacTestCheck:
|
|
|
395
396
|
if result.wasSuccessful():
|
|
396
397
|
print("Passed successfully.")
|
|
397
398
|
else:
|
|
398
|
-
|
|
399
|
+
fails = len(result.failures)
|
|
400
|
+
JacTestCheck.failcount += fails
|
|
401
|
+
JacTestCheck.breaker = (
|
|
402
|
+
(JacTestCheck.failcount >= maxfail) if maxfail else True
|
|
403
|
+
)
|
|
399
404
|
|
|
400
405
|
@staticmethod
|
|
401
406
|
def add_test(test_fun: Callable) -> None:
|
jaclang/core/registry.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""Registry Utilities.
|
|
2
|
+
|
|
3
|
+
This module contains classes and functions for managing the registry of
|
|
4
|
+
semantic information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SemInfo:
|
|
13
|
+
"""Semantic information class."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self, name: str, type: Optional[str] = None, semstr: Optional[str] = None
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Initialize the class."""
|
|
19
|
+
self.name = name
|
|
20
|
+
self.type = type
|
|
21
|
+
self.semstr = semstr
|
|
22
|
+
|
|
23
|
+
def __repr__(self) -> str:
|
|
24
|
+
"""Return the string representation of the class."""
|
|
25
|
+
return f"{self.semstr} ({self.type}) ({self.name})"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class SemScope:
|
|
29
|
+
"""Scope class."""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self, scope: str, type: str, parent: Optional[SemScope] = None
|
|
33
|
+
) -> None:
|
|
34
|
+
"""Initialize the class."""
|
|
35
|
+
self.parent = parent
|
|
36
|
+
self.type = type
|
|
37
|
+
self.scope = scope
|
|
38
|
+
|
|
39
|
+
def __str__(self) -> str:
|
|
40
|
+
"""Return the string representation of the class."""
|
|
41
|
+
if self.parent:
|
|
42
|
+
return f"{self.parent}.{self.scope}({self.type})"
|
|
43
|
+
return f"{self.scope}({self.type})"
|
|
44
|
+
|
|
45
|
+
def __repr__(self) -> str:
|
|
46
|
+
"""Return the string representation of the class."""
|
|
47
|
+
return self.__str__()
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def get_scope_from_str(scope_str: str) -> Optional[SemScope]:
|
|
51
|
+
"""Get scope from string."""
|
|
52
|
+
scope_list = scope_str.split(".")
|
|
53
|
+
parent = None
|
|
54
|
+
for scope in scope_list:
|
|
55
|
+
scope_name, scope_type = scope.split("(")
|
|
56
|
+
scope_type = scope_type[:-1]
|
|
57
|
+
parent = SemScope(scope_name, scope_type, parent)
|
|
58
|
+
return parent
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SemRegistry:
|
|
62
|
+
"""Registry class."""
|
|
63
|
+
|
|
64
|
+
def __init__(self) -> None:
|
|
65
|
+
"""Initialize the class."""
|
|
66
|
+
self.registry: dict[SemScope, list[SemInfo]] = {}
|
|
67
|
+
|
|
68
|
+
def add(self, scope: SemScope, seminfo: SemInfo) -> None:
|
|
69
|
+
"""Add semantic information to the registry."""
|
|
70
|
+
for k in self.registry.keys():
|
|
71
|
+
if str(k) == str(scope):
|
|
72
|
+
scope = k
|
|
73
|
+
break
|
|
74
|
+
else:
|
|
75
|
+
self.registry[scope] = []
|
|
76
|
+
self.registry[scope].append(seminfo)
|
|
77
|
+
|
|
78
|
+
def lookup(
|
|
79
|
+
self,
|
|
80
|
+
scope: Optional[SemScope] = None,
|
|
81
|
+
name: Optional[str] = None,
|
|
82
|
+
type: Optional[str] = None,
|
|
83
|
+
) -> tuple[Optional[SemScope], Optional[SemInfo | list[SemInfo]]]:
|
|
84
|
+
"""Lookup semantic information in the registry."""
|
|
85
|
+
if scope:
|
|
86
|
+
for k, v in self.registry.items():
|
|
87
|
+
if str(k) == str(scope):
|
|
88
|
+
if name:
|
|
89
|
+
for i in v:
|
|
90
|
+
if i.name == name:
|
|
91
|
+
return k, i
|
|
92
|
+
elif type:
|
|
93
|
+
for i in v:
|
|
94
|
+
if i.type == type:
|
|
95
|
+
return k, i
|
|
96
|
+
else:
|
|
97
|
+
return k, v
|
|
98
|
+
else:
|
|
99
|
+
for k, v in self.registry.items():
|
|
100
|
+
if name:
|
|
101
|
+
for i in v:
|
|
102
|
+
if i.name == name:
|
|
103
|
+
return k, i
|
|
104
|
+
elif type:
|
|
105
|
+
for i in v:
|
|
106
|
+
if i.type == type:
|
|
107
|
+
return k, i
|
|
108
|
+
return None, None
|
|
109
|
+
|
|
110
|
+
def pp(self) -> None:
|
|
111
|
+
"""Pretty print the registry."""
|
|
112
|
+
for k, v in self.registry.items():
|
|
113
|
+
print(k)
|
|
114
|
+
for i in v:
|
|
115
|
+
print(f" {i.name} {i.type} {i.semstr}")
|
jaclang/core/utils.py
CHANGED
|
@@ -4,6 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Callable, TYPE_CHECKING
|
|
6
6
|
|
|
7
|
+
import jaclang.compiler.absyntree as ast
|
|
8
|
+
from jaclang.core.registry import SemScope
|
|
7
9
|
|
|
8
10
|
if TYPE_CHECKING:
|
|
9
11
|
from jaclang.core.construct import NodeAnchor, NodeArchitype
|
|
@@ -88,3 +90,26 @@ def traverse_graph(
|
|
|
88
90
|
else:
|
|
89
91
|
|
|
90
92
|
dfs(other_nd, cur_depth + 1)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_sem_scope(node: ast.AstNode) -> SemScope:
|
|
96
|
+
"""Get scope of the node."""
|
|
97
|
+
a = (
|
|
98
|
+
node.name
|
|
99
|
+
if isinstance(node, ast.Module)
|
|
100
|
+
else node.name.value if isinstance(node, (ast.Enum, ast.Architype)) else ""
|
|
101
|
+
)
|
|
102
|
+
if isinstance(node, ast.Module):
|
|
103
|
+
return SemScope(a, "Module", None)
|
|
104
|
+
elif isinstance(node, (ast.Enum, ast.Architype)):
|
|
105
|
+
node_type = (
|
|
106
|
+
node.__class__.__name__
|
|
107
|
+
if isinstance(node, ast.Enum)
|
|
108
|
+
else node.arch_type.value
|
|
109
|
+
)
|
|
110
|
+
if node.parent:
|
|
111
|
+
return SemScope(a, node_type, get_sem_scope(node.parent))
|
|
112
|
+
else:
|
|
113
|
+
if node.parent:
|
|
114
|
+
return get_sem_scope(node.parent)
|
|
115
|
+
return SemScope("", "", None)
|
jaclang/plugin/default.py
CHANGED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import fnmatch
|
|
6
6
|
import os
|
|
7
|
+
import pickle
|
|
7
8
|
import types
|
|
8
9
|
from dataclasses import field
|
|
9
10
|
from functools import wraps
|
|
@@ -11,7 +12,15 @@ from typing import Any, Callable, Optional, Type
|
|
|
11
12
|
|
|
12
13
|
from jaclang.compiler.absyntree import Module
|
|
13
14
|
from jaclang.compiler.constant import EdgeDir, colors
|
|
14
|
-
from jaclang.core.aott import
|
|
15
|
+
from jaclang.core.aott import (
|
|
16
|
+
aott_raise,
|
|
17
|
+
extract_non_primary_type,
|
|
18
|
+
get_all_type_explanations,
|
|
19
|
+
get_info_types,
|
|
20
|
+
get_object_string,
|
|
21
|
+
get_reasoning_output,
|
|
22
|
+
get_type_annotation,
|
|
23
|
+
)
|
|
15
24
|
from jaclang.core.construct import (
|
|
16
25
|
Architype,
|
|
17
26
|
DSFunc,
|
|
@@ -28,6 +37,7 @@ from jaclang.core.construct import (
|
|
|
28
37
|
root,
|
|
29
38
|
)
|
|
30
39
|
from jaclang.core.importer import jac_importer
|
|
40
|
+
from jaclang.core.registry import SemScope
|
|
31
41
|
from jaclang.core.utils import traverse_graph
|
|
32
42
|
from jaclang.plugin.feature import JacFeature as Jac
|
|
33
43
|
from jaclang.plugin.spec import T
|
|
@@ -235,6 +245,7 @@ class JacFeatureDefaults:
|
|
|
235
245
|
if JacTestCheck.breaker and (xit or maxfail):
|
|
236
246
|
break
|
|
237
247
|
JacTestCheck.breaker = False
|
|
248
|
+
JacTestCheck.failcount = 0
|
|
238
249
|
print("No test files found.") if not test_file else None
|
|
239
250
|
|
|
240
251
|
return True
|
|
@@ -427,33 +438,66 @@ class JacFeatureDefaults:
|
|
|
427
438
|
@staticmethod
|
|
428
439
|
@hookimpl
|
|
429
440
|
def with_llm(
|
|
441
|
+
file_loc: str,
|
|
430
442
|
model: Any, # noqa: ANN401
|
|
431
443
|
model_params: dict[str, Any],
|
|
432
|
-
|
|
433
|
-
|
|
444
|
+
scope: str,
|
|
445
|
+
incl_info: list[tuple[str, str]],
|
|
446
|
+
excl_info: list[tuple[str, str]],
|
|
434
447
|
inputs: tuple,
|
|
435
448
|
outputs: tuple,
|
|
436
449
|
action: str,
|
|
437
450
|
) -> Any: # noqa: ANN401
|
|
438
451
|
"""Jac's with_llm feature."""
|
|
452
|
+
with open(
|
|
453
|
+
os.path.join(
|
|
454
|
+
os.path.dirname(file_loc),
|
|
455
|
+
"__jac_gen__",
|
|
456
|
+
os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
|
|
457
|
+
),
|
|
458
|
+
"rb",
|
|
459
|
+
) as f:
|
|
460
|
+
mod_registry = pickle.load(f)
|
|
461
|
+
|
|
462
|
+
_scope = SemScope.get_scope_from_str(scope)
|
|
463
|
+
assert _scope is not None
|
|
464
|
+
|
|
439
465
|
reason = False
|
|
440
466
|
if "reason" in model_params:
|
|
441
467
|
reason = model_params.pop("reason")
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
468
|
+
|
|
469
|
+
type_collector: list = []
|
|
470
|
+
information, collected_types = get_info_types(_scope, mod_registry, incl_info)
|
|
471
|
+
type_collector.extend(collected_types)
|
|
472
|
+
|
|
473
|
+
inputs_information_list = []
|
|
474
|
+
for i in inputs:
|
|
475
|
+
typ_anno = get_type_annotation(i[3])
|
|
476
|
+
type_collector.extend(extract_non_primary_type(typ_anno))
|
|
477
|
+
inputs_information_list.append(
|
|
478
|
+
f"{i[0]} ({i[2]}) ({typ_anno}) = {get_object_string(i[3])}"
|
|
479
|
+
)
|
|
480
|
+
inputs_information = "\n".join(inputs_information_list)
|
|
481
|
+
|
|
482
|
+
output_information = f"{outputs[0]} ({outputs[2]})"
|
|
483
|
+
type_collector.extend(extract_non_primary_type(outputs[2]))
|
|
484
|
+
|
|
485
|
+
type_explanations_list = list(
|
|
486
|
+
get_all_type_explanations(type_collector, mod_registry).values()
|
|
487
|
+
)
|
|
488
|
+
type_explanations = "\n".join(type_explanations_list)
|
|
489
|
+
|
|
446
490
|
meaning_in = aott_raise(
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
491
|
+
information,
|
|
492
|
+
inputs_information,
|
|
493
|
+
output_information,
|
|
494
|
+
type_explanations,
|
|
451
495
|
action,
|
|
452
496
|
reason,
|
|
453
497
|
)
|
|
454
498
|
meaning_out = model.__infer__(meaning_in, **model_params)
|
|
455
|
-
|
|
456
|
-
return
|
|
499
|
+
reasoning, output = get_reasoning_output(meaning_out)
|
|
500
|
+
return output
|
|
457
501
|
|
|
458
502
|
|
|
459
503
|
class JacBuiltin:
|
jaclang/plugin/feature.py
CHANGED
|
@@ -227,18 +227,22 @@ class JacFeature:
|
|
|
227
227
|
|
|
228
228
|
@staticmethod
|
|
229
229
|
def with_llm(
|
|
230
|
+
file_loc: str,
|
|
230
231
|
model: Any, # noqa: ANN401
|
|
231
232
|
model_params: dict[str, Any],
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
scope: str,
|
|
234
|
+
incl_info: list[tuple[str, str]],
|
|
235
|
+
excl_info: list[tuple[str, str]],
|
|
234
236
|
inputs: tuple,
|
|
235
237
|
outputs: tuple,
|
|
236
238
|
action: str,
|
|
237
239
|
) -> Any: # noqa: ANN401
|
|
238
240
|
"""Jac's with_llm feature."""
|
|
239
241
|
return pm.hook.with_llm(
|
|
242
|
+
file_loc=file_loc,
|
|
240
243
|
model=model,
|
|
241
244
|
model_params=model_params,
|
|
245
|
+
scope=scope,
|
|
242
246
|
incl_info=incl_info,
|
|
243
247
|
excl_info=excl_info,
|
|
244
248
|
inputs=inputs,
|
jaclang/plugin/spec.py
CHANGED
|
@@ -211,10 +211,12 @@ class JacFeatureSpec:
|
|
|
211
211
|
@staticmethod
|
|
212
212
|
@hookspec(firstresult=True)
|
|
213
213
|
def with_llm(
|
|
214
|
+
file_loc: str,
|
|
214
215
|
model: Any, # noqa: ANN401
|
|
215
216
|
model_params: dict[str, Any],
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
scope: str,
|
|
218
|
+
incl_info: list[tuple[str, str]],
|
|
219
|
+
excl_info: list[tuple[str, str]],
|
|
218
220
|
inputs: tuple,
|
|
219
221
|
outputs: tuple,
|
|
220
222
|
action: str,
|