jaclang 0.8.0__py3-none-any.whl → 0.8.2__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 -0
- jaclang/cli/cli.py +23 -50
- jaclang/compiler/codeinfo.py +0 -1
- jaclang/compiler/jac.lark +14 -22
- jaclang/compiler/larkparse/jac_parser.py +2 -2
- jaclang/compiler/parser.py +378 -531
- jaclang/compiler/passes/main/__init__.py +0 -14
- jaclang/compiler/passes/main/annex_pass.py +2 -8
- jaclang/compiler/passes/main/cfg_build_pass.py +39 -13
- jaclang/compiler/passes/main/def_impl_match_pass.py +14 -13
- jaclang/compiler/passes/main/def_use_pass.py +4 -7
- jaclang/compiler/passes/main/import_pass.py +6 -14
- jaclang/compiler/passes/main/inheritance_pass.py +2 -2
- jaclang/compiler/passes/main/pyast_gen_pass.py +428 -799
- jaclang/compiler/passes/main/pyast_load_pass.py +115 -311
- jaclang/compiler/passes/main/pyjac_ast_link_pass.py +8 -7
- jaclang/compiler/passes/main/sym_tab_build_pass.py +3 -3
- jaclang/compiler/passes/main/sym_tab_link_pass.py +6 -9
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/action/actions.jac +1 -5
- jaclang/compiler/passes/main/tests/fixtures/symtab_link_tests/main.jac +1 -8
- jaclang/compiler/passes/main/tests/test_cfg_build_pass.py +5 -9
- jaclang/compiler/passes/main/tests/test_decl_impl_match_pass.py +7 -8
- jaclang/compiler/passes/main/tests/test_import_pass.py +5 -18
- jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -6
- jaclang/compiler/passes/main/tests/test_sub_node_pass.py +1 -3
- jaclang/compiler/passes/main/tests/test_sym_tab_link_pass.py +20 -17
- jaclang/compiler/passes/tool/doc_ir_gen_pass.py +425 -216
- jaclang/compiler/passes/tool/jac_formatter_pass.py +2 -0
- jaclang/compiler/passes/tool/tests/fixtures/archetype_frmt.jac +14 -0
- jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/triple_quoted_string.jac +5 -4
- jaclang/compiler/passes/tool/tests/fixtures/import_fmt.jac +6 -0
- jaclang/compiler/passes/tool/tests/fixtures/simple_walk_fmt.jac +3 -3
- jaclang/compiler/passes/tool/tests/fixtures/tagbreak.jac +9 -0
- jaclang/compiler/passes/tool/tests/test_jac_format_pass.py +18 -3
- jaclang/compiler/passes/tool/tests/test_unparse_validate.py +2 -2
- jaclang/compiler/program.py +22 -66
- jaclang/compiler/tests/fixtures/fam.jac +2 -2
- jaclang/compiler/tests/fixtures/pkg_import_lib/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/__init__.jac +1 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/__init__.py +5 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/__init__.py +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/sub/helper.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_lib_py/tools.jac +3 -0
- jaclang/compiler/tests/fixtures/pkg_import_main.jac +10 -0
- jaclang/compiler/tests/fixtures/pkg_import_main_py.jac +11 -0
- jaclang/compiler/tests/test_importer.py +30 -13
- jaclang/compiler/tests/test_parser.py +1 -0
- jaclang/compiler/unitree.py +488 -320
- jaclang/langserve/__init__.jac +1 -0
- jaclang/langserve/engine.jac +503 -0
- jaclang/langserve/sem_manager.jac +309 -0
- jaclang/langserve/server.jac +201 -0
- jaclang/langserve/tests/server_test/test_lang_serve.py +139 -48
- jaclang/langserve/tests/server_test/utils.py +35 -6
- jaclang/langserve/tests/session.jac +294 -0
- jaclang/langserve/tests/test_sem_tokens.py +2 -2
- jaclang/langserve/tests/test_server.py +8 -7
- jaclang/langserve/utils.jac +51 -30
- jaclang/runtimelib/archetype.py +128 -6
- jaclang/runtimelib/builtin.py +17 -14
- jaclang/runtimelib/importer.py +51 -76
- jaclang/runtimelib/machine.py +469 -305
- jaclang/runtimelib/meta_importer.py +86 -0
- jaclang/runtimelib/tests/fixtures/graph_purger.jac +24 -26
- jaclang/runtimelib/tests/fixtures/other_root_access.jac +25 -16
- jaclang/runtimelib/tests/fixtures/traversing_save.jac +7 -5
- jaclang/runtimelib/tests/test_jaseci.py +3 -1
- jaclang/runtimelib/utils.py +3 -3
- jaclang/tests/fixtures/arch_rel_import_creation.jac +23 -23
- jaclang/tests/fixtures/async_ability.jac +43 -10
- jaclang/tests/fixtures/async_function.jac +18 -0
- jaclang/tests/fixtures/async_walker.jac +17 -12
- jaclang/tests/fixtures/backward_edge_visit.jac +31 -0
- jaclang/tests/fixtures/builtin_printgraph.jac +85 -0
- jaclang/tests/fixtures/builtin_printgraph_json.jac +21 -0
- jaclang/tests/fixtures/builtin_printgraph_mermaid.jac +16 -0
- jaclang/tests/fixtures/chandra_bugs2.jac +20 -13
- jaclang/tests/fixtures/concurrency.jac +1 -1
- jaclang/tests/fixtures/create_dynamic_archetype.jac +25 -28
- jaclang/tests/fixtures/deep/deeper/deep_outer_import.jac +7 -4
- jaclang/tests/fixtures/deep/deeper/snd_lev.jac +2 -2
- jaclang/tests/fixtures/deep/deeper/snd_lev_dup.jac +6 -0
- jaclang/tests/fixtures/deep/one_lev.jac +2 -2
- jaclang/tests/fixtures/deep/one_lev_dup.jac +4 -3
- jaclang/tests/fixtures/dynamic_archetype.jac +19 -12
- jaclang/tests/fixtures/edge_ability.jac +49 -0
- jaclang/tests/fixtures/foo.jac +14 -22
- jaclang/tests/fixtures/guess_game.jac +1 -1
- jaclang/tests/fixtures/here_usage_error.jac +21 -0
- jaclang/tests/fixtures/here_visitor_usage.jac +21 -0
- jaclang/tests/fixtures/jac_from_py.py +1 -1
- jaclang/tests/fixtures/jp_importer.jac +6 -6
- jaclang/tests/fixtures/jp_importer_auto.jac +5 -3
- jaclang/tests/fixtures/node_del.jac +30 -36
- jaclang/tests/fixtures/unicode_strings.jac +24 -0
- jaclang/tests/fixtures/visit_traversal.jac +47 -0
- jaclang/tests/fixtures/walker_update.jac +5 -7
- jaclang/tests/test_cli.py +12 -7
- jaclang/tests/test_language.py +218 -145
- jaclang/tests/test_reference.py +9 -4
- jaclang/tests/test_typecheck.py +13 -26
- jaclang/utils/helpers.py +14 -6
- jaclang/utils/lang_tools.py +9 -8
- jaclang/utils/module_resolver.py +23 -0
- jaclang/utils/tests/test_lang_tools.py +2 -1
- jaclang/utils/treeprinter.py +3 -4
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/METADATA +4 -3
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/RECORD +112 -94
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/WHEEL +1 -1
- jaclang/compiler/passes/main/tests/fixtures/main_err.jac +0 -6
- jaclang/compiler/passes/main/tests/fixtures/second_err.jac +0 -4
- jaclang/compiler/passes/tool/tests/fixtures/corelib.jac +0 -644
- jaclang/compiler/passes/tool/tests/test_doc_ir_gen_pass.py +0 -29
- jaclang/langserve/__init__.py +0 -1
- jaclang/langserve/engine.py +0 -553
- jaclang/langserve/sem_manager.py +0 -383
- jaclang/langserve/server.py +0 -167
- jaclang/langserve/tests/session.py +0 -255
- jaclang/tests/fixtures/builtin_dotgen.jac +0 -42
- jaclang/tests/fixtures/builtin_dotgen_json.jac +0 -21
- jaclang/tests/fixtures/deep/deeper/__init__.jac +0 -1
- {jaclang-0.8.0.dist-info → jaclang-0.8.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
from jaclang.utils.test import TestCase
|
|
2
2
|
from jaclang.vendor.pygls import uris
|
|
3
3
|
from jaclang.vendor.pygls.workspace import Workspace
|
|
4
|
-
from jaclang.langserve.engine import JacLangServer
|
|
5
|
-
from .session import LspSession
|
|
6
4
|
|
|
7
5
|
import lsprotocol.types as lspt
|
|
8
6
|
import pytest
|
|
7
|
+
from jaclang import JacMachineInterface as _
|
|
8
|
+
from jaclang.langserve.engine import JacLangServer
|
|
9
|
+
from .session import LspSession
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class TestJacLangServer(TestCase):
|
|
@@ -62,7 +63,7 @@ class TestJacLangServer(TestCase):
|
|
|
62
63
|
self.assertIn(
|
|
63
64
|
# "ability) calculate_area: float",
|
|
64
65
|
"ability) calculate_area\n( radius : float ) -> float",
|
|
65
|
-
lsp.get_hover_info(circle_impl_file, pos).contents.value,
|
|
66
|
+
lsp.get_hover_info(circle_impl_file, pos).contents.value.replace("'", ""),
|
|
66
67
|
)
|
|
67
68
|
|
|
68
69
|
def test_impl_auto_discover(self) -> None:
|
|
@@ -80,7 +81,7 @@ class TestJacLangServer(TestCase):
|
|
|
80
81
|
self.assertIn(
|
|
81
82
|
# "ability) calculate_area: float",
|
|
82
83
|
"(public ability) calculate_area\n( radius : float ) -> float",
|
|
83
|
-
lsp.get_hover_info(circle_impl_file, pos).contents.value,
|
|
84
|
+
lsp.get_hover_info(circle_impl_file, pos).contents.value.replace("'", ""),
|
|
84
85
|
)
|
|
85
86
|
|
|
86
87
|
@pytest.mark.xfail(reason="TODO: Fix when we have the type checker")
|
|
@@ -133,12 +134,12 @@ class TestJacLangServer(TestCase):
|
|
|
133
134
|
workspace = Workspace(workspace_path, lsp)
|
|
134
135
|
lsp.lsp._workspace = workspace
|
|
135
136
|
guess_game_file = uris.from_fs_path(
|
|
136
|
-
self.examples_abs_path("guess_game/guess_game4.jac")
|
|
137
|
+
self.examples_abs_path("guess_game/guess_game4.impl.jac")
|
|
137
138
|
)
|
|
138
139
|
lsp.deep_check(guess_game_file)
|
|
139
140
|
self.assertIn(
|
|
140
|
-
"guess_game4.jac:
|
|
141
|
-
str(lsp.get_definition(guess_game_file, lspt.Position(
|
|
141
|
+
"guess_game4.jac:16:8-16:21",
|
|
142
|
+
str(lsp.get_definition(guess_game_file, lspt.Position(15, 45))),
|
|
142
143
|
)
|
|
143
144
|
|
|
144
145
|
def test_go_to_definition_method_manual_impl(self) -> None:
|
jaclang/langserve/utils.jac
CHANGED
|
@@ -24,10 +24,8 @@ import from jaclang.vendor.pygls { uris }
|
|
|
24
24
|
import lsprotocol.types as lspt;
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
T = TypeVar('T', bound=Callable[(P, Coroutine[(Any, Any, Any)])]);
|
|
30
|
-
}
|
|
27
|
+
glob P = ParamSpec('P');
|
|
28
|
+
glob T = TypeVar('T', bound=Callable[(P, Coroutine[(Any, Any, Any)])]);
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
"""Return diagnostics."""
|
|
@@ -36,11 +34,15 @@ def gen_diagnostics(
|
|
|
36
34
|
errors: <>list[Alert],
|
|
37
35
|
warnings: <>list[Alert]
|
|
38
36
|
) -> <>list[lspt.Diagnostic] {
|
|
39
|
-
return
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
return [ lspt.Diagnostic(
|
|
38
|
+
range=create_range(error.loc),
|
|
39
|
+
message=error.msg,
|
|
40
|
+
severity=lspt.DiagnosticSeverity.Error
|
|
41
|
+
) for error in errors if error.loc.mod_path == uris.to_fs_path(from_path) ] + [ lspt.Diagnostic(
|
|
42
|
+
range=create_range(warning.loc),
|
|
43
|
+
message=warning.msg,
|
|
44
|
+
severity=lspt.DiagnosticSeverity.Warning
|
|
45
|
+
) for warning in warnings if warning.loc.mod_path == uris.to_fs_path(from_path) ];
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
|
|
@@ -156,25 +158,31 @@ def get_symbols_for_outline(<>node: UniScopeNode) -> <>list[lspt.DocumentSymbol]
|
|
|
156
158
|
continue;
|
|
157
159
|
}
|
|
158
160
|
pos = create_range(item.decl.loc);
|
|
159
|
-
symbol = lspt.DocumentSymbol(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
symbol = lspt.DocumentSymbol(
|
|
162
|
+
name=key,
|
|
163
|
+
kind=kind_map(item.decl),
|
|
164
|
+
range=pos,
|
|
165
|
+
selection_range=pos,
|
|
166
|
+
children=[]
|
|
167
|
+
);
|
|
164
168
|
symbols.append(symbol);
|
|
165
169
|
}
|
|
166
170
|
for sub_tab in [ i for i in <>node.kid_scope if i.loc.mod_path == <>node.loc.mod_path ] {
|
|
167
171
|
sub_symbols = get_symbols_for_outline(sub_tab);
|
|
168
|
-
if isinstance(
|
|
169
|
-
|
|
172
|
+
if isinstance(
|
|
173
|
+
sub_tab,
|
|
174
|
+
(uni.IfStmt, uni.ElseStmt, uni.WhileStmt, uni.IterForStmt, uni.InForStmt)
|
|
175
|
+
) {
|
|
170
176
|
symbols.extend(sub_symbols);
|
|
171
177
|
} else {
|
|
172
178
|
sub_pos = create_range(sub_tab.loc);
|
|
173
|
-
symbol = lspt.DocumentSymbol(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
symbol = lspt.DocumentSymbol(
|
|
180
|
+
name=sub_tab.scope_name,
|
|
181
|
+
kind=kind_map(sub_tab),
|
|
182
|
+
range=sub_pos,
|
|
183
|
+
selection_range=sub_pos,
|
|
184
|
+
children=sub_symbols
|
|
185
|
+
);
|
|
178
186
|
symbols.append(symbol);
|
|
179
187
|
}
|
|
180
188
|
}
|
|
@@ -193,10 +201,16 @@ def owner_sym(table: UniScopeNode) -> Optional[Symbol] {
|
|
|
193
201
|
|
|
194
202
|
"""Create an lspt.Range from a location object."""
|
|
195
203
|
def create_range(loc: CodeLocInfo) -> lspt.Range {
|
|
196
|
-
return lspt.Range(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
204
|
+
return lspt.Range(
|
|
205
|
+
start=lspt.Position(
|
|
206
|
+
line=(loc.first_line - 1) if loc.first_line > 0 else 0 ,
|
|
207
|
+
character=(loc.col_start - 1) if loc.col_start > 0 else 0
|
|
208
|
+
),
|
|
209
|
+
end=lspt.Position(
|
|
210
|
+
line=(loc.last_line - 1) if loc.last_line > 0 else 0 ,
|
|
211
|
+
character=(loc.col_end - 1) if loc.col_end > 0 else 0
|
|
212
|
+
)
|
|
213
|
+
);
|
|
200
214
|
}
|
|
201
215
|
|
|
202
216
|
|
|
@@ -263,8 +277,9 @@ def collect_all_symbols_in_scope(
|
|
|
263
277
|
visited.add(current_tab);
|
|
264
278
|
for (name, symbol) in current_tab.names_in_scope.items() {
|
|
265
279
|
if name not in dir(builtins) and symbol.sym_type != SymbolType.IMPL {
|
|
266
|
-
symbols.append(
|
|
267
|
-
|
|
280
|
+
symbols.append(
|
|
281
|
+
lspt.CompletionItem(label=name, kind=label_map(symbol.sym_type))
|
|
282
|
+
);
|
|
268
283
|
}
|
|
269
284
|
}
|
|
270
285
|
if not up_tree {
|
|
@@ -284,8 +299,12 @@ def collect_child_tabs(sym_tab: UniScopeNode) -> <>list[lspt.CompletionItem] {
|
|
|
284
299
|
symbols : <>list[lspt.CompletionItem] = [];
|
|
285
300
|
for tab in sym_tab.kid_scope {
|
|
286
301
|
if tab.scope_name not in [ i.label for i in symbols ] {
|
|
287
|
-
symbols.append(
|
|
288
|
-
|
|
302
|
+
symbols.append(
|
|
303
|
+
lspt.CompletionItem(
|
|
304
|
+
label=tab.scope_name,
|
|
305
|
+
kind=label_map(tab.get_type())
|
|
306
|
+
)
|
|
307
|
+
);
|
|
289
308
|
}
|
|
290
309
|
}
|
|
291
310
|
return symbols;
|
|
@@ -368,7 +387,9 @@ def find_surrounding_tokens(
|
|
|
368
387
|
prev_token_index = None;
|
|
369
388
|
next_token_index = None;
|
|
370
389
|
inside_tok = False;
|
|
371
|
-
for (i, tok) in enumerate(
|
|
390
|
+
for (i, tok) in enumerate(
|
|
391
|
+
[ get_token_start(i, sem_tokens) for i in range(0, len(sem_tokens), 5) ][ 0 : ]
|
|
392
|
+
) {
|
|
372
393
|
if (not (prev_token_index is None or next_token_index is None ))
|
|
373
394
|
and (tok[0] > change_end_line
|
|
374
395
|
or (tok[0] == change_end_line and tok[1] > change_end_char )
|
jaclang/runtimelib/archetype.py
CHANGED
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import inspect
|
|
6
5
|
from dataclasses import asdict, dataclass, field, fields, is_dataclass
|
|
7
6
|
from enum import IntEnum
|
|
8
7
|
from functools import cached_property
|
|
8
|
+
from inspect import _empty, signature
|
|
9
9
|
from logging import getLogger
|
|
10
10
|
from pickle import dumps
|
|
11
11
|
from types import UnionType
|
|
12
|
-
from typing import Any, Callable, ClassVar, Optional, TypeVar
|
|
12
|
+
from typing import Any, Callable, ClassVar, Optional, TypeAlias, TypeVar
|
|
13
13
|
from uuid import UUID, uuid4
|
|
14
14
|
|
|
15
|
+
from ..compiler.constant import EdgeDir
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
logger = getLogger(__name__)
|
|
17
19
|
|
|
18
20
|
TARCH = TypeVar("TARCH", bound="Archetype")
|
|
19
21
|
TANCH = TypeVar("TANCH", bound="Anchor")
|
|
22
|
+
T = TypeVar("T")
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
class AccessLevel(IntEnum):
|
|
@@ -66,6 +69,125 @@ class AnchorReport:
|
|
|
66
69
|
context: dict[str, Any]
|
|
67
70
|
|
|
68
71
|
|
|
72
|
+
DataSpatialFilter: TypeAlias = (
|
|
73
|
+
Callable[["Archetype"], bool] | "Archetype" | list["Archetype"] | None
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@dataclass(eq=False, repr=False)
|
|
78
|
+
class DataSpatialDestination:
|
|
79
|
+
"""Object-Spatial Destination."""
|
|
80
|
+
|
|
81
|
+
direction: EdgeDir
|
|
82
|
+
edge: Callable[["Archetype"], bool] | None = None
|
|
83
|
+
node: Callable[["Archetype"], bool] | None = None
|
|
84
|
+
|
|
85
|
+
def edge_filter(self, arch: Archetype) -> bool:
|
|
86
|
+
"""Filter edge."""
|
|
87
|
+
return not self.edge or self.edge(arch)
|
|
88
|
+
|
|
89
|
+
def node_filter(self, arch: Archetype) -> bool:
|
|
90
|
+
"""Filter node."""
|
|
91
|
+
return not self.node or self.node(arch)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass(eq=False, repr=False)
|
|
95
|
+
class DataSpatialPath:
|
|
96
|
+
"""Object-Spatial Path."""
|
|
97
|
+
|
|
98
|
+
origin: list[NodeArchetype]
|
|
99
|
+
destinations: list[DataSpatialDestination]
|
|
100
|
+
edge_only: bool
|
|
101
|
+
from_visit: bool
|
|
102
|
+
|
|
103
|
+
def __init__(
|
|
104
|
+
self,
|
|
105
|
+
origin: NodeArchetype | list[NodeArchetype],
|
|
106
|
+
destinations: list[DataSpatialDestination] | None = None,
|
|
107
|
+
) -> None:
|
|
108
|
+
"""Override Init."""
|
|
109
|
+
if not isinstance(origin, list):
|
|
110
|
+
origin = [origin]
|
|
111
|
+
self.origin = origin
|
|
112
|
+
self.destinations = [] if destinations is None else destinations
|
|
113
|
+
self.edge_only = False
|
|
114
|
+
self.from_visit = False
|
|
115
|
+
|
|
116
|
+
def convert(
|
|
117
|
+
self,
|
|
118
|
+
filter: DataSpatialFilter,
|
|
119
|
+
) -> Callable[["Archetype"], bool] | None:
|
|
120
|
+
"""Convert filter."""
|
|
121
|
+
if not filter:
|
|
122
|
+
return None
|
|
123
|
+
if callable(filter):
|
|
124
|
+
return filter
|
|
125
|
+
elif isinstance(filter, list):
|
|
126
|
+
return lambda i: i in filter
|
|
127
|
+
return lambda i: i == filter
|
|
128
|
+
|
|
129
|
+
def append(
|
|
130
|
+
self,
|
|
131
|
+
direction: EdgeDir,
|
|
132
|
+
edge: DataSpatialFilter,
|
|
133
|
+
node: DataSpatialFilter,
|
|
134
|
+
) -> DataSpatialPath:
|
|
135
|
+
"""Append destination."""
|
|
136
|
+
self.destinations.append(
|
|
137
|
+
DataSpatialDestination(direction, self.convert(edge), self.convert(node))
|
|
138
|
+
)
|
|
139
|
+
return self
|
|
140
|
+
|
|
141
|
+
def _out(
|
|
142
|
+
self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
|
|
143
|
+
) -> DataSpatialPath:
|
|
144
|
+
"""Override greater than function."""
|
|
145
|
+
return self.append(EdgeDir.OUT, edge, node)
|
|
146
|
+
|
|
147
|
+
def _in(
|
|
148
|
+
self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
|
|
149
|
+
) -> DataSpatialPath:
|
|
150
|
+
"""Override greater than function."""
|
|
151
|
+
return self.append(EdgeDir.IN, edge, node)
|
|
152
|
+
|
|
153
|
+
def _any(
|
|
154
|
+
self, edge: DataSpatialFilter = None, node: DataSpatialFilter = None
|
|
155
|
+
) -> DataSpatialPath:
|
|
156
|
+
"""Override greater than function."""
|
|
157
|
+
return self.append(EdgeDir.ANY, edge, node)
|
|
158
|
+
|
|
159
|
+
def edge(self) -> DataSpatialPath:
|
|
160
|
+
"""Set edge only."""
|
|
161
|
+
self.edge_only = True
|
|
162
|
+
return self
|
|
163
|
+
|
|
164
|
+
def visit(self) -> DataSpatialPath:
|
|
165
|
+
"""Set from visit."""
|
|
166
|
+
self.from_visit = True
|
|
167
|
+
return self
|
|
168
|
+
|
|
169
|
+
def repr_builder(self, repr: str, dest: DataSpatialDestination, mark: str) -> str:
|
|
170
|
+
"""Repr builder."""
|
|
171
|
+
repr += mark
|
|
172
|
+
repr += f' (edge{" filter" if dest.edge else ""}) '
|
|
173
|
+
repr += mark
|
|
174
|
+
repr += f' (node{" filter" if dest.node else ""}) '
|
|
175
|
+
return repr
|
|
176
|
+
|
|
177
|
+
def __repr__(self) -> str:
|
|
178
|
+
"""Override repr."""
|
|
179
|
+
repr = "nodes "
|
|
180
|
+
for dest in self.destinations:
|
|
181
|
+
match dest.direction:
|
|
182
|
+
case EdgeDir.IN:
|
|
183
|
+
repr = self.repr_builder(repr, dest, "<<")
|
|
184
|
+
case EdgeDir.OUT:
|
|
185
|
+
repr = self.repr_builder(repr, dest, ">>")
|
|
186
|
+
case _:
|
|
187
|
+
repr = self.repr_builder(repr, dest, "--")
|
|
188
|
+
return repr.strip()
|
|
189
|
+
|
|
190
|
+
|
|
69
191
|
@dataclass(eq=False, repr=False, kw_only=True)
|
|
70
192
|
class Anchor:
|
|
71
193
|
"""Object Anchor."""
|
|
@@ -223,7 +345,7 @@ class WalkerAnchor(Anchor):
|
|
|
223
345
|
|
|
224
346
|
archetype: WalkerArchetype
|
|
225
347
|
path: list[NodeAnchor] = field(default_factory=list)
|
|
226
|
-
next: list[NodeAnchor] = field(default_factory=list)
|
|
348
|
+
next: list[NodeAnchor | EdgeAnchor] = field(default_factory=list)
|
|
227
349
|
ignores: list[NodeAnchor] = field(default_factory=list)
|
|
228
350
|
disengaged: bool = False
|
|
229
351
|
|
|
@@ -329,7 +451,7 @@ class Root(NodeArchetype):
|
|
|
329
451
|
|
|
330
452
|
@dataclass(eq=False)
|
|
331
453
|
class DataSpatialFunction:
|
|
332
|
-
"""
|
|
454
|
+
"""Object-Spatial Function."""
|
|
333
455
|
|
|
334
456
|
name: str
|
|
335
457
|
func: Callable[[Any, Any], Any]
|
|
@@ -337,9 +459,9 @@ class DataSpatialFunction:
|
|
|
337
459
|
@cached_property
|
|
338
460
|
def trigger(self) -> type | UnionType | tuple[type | UnionType, ...] | None:
|
|
339
461
|
"""Get function parameter annotations."""
|
|
340
|
-
parameters =
|
|
462
|
+
parameters = signature(self.func, eval_str=True).parameters
|
|
341
463
|
if len(parameters) >= 2:
|
|
342
464
|
second_param = list(parameters.values())[1]
|
|
343
465
|
ty = second_param.annotation
|
|
344
|
-
return ty if ty !=
|
|
466
|
+
return ty if ty != _empty else None
|
|
345
467
|
return None
|
jaclang/runtimelib/builtin.py
CHANGED
|
@@ -10,10 +10,7 @@ from jaclang.runtimelib.constructs import Archetype, NodeArchetype, Root
|
|
|
10
10
|
from jaclang.runtimelib.machine import JacMachineInterface as Jac
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
# the existing code. Currently it can return the jac graph in both dot and json format.
|
|
15
|
-
# So the name shuouldn't be dotgen but something more generic.
|
|
16
|
-
def dotgen(
|
|
13
|
+
def printgraph(
|
|
17
14
|
node: Optional[NodeArchetype] = None,
|
|
18
15
|
depth: int = -1,
|
|
19
16
|
traverse: bool = False,
|
|
@@ -21,16 +18,17 @@ def dotgen(
|
|
|
21
18
|
bfs: bool = True,
|
|
22
19
|
edge_limit: int = 512,
|
|
23
20
|
node_limit: int = 512,
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
file: Optional[str] = None,
|
|
22
|
+
format: str = "dot",
|
|
26
23
|
) -> str:
|
|
27
|
-
"""Print the
|
|
24
|
+
"""Print the graph in different formats."""
|
|
28
25
|
from jaclang.runtimelib.machine import JacMachineInterface as Jac
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
fmt = format.lower()
|
|
28
|
+
if fmt == "json":
|
|
29
|
+
return _jac_graph_json(file)
|
|
32
30
|
|
|
33
|
-
return Jac.
|
|
31
|
+
return Jac.printgraph(
|
|
34
32
|
edge_type=edge_type,
|
|
35
33
|
node=node or Jac.root(),
|
|
36
34
|
depth=depth,
|
|
@@ -38,7 +36,8 @@ def dotgen(
|
|
|
38
36
|
bfs=bfs,
|
|
39
37
|
edge_limit=edge_limit,
|
|
40
38
|
node_limit=node_limit,
|
|
41
|
-
|
|
39
|
+
file=file,
|
|
40
|
+
format=fmt,
|
|
42
41
|
)
|
|
43
42
|
|
|
44
43
|
|
|
@@ -52,7 +51,7 @@ def jobj(id: str) -> Archetype | None:
|
|
|
52
51
|
return Jac.get_object(id)
|
|
53
52
|
|
|
54
53
|
|
|
55
|
-
def _jac_graph_json() -> str:
|
|
54
|
+
def _jac_graph_json(file: Optional[str] = None) -> str:
|
|
56
55
|
"""Get the graph in json string."""
|
|
57
56
|
processed: list[Root | NodeArchetype] = []
|
|
58
57
|
nodes: list[dict] = []
|
|
@@ -73,20 +72,24 @@ def _jac_graph_json() -> str:
|
|
|
73
72
|
for ref in Jac.refs(end):
|
|
74
73
|
if ref not in processed:
|
|
75
74
|
working_set.append((end, ref))
|
|
76
|
-
|
|
75
|
+
output = json.dumps(
|
|
77
76
|
{
|
|
78
77
|
"version": "1.0",
|
|
79
78
|
"nodes": nodes,
|
|
80
79
|
"edges": edges,
|
|
81
80
|
}
|
|
82
81
|
)
|
|
82
|
+
if file:
|
|
83
|
+
with open(file, "w") as f:
|
|
84
|
+
f.write(output)
|
|
85
|
+
return output
|
|
83
86
|
|
|
84
87
|
|
|
85
88
|
__all__ = [
|
|
86
89
|
"abstractmethod",
|
|
87
90
|
"ClassVar",
|
|
88
91
|
"override",
|
|
89
|
-
"
|
|
92
|
+
"printgraph",
|
|
90
93
|
"jid",
|
|
91
94
|
"jobj",
|
|
92
95
|
]
|