sonolus.py 0.1.4__py3-none-any.whl → 0.1.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 +18 -10
- sonolus/backend/interpret.py +7 -7
- sonolus/backend/ir.py +24 -0
- sonolus/backend/optimize/__init__.py +0 -0
- sonolus/backend/{allocate.py → optimize/allocate.py} +4 -3
- sonolus/backend/{constant_evaluation.py → optimize/constant_evaluation.py} +7 -7
- sonolus/backend/{coalesce.py → optimize/copy_coalesce.py} +3 -3
- sonolus/backend/optimize/dead_code.py +185 -0
- sonolus/backend/{dominance.py → optimize/dominance.py} +2 -17
- sonolus/backend/{flow.py → optimize/flow.py} +6 -5
- sonolus/backend/{inlining.py → optimize/inlining.py} +4 -17
- sonolus/backend/{liveness.py → optimize/liveness.py} +69 -65
- sonolus/backend/optimize/optimize.py +44 -0
- sonolus/backend/{passes.py → optimize/passes.py} +1 -1
- sonolus/backend/optimize/simplify.py +191 -0
- sonolus/backend/{ssa.py → optimize/ssa.py} +31 -18
- sonolus/backend/place.py +17 -25
- sonolus/backend/utils.py +10 -0
- sonolus/backend/visitor.py +360 -101
- sonolus/build/compile.py +8 -8
- sonolus/build/engine.py +10 -5
- sonolus/script/archetype.py +419 -137
- sonolus/script/array.py +25 -8
- sonolus/script/array_like.py +297 -0
- sonolus/script/bucket.py +73 -11
- sonolus/script/containers.py +234 -51
- sonolus/script/debug.py +8 -8
- sonolus/script/easing.py +147 -105
- sonolus/script/effect.py +60 -0
- sonolus/script/engine.py +71 -4
- sonolus/script/globals.py +66 -32
- sonolus/script/instruction.py +79 -25
- sonolus/script/internal/builtin_impls.py +138 -27
- sonolus/script/internal/constant.py +139 -0
- sonolus/script/internal/context.py +14 -5
- sonolus/script/internal/dict_impl.py +65 -0
- sonolus/script/internal/generic.py +6 -9
- sonolus/script/internal/impl.py +38 -13
- sonolus/script/internal/introspection.py +5 -2
- sonolus/script/{math.py → internal/math_impls.py} +28 -28
- sonolus/script/internal/native.py +3 -3
- sonolus/script/internal/random.py +67 -0
- sonolus/script/internal/range.py +81 -0
- sonolus/script/internal/transient.py +51 -0
- sonolus/script/internal/tuple_impl.py +113 -0
- sonolus/script/interval.py +234 -16
- sonolus/script/iterator.py +120 -167
- sonolus/script/level.py +24 -0
- sonolus/script/num.py +79 -47
- sonolus/script/options.py +78 -12
- sonolus/script/particle.py +37 -4
- sonolus/script/pointer.py +4 -4
- sonolus/script/print.py +22 -1
- sonolus/script/project.py +8 -0
- sonolus/script/{graphics.py → quad.py} +75 -12
- sonolus/script/record.py +44 -13
- sonolus/script/runtime.py +50 -1
- sonolus/script/sprite.py +197 -112
- sonolus/script/text.py +2 -0
- sonolus/script/timing.py +72 -0
- sonolus/script/transform.py +296 -66
- sonolus/script/ui.py +134 -78
- sonolus/script/values.py +6 -13
- sonolus/script/vec.py +118 -3
- {sonolus_py-0.1.4.dist-info → sonolus_py-0.1.5.dist-info}/METADATA +1 -1
- sonolus_py-0.1.5.dist-info/RECORD +89 -0
- sonolus/backend/dead_code.py +0 -80
- sonolus/backend/optimize.py +0 -37
- sonolus/backend/simplify.py +0 -47
- sonolus/script/comptime.py +0 -160
- sonolus/script/random.py +0 -14
- sonolus/script/range.py +0 -58
- sonolus_py-0.1.4.dist-info/RECORD +0 -84
- /sonolus/script/{callbacks.py → internal/callbacks.py} +0 -0
- {sonolus_py-0.1.4.dist-info → sonolus_py-0.1.5.dist-info}/WHEEL +0 -0
- {sonolus_py-0.1.4.dist-info → sonolus_py-0.1.5.dist-info}/entry_points.txt +0 -0
- {sonolus_py-0.1.4.dist-info → sonolus_py-0.1.5.dist-info}/licenses/LICENSE +0 -0
sonolus/script/containers.py
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from sonolus.script.array import Array
|
|
4
|
+
from sonolus.script.array_like import ArrayLike
|
|
4
5
|
from sonolus.script.debug import error
|
|
5
|
-
from sonolus.script.iterator import
|
|
6
|
-
from sonolus.script.range import Range
|
|
6
|
+
from sonolus.script.iterator import SonolusIterator
|
|
7
7
|
from sonolus.script.record import Record
|
|
8
8
|
from sonolus.script.values import alloc, copy
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Pair[T, U](Record):
|
|
12
|
+
"""A generic pair of values.
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
```python
|
|
16
|
+
Pair[T, U](first: T, second: U)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
```python
|
|
21
|
+
pair = Pair(1, 2)
|
|
22
|
+
pair = Pair[int, Pair[int, int]](1, Pair(2, 3))
|
|
23
|
+
```
|
|
24
|
+
"""
|
|
25
|
+
|
|
12
26
|
first: T
|
|
27
|
+
"""The first value."""
|
|
28
|
+
|
|
13
29
|
second: U
|
|
30
|
+
"""The second value."""
|
|
14
31
|
|
|
15
32
|
def __lt__(self, other):
|
|
16
33
|
if self.first == other.first:
|
|
@@ -34,46 +51,100 @@ class Pair[T, U](Record):
|
|
|
34
51
|
|
|
35
52
|
|
|
36
53
|
class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
54
|
+
"""An array with a variable size and fixed maximum capacity.
|
|
55
|
+
|
|
56
|
+
Usage:
|
|
57
|
+
```python
|
|
58
|
+
VarArray[T, Capacity].new() # Create a new empty array
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
```python
|
|
63
|
+
array = VarArray[int, 10].new()
|
|
64
|
+
array.append(1)
|
|
65
|
+
```
|
|
66
|
+
"""
|
|
67
|
+
|
|
37
68
|
_size: int
|
|
38
69
|
_array: Array[T, Capacity]
|
|
39
70
|
|
|
40
71
|
@classmethod
|
|
41
72
|
def new(cls):
|
|
42
|
-
|
|
43
|
-
|
|
73
|
+
"""Create a new empty array."""
|
|
74
|
+
element_type = cls.type_var_value(T)
|
|
75
|
+
capacity = cls.type_var_value(Capacity)
|
|
44
76
|
return cls(0, alloc(Array[element_type, capacity]))
|
|
45
77
|
|
|
46
|
-
def
|
|
78
|
+
def __len__(self) -> int:
|
|
79
|
+
"""Return the number of elements in the array."""
|
|
47
80
|
return self._size
|
|
48
81
|
|
|
49
82
|
@classmethod
|
|
50
83
|
def capacity(cls) -> int:
|
|
51
|
-
|
|
84
|
+
"""Return the maximum number of elements the array can hold."""
|
|
85
|
+
return cls.type_var_value(Capacity)
|
|
52
86
|
|
|
53
87
|
def is_full(self) -> bool:
|
|
88
|
+
"""Return whether the array is full."""
|
|
54
89
|
return self._size == self.capacity()
|
|
55
90
|
|
|
56
91
|
def __getitem__(self, item) -> T:
|
|
92
|
+
"""Return the element at the given index.
|
|
93
|
+
|
|
94
|
+
The returned value continues to be part of the array.
|
|
95
|
+
Future modifications to the array will affect the returned value.
|
|
96
|
+
|
|
97
|
+
Note:
|
|
98
|
+
Future modifications to the array may cause unexpected changes to the returned value.
|
|
99
|
+
If the array may be modified in the future, it's recommended to make a copy of the value.
|
|
100
|
+
|
|
101
|
+
For example:
|
|
102
|
+
```python
|
|
103
|
+
a = VarArray[Pair, 10].new()
|
|
104
|
+
a.append(Pair(1, 2))
|
|
105
|
+
a.append(Pair(3, 4))
|
|
106
|
+
a.append(Pair(5, 6))
|
|
107
|
+
p = a[1]
|
|
108
|
+
a.pop(0) # Elements are shifted back
|
|
109
|
+
assert p == Pair(5, 6) # The value of p has changed
|
|
110
|
+
```
|
|
111
|
+
"""
|
|
57
112
|
return self._array[item]
|
|
58
113
|
|
|
59
114
|
def __setitem__(self, key: int, value: T):
|
|
115
|
+
"""Update the element at the given index."""
|
|
60
116
|
self._array[key] = value
|
|
61
117
|
|
|
118
|
+
def __delitem__(self, key: int):
|
|
119
|
+
"""Remove the element at the given index."""
|
|
120
|
+
self.pop(key)
|
|
121
|
+
|
|
62
122
|
def append(self, value: T):
|
|
63
|
-
"""
|
|
64
|
-
|
|
123
|
+
"""Append a copy of the given value to the end of the array.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
value: The value to append.
|
|
127
|
+
"""
|
|
128
|
+
assert self._size < len(self._array)
|
|
65
129
|
self._array[self._size] = value
|
|
66
130
|
self._size += 1
|
|
67
131
|
|
|
68
132
|
def extend(self, values: ArrayLike[T]):
|
|
69
|
-
"""Appends copies of the values in the given array to the end of the array.
|
|
133
|
+
"""Appends copies of the values in the given array to the end of the array.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
values: The values to append.
|
|
137
|
+
"""
|
|
70
138
|
for value in values:
|
|
71
139
|
self.append(value)
|
|
72
140
|
|
|
73
141
|
def pop(self, index: int | None = None) -> T:
|
|
74
|
-
"""
|
|
142
|
+
"""Remove and return a copy of the value at the given index.
|
|
75
143
|
|
|
76
144
|
Preserves the relative order of the elements.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
index: The index of the value to remove. If None, the last element is removed.
|
|
77
148
|
"""
|
|
78
149
|
if index is None:
|
|
79
150
|
index = self._size - 1
|
|
@@ -81,35 +152,48 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
81
152
|
value = copy(self._array[index])
|
|
82
153
|
self._size -= 1
|
|
83
154
|
if index < self._size:
|
|
84
|
-
for i in
|
|
155
|
+
for i in range(index, self._size):
|
|
85
156
|
self._array[i] = self._array[i + 1]
|
|
86
157
|
return value
|
|
87
158
|
|
|
88
159
|
def insert(self, index: int, value: T):
|
|
89
|
-
"""
|
|
160
|
+
"""Insert a copy of the given value at the given index.
|
|
90
161
|
|
|
91
162
|
Preserves the relative order of the elements.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
index: The index at which to insert the value. Must be in the range [0, size].
|
|
166
|
+
value: The value to insert.
|
|
92
167
|
"""
|
|
93
168
|
assert 0 <= index <= self._size
|
|
94
|
-
assert self._size < self._array
|
|
169
|
+
assert self._size < len(self._array)
|
|
95
170
|
self._size += 1
|
|
96
|
-
for i in
|
|
171
|
+
for i in range(self._size - 1, index, -1):
|
|
97
172
|
self._array[i] = self._array[i - 1]
|
|
98
173
|
self._array[index] = value
|
|
99
174
|
|
|
100
175
|
def remove(self, value: T) -> bool:
|
|
101
|
-
"""
|
|
176
|
+
"""Remove the first occurrence of the given value, returning whether the value was removed.
|
|
102
177
|
|
|
103
178
|
Preserves the relative order of the elements.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
value: The value to remove
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
True if the value was removed, False otherwise.
|
|
104
185
|
"""
|
|
105
|
-
index = self.
|
|
186
|
+
index = self.index(value)
|
|
106
187
|
if index < 0:
|
|
107
188
|
return False
|
|
108
189
|
self.pop(index)
|
|
109
190
|
return True
|
|
110
191
|
|
|
111
192
|
def clear(self):
|
|
112
|
-
"""
|
|
193
|
+
"""Clear the array, removing all elements.
|
|
194
|
+
|
|
195
|
+
References to elements are not immediately changed, but future insertions may overwrite them.
|
|
196
|
+
"""
|
|
113
197
|
self._size = 0
|
|
114
198
|
|
|
115
199
|
def set_add(self, value: T) -> bool:
|
|
@@ -117,8 +201,14 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
117
201
|
|
|
118
202
|
If the value is already present, the array is not modified.
|
|
119
203
|
If the array is full, the value is not added.
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
value: The value to add
|
|
207
|
+
|
|
208
|
+
Returns:
|
|
209
|
+
True if the value was added, False otherwise.
|
|
120
210
|
"""
|
|
121
|
-
if self._size >= self._array
|
|
211
|
+
if self._size >= len(self._array):
|
|
122
212
|
return False
|
|
123
213
|
if value in self:
|
|
124
214
|
return False
|
|
@@ -129,8 +219,14 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
129
219
|
"""Removes the first occurrence of the given value, returning whether the value was removed.
|
|
130
220
|
|
|
131
221
|
Does not preserve the relative order of the elements.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
value: The value to remove
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
True if the value was removed, False otherwise.
|
|
132
228
|
"""
|
|
133
|
-
index = self.
|
|
229
|
+
index = self.index(value)
|
|
134
230
|
if index < 0:
|
|
135
231
|
return False
|
|
136
232
|
if index < self._size - 1:
|
|
@@ -138,11 +234,18 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
138
234
|
self._size -= 1
|
|
139
235
|
return True
|
|
140
236
|
|
|
237
|
+
def __iadd__(self, other):
|
|
238
|
+
"""Appends copies of the values in the given array to the end of the array."""
|
|
239
|
+
self.extend(other)
|
|
240
|
+
return self
|
|
241
|
+
|
|
141
242
|
def __eq__(self, other):
|
|
142
|
-
if
|
|
243
|
+
if not isinstance(other, ArrayLike):
|
|
244
|
+
return False
|
|
245
|
+
if len(self) != len(other):
|
|
143
246
|
return False
|
|
144
247
|
i = 0
|
|
145
|
-
while i < self
|
|
248
|
+
while i < len(self):
|
|
146
249
|
if self[i] != other[i]:
|
|
147
250
|
return False
|
|
148
251
|
i += 1
|
|
@@ -155,69 +258,144 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
155
258
|
raise TypeError("unhashable type: 'VarArray'")
|
|
156
259
|
|
|
157
260
|
|
|
158
|
-
class
|
|
261
|
+
class _ArrayMapEntry[K, V](Record):
|
|
159
262
|
key: K
|
|
160
263
|
value: V
|
|
161
264
|
|
|
162
265
|
|
|
163
266
|
class ArrayMap[K, V, Capacity](Record):
|
|
267
|
+
"""A map implemented as an array of key-value pairs with a fixed maximum capacity.
|
|
268
|
+
|
|
269
|
+
Usage:
|
|
270
|
+
```python
|
|
271
|
+
ArrayMap[K, V, Capacity].new() # Create a new empty map
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Examples:
|
|
275
|
+
```python
|
|
276
|
+
map = ArrayMap[int, int, 10].new()
|
|
277
|
+
map[1] = 2
|
|
278
|
+
map[3] = 4
|
|
279
|
+
assert 1 in map
|
|
280
|
+
assert 2 not in map
|
|
281
|
+
assert map[3] == 4
|
|
282
|
+
```
|
|
283
|
+
"""
|
|
284
|
+
|
|
164
285
|
_size: int
|
|
165
|
-
_array: Array[
|
|
286
|
+
_array: Array[_ArrayMapEntry[K, V], Capacity]
|
|
166
287
|
|
|
167
288
|
@classmethod
|
|
168
289
|
def new(cls):
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
290
|
+
"""Create a new empty map."""
|
|
291
|
+
key_type = cls.type_var_value(K)
|
|
292
|
+
value_type = cls.type_var_value(V)
|
|
293
|
+
capacity = cls.type_var_value(Capacity)
|
|
294
|
+
return cls(0, alloc(Array[_ArrayMapEntry[key_type, value_type], capacity]))
|
|
295
|
+
|
|
296
|
+
def __len__(self) -> int:
|
|
297
|
+
"""Return the number of key-value pairs in the map."""
|
|
175
298
|
return self._size
|
|
176
299
|
|
|
177
300
|
@classmethod
|
|
178
301
|
def capacity(cls) -> int:
|
|
179
|
-
|
|
302
|
+
"""Return the maximum number of key-value pairs the map can hold."""
|
|
303
|
+
return cls.type_var_value(Capacity)
|
|
180
304
|
|
|
181
305
|
def is_full(self) -> bool:
|
|
306
|
+
"""Return whether the map is full."""
|
|
182
307
|
return self._size == self.capacity()
|
|
183
308
|
|
|
184
309
|
def keys(self) -> SonolusIterator[K]:
|
|
310
|
+
"""Return an iterator over the keys in the map."""
|
|
185
311
|
return _ArrayMapKeyIterator(self, 0)
|
|
186
312
|
|
|
187
313
|
def values(self) -> SonolusIterator[V]:
|
|
188
|
-
|
|
314
|
+
"""Return an iterator over the values in the map."""
|
|
315
|
+
return _ArrayMapValueIterator(self, 0)
|
|
189
316
|
|
|
190
317
|
def items(self) -> SonolusIterator[tuple[K, V]]:
|
|
191
|
-
|
|
318
|
+
"""Return an iterator over the key-value pairs in the map."""
|
|
319
|
+
return _ArrayMapEntryIterator(self, 0)
|
|
192
320
|
|
|
193
321
|
def __iter__(self):
|
|
322
|
+
"""Return an iterator over the keys in the map."""
|
|
194
323
|
return self.keys()
|
|
195
324
|
|
|
196
325
|
def __getitem__(self, key: K) -> V:
|
|
197
|
-
|
|
326
|
+
"""Return the value associated with the given key.
|
|
327
|
+
|
|
328
|
+
Must be called with a key that is present in the map.
|
|
329
|
+
|
|
330
|
+
The returned value continues to be part of the map.
|
|
331
|
+
Future modifications to the map will affect the returned value.
|
|
332
|
+
|
|
333
|
+
Notes:
|
|
334
|
+
Future modifications to the map may cause unexpected changes to the returned value.
|
|
335
|
+
If the map may be modified in the future, it's recommended to make a copy of the value.
|
|
336
|
+
|
|
337
|
+
For example:
|
|
338
|
+
```python
|
|
339
|
+
map = ArrayMap[int, Pair[int, int], 10].new()
|
|
340
|
+
map[1] = Pair(2, 3)
|
|
341
|
+
map[3] = Pair(4, 5)
|
|
342
|
+
map[5] = Pair(6, 7)
|
|
343
|
+
p = map[3]
|
|
344
|
+
map.pop(1)
|
|
345
|
+
# The value of `p` may now be different
|
|
346
|
+
```
|
|
347
|
+
"""
|
|
348
|
+
for i in range(self._size):
|
|
198
349
|
entry = self._array[i]
|
|
199
350
|
if entry.key == key:
|
|
200
351
|
return entry.value
|
|
201
352
|
error()
|
|
202
353
|
|
|
203
354
|
def __setitem__(self, key: K, value: V):
|
|
204
|
-
|
|
355
|
+
"""Associate the given key with the given value.
|
|
356
|
+
|
|
357
|
+
If the key is already present in the map, the value is updated.
|
|
358
|
+
Must not be called if the map is full.
|
|
359
|
+
|
|
360
|
+
Args:
|
|
361
|
+
key: The key to associate with the value.
|
|
362
|
+
value: The value to associate with the key
|
|
363
|
+
"""
|
|
364
|
+
for i in range(self._size):
|
|
205
365
|
entry = self._array[i]
|
|
206
366
|
if entry.key == key:
|
|
207
367
|
entry.value = value
|
|
208
368
|
return
|
|
209
|
-
|
|
210
|
-
self._array[self._size] =
|
|
369
|
+
assert self._size < self.capacity()
|
|
370
|
+
self._array[self._size] = _ArrayMapEntry(key, value)
|
|
211
371
|
self._size += 1
|
|
212
372
|
|
|
213
373
|
def __contains__(self, key: K) -> bool:
|
|
214
|
-
|
|
374
|
+
"""Return whether the given key is present in the map.
|
|
375
|
+
|
|
376
|
+
Args:
|
|
377
|
+
key: The key to check for
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
True if the key is present, False otherwise.
|
|
381
|
+
"""
|
|
382
|
+
for i in range(self._size): # noqa: SIM110
|
|
215
383
|
if self._array[i].key == key:
|
|
216
384
|
return True
|
|
217
385
|
return False
|
|
218
386
|
|
|
219
387
|
def pop(self, key: K) -> V:
|
|
220
|
-
|
|
388
|
+
"""Remove and return a copy of the value associated with the given key.
|
|
389
|
+
|
|
390
|
+
Must be called with a key that is present in the map.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
key: The key to remove
|
|
394
|
+
|
|
395
|
+
Returns:
|
|
396
|
+
The value associated with the key
|
|
397
|
+
"""
|
|
398
|
+
for i in range(self._size):
|
|
221
399
|
entry = self._array[i]
|
|
222
400
|
if entry.key == key:
|
|
223
401
|
value = copy(entry.value)
|
|
@@ -228,6 +406,7 @@ class ArrayMap[K, V, Capacity](Record):
|
|
|
228
406
|
error()
|
|
229
407
|
|
|
230
408
|
def clear(self):
|
|
409
|
+
"""Clear the map, removing all key-value pairs."""
|
|
231
410
|
self._size = 0
|
|
232
411
|
|
|
233
412
|
|
|
@@ -236,35 +415,39 @@ class _ArrayMapKeyIterator[K, V, Capacity](Record, SonolusIterator):
|
|
|
236
415
|
_index: int
|
|
237
416
|
|
|
238
417
|
def has_next(self) -> bool:
|
|
239
|
-
return self._index < self._map
|
|
418
|
+
return self._index < len(self._map)
|
|
419
|
+
|
|
420
|
+
def get(self) -> K:
|
|
421
|
+
return self._map._array[self._index].key
|
|
240
422
|
|
|
241
|
-
def
|
|
242
|
-
key = self._map._array[self._index].key
|
|
423
|
+
def advance(self):
|
|
243
424
|
self._index += 1
|
|
244
|
-
return key
|
|
245
425
|
|
|
246
426
|
|
|
247
|
-
class
|
|
427
|
+
class _ArrayMapValueIterator[K, V, Capacity](Record, SonolusIterator):
|
|
248
428
|
_map: ArrayMap[K, V, Capacity]
|
|
249
429
|
_index: int
|
|
250
430
|
|
|
251
431
|
def has_next(self) -> bool:
|
|
252
|
-
return self._index < self._map
|
|
432
|
+
return self._index < len(self._map)
|
|
253
433
|
|
|
254
|
-
def
|
|
255
|
-
|
|
434
|
+
def get(self) -> V:
|
|
435
|
+
return self._map._array[self._index].value
|
|
436
|
+
|
|
437
|
+
def advance(self):
|
|
256
438
|
self._index += 1
|
|
257
|
-
return value
|
|
258
439
|
|
|
259
440
|
|
|
260
|
-
class
|
|
441
|
+
class _ArrayMapEntryIterator[K, V, Capacity](Record, SonolusIterator):
|
|
261
442
|
_map: ArrayMap[K, V, Capacity]
|
|
262
443
|
_index: int
|
|
263
444
|
|
|
264
445
|
def has_next(self) -> bool:
|
|
265
|
-
return self._index < self._map
|
|
446
|
+
return self._index < len(self._map)
|
|
266
447
|
|
|
267
|
-
def
|
|
448
|
+
def get(self) -> tuple[K, V]:
|
|
268
449
|
entry = self._map._array[self._index]
|
|
269
|
-
self._index += 1
|
|
270
450
|
return entry.key, entry.value
|
|
451
|
+
|
|
452
|
+
def advance(self):
|
|
453
|
+
self._index += 1
|
sonolus/script/debug.py
CHANGED
|
@@ -2,24 +2,22 @@ from collections.abc import Callable
|
|
|
2
2
|
from contextvars import ContextVar
|
|
3
3
|
from typing import Any, Never
|
|
4
4
|
|
|
5
|
-
from sonolus.backend.flow import cfg_to_mermaid
|
|
6
5
|
from sonolus.backend.mode import Mode
|
|
7
6
|
from sonolus.backend.ops import Op
|
|
8
|
-
from sonolus.backend.
|
|
9
|
-
from sonolus.backend.
|
|
10
|
-
from sonolus.
|
|
7
|
+
from sonolus.backend.optimize.flow import cfg_to_mermaid
|
|
8
|
+
from sonolus.backend.optimize.passes import CompilerPass, run_passes
|
|
9
|
+
from sonolus.backend.optimize.simplify import CoalesceFlow
|
|
11
10
|
from sonolus.script.internal.context import GlobalContextState, ctx, set_ctx
|
|
12
11
|
from sonolus.script.internal.impl import meta_fn, validate_value
|
|
13
12
|
from sonolus.script.internal.native import native_function
|
|
14
13
|
from sonolus.script.num import Num
|
|
15
|
-
from sonolus.script.values import with_default
|
|
16
14
|
|
|
17
15
|
debug_log_callback = ContextVar[Callable[[Num], None]]("debug_log_callback")
|
|
18
16
|
|
|
19
17
|
|
|
20
18
|
@meta_fn
|
|
21
19
|
def error(message: str | None = None) -> None:
|
|
22
|
-
message =
|
|
20
|
+
message = message._as_py_() if message is not None else "Error"
|
|
23
21
|
if not isinstance(message, str):
|
|
24
22
|
raise ValueError("Expected a string")
|
|
25
23
|
if ctx():
|
|
@@ -32,6 +30,7 @@ def error(message: str | None = None) -> None:
|
|
|
32
30
|
|
|
33
31
|
@meta_fn
|
|
34
32
|
def debug_log(value: Num):
|
|
33
|
+
"""Log a value in debug mode."""
|
|
35
34
|
if debug_log_callback.get(None):
|
|
36
35
|
return debug_log_callback.get()(value)
|
|
37
36
|
else:
|
|
@@ -46,17 +45,18 @@ def _debug_log(value: Num):
|
|
|
46
45
|
|
|
47
46
|
@native_function(Op.DebugPause)
|
|
48
47
|
def debug_pause():
|
|
48
|
+
"""Pause the game if in debug mode."""
|
|
49
49
|
input("[DEBUG] Paused")
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
def assert_true(value: Num, message: str | None = None):
|
|
53
|
-
message =
|
|
53
|
+
message = message if message is not None else "Assertion failed"
|
|
54
54
|
if not value:
|
|
55
55
|
error(message)
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
def assert_false(value: Num, message: str | None = None):
|
|
59
|
-
message =
|
|
59
|
+
message = message if message is not None else "Assertion failed"
|
|
60
60
|
if value:
|
|
61
61
|
error(message)
|
|
62
62
|
|