sonolus.py 0.1.0__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/__init__.py +0 -0
- sonolus/backend/__init__.py +0 -0
- sonolus/backend/allocate.py +51 -0
- sonolus/backend/blocks.py +756 -0
- sonolus/backend/excepthook.py +37 -0
- sonolus/backend/finalize.py +69 -0
- sonolus/backend/flow.py +92 -0
- sonolus/backend/interpret.py +333 -0
- sonolus/backend/ir.py +89 -0
- sonolus/backend/mode.py +24 -0
- sonolus/backend/node.py +40 -0
- sonolus/backend/ops.py +197 -0
- sonolus/backend/optimize.py +9 -0
- sonolus/backend/passes.py +6 -0
- sonolus/backend/place.py +90 -0
- sonolus/backend/simplify.py +30 -0
- sonolus/backend/utils.py +48 -0
- sonolus/backend/visitor.py +880 -0
- sonolus/build/__init__.py +0 -0
- sonolus/build/cli.py +170 -0
- sonolus/build/collection.py +293 -0
- sonolus/build/compile.py +90 -0
- sonolus/build/defaults.py +32 -0
- sonolus/build/engine.py +149 -0
- sonolus/build/level.py +23 -0
- sonolus/build/node.py +43 -0
- sonolus/build/project.py +94 -0
- sonolus/py.typed +0 -0
- sonolus/script/__init__.py +0 -0
- sonolus/script/archetype.py +651 -0
- sonolus/script/array.py +241 -0
- sonolus/script/bucket.py +192 -0
- sonolus/script/callbacks.py +105 -0
- sonolus/script/comptime.py +146 -0
- sonolus/script/containers.py +247 -0
- sonolus/script/debug.py +70 -0
- sonolus/script/effect.py +132 -0
- sonolus/script/engine.py +101 -0
- sonolus/script/globals.py +234 -0
- sonolus/script/graphics.py +141 -0
- sonolus/script/icon.py +73 -0
- sonolus/script/internal/__init__.py +5 -0
- sonolus/script/internal/builtin_impls.py +144 -0
- sonolus/script/internal/context.py +365 -0
- sonolus/script/internal/descriptor.py +17 -0
- sonolus/script/internal/error.py +15 -0
- sonolus/script/internal/generic.py +197 -0
- sonolus/script/internal/impl.py +69 -0
- sonolus/script/internal/introspection.py +14 -0
- sonolus/script/internal/native.py +38 -0
- sonolus/script/internal/value.py +144 -0
- sonolus/script/interval.py +98 -0
- sonolus/script/iterator.py +211 -0
- sonolus/script/level.py +52 -0
- sonolus/script/math.py +92 -0
- sonolus/script/num.py +382 -0
- sonolus/script/options.py +194 -0
- sonolus/script/particle.py +158 -0
- sonolus/script/pointer.py +30 -0
- sonolus/script/project.py +17 -0
- sonolus/script/range.py +58 -0
- sonolus/script/record.py +293 -0
- sonolus/script/runtime.py +526 -0
- sonolus/script/sprite.py +332 -0
- sonolus/script/text.py +404 -0
- sonolus/script/timing.py +42 -0
- sonolus/script/transform.py +118 -0
- sonolus/script/ui.py +160 -0
- sonolus/script/values.py +43 -0
- sonolus/script/vec.py +48 -0
- sonolus_py-0.1.0.dist-info/METADATA +10 -0
- sonolus_py-0.1.0.dist-info/RECORD +75 -0
- sonolus_py-0.1.0.dist-info/WHEEL +4 -0
- sonolus_py-0.1.0.dist-info/entry_points.txt +2 -0
- sonolus_py-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
from typing import dataclass_transform
|
|
3
|
+
|
|
4
|
+
from sonolus.backend.blocks import Block, PlayBlock, PreviewBlock, TutorialBlock, WatchBlock
|
|
5
|
+
from sonolus.backend.mode import Mode
|
|
6
|
+
from sonolus.script.internal.descriptor import SonolusDescriptor
|
|
7
|
+
from sonolus.script.internal.generic import validate_concrete_type
|
|
8
|
+
from sonolus.script.internal.value import Value
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GlobalInfo:
|
|
12
|
+
def __init__(self, name: str, size: int, blocks: dict[Mode, Block], offset: int | None):
|
|
13
|
+
self.name = name
|
|
14
|
+
self.size = size
|
|
15
|
+
self.blocks = blocks
|
|
16
|
+
self.offset = offset
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class GlobalField(SonolusDescriptor):
|
|
20
|
+
def __init__(self, name: str, type_: type[Value], index: int, offset: int):
|
|
21
|
+
self.name = name
|
|
22
|
+
self.type = type_
|
|
23
|
+
self.index = index
|
|
24
|
+
self.offset = offset
|
|
25
|
+
|
|
26
|
+
def __get__(self, instance, owner):
|
|
27
|
+
if instance is None:
|
|
28
|
+
return self
|
|
29
|
+
|
|
30
|
+
from sonolus.script.internal.context import ctx
|
|
31
|
+
|
|
32
|
+
info = owner._global_info_
|
|
33
|
+
if not ctx():
|
|
34
|
+
raise RuntimeError("Global field access outside of compilation")
|
|
35
|
+
base = ctx().get_global_base(info)
|
|
36
|
+
return self.type._from_place_(base.add_offset(self.offset))._get_()
|
|
37
|
+
|
|
38
|
+
def __set__(self, instance, value):
|
|
39
|
+
from sonolus.script.internal.context import ctx
|
|
40
|
+
|
|
41
|
+
info = instance._global_info_
|
|
42
|
+
if not ctx():
|
|
43
|
+
raise RuntimeError("Global field access outside of compilation")
|
|
44
|
+
base = ctx().get_global_base(info)
|
|
45
|
+
target = self.type._from_place_(base.add_offset(self.offset))
|
|
46
|
+
if self.type._is_value_type_():
|
|
47
|
+
target._set_(value)
|
|
48
|
+
else:
|
|
49
|
+
target._copy_from_(value)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class GlobalPlaceholder:
|
|
53
|
+
def __init__(self, type_: type[Value], blocks: dict[Mode, Block], offset: int | None):
|
|
54
|
+
self.type = type_
|
|
55
|
+
self.blocks = blocks
|
|
56
|
+
self.offset = offset
|
|
57
|
+
self.size = type_._size_()
|
|
58
|
+
|
|
59
|
+
def get(self):
|
|
60
|
+
from sonolus.script.internal.context import ctx
|
|
61
|
+
|
|
62
|
+
if not ctx():
|
|
63
|
+
raise RuntimeError("Global access outside of compilation")
|
|
64
|
+
base = ctx().get_global_base(self)
|
|
65
|
+
return self.type._from_place_(base)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def create_global(cls: type, blocks: dict[Mode, Block], offset: int | None):
|
|
69
|
+
if issubclass(cls, Value):
|
|
70
|
+
cls = validate_concrete_type(cls)
|
|
71
|
+
return GlobalPlaceholder(cls, blocks, offset)
|
|
72
|
+
if len(cls.__bases__) != 1:
|
|
73
|
+
raise TypeError("Expected a class with no bases or a Value subclass")
|
|
74
|
+
field_offset = 0
|
|
75
|
+
for i, (
|
|
76
|
+
name,
|
|
77
|
+
annotation,
|
|
78
|
+
) in enumerate(inspect.get_annotations(cls, eval_str=True).items()):
|
|
79
|
+
type_ = validate_concrete_type(annotation)
|
|
80
|
+
setattr(cls, name, GlobalField(name, type_, i, field_offset))
|
|
81
|
+
field_offset += type_._size_()
|
|
82
|
+
cls._global_info_ = GlobalInfo(cls.__name__, field_offset, blocks, offset)
|
|
83
|
+
cls._is_comptime_value_ = True
|
|
84
|
+
return cls()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass_transform()
|
|
88
|
+
def _play_runtime_environment[T](cls: type[T]) -> T:
|
|
89
|
+
return create_global(cls, {Mode.Play: PlayBlock.RuntimeEnvironment}, 0)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass_transform()
|
|
93
|
+
def _watch_runtime_environment[T](cls: type[T]) -> T:
|
|
94
|
+
return create_global(cls, {Mode.Watch: WatchBlock.RuntimeEnvironment}, 0)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dataclass_transform()
|
|
98
|
+
def _tutorial_runtime_environment[T](cls: type[T]) -> T:
|
|
99
|
+
return create_global(cls, {Mode.Tutorial: TutorialBlock.RuntimeEnvironment}, 0)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass_transform()
|
|
103
|
+
def _preview_runtime_environment[T](cls: type[T]) -> T:
|
|
104
|
+
return create_global(cls, {Mode.Preview: PreviewBlock.RuntimeEnvironment}, 0)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass_transform()
|
|
108
|
+
def _play_runtime_update[T](cls: type[T]) -> T:
|
|
109
|
+
return create_global(cls, {Mode.Play: PlayBlock.RuntimeUpdate}, 0)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass_transform()
|
|
113
|
+
def _watch_runtime_update[T](cls: type[T]) -> T:
|
|
114
|
+
return create_global(cls, {Mode.Watch: WatchBlock.RuntimeUpdate}, 0)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@dataclass_transform()
|
|
118
|
+
def _tutorial_runtime_update[T](cls: type[T]) -> T:
|
|
119
|
+
return create_global(cls, {Mode.Tutorial: TutorialBlock.RuntimeUpdate}, 0)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass_transform()
|
|
123
|
+
def _runtime_touch_array[T](cls: type[T]) -> T:
|
|
124
|
+
return create_global(cls, {Mode.Play: PlayBlock.RuntimeTouchArray}, 0)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass_transform()
|
|
128
|
+
def _runtime_skin_transform[T](cls: type[T]) -> T:
|
|
129
|
+
return create_global(
|
|
130
|
+
cls,
|
|
131
|
+
{
|
|
132
|
+
Mode.Play: PlayBlock.RuntimeSkinTransform,
|
|
133
|
+
Mode.Watch: WatchBlock.RuntimeSkinTransform,
|
|
134
|
+
Mode.Tutorial: TutorialBlock.RuntimeSkinTransform,
|
|
135
|
+
},
|
|
136
|
+
0,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@dataclass_transform()
|
|
141
|
+
def _runtime_particle_transform[T](cls: type[T]) -> T:
|
|
142
|
+
return create_global(
|
|
143
|
+
cls,
|
|
144
|
+
{
|
|
145
|
+
Mode.Play: PlayBlock.RuntimeParticleTransform,
|
|
146
|
+
Mode.Watch: WatchBlock.RuntimeParticleTransform,
|
|
147
|
+
Mode.Tutorial: TutorialBlock.RuntimeParticleTransform,
|
|
148
|
+
},
|
|
149
|
+
0,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@dataclass_transform()
|
|
154
|
+
def _runtime_background[T](cls: type[T]) -> T:
|
|
155
|
+
return create_global(
|
|
156
|
+
cls,
|
|
157
|
+
{
|
|
158
|
+
Mode.Play: PlayBlock.RuntimeBackground,
|
|
159
|
+
Mode.Watch: WatchBlock.RuntimeBackground,
|
|
160
|
+
Mode.Tutorial: TutorialBlock.RuntimeBackground,
|
|
161
|
+
},
|
|
162
|
+
0,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass_transform()
|
|
167
|
+
def _runtime_ui[T](cls: type[T]) -> T:
|
|
168
|
+
return create_global(
|
|
169
|
+
cls,
|
|
170
|
+
{
|
|
171
|
+
Mode.Play: PlayBlock.RuntimeUI,
|
|
172
|
+
Mode.Watch: WatchBlock.RuntimeUI,
|
|
173
|
+
Mode.Tutorial: TutorialBlock.RuntimeUI,
|
|
174
|
+
Mode.Preview: PreviewBlock.RuntimeUI,
|
|
175
|
+
},
|
|
176
|
+
0,
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass_transform()
|
|
181
|
+
def _runtime_ui_configuration[T](cls: type[T]) -> T:
|
|
182
|
+
return create_global(
|
|
183
|
+
cls,
|
|
184
|
+
{
|
|
185
|
+
Mode.Play: PlayBlock.RuntimeUIConfiguration,
|
|
186
|
+
Mode.Watch: WatchBlock.RuntimeUIConfiguration,
|
|
187
|
+
Mode.Tutorial: TutorialBlock.RuntimeUIConfiguration,
|
|
188
|
+
Mode.Preview: PreviewBlock.RuntimeUIConfiguration,
|
|
189
|
+
},
|
|
190
|
+
0,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@dataclass_transform()
|
|
195
|
+
def _tutorial_instruction[T](cls: type[T]) -> T:
|
|
196
|
+
return create_global(cls, {Mode.Tutorial: TutorialBlock.TutorialInstruction}, 0)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dataclass_transform()
|
|
200
|
+
def level_memory[T](cls: type[T]) -> T:
|
|
201
|
+
return create_global(cls, {Mode.Play: PlayBlock.LevelMemory, Mode.Watch: WatchBlock.LevelMemory}, None)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass_transform()
|
|
205
|
+
def level_data[T](cls: type[T]) -> T:
|
|
206
|
+
return create_global(cls, {Mode.Play: PlayBlock.LevelData, Mode.Watch: WatchBlock.LevelData}, None)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# level_option is handled by the options decorator
|
|
210
|
+
# level_bucket is handled by the bucket decorator
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@dataclass_transform()
|
|
214
|
+
def _level_score[T](cls: type[T]) -> T:
|
|
215
|
+
return create_global(cls, {Mode.Play: PlayBlock.LevelScore, Mode.Watch: WatchBlock.LevelScore}, 0)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@dataclass_transform()
|
|
219
|
+
def _level_life[T](cls: type[T]) -> T:
|
|
220
|
+
return create_global(cls, {Mode.Play: PlayBlock.LevelLife, Mode.Watch: WatchBlock.LevelLife}, 0)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# engine_rom is handled by the compiler
|
|
224
|
+
# entity memory is handled by the archetype
|
|
225
|
+
# entity data is handled by the archetype
|
|
226
|
+
# entity shared memory is handled by the archetype
|
|
227
|
+
# entity info is handled by the archetype
|
|
228
|
+
# entity despawn is handled by the archetype
|
|
229
|
+
# entity input is handled by the archetype
|
|
230
|
+
# entity data array is handled by the archetype
|
|
231
|
+
# entity shared memory array is handled by the archetype
|
|
232
|
+
# entity info array is handled by the archetype
|
|
233
|
+
# archetype life is handled by the archetype
|
|
234
|
+
# temporary memory is handled by the compiler
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Protocol
|
|
4
|
+
|
|
5
|
+
from sonolus.script.record import Record
|
|
6
|
+
from sonolus.script.vec import Vec2
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Quad(Record):
|
|
10
|
+
bl: Vec2
|
|
11
|
+
tl: Vec2
|
|
12
|
+
tr: Vec2
|
|
13
|
+
br: Vec2
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Rect(Record):
|
|
17
|
+
t: float
|
|
18
|
+
r: float
|
|
19
|
+
b: float
|
|
20
|
+
l: float # noqa: E741
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def from_xywh(cls, x: float, y: float, w: float, h: float) -> Rect:
|
|
24
|
+
return cls(
|
|
25
|
+
t=y + h,
|
|
26
|
+
r=x + w,
|
|
27
|
+
b=y,
|
|
28
|
+
l=x,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def from_center(cls, x: float, y: float, w: float, h: float) -> Rect:
|
|
33
|
+
return cls(
|
|
34
|
+
t=y + h / 2,
|
|
35
|
+
r=x + w / 2,
|
|
36
|
+
b=y - h / 2,
|
|
37
|
+
l=x - w / 2,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def x(self) -> float:
|
|
42
|
+
return self.l
|
|
43
|
+
|
|
44
|
+
@x.setter
|
|
45
|
+
def x(self, value: float):
|
|
46
|
+
self.r += value - self.l
|
|
47
|
+
self.l = value
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def y(self) -> float:
|
|
51
|
+
return self.t
|
|
52
|
+
|
|
53
|
+
@y.setter
|
|
54
|
+
def y(self, value: float):
|
|
55
|
+
self.b += value - self.t
|
|
56
|
+
self.t = value
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def w(self) -> float:
|
|
60
|
+
return self.r - self.l
|
|
61
|
+
|
|
62
|
+
@w.setter
|
|
63
|
+
def w(self, value: float):
|
|
64
|
+
self.r = self.l + value
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def h(self) -> float:
|
|
68
|
+
return self.t - self.b
|
|
69
|
+
|
|
70
|
+
@h.setter
|
|
71
|
+
def h(self, value: float):
|
|
72
|
+
self.t = self.b + value
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def bl(self) -> Vec2:
|
|
76
|
+
return Vec2(self.l, self.b)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def tl(self) -> Vec2:
|
|
80
|
+
return Vec2(self.l, self.t)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def tr(self) -> Vec2:
|
|
84
|
+
return Vec2(self.r, self.t)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def br(self) -> Vec2:
|
|
88
|
+
return Vec2(self.r, self.b)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def center(self) -> Vec2:
|
|
92
|
+
return Vec2((self.l + self.r) / 2, (self.t + self.b) / 2)
|
|
93
|
+
|
|
94
|
+
def as_quad(self) -> Quad:
|
|
95
|
+
return Quad(
|
|
96
|
+
bl=self.bl,
|
|
97
|
+
tl=self.tl,
|
|
98
|
+
tr=self.tr,
|
|
99
|
+
br=self.br,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def scale(self, x: float, y: float | None, /):
|
|
103
|
+
if y is None:
|
|
104
|
+
y = x
|
|
105
|
+
self.l *= x
|
|
106
|
+
self.r *= x
|
|
107
|
+
self.t *= y
|
|
108
|
+
self.b *= y
|
|
109
|
+
|
|
110
|
+
def translate(self, x: float, y: float, /):
|
|
111
|
+
self.l += x
|
|
112
|
+
self.r += x
|
|
113
|
+
self.t += y
|
|
114
|
+
self.b += y
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class QuadLike(Protocol):
|
|
118
|
+
@property
|
|
119
|
+
def bl(self) -> Vec2: ...
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def tl(self) -> Vec2: ...
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def tr(self) -> Vec2: ...
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def br(self) -> Vec2: ...
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def flatten_quad(quad: QuadLike) -> tuple[float, float, float, float, float, float, float, float]:
|
|
132
|
+
return (
|
|
133
|
+
quad.bl.x,
|
|
134
|
+
quad.bl.y,
|
|
135
|
+
quad.tl.x,
|
|
136
|
+
quad.tl.y,
|
|
137
|
+
quad.tr.x,
|
|
138
|
+
quad.tr.y,
|
|
139
|
+
quad.br.x,
|
|
140
|
+
quad.br.y,
|
|
141
|
+
)
|
sonolus/script/icon.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class StandardIcon(StrEnum):
|
|
5
|
+
ADVANCED = "advanced"
|
|
6
|
+
ANGLE_DOWN = "angleDown"
|
|
7
|
+
ANGLE_LEFT = "angleLeft"
|
|
8
|
+
ANGLE_RIGHT = "angleRight"
|
|
9
|
+
ANGLES_DOWN = "anglesDown"
|
|
10
|
+
ANGLES_LEFT = "anglesLeft"
|
|
11
|
+
ANGLES_RIGHT = "anglesRight"
|
|
12
|
+
ANGLES_UP = "anglesUp"
|
|
13
|
+
ANGLE_UP = "angleUp"
|
|
14
|
+
ARROW_DOWN = "arrowDown"
|
|
15
|
+
ARROW_LEFT = "arrowLeft"
|
|
16
|
+
ARROW_RIGHT = "arrowRight"
|
|
17
|
+
ARROW_UP = "arrowUp"
|
|
18
|
+
AWARD = "award"
|
|
19
|
+
BACKGROUND = "background"
|
|
20
|
+
BELL = "bell"
|
|
21
|
+
BELL_SLASH = "bellSlash"
|
|
22
|
+
BOOKMARK = "bookmark"
|
|
23
|
+
BOOKMARK_HOLLOW = "bookmarkHollow"
|
|
24
|
+
CHECK = "check"
|
|
25
|
+
CLOCK = "clock"
|
|
26
|
+
COMMENT = "comment"
|
|
27
|
+
CROWN = "crown"
|
|
28
|
+
DELETE = "delete"
|
|
29
|
+
EDIT = "edit"
|
|
30
|
+
EFFECT = "effect"
|
|
31
|
+
ENGINE = "engine"
|
|
32
|
+
ENVELOPE = "envelope"
|
|
33
|
+
ENVELOPE_OPEN = "envelopeOpen"
|
|
34
|
+
GLOBE = "globe"
|
|
35
|
+
HEART = "heart"
|
|
36
|
+
HEART_HOLLOW = "heartHollow"
|
|
37
|
+
HIDE = "hide"
|
|
38
|
+
INFORMATION = "information"
|
|
39
|
+
LEVEL = "level"
|
|
40
|
+
LOCK = "lock"
|
|
41
|
+
MEDAL = "medal"
|
|
42
|
+
MESSAGE = "message"
|
|
43
|
+
MINUS = "minus"
|
|
44
|
+
OPTIONS = "options"
|
|
45
|
+
PARTICLE = "particle"
|
|
46
|
+
PIN = "pin"
|
|
47
|
+
PLAYER = "player"
|
|
48
|
+
PLAYLIST = "playlist"
|
|
49
|
+
PLUS = "plus"
|
|
50
|
+
POST = "post"
|
|
51
|
+
QUESTION = "question"
|
|
52
|
+
RANKING = "ranking"
|
|
53
|
+
REPLAY = "replay"
|
|
54
|
+
REPLY = "reply"
|
|
55
|
+
RESTORE = "restore"
|
|
56
|
+
ROOM = "room"
|
|
57
|
+
SEARCH = "search"
|
|
58
|
+
SETTINGS = "settings"
|
|
59
|
+
SHOW = "show"
|
|
60
|
+
SHUFFLE = "shuffle"
|
|
61
|
+
SKIN = "skin"
|
|
62
|
+
STAR = "star"
|
|
63
|
+
STAR_HALF = "starHalf"
|
|
64
|
+
STAR_HOLLOW = "starHollow"
|
|
65
|
+
STOPWATCH = "stopwatch"
|
|
66
|
+
TAG = "tag"
|
|
67
|
+
THUMBS_DOWN = "thumbsDown"
|
|
68
|
+
THUMBS_DOWN_HOLLOW = "thumbsDownHollow"
|
|
69
|
+
THUMBS_UP = "thumbsUp"
|
|
70
|
+
THUMBS_UP_HOLLOW = "thumbsUpHollow"
|
|
71
|
+
TROPHY = "trophy"
|
|
72
|
+
UNLOCK = "unlock"
|
|
73
|
+
X_MARK = "xMark"
|
|
@@ -0,0 +1,144 @@
|
|
|
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 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(isinstance(arg, Num) 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(isinstance(arg, Num) 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
|
+
}
|