sonolus.py 0.3.4__py3-none-any.whl → 0.4.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.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

Files changed (64) hide show
  1. sonolus/backend/excepthook.py +30 -0
  2. sonolus/backend/finalize.py +15 -1
  3. sonolus/backend/ops.py +4 -0
  4. sonolus/backend/optimize/allocate.py +5 -5
  5. sonolus/backend/optimize/constant_evaluation.py +124 -19
  6. sonolus/backend/optimize/copy_coalesce.py +15 -12
  7. sonolus/backend/optimize/dead_code.py +7 -6
  8. sonolus/backend/optimize/dominance.py +2 -2
  9. sonolus/backend/optimize/flow.py +54 -8
  10. sonolus/backend/optimize/inlining.py +137 -30
  11. sonolus/backend/optimize/liveness.py +2 -2
  12. sonolus/backend/optimize/optimize.py +15 -1
  13. sonolus/backend/optimize/passes.py +11 -3
  14. sonolus/backend/optimize/simplify.py +137 -8
  15. sonolus/backend/optimize/ssa.py +47 -13
  16. sonolus/backend/place.py +5 -4
  17. sonolus/backend/utils.py +44 -16
  18. sonolus/backend/visitor.py +288 -17
  19. sonolus/build/cli.py +47 -19
  20. sonolus/build/compile.py +12 -5
  21. sonolus/build/engine.py +70 -1
  22. sonolus/build/level.py +3 -3
  23. sonolus/build/project.py +2 -2
  24. sonolus/script/archetype.py +12 -9
  25. sonolus/script/array.py +23 -18
  26. sonolus/script/array_like.py +26 -29
  27. sonolus/script/bucket.py +1 -1
  28. sonolus/script/containers.py +22 -26
  29. sonolus/script/debug.py +20 -43
  30. sonolus/script/effect.py +1 -1
  31. sonolus/script/globals.py +3 -3
  32. sonolus/script/instruction.py +2 -2
  33. sonolus/script/internal/builtin_impls.py +155 -28
  34. sonolus/script/internal/constant.py +13 -3
  35. sonolus/script/internal/context.py +46 -15
  36. sonolus/script/internal/impl.py +9 -3
  37. sonolus/script/internal/introspection.py +8 -1
  38. sonolus/script/internal/native.py +2 -2
  39. sonolus/script/internal/range.py +8 -11
  40. sonolus/script/internal/simulation_context.py +1 -1
  41. sonolus/script/internal/transient.py +2 -2
  42. sonolus/script/internal/value.py +41 -3
  43. sonolus/script/interval.py +13 -13
  44. sonolus/script/iterator.py +53 -107
  45. sonolus/script/level.py +2 -2
  46. sonolus/script/maybe.py +241 -0
  47. sonolus/script/num.py +29 -14
  48. sonolus/script/options.py +1 -1
  49. sonolus/script/particle.py +1 -1
  50. sonolus/script/project.py +24 -5
  51. sonolus/script/quad.py +15 -15
  52. sonolus/script/record.py +48 -44
  53. sonolus/script/runtime.py +22 -18
  54. sonolus/script/sprite.py +1 -1
  55. sonolus/script/stream.py +66 -82
  56. sonolus/script/transform.py +35 -34
  57. sonolus/script/values.py +10 -10
  58. sonolus/script/vec.py +21 -18
  59. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/METADATA +1 -1
  60. sonolus_py-0.4.1.dist-info/RECORD +93 -0
  61. sonolus_py-0.3.4.dist-info/RECORD +0 -92
  62. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/WHEEL +0 -0
  63. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/entry_points.txt +0 -0
  64. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.1.dist-info}/licenses/LICENSE +0 -0
sonolus/script/quad.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Protocol, Self
3
+ from typing import Protocol
4
4
 
5
5
  from sonolus.script.record import Record
6
6
  from sonolus.script.values import zeros
@@ -57,7 +57,7 @@ class Quad(Record):
57
57
  """The center of the quad."""
58
58
  return (self.bl + self.tr + self.tl + self.br) / 4
59
59
 
