jaclang 0.5.6__py3-none-any.whl → 0.5.8__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/__init__.py +6 -1
- jaclang/cli/cli.py +63 -20
- jaclang/cli/cmdreg.py +42 -12
- jaclang/compiler/__init__.py +6 -3
- jaclang/compiler/__jac_gen__/jac_parser.py +2 -2
- jaclang/compiler/absyntree.py +1740 -61
- jaclang/compiler/codeloc.py +7 -0
- jaclang/compiler/compile.py +4 -5
- jaclang/compiler/constant.py +52 -6
- jaclang/compiler/parser.py +220 -129
- jaclang/compiler/passes/main/def_impl_match_pass.py +19 -3
- jaclang/compiler/passes/main/def_use_pass.py +1 -1
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +357 -0
- jaclang/compiler/passes/main/import_pass.py +7 -3
- jaclang/compiler/passes/main/pyast_gen_pass.py +333 -93
- jaclang/compiler/passes/main/pyast_load_pass.py +1779 -206
- jaclang/compiler/passes/main/pyout_pass.py +2 -2
- jaclang/compiler/passes/main/schedules.py +2 -1
- jaclang/compiler/passes/main/sym_tab_build_pass.py +20 -28
- jaclang/compiler/passes/main/tests/test_decl_def_match_pass.py +4 -4
- jaclang/compiler/passes/main/tests/test_pyast_build_pass.py +14 -5
- jaclang/compiler/passes/main/tests/test_sym_tab_build_pass.py +8 -8
- jaclang/compiler/passes/main/tests/test_typeinfo_pass.py +7 -0
- jaclang/compiler/passes/main/type_check_pass.py +0 -1
- jaclang/compiler/passes/tool/jac_formatter_pass.py +8 -17
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +43 -0
- jaclang/compiler/passes/utils/mypy_ast_build.py +28 -14
- jaclang/compiler/symtable.py +23 -2
- jaclang/compiler/tests/test_parser.py +53 -0
- jaclang/compiler/workspace.py +52 -26
- jaclang/core/aott.py +68 -0
- jaclang/core/construct.py +58 -6
- jaclang/core/importer.py +9 -10
- jaclang/core/utils.py +65 -3
- jaclang/plugin/builtin.py +42 -0
- jaclang/plugin/default.py +163 -18
- jaclang/plugin/feature.py +38 -10
- jaclang/plugin/spec.py +33 -6
- jaclang/utils/helpers.py +25 -0
- jaclang/utils/lang_tools.py +4 -1
- jaclang/utils/test.py +1 -0
- jaclang/utils/tests/test_lang_tools.py +12 -15
- jaclang/utils/treeprinter.py +10 -2
- {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/METADATA +1 -1
- {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/RECORD +48 -46
- {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/WHEEL +1 -1
- jaclang/compiler/tests/fixtures/__jac_gen__/__init__.py +0 -0
- jaclang/compiler/tests/fixtures/__jac_gen__/hello_world.py +0 -5
- jaclang/core/jacbuiltins.py +0 -10
- {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/entry_points.txt +0 -0
- {jaclang-0.5.6.dist-info → jaclang-0.5.8.dist-info}/top_level.txt +0 -0
jaclang/compiler/workspace.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from typing import Sequence
|
|
6
|
+
from typing import Optional, Sequence
|
|
7
7
|
|
|
8
8
|
import jaclang.compiler.absyntree as ast
|
|
9
9
|
from jaclang.compiler.compile import jac_str_to_pass
|
|
@@ -33,7 +33,7 @@ class ModuleInfo:
|
|
|
33
33
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self,
|
|
36
|
-
ir: ast.Module,
|
|
36
|
+
ir: Optional[ast.Module],
|
|
37
37
|
errors: Sequence[Alert],
|
|
38
38
|
warnings: Sequence[Alert],
|
|
39
39
|
) -> None:
|
|
@@ -46,10 +46,11 @@ class ModuleInfo:
|
|
|
46
46
|
class Workspace:
|
|
47
47
|
"""Class for managing workspace."""
|
|
48
48
|
|
|
49
|
-
def __init__(self, path: str) -> None:
|
|
49
|
+
def __init__(self, path: str, lazy_parse: bool = False) -> None:
|
|
50
50
|
"""Initialize workspace."""
|
|
51
51
|
self.path = path
|
|
52
52
|
self.modules: dict[str, ModuleInfo] = {}
|
|
53
|
+
self.lazy_parse = lazy_parse
|
|
53
54
|
self.rebuild_workspace()
|
|
54
55
|
|
|
55
56
|
def rebuild_workspace(self) -> None:
|
|
@@ -63,6 +64,15 @@ class Workspace:
|
|
|
63
64
|
]:
|
|
64
65
|
if file in self.modules:
|
|
65
66
|
continue
|
|
67
|
+
if self.lazy_parse:
|
|
68
|
+
# If lazy_parse is True, add the file to modules with empty IR
|
|
69
|
+
self.modules[file] = ModuleInfo(
|
|
70
|
+
ir=None,
|
|
71
|
+
errors=[],
|
|
72
|
+
warnings=[],
|
|
73
|
+
)
|
|
74
|
+
continue
|
|
75
|
+
|
|
66
76
|
with open(file, "r") as f:
|
|
67
77
|
source = f.read()
|
|
68
78
|
build = jac_str_to_pass(
|
|
@@ -98,10 +108,13 @@ class Workspace:
|
|
|
98
108
|
warnings=build.warnings_had,
|
|
99
109
|
)
|
|
100
110
|
|
|
101
|
-
def rebuild_file(
|
|
111
|
+
def rebuild_file(
|
|
112
|
+
self, file_path: str, deep: bool = False, source: str = ""
|
|
113
|
+
) -> bool:
|
|
102
114
|
"""Rebuild a file."""
|
|
103
|
-
|
|
104
|
-
|
|
115
|
+
if source == "":
|
|
116
|
+
with open(file_path, "r") as f:
|
|
117
|
+
source = f.read()
|
|
105
118
|
build = jac_str_to_pass(
|
|
106
119
|
jac_str=source,
|
|
107
120
|
file_path=file_path,
|
|
@@ -152,30 +165,40 @@ class Workspace:
|
|
|
152
165
|
self, file_path: str, deep: bool = False
|
|
153
166
|
) -> list[ast.ModulePath]:
|
|
154
167
|
"""Return a list of dependencies for a file."""
|
|
168
|
+
mod_ir = self.modules[file_path].ir
|
|
155
169
|
if deep:
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
170
|
+
return (
|
|
171
|
+
[
|
|
172
|
+
i
|
|
173
|
+
for i in mod_ir.get_all_sub_nodes(ast.ModulePath)
|
|
174
|
+
if i.parent
|
|
175
|
+
and isinstance(i.parent, ast.Import)
|
|
176
|
+
and i.parent.lang.tag.value == "jac"
|
|
177
|
+
]
|
|
178
|
+
if mod_ir
|
|
179
|
+
else []
|
|
180
|
+
)
|
|
163
181
|
else:
|
|
164
|
-
return
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
182
|
+
return (
|
|
183
|
+
[
|
|
184
|
+
i
|
|
185
|
+
for i in mod_ir.get_all_sub_nodes(ast.ModulePath)
|
|
186
|
+
if i.loc.mod_path == file_path
|
|
187
|
+
and i.parent
|
|
188
|
+
and isinstance(i.parent, ast.Import)
|
|
189
|
+
and i.parent.lang.tag.value == "jac"
|
|
190
|
+
]
|
|
191
|
+
if mod_ir
|
|
192
|
+
else []
|
|
193
|
+
)
|
|
172
194
|
|
|
173
195
|
def get_symbols(self, file_path: str) -> Sequence[Symbol]:
|
|
174
196
|
"""Return a list of symbols for a file."""
|
|
175
197
|
symbols = []
|
|
198
|
+
mod_ir = self.modules[file_path].ir
|
|
176
199
|
if file_path in self.modules:
|
|
177
|
-
root_table =
|
|
178
|
-
if file_path in self.modules and
|
|
200
|
+
root_table = mod_ir.sym_tab if mod_ir else None
|
|
201
|
+
if file_path in self.modules and root_table:
|
|
179
202
|
for i in sym_tab_list(sym_tab=root_table, file_path=file_path):
|
|
180
203
|
symbols += list(i.tab.values())
|
|
181
204
|
return symbols
|
|
@@ -191,10 +214,13 @@ class Workspace:
|
|
|
191
214
|
|
|
192
215
|
def get_uses(self, file_path: str) -> Sequence[ast.AstSymbolNode]: # need test
|
|
193
216
|
"""Return a list of definitions for a file."""
|
|
194
|
-
|
|
217
|
+
mod_ir = self.modules[file_path].ir
|
|
218
|
+
uses: list[ast.AstSymbolNode] = []
|
|
219
|
+
if self.lazy_parse:
|
|
220
|
+
return uses
|
|
195
221
|
if file_path in self.modules:
|
|
196
|
-
root_table =
|
|
197
|
-
if file_path in self.modules and
|
|
222
|
+
root_table = mod_ir.sym_tab if mod_ir else None
|
|
223
|
+
if file_path in self.modules and root_table:
|
|
198
224
|
for i in sym_tab_list(sym_tab=root_table, file_path=file_path):
|
|
199
225
|
uses += i.uses
|
|
200
226
|
return uses
|
jaclang/core/aott.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AOTT: Automated Operational Type Transformation.
|
|
3
|
+
|
|
4
|
+
This has all the necessary functions to perform the AOTT operations.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
prompt_template = """
|
|
11
|
+
[System Prompt]
|
|
12
|
+
This is an operation you must perform and return the output values. Neither, the methodology,
|
|
13
|
+
extra sentences nor the code are not needed.
|
|
14
|
+
|
|
15
|
+
[Information]
|
|
16
|
+
{information_str}
|
|
17
|
+
|
|
18
|
+
[Inputs and Input Type Information]
|
|
19
|
+
{input_types_n_information_str}
|
|
20
|
+
|
|
21
|
+
[Output Type]
|
|
22
|
+
{output_type_str}
|
|
23
|
+
|
|
24
|
+
[Output Type Explanations]
|
|
25
|
+
{output_type_info_str}
|
|
26
|
+
|
|
27
|
+
[Action]
|
|
28
|
+
{action}
|
|
29
|
+
|
|
30
|
+
{reason_suffix}
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
with_reason_suffix = """
|
|
34
|
+
Reason and return the output result(s) only, adhering to the provided Type in the following format
|
|
35
|
+
|
|
36
|
+
[Reasoning] <Reason>
|
|
37
|
+
[Output] <Result>
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
without_reason_suffix = """Generate and return the output result(s) only, adhering to the provided Type in the
|
|
41
|
+
following format
|
|
42
|
+
|
|
43
|
+
[Output] <result>
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def aott_raise(
|
|
48
|
+
information_str: str,
|
|
49
|
+
input_types_n_information_str: str,
|
|
50
|
+
output_type_str: str,
|
|
51
|
+
output_type_info_str: str,
|
|
52
|
+
action: str,
|
|
53
|
+
reason: bool,
|
|
54
|
+
) -> str:
|
|
55
|
+
"""AOTT Raise uses the information (Meanings types values) provided to generate a prompt(meaning in)."""
|
|
56
|
+
return prompt_template.format(
|
|
57
|
+
information_str=information_str,
|
|
58
|
+
input_types_n_information_str=input_types_n_information_str,
|
|
59
|
+
output_type_str=output_type_str,
|
|
60
|
+
output_type_info_str=output_type_info_str,
|
|
61
|
+
action=action,
|
|
62
|
+
reason_suffix=with_reason_suffix if reason else without_reason_suffix,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def aott_lower(meaning_out: str, output_type_info: tuple) -> Any: # noqa: ANN401
|
|
67
|
+
"""AOTT Lower uses the meaning out provided by the language model and return the result in the desired type."""
|
|
68
|
+
return meaning_out
|
jaclang/core/construct.py
CHANGED
|
@@ -141,14 +141,14 @@ class EdgeAnchor(ObjectAnchor):
|
|
|
141
141
|
|
|
142
142
|
def detach(
|
|
143
143
|
self, src: NodeArchitype, trg: NodeArchitype, is_undirected: bool = False
|
|
144
|
-
) ->
|
|
144
|
+
) -> None:
|
|
145
145
|
"""Detach edge from nodes."""
|
|
146
|
-
self.source = src # TODO: Delete me, don't keep attached
|
|
147
|
-
self.target = trg # TODO: Delete me, don't keep attached
|
|
148
146
|
self.is_undirected = is_undirected
|
|
149
147
|
src._jac_.edges.remove(self.obj)
|
|
150
148
|
trg._jac_.edges.remove(self.obj)
|
|
151
|
-
|
|
149
|
+
self.source = None
|
|
150
|
+
self.target = None
|
|
151
|
+
del self
|
|
152
152
|
|
|
153
153
|
def spawn_call(self, walk: WalkerArchitype) -> WalkerArchitype:
|
|
154
154
|
"""Invoke data spatial call."""
|
|
@@ -328,11 +328,57 @@ class DSFunc:
|
|
|
328
328
|
self.func = getattr(cls, self.name)
|
|
329
329
|
|
|
330
330
|
|
|
331
|
+
class JacTestResult(unittest.TextTestResult):
|
|
332
|
+
"""Jac test result class."""
|
|
333
|
+
|
|
334
|
+
def __init__(
|
|
335
|
+
self,
|
|
336
|
+
stream, # noqa
|
|
337
|
+
descriptions, # noqa
|
|
338
|
+
verbosity: int,
|
|
339
|
+
max_failures: Optional[int] = None,
|
|
340
|
+
) -> None:
|
|
341
|
+
"""Initialize FailFastTestResult object."""
|
|
342
|
+
super().__init__(stream, descriptions, verbosity) # noqa
|
|
343
|
+
self.failures_count = 0
|
|
344
|
+
self.max_failures = max_failures
|
|
345
|
+
|
|
346
|
+
def addFailure(self, test, err) -> None: # noqa
|
|
347
|
+
"""Count failures and stop."""
|
|
348
|
+
super().addFailure(test, err)
|
|
349
|
+
self.failures_count += 1
|
|
350
|
+
if self.max_failures is not None and self.failures_count >= self.max_failures:
|
|
351
|
+
self.stop()
|
|
352
|
+
|
|
353
|
+
def stop(self) -> None:
|
|
354
|
+
"""Stop the test execution."""
|
|
355
|
+
self.shouldStop = True
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
class JacTextTestRunner(unittest.TextTestRunner):
|
|
359
|
+
"""Jac test runner class."""
|
|
360
|
+
|
|
361
|
+
def __init__(self, max_failures: Optional[int] = None, **kwargs) -> None: # noqa
|
|
362
|
+
"""Initialize JacTextTestRunner object."""
|
|
363
|
+
self.max_failures = max_failures
|
|
364
|
+
super().__init__(**kwargs)
|
|
365
|
+
|
|
366
|
+
def _makeResult(self) -> JacTestResult: # noqa
|
|
367
|
+
"""Override the method to return an instance of JacTestResult."""
|
|
368
|
+
return JacTestResult(
|
|
369
|
+
self.stream,
|
|
370
|
+
self.descriptions,
|
|
371
|
+
self.verbosity,
|
|
372
|
+
max_failures=self.max_failures,
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
331
376
|
class JacTestCheck:
|
|
332
377
|
"""Jac Testing and Checking."""
|
|
333
378
|
|
|
334
379
|
test_case = unittest.TestCase()
|
|
335
380
|
test_suite = unittest.TestSuite()
|
|
381
|
+
breaker = False
|
|
336
382
|
|
|
337
383
|
@staticmethod
|
|
338
384
|
def reset() -> None:
|
|
@@ -341,9 +387,15 @@ class JacTestCheck:
|
|
|
341
387
|
JacTestCheck.test_suite = unittest.TestSuite()
|
|
342
388
|
|
|
343
389
|
@staticmethod
|
|
344
|
-
def run_test() -> None:
|
|
390
|
+
def run_test(xit: bool, maxfail: int | None, verbose: bool) -> None:
|
|
345
391
|
"""Run the test suite."""
|
|
346
|
-
|
|
392
|
+
verb = 2 if verbose else 1
|
|
393
|
+
runner = JacTextTestRunner(max_failures=maxfail, failfast=xit, verbosity=verb)
|
|
394
|
+
result = runner.run(JacTestCheck.test_suite)
|
|
395
|
+
if result.wasSuccessful():
|
|
396
|
+
print("Passed successfully.")
|
|
397
|
+
else:
|
|
398
|
+
JacTestCheck.breaker = True
|
|
347
399
|
|
|
348
400
|
@staticmethod
|
|
349
401
|
def add_test(test_fun: Callable) -> None:
|
jaclang/core/importer.py
CHANGED
|
@@ -46,24 +46,23 @@ def jac_importer(
|
|
|
46
46
|
codeobj = marshal.loads(codeobj)
|
|
47
47
|
else:
|
|
48
48
|
gen_dir = path.join(caller_dir, Con.JAC_GEN_DIR)
|
|
49
|
-
py_file_path = path.join(gen_dir, module_name + ".py")
|
|
50
49
|
pyc_file_path = path.join(gen_dir, module_name + ".jbc")
|
|
51
50
|
if (
|
|
52
51
|
cachable
|
|
53
|
-
and path.exists(
|
|
54
|
-
and path.getmtime(
|
|
52
|
+
and path.exists(pyc_file_path)
|
|
53
|
+
and path.getmtime(pyc_file_path) > path.getmtime(full_target)
|
|
55
54
|
):
|
|
56
55
|
with open(pyc_file_path, "rb") as f:
|
|
57
56
|
codeobj = marshal.load(f)
|
|
58
57
|
else:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
result = compile_jac(full_target, cache_result=cachable)
|
|
59
|
+
if result.errors_had or not result.ir.gen.py_bytecode:
|
|
60
|
+
for e in result.errors_had:
|
|
61
|
+
print(e)
|
|
62
|
+
logging.error(e)
|
|
64
63
|
return None
|
|
65
|
-
|
|
66
|
-
codeobj = marshal.
|
|
64
|
+
else:
|
|
65
|
+
codeobj = marshal.loads(result.ir.gen.py_bytecode)
|
|
67
66
|
|
|
68
67
|
module_name = override_name if override_name else module_name
|
|
69
68
|
module = types.ModuleType(module_name)
|
jaclang/core/utils.py
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
5
|
+
from typing import Callable, TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from jaclang.core.construct import NodeAnchor
|
|
9
|
+
from jaclang.core.construct import NodeAnchor, NodeArchitype
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def collect_node_connections(
|
|
@@ -18,7 +18,6 @@ def collect_node_connections(
|
|
|
18
18
|
if current_node not in visited_nodes:
|
|
19
19
|
visited_nodes.add(current_node)
|
|
20
20
|
edges = current_node.edges
|
|
21
|
-
|
|
22
21
|
for edge_ in edges:
|
|
23
22
|
target = edge_._jac_.target
|
|
24
23
|
if target:
|
|
@@ -26,3 +25,66 @@ def collect_node_connections(
|
|
|
26
25
|
(current_node.obj, target._jac_.obj, edge_.__class__.__name__)
|
|
27
26
|
)
|
|
28
27
|
collect_node_connections(target._jac_, visited_nodes, connections)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def traverse_graph(
|
|
31
|
+
node: NodeArchitype,
|
|
32
|
+
cur_depth: int,
|
|
33
|
+
depth: int,
|
|
34
|
+
edge_type: list[str],
|
|
35
|
+
traverse: bool,
|
|
36
|
+
connections: list,
|
|
37
|
+
node_depths: dict[NodeArchitype, int],
|
|
38
|
+
visited_nodes: list,
|
|
39
|
+
queue: list,
|
|
40
|
+
bfs: bool,
|
|
41
|
+
dfs: Callable,
|
|
42
|
+
node_limit: int,
|
|
43
|
+
edge_limit: int,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Traverse the graph using Breadth-First Search (BFS) or Depth-First Search (DFS)."""
|
|
46
|
+
for edge in node._jac_.edges:
|
|
47
|
+
is_self_loop = id(edge._jac_.source) == id(edge._jac_.target)
|
|
48
|
+
is_in_edge = edge._jac_.target == node
|
|
49
|
+
if (traverse and is_in_edge) or edge._jac_.obj.__class__.__name__ in edge_type:
|
|
50
|
+
continue
|
|
51
|
+
if is_self_loop:
|
|
52
|
+
continue # lets skip self loop for a while, need to handle it later
|
|
53
|
+
else:
|
|
54
|
+
other_nd = edge._jac_.target if not is_in_edge else edge._jac_.source
|
|
55
|
+
new_con = (
|
|
56
|
+
(node, other_nd, edge) if not is_in_edge else (other_nd, node, edge)
|
|
57
|
+
)
|
|
58
|
+
if node in node_depths and node_depths[node] is not None:
|
|
59
|
+
if other_nd in node_depths:
|
|
60
|
+
node_depths[node] = min(
|
|
61
|
+
cur_depth, node_depths[node], node_depths[other_nd] + 1
|
|
62
|
+
)
|
|
63
|
+
node_depths[other_nd] = min(
|
|
64
|
+
cur_depth + 1, node_depths[node] + 1, node_depths[other_nd]
|
|
65
|
+
)
|
|
66
|
+
else:
|
|
67
|
+
if other_nd:
|
|
68
|
+
node_depths[other_nd] = min(
|
|
69
|
+
cur_depth + 1, node_depths[node] + 1
|
|
70
|
+
)
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError("Edge is detached from node in graph")
|
|
73
|
+
if (
|
|
74
|
+
other_nd
|
|
75
|
+
and new_con not in connections
|
|
76
|
+
and (
|
|
77
|
+
(
|
|
78
|
+
depth < 0
|
|
79
|
+
or min(node_depths[node], node_depths[other_nd]) + 1 <= depth
|
|
80
|
+
)
|
|
81
|
+
and node_limit > len(visited_nodes)
|
|
82
|
+
and edge_limit > len(connections)
|
|
83
|
+
)
|
|
84
|
+
):
|
|
85
|
+
connections.append(new_con)
|
|
86
|
+
if bfs:
|
|
87
|
+
queue.append([other_nd, cur_depth + 1])
|
|
88
|
+
else:
|
|
89
|
+
|
|
90
|
+
dfs(other_nd, cur_depth + 1)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Jac specific builtins."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from typing import Optional
|
|
9
|
+
from jaclang.core.construct import NodeArchitype
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def dotgen(
|
|
13
|
+
node: Optional[NodeArchitype] = None,
|
|
14
|
+
depth: Optional[int] = None,
|
|
15
|
+
traverse: Optional[bool] = None,
|
|
16
|
+
edge_type: Optional[list[str]] = None,
|
|
17
|
+
bfs: Optional[bool] = None,
|
|
18
|
+
edge_limit: Optional[int] = None,
|
|
19
|
+
node_limit: Optional[int] = None,
|
|
20
|
+
dot_file: Optional[str] = None,
|
|
21
|
+
) -> str:
|
|
22
|
+
"""Print the dot graph."""
|
|
23
|
+
from jaclang.core.construct import root
|
|
24
|
+
from jaclang.plugin.feature import pm
|
|
25
|
+
|
|
26
|
+
node = node if node is not None else root
|
|
27
|
+
depth = depth if depth is not None else -1
|
|
28
|
+
traverse = traverse if traverse is not None else False
|
|
29
|
+
bfs = bfs if bfs is not None else True
|
|
30
|
+
edge_limit = edge_limit if edge_limit is not None else 512
|
|
31
|
+
node_limit = node_limit if node_limit is not None else 512
|
|
32
|
+
|
|
33
|
+
return pm.hook.dotgen(
|
|
34
|
+
edge_type=edge_type,
|
|
35
|
+
node=node,
|
|
36
|
+
depth=depth,
|
|
37
|
+
traverse=traverse,
|
|
38
|
+
bfs=bfs,
|
|
39
|
+
edge_limit=edge_limit,
|
|
40
|
+
node_limit=node_limit,
|
|
41
|
+
dot_file=dot_file,
|
|
42
|
+
)
|
jaclang/plugin/default.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import fnmatch
|
|
5
6
|
import os
|
|
6
7
|
import types
|
|
7
8
|
from dataclasses import field
|
|
@@ -9,7 +10,8 @@ from functools import wraps
|
|
|
9
10
|
from typing import Any, Callable, Optional, Type
|
|
10
11
|
|
|
11
12
|
from jaclang.compiler.absyntree import Module
|
|
12
|
-
from jaclang.compiler.constant import EdgeDir
|
|
13
|
+
from jaclang.compiler.constant import EdgeDir, colors
|
|
14
|
+
from jaclang.core.aott import aott_lower, aott_raise
|
|
13
15
|
from jaclang.core.construct import (
|
|
14
16
|
Architype,
|
|
15
17
|
DSFunc,
|
|
@@ -26,7 +28,7 @@ from jaclang.core.construct import (
|
|
|
26
28
|
root,
|
|
27
29
|
)
|
|
28
30
|
from jaclang.core.importer import jac_importer
|
|
29
|
-
from jaclang.core.
|
|
31
|
+
from jaclang.core.utils import traverse_graph
|
|
30
32
|
from jaclang.plugin.feature import JacFeature as Jac
|
|
31
33
|
from jaclang.plugin.spec import T
|
|
32
34
|
|
|
@@ -184,20 +186,57 @@ class JacFeatureDefaults:
|
|
|
184
186
|
|
|
185
187
|
@staticmethod
|
|
186
188
|
@hookimpl
|
|
187
|
-
def run_test(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
:
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
189
|
+
def run_test(
|
|
190
|
+
filepath: str,
|
|
191
|
+
filter: Optional[str],
|
|
192
|
+
xit: bool,
|
|
193
|
+
maxfail: Optional[int],
|
|
194
|
+
directory: Optional[str],
|
|
195
|
+
verbose: bool,
|
|
196
|
+
) -> bool:
|
|
197
|
+
"""Run the test suite in the specified .jac file."""
|
|
198
|
+
test_file = False
|
|
199
|
+
if filepath:
|
|
200
|
+
if filepath.endswith(".jac"):
|
|
201
|
+
base, mod_name = os.path.split(filepath)
|
|
202
|
+
base = base if base else "./"
|
|
203
|
+
mod_name = mod_name[:-4]
|
|
204
|
+
JacTestCheck.reset()
|
|
205
|
+
Jac.jac_import(target=mod_name, base_path=base)
|
|
206
|
+
JacTestCheck.run_test(xit, maxfail, verbose)
|
|
207
|
+
else:
|
|
208
|
+
print("Not a .jac file.")
|
|
199
209
|
else:
|
|
200
|
-
|
|
210
|
+
directory = directory if directory else os.getcwd()
|
|
211
|
+
|
|
212
|
+
if filter or directory:
|
|
213
|
+
current_dir = directory if directory else os.getcwd()
|
|
214
|
+
for root_dir, _, files in os.walk(current_dir, topdown=True):
|
|
215
|
+
files = (
|
|
216
|
+
[file for file in files if fnmatch.fnmatch(file, filter)]
|
|
217
|
+
if filter
|
|
218
|
+
else files
|
|
219
|
+
)
|
|
220
|
+
files = [
|
|
221
|
+
file
|
|
222
|
+
for file in files
|
|
223
|
+
if not file.endswith((".test.jac", ".impl.jac"))
|
|
224
|
+
]
|
|
225
|
+
for file in files:
|
|
226
|
+
if file.endswith(".jac"):
|
|
227
|
+
test_file = True
|
|
228
|
+
print(f"\n\n\t\t* Inside {root_dir}" + "/" + f"{file} *")
|
|
229
|
+
JacTestCheck.reset()
|
|
230
|
+
Jac.jac_import(target=file[:-4], base_path=root_dir)
|
|
231
|
+
JacTestCheck.run_test(xit, maxfail, verbose)
|
|
232
|
+
|
|
233
|
+
if JacTestCheck.breaker and (xit or maxfail):
|
|
234
|
+
break
|
|
235
|
+
if JacTestCheck.breaker and (xit or maxfail):
|
|
236
|
+
break
|
|
237
|
+
JacTestCheck.breaker = False
|
|
238
|
+
print("No test files found.") if not test_file else None
|
|
239
|
+
|
|
201
240
|
return True
|
|
202
241
|
|
|
203
242
|
@staticmethod
|
|
@@ -385,15 +424,121 @@ class JacFeatureDefaults:
|
|
|
385
424
|
|
|
386
425
|
return builder
|
|
387
426
|
|
|
427
|
+
@staticmethod
|
|
428
|
+
@hookimpl
|
|
429
|
+
def with_llm(
|
|
430
|
+
model: Any, # noqa: ANN401
|
|
431
|
+
model_params: dict[str, Any],
|
|
432
|
+
incl_info: tuple,
|
|
433
|
+
excl_info: tuple,
|
|
434
|
+
inputs: tuple,
|
|
435
|
+
outputs: tuple,
|
|
436
|
+
action: str,
|
|
437
|
+
) -> Any: # noqa: ANN401
|
|
438
|
+
"""Jac's with_llm feature."""
|
|
439
|
+
reason = False
|
|
440
|
+
if "reason" in model_params:
|
|
441
|
+
reason = model_params.pop("reason")
|
|
442
|
+
input_types_n_information_str = "" # TODO: We have to generate this
|
|
443
|
+
output_type_str = "" # TODO: We have to generate this
|
|
444
|
+
output_type_info_str = "" # TODO: We have to generate this
|
|
445
|
+
information_str = "" # TODO: We have to generate this
|
|
446
|
+
meaning_in = aott_raise(
|
|
447
|
+
information_str,
|
|
448
|
+
input_types_n_information_str,
|
|
449
|
+
output_type_str,
|
|
450
|
+
output_type_info_str,
|
|
451
|
+
action,
|
|
452
|
+
reason,
|
|
453
|
+
)
|
|
454
|
+
meaning_out = model.__infer__(meaning_in, **model_params)
|
|
455
|
+
output_type_info = (None, None) # TODO: We have to generate this
|
|
456
|
+
return aott_lower(meaning_out, output_type_info)
|
|
457
|
+
|
|
388
458
|
|
|
389
459
|
class JacBuiltin:
|
|
390
460
|
"""Jac Builtins."""
|
|
391
461
|
|
|
392
462
|
@staticmethod
|
|
393
463
|
@hookimpl
|
|
394
|
-
def dotgen(
|
|
395
|
-
|
|
396
|
-
|
|
464
|
+
def dotgen(
|
|
465
|
+
node: NodeArchitype,
|
|
466
|
+
depth: int,
|
|
467
|
+
traverse: bool,
|
|
468
|
+
edge_type: list[str],
|
|
469
|
+
bfs: bool,
|
|
470
|
+
edge_limit: int,
|
|
471
|
+
node_limit: int,
|
|
472
|
+
dot_file: Optional[str],
|
|
473
|
+
) -> str:
|
|
474
|
+
"""Generate Dot file for visualizing nodes and edges."""
|
|
475
|
+
edge_type = edge_type if edge_type else []
|
|
476
|
+
visited_nodes: list[NodeArchitype] = []
|
|
477
|
+
node_depths: dict[NodeArchitype, int] = {node: 0}
|
|
478
|
+
queue: list = [[node, 0]]
|
|
479
|
+
connections: list[tuple[NodeArchitype, NodeArchitype, EdgeArchitype]] = []
|
|
480
|
+
|
|
481
|
+
def dfs(node: NodeArchitype, cur_depth: int) -> None:
|
|
482
|
+
"""Depth first search."""
|
|
483
|
+
if node not in visited_nodes:
|
|
484
|
+
visited_nodes.append(node)
|
|
485
|
+
traverse_graph(
|
|
486
|
+
node,
|
|
487
|
+
cur_depth,
|
|
488
|
+
depth,
|
|
489
|
+
edge_type,
|
|
490
|
+
traverse,
|
|
491
|
+
connections,
|
|
492
|
+
node_depths,
|
|
493
|
+
visited_nodes,
|
|
494
|
+
queue,
|
|
495
|
+
bfs,
|
|
496
|
+
dfs,
|
|
497
|
+
node_limit,
|
|
498
|
+
edge_limit,
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
if bfs:
|
|
502
|
+
cur_depth = 0
|
|
503
|
+
while queue:
|
|
504
|
+
current_node, cur_depth = queue.pop(0)
|
|
505
|
+
if current_node not in visited_nodes:
|
|
506
|
+
visited_nodes.append(current_node)
|
|
507
|
+
traverse_graph(
|
|
508
|
+
current_node,
|
|
509
|
+
cur_depth,
|
|
510
|
+
depth,
|
|
511
|
+
edge_type,
|
|
512
|
+
traverse,
|
|
513
|
+
connections,
|
|
514
|
+
node_depths,
|
|
515
|
+
visited_nodes,
|
|
516
|
+
queue,
|
|
517
|
+
bfs,
|
|
518
|
+
dfs,
|
|
519
|
+
node_limit,
|
|
520
|
+
edge_limit,
|
|
521
|
+
)
|
|
522
|
+
else:
|
|
523
|
+
dfs(node, cur_depth=0)
|
|
524
|
+
dot_content = (
|
|
525
|
+
'digraph {\nnode [style="filled", shape="ellipse", '
|
|
526
|
+
'fillcolor="invis", fontcolor="black"];\n'
|
|
527
|
+
)
|
|
528
|
+
for source, target, edge in connections:
|
|
529
|
+
dot_content += (
|
|
530
|
+
f"{visited_nodes.index(source)} -> {visited_nodes.index(target)} "
|
|
531
|
+
f' [label="{edge._jac_.obj.__class__.__name__} "];\n'
|
|
532
|
+
)
|
|
533
|
+
for node_ in visited_nodes:
|
|
534
|
+
color = (
|
|
535
|
+
colors[node_depths[node_]] if node_depths[node_] < 25 else colors[24]
|
|
536
|
+
)
|
|
537
|
+
dot_content += f'{visited_nodes.index(node_)} [label="{node_._jac_.obj}" fillcolor="{color}"];\n'
|
|
538
|
+
if dot_file:
|
|
539
|
+
with open(dot_file, "w") as f:
|
|
540
|
+
f.write(dot_content + "}")
|
|
541
|
+
return dot_content + "}"
|
|
397
542
|
|
|
398
543
|
|
|
399
544
|
class JacCmdDefaults:
|