sonolus.py 0.3.3__tar.gz → 0.3.4__tar.gz
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_py-0.3.3 → sonolus_py-0.3.4}/PKG-INFO +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/doc_stubs/math.pyi +33 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/builtins.md +3 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/cli.md +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/constructs.md +3 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/types.md +5 -1
- sonolus_py-0.3.4/docs/index.md +27 -0
- sonolus_py-0.3.4/docs/overview.md +174 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/mkdocs.yml +1 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/pyproject.toml +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/archetype.py +15 -15
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/array.py +3 -2
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/array_like.py +20 -20
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/debug.py +4 -4
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/engine.py +2 -2
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/instruction.py +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/math_impls.py +17 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/native.py +3 -3
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/range.py +6 -6
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/value.py +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/interval.py +2 -2
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/num.py +13 -13
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/pointer.py +1 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/record.py +5 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/stream.py +3 -3
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/vec.py +6 -6
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_interval.py +3 -1
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_vec.py +20 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/uv.lock +1 -1
- sonolus_py-0.3.3/docs/index.md +0 -22
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/.github/workflows/publish.yaml +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/.gitignore +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/.python-version +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/.run/Python tests in tests.run.xml +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/LICENSE +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/README.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/doc_stubs/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/doc_stubs/builtins.pyi +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/doc_stubs/num.pyi +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/doc_stubs/random.pyi +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/CNAME +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/index.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/project.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/concepts/resources.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/builtins.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/index.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/math.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/random.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.archetype.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.array.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.array_like.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.bucket.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.containers.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.debug.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.easing.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.effect.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.engine.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.globals.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.instruction.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.interval.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.iterator.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.level.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.metadata.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.num.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.options.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.particle.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.printing.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.project.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.quad.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.record.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.runtime.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.sprite.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.stream.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.text.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.timing.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.transform.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.ui.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.values.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/docs/reference/sonolus.script.vec.md +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/generate.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/runtimes/Functions.json +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/runtimes/Level/Play/Blocks.json +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/blocks.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/excepthook.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/finalize.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/interpret.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/ir.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/mode.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/node.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/ops.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/allocate.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/constant_evaluation.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/copy_coalesce.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/dead_code.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/dominance.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/flow.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/inlining.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/liveness.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/optimize.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/passes.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/simplify.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/optimize/ssa.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/place.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/utils.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/backend/visitor.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/cli.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/collection.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/compile.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/engine.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/level.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/node.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/build/project.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/py.typed +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/bucket.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/containers.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/easing.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/effect.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/globals.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/builtin_impls.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/callbacks.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/constant.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/context.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/descriptor.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/dict_impl.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/error.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/generic.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/impl.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/introspection.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/random.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/simulation_context.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/transient.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/internal/tuple_impl.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/iterator.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/level.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/metadata.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/options.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/particle.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/printing.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/project.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/quad.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/runtime.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/sprite.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/text.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/timing.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/transform.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/ui.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/sonolus/script/values.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/__init__.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/conftest.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_array.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_array_map.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_array_set.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_assert.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_dict.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_flow.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_functions.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_helpers.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_match.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_num.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_operator.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_quad.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_random.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_range.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_record.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_transform.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_tuple.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_values.py +0 -0
- {sonolus_py-0.3.3 → sonolus_py-0.3.4}/tests/script/test_var_array.py +0 -0
|
@@ -154,3 +154,36 @@ def log(x: float, base: float = ...) -> float:
|
|
|
154
154
|
The logarithm of x to the specified base.
|
|
155
155
|
"""
|
|
156
156
|
...
|
|
157
|
+
|
|
158
|
+
def sqrt(x: float) -> float:
|
|
159
|
+
"""Compute the square root of x.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
x: A non-negative numeric value.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
The square root of x.
|
|
166
|
+
"""
|
|
167
|
+
...
|
|
168
|
+
|
|
169
|
+
def degrees(x: float) -> float:
|
|
170
|
+
"""Convert radians to degrees.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
x: An angle in radians.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
The angle in degrees.
|
|
177
|
+
"""
|
|
178
|
+
...
|
|
179
|
+
|
|
180
|
+
def radians(x: float) -> float:
|
|
181
|
+
"""Convert degrees to radians.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
x: An angle in degrees.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The angle in radians.
|
|
188
|
+
"""
|
|
189
|
+
...
|
|
@@ -25,4 +25,4 @@ sonolus-py schema
|
|
|
25
25
|
## Programmatic usage
|
|
26
26
|
The same functionality can be accessed programmatically as methods of a project.
|
|
27
27
|
|
|
28
|
-
See [Project]
|
|
28
|
+
See [Project](../reference/sonolus.script.project.md) for more information.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Constructs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Sonolus.py functions as a compiler from Python to Sonolus nodes. While most standard Python constructs are supported,
|
|
4
|
+
there are some limitations compared to standard Python. The following sections outline what Sonolus.py supports and
|
|
5
|
+
how it differs from standard Python.
|
|
4
6
|
|
|
5
7
|
## Key Differences
|
|
6
8
|
|
|
@@ -11,8 +11,12 @@ the constants `None`, `Ellipsis`, and `NotImplemented`.
|
|
|
11
11
|
`Num` is the numeric and boolean type in Sonolus.py. It is interchangeable with `int`, `float`, and `bool`.
|
|
12
12
|
Sonolus.py will treat any of these types as `Num`, but it's recommended to use what's appropriate for clarity.
|
|
13
13
|
|
|
14
|
+
Typically, `Num` isn't directly used in code since `int`, `float`, and `bool` are more specific and easier to read.
|
|
15
|
+
The main exception is for instance checking (`isinstance` or `match` patterns), where `Num` is the only supported
|
|
16
|
+
way to check for numeric or boolean values.
|
|
17
|
+
|
|
14
18
|
The Sonolus app uses 32-bit floating-point numbers for all numeric values, so precision may be lower compared to Python
|
|
15
|
-
when running
|
|
19
|
+
when running within Sonolus.
|
|
16
20
|
|
|
17
21
|
NaN and values outside the range of 32-bit floating-point numbers are not supported.
|
|
18
22
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Sonolus.py
|
|
2
|
+
Sonolus.py is a Python library for creating Sonolus engines.
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
Sonolus.py is available on PyPI and can be installed using a package manager like pip.
|
|
6
|
+
|
|
7
|
+
=== "pip"
|
|
8
|
+
```bash
|
|
9
|
+
pip install sonolus.py
|
|
10
|
+
```
|
|
11
|
+
=== "uv"
|
|
12
|
+
```bash
|
|
13
|
+
uv add sonolus.py
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Getting Started
|
|
17
|
+
Example Projects:
|
|
18
|
+
|
|
19
|
+
- [pydori](https://github.com/qwewqa/pydori): A Bandori-like engine designed to be an example project for Sonolus.py.
|
|
20
|
+
|
|
21
|
+
New Project Template: [sonolus.py-template-project](https://github.com/qwewqa/sonolus.py-template-project)
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
- [Overview](overview.md): High-level overview of Sonolus.py.
|
|
26
|
+
- [Concepts](concepts/index.md): Detailed information on concepts and usage.
|
|
27
|
+
- [Reference](reference/index.md): Detailed information on included classes and functions.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
Sonolus.py is a Python library for creating Sonolus engines. This page provides an overview of the key functionality
|
|
4
|
+
available in the library. For more detailed information, see the [Concepts](concepts/index.md) and
|
|
5
|
+
[Reference](reference/index.md) sections.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
Sonolus.py functions by compiling Python code into Sonolus nodes. As such, it supports a subset of Python including
|
|
9
|
+
most syntax and a portion of the standard library. Additionally, Sonolus.py provides its own library of types and
|
|
10
|
+
functions that are specifically designed for use in Sonolus engines.
|
|
11
|
+
|
|
12
|
+
### Language
|
|
13
|
+
|
|
14
|
+
#### Syntax
|
|
15
|
+
Most Python syntax is supported, but there are a few limitations:
|
|
16
|
+
|
|
17
|
+
- Destructuring assignment with the `*` operator is unsupported.
|
|
18
|
+
- Sequence (list and array) `match` patterns with the `*` operator are unsupported.
|
|
19
|
+
- Mapping (dict) `match` patterns are unsupported.
|
|
20
|
+
- Within functions, `import` statements are unsupported.
|
|
21
|
+
- The `global` and `nonlocal` keywords are unsupported.
|
|
22
|
+
- Exception related statements (`try`, `except`, `finally`, `raise`) are unsupported.
|
|
23
|
+
|
|
24
|
+
#### Compile Time Evaluation
|
|
25
|
+
Sonolus.py will evaluate some expressions at compile time such as basic arithmetic operations on constants,
|
|
26
|
+
boolean logical operations (`and`, `or`, `not`) on constants, and type checks (`isinstance`, `issubclass`).
|
|
27
|
+
|
|
28
|
+
In control flow constructs like `if` and `match`, Sonolus.py may determine some branches to be unreachable at compile
|
|
29
|
+
and eliminate them without evaluating them. This allows code like the following to compile successfully:
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
a = 1
|
|
33
|
+
if isinstance(a, Vec2):
|
|
34
|
+
# This branch is eliminated at compile time.
|
|
35
|
+
# If it were not, compilation would fail because `a` has no attribute `x`.
|
|
36
|
+
debug_log(a.x)
|
|
37
|
+
else:
|
|
38
|
+
debug_log(a)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
#### Variables
|
|
42
|
+
Numeric (`int`, `float`, `bool`) variables are fully supported and can be freely assigned and modified.
|
|
43
|
+
|
|
44
|
+
All other variables have the restriction that if the compiler finds multiple possible values for a variable, it may
|
|
45
|
+
not be accessed. For example, the following code will not compile:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
if random() < 0.5:
|
|
49
|
+
a = Vec2(1, 2)
|
|
50
|
+
else:
|
|
51
|
+
a = Vec2(3, 4)
|
|
52
|
+
# This will not compile because `a` could have been defined in either branch.
|
|
53
|
+
debug_log(a.x)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Function Returns
|
|
57
|
+
Similar to variables, functions returning `int`, `float`, or `bool` can have any number of return statements. Functions
|
|
58
|
+
returning `None` may also have any number of `return` or `return None` statements.
|
|
59
|
+
|
|
60
|
+
Functions returning any other type must have exactly one `return` statement, and it must be the only exit point of the
|
|
61
|
+
function. It is ok, however, for a function to have other `return` statements that are eliminated at compile time.
|
|
62
|
+
For example, the following code will compile successfully:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
def fn(a: int | Vec2):
|
|
66
|
+
if isinstance(a, Vec2):
|
|
67
|
+
return a.x + a.y
|
|
68
|
+
else:
|
|
69
|
+
return a * 2
|
|
70
|
+
|
|
71
|
+
fn(123)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Types
|
|
75
|
+
|
|
76
|
+
#### Numbers
|
|
77
|
+
Sonolus.py supports `int`, `float`, and `bool` types and most of the standard operations such as mathematical operations
|
|
78
|
+
(`+`, `-`, `*`, `/`, `//`, `%`), comparisons (`<`, `<=`, `>`, `>=`, `==`, `!=`), and boolean operations
|
|
79
|
+
(`and`, `or`, `not`).
|
|
80
|
+
|
|
81
|
+
#### Record
|
|
82
|
+
[`Record`](reference/sonolus.script.record.md) is the main way to define custom types in Sonolus.py. It functions similarly to a data class and
|
|
83
|
+
provides a way to define a type with named fields:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
class MyRecord(Record):
|
|
87
|
+
a: int
|
|
88
|
+
b: float
|
|
89
|
+
|
|
90
|
+
my_record = MyRecord(1, b=2.5)
|
|
91
|
+
my_zero_record = +MyRecord # Short for MyRecord(0, 0.0)
|
|
92
|
+
my_record_copy = +my_record # Create a copy of my_record with the same values
|
|
93
|
+
my_record.a = 123 # Modify a field of the record
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Records may also be generic:
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
class MyGenericRecord[T](Record):
|
|
100
|
+
value: T
|
|
101
|
+
|
|
102
|
+
my_generic_record = MyGenericRecord[int](42)
|
|
103
|
+
my_generic_record_2 = MyGenericRecord(MyRecord(1, 3.5)) # Type arguments are inferred
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Array
|
|
107
|
+
[`Array`](reference/sonolus.script.array.md) is a type that represents a fixed-size array of elements of a specific type.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
my_array = Array[int, 3](1, 2, 3)
|
|
111
|
+
my_array_2 = Array(4, 5, 6) # Type arguments are inferred
|
|
112
|
+
my_zero_array = +Array[int, 3] # Short for Array[int, 3](0, 0, 0)
|
|
113
|
+
my_array_copy = +my_array # Create a copy of my_array with the same values
|
|
114
|
+
my_array[2] = 10 # Modify an element of the array
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Other Types
|
|
118
|
+
Sonolus.py has limited support for other types of values such as strings, tuples, and functions. These have restrictions
|
|
119
|
+
such as not being valid as Record field types or Array element types.
|
|
120
|
+
|
|
121
|
+
### Modules
|
|
122
|
+
Sonolus.py provides a number of built-in modules that can be used in Sonolus engines. These include:
|
|
123
|
+
|
|
124
|
+
- Project
|
|
125
|
+
- [Project](reference/sonolus.script.project.md): Configuration for a Sonolus.py project.
|
|
126
|
+
- [Engine](reference/sonolus.script.engine.md): Configuration for a Sonolus.py engine.
|
|
127
|
+
- [Level](reference/sonolus.script.level.md): Configuration for a Sonolus.py level.
|
|
128
|
+
- [Archetype](reference/sonolus.script.archetype.md): Engine archetypes and their configuration.
|
|
129
|
+
- Core Types
|
|
130
|
+
- [Array](reference/sonolus.script.array.md): Fixed-size arrays.
|
|
131
|
+
- [Num](reference/sonolus.script.num.md): Numeric values (int, float, bool).
|
|
132
|
+
- [Record](reference/sonolus.script.record.md): User-defined types with named fields.
|
|
133
|
+
- Engine Resources
|
|
134
|
+
- [Bucket](reference/sonolus.script.bucket.md): Judgment buckets.
|
|
135
|
+
- [Effect](reference/sonolus.script.effect.md): Sound effects.
|
|
136
|
+
- [Instruction](reference/sonolus.script.instruction.md): Tutorial instructions.
|
|
137
|
+
- [Options](reference/sonolus.script.options.md): Engine options.
|
|
138
|
+
- [Particle](reference/sonolus.script.particle.md): Particle effects.
|
|
139
|
+
- [Sprite](reference/sonolus.script.sprite.md): Sprites and skins.
|
|
140
|
+
- [UI](reference/sonolus.script.ui.md): Engine ui configuration.
|
|
141
|
+
- Sonolus Runtime
|
|
142
|
+
- [Globals](reference/sonolus.script.globals.md): Level data and level memory definition.
|
|
143
|
+
- [Runtime](reference/sonolus.script.runtime.md): Runtime functions like time and ui configuration.
|
|
144
|
+
- [Stream](reference/sonolus.script.stream.md): Data streams recorded in play mode and used in watch mode.
|
|
145
|
+
- [Text](reference/sonolus.script.text.md): Standard Sonolus text constants.
|
|
146
|
+
- [Timing](reference/sonolus.script.timing.md): Beat and timescale related functions.
|
|
147
|
+
- Python Builtins
|
|
148
|
+
- [builtins](reference/builtins.md): Supported Python builtins.
|
|
149
|
+
- [math](reference/math.md): Supported math functions.
|
|
150
|
+
- [random](reference/random.md): Supported random functions.
|
|
151
|
+
- Utilities
|
|
152
|
+
- [ArrayLike](reference/sonolus.script.array_like.md): Mixin for array functionality.
|
|
153
|
+
- [Containers](reference/sonolus.script.containers.md): Additional container types like `VarArray` and `ArrayMap`.
|
|
154
|
+
- [Debug](reference/sonolus.script.debug.md): Debugging utilities.
|
|
155
|
+
- [Easing](reference/sonolus.script.easing.md): Easing functions for animations.
|
|
156
|
+
- [Interval](reference/sonolus.script.interval.md): Mathematical intervals.
|
|
157
|
+
- [Iterator](reference/sonolus.script.iterator.md): Iterators over collections.
|
|
158
|
+
- [Printing](reference/sonolus.script.printing.md): Preview mode number printing.
|
|
159
|
+
- [Quad](reference/sonolus.script.quad.md): Quadrilaterals.
|
|
160
|
+
- [Transform](reference/sonolus.script.transform.md): Transformations like translation, rotation, and scaling.
|
|
161
|
+
- [Values](reference/sonolus.script.values.md): Generic utilities for working with values.
|
|
162
|
+
- [Vec](reference/sonolus.script.vec.md): The Vec2 type and related functions.
|
|
163
|
+
|
|
164
|
+
For more details, see the [Reference](reference/index.md) section.
|
|
165
|
+
|
|
166
|
+
## Getting Started
|
|
167
|
+
|
|
168
|
+
Before making a new Sonolus.py engine, it may be helpful to look at some existing projects to see how they use
|
|
169
|
+
the library:
|
|
170
|
+
|
|
171
|
+
- [pydori](https://github.com/qwewqa/pydori): A Bandori-like engine designed to be an example project for Sonolus.py.
|
|
172
|
+
|
|
173
|
+
If you're starting a new project, you'll probably want to use the
|
|
174
|
+
[new project template](https://github.com/qwewqa/sonolus.py-template-project).
|
|
@@ -312,7 +312,7 @@ class StandardImport:
|
|
|
312
312
|
def callback[T: Callable](*, order: int = 0) -> Callable[[T], T]:
|
|
313
313
|
"""Annotate a callback with its order.
|
|
314
314
|
|
|
315
|
-
Callbacks are
|
|
315
|
+
Callbacks are executed from lowest to highest order. By default, callbacks have an order of 0.
|
|
316
316
|
|
|
317
317
|
Usage:
|
|
318
318
|
```python
|
|
@@ -338,9 +338,9 @@ class _ArchetypeSelfData:
|
|
|
338
338
|
|
|
339
339
|
|
|
340
340
|
class _ArchetypeReferenceData:
|
|
341
|
-
index:
|
|
341
|
+
index: int
|
|
342
342
|
|
|
343
|
-
def __init__(self, index:
|
|
343
|
+
def __init__(self, index: int):
|
|
344
344
|
self.index = index
|
|
345
345
|
|
|
346
346
|
|
|
@@ -416,21 +416,21 @@ class _BaseArchetype:
|
|
|
416
416
|
|
|
417
417
|
@classmethod
|
|
418
418
|
@meta_fn
|
|
419
|
-
def at(cls, index:
|
|
419
|
+
def at(cls, index: int) -> Self:
|
|
420
420
|
result = cls._new()
|
|
421
421
|
result._data_ = _ArchetypeReferenceData(index=Num._accept_(index))
|
|
422
422
|
return result
|
|
423
423
|
|
|
424
424
|
@classmethod
|
|
425
425
|
@meta_fn
|
|
426
|
-
def is_at(cls, index:
|
|
426
|
+
def is_at(cls, index: int) -> bool:
|
|
427
427
|
if not ctx():
|
|
428
428
|
raise RuntimeError("is_at is only available during compilation")
|
|
429
429
|
return entity_info_at(index).archetype_id == cls.id()
|
|
430
430
|
|
|
431
431
|
@classmethod
|
|
432
432
|
@meta_fn
|
|
433
|
-
def id(cls):
|
|
433
|
+
def id(cls) -> int:
|
|
434
434
|
if not ctx():
|
|
435
435
|
raise RuntimeError("Archetype id is only available during compilation")
|
|
436
436
|
result = ctx().global_state.archetypes.get(cls)
|
|
@@ -992,7 +992,7 @@ class PreviewArchetype(_BaseArchetype):
|
|
|
992
992
|
|
|
993
993
|
|
|
994
994
|
@meta_fn
|
|
995
|
-
def entity_info_at(index:
|
|
995
|
+
def entity_info_at(index: int) -> PlayEntityInfo | WatchEntityInfo | PreviewEntityInfo:
|
|
996
996
|
"""Retrieve entity info of the entity at the given index.
|
|
997
997
|
|
|
998
998
|
Available in play, watch, and preview mode.
|
|
@@ -1047,24 +1047,24 @@ class PreviewEntityInfo(Record):
|
|
|
1047
1047
|
class ArchetypeLife(Record):
|
|
1048
1048
|
"""How an entity contributes to life."""
|
|
1049
1049
|
|
|
1050
|
-
perfect_increment:
|
|
1050
|
+
perfect_increment: int
|
|
1051
1051
|
"""Life increment for a perfect judgment."""
|
|
1052
1052
|
|
|
1053
|
-
great_increment:
|
|
1053
|
+
great_increment: int
|
|
1054
1054
|
"""Life increment for a great judgment."""
|
|
1055
1055
|
|
|
1056
|
-
good_increment:
|
|
1056
|
+
good_increment: int
|
|
1057
1057
|
"""Life increment for a good judgment."""
|
|
1058
1058
|
|
|
1059
|
-
miss_increment:
|
|
1059
|
+
miss_increment: int
|
|
1060
1060
|
"""Life increment for a miss judgment."""
|
|
1061
1061
|
|
|
1062
1062
|
def update(
|
|
1063
1063
|
self,
|
|
1064
|
-
perfect_increment:
|
|
1065
|
-
great_increment:
|
|
1066
|
-
good_increment:
|
|
1067
|
-
miss_increment:
|
|
1064
|
+
perfect_increment: int | None = None,
|
|
1065
|
+
great_increment: int | None = None,
|
|
1066
|
+
good_increment: int | None = None,
|
|
1067
|
+
miss_increment: int | None = None,
|
|
1068
1068
|
):
|
|
1069
1069
|
"""Update the life increments."""
|
|
1070
1070
|
if perfect_increment is not None:
|
|
@@ -31,6 +31,7 @@ class Array[T, Size](GenericValue, ArrayLike[T], metaclass=ArrayMeta):
|
|
|
31
31
|
array_1 = Array(1, 2, 3)
|
|
32
32
|
array_2 = Array[int, 0]()
|
|
33
33
|
array_3 = +Array[int, 3] # Create a zero-initialized array
|
|
34
|
+
array_4 = +array_1 # Create a copy of array_1
|
|
34
35
|
```
|
|
35
36
|
"""
|
|
36
37
|
|
|
@@ -186,7 +187,7 @@ class Array[T, Size](GenericValue, ArrayLike[T], metaclass=ArrayMeta):
|
|
|
186
187
|
return self.size()
|
|
187
188
|
|
|
188
189
|
@meta_fn
|
|
189
|
-
def __getitem__(self, index:
|
|
190
|
+
def __getitem__(self, index: int) -> T:
|
|
190
191
|
index: Num = Num._accept_(get_positive_index(index, self.size()))
|
|
191
192
|
if index._is_py_() and 0 <= index._as_py_() < self.size():
|
|
192
193
|
const_index = index._as_py_()
|
|
@@ -230,7 +231,7 @@ class Array[T, Size](GenericValue, ArrayLike[T], metaclass=ArrayMeta):
|
|
|
230
231
|
raise InternalError("Unexpected array value")
|
|
231
232
|
|
|
232
233
|
@meta_fn
|
|
233
|
-
def __setitem__(self, index:
|
|
234
|
+
def __setitem__(self, index: int, value: T):
|
|
234
235
|
index: Num = Num._accept_(get_positive_index(index, self.size()))
|
|
235
236
|
value = self.element_type()._accept_(value)
|
|
236
237
|
if ctx():
|
|
@@ -26,10 +26,10 @@ class ArrayLike[T]:
|
|
|
26
26
|
def __len__(self) -> int:
|
|
27
27
|
...
|
|
28
28
|
|
|
29
|
-
def __getitem__(self, index:
|
|
29
|
+
def __getitem__(self, index: int) -> T:
|
|
30
30
|
...
|
|
31
31
|
|
|
32
|
-
def __setitem__(self, index:
|
|
32
|
+
def __setitem__(self, index: int, value: T):
|
|
33
33
|
...
|
|
34
34
|
```
|
|
35
35
|
"""
|
|
@@ -41,7 +41,7 @@ class ArrayLike[T]:
|
|
|
41
41
|
"""Return the length of the array."""
|
|
42
42
|
|
|
43
43
|
@abstractmethod
|
|
44
|
-
def __getitem__(self, index:
|
|
44
|
+
def __getitem__(self, index: int) -> T:
|
|
45
45
|
"""Return the item at the given index.
|
|
46
46
|
|
|
47
47
|
Args:
|
|
@@ -49,7 +49,7 @@ class ArrayLike[T]:
|
|
|
49
49
|
"""
|
|
50
50
|
|
|
51
51
|
@abstractmethod
|
|
52
|
-
def __setitem__(self, index:
|
|
52
|
+
def __setitem__(self, index: int, value: T):
|
|
53
53
|
"""Set the value of the item at the given index.
|
|
54
54
|
|
|
55
55
|
Args:
|
|
@@ -78,10 +78,10 @@ class ArrayLike[T]:
|
|
|
78
78
|
"""Return a reversed view of the array."""
|
|
79
79
|
return _ArrayReverser(self)
|
|
80
80
|
|
|
81
|
-
def _enumerate_(self, start:
|
|
81
|
+
def _enumerate_(self, start: int = 0) -> SonolusIterator[T]:
|
|
82
82
|
return _ArrayEnumerator(0, start, self)
|
|
83
83
|
|
|
84
|
-
def index(self, value: T, start:
|
|
84
|
+
def index(self, value: T, start: int = 0, stop: int | None = None) -> int:
|
|
85
85
|
"""Return the index of the value in the array equal to the given value.
|
|
86
86
|
|
|
87
87
|
Args:
|
|
@@ -98,7 +98,7 @@ class ArrayLike[T]:
|
|
|
98
98
|
i += 1
|
|
99
99
|
return -1
|
|
100
100
|
|
|
101
|
-
def count(self, value: T) ->
|
|
101
|
+
def count(self, value: T) -> int:
|
|
102
102
|
"""Return the number of elements in the array equal to the given value.
|
|
103
103
|
|
|
104
104
|
Args:
|
|
@@ -112,7 +112,7 @@ class ArrayLike[T]:
|
|
|
112
112
|
i += 1
|
|
113
113
|
return count
|
|
114
114
|
|
|
115
|
-
def last_index(self, value: T) ->
|
|
115
|
+
def last_index(self, value: T) -> int:
|
|
116
116
|
"""Return the last index of the value in the array equal to the given value.
|
|
117
117
|
|
|
118
118
|
Args:
|
|
@@ -125,7 +125,7 @@ class ArrayLike[T]:
|
|
|
125
125
|
i -= 1
|
|
126
126
|
return -1
|
|
127
127
|
|
|
128
|
-
def index_of_max(self, *, key: Callable[T, Any] | None = None) ->
|
|
128
|
+
def index_of_max(self, *, key: Callable[[T], Any] | None = None) -> int:
|
|
129
129
|
"""Return the index of the maximum value in the array.
|
|
130
130
|
|
|
131
131
|
Args:
|
|
@@ -143,7 +143,7 @@ class ArrayLike[T]:
|
|
|
143
143
|
i += 1
|
|
144
144
|
return max_index
|
|
145
145
|
|
|
146
|
-
def index_of_min(self, *, key: Callable[T, Any] | None = None) ->
|
|
146
|
+
def index_of_min(self, *, key: Callable[[T], Any] | None = None) -> int:
|
|
147
147
|
"""Return the index of the minimum value in the array.
|
|
148
148
|
|
|
149
149
|
Args:
|
|
@@ -161,17 +161,17 @@ class ArrayLike[T]:
|
|
|
161
161
|
i += 1
|
|
162
162
|
return min_index
|
|
163
163
|
|
|
164
|
-
def _max_(self, key: Callable[T, Any] | None = None) -> T:
|
|
164
|
+
def _max_(self, key: Callable[[T], Any] | None = None) -> T:
|
|
165
165
|
index = self.index_of_max(key=key)
|
|
166
166
|
assert index != -1
|
|
167
167
|
return self[index]
|
|
168
168
|
|
|
169
|
-
def _min_(self, key: Callable[T, Any] | None = None) -> T:
|
|
169
|
+
def _min_(self, key: Callable[[T], Any] | None = None) -> T:
|
|
170
170
|
index = self.index_of_min(key=key)
|
|
171
171
|
assert index != -1
|
|
172
172
|
return self[index]
|
|
173
173
|
|
|
174
|
-
def swap(self, i:
|
|
174
|
+
def swap(self, i: int, j: int, /):
|
|
175
175
|
"""Swap the values at the given indices.
|
|
176
176
|
|
|
177
177
|
Args:
|
|
@@ -182,7 +182,7 @@ class ArrayLike[T]:
|
|
|
182
182
|
self[i] = self[j]
|
|
183
183
|
self[j] = temp
|
|
184
184
|
|
|
185
|
-
def sort(self, *, key: Callable[T, Any] | None = None, reverse: bool = False):
|
|
185
|
+
def sort(self, *, key: Callable[[T], Any] | None = None, reverse: bool = False):
|
|
186
186
|
"""Sort the values in the array in place.
|
|
187
187
|
|
|
188
188
|
Args:
|
|
@@ -216,7 +216,7 @@ def _identity[T](value: T) -> T:
|
|
|
216
216
|
return value
|
|
217
217
|
|
|
218
218
|
|
|
219
|
-
def _insertion_sort[T](array: ArrayLike[T], start:
|
|
219
|
+
def _insertion_sort[T](array: ArrayLike[T], start: int, end: int, key: Callable[[T], Any], reverse: bool):
|
|
220
220
|
i = start + 1
|
|
221
221
|
if reverse:
|
|
222
222
|
while i < end:
|
|
@@ -234,7 +234,7 @@ def _insertion_sort[T](array: ArrayLike[T], start: Num, end: Num, key: Callable[
|
|
|
234
234
|
i += 1
|
|
235
235
|
|
|
236
236
|
|
|
237
|
-
def _heapify[T](array: ArrayLike[T], end:
|
|
237
|
+
def _heapify[T](array: ArrayLike[T], end: int, index: int, reverse: bool):
|
|
238
238
|
while True:
|
|
239
239
|
left = index * 2 + 1
|
|
240
240
|
right = left + 1
|
|
@@ -249,7 +249,7 @@ def _heapify[T](array: ArrayLike[T], end: Num, index: Num, reverse: bool):
|
|
|
249
249
|
index = largest
|
|
250
250
|
|
|
251
251
|
|
|
252
|
-
def _heap_sort[T](array: ArrayLike[T], start:
|
|
252
|
+
def _heap_sort[T](array: ArrayLike[T], start: int, end: int, reverse: bool):
|
|
253
253
|
i = end // 2 - 1
|
|
254
254
|
while i >= start:
|
|
255
255
|
_heapify(array, end, i, reverse)
|
|
@@ -281,10 +281,10 @@ class _ArrayReverser[V: ArrayLike](Record, ArrayLike):
|
|
|
281
281
|
def __len__(self) -> int:
|
|
282
282
|
return len(self.array)
|
|
283
283
|
|
|
284
|
-
def __getitem__(self, index:
|
|
284
|
+
def __getitem__(self, index: int) -> V:
|
|
285
285
|
return self.array[len(self) - 1 - index]
|
|
286
286
|
|
|
287
|
-
def __setitem__(self, index:
|
|
287
|
+
def __setitem__(self, index: int, value: V):
|
|
288
288
|
self.array[len(self) - 1 - index] = value
|
|
289
289
|
|
|
290
290
|
def reversed(self) -> ArrayLike[V]:
|
|
@@ -307,7 +307,7 @@ class _ArrayEnumerator[V: ArrayLike](Record, SonolusIterator):
|
|
|
307
307
|
|
|
308
308
|
|
|
309
309
|
@meta_fn
|
|
310
|
-
def get_positive_index(index:
|
|
310
|
+
def get_positive_index(index: int, length: int) -> int:
|
|
311
311
|
"""Get the positive index for the given index in the array of the given length.
|
|
312
312
|
|
|
313
313
|
This is used to convert negative indixes relative to the end of the array to positive indices.
|
|
@@ -57,7 +57,7 @@ def static_error(message: str | None = None) -> Never:
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
@meta_fn
|
|
60
|
-
def debug_log(value:
|
|
60
|
+
def debug_log(value: int | float | bool):
|
|
61
61
|
"""Log a value in debug mode."""
|
|
62
62
|
if debug_log_callback.get(None):
|
|
63
63
|
return debug_log_callback.get()(value)
|
|
@@ -66,7 +66,7 @@ def debug_log(value: Num):
|
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
@native_function(Op.DebugLog)
|
|
69
|
-
def _debug_log(value:
|
|
69
|
+
def _debug_log(value: int | float | bool):
|
|
70
70
|
print(f"[DEBUG] {value}")
|
|
71
71
|
return 0
|
|
72
72
|
|
|
@@ -77,13 +77,13 @@ def debug_pause():
|
|
|
77
77
|
input("[DEBUG] Paused")
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
def assert_true(value:
|
|
80
|
+
def assert_true(value: int | float | bool, message: str | None = None):
|
|
81
81
|
message = message if message is not None else "Assertion failed"
|
|
82
82
|
if not value:
|
|
83
83
|
error(message)
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
def assert_false(value:
|
|
86
|
+
def assert_false(value: int | float | bool, message: str | None = None):
|
|
87
87
|
message = message if message is not None else "Assertion failed"
|
|
88
88
|
if value:
|
|
89
89
|
error(message)
|
|
@@ -217,7 +217,7 @@ class WatchMode:
|
|
|
217
217
|
|
|
218
218
|
for archetype in self.archetypes:
|
|
219
219
|
if not issubclass(archetype, WatchArchetype):
|
|
220
|
-
raise ValueError(f"archetype {archetype} is not a
|
|
220
|
+
raise ValueError(f"archetype {archetype} is not a WatchArchetype")
|
|
221
221
|
|
|
222
222
|
|
|
223
223
|
class PreviewMode:
|
|
@@ -239,7 +239,7 @@ class PreviewMode:
|
|
|
239
239
|
|
|
240
240
|
for archetype in self.archetypes:
|
|
241
241
|
if not issubclass(archetype, PreviewArchetype):
|
|
242
|
-
raise ValueError(f"archetype {archetype} is not a
|
|
242
|
+
raise ValueError(f"archetype {archetype} is not a PreviewArchetype")
|
|
243
243
|
|
|
244
244
|
|
|
245
245
|
class TutorialMode:
|
|
@@ -97,7 +97,7 @@ def instructions[T](cls: type[T]) -> T | TutorialInstructions:
|
|
|
97
97
|
annotation_values = annotation.__metadata__
|
|
98
98
|
if annotation_type is not Instruction:
|
|
99
99
|
raise TypeError(
|
|
100
|
-
f"Invalid annotation for instruction: {annotation}, expected annotation of type
|
|
100
|
+
f"Invalid annotation for instruction: {annotation}, expected annotation of type Instruction"
|
|
101
101
|
)
|
|
102
102
|
if len(annotation_values) != 1 or not isinstance(annotation_values[0], _InstructionTextInfo):
|
|
103
103
|
raise TypeError(f"Invalid annotation for instruction: {annotation}, expected a single annotation value")
|
|
@@ -97,6 +97,22 @@ def _log(x: float, base: float | None = None) -> float:
|
|
|
97
97
|
return _ln(x) / _ln(base)
|
|
98
98
|
|
|
99
99
|
|
|
100
|
+
def _sqrt(x: float) -> float:
|
|
101
|
+
return x**0.5
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@native_function(Op.Degree)
|
|
105
|
+
def _degrees(x: float) -> float:
|
|
106
|
+
"""Convert radians to degrees."""
|
|
107
|
+
return math.degrees(x)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@native_function(Op.Radian)
|
|
111
|
+
def _radians(x: float) -> float:
|
|
112
|
+
"""Convert degrees to radians."""
|
|
113
|
+
return math.radians(x)
|
|
114
|
+
|
|
115
|
+
|
|
100
116
|
@native_function(Op.Rem)
|
|
101
117
|
def _remainder(x: float, y: float) -> float:
|
|
102
118
|
# This is different from math.remainder in Python's math package, which could be confusing
|
|
@@ -119,4 +135,5 @@ MATH_BUILTIN_IMPLS = {
|
|
|
119
135
|
id(math.trunc): _trunc,
|
|
120
136
|
id(round): _round,
|
|
121
137
|
id(math.log): _log,
|
|
138
|
+
id(math.sqrt): _sqrt,
|
|
122
139
|
}
|