60
- def translate(self, translation: Vec2, /) -> Self:
60
+ def translate(self, translation: Vec2, /) -> Quad:
61
61
  """Translate the quad by the given translation and return a new quad."""
62
62
  return Quad(
63
63
  bl=self.bl + translation,
@@ -66,7 +66,7 @@ class Quad(Record):
66
66
  br=self.br + translation,
67
67
  )
68
68
 
69
- def scale(self, factor: Vec2, /) -> Self:
69
+ def scale(self, factor: Vec2, /) -> Quad:
70
70
  """Scale the quad by the given factor about the origin and return a new quad."""
71
71
  return Quad(
72
72
  bl=self.bl * factor,
@@ -75,7 +75,7 @@ class Quad(Record):
75
75
  br=self.br * factor,
76
76
  )
77
77
 
78
- def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Self:
78
+ def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Quad:
79
79
  """Scale the quad by the given factor about the given pivot and return a new quad."""
80
80
  return Quad(
81
81
  bl=(self.bl - pivot) * factor + pivot,
@@ -84,7 +84,7 @@ class Quad(Record):
84
84
  br=(self.br - pivot) * factor + pivot,
85
85
  )
86
86
 
87
- def scale_centered(self, factor: Vec2, /) -> Self:
87
+ def scale_centered(self, factor: Vec2, /) -> Quad:
88
88
  """Scale the quad by the given factor about its center and return a new quad."""
89
89
  return Quad(
90
90
  bl=self.bl * factor,
@@ -93,7 +93,7 @@ class Quad(Record):
93
93
  br=self.br * factor,
94
94
  ).translate(self.center * (Vec2(1, 1) - factor))
95
95
 
96
- def rotate(self, angle: float, /) -> Self:
96
+ def rotate(self, angle: float, /) -> Quad:
97
97
  """Rotate the quad by the given angle about the origin and return a new quad.
98
98
 
99
99
  Args:
@@ -114,7 +114,7 @@ class Quad(Record):
114
114
  angle: float,
115
115
  /,
116
116
  pivot: Vec2,
117
- ) -> Self:
117
+ ) -> Quad:
118
118
  """Rotate the quad by the given angle about the given pivot and return a new quad.
119
119
 
120
120
  Args:
@@ -131,7 +131,7 @@ class Quad(Record):
131
131
  br=self.br.rotate_about(angle, pivot),
132
132
  )
133
133
 
134
- def rotate_centered(self, angle: float, /) -> Self:
134
+ def rotate_centered(self, angle: float, /) -> Quad:
135
135
  """Rotate the quad by the given angle about its center and return a new quad.
136
136
 
137
137
  Args:
@@ -142,7 +142,7 @@ class Quad(Record):
142
142
  """
143
143
  return self.rotate_about(angle, self.center)
144
144
 
