sonolus.py 0.10.9__py3-none-any.whl → 0.11.1__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.
- 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 +3 -1
- sonolus/build/compile.py +13 -0
- sonolus/build/dev_server.py +2 -0
- sonolus/build/node.py +6 -8
- sonolus/script/archetype.py +10 -1
- sonolus/script/containers.py +51 -0
- sonolus/script/internal/context.py +5 -1
- sonolus/script/internal/impl.py +5 -5
- sonolus/script/internal/tuple_impl.py +6 -0
- {sonolus_py-0.10.9.dist-info → sonolus_py-0.11.1.dist-info}/METADATA +1 -1
- {sonolus_py-0.10.9.dist-info → sonolus_py-0.11.1.dist-info}/RECORD +18 -18
- {sonolus_py-0.10.9.dist-info → sonolus_py-0.11.1.dist-info}/WHEEL +0 -0
- {sonolus_py-0.10.9.dist-info → sonolus_py-0.11.1.dist-info}/entry_points.txt +0 -0
- {sonolus_py-0.10.9.dist-info → sonolus_py-0.11.1.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
|
@@ -1006,7 +1006,9 @@ class Visitor(ast.NodeVisitor):
|
|
|
1006
1006
|
return validate_value({self.visit(k): self.visit(v) for k, v in zip(node.keys, node.values, strict=True)})
|
|
1007
1007
|
|
|
1008
1008
|
def visit_Set(self, node):
|
|
1009
|
-
|
|
1009
|
+
from sonolus.script.containers import FrozenNumSet
|
|
1010
|
+
|
|
1011
|
+
return self.handle_call(node, FrozenNumSet.of, *(self.visit(elt) for elt in node.elts))
|
|
1010
1012
|
|
|
1011
1013
|
def visit_ListComp(self, node):
|
|
1012
1014
|
raise NotImplementedError("List comprehensions are not supported")
|
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,
|
sonolus/build/dev_server.py
CHANGED
|
@@ -119,6 +119,7 @@ class RebuildCommand:
|
|
|
119
119
|
print("Rebuilding...")
|
|
120
120
|
try:
|
|
121
121
|
start_time = perf_counter()
|
|
122
|
+
server_state.cache.reset_accessed()
|
|
122
123
|
server_state.project_state = ProjectContextState.from_build_config(server_state.config)
|
|
123
124
|
server_state.project = project_module.project
|
|
124
125
|
build_collection(
|
|
@@ -128,6 +129,7 @@ class RebuildCommand:
|
|
|
128
129
|
cache=server_state.cache,
|
|
129
130
|
project_state=server_state.project_state,
|
|
130
131
|
)
|
|
132
|
+
server_state.cache.prune_unaccessed()
|
|
131
133
|
end_time = perf_counter()
|
|
132
134
|
print(f"Rebuild completed in {end_time - start_time:.2f} seconds")
|
|
133
135
|
except CompilationError:
|
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
|
sonolus/script/archetype.py
CHANGED
|
@@ -12,6 +12,7 @@ from sonolus.backend.ir import IRConst, IRExpr, IRInstr, IRPureInstr, IRStmt
|
|
|
12
12
|
from sonolus.backend.mode import Mode
|
|
13
13
|
from sonolus.backend.ops import Op
|
|
14
14
|
from sonolus.script.bucket import Bucket, Judgment
|
|
15
|
+
from sonolus.script.debug import static_error
|
|
15
16
|
from sonolus.script.internal.callbacks import PLAY_CALLBACKS, PREVIEW_CALLBACKS, WATCH_ARCHETYPE_CALLBACKS, CallbackInfo
|
|
16
17
|
from sonolus.script.internal.context import ctx
|
|
17
18
|
from sonolus.script.internal.descriptor import SonolusDescriptor
|
|
@@ -581,7 +582,6 @@ class _BaseArchetype:
|
|
|
581
582
|
def _init_fields(cls):
|
|
582
583
|
if cls._field_init_done:
|
|
583
584
|
return
|
|
584
|
-
cls._field_init_done = True
|
|
585
585
|
for mro_entry in cls.mro()[1:]:
|
|
586
586
|
if hasattr(mro_entry, "_field_init_done"):
|
|
587
587
|
mro_entry._init_fields()
|
|
@@ -706,6 +706,7 @@ class _BaseArchetype:
|
|
|
706
706
|
[inspect.Parameter(name, inspect.Parameter.POSITIONAL_OR_KEYWORD) for name in cls._memory_fields_]
|
|
707
707
|
)
|
|
708
708
|
cls._post_init_fields()
|
|
709
|
+
cls._field_init_done = True
|
|
709
710
|
|
|
710
711
|
@property
|
|
711
712
|
@abstractmethod
|
|
@@ -1210,6 +1211,8 @@ class EntityRef[A: _BaseArchetype](Record):
|
|
|
1210
1211
|
|
|
1211
1212
|
Usage:
|
|
1212
1213
|
```python
|
|
1214
|
+
ref = EntityRef[MyArchetype](index=123)
|
|
1215
|
+
|
|
1213
1216
|
class MyArchetype(PlayArchetype):
|
|
1214
1217
|
ref_1: EntityRef[OtherArchetype] = imported()
|
|
1215
1218
|
ref_2: EntityRef[Any] = imported()
|
|
@@ -1238,6 +1241,12 @@ class EntityRef[A: _BaseArchetype](Record):
|
|
|
1238
1241
|
return hash(id(self._ref_))
|
|
1239
1242
|
return super().__hash__()
|
|
1240
1243
|
|
|
1244
|
+
@meta_fn
|
|
1245
|
+
def __bool__(self):
|
|
1246
|
+
if ctx():
|
|
1247
|
+
static_error("EntityRef cannot be used in a boolean context. Check index directly instead.")
|
|
1248
|
+
return True
|
|
1249
|
+
|
|
1241
1250
|
@meta_fn
|
|
1242
1251
|
def get(self) -> A:
|
|
1243
1252
|
"""Get the entity."""
|
sonolus/script/containers.py
CHANGED
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
from typing import Any, Protocol, Self
|
|
5
5
|
|
|
6
|
+
from sonolus.backend.visitor import compile_and_call
|
|
6
7
|
from sonolus.script.archetype import AnyArchetype, EntityRef
|
|
7
8
|
from sonolus.script.array import Array
|
|
8
9
|
from sonolus.script.array_like import ArrayLike, get_positive_index
|
|
@@ -441,6 +442,56 @@ class ArraySet[T, Capacity](Record):
|
|
|
441
442
|
self._values.clear()
|
|
442
443
|
|
|
443
444
|
|
|
445
|
+
class FrozenNumSet[Size](Record):
|
|
446
|
+
_values: Array[Num, Size]
|
|
447
|
+
|
|
448
|
+
@classmethod
|
|
449
|
+
@meta_fn
|
|
450
|
+
def of(cls, *values: Num) -> Self:
|
|
451
|
+
if ctx():
|
|
452
|
+
try:
|
|
453
|
+
num_values = [Num._accept_(v) for v in values]
|
|
454
|
+
except TypeError:
|
|
455
|
+
raise TypeError("Only sets of numeric values are supported") from None
|
|
456
|
+
if all(v._is_py_() for v in num_values):
|
|
457
|
+
const_values = [v._as_py_() for v in num_values]
|
|
458
|
+
arr = Array[Num, len(const_values)]._with_value([Num(v) for v in sorted(const_values)])
|
|
459
|
+
return cls(arr)
|
|
460
|
+
else:
|
|
461
|
+
arr = Array[Num, len(values)](*values)
|
|
462
|
+
compile_and_call(arr.sort)
|
|
463
|
+
else:
|
|
464
|
+
arr = Array[Num, len(values)](*sorted(values))
|
|
465
|
+
return cls(arr)
|
|
466
|
+
|
|
467
|
+
def __len__(self) -> int:
|
|
468
|
+
return len(self._values)
|
|
469
|
+
|
|
470
|
+
def __contains__(self, value: Num) -> bool:
|
|
471
|
+
if len(self) < 8:
|
|
472
|
+
return value in self._as_tuple()
|
|
473
|
+
else:
|
|
474
|
+
left = 0
|
|
475
|
+
right = len(self) - 1
|
|
476
|
+
while left <= right:
|
|
477
|
+
mid = (left + right) // 2
|
|
478
|
+
mid_value = self._values.get_unchecked(mid)
|
|
479
|
+
if mid_value == value:
|
|
480
|
+
return True
|
|
481
|
+
elif mid_value < value:
|
|
482
|
+
left = mid + 1
|
|
483
|
+
else:
|
|
484
|
+
right = mid - 1
|
|
485
|
+
return False
|
|
486
|
+
|
|
487
|
+
def __iter__(self) -> SonolusIterator[Num]:
|
|
488
|
+
return self._values.__iter__()
|
|
489
|
+
|
|
490
|
+
@meta_fn
|
|
491
|
+
def _as_tuple(self) -> tuple[Num, ...]:
|
|
492
|
+
return tuple(self._values.get_unchecked(i) for i in range(Num._accept_(len(self))._as_py_()))
|
|
493
|
+
|
|
494
|
+
|
|
444
495
|
class _ArrayMapEntry[K, V](Record):
|
|
445
496
|
key: K
|
|
446
497
|
value: V
|
|
@@ -551,7 +551,11 @@ def context_to_cfg(context: Context) -> BasicBlock:
|
|
|
551
551
|
edge = FlowEdge(src=blocks[current], dst=blocks[target], cond=condition)
|
|
552
552
|
blocks[current].outgoing.add(edge)
|
|
553
553
|
blocks[target].incoming.add(edge)
|
|
554
|
-
|
|
554
|
+
result = blocks[context]
|
|
555
|
+
for current in tuple(iter_contexts(context)):
|
|
556
|
+
# Break cycles so memory can be cleaned without gc
|
|
557
|
+
del current.outgoing
|
|
558
|
+
return result
|
|
555
559
|
|
|
556
560
|
|
|
557
561
|
def unique[T](iterable: Iterable[T]) -> list[T]:
|
sonolus/script/internal/impl.py
CHANGED
|
@@ -77,6 +77,10 @@ def try_validate_value(value: Any) -> Value | None:
|
|
|
77
77
|
return TupleImpl._accept_(value)
|
|
78
78
|
case dict():
|
|
79
79
|
return DictImpl._accept_(value)
|
|
80
|
+
case set() | frozenset():
|
|
81
|
+
from sonolus.script.containers import FrozenNumSet
|
|
82
|
+
|
|
83
|
+
return FrozenNumSet.of(*value)
|
|
80
84
|
case (
|
|
81
85
|
PartialGeneric()
|
|
82
86
|
| TypeVar()
|
|
@@ -90,11 +94,7 @@ def try_validate_value(value: Any) -> Value | None:
|
|
|
90
94
|
| super()
|
|
91
95
|
):
|
|
92
96
|
return BasicConstantValue.of(value)
|
|
93
|
-
case special_form if value
|
|
94
|
-
Literal,
|
|
95
|
-
Annotated,
|
|
96
|
-
Union,
|
|
97
|
-
}:
|
|
97
|
+
case special_form if value == Literal or value == Annotated or value == Union: # noqa: PLR1714, SIM109
|
|
98
98
|
return TypingSpecialFormConstant.of(special_form)
|
|
99
99
|
case other_type if get_origin(value) in {Literal, Annotated, UnionType, tuple, type}:
|
|
100
100
|
return BasicConstantValue.of(other_type)
|
|
@@ -91,6 +91,12 @@ class TupleImpl(TransientValue):
|
|
|
91
91
|
other = TupleImpl._accept_(other)
|
|
92
92
|
return TupleImpl._accept_(self.value + other.value)
|
|
93
93
|
|
|
94
|
+
def __contains__(self, item):
|
|
95
|
+
for element in self.value: # noqa: SIM110
|
|
96
|
+
if element == item:
|
|
97
|
+
return True
|
|
98
|
+
return False
|
|
99
|
+
|
|
94
100
|
@staticmethod
|
|
95
101
|
@meta_fn
|
|
96
102
|
def _is_tuple_impl(value: Any) -> bool:
|
|
@@ -3,15 +3,15 @@ sonolus/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
3
3
|
sonolus/backend/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
4
|
sonolus/backend/blocks.py,sha256=3peyb9eYBy0s53xNVJ1KmK4IgoyVkkwG-lqDQ_VZTHc,18531
|
|
5
5
|
sonolus/backend/excepthook.py,sha256=ezsTi8hPXSUhqZ7-H0rmkWcndBQcZFAShF543zzaEPM,1912
|
|
6
|
-
sonolus/backend/finalize.py,sha256=
|
|
7
|
-
sonolus/backend/interpret.py,sha256=
|
|
6
|
+
sonolus/backend/finalize.py,sha256=MRp_ATPreSmBGn8N6iwesS50rFWH9FIiQI6_Ea8RVTM,5090
|
|
7
|
+
sonolus/backend/interpret.py,sha256=dnm0SJFfI4KIE6Ca2tKrLq10XwBC9EPSqN7OOYtA8Ws,14304
|
|
8
8
|
sonolus/backend/ir.py,sha256=eyNXorOQY4zgKOvN4kO1MdJF3sU8H0Qw5RTPqbEjJHY,3854
|
|
9
9
|
sonolus/backend/mode.py,sha256=NkcPZJm8dn83LX35uP24MtQOCnfRDFZ280dHeEEfauE,613
|
|
10
|
-
sonolus/backend/node.py,sha256=
|
|
10
|
+
sonolus/backend/node.py,sha256=w5y2GwSc2E9rQvGJNaMzvPW_FYjjfHw4QDUmKs1dAnc,714
|
|
11
11
|
sonolus/backend/ops.py,sha256=5weB_vIxbkwCSJuzYZyKUk7vVXsSIEDJYRlvE-2ke8A,10572
|
|
12
12
|
sonolus/backend/place.py,sha256=7qwV732hZ4WP-9GNN8FQSEKssPJZELip1wLXTWfop7Y,4717
|
|
13
13
|
sonolus/backend/utils.py,sha256=OwD1EPh8j-hsfkLzeKNzPQojT_3kklpJou0WTJNoCbc,2337
|
|
14
|
-
sonolus/backend/visitor.py,sha256=
|
|
14
|
+
sonolus/backend/visitor.py,sha256=lEq_lkCh74_mK_saE4JeRI9_mM8MMeWRzw4mqJ0Et7c,64450
|
|
15
15
|
sonolus/backend/optimize/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
16
|
sonolus/backend/optimize/allocate.py,sha256=CuumoMphkpQlGRNeKLHT4FBGE0XVj5pwhfNdrqiLFSs,7535
|
|
17
17
|
sonolus/backend/optimize/constant_evaluation.py,sha256=_u_VfLmd4Rlq9aKyRSeKb47352CXuf8uNgNhNTK1qe0,21510
|
|
@@ -20,7 +20,7 @@ sonolus/backend/optimize/dead_code.py,sha256=ZRJ95zJ49R-wZTzJtcSSbl5LYKHWI-byHM3
|
|
|
20
20
|
sonolus/backend/optimize/dominance.py,sha256=3jAgXqXTbuYLpXvIm8UB06NkIOLtaoVp7pBVPcLb5vY,3259
|
|
21
21
|
sonolus/backend/optimize/flow.py,sha256=xUoBpWIYi-NjqXahA6obAZaPvLj_HaDNNv7cO13e2ps,7192
|
|
22
22
|
sonolus/backend/optimize/inlining.py,sha256=BEXjPbJMGTJbgA4ydC38TbEuYEFqb6oxDS0roZTmuds,10417
|
|
23
|
-
sonolus/backend/optimize/liveness.py,sha256=
|
|
23
|
+
sonolus/backend/optimize/liveness.py,sha256=cj0oUrqItVjj58ZQq86nRBO5k0fuTxbmWkvrSv3H-pY,7420
|
|
24
24
|
sonolus/backend/optimize/optimize.py,sha256=2gW0n1AIlwgVjY6teQlt9YP-GsFUxU-mr1ZqAZamnUo,1672
|
|
25
25
|
sonolus/backend/optimize/passes.py,sha256=YyFKy6qCwcR_Ua2_SXpcBODfvBbm_ygVYcqloOlfDZI,1911
|
|
26
26
|
sonolus/backend/optimize/simplify.py,sha256=wvhixe0SfditrGMh0nX0Wt0JR00JqAmz4BKBzMoBAVI,14701
|
|
@@ -28,18 +28,18 @@ sonolus/backend/optimize/ssa.py,sha256=raQO0furQQRPYb8iIBKfNrJlj-_5wqtI4EWNfLZ8Q
|
|
|
28
28
|
sonolus/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
29
29
|
sonolus/build/cli.py,sha256=uLY7JG3PTAb2a1bbjulFlgUGDzsHXyRAfkGV0lbuMgQ,10538
|
|
30
30
|
sonolus/build/collection.py,sha256=6hniAzriPWBKUeGDkXabNXpbdHiHnqiK9shs6U1OExM,12748
|
|
31
|
-
sonolus/build/compile.py,sha256=
|
|
32
|
-
sonolus/build/dev_server.py,sha256=
|
|
31
|
+
sonolus/build/compile.py,sha256=YKqldBTWAXz5kzsS9Qmwy3FdrFloYZWvapR5QWsx2G0,8862
|
|
32
|
+
sonolus/build/dev_server.py,sha256=yHD3KGqzebdqcEBOC5JDlNptzlH8Sq4i-DNnh_zXWCA,10705
|
|
33
33
|
sonolus/build/engine.py,sha256=jMymxbBXu-ekv71uU8TF2KbFaHs3yGjyJAztd1SoRDs,14808
|
|
34
34
|
sonolus/build/level.py,sha256=KLqUAtxIuIqrzeFURJA97rdqjA5pcvYSmwNZQhElaMQ,702
|
|
35
|
-
sonolus/build/node.py,sha256=
|
|
35
|
+
sonolus/build/node.py,sha256=Dhuz_-UlRd-EJC7-AP1NuyvrjHWNo7jGssniRh4dZhI,1239
|
|
36
36
|
sonolus/build/project.py,sha256=Uuz82QtTNFdklrVJ_i7EPp8hSjyOxLU1xAeOloa6G00,8579
|
|
37
37
|
sonolus/script/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
sonolus/script/archetype.py,sha256=
|
|
38
|
+
sonolus/script/archetype.py,sha256=TZ9Semvzh6zHtUyJGN7ZrLYkux4zgqxFhrh-dGiaLEo,49907
|
|
39
39
|
sonolus/script/array.py,sha256=EbrNwl_WuJ0JjjkX0s_VJNXWqvYdm_ljTbyrDEMLGUY,13348
|
|
40
40
|
sonolus/script/array_like.py,sha256=E6S4TW2muXgcyVkhUASQVt7JSYUkpvdJPgHz6YiSHNo,14708
|
|
41
41
|
sonolus/script/bucket.py,sha256=LNePLmCwgXfKLmH4Z7ZcTFKWR32eq4AnnagI7jacrsU,7782
|
|
42
|
-
sonolus/script/containers.py,sha256=
|
|
42
|
+
sonolus/script/containers.py,sha256=KKySXTh_ON9hut1ScMS31ewRNnVd4t7OwpIZg2bPhno,28676
|
|
43
43
|
sonolus/script/debug.py,sha256=21_bvhP2cZ4kwS3Spxp8tP6ojIfmthQxlq4gtqrt0lo,7757
|
|
44
44
|
sonolus/script/easing.py,sha256=2FUJI_nfp990P_armCcRqHm2329O985glJAhSC6tnxs,11379
|
|
45
45
|
sonolus/script/effect.py,sha256=SfJxSNF3RlPCRXnkt62ZlWhCXw3mmmRCsoMsvTErUP0,7960
|
|
@@ -72,12 +72,12 @@ sonolus/script/internal/__init__.py,sha256=T6rzLoiOUaiSQtaHMZ88SNO-ijSjSSv33TKtU
|
|
|
72
72
|
sonolus/script/internal/builtin_impls.py,sha256=1fo6UuWlaLoqpVwFSrFS5BabNeRCdS2T2mjsS4BPYcY,13603
|
|
73
73
|
sonolus/script/internal/callbacks.py,sha256=vWzJG8uiJoEtsNnbeZPqOHogCwoLpz2D1MnHY2wVV8s,2801
|
|
74
74
|
sonolus/script/internal/constant.py,sha256=3ycbGkDJVUwcrCZ96vLjAoAARgsvaqDM8rJ_YCrLrvo,4289
|
|
75
|
-
sonolus/script/internal/context.py,sha256=
|
|
75
|
+
sonolus/script/internal/context.py,sha256=fRvdxkx7EILU54-ogR1HSjLOZnH2PVw2gQri9m86K5Y,19852
|
|
76
76
|
sonolus/script/internal/descriptor.py,sha256=XRFey-EjiAm_--KsNl-8N0Mi_iyQwlPh68gDp0pKf3E,392
|
|
77
77
|
sonolus/script/internal/dict_impl.py,sha256=alu_wKGSk1kZajNf64qbe7t71shEzD4N5xNIATH8Swo,1885
|
|
78
78
|
sonolus/script/internal/error.py,sha256=ZNnsvQVQAnFKzcvsm6-sste2lo-tP5pPI8sD7XlAZWc,490
|
|
79
79
|
sonolus/script/internal/generic.py,sha256=_3d5Rn_tn214-77fPE67vdbdqt1PQF8-2WB_XDu5YRg,7551
|
|
80
|
-
sonolus/script/internal/impl.py,sha256=
|
|
80
|
+
sonolus/script/internal/impl.py,sha256=R88cl4nLcfF0UhA9qdYRBOsl4nMx8ucgz8l7_oRY-l8,3503
|
|
81
81
|
sonolus/script/internal/introspection.py,sha256=guL9_NR2D3OJAnNpeFdyYkO_vVXk-3KQr2-y4YielM0,1133
|
|
82
82
|
sonolus/script/internal/math_impls.py,sha256=ox2pBJ6ELRO0LdLn_RZxgHHs_PCgQOHIhmDkwmLxJaU,2975
|
|
83
83
|
sonolus/script/internal/native.py,sha256=zOuRtgI3XJ_ExyR_ZkvbDABVc_JIWaKl62lFEL_bMaw,2007
|
|
@@ -85,10 +85,10 @@ sonolus/script/internal/random.py,sha256=6Ku5edRcDUh7rtqEEYCJz0BQavw69RALsVHS25z
|
|
|
85
85
|
sonolus/script/internal/range.py,sha256=j94uV1NTZoCdZ8mOw3v51vD8L7h8l5vZpOAp6breD9I,3521
|
|
86
86
|
sonolus/script/internal/simulation_context.py,sha256=LGxLTvxbqBIhoe1R-SfwGajNIDwIJMVsHle0kvzd500,4818
|
|
87
87
|
sonolus/script/internal/transient.py,sha256=y2AWABqF1aoaP6H4_2u4MMpNioC4OsZQCtPyNI0txqo,1634
|
|
88
|
-
sonolus/script/internal/tuple_impl.py,sha256=
|
|
88
|
+
sonolus/script/internal/tuple_impl.py,sha256=WaI5HSF5h03ddXiSHEwzY9ttfsPUItaf86Y5VbZypek,3754
|
|
89
89
|
sonolus/script/internal/value.py,sha256=OngrCdmY_h6mV2Zgwqhuo4eYFad0kTk6263UAxctZcY,6963
|
|
90
|
-
sonolus_py-0.
|
|
91
|
-
sonolus_py-0.
|
|
92
|
-
sonolus_py-0.
|
|
93
|
-
sonolus_py-0.
|
|
94
|
-
sonolus_py-0.
|
|
90
|
+
sonolus_py-0.11.1.dist-info/METADATA,sha256=RUqohCNBMfRgWQrbN51EW2yocoNb136sH8eRKCr_T_o,554
|
|
91
|
+
sonolus_py-0.11.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
92
|
+
sonolus_py-0.11.1.dist-info/entry_points.txt,sha256=oTYspY_b7SA8TptEMTDxh4-Aj-ZVPnYC9f1lqH6s9G4,54
|
|
93
|
+
sonolus_py-0.11.1.dist-info/licenses/LICENSE,sha256=JEKpqVhQYfEc7zg3Mj462sKbKYmO1K7WmvX1qvg9IJk,1067
|
|
94
|
+
sonolus_py-0.11.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|