jaseci 1.4.0.18__py3-none-any.whl → 1.4.0.20__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 jaseci might be problematic. Click here for more details.
- jaseci/VERSION +1 -1
- jaseci/cli_tools/jsctl.py +41 -2
- jaseci/cli_tools/tests/test_jsctl.py +11 -0
- jaseci/extens/act_lib/internal.py +2 -1
- jaseci/extens/act_lib/std.py +7 -0
- jaseci/extens/act_lib/tests/test_std_lib.py +3 -1
- jaseci/extens/api/jsorc_api.py +41 -1
- jaseci/extens/api/walker_api.py +9 -0
- jaseci/jac/interpreter/architype_interp.py +63 -28
- jaseci/jac/interpreter/interp.py +54 -158
- jaseci/jac/interpreter/sentinel_interp.py +73 -5
- jaseci/jac/interpreter/walker_interp.py +27 -38
- jaseci/jac/ir/ast.py +9 -1
- jaseci/jac/jac.g4 +5 -4
- jaseci/jac/jac_parse/jacListener.py +8 -8
- jaseci/jac/jac_parse/jacParser.py +1167 -1154
- jaseci/jac/machine/jac_scope.py +23 -30
- jaseci/jac/machine/machine_state.py +76 -12
- jaseci/jsorc/jsorc.py +92 -79
- jaseci/jsorc/live_actions.py +29 -24
- jaseci/jsorc/redis.py +7 -5
- jaseci/prim/{action.py → ability.py} +44 -31
- jaseci/prim/architype.py +26 -8
- jaseci/prim/obj_mixins.py +5 -0
- jaseci/prim/sentinel.py +3 -1
- jaseci/prim/walker.py +7 -5
- jaseci/tests/jac_test_progs.py +9 -0
- jaseci/tests/test_jac.py +3 -3
- jaseci/tests/test_node.py +9 -12
- jaseci/tests/test_progs.py +16 -1
- jaseci/tests/test_stack.py +22 -0
- jaseci/utils/actions/actions_optimizer.py +23 -8
- jaseci/utils/gprof2dot.py +3786 -0
- jaseci/utils/json_handler.py +5 -1
- jaseci/utils/utils.py +52 -21
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/METADATA +2 -2
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/RECORD +41 -41
- jaseci/prim/item.py +0 -29
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/LICENSE +0 -0
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/WHEEL +0 -0
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/entry_points.txt +0 -0
- {jaseci-1.4.0.18.dist-info → jaseci-1.4.0.20.dist-info}/top_level.txt +0 -0
jaseci/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.4.0.
|
|
1
|
+
1.4.0.20
|
jaseci/cli_tools/jsctl.py
CHANGED
|
@@ -17,6 +17,7 @@ from jaseci.utils.utils import copy_func
|
|
|
17
17
|
from .book_tools import Book, modifiedBook
|
|
18
18
|
from jaseci.utils.utils import logger, perf_test_start, perf_test_stop, find_first_api
|
|
19
19
|
from jaseci.jsorc.jsorc import JsOrc
|
|
20
|
+
from prettytable import PrettyTable
|
|
20
21
|
|
|
21
22
|
session = None
|
|
22
23
|
|
|
@@ -112,6 +113,39 @@ def resolve_none_type(kwargs):
|
|
|
112
113
|
kwargs[i] = None
|
|
113
114
|
|
|
114
115
|
|
|
116
|
+
def has_profile(output):
|
|
117
|
+
if isinstance(output, dict):
|
|
118
|
+
if "profile" in output.keys():
|
|
119
|
+
if "jac" in output["profile"].keys() and "perf" in output["profile"].keys():
|
|
120
|
+
return True
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def gen_pretty_table(csv_str):
|
|
125
|
+
rows = csv_str.split("\n")
|
|
126
|
+
row_width = len(rows[0].split(","))
|
|
127
|
+
first_row = rows[0].split(",")
|
|
128
|
+
if first_row[2] == "percall":
|
|
129
|
+
first_row[2] = "percall_tot"
|
|
130
|
+
try:
|
|
131
|
+
table = PrettyTable(first_row)
|
|
132
|
+
for i in rows[1:]:
|
|
133
|
+
row = i.split(",")
|
|
134
|
+
if len(row) != row_width:
|
|
135
|
+
continue
|
|
136
|
+
table.add_row(row)
|
|
137
|
+
return table
|
|
138
|
+
except Exception as e:
|
|
139
|
+
click.echo(f"Something went wrong pretty printing profile: {e}")
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def pretty_profile(output):
|
|
143
|
+
click.echo("Jac Code Profile:")
|
|
144
|
+
click.echo(gen_pretty_table(output["profile"]["jac"]))
|
|
145
|
+
click.echo("\nInternal Jaseci Profile:")
|
|
146
|
+
click.echo(gen_pretty_table(output["profile"]["perf"]))
|
|
147
|
+
|
|
148
|
+
|
|
115
149
|
def interface_api(api_name, is_public, is_cli_only, **kwargs):
|
|
116
150
|
"""
|
|
117
151
|
Interfaces Master apis after processing arguments/parameters
|
|
@@ -137,6 +171,7 @@ def interface_api(api_name, is_public, is_cli_only, **kwargs):
|
|
|
137
171
|
out = session["master"].public_interface_to_api(kwargs, api_name)
|
|
138
172
|
else:
|
|
139
173
|
out = session["master"].general_interface_to_api(kwargs, api_name)
|
|
174
|
+
d_out = out
|
|
140
175
|
if (
|
|
141
176
|
isinstance(out, dict)
|
|
142
177
|
and "report_custom" in out.keys()
|
|
@@ -153,6 +188,8 @@ def interface_api(api_name, is_public, is_cli_only, **kwargs):
|
|
|
153
188
|
if not session["mem-only"]:
|
|
154
189
|
with open(session["filename"], "wb") as f:
|
|
155
190
|
pickle.dump(session, f)
|
|
191
|
+
if has_profile(d_out):
|
|
192
|
+
pretty_profile(d_out)
|
|
156
193
|
|
|
157
194
|
|
|
158
195
|
def extract_api_tree():
|
|
@@ -384,20 +421,22 @@ def script(filename, profile, output):
|
|
|
384
421
|
with open(output, "w") as f:
|
|
385
422
|
f.write("Multi Command Script Output:\n")
|
|
386
423
|
for i in cmds:
|
|
387
|
-
res = CliRunner(mix_stderr=False).invoke(jsctl, i
|
|
424
|
+
res = CliRunner(mix_stderr=False).invoke(jsctl, i)
|
|
388
425
|
click.echo(res.stdout)
|
|
389
426
|
if output:
|
|
390
427
|
with open(output, "a") as f:
|
|
391
428
|
f.write(f"Output for {i}:\n")
|
|
392
429
|
f.write(res.stdout)
|
|
393
430
|
if profile:
|
|
394
|
-
perf = perf_test_stop(prof)
|
|
431
|
+
perf, graph = perf_test_stop(prof)
|
|
395
432
|
click.echo(perf)
|
|
433
|
+
click.echo(graph)
|
|
396
434
|
if output:
|
|
397
435
|
with open(output, "a") as f:
|
|
398
436
|
if profile:
|
|
399
437
|
f.write(f"\nProfile:\n")
|
|
400
438
|
f.write(perf)
|
|
439
|
+
f.write(graph)
|
|
401
440
|
click.echo(f"[saved to {output}]")
|
|
402
441
|
|
|
403
442
|
|
|
@@ -506,6 +506,17 @@ class JsctlTest(TestCaseHelper, TestCase):
|
|
|
506
506
|
],
|
|
507
507
|
)
|
|
508
508
|
|
|
509
|
+
def test_jsctl_pretty_profiles(self):
|
|
510
|
+
self.call(f"actions load local {self.infer_loc}")
|
|
511
|
+
r = self.call(
|
|
512
|
+
f"sentinel register "
|
|
513
|
+
f"{os.path.dirname(__file__)}/graph_can.jac -name gc -set_active true"
|
|
514
|
+
)
|
|
515
|
+
r = self.call("walker run go -profiling true")
|
|
516
|
+
self.assertIn("walker::go", r)
|
|
517
|
+
self.assertIn("cumtime", r)
|
|
518
|
+
self.assertIn("cum_time", r)
|
|
519
|
+
|
|
509
520
|
|
|
510
521
|
class JsctlTestWithSession(TestCaseHelper, TestCase):
|
|
511
522
|
"""Unit tests for Jac language"""
|
|
@@ -14,4 +14,5 @@ def start_perf_test(name: str = "default"):
|
|
|
14
14
|
def stop_perf_test(name: str = "default"):
|
|
15
15
|
if name not in perf_tests.keys():
|
|
16
16
|
return
|
|
17
|
-
|
|
17
|
+
calls, graph = perf_test_stop(perf_tests[name])
|
|
18
|
+
return {"calls": calls, "graph": graph}
|
jaseci/extens/act_lib/std.py
CHANGED
|
@@ -11,6 +11,7 @@ from jaseci.extens.svc.elastic_svc import Elastic
|
|
|
11
11
|
|
|
12
12
|
import sys
|
|
13
13
|
import json
|
|
14
|
+
import time
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
@jaseci_action()
|
|
@@ -49,6 +50,12 @@ def err(*args):
|
|
|
49
50
|
print(*args, file=sys.stderr)
|
|
50
51
|
|
|
51
52
|
|
|
53
|
+
@jaseci_action()
|
|
54
|
+
def sleep(secs: float):
|
|
55
|
+
"""Standard built in for sleep"""
|
|
56
|
+
return time.sleep(secs)
|
|
57
|
+
|
|
58
|
+
|
|
52
59
|
@jaseci_action()
|
|
53
60
|
def sort_by_col(lst: list, col_num: int, reverse: bool = False):
|
|
54
61
|
"""
|
|
@@ -21,7 +21,9 @@ class StdLibTest(CoreTest):
|
|
|
21
21
|
ret = self.call(self.mast, ["walker_run", {"name": "internal_lib"}])
|
|
22
22
|
self.assertEqual(len(ret["report"]), 1)
|
|
23
23
|
self.assertTrue(
|
|
24
|
-
ret["report"][0].startswith(
|
|
24
|
+
ret["report"][0]["calls"].startswith(
|
|
25
|
+
"ncalls,tottime,percall,cumtime,percall,"
|
|
26
|
+
)
|
|
25
27
|
)
|
|
26
28
|
|
|
27
29
|
def test_rand_float_round(self):
|
jaseci/extens/api/jsorc_api.py
CHANGED
|
@@ -88,6 +88,37 @@ class JsOrcApi:
|
|
|
88
88
|
|
|
89
89
|
return new_config
|
|
90
90
|
|
|
91
|
+
@Interface.admin_api()
|
|
92
|
+
def jsorc_refresh(self):
|
|
93
|
+
"""
|
|
94
|
+
refreshing jsorc's config.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
JsOrc.configure()
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
"running_interval": JsOrc._running_interval,
|
|
101
|
+
"config": JsOrc._config,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@Interface.admin_api(cli_args=["name"])
|
|
105
|
+
def service_info(self, name: str):
|
|
106
|
+
"""
|
|
107
|
+
getting service's info.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# will throw exception if not existing
|
|
111
|
+
svc = JsOrc.svc(name)
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
"enabled": svc.enabled,
|
|
115
|
+
"automated": svc.automated,
|
|
116
|
+
"quiet": svc.quiet,
|
|
117
|
+
"state": svc.state.name,
|
|
118
|
+
"config": svc.config,
|
|
119
|
+
"error": str(svc.error) if svc.error else None,
|
|
120
|
+
}
|
|
121
|
+
|
|
91
122
|
@Interface.admin_api(cli_args=["name"])
|
|
92
123
|
def service_refresh(self, name: str):
|
|
93
124
|
"""
|
|
@@ -261,7 +292,16 @@ class JsOrcApi:
|
|
|
261
292
|
return {"success": True, "policy": policy}
|
|
262
293
|
|
|
263
294
|
@Interface.admin_api()
|
|
264
|
-
def jsorc_loadtest(
|
|
295
|
+
def jsorc_loadtest(
|
|
296
|
+
self,
|
|
297
|
+
test: str,
|
|
298
|
+
experiment: str = "",
|
|
299
|
+
mem: int = 0,
|
|
300
|
+
policy: str = "all_local",
|
|
301
|
+
experiment_duration: int = 180,
|
|
302
|
+
eval_phase: int = 10,
|
|
303
|
+
perf_phase: int = 100,
|
|
304
|
+
):
|
|
265
305
|
"""
|
|
266
306
|
load test API. overwritten in jaseci_serv
|
|
267
307
|
"""
|
jaseci/extens/api/walker_api.py
CHANGED
|
@@ -22,6 +22,11 @@ class WalkerApi:
|
|
|
22
22
|
def __init__(self):
|
|
23
23
|
self.spawned_walker_ids = IdList(self)
|
|
24
24
|
self.yielded_walkers_ids = IdList(self)
|
|
25
|
+
self.reset_profiling(False)
|
|
26
|
+
|
|
27
|
+
def reset_profiling(self, profiling):
|
|
28
|
+
self._profiling = profiling
|
|
29
|
+
self._jac_profile = {}
|
|
25
30
|
|
|
26
31
|
@Interface.private_api(cli_args=["wlk"])
|
|
27
32
|
def walker_get(self, wlk: Walker, mode: str = "default", detailed: bool = False):
|
|
@@ -64,6 +69,7 @@ class WalkerApi:
|
|
|
64
69
|
Creates new instance of walker and returns new walker object
|
|
65
70
|
"""
|
|
66
71
|
wlk = snt.run_architype(name=name, kind="walker", caller=self, is_async=False)
|
|
72
|
+
wlk.make_persistent()
|
|
67
73
|
if wlk:
|
|
68
74
|
if self.spawned_walker_ids.has_obj_by_name(name):
|
|
69
75
|
self.spawned_walker_ids.destroy_obj_by_name(name)
|
|
@@ -165,6 +171,7 @@ class WalkerApi:
|
|
|
165
171
|
"""
|
|
166
172
|
Executes walker (assumes walker is primed)
|
|
167
173
|
"""
|
|
174
|
+
self.reset_profiling(profiling)
|
|
168
175
|
return wlk.run(
|
|
169
176
|
start_node=prime, prime_ctx=ctx, request_ctx=_req_ctx, profiling=profiling
|
|
170
177
|
)
|
|
@@ -199,6 +206,7 @@ class WalkerApi:
|
|
|
199
206
|
Creates walker instance, primes walker on node, executes walker,
|
|
200
207
|
reports results, and cleans up walker instance.
|
|
201
208
|
"""
|
|
209
|
+
self.reset_profiling(profiling)
|
|
202
210
|
wlk = self.yielded_walkers_ids.get_obj_by_name(name, silent=True)
|
|
203
211
|
if wlk is None:
|
|
204
212
|
wlk = snt.run_architype(
|
|
@@ -225,6 +233,7 @@ class WalkerApi:
|
|
|
225
233
|
"""
|
|
226
234
|
Walker individual APIs
|
|
227
235
|
"""
|
|
236
|
+
self.reset_profiling(profiling)
|
|
228
237
|
return self.walker_run(name, nd, ctx, _req_ctx, snt, profiling)
|
|
229
238
|
|
|
230
239
|
@Interface.public_api(cli_args=["wlk"])
|
|
@@ -9,6 +9,7 @@ from jaseci.prim.edge import Edge
|
|
|
9
9
|
from jaseci.prim.walker import Walker
|
|
10
10
|
from jaseci.jac.interpreter.interp import Interp
|
|
11
11
|
from jaseci.jac.machine.jac_scope import JacScope
|
|
12
|
+
from jaseci.jac.machine.jac_value import JacValue
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class ArchitypeInterp(Interp):
|
|
@@ -43,7 +44,7 @@ class ArchitypeInterp(Interp):
|
|
|
43
44
|
|
|
44
45
|
kid = self.set_cur_ast(jac_ast)
|
|
45
46
|
|
|
46
|
-
self.push_scope(JacScope(parent=self,
|
|
47
|
+
self.push_scope(JacScope(parent=self, name=f"spawn:{jac_ast.loc_str()}"))
|
|
47
48
|
if kid[0].name == "KW_NODE":
|
|
48
49
|
item = Node(
|
|
49
50
|
m_id=self._m_id,
|
|
@@ -78,6 +79,7 @@ class ArchitypeInterp(Interp):
|
|
|
78
79
|
)
|
|
79
80
|
if kid[2].name == "namespaces":
|
|
80
81
|
item.namespaces = self.run_namespaces(jac_ast.kid[2])
|
|
82
|
+
self.build_object_with_supers(item, kid[-1])
|
|
81
83
|
elif jac_ast.name == "graph_block": # usedi n jac tests
|
|
82
84
|
item = self.run_graph_block(jac_ast)
|
|
83
85
|
self.pop_scope()
|
|
@@ -89,6 +91,19 @@ class ArchitypeInterp(Interp):
|
|
|
89
91
|
"""
|
|
90
92
|
return self.run_name_list(jac_ast.kid[1])
|
|
91
93
|
|
|
94
|
+
def run_walker_block(self, jac_ast, obj):
|
|
95
|
+
"""
|
|
96
|
+
walker_block:
|
|
97
|
+
LBRACE attr_stmt* walk_entry_block? (
|
|
98
|
+
statement
|
|
99
|
+
| walk_activity_block
|
|
100
|
+
)* walk_exit_block? RBRACE;
|
|
101
|
+
"""
|
|
102
|
+
kid = self.set_cur_ast(jac_ast)
|
|
103
|
+
for i in kid:
|
|
104
|
+
if i.name == "attr_stmt":
|
|
105
|
+
self.run_attr_stmt(jac_ast=i, obj=obj)
|
|
106
|
+
|
|
92
107
|
def run_attr_block(self, jac_ast, obj):
|
|
93
108
|
"""
|
|
94
109
|
attr_block:
|
|
@@ -101,52 +116,68 @@ class ArchitypeInterp(Interp):
|
|
|
101
116
|
if i.name == "attr_stmt":
|
|
102
117
|
self.run_attr_stmt(i, obj)
|
|
103
118
|
|
|
104
|
-
def
|
|
119
|
+
def run_attr_stmt(self, jac_ast, obj):
|
|
105
120
|
"""
|
|
106
|
-
|
|
121
|
+
attr_stmt: has_stmt | can_stmt;
|
|
107
122
|
"""
|
|
108
123
|
kid = self.set_cur_ast(jac_ast)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self.run_has_stmt(i, ret)
|
|
113
|
-
return ret
|
|
124
|
+
if kid[0].name == "has_stmt":
|
|
125
|
+
self.run_has_stmt(kid[0], obj)
|
|
126
|
+
# Can statements in architype handled in architype load
|
|
114
127
|
|
|
115
|
-
def
|
|
128
|
+
def run_has_stmt(self, jac_ast, obj):
|
|
116
129
|
"""
|
|
117
|
-
|
|
130
|
+
has_stmt: KW_HAS has_assign (COMMA has_assign)* SEMI;
|
|
118
131
|
"""
|
|
119
132
|
kid = self.set_cur_ast(jac_ast)
|
|
120
133
|
for i in kid:
|
|
121
|
-
if i.name == "
|
|
122
|
-
self.
|
|
134
|
+
if i.name == "has_assign":
|
|
135
|
+
self.run_has_assign(i, obj)
|
|
123
136
|
|
|
124
|
-
def
|
|
137
|
+
def run_has_assign(self, jac_ast, obj):
|
|
125
138
|
"""
|
|
126
|
-
|
|
139
|
+
has_assign: KW_PRIVATE? KW_ANCHOR? (NAME | NAME EQ expression);
|
|
127
140
|
"""
|
|
128
141
|
kid = self.set_cur_ast(jac_ast)
|
|
129
|
-
|
|
142
|
+
while kid[0].name in ["KW_PRIVATE", "KW_ANCHOR"]:
|
|
143
|
+
kid = kid[1:]
|
|
144
|
+
var_name = kid[0].token_text()
|
|
145
|
+
var_val = None # jac's null
|
|
146
|
+
if len(kid) > 1:
|
|
147
|
+
self.run_expression(kid[2])
|
|
148
|
+
var_val = self.pop().value
|
|
149
|
+
if isinstance(obj, dict):
|
|
150
|
+
obj[var_name] = var_val
|
|
151
|
+
# Runs only once for walkers
|
|
152
|
+
elif var_name not in obj.context.keys() or obj.j_type != "walker":
|
|
153
|
+
JacValue(
|
|
154
|
+
self, ctx=obj, name=var_name, value=var_val, create_mode=True
|
|
155
|
+
).write(kid[0], force=True)
|
|
130
156
|
|
|
131
|
-
def
|
|
157
|
+
def run_struct_block(self, jac_ast):
|
|
158
|
+
"""
|
|
159
|
+
struct_block: LBRACE (has_stmt)* RBRACE | COLON has_stmt | SEMI;
|
|
160
|
+
"""
|
|
161
|
+
kid = self.set_cur_ast(jac_ast)
|
|
162
|
+
ret = {}
|
|
163
|
+
for i in kid:
|
|
164
|
+
if i.name == "has_stmt":
|
|
165
|
+
self.run_has_stmt(i, ret)
|
|
166
|
+
return ret
|
|
167
|
+
|
|
168
|
+
def run_graph_block(self, jac_ast):
|
|
132
169
|
"""
|
|
133
|
-
|
|
170
|
+
graph_block:
|
|
134
171
|
LBRACE has_root can_block KW_SPAWN code_block RBRACE
|
|
135
172
|
| COLON has_root can_block KW_SPAWN code_block SEMI;
|
|
136
173
|
"""
|
|
137
174
|
kid = self.set_cur_ast(jac_ast)
|
|
138
175
|
root_name = self.run_has_root(kid[1])
|
|
139
|
-
self.run_can_block(kid[2])
|
|
140
|
-
m = Interp(parent_override=self.parent(), caller=self)
|
|
141
|
-
m.push_scope(
|
|
142
|
-
JacScope(parent=self, has_obj=None, action_sets=[self.activity_action_ids])
|
|
143
|
-
)
|
|
144
176
|
try:
|
|
145
|
-
|
|
177
|
+
self.run_code_block(kid[4])
|
|
146
178
|
except Exception as e:
|
|
147
|
-
self.rt_error(f"Internal Exception: {e}",
|
|
148
|
-
local_state =
|
|
149
|
-
self.report = self.report + m.report
|
|
179
|
+
self.rt_error(f"Internal Exception: {e}", self._cur_jac_ast)
|
|
180
|
+
local_state = self._jac_scope.local_scope
|
|
150
181
|
if root_name in local_state.keys():
|
|
151
182
|
obj = local_state[root_name]
|
|
152
183
|
if not isinstance(obj, Node):
|
|
@@ -173,5 +204,9 @@ class ArchitypeInterp(Interp):
|
|
|
173
204
|
.get_jac_ast()
|
|
174
205
|
.kid[-1]
|
|
175
206
|
)
|
|
176
|
-
self.run_attr_block(super_jac_ast, item)
|
|
177
|
-
|
|
207
|
+
self.run_attr_block(super_jac_ast, item) if not isinstance(
|
|
208
|
+
item, Walker
|
|
209
|
+
) else self.run_walker_block(super_jac_ast, item)
|
|
210
|
+
self.run_attr_block(jac_ast, item) if not isinstance(
|
|
211
|
+
item, Walker
|
|
212
|
+
) else self.run_walker_block(jac_ast, item)
|