145
- def permute(self, count: int = 1, /) -> Self:
145
+ def permute(self, count: int = 1, /) -> Quad:
146
146
  """Perform a cyclic permutation of the quad's vertices and return a new quad.
147
147
 
148
148
  On a square, this operation is equivalent to rotating the square counterclockwise 90 degrees `count` times.
@@ -269,7 +269,7 @@ class Rect(Record):
269
269
  br=self.br,
270
270
  )
271
271
 
272
- def translate(self, translation: Vec2, /) -> Self:
272
+ def translate(self, translation: Vec2, /) -> Rect:
273
273
  """Translate the rectangle by the given translation and return a new rectangle."""
274
274
  return Rect(
275
275
  t=self.t + translation.y,
@@ -278,7 +278,7 @@ class Rect(Record):
278
278
  l=self.l + translation.x,
279
279
  )
280
280
 
281
- def scale(self, factor: Vec2, /) -> Self:
281
+ def scale(self, factor: Vec2, /) -> Rect:
282
282
  """Scale the rectangle by the given factor about the origin and return a new rectangle."""
283
283
  return Rect(
284
284
  t=self.t * factor.y,
@@ -287,7 +287,7 @@ class Rect(Record):
287
287
  l=self.l * factor.x,
288
288
  )
289
289
 
290
- def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Self:
290
+ def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Rect:
291
291
  """Scale the rectangle by the given factor about the given pivot and return a new rectangle."""
292
292
  return Rect(
293
293
  t=(self.t - pivot.y) * factor.y + pivot.y,
@@ -296,7 +296,7 @@ class Rect(Record):
296
296
  l=(self.l - pivot.x) * factor.x + pivot.x,
297
297
  )
298
298
 
299
- def scale_centered(self, factor: Vec2, /) -> Self:
299
+ def scale_centered(self, factor: Vec2, /) -> Rect:
300
300
  """Scale the rectangle by the given factor about its center and return a new rectangle."""
301
301
  return Rect(
302
302
  t=self.t * factor.y,
@@ -305,7 +305,7 @@ class Rect(Record):
305
305
  l=self.l * factor.x,
306
306
  ).translate(self.center * (Vec2(1, 1) - factor))
307
307
 
308
- def expand(self, expansion: Vec2, /) -> Self:
308
+ def expand(self, expansion: Vec2, /) -> Rect:
309
309
  """Expand the rectangle by the given amount and return a new rectangle."""
310
310
  return Rect(
311
311
  t=self.t + expansion.y,
@@ -314,7 +314,7 @@ class Rect(Record):
314
314
  l=self.l - expansion.x,
315
315
  )
316
316
 
317
- def shrink(self, shrinkage: Vec2, /) -> Self:
317
+ def shrink(self, shrinkage: Vec2, /) -> Rect:
318
318
  """Shrink the rectangle by the given amount and return a new rectangle."""
319
319
  return Rect(
320
320
  t=self.t - shrinkage.y,
sonolus/script/record.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
+ from abc import ABCMeta
4
5
  from collections.abc import Iterable
5
6
  from inspect import getmro
6
7
  from typing import Any, ClassVar, Self, TypeVar, dataclass_transform, get_origin
@@ -20,7 +21,7 @@ from sonolus.script.internal.value import BackingSource, DataValue, Value
20
21
  from sonolus.script.num import Num
21
22
 
22
23
 
23
- class RecordMeta(type):
24
+ class RecordMeta(ABCMeta):
24
25
  @meta_fn
25
26
  def __pos__[T](cls: type[T]) -> T:
26
27
  """Create a zero-initialized record instance."""
@@ -61,13 +62,13 @@ class Record(GenericValue, metaclass=RecordMeta):
61
62
  ```
62
63
  """
63
64
 
64
- _value: dict[str, Value]
65
- _fields: ClassVar[list[_RecordField] | None] = None
66
- _constructor_signature: ClassVar[inspect.Signature]
65
+ _value_: dict[str, Value]
66
+ _fields_: ClassVar[list[_RecordField] | None] = None
67
+ _constructor_signature_: ClassVar[inspect.Signature]
67
68
 
68
69
  @classmethod
69
70
  def _validate_type_args_(cls, args: tuple[Any, ...]) -> tuple[Any, ...]:
70
- if cls._fields is None:
71
+ if cls._fields_ is None:
71
72
  raise TypeError("Base Record class cannot have type arguments")
72
73
  return super()._validate_type_args_(args)
73
74
 
@@ -79,16 +80,16 @@ class Record(GenericValue, metaclass=RecordMeta):
79
80
  if is_parameterizing:
80
81
  fields = []
81
82
  offset = 0
82
- for generic_field in cls._fields:
83
+ for generic_field in cls._fields_:
83
84
  resolved_type = validate_and_resolve_type(generic_field.type, cls._type_vars_to_args_)
84
85
  resolved_type = validate_concrete_type(resolved_type)
85
86
  field = _RecordField(generic_field.name, resolved_type, generic_field.index, offset)
86
87
  fields.append(field)
87
88
  setattr(cls, field.name, field)
88
89
  offset += resolved_type._size_()
89
- cls._fields = fields
90
+ cls._fields_ = fields
90
91
  return
91
- is_inheriting_from_existing_record_class = cls._fields is not None
92
+ is_inheriting_from_existing_record_class = cls._fields_ is not None
92
93
  if is_inheriting_from_existing_record_class and not is_parameterizing:
93
94
  # The main reason this is disallowed is that subclasses wouldn't be substitutable for their parent classes
