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
sonolus/script/ui.py CHANGED
@@ -1,160 +1,216 @@
1
- from dataclasses import dataclass, field
2
- from typing import Literal
3
-
4
- UiMetric = Literal[
5
- "arcade",
6
- "arcadePercentage",
7
- "accuracy",
8
- "accuracyPercentage",
9
- "life",
10
- "perfect",
11
- "perfectPercentage",
12
- "greatGoodMiss",
13
- "greatGoodMissPercentage",
14
- "miss",
15
- "missPercentage",
16
- "errorHeatmap",
17
- ]
18
-
19
- UiJudgmentErrorStyle = Literal[
20
- "none",
21
- "plus",
22
- "minus",
23
- "arrowUp",
24
- "arrowDown",
25
- "arrowLeft",
26
- "arrowRight",
27
- "triangleUp",
28
- "triangleDown",
29
- "triangleLeft",
30
- "triangleRight",
31
- ]
32
-
33
- UiJudgmentErrorPlacement = Literal["both", "left", "right"]
34
-
35
- EaseType = Literal[
36
- "linear",
37
- "none",
38
- "inSine",
39
- "inQuad",
40
- "inCubic",
41
- "inQuart",
42
- "inQuint",
43
- "inExpo",
44
- "inCirc",
45
- "inBack",
46
- "inElastic",
47
- "outSine",
48
- "outQuad",
49
- "outCubic",
50
- "outQuart",
51
- "outQuint",
52
- "outExpo",
53
- "outCirc",
54
- "outBack",
55
- "outElastic",
56
- "inOutSine",
57
- "inOutQuad",
58
- "inOutCubic",
59
- "inOutQuart",
60
- "inOutQuint",
61
- "inOutExpo",
62
- "inOutCirc",
63
- "inOutBack",
64
- "inOutElastic",
65
- "outInSine",
66
- "outInQuad",
67
- "outInCubic",
68
- "outInQuart",
69
- "outInQuint",
70
- "outInExpo",
71
- "outInCirc",
72
- "outInBack",
73
- "outInElastic",
74
- ]
75
-
76
-
77
- @dataclass
78
- class UiAnimationTween:
79
- start: float
80
- end: float
81
- duration: float
82
- ease: EaseType
83
-
84
- def to_dict(self):
85
- return {
86
- "from": self.start,
87
- "to": self.end,
88
- "duration": self.duration,
89
- "ease": self.ease,
90
- }
91
-
92
-
93
- @dataclass
94
- class UiAnimation:
95
- scale: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 1, 0, "none"))
96
- alpha: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 0, 0.2, "outCubic"))
97
-
98
- def to_dict(self):
99
- return {
100
- "scale": self.scale.to_dict(),
101
- "alpha": self.alpha.to_dict(),
102
- }
103
-
104
-
105
- @dataclass
106
- class UiVisibility:
107
- scale: float = 1.0
108
- alpha: float = 1.0
109
-
110
- def to_dict(self):
111
- return {
112
- "scale": self.scale,
113
- "alpha": self.alpha,
114
- }
115
-
116
-
117
- @dataclass
118
- class UiConfig:
119
- scope: str | None = None
120
- primary_metric: UiMetric = "arcade"
121
- secondary_metric: UiMetric = "life"
122
- menu_visibility: UiVisibility = field(default_factory=UiVisibility)
123
- judgment_visibility: UiVisibility = field(default_factory=UiVisibility)
124
- combo_visibility: UiVisibility = field(default_factory=UiVisibility)
125
- primary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
126
- secondary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
127
- progress_visibility: UiVisibility = field(default_factory=UiVisibility)
128
- tutorial_navigation_visibility: UiVisibility = field(default_factory=UiVisibility)
129
- tutorial_instruction_visibility: UiVisibility = field(default_factory=UiVisibility)
130
- judgment_animation: UiAnimation = field(default_factory=UiAnimation)
131
- combo_animation: UiAnimation = field(
132
- default_factory=lambda: UiAnimation(
133
- scale=UiAnimationTween(1.2, 1, 0.2, "inCubic"), alpha=UiAnimationTween(1, 1, 0, "none")
134
- )
135
- )
136
- judgment_error_style: UiJudgmentErrorStyle = "none"
137
- judgment_error_placement: UiJudgmentErrorPlacement = "both"
138
- judgment_error_min: float = 0.0
139
-
140
- def to_dict(self):
141
- data = {
142
- "primaryMetric": self.primary_metric,
143
- "secondaryMetric": self.secondary_metric,
144
- "menuVisibility": self.menu_visibility.to_dict(),
145
- "judgmentVisibility": self.judgment_visibility.to_dict(),
146
- "comboVisibility": self.combo_visibility.to_dict(),
147
- "primaryMetricVisibility": self.primary_metric_visibility.to_dict(),
148
- "secondaryMetricVisibility": self.secondary_metric_visibility.to_dict(),
149
- "progressVisibility": self.progress_visibility.to_dict(),
150
- "tutorialNavigationVisibility": self.tutorial_navigation_visibility.to_dict(),
151
- "tutorialInstructionVisibility": self.tutorial_instruction_visibility.to_dict(),
152
- "judgmentAnimation": self.judgment_animation.to_dict(),
153
- "comboAnimation": self.combo_animation.to_dict(),
154
- "judgmentErrorStyle": self.judgment_error_style,
155
- "judgmentErrorPlacement": self.judgment_error_placement,
156
- "judgmentErrorMin": self.judgment_error_min,
157
- }
158
- if self.scope is not None:
159
- data["scope"] = self.scope
160
- return data
1
+ from dataclasses import dataclass, field
2
+ from enum import StrEnum
3
+
4
+
5
+ class UiMetric(StrEnum):
6
+ """A metric to display on the UI."""
7
+
8
+ ARCADE = "arcade"
9
+ ARCADE_PERCENTAGE = "arcadePercentage"
10
+ ACCURACY = "accuracy"
11
+ ACCURACY_PERCENTAGE = "accuracyPercentage"
12
+ LIFE = "life"
13
+ PERFECT = "perfect"
14
+ PERFECT_PERCENTAGE = "perfectPercentage"
15
+ GREAT_GOOD_MISS = "greatGoodMiss"
16
+ GREAT_GOOD_MISS_PERCENTAGE = "greatGoodMissPercentage"
17
+ MISS = "miss"
18
+ MISS_PERCENTAGE = "missPercentage"
19
+ ERROR_HEATMAP = "errorHeatmap"
20
+
21
+
22
+ class UiJudgmentErrorStyle(StrEnum):
23
+ """The style of the judgment error."""
24
+
25
+ NONE = "none"
26
+ PLUS = "plus"
27
+ MINUS = "minus"
28
+ ARROW_UP = "arrowUp"
29
+ ARROW_DOWN = "arrowDown"
30
+ ARROW_LEFT = "arrowLeft"
31
+ ARROW_RIGHT = "arrowRight"
32
+ TRIANGLE_UP = "triangleUp"
33
+ TRIANGLE_DOWN = "triangleDown"
34
+ TRIANGLE_LEFT = "triangleLeft"
35
+ TRIANGLE_RIGHT = "triangleRight"
36
+
37
+
38
+ class UiJudgmentErrorPlacement(StrEnum):
39
+ """The placement of the judgment error."""
40
+
41
+ BOTH = "both"
42
+ LEFT = "left"
43
+ RIGHT = "right"
44
+
45
+
46
+ class EaseType(StrEnum):
47
+ """The easing function to use."""
48
+
49
+ LINEAR = "linear"
50
+ NONE = "none"
51
+ IN_SINE = "inSine"
52
+ IN_QUAD = "inQuad"
53
+ IN_CUBIC = "inCubic"
54
+ IN_QUART = "inQuart"
55
+ IN_QUINT = "inQuint"
56
+ IN_EXPO = "inExpo"
57
+ IN_CIRC = "inCirc"
58
+ IN_BACK = "inBack"
59
+ IN_ELASTIC = "inElastic"
60
+ OUT_SINE = "outSine"
61
+ OUT_QUAD = "outQuad"
62
+ OUT_CUBIC = "outCubic"
63
+ OUT_QUART = "outQuart"
64
+ OUT_QUINT = "outQuint"
65
+ OUT_EXPO = "outExpo"
66
+ OUT_CIRC = "outCirc"
67
+ OUT_BACK = "outBack"
68
+ OUT_ELASTIC = "outElastic"
69
+ IN_OUT_SINE = "inOutSine"
70
+ IN_OUT_QUAD = "inOutQuad"
71
+ IN_OUT_CUBIC = "inOutCubic"
72
+ IN_OUT_QUART = "inOutQuart"
73
+ IN_OUT_QUINT = "inOutQuint"
74
+ IN_OUT_EXPO = "inOutExpo"
75
+ IN_OUT_CIRC = "inOutCirc"
76
+ IN_OUT_BACK = "inOutBack"
77
+ IN_OUT_ELASTIC = "inOutElastic"
78
+ OUT_IN_SINE = "outInSine"
79
+ OUT_IN_QUAD = "outInQuad"
80
+ OUT_IN_CUBIC = "outInCubic"
81
+ OUT_IN_QUART = "outInQuart"
82
+ OUT_IN_QUINT = "outInQuint"
83
+ OUT_IN_EXPO = "outInExpo"
84
+ OUT_IN_CIRC = "outInCirc"
85
+ OUT_IN_BACK = "outInBack"
86
+ OUT_IN_ELASTIC = "outInElastic"
87
+
88
+
89
+ @dataclass
90
+ class UiAnimationTween:
91
+ """Tween animation configuration for UI elements.
92
+
93
+ Args:
94
+ start: The initial value.
95
+ end: The final value.
96
+ duration: The duration of the animation.
97
+ ease: The easing function to use.
98
+ """
99
+
100
+ start: float
101
+ end: float
102
+ duration: float
103
+ ease: EaseType
104
+
105
+ def to_dict(self):
106
+ return {
107
+ "from": self.start,
108
+ "to": self.end,
109
+ "duration": self.duration,
110
+ "ease": self.ease,
111
+ }
112
+
113
+
114
+ @dataclass
115
+ class UiAnimation:
116
+ """Animation configuration for UI elements.
117
+
118
+ Args:
119
+ scale: The animation applied to scale.
120
+ alpha: The animation applied to alpha.
121
+ """
122
+
123
+ scale: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 1, 0, "none"))
124
+ alpha: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 0, 0.2, "outCubic"))
125
+
126
+ def to_dict(self):
127
+ return {
128
+ "scale": self.scale.to_dict(),
129
+ "alpha": self.alpha.to_dict(),
130
+ }
131
+
132
+
133
+ @dataclass
134
+ class UiVisibility:
135
+ """Visibility configuration for UI elements.
136
+
137
+ Args:
138
+ scale: The scale of the element.
139
+ alpha: The alpha of the element.
140
+ """
141
+
142
+ scale: float = 1.0
143
+ alpha: float = 1.0
144
+
145
+ def to_dict(self):
146
+ return {
147
+ "scale": self.scale,
148
+ "alpha": self.alpha,
149
+ }
150
+
151
+
152
+ @dataclass
153
+ class UiConfig:
154
+ """Configuration for UI elements.
155
+
156
+ Args:
157
+ scope: The scope of the configuration.
158
+ primary_metric: The primary metric to display.
159
+ secondary_metric: The secondary metric to display.
160
+ menu_visibility: The visibility configuration for the menu.
161
+ judgment_visibility: The visibility configuration for judgments.
162
+ combo_visibility: The visibility configuration for the combo.
163
+ primary_metric_visibility: The visibility configuration for the primary metric.
164
+ secondary_metric_visibility: The visibility configuration for the secondary metric.
165
+ progress_visibility: The visibility configuration for progress.
166
+ tutorial_navigation_visibility: The visibility configuration for tutorial navigation.
167
+ tutorial_instruction_visibility: The visibility configuration for tutorial instructions.
168
+ judgment_animation: The animation configuration for judgments.
169
+ combo_animation: The animation configuration for the combo.
170
+ judgment_error_style: The style of the judgment error.
171
+ judgment_error_placement: The placement of the judgment error.
172
+ judgment_error_min: The minimum judgment error.
173
+ """
174
+
175
+ scope: str | None = None
176
+ primary_metric: UiMetric = UiMetric.ARCADE
177
+ secondary_metric: UiMetric = UiMetric.LIFE
178
+ menu_visibility: UiVisibility = field(default_factory=UiVisibility)
179
+ judgment_visibility: UiVisibility = field(default_factory=UiVisibility)
180
+ combo_visibility: UiVisibility = field(default_factory=UiVisibility)
181
+ primary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
182
+ secondary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
183
+ progress_visibility: UiVisibility = field(default_factory=UiVisibility)
184
+ tutorial_navigation_visibility: UiVisibility = field(default_factory=UiVisibility)
185
+ tutorial_instruction_visibility: UiVisibility = field(default_factory=UiVisibility)
186
+ judgment_animation: UiAnimation = field(default_factory=UiAnimation)
187
+ combo_animation: UiAnimation = field(
188
+ default_factory=lambda: UiAnimation(
189
+ scale=UiAnimationTween(1.2, 1, 0.2, EaseType.IN_CUBIC), alpha=UiAnimationTween(1, 1, 0, EaseType.NONE)
190
+ )
191
+ )
192
+ judgment_error_style: UiJudgmentErrorStyle = UiJudgmentErrorStyle.NONE
193
+ judgment_error_placement: UiJudgmentErrorPlacement = UiJudgmentErrorPlacement.BOTH
194
+ judgment_error_min: float = 0.0
195
+
196
+ def to_dict(self):
197
+ data = {
198
+ "primaryMetric": self.primary_metric,
199
+ "secondaryMetric": self.secondary_metric,
200
+ "menuVisibility": self.menu_visibility.to_dict(),
201
+ "judgmentVisibility": self.judgment_visibility.to_dict(),
202
+ "comboVisibility": self.combo_visibility.to_dict(),
203
+ "primaryMetricVisibility": self.primary_metric_visibility.to_dict(),
204
+ "secondaryMetricVisibility": self.secondary_metric_visibility.to_dict(),
205
+ "progressVisibility": self.progress_visibility.to_dict(),
206
+ "tutorialNavigationVisibility": self.tutorial_navigation_visibility.to_dict(),
207
+ "tutorialInstructionVisibility": self.tutorial_instruction_visibility.to_dict(),
208
+ "judgmentAnimation": self.judgment_animation.to_dict(),
209
+ "comboAnimation": self.combo_animation.to_dict(),
210
+ "judgmentErrorStyle": self.judgment_error_style,
211
+ "judgmentErrorPlacement": self.judgment_error_placement,
212
+ "judgmentErrorMin": self.judgment_error_min,
213
+ }
214
+ if self.scope is not None:
215
+ data["scope"] = self.scope
216
+ return data
sonolus/script/values.py CHANGED
@@ -5,7 +5,10 @@ from sonolus.script.internal.impl import meta_fn, validate_value
5
5
 
