sonolus.py 0.10.7__py3-none-any.whl → 0.12.5__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 sonolus.py might be problematic. Click here for more details.
- sonolus/backend/finalize.py +38 -32
- sonolus/backend/interpret.py +3 -3
- sonolus/backend/node.py +6 -28
- sonolus/backend/optimize/liveness.py +5 -2
- sonolus/backend/visitor.py +5 -2
- sonolus/build/cli.py +18 -0
- sonolus/build/compile.py +17 -3
- sonolus/build/dev_server.py +9 -1
- sonolus/build/node.py +6 -8
- sonolus/script/archetype.py +183 -45
- sonolus/script/bucket.py +2 -2
- sonolus/script/containers.py +51 -0
- sonolus/script/debug.py +20 -3
- sonolus/script/engine.py +48 -0
- sonolus/script/internal/builtin_impls.py +91 -4
- sonolus/script/internal/context.py +51 -6
- sonolus/script/internal/generic.py +34 -7
- sonolus/script/internal/impl.py +11 -5
- sonolus/script/internal/introspection.py +10 -1
- sonolus/script/internal/tuple_impl.py +6 -0
- sonolus/script/interval.py +5 -5
- sonolus/script/project.py +2 -0
- sonolus/script/record.py +36 -21
- sonolus/script/runtime.py +1 -1
- sonolus/script/stream.py +28 -21
- sonolus/script/transform.py +9 -8
- sonolus/script/values.py +1 -6
- sonolus/script/vec.py +27 -14
- {sonolus_py-0.10.7.dist-info → sonolus_py-0.12.5.dist-info}/METADATA +2 -2
- {sonolus_py-0.10.7.dist-info → sonolus_py-0.12.5.dist-info}/RECORD +33 -33
- {sonolus_py-0.10.7.dist-info → sonolus_py-0.12.5.dist-info}/WHEEL +0 -0
- {sonolus_py-0.10.7.dist-info → sonolus_py-0.12.5.dist-info}/entry_points.txt +0 -0
- {sonolus_py-0.10.7.dist-info → sonolus_py-0.12.5.dist-info}/licenses/LICENSE +0 -0
sonolus/backend/finalize.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from math import isfinite, isinf, isnan
|
|
2
2
|
|
|
3
3
|
from sonolus.backend.ir import IRConst, IRGet, IRInstr, IRPureInstr, IRSet
|
|
4
|
-
from sonolus.backend.node import
|
|
4
|
+
from sonolus.backend.node import EngineNode, FunctionNode
|
|
5
5
|
from sonolus.backend.ops import Op
|
|
6
6
|
from sonolus.backend.optimize.flow import BasicBlock, traverse_cfg_reverse_postorder
|
|
7
7
|
from sonolus.backend.place import BlockPlace
|
|
@@ -18,18 +18,18 @@ def cfg_to_engine_node(entry: BasicBlock):
|
|
|
18
18
|
}
|
|
19
19
|
match outgoing:
|
|
20
20
|
case {**other} if not other:
|
|
21
|
-
statements.append(
|
|
21
|
+
statements.append(len(block_indexes))
|
|
22
22
|
case {None: target, **other} if not other:
|
|
23
|
-
statements.append(
|
|
23
|
+
statements.append(block_indexes[target])
|
|
24
24
|
case {0: f_branch, None: t_branch, **other} if not other:
|
|
25
25
|
statements.append(
|
|
26
26
|
FunctionNode(
|
|
27
27
|
func=Op.If,
|
|
28
|
-
args=
|
|
28
|
+
args=(
|
|
29
29
|
ir_to_engine_node(block.test),
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
block_indexes[t_branch],
|
|
31
|
+
block_indexes[f_branch],
|
|
32
|
+
),
|
|
33
33
|
)
|
|
34
34
|
)
|
|
35
35
|
case {None: default_branch, **other} if len(other) == 1:
|
|
@@ -37,11 +37,11 @@ def cfg_to_engine_node(entry: BasicBlock):
|
|
|
37
37
|
statements.append(
|
|
38
38
|
FunctionNode(
|
|
39
39
|
func=Op.If,
|
|
40
|
-
args=
|
|
40
|
+
args=(
|
|
41
41
|
ir_to_engine_node(IRPureInstr(Op.Equal, args=[block.test, IRConst(cond)])),
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
block_indexes[cond_branch],
|
|
43
|
+
block_indexes[default_branch],
|
|
44
|
+
),
|
|
45
45
|
)
|
|
46
46
|
)
|
|
47
47
|
case dict() as targets:
|
|
@@ -49,23 +49,31 @@ def cfg_to_engine_node(entry: BasicBlock):
|
|
|
49
49
|
default = len(block_indexes)
|
|
50
50
|
conds = [cond for cond in targets if cond is not None]
|
|
51
51
|
if min(conds) == 0 and max(conds) == len(conds) - 1 and all(int(cond) == cond for cond in conds):
|
|
52
|
-
args.extend(
|
|
52
|
+
args.extend(block_indexes[targets[cond]] for cond in range(len(conds)))
|
|
53
53
|
if None in targets:
|
|
54
54
|
default = block_indexes[targets[None]]
|
|
55
|
-
args.append(
|
|
56
|
-
statements.append(FunctionNode(Op.SwitchIntegerWithDefault, args))
|
|
55
|
+
args.append(default)
|
|
56
|
+
statements.append(FunctionNode(Op.SwitchIntegerWithDefault, tuple(args)))
|
|
57
57
|
else:
|
|
58
58
|
for cond, target in targets.items():
|
|
59
59
|
if cond is None:
|
|
60
60
|
default = block_indexes[target]
|
|
61
61
|
continue
|
|
62
|
-
args.append(
|
|
63
|
-
args.append(
|
|
64
|
-
args.append(
|
|
65
|
-
statements.append(FunctionNode(Op.SwitchWithDefault, args))
|
|
66
|
-
block_statements.append(FunctionNode(Op.Execute, statements))
|
|
67
|
-
block_statements.append(
|
|
68
|
-
|
|
62
|
+
args.append(cond)
|
|
63
|
+
args.append(block_indexes[target])
|
|
64
|
+
args.append(default)
|
|
65
|
+
statements.append(FunctionNode(Op.SwitchWithDefault, tuple(args)))
|
|
66
|
+
block_statements.append(FunctionNode(Op.Execute, tuple(statements)))
|
|
67
|
+
block_statements.append(0)
|
|
68
|
+
result = FunctionNode(Op.Block, (FunctionNode(Op.JumpLoop, tuple(block_statements)),))
|
|
69
|
+
for block in block_indexes:
|
|
70
|
+
# Clean up without relying on gc
|
|
71
|
+
del block.incoming
|
|
72
|
+
del block.outgoing
|
|
73
|
+
del block.phis
|
|
74
|
+
del block.statements
|
|
75
|
+
del block.test
|
|
76
|
+
return result
|
|
69
77
|
|
|
70
78
|
|
|
71
79
|
def ir_to_engine_node(stmt) -> EngineNode:
|
|
@@ -73,32 +81,30 @@ def ir_to_engine_node(stmt) -> EngineNode:
|
|
|
73
81
|
case int(value) | float(value) | IRConst(value=int(value) | float(value)):
|
|
74
82
|
value = float(value)
|
|
75
83
|
if value.is_integer():
|
|
76
|
-
return
|
|
84
|
+
return int(value)
|
|
77
85
|
elif isfinite(value):
|
|
78
|
-
return
|
|
86
|
+
return value
|
|
79
87
|
elif isinf(value):
|
|
80
88
|
# Read values from ROM
|
|
81
|
-
return FunctionNode(Op.Get, args=
|
|
89
|
+
return FunctionNode(Op.Get, args=(3000, 1 if value > 0 else 2))
|
|
82
90
|
elif isnan(value):
|
|
83
91
|
# Read value from ROM
|
|
84
|
-
return FunctionNode(Op.Get, args=
|
|
92
|
+
return FunctionNode(Op.Get, args=(3000, 0))
|
|
85
93
|
else:
|
|
86
94
|
raise ValueError(f"Invalid constant value: {value}")
|
|
87
95
|
case IRPureInstr(op=op, args=args) | IRInstr(op=op, args=args):
|
|
88
|
-
return FunctionNode(func=op, args=
|
|
96
|
+
return FunctionNode(func=op, args=tuple(ir_to_engine_node(arg) for arg in args))
|
|
89
97
|
case IRGet(place=place):
|
|
90
98
|
return ir_to_engine_node(place)
|
|
91
99
|
case BlockPlace() as place:
|
|
92
100
|
if place.offset == 0:
|
|
93
101
|
index = ir_to_engine_node(place.index)
|
|
94
102
|
elif place.index == 0:
|
|
95
|
-
index =
|
|
103
|
+
index = place.offset
|
|
96
104
|
else:
|
|
97
|
-
index = FunctionNode(
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
return FunctionNode(func=Op.Get, args=[ir_to_engine_node(place.block), index])
|
|
105
|
+
index = FunctionNode(func=Op.Add, args=(ir_to_engine_node(place.index), place.offset))
|
|
106
|
+
return FunctionNode(func=Op.Get, args=(ir_to_engine_node(place.block), index))
|
|
101
107
|
case IRSet(place=place, value=value):
|
|
102
|
-
return FunctionNode(func=Op.Set, args=
|
|
108
|
+
return FunctionNode(func=Op.Set, args=(*ir_to_engine_node(place).args, ir_to_engine_node(value)))
|
|
103
109
|
case _:
|
|
104
110
|
raise TypeError(f"Unsupported IR statement: {stmt}")
|
sonolus/backend/interpret.py
CHANGED
|
@@ -2,7 +2,7 @@ import math
|
|
|
2
2
|
import operator
|
|
3
3
|
import random
|
|
4
4
|
|
|
5
|
-
from sonolus.backend.node import
|
|
5
|
+
from sonolus.backend.node import EngineNode, FunctionNode
|
|
6
6
|
from sonolus.backend.ops import Op
|
|
7
7
|
|
|
8
8
|
|
|
@@ -24,8 +24,8 @@ class Interpreter:
|
|
|
24
24
|
self.log = []
|
|
25
25
|
|
|
26
26
|
def run(self, node: EngineNode) -> float:
|
|
27
|
-
if isinstance(node,
|
|
28
|
-
return node
|
|
27
|
+
if not isinstance(node, FunctionNode):
|
|
28
|
+
return node
|
|
29
29
|
func = node.func
|
|
30
30
|
args = node.args
|
|
31
31
|
match func:
|
sonolus/backend/node.py
CHANGED
|
@@ -1,40 +1,18 @@
|
|
|
1
1
|
import textwrap
|
|
2
|
-
from
|
|
2
|
+
from typing import NamedTuple
|
|
3
3
|
|
|
4
4
|
from sonolus.backend.ops import Op
|
|
5
5
|
|
|
6
|
-
type EngineNode =
|
|
6
|
+
type EngineNode = int | float | FunctionNode
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
class ConstantNode:
|
|
11
|
-
value: float
|
|
12
|
-
_hash: int = field(init=False, repr=False)
|
|
13
|
-
|
|
14
|
-
def __post_init__(self):
|
|
15
|
-
self._hash = hash(self.value)
|
|
16
|
-
|
|
17
|
-
def __hash__(self):
|
|
18
|
-
return hash(self.value)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@dataclass(slots=True)
|
|
22
|
-
class FunctionNode:
|
|
9
|
+
class FunctionNode(NamedTuple):
|
|
23
10
|
func: Op
|
|
24
|
-
args:
|
|
25
|
-
_hash: int = field(init=False, repr=False)
|
|
26
|
-
|
|
27
|
-
def __post_init__(self):
|
|
28
|
-
self._hash = hash((self.func, tuple(self.args)))
|
|
29
|
-
|
|
30
|
-
def __hash__(self):
|
|
31
|
-
return self._hash
|
|
11
|
+
args: tuple[EngineNode, ...]
|
|
32
12
|
|
|
33
13
|
|
|
34
14
|
def format_engine_node(node: EngineNode) -> str:
|
|
35
|
-
if isinstance(node,
|
|
36
|
-
return str(node.value)
|
|
37
|
-
elif isinstance(node, FunctionNode):
|
|
15
|
+
if isinstance(node, FunctionNode):
|
|
38
16
|
match len(node.args):
|
|
39
17
|
case 0:
|
|
40
18
|
return f"{node.func.name}()"
|
|
@@ -45,4 +23,4 @@ def format_engine_node(node: EngineNode) -> str:
|
|
|
45
23
|
textwrap.indent('\n'.join(format_engine_node(arg) for arg in node.args), ' ')
|
|
46
24
|
}\n)"
|
|
47
25
|
else:
|
|
48
|
-
|
|
26
|
+
return str(node)
|
|
@@ -24,15 +24,18 @@ class LivenessAnalysis(CompilerPass):
|
|
|
24
24
|
block.live_phi_targets = set()
|
|
25
25
|
block.array_defs_in = set()
|
|
26
26
|
block.array_defs_out = None
|
|
27
|
+
last_live_set = set()
|
|
27
28
|
for statement in block.statements:
|
|
28
|
-
statement
|
|
29
|
+
if isinstance(statement, IRSet):
|
|
30
|
+
last_live_set = set()
|
|
31
|
+
statement.live = last_live_set
|
|
29
32
|
statement.visited = False
|
|
30
33
|
statement.uses = self.get_uses(statement, set())
|
|
31
34
|
statement.defs = self.get_defs(statement)
|
|
32
35
|
statement.is_array_init = False # True if this may be the first assignment to an array
|
|
33
36
|
statement.array_defs = self.get_array_defs(statement)
|
|
34
37
|
if not isinstance(block.test, IRConst):
|
|
35
|
-
block.test.live =
|
|
38
|
+
block.test.live = last_live_set
|
|
36
39
|
block.test.uses = self.get_uses(block.test, set())
|
|
37
40
|
self.preprocess_arrays(entry)
|
|
38
41
|
|
sonolus/backend/visitor.py
CHANGED
|
@@ -319,7 +319,6 @@ class Visitor(ast.NodeVisitor):
|
|
|
319
319
|
with using_ctx(before_ctx):
|
|
320
320
|
state_var._set_(0)
|
|
321
321
|
with using_ctx(return_ctx):
|
|
322
|
-
state_var._set_(len(self.return_ctxs) + 1)
|
|
323
322
|
is_present_var._set_(0)
|
|
324
323
|
del before_ctx.outgoing[None] # Unlink the state machine body from the call site
|
|
325
324
|
entry = before_ctx.new_empty_disconnected()
|
|
@@ -1007,7 +1006,9 @@ class Visitor(ast.NodeVisitor):
|
|
|
1007
1006
|
return validate_value({self.visit(k): self.visit(v) for k, v in zip(node.keys, node.values, strict=True)})
|
|
1008
1007
|
|
|
1009
1008
|
def visit_Set(self, node):
|
|
1010
|
-
|
|
1009
|
+
from sonolus.script.containers import FrozenNumSet
|
|
1010
|
+
|
|
1011
|
+
return self.handle_call(node, FrozenNumSet.of, *(self.visit(elt) for elt in node.elts))
|
|
1011
1012
|
|
|
1012
1013
|
def visit_ListComp(self, node):
|
|
1013
1014
|
raise NotImplementedError("List comprehensions are not supported")
|
|
@@ -1307,6 +1308,7 @@ class Visitor(ast.NodeVisitor):
|
|
|
1307
1308
|
raise NotImplementedError(f"Unsupported syntax: {type(node).__name__}")
|
|
1308
1309
|
|
|
1309
1310
|
def handle_getattr(self, node: ast.stmt | ast.expr, target: Value, key: str) -> Value:
|
|
1311
|
+
# If this is changed, remember to update the getattr impl too
|
|
1310
1312
|
with self.reporting_errors_at_node(node):
|
|
1311
1313
|
if isinstance(target, ConstantValue):
|
|
1312
1314
|
# Unwrap so we can access fields
|
|
@@ -1327,6 +1329,7 @@ class Visitor(ast.NodeVisitor):
|
|
|
1327
1329
|
raise TypeError(f"Unsupported field or descriptor {key}")
|
|
1328
1330
|
|
|
1329
1331
|
def handle_setattr(self, node: ast.stmt | ast.expr, target: Value, key: str, value: Value):
|
|
1332
|
+
# If this is changed, remember to update the setattr impl too
|
|
1330
1333
|
with self.reporting_errors_at_node(node):
|
|
1331
1334
|
if target._is_py_():
|
|
1332
1335
|
target = target._as_py_()
|
sonolus/build/cli.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
import gc
|
|
2
3
|
import importlib
|
|
3
4
|
import json
|
|
4
5
|
import shutil
|
|
@@ -129,6 +130,7 @@ def get_config(args: argparse.Namespace) -> BuildConfig:
|
|
|
129
130
|
build_preview=build_preview,
|
|
130
131
|
build_tutorial=build_tutorial,
|
|
131
132
|
runtime_checks=get_runtime_checks(args),
|
|
133
|
+
verbose=hasattr(args, "verbose") and args.verbose,
|
|
132
134
|
)
|
|
133
135
|
|
|
134
136
|
|
|
@@ -164,12 +166,18 @@ def main():
|
|
|
164
166
|
help="Runtime error checking mode (default: none for build, notify for dev)",
|
|
165
167
|
)
|
|
166
168
|
|
|
169
|
+
gc_group = parser.add_mutually_exclusive_group()
|
|
170
|
+
gc_group.add_argument("--no-gc", action="store_true", default=True, help="Disable garbage collection (default)")
|
|
171
|
+
gc_group.add_argument("--gc", action="store_true", help="Enable garbage collection")
|
|
172
|
+
|
|
167
173
|
build_components = parser.add_argument_group("build components")
|
|
168
174
|
build_components.add_argument("--play", action="store_true", help="Build play component")
|
|
169
175
|
build_components.add_argument("--watch", action="store_true", help="Build watch component")
|
|
170
176
|
build_components.add_argument("--preview", action="store_true", help="Build preview component")
|
|
171
177
|
build_components.add_argument("--tutorial", action="store_true", help="Build tutorial component")
|
|
172
178
|
|
|
179
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="Enable verbose output")
|
|
180
|
+
|
|
173
181
|
build_parser = subparsers.add_parser("build")
|
|
174
182
|
build_parser.add_argument(
|
|
175
183
|
"module",
|
|
@@ -219,6 +227,12 @@ def main():
|
|
|
219
227
|
else:
|
|
220
228
|
parser.error("Module argument is required when multiple or no modules are found")
|
|
221
229
|
|
|
230
|
+
if args.command in {"build", "check", "dev"}:
|
|
231
|
+
if hasattr(args, "gc") and args.gc:
|
|
232
|
+
gc.enable()
|
|
233
|
+
elif hasattr(args, "no_gc") and args.no_gc:
|
|
234
|
+
gc.disable()
|
|
235
|
+
|
|
222
236
|
if no_gil():
|
|
223
237
|
print("Multithreading is enabled")
|
|
224
238
|
if hasattr(sys, "_jit") and sys._jit.is_enabled():
|
|
@@ -254,5 +268,9 @@ def main():
|
|
|
254
268
|
end_time = perf_counter()
|
|
255
269
|
print(f"Project validation completed successfully in {end_time - start_time:.2f}s")
|
|
256
270
|
except CompilationError:
|
|
271
|
+
if args.verbose:
|
|
272
|
+
raise
|
|
257
273
|
exc_info = sys.exc_info()
|
|
258
274
|
print_simple_traceback(*exc_info)
|
|
275
|
+
print("\nFor more details, run with the --verbose (-v) flag.")
|
|
276
|
+
sys.exit(1)
|
sonolus/build/compile.py
CHANGED
|
@@ -32,9 +32,11 @@ class CompileCache:
|
|
|
32
32
|
self._cache = {}
|
|
33
33
|
self._lock = Lock()
|
|
34
34
|
self._event = Event()
|
|
35
|
+
self._accessed_hashes = set()
|
|
35
36
|
|
|
36
37
|
def get(self, entry_hash: int) -> EngineNode | None:
|
|
37
38
|
with self._lock:
|
|
39
|
+
self._accessed_hashes.add(entry_hash)
|
|
38
40
|
if entry_hash not in self._cache:
|
|
39
41
|
self._cache[entry_hash] = None # Mark as being compiled
|
|
40
42
|
return None
|
|
@@ -47,10 +49,21 @@ class CompileCache:
|
|
|
47
49
|
|
|
48
50
|
def set(self, entry_hash: int, node: EngineNode) -> None:
|
|
49
51
|
with self._lock:
|
|
52
|
+
self._accessed_hashes.add(entry_hash)
|
|
50
53
|
self._cache[entry_hash] = node
|
|
51
54
|
self._event.set()
|
|
52
55
|
self._event.clear()
|
|
53
56
|
|
|
57
|
+
def reset_accessed(self) -> None:
|
|
58
|
+
with self._lock:
|
|
59
|
+
self._accessed_hashes.clear()
|
|
60
|
+
|
|
61
|
+
def prune_unaccessed(self) -> None:
|
|
62
|
+
with self._lock:
|
|
63
|
+
unaccessed_hashes = set(self._cache.keys()) - self._accessed_hashes
|
|
64
|
+
for h in unaccessed_hashes:
|
|
65
|
+
del self._cache[h]
|
|
66
|
+
|
|
54
67
|
|
|
55
68
|
def compile_mode(
|
|
56
69
|
mode: Mode,
|
|
@@ -67,7 +80,7 @@ def compile_mode(
|
|
|
67
80
|
|
|
68
81
|
mode_state = ModeContextState(
|
|
69
82
|
mode,
|
|
70
|
-
|
|
83
|
+
archetypes,
|
|
71
84
|
)
|
|
72
85
|
nodes = OutputNodeGenerator()
|
|
73
86
|
results = {}
|
|
@@ -134,9 +147,10 @@ def compile_mode(
|
|
|
134
147
|
archetype_data["exports"] = [*archetype._exported_keys_]
|
|
135
148
|
|
|
136
149
|
callback_items = [
|
|
137
|
-
(cb_name, cb_info,
|
|
150
|
+
(cb_name, cb_info, archetype._callbacks_[cb_name])
|
|
138
151
|
for cb_name, cb_info in archetype._supported_callbacks_.items()
|
|
139
|
-
if
|
|
152
|
+
if cb_name in archetype._callbacks_
|
|
153
|
+
and archetype._callbacks_[cb_name] not in archetype._default_callbacks_
|
|
140
154
|
]
|
|
141
155
|
|
|
142
156
|
if thread_pool is not None:
|
sonolus/build/dev_server.py
CHANGED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
import contextlib
|
|
5
|
+
import gc
|
|
5
6
|
import http.server
|
|
6
7
|
import importlib
|
|
7
8
|
import queue
|
|
@@ -118,6 +119,7 @@ class RebuildCommand:
|
|
|
118
119
|
print("Rebuilding...")
|
|
119
120
|
try:
|
|
120
121
|
start_time = perf_counter()
|
|
122
|
+
server_state.cache.reset_accessed()
|
|
121
123
|
server_state.project_state = ProjectContextState.from_build_config(server_state.config)
|
|
122
124
|
server_state.project = project_module.project
|
|
123
125
|
build_collection(
|
|
@@ -127,11 +129,16 @@ class RebuildCommand:
|
|
|
127
129
|
cache=server_state.cache,
|
|
128
130
|
project_state=server_state.project_state,
|
|
129
131
|
)
|
|
132
|
+
server_state.cache.prune_unaccessed()
|
|
130
133
|
end_time = perf_counter()
|
|
131
134
|
print(f"Rebuild completed in {end_time - start_time:.2f} seconds")
|
|
132
135
|
except CompilationError:
|
|
133
136
|
exc_info = sys.exc_info()
|
|
134
|
-
|
|
137
|
+
if server_state.config.verbose:
|
|
138
|
+
print(traceback.format_exc())
|
|
139
|
+
else:
|
|
140
|
+
print_simple_traceback(*exc_info)
|
|
141
|
+
print("\nFor more details, run with the --verbose (-v) flag.")
|
|
135
142
|
|
|
136
143
|
|
|
137
144
|
@dataclass
|
|
@@ -331,6 +338,7 @@ def run_server(
|
|
|
331
338
|
cmd = command_queue.get()
|
|
332
339
|
try:
|
|
333
340
|
cmd.execute(server_state)
|
|
341
|
+
gc.collect()
|
|
334
342
|
except Exception:
|
|
335
343
|
print(f"{traceback.format_exc()}\n")
|
|
336
344
|
prompt_event.set()
|
sonolus/build/node.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from threading import Lock
|
|
2
2
|
from typing import TypedDict
|
|
3
3
|
|
|
4
|
-
from sonolus.backend.node import
|
|
4
|
+
from sonolus.backend.node import EngineNode, FunctionNode
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class ValueOutputNode(TypedDict):
|
|
@@ -32,19 +32,17 @@ class OutputNodeGenerator:
|
|
|
32
32
|
return self.indexes[node]
|
|
33
33
|
|
|
34
34
|
match node:
|
|
35
|
-
case ConstantNode(value):
|
|
36
|
-
index = len(self.nodes)
|
|
37
|
-
self.nodes.append({"value": value})
|
|
38
|
-
self.indexes[node] = index
|
|
39
|
-
return index
|
|
40
35
|
case FunctionNode(func, args):
|
|
41
36
|
arg_indexes = [self._add(arg) for arg in args]
|
|
42
37
|
index = len(self.nodes)
|
|
43
38
|
self.nodes.append({"func": func.value, "args": arg_indexes})
|
|
44
39
|
self.indexes[node] = index
|
|
45
40
|
return index
|
|
46
|
-
case
|
|
47
|
-
|
|
41
|
+
case constant:
|
|
42
|
+
index = len(self.nodes)
|
|
43
|
+
self.nodes.append({"value": constant})
|
|
44
|
+
self.indexes[node] = index
|
|
45
|
+
return index
|
|
48
46
|
|
|
49
47
|
def get(self):
|
|
50
48
|
return self.nodes
|