94
95
  # Assignment of a subclass instance to a variable of the parent class would either be disallowed or would
@@ -123,8 +124,8 @@ class Record(GenericValue, metaclass=RecordMeta):
123
124
  )
124
125
 
125
126
  cls._parameterized_ = {}
126
- cls._fields = fields
127
- cls._constructor_signature = inspect.Signature(params)
127
+ cls._fields_ = fields
128
+ cls._constructor_signature_ = inspect.Signature(params)
128
129
 
129
130
  _add_inplace_ops(cls)
130
131
 
@@ -138,13 +139,13 @@ class Record(GenericValue, metaclass=RecordMeta):
138
139
 
139
140
  def __new__(cls, *args, **kwargs):
140
141
  # We override __new__ to allow changing to the parameterized version
141
- if cls._constructor_signature is None:
142
+ if cls._constructor_signature_ is None:
142
143
  raise TypeError(f"Cannot instantiate {cls.__name__}")
143
- bound = cls._constructor_signature.bind(*args, **kwargs)
144
+ bound = cls._constructor_signature_.bind(*args, **kwargs)
144
145
  bound.apply_defaults()
145
146
  values = {}
146
147
  type_vars = {}
147
- for field in cls._fields:
148
+ for field in cls._fields_:
148
149
  value = bound.arguments[field.name]
149
150
  value = accept_and_infer_types(field.type, value, type_vars)
150
151
  values[field.name] = value._get_()
@@ -157,7 +158,7 @@ class Record(GenericValue, metaclass=RecordMeta):
157
158
  else:
158
159
  parameterized = cls[type_args]
159
160
  result: cls = object.__new__(parameterized) # type: ignore
160
- result._value = values
161
+ result._value_ = values
161
162
  return result
162
163
 
163
164
  def __init__(self, *args, **kwargs):
@@ -167,12 +168,12 @@ class Record(GenericValue, metaclass=RecordMeta):
167
168
  @classmethod
168
169
  def _raw(cls, **kwargs) -> Self:
169
170
  result = object.__new__(cls)
170
- result._value = kwargs
171
+ result._value_ = kwargs
171
172
  return result
172
173
 
173
174
  @classmethod
174
175
  def _size_(cls) -> int:
175
- return sum(field.type._size_() for field in cls._fields)
176
+ return sum(field.type._size_() for field in cls._fields_)
176
177
 
177
178
  @classmethod
178
179
  def _is_value_type_(cls) -> bool:
@@ -181,18 +182,18 @@ class Record(GenericValue, metaclass=RecordMeta):
181
182
  @classmethod
182
183
  def _from_backing_source_(cls, source: BackingSource) -> Self:
183
184
  result = object.__new__(cls)