6
6
  @meta_fn
7
7
  def alloc[T](type_: type[T]) -> T:
8
- """Returns an uninitialized instance of the given type."""
8
+ """Return an uninitialized instance of the given type.
9
+
10
+ Use this carefully as reading from uninitialized memory can lead to unexpected behavior.
11
+ """
9
12
  type_ = validate_concrete_type(type_)
10
13
  if ctx():
11
14
  return type_._alloc_()
@@ -15,7 +18,7 @@ def alloc[T](type_: type[T]) -> T:
15
18
 
16
19
  @meta_fn
17
20
  def zeros[T](type_: type[T]) -> T:
18
- """Returns a new instance of the given type initialized with zeros."""
21
+ """Make a new instance of the given type initialized with zeros."""
19
22
  type_ = validate_concrete_type(type_)
20
23
  if ctx():
21
24
  return copy(type_._from_list_([0] * type_._size_()))
@@ -25,19 +28,9 @@ def zeros[T](type_: type[T]) -> T:
25
28
 
26
29
  @meta_fn
27
30
  def copy[T](value: T) -> T:
28
- """Returns a deep copy of the given value."""
31
+ """Make a deep copy of the given value."""
29
32
  value = validate_value(value)
30
33
  if ctx():
31
34
  return value._copy_()
32
35
  else:
33
36
  return value._copy_()._as_py_()
34
-
35
-
36
- @meta_fn
37
- def with_default[T](value: T, default: T) -> T:
38
- """Returns the given value if it's not None, otherwise the default value."""
39
- value = validate_value(value)
40
- default = validate_value(default)
41
- if value._is_py_() and value._as_py_() is None:
42
- return default
43
- return value