sonolus.py 0.1.3__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.

Files changed (90) hide show
  1. sonolus/backend/blocks.py +756 -756
  2. sonolus/backend/excepthook.py +37 -37
  3. sonolus/backend/finalize.py +77 -69
  4. sonolus/backend/interpret.py +7 -7
  5. sonolus/backend/ir.py +29 -3
  6. sonolus/backend/mode.py +24 -24
  7. sonolus/backend/node.py +40 -40
  8. sonolus/backend/ops.py +197 -197
  9. sonolus/backend/optimize/__init__.py +0 -0
  10. sonolus/backend/optimize/allocate.py +126 -0
  11. sonolus/backend/optimize/constant_evaluation.py +374 -0
  12. sonolus/backend/optimize/copy_coalesce.py +85 -0
  13. sonolus/backend/optimize/dead_code.py +185 -0
  14. sonolus/backend/optimize/dominance.py +96 -0
  15. sonolus/backend/{flow.py → optimize/flow.py} +122 -92
  16. sonolus/backend/optimize/inlining.py +137 -0
  17. sonolus/backend/optimize/liveness.py +177 -0
  18. sonolus/backend/optimize/optimize.py +44 -0
  19. sonolus/backend/optimize/passes.py +52 -0
  20. sonolus/backend/optimize/simplify.py +191 -0
  21. sonolus/backend/optimize/ssa.py +200 -0
  22. sonolus/backend/place.py +17 -25
  23. sonolus/backend/utils.py +58 -48
  24. sonolus/backend/visitor.py +1151 -882
  25. sonolus/build/cli.py +7 -1
  26. sonolus/build/compile.py +88 -90
  27. sonolus/build/engine.py +10 -5
  28. sonolus/build/level.py +24 -23
  29. sonolus/build/node.py +43 -43
  30. sonolus/script/archetype.py +438 -139
  31. sonolus/script/array.py +27 -10
  32. sonolus/script/array_like.py +297 -0
  33. sonolus/script/bucket.py +253 -191
  34. sonolus/script/containers.py +257 -51
  35. sonolus/script/debug.py +26 -10
  36. sonolus/script/easing.py +365 -0
  37. sonolus/script/effect.py +191 -131
  38. sonolus/script/engine.py +71 -4
  39. sonolus/script/globals.py +303 -269
  40. sonolus/script/instruction.py +205 -151
  41. sonolus/script/internal/__init__.py +5 -5
  42. sonolus/script/internal/builtin_impls.py +255 -144
  43. sonolus/script/{callbacks.py → internal/callbacks.py} +127 -127
  44. sonolus/script/internal/constant.py +139 -0
  45. sonolus/script/internal/context.py +26 -9
  46. sonolus/script/internal/descriptor.py +17 -17
  47. sonolus/script/internal/dict_impl.py +65 -0
  48. sonolus/script/internal/generic.py +6 -9
  49. sonolus/script/internal/impl.py +38 -13
  50. sonolus/script/internal/introspection.py +17 -14
  51. sonolus/script/internal/math_impls.py +121 -0
  52. sonolus/script/internal/native.py +40 -38
  53. sonolus/script/internal/random.py +67 -0
  54. sonolus/script/internal/range.py +81 -0
  55. sonolus/script/internal/transient.py +51 -0
  56. sonolus/script/internal/tuple_impl.py +113 -0
  57. sonolus/script/internal/value.py +3 -3
  58. sonolus/script/interval.py +338 -112
  59. sonolus/script/iterator.py +167 -214
  60. sonolus/script/level.py +24 -0
  61. sonolus/script/num.py +80 -48
  62. sonolus/script/options.py +257 -191
  63. sonolus/script/particle.py +190 -157
  64. sonolus/script/pointer.py +30 -30
  65. sonolus/script/print.py +102 -81
  66. sonolus/script/project.py +8 -0
  67. sonolus/script/quad.py +263 -0
  68. sonolus/script/record.py +47 -16
  69. sonolus/script/runtime.py +52 -1
  70. sonolus/script/sprite.py +418 -333
  71. sonolus/script/text.py +409 -407
  72. sonolus/script/timing.py +114 -42
  73. sonolus/script/transform.py +332 -48
  74. sonolus/script/ui.py +216 -160
  75. sonolus/script/values.py +6 -13
  76. sonolus/script/vec.py +196 -78
  77. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/METADATA +1 -1
  78. sonolus_py-0.1.5.dist-info/RECORD +89 -0
  79. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/WHEEL +1 -1
  80. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/licenses/LICENSE +21 -21
  81. sonolus/backend/allocate.py +0 -51
  82. sonolus/backend/optimize.py +0 -9
  83. sonolus/backend/passes.py +0 -6
  84. sonolus/backend/simplify.py +0 -30
  85. sonolus/script/comptime.py +0 -160
  86. sonolus/script/graphics.py +0 -150
  87. sonolus/script/math.py +0 -92
  88. sonolus/script/range.py +0 -58
  89. sonolus_py-0.1.3.dist-info/RECORD +0 -75
  90. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/entry_points.txt +0 -0