184
- result._value = {
185
+ result._value_ = {
185
186
  field.name: field.type._from_backing_source_(
186
- lambda offset, field_offset=field.offset: source((Num(offset) + Num(field_offset)).ir())
187
+ lambda offset, field_offset=field.offset: source((Num(offset) + Num(field_offset)).ir()) # type: ignore
187
188
  )
188
- for field in cls._fields
189
+ for field in cls._fields_
189
190
  }
190
191
  return result
191
192
 
192
193
  @classmethod
193
194
  def _from_place_(cls, place: BlockPlace) -> Self:
194
195
  result = object.__new__(cls)
195
- result._value = {field.name: field.type._from_place_(place.add_offset(field.offset)) for field in cls._fields}
196
+ result._value_ = {field.name: field.type._from_place_(place.add_offset(field.offset)) for field in cls._fields_}
196
197
  return result
197
198
 
198
199
  @classmethod
@@ -206,7 +207,7 @@ class Record(GenericValue, metaclass=RecordMeta):
206
207
  return value
207
208
 
208
209
  def _is_py_(self) -> bool:
209
- return all(value._is_py_() for value in self._value.values())
210
+ return all(value._is_py_() for value in self._value_.values())
210
211
 
211
212
  def _as_py_(self) -> Self:
212
213
  if not self._is_py_():
@@ -216,64 +217,64 @@ class Record(GenericValue, metaclass=RecordMeta):
216
217
  @classmethod
217
218
  def _from_list_(cls, values: Iterable[DataValue]) -> Self:
218
219
  iterator = iter(values)
219
- return cls(**{field.name: field.type._from_list_(iterator) for field in cls._fields})
220
+ return cls(**{field.name: field.type._from_list_(iterator) for field in cls._fields_})
220
221
 
221
222
  def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[DataValue | str]:
222
223
  result = []
223
- for field in self._fields:
224
- result.extend(self._value[field.name]._to_list_(level_refs))
224
+ for field in self._fields_:
225
+ result.extend(self._value_[field.name]._to_list_(level_refs))
225
226
  return result
226
227
 
227
228
  @classmethod
228
229
  def _flat_keys_(cls, prefix: str) -> list[str]:
229
230
  result = []
230
- for field in cls._fields:
231
+ for field in cls._fields_:
231
232
  result.extend(field.type._flat_keys_(f"{prefix}.{field.name}"))
232
233
  return result
233
234
 
234
235
  def _get_(self) -> Self:
235
236
  return self
236
237
 
237
- def _set_(self, value: Self):
238
+ def _set_(self, value: Any):
238
239
  raise TypeError("Record does not support _set_")
239
240
 
240
- def _copy_from_(self, value: Self):
241
+ def _copy_from_(self, value: Any):
241
242
  value = self._accept_(value)
242
- for field in self._fields:
243
+ for field in self._fields_:
243
244
  field.__set__(self, field.__get__(value))
244
245
 
245
246
  def _copy_(self) -> Self:
246
- return type(self)._raw(**{field.name: self._value[field.name]._copy_() for field in self._fields})
247
+ return type(self)._raw(**{field.name: self._value_[field.name]._copy_() for field in self._fields_})
247
248
 
248
249
  @classmethod
249
250
  def _alloc_(cls) -> Self:
250
251
  # Compared to using the constructor, this avoids unnecessary _get_ calls
251
252
  result = object.__new__(cls)
252
- result._value = {field.name: field.type._alloc_() for field in cls._fields}
253
+ result._value_ = {field.name: field.type._alloc_() for field in cls._fields_}
253
254
  return result
254
255
 
255
256
  @classmethod
256
257
  def _zero_(cls) -> Self:
257
258
  result = object.__new__(cls)
258
- result._value = {field.name: field.type._zero_() for field in cls._fields}
259
+ result._value_ = {field.name: field.type._zero_() for field in cls._fields_}
259
260
  return result
260
261
 
261
262
  def __str__(self):
262
- return (
263
- f"{self.__class__.__name__}({', '.join(f'{field.name}={field.__get__(self)}' for field in self._fields)})"
264
- )
263
+ return f"{self.__class__.__name__}({
264
+ ', '.join(f'{field.name}={field.get_internal(self)}' for field in self._fields_)
265
+ })"
265
266
 
266
267
  def __repr__(self):
267
- return (
268
- f"{self.__class__.__name__}({', '.join(f'{field.name}={field.__get__(self)!r}' for field in self._fields)})"
269
- )
268
+ return f"{self.__class__.__name__}({
269
+ ', '.join(f'{field.name}={field.get_internal(self)!r}' for field in self._fields_)
270
+ })"
270
271
 
271
272
  @meta_fn
272
273
  def __eq__(self, other: Any) -> bool:
273
274
  if not isinstance(other, type(self)):
274
275
  return False
275
276
  result: Num = Num._accept_(True)
276
- for field in self._fields:
277
+ for field in self._fields_:
277
278
  result = result.and_(field.__get__(self) == field.__get__(other))
278
279
  return result
279
280
 
@@ -282,12 +283,12 @@ class Record(GenericValue, metaclass=RecordMeta):
282
283
  if not isinstance(other, type(self)):
283
284
  return True
284
285
  result: Num = Num._accept_(False)
285
- for field in self._fields:
286
+ for field in self._fields_:
286
287
  result = result.or_(field.__get__(self) != field.__get__(other))
287
288
  return result
288
289
 
289
290
  def __hash__(self):
