jaclang 0.7.27__py3-none-any.whl → 0.7.30__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 +3 -0
- jaclang/compiler/__init__.py +1 -1
- jaclang/compiler/absyntree.py +30 -5
- jaclang/compiler/compile.py +1 -1
- jaclang/compiler/constant.py +0 -1
- jaclang/compiler/jac.lark +1 -5
- jaclang/compiler/parser.py +2 -10
- jaclang/compiler/passes/main/__init__.py +1 -1
- jaclang/compiler/passes/main/access_modifier_pass.py +1 -1
- jaclang/compiler/passes/main/fuse_typeinfo_pass.py +62 -33
- jaclang/compiler/passes/main/import_pass.py +285 -64
- jaclang/compiler/passes/main/inheritance_pass.py +103 -0
- jaclang/compiler/passes/main/py_collect_dep_pass.py +5 -5
- jaclang/compiler/passes/main/pyast_gen_pass.py +0 -19
- jaclang/compiler/passes/main/pyast_load_pass.py +1 -1
- jaclang/compiler/passes/main/schedules.py +2 -0
- jaclang/compiler/passes/main/sym_tab_build_pass.py +17 -0
- jaclang/compiler/passes/main/tests/fixtures/data_spatial_types.jac +130 -0
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.py +3 -3
- jaclang/compiler/passes/main/tests/fixtures/pygame_mock/__init__.pyi +3 -3
- jaclang/compiler/passes/main/tests/test_import_pass.py +16 -17
- jaclang/compiler/passes/main/tests/test_type_check_pass.py +24 -0
- jaclang/compiler/passes/main/type_check_pass.py +3 -2
- jaclang/compiler/passes/tool/jac_formatter_pass.py +0 -1
- jaclang/compiler/py_info.py +22 -0
- jaclang/compiler/symtable.py +9 -2
- jaclang/compiler/tests/test_importer.py +45 -1
- jaclang/langserve/tests/test_server.py +2 -2
- jaclang/plugin/default.py +86 -62
- jaclang/plugin/feature.py +2 -5
- jaclang/plugin/spec.py +1 -6
- jaclang/runtimelib/architype.py +20 -16
- jaclang/runtimelib/importer.py +26 -3
- jaclang/runtimelib/machine.py +2 -2
- jaclang/runtimelib/test.py +59 -4
- jaclang/runtimelib/utils.py +15 -0
- jaclang/settings.py +3 -0
- jaclang/tests/fixtures/base_class1.jac +11 -0
- jaclang/tests/fixtures/base_class2.jac +11 -0
- jaclang/tests/fixtures/import_all.jac +7 -0
- jaclang/tests/fixtures/import_all_py.py +8 -0
- jaclang/tests/fixtures/jactest_imported.jac +6 -0
- jaclang/tests/fixtures/jactest_main.jac +22 -0
- jaclang/tests/fixtures/multi_dim_array_split.jac +2 -6
- jaclang/tests/fixtures/test_py.py +12 -0
- jaclang/tests/fixtures/visit_sequence.jac +50 -0
- jaclang/tests/test_cli.py +83 -1
- jaclang/tests/test_language.py +24 -9
- jaclang/utils/helpers.py +9 -1
- jaclang/utils/test.py +2 -2
- jaclang/utils/tests/test_lang_tools.py +4 -2
- jaclang/utils/treeprinter.py +6 -3
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/METADATA +3 -3
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/RECORD +56 -45
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/WHEEL +1 -1
- {jaclang-0.7.27.dist-info → jaclang-0.7.30.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
node NodeA {
|
|
2
|
+
has value: int = 10;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
node NodeC {
|
|
6
|
+
has value: int = 10;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
edge EdgeB {
|
|
10
|
+
has value: int = 20;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
with entry {
|
|
14
|
+
node_1 = a(value=5);
|
|
15
|
+
node_2 = a();
|
|
16
|
+
node_3 = a(value=15);
|
|
17
|
+
node_4 = a(value=20);
|
|
18
|
+
node_5 = c(value=25);
|
|
19
|
+
print(type(root ++> node_1));
|
|
20
|
+
node_1 +:edge_1 := b(value=5):+> node_2;
|
|
21
|
+
node_1 +:edge_2 := b(value=10):+> node_3;
|
|
22
|
+
node_1 +:edge_3 := b(value=15):+> node_4;
|
|
23
|
+
node_1 +:edge_4 := b():+> node_5;
|
|
24
|
+
node_1 del--> node_2;
|
|
25
|
+
del node_3;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
node A {
|
|
30
|
+
has val: int = 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
edge a {}
|
|
34
|
+
|
|
35
|
+
walker W {
|
|
36
|
+
can create with `root entry;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:walker:W:can:create {
|
|
40
|
+
Start = A(5);
|
|
41
|
+
here +:a:+> Start;
|
|
42
|
+
Start +:a:+> A(10) +:a:+> A(15);
|
|
43
|
+
Start +:a:+> A(20) +:a:+> A(25);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
with entry {
|
|
47
|
+
root spawn W();
|
|
48
|
+
print([root-->-->(`?A)]);
|
|
49
|
+
print([root-->-->-->(`?A)]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
"""Bubble sort using DS Features of Jac (somparision and swapping happens in inner nodes)."""
|
|
53
|
+
glob list1 = [80, 79, 60, 59, 40, 35, 19, 1];
|
|
54
|
+
|
|
55
|
+
node main_node {
|
|
56
|
+
has no: int = 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
node inner_node {
|
|
60
|
+
has main: int = 0,
|
|
61
|
+
sub: int = 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
walker walker1 {
|
|
65
|
+
can create_main_node with `root entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:walker:walker1:can:create_main_node {
|
|
69
|
+
end = here;
|
|
70
|
+
for i=0 to i<len(list1)+1 by i+=1 {
|
|
71
|
+
end ++> (end := main_node(no=i + 1));
|
|
72
|
+
visit [-->];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
walker walker2 {
|
|
77
|
+
can skip_root with `root entry {
|
|
78
|
+
visit [-->];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
can process with main_node entry;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:walker:walker2:can:process {
|
|
85
|
+
:g: list1 ;
|
|
86
|
+
|
|
87
|
+
for j in range(0, len(list1) - (here.no)) {
|
|
88
|
+
here ++> inner_node(main=here.no, sub=j + 1);
|
|
89
|
+
}
|
|
90
|
+
visit [-->];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
walker walker3 {
|
|
94
|
+
can skiproot with `root entry {
|
|
95
|
+
visit [-->];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
can adjust with main_node entry;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:walker:walker3:can:adjust {
|
|
102
|
+
here spawn walker4();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
walker walker4 {
|
|
106
|
+
can skipmain with main_node entry {
|
|
107
|
+
visit [-->];# print(f"iteration {here.no} started {list1}");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
can skipin with inner_node entry {
|
|
111
|
+
:g: list1 ;
|
|
112
|
+
|
|
113
|
+
j = here.sub - 1;
|
|
114
|
+
if list1[j] > list1[j + 1] {
|
|
115
|
+
x = list1[j];
|
|
116
|
+
list1[j] = list1[j + 1];
|
|
117
|
+
list1[j + 1] = x;
|
|
118
|
+
}
|
|
119
|
+
#uncomment below to see the swap in each inner nodes
|
|
120
|
+
# print(list1);
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
with entry {
|
|
126
|
+
root spawn walker1();
|
|
127
|
+
root spawn walker2();
|
|
128
|
+
root spawn walker3();
|
|
129
|
+
print(Jac.node_dot(root));
|
|
130
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .display import
|
|
2
|
-
from .color import
|
|
3
|
-
from .constants import
|
|
1
|
+
from .display import set_mode
|
|
2
|
+
from .color import Color
|
|
3
|
+
from .constants import CONST_VALUE, CL
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
from .display import
|
|
2
|
-
from .color import
|
|
3
|
-
from .constants import
|
|
1
|
+
from .display import set_mode
|
|
2
|
+
from .color import Color
|
|
3
|
+
from .constants import CONST_VALUE, CL
|
|
@@ -81,39 +81,38 @@ class ImportPassPassTests(TestCase):
|
|
|
81
81
|
"genericpath": r"jaclang/vendor/mypy/typeshed/stdlib/genericpath.pyi$",
|
|
82
82
|
}
|
|
83
83
|
for i in p:
|
|
84
|
-
self.assertIn(i, build.ir.py_raise_map)
|
|
85
|
-
self.assertRegex(
|
|
84
|
+
self.assertIn(i, build.ir.py_info.py_raise_map)
|
|
85
|
+
self.assertRegex(
|
|
86
|
+
re.sub(r".*fixtures/", "", build.ir.py_info.py_raise_map[i]).replace(
|
|
87
|
+
"\\", "/"
|
|
88
|
+
),
|
|
89
|
+
p[i],
|
|
90
|
+
)
|
|
86
91
|
|
|
87
92
|
def test_py_raised_mods(self) -> None:
|
|
88
93
|
"""Basic test for pass."""
|
|
89
94
|
state = jac_file_to_pass(
|
|
90
95
|
self.fixture_abs_path("py_imp_test.jac"), schedule=py_code_gen_typed
|
|
91
96
|
)
|
|
97
|
+
for i in list(
|
|
98
|
+
filter(
|
|
99
|
+
lambda x: x.py_info.is_raised_from_py,
|
|
100
|
+
state.ir.get_all_sub_nodes(ast.Module),
|
|
101
|
+
)
|
|
102
|
+
):
|
|
103
|
+
print(ast.Module.get_href_path(i))
|
|
92
104
|
self.assertEqual(
|
|
93
105
|
len(
|
|
94
106
|
list(
|
|
95
107
|
filter(
|
|
96
|
-
lambda x: x.is_raised_from_py,
|
|
108
|
+
lambda x: x.py_info.is_raised_from_py,
|
|
97
109
|
state.ir.get_all_sub_nodes(ast.Module),
|
|
98
110
|
)
|
|
99
111
|
)
|
|
100
112
|
),
|
|
101
|
-
|
|
113
|
+
11, # TODO: Need to only link the modules one time
|
|
102
114
|
)
|
|
103
115
|
|
|
104
|
-
# def test_py_resolve_list(self) -> None:
|
|
105
|
-
# """Basic test for pass."""
|
|
106
|
-
# state: JacImportPass = jac_file_to_pass(
|
|
107
|
-
# self.examples_abs_path("rpg_game/jac_impl/jac_impl_5/main.jac"),
|
|
108
|
-
# JacImportPass,
|
|
109
|
-
# )
|
|
110
|
-
# self.assertGreater(len(state.py_resolve_list), 20)
|
|
111
|
-
# self.assertIn("pygame.sprite.Sprite.__init__", state.py_resolve_list)
|
|
112
|
-
# self.assertIn("pygame.mouse.get_pressed", state.py_resolve_list)
|
|
113
|
-
# self.assertIn("pygame.K_SPACE", state.py_resolve_list)
|
|
114
|
-
# self.assertIn("random.randint", state.py_resolve_list)
|
|
115
|
-
# self.assertIn("pygame.font.Font", state.py_resolve_list)
|
|
116
|
-
|
|
117
116
|
def test_double_empty_anx(self) -> None:
|
|
118
117
|
"""Test importing python."""
|
|
119
118
|
captured_output = io.StringIO()
|
|
@@ -62,3 +62,27 @@ class MypyTypeCheckPassTests(TestCase):
|
|
|
62
62
|
self.assertEqual(out.count("Type: builtins.str"), 35)
|
|
63
63
|
for i in lis:
|
|
64
64
|
self.assertNotIn(i, out)
|
|
65
|
+
|
|
66
|
+
def test_data_spatial_type_info(self) -> None:
|
|
67
|
+
"""Testing for type info for dataspatial constructs."""
|
|
68
|
+
out = AstTool().ir(
|
|
69
|
+
["ast", f"{self.fixture_abs_path('data_spatial_types.jac')}"]
|
|
70
|
+
)
|
|
71
|
+
self.assertRegex(
|
|
72
|
+
out,
|
|
73
|
+
r"129:24 - 129:28.*SpecialVarRef - _Jac.get_root\(\) \- Type\: jaclang.runtimelib.architype.Root",
|
|
74
|
+
)
|
|
75
|
+
self.assertRegex(out, r"129:11 - 129:29.*FuncCall \- Type\: builtins\.str")
|
|
76
|
+
self.assertRegex(
|
|
77
|
+
out,
|
|
78
|
+
r"129:15 - 129:23.*Name \- node_dot \- Type\: builtins.str, SymbolTable\: str",
|
|
79
|
+
)
|
|
80
|
+
self.assertRegex(
|
|
81
|
+
out,
|
|
82
|
+
r"128:5 - 128:25.*BinaryExpr \- Type\: jaclang.runtimelib.architype.WalkerArchitype",
|
|
83
|
+
)
|
|
84
|
+
self.assertRegex(
|
|
85
|
+
out,
|
|
86
|
+
r"48:11 - 48:28.*EdgeRefTrailer \- Type\: builtins.list\[data_spatial_types.A\]",
|
|
87
|
+
)
|
|
88
|
+
self.assertRegex(out, r"24:5 - 24:25.*BinaryExpr \- Type\: builtins.bool", out)
|
|
@@ -115,13 +115,14 @@ class JacTypeCheckPass(Pass):
|
|
|
115
115
|
for k, v in mypy_graph.items()
|
|
116
116
|
if (
|
|
117
117
|
k.startswith("jaclang.plugin")
|
|
118
|
+
or k.startswith("jaclang.runtimelib")
|
|
118
119
|
or not (k.startswith("jaclang.") or k.startswith("mypy."))
|
|
119
120
|
)
|
|
120
121
|
}
|
|
121
122
|
for i in mypy_graph:
|
|
122
|
-
self.ir.py_mod_dep_map[i] = mypy_graph[i].xpath
|
|
123
|
+
self.ir.py_info.py_mod_dep_map[i] = mypy_graph[i].xpath
|
|
123
124
|
for j in mypy_graph[i].dependencies:
|
|
124
|
-
self.ir.py_mod_dep_map[j] = str(
|
|
125
|
+
self.ir.py_info.py_mod_dep_map[j] = str(
|
|
125
126
|
myab.find_module_with_reason(j, manager)
|
|
126
127
|
)
|
|
127
128
|
myab.process_graph(mypy_graph, manager)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Code location info for AST nodes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PyInfo:
|
|
7
|
+
"""Python info related to python imports."""
|
|
8
|
+
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
"""Object Initialization."""
|
|
11
|
+
# Module dependacy map used to store all module dependacies detected
|
|
12
|
+
# by mypy. The dependacies are computed using the mypy graph in
|
|
13
|
+
# TypeCheck pass
|
|
14
|
+
self.py_mod_dep_map: dict[str, str] = {}
|
|
15
|
+
|
|
16
|
+
# Get all the modules that we really need to raise inorder to make
|
|
17
|
+
# all Jac types correct (FuseTypeInfo works). This is computed using
|
|
18
|
+
# PyCollectDepsPass.
|
|
19
|
+
self.py_raise_map: dict[str, str] = {}
|
|
20
|
+
|
|
21
|
+
# Flag for python modules raised into jac
|
|
22
|
+
self.is_raised_from_py: bool = False
|
jaclang/compiler/symtable.py
CHANGED
|
@@ -115,6 +115,7 @@ class SymbolTable:
|
|
|
115
115
|
node: ast.AstSymbolNode,
|
|
116
116
|
access_spec: Optional[ast.AstAccessNode] | SymbolAccess = None,
|
|
117
117
|
single: bool = False,
|
|
118
|
+
force_overwrite: bool = False,
|
|
118
119
|
) -> Optional[ast.AstNode]:
|
|
119
120
|
"""Set a variable in the symbol table.
|
|
120
121
|
|
|
@@ -126,7 +127,7 @@ class SymbolTable:
|
|
|
126
127
|
if single and node.sym_name in self.tab
|
|
127
128
|
else None
|
|
128
129
|
)
|
|
129
|
-
if node.sym_name not in self.tab:
|
|
130
|
+
if force_overwrite or node.sym_name not in self.tab:
|
|
130
131
|
self.tab[node.sym_name] = Symbol(
|
|
131
132
|
defn=node.name_spec,
|
|
132
133
|
access=(
|
|
@@ -163,11 +164,17 @@ class SymbolTable:
|
|
|
163
164
|
node: ast.AstSymbolNode,
|
|
164
165
|
access_spec: Optional[ast.AstAccessNode] | SymbolAccess = None,
|
|
165
166
|
single_decl: Optional[str] = None,
|
|
167
|
+
force_overwrite: bool = False,
|
|
166
168
|
) -> Optional[Symbol]:
|
|
167
169
|
"""Insert into symbol table."""
|
|
168
170
|
if node.sym and self == node.sym.parent_tab:
|
|
169
171
|
return node.sym
|
|
170
|
-
self.insert(
|
|
172
|
+
self.insert(
|
|
173
|
+
node=node,
|
|
174
|
+
single=single_decl is not None,
|
|
175
|
+
access_spec=access_spec,
|
|
176
|
+
force_overwrite=force_overwrite,
|
|
177
|
+
)
|
|
171
178
|
self.update_py_ctx_for_def(node)
|
|
172
179
|
return node.sym
|
|
173
180
|
|
|
@@ -33,7 +33,7 @@ class TestLoader(TestCase):
|
|
|
33
33
|
)
|
|
34
34
|
self.assertIn(
|
|
35
35
|
"/tests/fixtures/hello_world.jac",
|
|
36
|
-
str(JacMachine.get().loaded_modules),
|
|
36
|
+
str(JacMachine.get().loaded_modules).replace("\\\\", "/"),
|
|
37
37
|
)
|
|
38
38
|
JacMachine.detach()
|
|
39
39
|
|
|
@@ -62,3 +62,47 @@ class TestLoader(TestCase):
|
|
|
62
62
|
"{SomeObj(a=10): 'check'} [MyObj(apple=5, banana=7), MyObj(apple=5, banana=7)]",
|
|
63
63
|
stdout_value,
|
|
64
64
|
)
|
|
65
|
+
|
|
66
|
+
def test_import_with_jacpath(self) -> None:
|
|
67
|
+
"""Test module import using JACPATH."""
|
|
68
|
+
# Set up a temporary JACPATH environment variable
|
|
69
|
+
import os
|
|
70
|
+
import tempfile
|
|
71
|
+
|
|
72
|
+
jacpath_dir = tempfile.TemporaryDirectory()
|
|
73
|
+
os.environ["JACPATH"] = jacpath_dir.name
|
|
74
|
+
|
|
75
|
+
# Create a mock Jac file in the JACPATH directory
|
|
76
|
+
module_name = "test_module"
|
|
77
|
+
jac_file_path = os.path.join(jacpath_dir.name, f"{module_name}.jac")
|
|
78
|
+
with open(jac_file_path, "w") as f:
|
|
79
|
+
f.write(
|
|
80
|
+
"""
|
|
81
|
+
with entry {
|
|
82
|
+
"Hello from JACPATH!" :> print;
|
|
83
|
+
}
|
|
84
|
+
"""
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Capture the output
|
|
88
|
+
captured_output = io.StringIO()
|
|
89
|
+
sys.stdout = captured_output
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
JacMachine(self.fixture_abs_path(__file__)).attach_program(
|
|
93
|
+
JacProgram(mod_bundle=None, bytecode=None, sem_ir=None)
|
|
94
|
+
)
|
|
95
|
+
jac_import(module_name, base_path=__file__)
|
|
96
|
+
cli.run(jac_file_path)
|
|
97
|
+
|
|
98
|
+
# Reset stdout and get the output
|
|
99
|
+
sys.stdout = sys.__stdout__
|
|
100
|
+
stdout_value = captured_output.getvalue()
|
|
101
|
+
|
|
102
|
+
self.assertIn("Hello from JACPATH!", stdout_value)
|
|
103
|
+
|
|
104
|
+
finally:
|
|
105
|
+
captured_output.close()
|
|
106
|
+
JacMachine.detach()
|
|
107
|
+
os.environ.pop("JACPATH", None)
|
|
108
|
+
jacpath_dir.cleanup()
|
|
@@ -330,7 +330,7 @@ class TestJacLangServer(TestCase):
|
|
|
330
330
|
"doubleinner",
|
|
331
331
|
"apply_red",
|
|
332
332
|
],
|
|
333
|
-
|
|
333
|
+
11,
|
|
334
334
|
),
|
|
335
335
|
(
|
|
336
336
|
lspt.Position(65, 23),
|
|
@@ -359,7 +359,7 @@ class TestJacLangServer(TestCase):
|
|
|
359
359
|
"doubleinner",
|
|
360
360
|
"apply_red",
|
|
361
361
|
],
|
|
362
|
-
|
|
362
|
+
11,
|
|
363
363
|
),
|
|
364
364
|
(
|
|
365
365
|
lspt.Position(73, 22),
|
jaclang/plugin/default.py
CHANGED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import ast as ast3
|
|
6
6
|
import fnmatch
|
|
7
7
|
import html
|
|
8
|
+
import inspect
|
|
8
9
|
import os
|
|
9
10
|
import types
|
|
10
11
|
from collections import OrderedDict
|
|
@@ -42,8 +43,11 @@ from jaclang.runtimelib.constructs import (
|
|
|
42
43
|
from jaclang.runtimelib.importer import ImportPathSpec, JacImporter, PythonImporter
|
|
43
44
|
from jaclang.runtimelib.machine import JacMachine, JacProgram
|
|
44
45
|
from jaclang.runtimelib.memory import Shelf, ShelfStorage
|
|
45
|
-
from jaclang.runtimelib.utils import
|
|
46
|
-
|
|
46
|
+
from jaclang.runtimelib.utils import (
|
|
47
|
+
all_issubclass,
|
|
48
|
+
collect_node_connections,
|
|
49
|
+
traverse_graph,
|
|
50
|
+
)
|
|
47
51
|
|
|
48
52
|
import pluggy
|
|
49
53
|
|
|
@@ -175,14 +179,12 @@ class JacAccessValidationImpl:
|
|
|
175
179
|
if to_root.access.all > access_level:
|
|
176
180
|
access_level = to_root.access.all
|
|
177
181
|
|
|
178
|
-
level
|
|
179
|
-
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
182
|
+
if (level := to_root.access.roots.check(str(jroot.id))) is not None:
|
|
180
183
|
access_level = level
|
|
181
184
|
|
|
182
185
|
# if target anchor have set allowed roots
|
|
183
186
|
# if current root is allowed to target anchor
|
|
184
|
-
level
|
|
185
|
-
if level > AccessLevel.NO_ACCESS and access_level == AccessLevel.NO_ACCESS:
|
|
187
|
+
if (level := to_access.roots.check(str(jroot.id))) is not None:
|
|
186
188
|
access_level = level
|
|
187
189
|
|
|
188
190
|
return access_level
|
|
@@ -398,64 +400,85 @@ class JacWalkerImpl:
|
|
|
398
400
|
|
|
399
401
|
walker.path = []
|
|
400
402
|
walker.next = [node]
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
403
|
+
current_node = node.architype
|
|
404
|
+
|
|
405
|
+
# walker entry
|
|
406
|
+
for i in warch._jac_entry_funcs_:
|
|
407
|
+
if i.func and not i.trigger:
|
|
408
|
+
i.func(warch, current_node)
|
|
409
|
+
if walker.disengaged:
|
|
410
|
+
return warch
|
|
411
|
+
|
|
410
412
|
while len(walker.next):
|
|
411
413
|
if current_node := walker.next.pop(0).architype:
|
|
414
|
+
# walker entry with
|
|
415
|
+
for i in warch._jac_entry_funcs_:
|
|
416
|
+
if (
|
|
417
|
+
i.func
|
|
418
|
+
and i.trigger
|
|
419
|
+
and all_issubclass(i.trigger, NodeArchitype)
|
|
420
|
+
and isinstance(current_node, i.trigger)
|
|
421
|
+
):
|
|
422
|
+
i.func(warch, current_node)
|
|
423
|
+
if walker.disengaged:
|
|
424
|
+
return warch
|
|
425
|
+
|
|
426
|
+
# node entry
|
|
412
427
|
for i in current_node._jac_entry_funcs_:
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if i.func:
|
|
416
|
-
i.func(current_node, warch)
|
|
417
|
-
else:
|
|
418
|
-
raise ValueError(f"No function {i.name} to call.")
|
|
428
|
+
if i.func and not i.trigger:
|
|
429
|
+
i.func(current_node, warch)
|
|
419
430
|
if walker.disengaged:
|
|
420
431
|
return warch
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
432
|
+
|
|
433
|
+
# node entry with
|
|
434
|
+
for i in current_node._jac_entry_funcs_:
|
|
435
|
+
if (
|
|
436
|
+
i.func
|
|
437
|
+
and i.trigger
|
|
438
|
+
and all_issubclass(i.trigger, WalkerArchitype)
|
|
439
|
+
and isinstance(warch, i.trigger)
|
|
440
|
+
):
|
|
441
|
+
i.func(current_node, warch)
|
|
430
442
|
if walker.disengaged:
|
|
431
443
|
return warch
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
444
|
+
|
|
445
|
+
# node exit with
|
|
446
|
+
for i in current_node._jac_exit_funcs_:
|
|
447
|
+
if (
|
|
448
|
+
i.func
|
|
449
|
+
and i.trigger
|
|
450
|
+
and all_issubclass(i.trigger, WalkerArchitype)
|
|
451
|
+
and isinstance(warch, i.trigger)
|
|
452
|
+
):
|
|
453
|
+
i.func(current_node, warch)
|
|
441
454
|
if walker.disengaged:
|
|
442
455
|
return warch
|
|
456
|
+
|
|
457
|
+
# node exit
|
|
443
458
|
for i in current_node._jac_exit_funcs_:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
459
|
+
if i.func and not i.trigger:
|
|
460
|
+
i.func(current_node, warch)
|
|
461
|
+
if walker.disengaged:
|
|
462
|
+
return warch
|
|
463
|
+
|
|
464
|
+
# walker exit with
|
|
465
|
+
for i in warch._jac_exit_funcs_:
|
|
466
|
+
if (
|
|
467
|
+
i.func
|
|
468
|
+
and i.trigger
|
|
469
|
+
and all_issubclass(i.trigger, NodeArchitype)
|
|
470
|
+
and isinstance(current_node, i.trigger)
|
|
471
|
+
):
|
|
472
|
+
i.func(warch, current_node)
|
|
450
473
|
if walker.disengaged:
|
|
451
474
|
return warch
|
|
475
|
+
# walker exit
|
|
452
476
|
for i in warch._jac_exit_funcs_:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
raise ValueError(f"No function {i.name} to call.")
|
|
477
|
+
if i.func and not i.trigger:
|
|
478
|
+
i.func(warch, current_node)
|
|
479
|
+
if walker.disengaged:
|
|
480
|
+
return warch
|
|
481
|
+
|
|
459
482
|
walker.ignores = []
|
|
460
483
|
return warch
|
|
461
484
|
|
|
@@ -818,12 +841,14 @@ class JacFeatureImpl(
|
|
|
818
841
|
@hookimpl
|
|
819
842
|
def create_test(test_fun: Callable) -> Callable:
|
|
820
843
|
"""Create a new test."""
|
|
844
|
+
file_path = inspect.getfile(test_fun)
|
|
845
|
+
func_name = test_fun.__name__
|
|
821
846
|
|
|
822
847
|
def test_deco() -> None:
|
|
823
848
|
test_fun(JacTestCheck())
|
|
824
849
|
|
|
825
850
|
test_deco.__name__ = test_fun.__name__
|
|
826
|
-
JacTestCheck.add_test(test_deco)
|
|
851
|
+
JacTestCheck.add_test(file_path, func_name, test_deco)
|
|
827
852
|
|
|
828
853
|
return test_deco
|
|
829
854
|
|
|
@@ -831,6 +856,7 @@ class JacFeatureImpl(
|
|
|
831
856
|
@hookimpl
|
|
832
857
|
def run_test(
|
|
833
858
|
filepath: str,
|
|
859
|
+
func_name: Optional[str],
|
|
834
860
|
filter: Optional[str],
|
|
835
861
|
xit: bool,
|
|
836
862
|
maxfail: Optional[int],
|
|
@@ -849,7 +875,9 @@ class JacFeatureImpl(
|
|
|
849
875
|
mod_name = mod_name[:-5]
|
|
850
876
|
JacTestCheck.reset()
|
|
851
877
|
Jac.jac_import(target=mod_name, base_path=base, cachable=False)
|
|
852
|
-
JacTestCheck.run_test(
|
|
878
|
+
JacTestCheck.run_test(
|
|
879
|
+
xit, maxfail, verbose, os.path.abspath(filepath), func_name
|
|
880
|
+
)
|
|
853
881
|
ret_count = JacTestCheck.failcount
|
|
854
882
|
else:
|
|
855
883
|
print("Not a .jac file.")
|
|
@@ -875,7 +903,9 @@ class JacFeatureImpl(
|
|
|
875
903
|
print(f"\n\n\t\t* Inside {root_dir}" + "/" + f"{file} *")
|
|
876
904
|
JacTestCheck.reset()
|
|
877
905
|
Jac.jac_import(target=file[:-4], base_path=root_dir)
|
|
878
|
-
JacTestCheck.run_test(
|
|
906
|
+
JacTestCheck.run_test(
|
|
907
|
+
xit, maxfail, verbose, os.path.abspath(file), func_name
|
|
908
|
+
)
|
|
879
909
|
|
|
880
910
|
if JacTestCheck.breaker and (xit or maxfail):
|
|
881
911
|
break
|
|
@@ -888,12 +918,6 @@ class JacFeatureImpl(
|
|
|
888
918
|
|
|
889
919
|
return ret_count
|
|
890
920
|
|
|
891
|
-
@staticmethod
|
|
892
|
-
@hookimpl
|
|
893
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
894
|
-
"""Jac's elvis operator feature."""
|
|
895
|
-
return ret if (ret := op1) is not None else op2
|
|
896
|
-
|
|
897
921
|
@staticmethod
|
|
898
922
|
@hookimpl
|
|
899
923
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
|
@@ -1000,7 +1024,7 @@ class JacFeatureImpl(
|
|
|
1000
1024
|
dir in [EdgeDir.OUT, EdgeDir.ANY]
|
|
1001
1025
|
and node == source
|
|
1002
1026
|
and target.architype in right
|
|
1003
|
-
and Jac.
|
|
1027
|
+
and Jac.check_connect_access(target)
|
|
1004
1028
|
):
|
|
1005
1029
|
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
1006
1030
|
disconnect_occurred = True
|
|
@@ -1008,7 +1032,7 @@ class JacFeatureImpl(
|
|
|
1008
1032
|
dir in [EdgeDir.IN, EdgeDir.ANY]
|
|
1009
1033
|
and node == target
|
|
1010
1034
|
and source.architype in right
|
|
1011
|
-
and Jac.
|
|
1035
|
+
and Jac.check_connect_access(source)
|
|
1012
1036
|
):
|
|
1013
1037
|
Jac.destroy(anchor) if anchor.persistent else Jac.detach(anchor)
|
|
1014
1038
|
disconnect_occurred = True
|
jaclang/plugin/feature.py
CHANGED
|
@@ -359,6 +359,7 @@ class JacFeature(
|
|
|
359
359
|
@staticmethod
|
|
360
360
|
def run_test(
|
|
361
361
|
filepath: str,
|
|
362
|
+
func_name: Optional[str] = None,
|
|
362
363
|
filter: Optional[str] = None,
|
|
363
364
|
xit: bool = False,
|
|
364
365
|
maxfail: Optional[int] = None,
|
|
@@ -368,6 +369,7 @@ class JacFeature(
|
|
|
368
369
|
"""Run the test suite in the specified .jac file."""
|
|
369
370
|
return plugin_manager.hook.run_test(
|
|
370
371
|
filepath=filepath,
|
|
372
|
+
func_name=func_name,
|
|
371
373
|
filter=filter,
|
|
372
374
|
xit=xit,
|
|
373
375
|
maxfail=maxfail,
|
|
@@ -375,11 +377,6 @@ class JacFeature(
|
|
|
375
377
|
verbose=verbose,
|
|
376
378
|
)
|
|
377
379
|
|
|
378
|
-
@staticmethod
|
|
379
|
-
def elvis(op1: Optional[T], op2: T) -> T:
|
|
380
|
-
"""Jac's elvis operator feature."""
|
|
381
|
-
return plugin_manager.hook.elvis(op1=op1, op2=op2)
|
|
382
|
-
|
|
383
380
|
@staticmethod
|
|
384
381
|
def has_instance_default(gen_func: Callable[[], T]) -> T:
|
|
385
382
|
"""Jac's has container default feature."""
|