@@ -1,112 +1,338 @@
1
- from typing import Self
2
-
3
- from sonolus.backend.ops import Op
4
- from sonolus.script.debug import error
5
- from sonolus.script.internal.native import native_function
6
- from sonolus.script.record import Record
7
-
8
-
9
- class Interval(Record):
10
- """A closed interval."""
11
-
12
- start: float
13
- end: float
14
-
15
- @property
16
- def length(self) -> float:
17
- return self.end - self.start
18
-
19
- @property
20
- def is_empty(self) -> bool:
21
- return self.start > self.end
22
-
23
- @property
24
- def mid(self) -> float:
25
- return (self.start + self.end) / 2
26
-
27
- @property
28
- def tuple(self):
29
- return self.start, self.end
30
-
31
- def __contains__(self, item: Self | float | int) -> bool:
32
- match item:
33
- case Interval(start, end):
34
- return self.start <= start and end <= self.end
35
- case float() | int() as value:
36
- return self.start <= value <= self.end
37
- case _:
38
- error("Invalid type for interval check")
39
-
40
- def __add__(self, other: float | int) -> Self:
41
- return Interval(self.start + other, self.end + other)
42
-
43
- def __sub__(self, other: float | int) -> Self:
44
- return Interval(self.start - other, self.end - other)
45
-
46
- def __mul__(self, other: float | int) -> Self:
47
- return Interval(self.start * other, self.end * other)
48
-
49
- def __truediv__(self, other: float | int) -> Self:
50
- return Interval(self.start / other, self.end / other)
51
-
52
- def __floordiv__(self, other: float | int) -> Self:
53
- return Interval(self.start // other, self.end // other)
54
-
55
- def __and__(self, other: Self) -> Self:
56
- return Interval(max(self.start, other.start), min(self.end, other.end))
57
-
58
- def shrink(self, value: float | int) -> Self:
59
- return Interval(self.start + value, self.end - value)
60
-
61
- def expand(self, value: float | int) -> Self:
62
- return Interval(self.start - value, self.end + value)
63
-
64
- def lerp(self, x: float, /) -> float:
65
- return lerp(self.start, self.end, x)
66
-
67
- def lerp_clamped(self, x: float, /) -> float:
68
- return lerp_clamped(self.start, self.end, x)
69
-
70
- def unlerp(self, x: float, /) -> float:
71
- return unlerp(self.start, self.end, x)
72
-
73
- def unlerp_clamped(self, x: float, /) -> float:
74
- return unlerp_clamped(self.start, self.end, x)
75
-
76
- def clamp(self, x: float, /) -> float:
77
- return clamp(x, self.start, self.end)
78
-
79
-
80
- @native_function(Op.Lerp)
81
- def lerp(a, b, x, /):
82
- return a + (b - a) * x
83
-
84
-
85
- @native_function(Op.LerpClamped)
86
- def lerp_clamped(a, b, x, /):
87
- return a + (b - a) * max(0, min(1, x))
88
-
89
-
90
- @native_function(Op.Unlerp)
91
- def unlerp(a, b, x, /):
92
- return (x - a) / (b - a)
93
-
94
-
95
- @native_function(Op.UnlerpClamped)
96
- def unlerp_clamped(a, b, x, /):
97
- return max(0, min(1, (x - a) / (b - a)))
98
-
99
-
100
- @native_function(Op.Remap)
101
- def remap(a, b, c, d, x, /):
102
- return c + (d - c) * (x - a) / (b - a)
103
-
104
-
105
- @native_function(Op.RemapClamped)
106
- def remap_clamped(a, b, c, d, x, /):
107
- return c + (d - c) * max(0, min(1, (x - a) / (b - a)))
108
-
109
-
110
- @native_function(Op.Clamp)
111
- def clamp(x, a, b, /):
112
- return max(a, min(b, x))
1
+ from typing import Self
2
+
3
+ from sonolus.backend.ops import Op
4
+ from sonolus.script.debug import error
5
+ from sonolus.script.internal.native import native_function
6
+ from sonolus.script.num import Num
7
+ from sonolus.script.record import Record
8
+
9
+
10
+ class Interval(Record):
11
+ """A closed interval.
12
+
13
+ Usage:
14
+ ```python
15
+ Interval(start: float, end: float)
16
+ ```
17
+ """
18
+
19
+ start: float
20
+ end: float
21
+
22
+ @property
23
+ def length(self) -> float:
24
+ """The length of the interval.
25
+
26
+ May be negative if the end is less than the start.
27
+ """
28
+ return self.end - self.start
29
+
30
+ @property
31
+ def is_empty(self) -> bool:
32
+ """Whether the interval has length of zero or less."""
33
+ return self.start > self.end
34
+
35
+ @property
36
+ def mid(self) -> float:
37
+ """The midpoint of the interval."""
38
+ return (self.start + self.end) / 2
39
+
40
+ @property
41
+ def tuple(self):
42
+ """The interval as a tuple."""
43
+ return self.start, self.end
44
+
45
+ def __contains__(self, item: Self | float | int) -> bool:
46
+ """Check if an item is within the interval.
47
+
48
+ Args:
49
+ item: The item to check. If it is an interval, it must be fully contained within this interval.
50
+
51
+ Returns:
52
+ True if the item is within the interval, False otherwise.
53
+ """
54
+ match item:
55
+ case Interval(start, end):
56
+ return self.start <= start and end <= self.end
57
+ case Num(value):
58
+ return self.start <= value <= self.end
59
+ case _:
60
+ error("Invalid type for interval check")
61
+
62
+ def __add__(self, other: float | int) -> Self:
63
+ """Add a value to both ends of the interval.
64
+
65
+ Args:
66
+ other: The value to add.
67
+
68
+ Returns:
69
+ A new interval with the value added to both ends.
70
+ """
71
+ return Interval(self.start + other, self.end + other)
72
+
73
+ def __sub__(self, other: float | int) -> Self:
74
+ """Subtract a value from both ends of the interval.
75
+
76
+ Args:
77
+ other: The value to subtract.
78
+
79
+ Returns:
80
+ A new interval with the value subtracted from both ends.
81
+ """
82
+ return Interval(self.start - other, self.end - other)
83
+
84
+ def __mul__(self, other: float | int) -> Self:
85
+ """Multiply both ends of the interval by a value.
86
+
87
+ Args:
88
+ other: The value to multiply by.
89
+
90
+ Returns:
91
+ A new interval with both ends multiplied by the value.
92
+ """
93
+ return Interval(self.start * other, self.end * other)
94
+
95
+ def __truediv__(self, other: float | int) -> Self:
96
+ """Divide both ends of the interval by a value.
97
+
98
+ Args:
99
+ other: The value to divide by.
100
+
101
+ Returns:
102
+ A new interval with both ends divided by the value.
103
+ """
104
+ return Interval(self.start / other, self.end / other)
105
+
106
+ def __floordiv__(self, other: float | int) -> Self:
107
+ """Divide both ends of the interval by a value and floor the result.
108
+
109
+ Args:
110
+ other: The value to divide by.
111
+
112
+ Returns:
113
+ A new interval with both ends divided by the value and floored.
114
+ """
115
+ return Interval(self.start // other, self.end // other)
116
+
117
+ def __and__(self, other: Self) -> Self:
118
+ """Get the intersection of two intervals.
119
+
120
+ The resulting interval will be empty and may have a negative length if the two intervals do not overlap.
121
+
122
+ Args:
123
+ other: The other interval.
124
+
125
+ Returns:
126
+ A new interval representing the intersection of the two intervals.
127
+ """
128
+ return Interval(max(self.start, other.start), min(self.end, other.end))
129
+
130
+ def shrink(self, value: float | int) -> Self:
131
+ """Shrink the interval by a value on both ends.
132
+
133
+ Args:
134
+ value: The value to shrink by.
135
+
136
+ Returns:
137
+ A new interval with the value subtracted from the start and added to the end.
138
+ """
139
+ return Interval(self.start + value, self.end - value)
140
+
141
+ def expand(self, value: float | int) -> Self:
142
+ """Expand the interval by a value on both ends.
143
+
144
+ Args:
145
+ value: The value to expand by.
146
+
147
+ Returns:
148
+ A new interval with the value subtracted from the start and added to the end.
149
+ """
150
+ return Interval(self.start - value, self.end + value)
151
+
152
+ def lerp(self, x: float, /) -> float:
153
+ """Linearly interpolate a value within the interval.
154
+
155
+ Args:
156
+ x: The interpolation factor.
157
+
158
+ Returns:
159
+ The interpolated value.
160
+ """
161
+ return lerp(self.start, self.end, x)
162
+
163
+ def lerp_clamped(self, x: float, /) -> float:
164
+ """Linearly interpolate a value within the interval, clamped to the interval.
165
+
166
+ Args:
167
+ x: The interpolation factor.
168
+
169
+ Returns:
170
+ The interpolated value.
171
+ """
172
+ return lerp_clamped(self.start, self.end, x)
173
+
174
+ def unlerp(self, x: float, /) -> float:
175
+ """Inverse linear interpolation of a value within the interval.
176
+
177
+ Args:
178
+ x: The value to unlerp.
179
+
180
+ Returns:
181
+ The unlerped value.
182
+ """
183
+ return unlerp(self.start, self.end, x)
184
+
185
+ def unlerp_clamped(self, x: float, /) -> float:
186
+ """Inverse linear interpolation of a value within the interval, clamped to the interval.
187
+
188
+ Args:
189
+ x: The value to unlerp.
190
+
191
+ Returns:
192
+ The unlerped value.
193
+ """
194
+ return unlerp_clamped(self.start, self.end, x)
195
+
196
+ def clamp(self, x: float, /) -> float:
197
+ """Clamp a value to the interval.
198
+
199
+ Args:
200
+ x: The value to clamp.
201
+
202
+ Returns:
203
+ The clamped value.
204
+ """
205
+ return clamp(x, self.start, self.end)
206
+
207
+
208
+ @native_function(Op.Lerp)
209
+ def _num_lerp(a, b, x, /):
210
+ return a + (b - a) * x
211
+
212
+
213
+ @native_function(Op.LerpClamped)
214
+ def _num_lerp_clamped(a, b, x, /):
215
+ return a + (b - a) * max(0, min(1, x))
216
+
217
+
218
+ def _generic_lerp[T](a: T, b: T, x: float, /) -> T:
219
+ return a + (b - a) * x
220
+
221
+
222
+ def _generic_lerp_clamped[T](a: T, b: T, x: float, /) -> T:
223
+ return a + (b - a) * max(0, min(1, x))
224
+
225
+
226
+ def lerp[T](a: T, b: T, x: float, /) -> T:
227
+ """Linearly interpolate between two values.
228
+
229
+ Args:
230
+ a: The start value.
231
+ b: The end value.
232
+ x: The interpolation factor.
233
+
234
+ Returns:
235
+ The interpolated value.
236
+ """
237
+ match a, b:
238
+ case (Num(a), Num(b)):
239
+ return _num_lerp(a, b, x)
240
+ case _:
241
+ return _generic_lerp(a, b, x)
242
+
243
+
244
+ def lerp_clamped[T](a: T, b: T, x: float, /) -> T:
245
+ """Linearly interpolate between two values, clamped to the interval.
246
+
247
+ Args:
248
+ a: The start value.
249
+ b: The end value.
250
+ x: The interpolation factor.
251
+
252
+ Returns:
253
+ The interpolated value.
254
+ """
255
+ match a, b:
256
+ case (Num(a), Num(b)):
257
+ return _num_lerp_clamped(a, b, x)
258
+ case _:
259
+ return _generic_lerp_clamped(a, b, x)
260
+
261
+
262
+ @native_function(Op.Unlerp)
263
+ def unlerp(a: float, b: float, x: float, /) -> float:
264
+ """Inverse linear interpolation.
265
+
266
+ Args:
267
+ a: The start value.
268
+ b: The end value.
269
+ x: The value to unlerp.
270
+
271
+ Returns:
272
+ The unlerped value.
273
+ """
274
+ return (x - a) / (b - a)
275
+
276
+
277
+ @native_function(Op.UnlerpClamped)
278
+ def unlerp_clamped(a: float, b: float, x: float, /) -> float:
279
+ """Inverse linear interpolation, clamped to the interval.
280
+
281
+ Args:
282
+ a: The start value.
283
+ b: The end value.
284
+ x: The value to unlerp.
285
+
286
+ Returns:
287
+ The unlerped value.
288
+ """
289
+ return max(0, min(1, (x - a) / (b - a)))
290
+
291
+
292
+ @native_function(Op.Remap)
293
+ def remap(a: float, b: float, c: float, d: float, x: float, /) -> float:
294
+ """Remap a value from one interval to another.
295
+
296
+ Args:
297
+ a: The start of the input interval.
298
+ b: The end of the input interval.
299
+ c: The start of the output interval.
300
+ d: The end of the output interval.
301
+ x: The value to remap.
302
+
303
+ Returns:
304
+ The remapped value.
305
+ """
306
+ return c + (d - c) * (x - a) / (b - a)
307
+
308
+
309
+ @native_function(Op.RemapClamped)
310
+ def remap_clamped(a: float, b: float, c: float, d: float, x: float, /) -> float:
311
+ """Remap a value from one interval to another, clamped to the output interval.
312
+
313
+ Args:
314
+ a: The start of the input interval.
315
+ b: The end of the input interval.
316
+ c: The start of the output interval.
317
+ d: The end of the output interval.
318
+ x: The value to remap.
319
+
320
+ Returns:
321
+ The remapped value.
322
+ """
323
+ return c + (d - c) * max(0, min(1, (x - a) / (b - a)))
324
+
325
+
326
+ @native_function(Op.Clamp)
327
+ def clamp(x: float, a: float, b: float, /) -> float:
328
+ """Clamp a value to an interval.
329
+
330
+ Args:
331
+ x: The value to clamp.
332
+ a: The start of the interval.
333
+ b: The end of the interval.
334
+
335
+ Returns:
336
+ The clamped value.
337
+ """
338
+ return max(a, min(b, x))