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,144 +1,255 @@
1
- from collections.abc import Iterable
2
- from typing import overload
3
-
4
- from sonolus.script.internal.context import ctx
5
- from sonolus.script.internal.impl import meta_fn, validate_value
6
- from sonolus.script.iterator import ArrayLike, Enumerator, SonolusIterator
7
- from sonolus.script.math import MATH_BUILTIN_IMPLS
8
- from sonolus.script.num import is_num
9
- from sonolus.script.range import Range
10
-
11
-
12
- @meta_fn
13
- def _isinstance(value, type_):
14
- value = validate_value(value)
15
- type_ = validate_value(type_)._as_py_()
16
- return validate_value(isinstance(value, type_))
17
-
18
-
19
- @meta_fn
20
- def _len(value):
21
- from sonolus.backend.visitor import compile_and_call
22
-
23
- value = validate_value(value)
24
- if not hasattr(value, "__len__"):
25
- raise TypeError(f"object of type '{type(value).__name__}' has no len()")
26
- return compile_and_call(value.__len__)
27
-
28
-
29
- @meta_fn
30
- def _enumerate(iterable, start=0):
31
- from sonolus.backend.visitor import compile_and_call
32
-
33
- iterable = validate_value(iterable)
34
- if not hasattr(iterable, "__iter__"):
35
- raise TypeError(f"'{type(iterable).__name__}' object is not iterable")
36
- if isinstance(iterable, ArrayLike):
37
- return compile_and_call(iterable.enumerate, start)
38
- else:
39
- iterator = compile_and_call(iterable.__iter__)
40
- if not isinstance(iterator, SonolusIterator):
41
- raise TypeError("Only subclasses of SonolusIterator are supported as iterators")
42
- return Enumerator(0, start, iterator)
43
-
44
-
45
- @meta_fn
46
- def _abs(value):
47
- from sonolus.backend.visitor import compile_and_call
48
-
49
- value = validate_value(value)
50
- if not hasattr(value, "__abs__"):
51
- raise TypeError(f"bad operand type for abs(): '{type(value).__name__}'")
52
- return compile_and_call(value.__abs__)
53
-
54
-
55
- @overload
56
- def _max[T](iterable: Iterable[T]) -> T: ...
57
-
58
-
59
- @overload
60
- def _max[T](a: T, b: T, *args: T) -> T: ...
61
-
62
-
63
- @meta_fn
64
- def _max(*args):
65
- from sonolus.backend.visitor import compile_and_call
66
-
67
- args = tuple(validate_value(arg) for arg in args)
68
- if len(args) == 0:
69
- raise ValueError("Expected at least one argument to max")
70
- elif len(args) == 1:
71
- (iterable,) = args
72
- if isinstance(iterable, ArrayLike):
73
- return iterable.max()
74
- else:
75
- raise TypeError(f"Unsupported type: {type(iterable)} for max")
76
- else:
77
- if not all(is_num(arg) for arg in args):
78
- raise TypeError("Arguments to max must be numbers")
79
- if ctx():
80
- result = compile_and_call(_max2, args[0], args[1])
81
- for arg in args[2:]:
82
- result = compile_and_call(_max2, result, arg)
83
- return result
84
- else:
85
- return max(arg._as_py_() for arg in args)
86
-
87
-
88
- def _max2(a, b):
89
- if a > b:
90
- return a
91
- else:
92
- return b
93
-
94
-
95
- @overload
96
- def _min[T](iterable: Iterable[T]) -> T: ...
97
-
98
-
99
- @overload
100
- def _min[T](a: T, b: T, *args: T) -> T: ...
101
-
102
-
103
- @meta_fn
104
- def _min(*args):
105
- from sonolus.backend.visitor import compile_and_call
106
-
107
- args = tuple(validate_value(arg) for arg in args)
108
- if len(args) == 0:
109
- raise ValueError("Expected at least one argument to min")
110
- elif len(args) == 1:
111
- (iterable,) = args
112
- if isinstance(iterable, ArrayLike):
113
- return iterable.min()
114
- else:
115
- raise TypeError(f"Unsupported type: {type(iterable)} for min")
116
- else:
117
- if not all(is_num(arg) for arg in args):
118
- raise TypeError("Arguments to min must be numbers")
119
- if ctx():
120
- result = compile_and_call(_min2, args[0], args[1])
121
- for arg in args[2:]:
122
- result = compile_and_call(_min2, result, arg)
123
- return result
124
- else:
125
- return min(arg._as_py_() for arg in args)
126
-
127
-
128
- def _min2(a, b):
129
- if a < b:
130
- return a
131
- else:
132
- return b
133
-
134
-
135
- BUILTIN_IMPLS = {
136
- id(isinstance): _isinstance,
137
- id(len): _len,
138
- id(enumerate): _enumerate,
139
- id(abs): _abs,
140
- id(max): _max,
141
- id(min): _min,
142
- id(range): Range,
143
- **MATH_BUILTIN_IMPLS,
144
- }
1
+ from abc import ABC
2
+ from collections.abc import Iterable
3
+ from typing import overload
4
+
5
+ from sonolus.script.array_like import ArrayLike
6
+ from sonolus.script.internal.context import ctx
7
+ from sonolus.script.internal.dict_impl import DictImpl
8
+ from sonolus.script.internal.impl import meta_fn, validate_value
9
+ from sonolus.script.internal.math_impls import MATH_BUILTIN_IMPLS, _trunc
10
+ from sonolus.script.internal.random import RANDOM_BUILTIN_IMPLS
11
+ from sonolus.script.internal.range import Range
12
+ from sonolus.script.internal.tuple_impl import TupleImpl
13
+ from sonolus.script.internal.value import Value
14
+ from sonolus.script.iterator import (
15
+ SonolusIterator,
16
+ _EmptyIterator,
17
+ _Enumerator,
18
+ _FilteringIterator,
19
+ _MappingIterator,
20
+ _Zipper,
21
+ )
22
+ from sonolus.script.num import Num, _is_num
23
+
24
+
25
+ @meta_fn
26
+ def _isinstance(value, type_):
27
+ value = validate_value(value)
28
+ type_ = validate_value(type_)._as_py_()
29
+ if type_ is dict:
30
+ return isinstance(value, DictImpl)
31
+ if type_ is tuple:
32
+ return isinstance(value, TupleImpl)
33
+ if type_ in {_int, _float, _bool}:
34
+ raise TypeError("Instance check against int, float, or bool is not supported, use Num instead")
35
+ if not (isinstance(type_, type) and issubclass(type_, Value | ABC)):
36
+ raise TypeError(f"Unsupported type: {type_} for isinstance")
37
+ return validate_value(isinstance(value, type_))
38
+
39
+
40
+ @meta_fn
41
+ def _len(value):
42
+ from sonolus.backend.visitor import compile_and_call
43
+
44
+ value = validate_value(value)
45
+ if not hasattr(value, "__len__"):
46
+ raise TypeError(f"object of type '{type(value).__name__}' has no len()")
47
+ return compile_and_call(value.__len__)
48
+
49
+
50
+ @meta_fn
51
+ def _enumerate(iterable, start=0):
52
+ from sonolus.backend.visitor import compile_and_call
53
+
54
+ iterable = validate_value(iterable)
55
+ if not hasattr(iterable, "__iter__"):
56
+ raise TypeError(f"'{type(iterable).__name__}' object is not iterable")
57
+ if isinstance(iterable, ArrayLike):
58
+ return compile_and_call(iterable._enumerate_, start)
59
+ else:
60
+ iterator = compile_and_call(iterable.__iter__)
61
+ if not isinstance(iterator, SonolusIterator):
62
+ raise TypeError("Only subclasses of SonolusIterator are supported as iterators")
63
+ return _Enumerator(0, start, iterator)
64
+
65
+
66
+ @meta_fn
67
+ def _reversed(iterable):
68
+ from sonolus.backend.visitor import compile_and_call
69
+
70
+ iterable = validate_value(iterable)
71
+ if not isinstance(iterable, ArrayLike):
72
+ raise TypeError(f"Unsupported type: {type(iterable)} for reversed")
73
+ return compile_and_call(iterable.__reversed__)
74
+
75
+
76
+ @meta_fn
77
+ def _zip(*iterables):
78
+ from sonolus.backend.visitor import compile_and_call
79
+ from sonolus.script.containers import Pair
80
+
81
+ if not iterables:
82
+ return _EmptyIterator()
83
+
84
+ iterables = [validate_value(iterable) for iterable in iterables]
85
+ if any(isinstance(iterable, TupleImpl) for iterable in iterables):
86
+ if not all(isinstance(iterable, TupleImpl) for iterable in iterables):
87
+ raise TypeError("Cannot mix tuples with other types in zip")
88
+ return TupleImpl._accept_(tuple(zip(*(iterable._as_py_() for iterable in iterables), strict=False)))
89
+ iterators = [compile_and_call(iterable.__iter__) for iterable in iterables]
90
+ if not all(isinstance(iterator, SonolusIterator) for iterator in iterators):
91
+ raise TypeError("Only subclasses of SonolusIterator are supported as iterators")
92
+ v = iterators.pop()
93
+ while iterators:
94
+ v = Pair(iterators.pop(), v)
95
+ return _Zipper(v)
96
+
97
+
98
+ @meta_fn
99
+ def _abs(value):
100
+ from sonolus.backend.visitor import compile_and_call
101
+
102
+ value = validate_value(value)
103
+ if not hasattr(value, "__abs__"):
104
+ raise TypeError(f"bad operand type for abs(): '{type(value).__name__}'")
105
+ return compile_and_call(value.__abs__)
106
+
107
+
108
+ def _identity(value):
109
+ return value
110
+
111
+
112
+ @overload
113
+ def _max[T](iterable: Iterable[T], *, key: callable = ...) -> T: ...
114
+
115
+
116
+ @overload
117
+ def _max[T](a: T, b: T, *args: T, key: callable = ...) -> T: ...
118
+
119
+
120
+ @meta_fn
121
+ def _max(*args, key: callable = _identity):
122
+ from sonolus.backend.visitor import compile_and_call
123
+
124
+ args = tuple(validate_value(arg) for arg in args)
125
+ if len(args) == 0:
126
+ raise ValueError("Expected at least one argument to max")
127
+ elif len(args) == 1:
128
+ (iterable,) = args
129
+ if isinstance(iterable, ArrayLike):
130
+ return compile_and_call(iterable._max_, key=key)
131
+ else:
132
+ raise TypeError(f"Unsupported type: {type(iterable)} for max")
133
+ else:
134
+ if not all(_is_num(arg) for arg in args):
135
+ raise TypeError("Arguments to max must be numbers")
136
+ if ctx():
137
+ result = compile_and_call(_max2, args[0], args[1], key=key)
138
+ for arg in args[2:]:
139
+ result = compile_and_call(_max2, result, arg, key=key)
140
+ return result
141
+ else:
142
+ return max(arg._as_py_() for arg in args)
143
+
144
+
145
+ def _max2(a, b, key=_identity):
146
+ if key(a) > key(b):
147
+ return a
148
+ else:
149
+ return b
150
+
151
+
152
+ @overload
153
+ def _min[T](iterable: Iterable[T], *, key: callable = ...) -> T: ...
154
+
155
+
156
+ @overload
157
+ def _min[T](a: T, b: T, *args: T, key: callable = ...) -> T: ...
158
+
159
+
160
+ @meta_fn
161
+ def _min(*args, key: callable = _identity):
162
+ from sonolus.backend.visitor import compile_and_call
163
+
164
+ args = tuple(validate_value(arg) for arg in args)
165
+ if len(args) == 0:
166
+ raise ValueError("Expected at least one argument to min")
167
+ elif len(args) == 1:
168
+ (iterable,) = args
169
+ if isinstance(iterable, ArrayLike):
170
+ return compile_and_call(iterable._min_, key=key)
171
+ else:
172
+ raise TypeError(f"Unsupported type: {type(iterable)} for min")
173
+ else:
174
+ if not all(_is_num(arg) for arg in args):
175
+ raise TypeError("Arguments to min must be numbers")
176
+ if ctx():
177
+ result = compile_and_call(_min2, args[0], args[1], key=key)
178
+ for arg in args[2:]:
179
+ result = compile_and_call(_min2, result, arg, key=key)
180
+ return result
181
+ else:
182
+ return min(arg._as_py_() for arg in args)
183
+
184
+
185
+ def _min2(a, b, key=_identity):
186
+ if key(a) < key(b):
187
+ return a
188
+ else:
189
+ return b
190
+
191
+
192
+ @meta_fn
193
+ def _callable(value):
194
+ return callable(value)
195
+
196
+
197
+ def _map(fn, iterable, *iterables):
198
+ return _MappingIterator(lambda args: fn(*args), zip(iterable, *iterables)) # noqa: B905
199
+
200
+
201
+ def _filter(fn, iterable):
202
+ if fn is None:
203
+ fn = _identity
204
+ return _FilteringIterator(fn, iterable.__iter__()) # noqa: PLC2801
205
+
206
+
207
+ @meta_fn
208
+ def _int(value=0):
209
+ value = validate_value(value)
210
+ if not _is_num(value):
211
+ raise TypeError("Only numeric arguments to int() are supported")
212
+ return _trunc(value)
213
+
214
+
215
+ @meta_fn
216
+ def _float(value=0.0):
217
+ value = validate_value(value)
218
+ if not _is_num(value):
219
+ raise TypeError("Only numeric arguments to float() are supported")
220
+ return value
221
+
222
+
223
+ @meta_fn
224
+ def _bool(value=False):
225
+ value = validate_value(value)
226
+ if not _is_num(value):
227
+ raise TypeError("Only numeric arguments to bool() are supported")
228
+ return value != 0
229
+
230
+
231
+ _int._type_mapping_ = Num
232
+ _float._type_mapping_ = Num
233
+ _bool._type_mapping_ = Num
234
+
235
+ # classmethod, property, staticmethod are supported as decorators, but not within functions
236
+
237
+ BUILTIN_IMPLS = {
238
+ id(abs): _abs,
239
+ id(bool): _bool,
240
+ id(callable): _callable,
241
+ id(enumerate): _enumerate,
242
+ id(filter): _filter,
243
+ id(float): _float,
244
+ id(int): _int,
245
+ id(isinstance): _isinstance,
246
+ id(len): _len,
247
+ id(map): _map,
248
+ id(max): _max,
249
+ id(min): _min,
250
+ id(range): Range,
251
+ id(reversed): _reversed,
252
+ id(zip): _zip,
253
+ **MATH_BUILTIN_IMPLS, # Includes round
254
+ **RANDOM_BUILTIN_IMPLS,
255
+ }
@@ -1,127 +1,127 @@
1
- from dataclasses import dataclass
2
-
3
-
4
- @dataclass
5
- class CallbackInfo:
6
- name: str
7
- py_name: str
8
- supports_order: bool
9
- returns_value: bool
10
-
11
-
12
- preprocess_callback = CallbackInfo(
13
- name="preprocess",
14
- py_name="preprocess",
15
- supports_order=True,
16
- returns_value=False,
17
- )
18
- spawn_order_callback = CallbackInfo(
19
- name="spawnOrder",
20
- py_name="spawn_order",
21
- supports_order=True,
22
- returns_value=True,
23
- )
24
- should_spawn_callback = CallbackInfo(
25
- name="shouldSpawn",
26
- py_name="should_spawn",
27
- supports_order=False,
28
- returns_value=True,
29
- )
30
- initialize_callback = CallbackInfo(
31
- name="initialize",
32
- py_name="initialize",
33
- supports_order=False,
34
- returns_value=False,
35
- )
36
- update_sequential_callback = CallbackInfo(
37
- name="updateSequential",
38
- py_name="update_sequential",
39
- supports_order=True,
40
- returns_value=False,
41
- )
42
- touch_callback = CallbackInfo(
43
- name="touch",
44
- py_name="touch",
45
- supports_order=True,
46
- returns_value=False,
47
- )
48
- update_parallel_callback = CallbackInfo(
49
- name="updateParallel",
50
- py_name="update_parallel",
51
- supports_order=False,
52
- returns_value=False,
53
- )
54
- terminate_callback = CallbackInfo(
55
- name="terminate",
56
- py_name="terminate",
57
- supports_order=False,
58
- returns_value=False,
59
- )
60
- spawn_time_callback = CallbackInfo(
61
- name="spawnTime",
62
- py_name="spawn_time",
63
- supports_order=False,
64
- returns_value=True,
65
- )
66
- despawn_time_callback = CallbackInfo(
67
- name="despawnTime",
68
- py_name="despawn_time",
69
- supports_order=False,
70
- returns_value=True,
71
- )
72
- update_spawn_callback = CallbackInfo(
73
- name="updateSpawn",
74
- py_name="update_spawn",
75
- supports_order=False,
76
- returns_value=True,
77
- )
78
- render_callback = CallbackInfo(
79
- name="render",
80
- py_name="render",
81
- supports_order=False,
82
- returns_value=False,
83
- )
84
- navigate_callback = CallbackInfo(
85
- name="navigate",
86
- py_name="navigate",
87
- supports_order=False,
88
- returns_value=False,
89
- )
90
- update_callback = CallbackInfo(
91
- name="update",
92
- py_name="update",
93
- supports_order=False,
94
- returns_value=False,
95
- )
96
-
97
-
98
- def _by_name(*callbacks: CallbackInfo) -> dict[str, CallbackInfo]:
99
- return {cb.py_name: cb for cb in callbacks}
100
-
101
-
102
- PLAY_CALLBACKS = _by_name(
103
- preprocess_callback,
104
- spawn_order_callback,
105
- should_spawn_callback,
106
- initialize_callback,
107
- update_sequential_callback,
108
- touch_callback,
109
- update_parallel_callback,
110
- terminate_callback,
111
- )
112
- WATCH_ARCHETYPE_CALLBACKS = _by_name(
113
- preprocess_callback,
114
- spawn_time_callback,
115
- despawn_time_callback,
116
- initialize_callback,
117
- update_sequential_callback,
118
- update_parallel_callback,
119
- terminate_callback,
120
- )
121
- WATCH_GLOBAL_CALLBACKS = _by_name(
122
- update_spawn_callback,
123
- )
124
- PREVIEW_CALLBACKS = _by_name(
125
- preprocess_callback,
126
- render_callback,
127
- )
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class CallbackInfo:
6
+ name: str
7
+ py_name: str
8
+ supports_order: bool
9
+ returns_value: bool
10
+
11
+
12
+ preprocess_callback = CallbackInfo(
13
+ name="preprocess",
14
+ py_name="preprocess",
15
+ supports_order=True,
16
+ returns_value=False,
17
+ )
18
+ spawn_order_callback = CallbackInfo(
19
+ name="spawnOrder",
20
+ py_name="spawn_order",
21
+ supports_order=True,
22
+ returns_value=True,
23
+ )
24
+ should_spawn_callback = CallbackInfo(
25
+ name="shouldSpawn",
26
+ py_name="should_spawn",
27
+ supports_order=False,
28
+ returns_value=True,
29
+ )
30
+ initialize_callback = CallbackInfo(
31
+ name="initialize",
32
+ py_name="initialize",
33
+ supports_order=False,
34
+ returns_value=False,
35
+ )
36
+ update_sequential_callback = CallbackInfo(
37
+ name="updateSequential",
38
+ py_name="update_sequential",
39
+ supports_order=True,
40
+ returns_value=False,
41
+ )
42
+ touch_callback = CallbackInfo(
43
+ name="touch",
44
+ py_name="touch",
45
+ supports_order=True,
46
+ returns_value=False,
47
+ )
48
+ update_parallel_callback = CallbackInfo(
49
+ name="updateParallel",
50
+ py_name="update_parallel",
51
+ supports_order=False,
52
+ returns_value=False,
53
+ )
54
+ terminate_callback = CallbackInfo(
55
+ name="terminate",
56
+ py_name="terminate",
57
+ supports_order=False,
58
+ returns_value=False,
59
+ )
60
+ spawn_time_callback = CallbackInfo(
61
+ name="spawnTime",
62
+ py_name="spawn_time",
63
+ supports_order=False,
64
+ returns_value=True,
65
+ )
66
+ despawn_time_callback = CallbackInfo(
67
+ name="despawnTime",
68
+ py_name="despawn_time",
69
+ supports_order=False,
70
+ returns_value=True,
71
+ )
72
+ update_spawn_callback = CallbackInfo(
73
+ name="updateSpawn",
74
+ py_name="update_spawn",
75
+ supports_order=False,
76
+ returns_value=True,
77
+ )
78
+ render_callback = CallbackInfo(
79
+ name="render",
80
+ py_name="render",
81
+ supports_order=False,
82
+ returns_value=False,
83
+ )
84
+ navigate_callback = CallbackInfo(
85
+ name="navigate",
86
+ py_name="navigate",
87
+ supports_order=False,
88
+ returns_value=False,
89
+ )
90
+ update_callback = CallbackInfo(
91
+ name="update",
92
+ py_name="update",
93
+ supports_order=False,
94
+ returns_value=False,
95
+ )
96
+
97
+
98
+ def _by_name(*callbacks: CallbackInfo) -> dict[str, CallbackInfo]:
99
+ return {cb.py_name: cb for cb in callbacks}
100
+
101
+
102
+ PLAY_CALLBACKS = _by_name(
103
+ preprocess_callback,
104
+ spawn_order_callback,
105
+ should_spawn_callback,
106
+ initialize_callback,
107
+ update_sequential_callback,
108
+ touch_callback,
109
+ update_parallel_callback,
110
+ terminate_callback,
111
+ )
112
+ WATCH_ARCHETYPE_CALLBACKS = _by_name(
113
+ preprocess_callback,
114
+ spawn_time_callback,
115
+ despawn_time_callback,
116
+ initialize_callback,
117
+ update_sequential_callback,
118
+ update_parallel_callback,
119
+ terminate_callback,
120
+ )
121
+ WATCH_GLOBAL_CALLBACKS = _by_name(
122
+ update_spawn_callback,
123
+ )
124
+ PREVIEW_CALLBACKS = _by_name(
125
+ preprocess_callback,
126
+ render_callback,
127
+ )