290
- return hash(tuple(field.__get__(self) for field in self._fields))
291
+ return hash(tuple(field.__get__(self) for field in self._fields_))
291
292
 
292
293
  @meta_fn
293
294
  def __pos__(self) -> Self:
@@ -309,16 +310,19 @@ class Record(GenericValue, metaclass=RecordMeta):
309
310
 
310
311
 
311
312
  class _RecordField(SonolusDescriptor):
312
- def __init__(self, name: str, type_: type[Value], index: int, offset: int):
313
+ def __init__(self, name: str, type_: type[Value] | Any, index: int, offset: int):
313
314
  self.name = name
314
315
  self.type = type_
315
316
  self.index = index
316
317
  self.offset = offset
317
318
 
319
+ def get_internal(self, instance: Record) -> Value:
320
+ return instance._value_[self.name]
321
+
318
322
  def __get__(self, instance: Record | None, owner=None):
319
323
  if instance is None:
320
324
  return self
321
- result = instance._value[self.name]._get_()
325
+ result = instance._value_[self.name]._get_readonly_()
322
326
  if ctx():
323
327
  return result
324
328
  else:
@@ -327,9 +331,9 @@ class _RecordField(SonolusDescriptor):
327
331
  def __set__(self, instance: Record, value):
328
332
  value = self.type._accept_(value)
329
333
  if self.type._is_value_type_():
330
- instance._value[self.name]._set_(value)
334
+ instance._value_[self.name]._set_(value)
331
335
  else:
332
- instance._value[self.name]._copy_from_(value)
336
+ instance._value_[self.name]._copy_from_(value)
333
337
 
334
338
 
335
339
  _ops_to_inplace_ops = {
sonolus/script/runtime.py CHANGED
@@ -698,7 +698,7 @@ class _TouchArray:
698
698
 
699
699
  @_runtime_skin_transform
700
700
  class _SkinTransform:
701
- value: Array[Array[float, 4], 4]
701
+ value: Array[Array[float, 4], 4] # type: ignore
702
702
 
703
703
  @property
704
704
  @meta_fn
@@ -719,7 +719,7 @@ class _SkinTransform:
719
719
 
720
720
  @_runtime_particle_transform
721
721
  class _ParticleTransform:
722
- value: Array[Array[float, 4], 4]
722
+ value: Array[Array[float, 4], 4] # type: ignore
723
723
 
724
724
  @property
725
725
  @meta_fn
@@ -857,25 +857,25 @@ def is_debug() -> bool:
857
857
  @meta_fn
858
858
  def is_play() -> bool:
859
859
  """Check if the game is running in play mode."""
860
- return ctx() and ctx().global_state.mode == Mode.PLAY
860
+ return bool(ctx() and ctx().global_state.mode == Mode.PLAY)
861
861
 
862
862
 
863
863
  @meta_fn
864
864
  def is_preview() -> bool:
865
865
  """Check if the game is running in preview mode."""
866
- return ctx() and ctx().global_state.mode == Mode.PREVIEW
866
+ return bool(ctx() and ctx().global_state.mode == Mode.PREVIEW)
867
867
 
868
868
 
869
869
  @meta_fn
870
870
  def is_watch() -> bool:
871
871
  """Check if the game is running in watch mode."""
872
- return ctx() and ctx().global_state.mode == Mode.WATCH
872
+ return bool(ctx() and ctx().global_state.mode == Mode.WATCH)
873
873
 
874
874
 
875
875
  @meta_fn
876
876
  def is_tutorial() -> bool:
877
877
  """Check if the game is running in tutorial mode."""
878
- return ctx() and ctx().global_state.mode == Mode.TUTORIAL
878
+ return bool(ctx() and ctx().global_state.mode == Mode.TUTORIAL)
879
879
 
880
880
 
881
881
  @meta_fn
@@ -884,7 +884,7 @@ def is_preprocessing() -> bool:
884
884
 
885
885
  Returns True if the current callback is one of preprocess, spawn_order, spawn_time, or despawn_time.
886
886
  """
887
- return ctx() and ctx().callback in {"preprocess", "spawnOrder", "spawnTime", "despawnTime"}
887
+ return bool(ctx() and ctx().callback in {"preprocess", "spawnOrder", "spawnTime", "despawnTime"})
888
888
 
889
889
 
890
890
  @meta_fn
@@ -1058,12 +1058,16 @@ def prev_time() -> float:
1058
1058
  def touches() -> ArrayLike[Touch]:
1059
1059
  """Get the current touches of the game."""
1060
1060
  if not ctx():
1061
- return Array[Touch, 0]()
1061
+ return Array[Touch, 0]() # type: ignore
1062
1062
  match ctx().global_state.mode:
1063
1063
  case Mode.PLAY:
1064
- return ArrayPointer[Touch](_PlayRuntimeUpdate.touch_count, ctx().blocks.RuntimeTouchArray, 0)
1064
+ return ArrayPointer[Touch]._raw(
1065
+ size=Num._accept_(_PlayRuntimeUpdate.touch_count),
1066
+ block=Num._accept_(ctx().blocks.RuntimeTouchArray),
1067
+ offset=Num._accept_(0),
1068
+ )
1065
1069
  case _:
1066
- return Array[Touch, 0]()
1070
+ return Array[Touch, 0]() # type: ignore
1067
1071
 
1068
1072
 
1069
1073
  @meta_fn
@@ -1098,24 +1102,24 @@ def navigation_direction() -> int:
1098
1102
 
1099
1103
  def skin_transform() -> Transform2d:
1100
1104
  """Get the global skin transform."""
1101
- return _SkinTransform.transform
1105
+ return _SkinTransform.transform # type: ignore
1102
1106
 
1103
1107
 
1104
1108
  @meta_fn
1105
1109
  def set_skin_transform(value: Transform2d):
1106
1110
  """Set the global skin transform."""
1107
- _SkinTransform.transform._copy_from_(value)
1111
+ _SkinTransform.transform._copy_from_(value) # type: ignore
1108
1112
 
1109
1113
 
1110
1114
  def particle_transform() -> Transform2d:
1111
1115
  """Get the global particle transform."""
1112
- return _ParticleTransform.transform
1116
+ return _ParticleTransform.transform # type: ignore
1113
1117
 
1114
1118
 
1115
1119
  @meta_fn
1116
1120
  def set_particle_transform(value: Transform2d):
1117
1121
  """Set the global particle transform."""
1118
- _ParticleTransform.transform._copy_from_(value)
1122
+ _ParticleTransform.transform._copy_from_(value) # type: ignore
1119
1123
 
1120
1124
 
1121
1125
  def background() -> Quad:
@@ -1142,12 +1146,12 @@ _runtime_ui = RuntimeUi()
1142
1146
 
1143
1147
  def runtime_ui() -> RuntimeUi:
1144
1148
  """Get the runtime UI configuration."""
1145
- return _runtime_ui
1149
+ return _runtime_ui # type: ignore
1146
1150
 
1147
1151
 
1148
1152
  def canvas() -> _PreviewRuntimeCanvas:
1149
1153
  """Get the preview canvas."""
1150
- return _PreviewRuntimeCanvas
1154
+ return _PreviewRuntimeCanvas # type: ignore
1151
1155
 
1152
1156
 
1153
1157
  def screen() -> Rect:
@@ -1157,9 +1161,9 @@ def screen() -> Rect:
1157
1161
 
1158
1162
  def level_score() -> _LevelScore:
1159
1163
  """Get the level score configuration."""
1160
- return _LevelScore
1164
+ return _LevelScore # type: ignore
1161
1165
 
1162
1166
 
1163
1167
  def level_life() -> _LevelLife:
1164
1168
  """Get the level life configuration."""
1165
- return _LevelLife
1169
+ return _LevelLife # type: ignore
sonolus/script/sprite.py CHANGED
@@ -267,7 +267,7 @@ def sprite(name: str) -> Any:
267
267
  return SkinSprite(name)
268
268
 
269
269
 
270
- type Skin = NewType("Skin", Any)
270
+ type Skin = NewType("Skin", Any) # type: ignore
271
271
 
272
272
 
273
273
  class RenderMode(StrEnum):