sonolus.py 0.1.9__tar.gz → 0.2.1__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.2.1/.python-version +1 -0
- sonolus_py-0.2.1/.run/Python tests in tests.run.xml +21 -0
- sonolus_py-0.2.1/PKG-INFO +10 -0
- sonolus_py-0.2.1/README.md +2 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/doc_stubs/builtins.pyi +25 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/constructs.md +18 -13
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/resources.md +8 -3
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/types.md +16 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/index.md +1 -1
- sonolus_py-0.2.1/docs/reference/sonolus.script.metadata.md +3 -0
- sonolus_py-0.2.1/docs/reference/sonolus.script.printing.md +3 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/mkdocs.yml +2 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/pyproject.toml +12 -11
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/constant_evaluation.py +2 -2
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/optimize.py +12 -4
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/passes.py +2 -1
- sonolus_py-0.2.1/sonolus/backend/place.py +163 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/visitor.py +51 -3
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/cli.py +60 -9
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/collection.py +68 -26
- sonolus_py-0.2.1/sonolus/build/compile.py +145 -0
- sonolus_py-0.2.1/sonolus/build/engine.py +346 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/node.py +8 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/project.py +30 -11
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/archetype.py +154 -32
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/array.py +14 -3
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/array_like.py +6 -2
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/containers.py +166 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/debug.py +22 -4
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/effect.py +2 -2
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/engine.py +125 -17
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/builtin_impls.py +21 -2
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/constant.py +8 -4
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/context.py +30 -25
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/math_impls.py +2 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/transient.py +7 -3
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/value.py +33 -11
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/interval.py +8 -3
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/iterator.py +17 -0
- sonolus_py-0.2.1/sonolus/script/level.py +198 -0
- sonolus_py-0.2.1/sonolus/script/metadata.py +32 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/num.py +35 -15
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/options.py +23 -6
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/pointer.py +11 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/project.py +41 -5
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/quad.py +55 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/record.py +10 -5
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/runtime.py +78 -16
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/sprite.py +18 -1
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/text.py +9 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/ui.py +20 -7
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/values.py +8 -5
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/vec.py +28 -0
- sonolus_py-0.2.1/tests/script/test_array_set.py +150 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_quad.py +21 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_var_array.py +52 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/uv.lock +1 -1
- sonolus_py-0.1.9/.python-version +0 -1
- sonolus_py-0.1.9/PKG-INFO +0 -9
- sonolus_py-0.1.9/README.md +0 -2
- sonolus_py-0.1.9/docs/reference/sonolus.script.print.md +0 -3
- sonolus_py-0.1.9/sonolus/backend/place.py +0 -82
- sonolus_py-0.1.9/sonolus/build/compile.py +0 -87
- sonolus_py-0.1.9/sonolus/build/engine.py +0 -220
- sonolus_py-0.1.9/sonolus/script/level.py +0 -95
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/.github/workflows/publish.yaml +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/.gitignore +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/LICENSE +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/doc_stubs/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/doc_stubs/math.pyi +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/doc_stubs/num.pyi +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/doc_stubs/random.pyi +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/CNAME +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/builtins.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/cli.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/index.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/concepts/project.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/builtins.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/index.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/math.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/random.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.archetype.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.array.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.array_like.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.bucket.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.containers.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.debug.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.easing.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.effect.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.engine.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.globals.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.instruction.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.interval.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.iterator.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.level.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.num.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.options.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.particle.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.project.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.quad.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.record.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.runtime.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.sprite.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.text.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.timing.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.transform.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.ui.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.values.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/docs/reference/sonolus.script.vec.md +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/generate.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/runtimes/Functions.json +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/runtimes/Level/Play/Blocks.json +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/blocks.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/excepthook.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/finalize.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/interpret.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/ir.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/mode.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/node.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/ops.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/allocate.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/copy_coalesce.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/dead_code.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/dominance.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/flow.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/inlining.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/liveness.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/simplify.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/optimize/ssa.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/backend/utils.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/build/level.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/py.typed +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/bucket.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/easing.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/globals.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/instruction.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/callbacks.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/descriptor.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/dict_impl.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/error.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/generic.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/impl.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/introspection.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/native.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/random.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/range.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/internal/tuple_impl.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/particle.py +0 -0
- /sonolus_py-0.1.9/sonolus/script/print.py → /sonolus_py-0.2.1/sonolus/script/printing.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/timing.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/sonolus/script/transform.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/__init__.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/conftest.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_array.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_array_map.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_assert.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_dict.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_flow.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_functions.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_helpers.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_interval.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_match.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_num.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_operator.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_random.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_range.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_record.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_transform.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_tuple.py +0 -0
- {sonolus_py-0.1.9 → sonolus_py-0.2.1}/tests/script/test_vec.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13t
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<component name="ProjectRunConfigurationManager">
|
|
2
|
+
<configuration default="false" name="Python tests in tests" type="tests" factoryName="Autodetect" nameIsGenerated="true">
|
|
3
|
+
<module name="sonolus" />
|
|
4
|
+
<option name="ENV_FILES" value="" />
|
|
5
|
+
<option name="INTERPRETER_OPTIONS" value="" />
|
|
6
|
+
<option name="PARENT_ENVS" value="true" />
|
|
7
|
+
<envs>
|
|
8
|
+
<env name="PYTHON_JIT" value="1" />
|
|
9
|
+
</envs>
|
|
10
|
+
<option name="SDK_HOME" value="" />
|
|
11
|
+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
|
12
|
+
<option name="IS_MODULE_SDK" value="true" />
|
|
13
|
+
<option name="ADD_CONTENT_ROOTS" value="true" />
|
|
14
|
+
<option name="ADD_SOURCE_ROOTS" value="true" />
|
|
15
|
+
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
|
16
|
+
<option name="_new_additionalArguments" value=""-n 32 --cov sonolus --cov tests --cov-report xml"" />
|
|
17
|
+
<option name="_new_target" value=""$PROJECT_DIR$/tests"" />
|
|
18
|
+
<option name="_new_targetType" value=""PATH"" />
|
|
19
|
+
<method v="2" />
|
|
20
|
+
</configuration>
|
|
21
|
+
</component>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sonolus.py
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Sonolus engine development in Python
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# Sonolus.py
|
|
10
|
+
Sonolus engine development in Python. See [docs](https://sonolus.py.qwewqa.xyz) for more information.
|
|
@@ -9,6 +9,28 @@ from typing import (
|
|
|
9
9
|
overload,
|
|
10
10
|
)
|
|
11
11
|
|
|
12
|
+
def all(iterable: Iterable[builtins.bool]) -> builtins.bool:
|
|
13
|
+
"""Return True if all elements of the iterable are true.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
iterable: The iterable to evaluate.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
True if all elements are true, False otherwise.
|
|
20
|
+
"""
|
|
21
|
+
...
|
|
22
|
+
|
|
23
|
+
def any(iterable: Iterable[builtins.bool]) -> builtins.bool:
|
|
24
|
+
"""Return True if any element of the iterable is true.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
iterable: The iterable to evaluate.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
True if any element is true, False otherwise.
|
|
31
|
+
"""
|
|
32
|
+
...
|
|
33
|
+
|
|
12
34
|
def abs(x: builtins.int | builtins.float) -> builtins.int | builtins.float:
|
|
13
35
|
"""Return the absolute value of a number.
|
|
14
36
|
|
|
@@ -126,6 +148,9 @@ def len(s: object) -> builtins.int:
|
|
|
126
148
|
def map[T, S](function: Callable[[T], S], iterable: Iterable[T]) -> Iterator[S]:
|
|
127
149
|
"""Apply a function to every item of an iterable and return an iterator.
|
|
128
150
|
|
|
151
|
+
Unlike the standard Python map function, it is possible that the function may be called more than once on the
|
|
152
|
+
same item.
|
|
153
|
+
|
|
129
154
|
Args:
|
|
130
155
|
function: The function to apply.
|
|
131
156
|
iterable: The iterable to process.
|
|
@@ -18,6 +18,8 @@ Most standard Python constructs are supported in Sonolus.py.
|
|
|
18
18
|
|
|
19
19
|
## Overview
|
|
20
20
|
|
|
21
|
+
The following constructs are supported in Sonolus.py:
|
|
22
|
+
|
|
21
23
|
- Expressions:
|
|
22
24
|
- Literals:
|
|
23
25
|
- Numbers (excluding complex numbers): `0`, `1`, `1.0`, `1e3`, `0x1`, `0b1`, `0o1`
|
|
@@ -80,18 +82,20 @@ Some expressions can be evaluated at compile time:
|
|
|
80
82
|
- Comparison: for compile time constant operands: `a == b`, `a != b`, `a > b`, `a < b`, `a >= b`, `a <= b`, ...
|
|
81
83
|
- Variables assigned to compile time constants: `a = 1`, `b = a + 1`, ...
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
Some values like array sizes must be compile-time constants.
|
|
86
|
+
|
|
87
|
+
The compiler will eliminate branches known to be unreachable at compile time:
|
|
84
88
|
|
|
85
89
|
```python
|
|
86
|
-
|
|
90
|
+
def f(a):
|
|
91
|
+
if isinstance(a, Num):
|
|
92
|
+
debug_log(a)
|
|
93
|
+
else:
|
|
94
|
+
debug_log(a.x + a.y)
|
|
87
95
|
|
|
88
|
-
# This
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
elif isinstance(x, Vec2):
|
|
92
|
-
debug_log(x.x + x.y)
|
|
93
|
-
else:
|
|
94
|
-
debug_log(-1)
|
|
96
|
+
# This works because `isinstance` is evaluated at compile time and only the first (if) branch is reachable.
|
|
97
|
+
# The second (else) branch is eliminated, so we don't get an error that a does not have 'x' and 'y' attributes.
|
|
98
|
+
f(123)
|
|
95
99
|
```
|
|
96
100
|
|
|
97
101
|
## Variables
|
|
@@ -385,7 +389,8 @@ def g(a):
|
|
|
385
389
|
```
|
|
386
390
|
|
|
387
391
|
Function returns follow the same rules as variable access. If a function returns a non-num value, it most only
|
|
388
|
-
return that value.
|
|
392
|
+
return that value. If the function always returns a num, it may have any number of returns. Similarly, if a function
|
|
393
|
+
always returns None (`return None` or just `return`), it may have any number of returns.
|
|
389
394
|
|
|
390
395
|
The following are allowed:
|
|
391
396
|
|
|
@@ -439,7 +444,7 @@ def k():
|
|
|
439
444
|
return Vec2(1, 2)
|
|
440
445
|
```
|
|
441
446
|
|
|
442
|
-
|
|
447
|
+
Outside of functions returning `None` or a num, most functions should have a single `return` statement at the end.
|
|
443
448
|
|
|
444
449
|
### Classes
|
|
445
450
|
|
|
@@ -475,8 +480,8 @@ Imports are supported at the module level, but not within functions.
|
|
|
475
480
|
|
|
476
481
|
### assert
|
|
477
482
|
|
|
478
|
-
Assertions are supported.
|
|
479
|
-
callback when running in the Sonolus app.
|
|
483
|
+
Assertions are supported. Assertion failures cannot be handled and will terminate the current
|
|
484
|
+
callback when running in the Sonolus app. In debug mode, the game will also pause to indicate the error.
|
|
480
485
|
|
|
481
486
|
```python
|
|
482
487
|
assert a > 0, 'a must be positive'
|
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
Skins are defined with the `@skin` decorator:
|
|
5
5
|
|
|
6
6
|
```python
|
|
7
|
-
from sonolus.script.sprite import skin, StandardSprite, sprite, Sprite
|
|
7
|
+
from sonolus.script.sprite import skin, StandardSprite, sprite, Sprite, RenderMode
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
@skin
|
|
11
11
|
class Skin:
|
|
12
|
+
render_mode: RenderMode = RenderMode.DEFAULT
|
|
13
|
+
|
|
12
14
|
note: StandardSprite.NOTE_HEAD_RED
|
|
13
15
|
other: Sprite = sprite("other")
|
|
14
16
|
```
|
|
@@ -17,6 +19,8 @@ Standard sprites are defined by annotating the field with the corresponding valu
|
|
|
17
19
|
|
|
18
20
|
Custom sprites are defined by annotating the field with `Sprite` and calling `skin_sprite` with the sprite name.
|
|
19
21
|
|
|
22
|
+
To set the render mode for the skin, set the `render_mode` field to the desired value from `RenderMode`.
|
|
23
|
+
|
|
20
24
|
## Sound Effects
|
|
21
25
|
Sound effects are defined with the `@effects` decorator:
|
|
22
26
|
|
|
@@ -149,6 +153,7 @@ class Options:
|
|
|
149
153
|
```
|
|
150
154
|
|
|
151
155
|
There are three types of options available:
|
|
156
|
+
|
|
152
157
|
1. `slider_option`: A slider control for numeric values
|
|
153
158
|
2. `toggle_option`: A toggle switch for boolean values
|
|
154
159
|
3. `select_option`: A dropdown menu for selecting from predefined values
|
|
@@ -232,8 +237,8 @@ ui_config = UiConfig(
|
|
|
232
237
|
ease=EaseType.NONE,
|
|
233
238
|
),
|
|
234
239
|
),
|
|
235
|
-
judgment_error_style=UiJudgmentErrorStyle.
|
|
236
|
-
judgment_error_placement=UiJudgmentErrorPlacement.
|
|
240
|
+
judgment_error_style=UiJudgmentErrorStyle.LATE,
|
|
241
|
+
judgment_error_placement=UiJudgmentErrorPlacement.TOP,
|
|
237
242
|
judgment_error_min=0.0,
|
|
238
243
|
)
|
|
239
244
|
```
|
|
@@ -124,7 +124,8 @@ Array # The Generic Array type
|
|
|
124
124
|
Array[int, 3] # A concrete Array type
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
The element type of an array must be concrete (not generic) and the size must be a non-negative
|
|
127
|
+
The element type of an array must be concrete (not generic) and the size must be a non-negative compile-time
|
|
128
|
+
constant integer:
|
|
128
129
|
|
|
129
130
|
```python
|
|
130
131
|
# Ok
|
|
@@ -242,6 +243,20 @@ assert not isinstance(a, Array[int, 2])
|
|
|
242
243
|
assert not isinstance(a, Array[Pair, 3])
|
|
243
244
|
```
|
|
244
245
|
|
|
246
|
+
### Enums
|
|
247
|
+
|
|
248
|
+
There is limited support for enums containing `Num` values. Methods on enums are not supported.
|
|
249
|
+
When used as a type, any enum class is treated as `Num` and no enforcement is done on the values.
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
class MyEnum(IntEnum):
|
|
253
|
+
A = 1
|
|
254
|
+
B = 2
|
|
255
|
+
|
|
256
|
+
a = Array[MyEnum, 2](MyEnum.A, MyEnum.B)
|
|
257
|
+
b = Array[MyEnum, 2](1, 2)
|
|
258
|
+
```
|
|
259
|
+
|
|
245
260
|
## Record
|
|
246
261
|
|
|
247
262
|
`Record` is the base class for user-defined types in Sonolus.py. It functions similarly to dataclasses.
|
|
@@ -96,10 +96,11 @@ nav:
|
|
|
96
96
|
- reference/sonolus.script.interval.md
|
|
97
97
|
- reference/sonolus.script.iterator.md
|
|
98
98
|
- reference/sonolus.script.level.md
|
|
99
|
+
- reference/sonolus.script.metadata.md
|
|
99
100
|
- reference/sonolus.script.num.md
|
|
100
101
|
- reference/sonolus.script.options.md
|
|
101
102
|
- reference/sonolus.script.particle.md
|
|
102
|
-
- reference/sonolus.script.
|
|
103
|
+
- reference/sonolus.script.printing.md
|
|
103
104
|
- reference/sonolus.script.project.md
|
|
104
105
|
- reference/sonolus.script.quad.md
|
|
105
106
|
- reference/sonolus.script.record.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sonolus.py"
|
|
3
|
-
version = "0.1
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
description = "Sonolus engine development in Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -9,16 +9,7 @@ requires-python = ">=3.12"
|
|
|
9
9
|
sonolus-py = "sonolus.build.cli:main"
|
|
10
10
|
|
|
11
11
|
[tool.uv]
|
|
12
|
-
|
|
13
|
-
"hypothesis>=6.115.3",
|
|
14
|
-
"pre-commit>=4.0.1",
|
|
15
|
-
"pytest-xdist>=3.6.1",
|
|
16
|
-
"pytest>=8.3.3",
|
|
17
|
-
"ruff>=0.6.9",
|
|
18
|
-
"pytest-cov>=6.0.0",
|
|
19
|
-
"tox>=4.23.2",
|
|
20
|
-
"tox-uv>=1.16.0",
|
|
21
|
-
]
|
|
12
|
+
default-groups = ["dev", "docs"]
|
|
22
13
|
|
|
23
14
|
[tool.ruff]
|
|
24
15
|
line-length = 120
|
|
@@ -37,6 +28,16 @@ requires = ["hatchling"]
|
|
|
37
28
|
build-backend = "hatchling.build"
|
|
38
29
|
|
|
39
30
|
[dependency-groups]
|
|
31
|
+
dev = [
|
|
32
|
+
"hypothesis>=6.115.3",
|
|
33
|
+
"pre-commit>=4.0.1",
|
|
34
|
+
"pytest-xdist>=3.6.1",
|
|
35
|
+
"pytest>=8.3.3",
|
|
36
|
+
"ruff>=0.6.9",
|
|
37
|
+
"pytest-cov>=6.0.0",
|
|
38
|
+
"tox>=4.23.2",
|
|
39
|
+
"tox-uv>=1.16.0",
|
|
40
|
+
]
|
|
40
41
|
docs = [
|
|
41
42
|
"mkdocs-material>=9.5.45",
|
|
42
43
|
"mkdocs>=1.6.1",
|
|
@@ -315,8 +315,8 @@ class SparseConditionalConstantPropagation(CompilerPass):
|
|
|
315
315
|
return 1
|
|
316
316
|
return functools.reduce(operator.pow, args)
|
|
317
317
|
case Op.Log:
|
|
318
|
-
assert len(args) ==
|
|
319
|
-
return math.log(args[0]
|
|
318
|
+
assert len(args) == 1
|
|
319
|
+
return math.log(args[0])
|
|
320
320
|
case Op.Ceil:
|
|
321
321
|
assert len(args) == 1
|
|
322
322
|
return math.ceil(args[0])
|
|
@@ -12,13 +12,21 @@ from sonolus.backend.optimize.passes import run_passes
|
|
|
12
12
|
from sonolus.backend.optimize.simplify import CoalesceFlow, NormalizeSwitch, RewriteToSwitch
|
|
13
13
|
from sonolus.backend.optimize.ssa import FromSSA, ToSSA
|
|
14
14
|
|
|
15
|
-
MINIMAL_PASSES =
|
|
15
|
+
MINIMAL_PASSES = (
|
|
16
16
|
CoalesceFlow(),
|
|
17
17
|
UnreachableCodeElimination(),
|
|
18
18
|
AllocateBasic(),
|
|
19
|
-
|
|
19
|
+
)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
FAST_PASSES = (
|
|
22
|
+
CoalesceFlow(),
|
|
23
|
+
UnreachableCodeElimination(),
|
|
24
|
+
AdvancedDeadCodeElimination(),
|
|
25
|
+
CoalesceFlow(),
|
|
26
|
+
Allocate(),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
STANDARD_PASSES = (
|
|
22
30
|
CoalesceFlow(),
|
|
23
31
|
UnreachableCodeElimination(),
|
|
24
32
|
DeadCodeElimination(),
|
|
@@ -37,7 +45,7 @@ STANDARD_PASSES = [
|
|
|
37
45
|
CoalesceFlow(),
|
|
38
46
|
NormalizeSwitch(),
|
|
39
47
|
Allocate(),
|
|
40
|
-
|
|
48
|
+
)
|
|
41
49
|
|
|
42
50
|
|
|
43
51
|
def optimize_and_allocate(cfg: BasicBlock):
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from collections import deque
|
|
5
|
+
from collections.abc import Sequence
|
|
5
6
|
|
|
6
7
|
from sonolus.backend.optimize.flow import BasicBlock
|
|
7
8
|
|
|
@@ -35,7 +36,7 @@ class CompilerPass(ABC):
|
|
|
35
36
|
pass
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def run_passes(entry: BasicBlock, passes:
|
|
39
|
+
def run_passes(entry: BasicBlock, passes: Sequence[CompilerPass]) -> BasicBlock:
|
|
39
40
|
active_passes = set()
|
|
40
41
|
queue = deque(passes)
|
|
41
42
|
while queue:
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from typing import Self
|
|
3
|
+
|
|
4
|
+
from sonolus.backend.blocks import Block
|
|
5
|
+
|
|
6
|
+
type Place = BlockPlace | SSAPlace
|
|
7
|
+
type BlockValue = Block | int | TempBlock | Place
|
|
8
|
+
type IndexValue = int | Place
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TempBlock:
|
|
12
|
+
__slots__ = ("__hash", "name", "size")
|
|
13
|
+
|
|
14
|
+
def __init__(self, name: str, size: int = 1):
|
|
15
|
+
self.name = name
|
|
16
|
+
self.size = size
|
|
17
|
+
self.__hash = hash(name) # Precompute hash based on name alone
|
|
18
|
+
|
|
19
|
+
def __repr__(self):
|
|
20
|
+
return f"TempBlock(name={self.name!r}, size={self.size!r})"
|
|
21
|
+
|
|
22
|
+
def __str__(self):
|
|
23
|
+
return f"{self.name}"
|
|
24
|
+
|
|
25
|
+
def __getitem__(self, item) -> "BlockPlace":
|
|
26
|
+
return BlockPlace(self, item)
|
|
27
|
+
|
|
28
|
+
def __iter__(self) -> "Iterator[BlockPlace]":
|
|
29
|
+
for i in range(self.size):
|
|
30
|
+
yield self[i]
|
|
31
|
+
|
|
32
|
+
def __eq__(self, other):
|
|
33
|
+
return isinstance(other, TempBlock) and self.name == other.name and self.size == other.size
|
|
34
|
+
|
|
35
|
+
def __lt__(self, other):
|
|
36
|
+
if not isinstance(other, TempBlock):
|
|
37
|
+
return NotImplemented
|
|
38
|
+
return str(self) < str(other)
|
|
39
|
+
|
|
40
|
+
def __le__(self, other):
|
|
41
|
+
if not isinstance(other, TempBlock):
|
|
42
|
+
return NotImplemented
|
|
43
|
+
return str(self) <= str(other)
|
|
44
|
+
|
|
45
|
+
def __gt__(self, other):
|
|
46
|
+
if not isinstance(other, TempBlock):
|
|
47
|
+
return NotImplemented
|
|
48
|
+
return str(self) > str(other)
|
|
49
|
+
|
|
50
|
+
def __ge__(self, other):
|
|
51
|
+
if not isinstance(other, TempBlock):
|
|
52
|
+
return NotImplemented
|
|
53
|
+
return str(self) >= str(other)
|
|
54
|
+
|
|
55
|
+
def __hash__(self):
|
|
56
|
+
return self.__hash
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class BlockPlace:
|
|
60
|
+
__slots__ = ("__hash", "block", "index", "offset")
|
|
61
|
+
|
|
62
|
+
def __init__(self, block: BlockValue, index: IndexValue = 0, offset: int = 0):
|
|
63
|
+
self.block = block
|
|
64
|
+
self.index = index
|
|
65
|
+
self.offset = offset
|
|
66
|
+
self.__hash = hash((block, index, offset))
|
|
67
|
+
|
|
68
|
+
def __repr__(self):
|
|
69
|
+
return f"BlockPlace(block={self.block!r}, index={self.index!r}, offset={self.offset!r})"
|
|
70
|
+
|
|
71
|
+
def __str__(self):
|
|
72
|
+
if isinstance(self.block, TempBlock) and self.block.size == 1 and self.index == 0 and self.offset == 0:
|
|
73
|
+
return f"{self.block}"
|
|
74
|
+
elif isinstance(self.index, int):
|
|
75
|
+
return f"{self.block}[{self.index + self.offset}]"
|
|
76
|
+
elif self.offset == 0:
|
|
77
|
+
return f"{self.block}[{self.index}]"
|
|
78
|
+
else:
|
|
79
|
+
return f"{self.block}[{self.index} + {self.offset}]"
|
|
80
|
+
|
|
81
|
+
def add_offset(self, offset: int) -> Self:
|
|
82
|
+
return BlockPlace(self.block, self.index, self.offset + offset)
|
|
83
|
+
|
|
84
|
+
def __eq__(self, other):
|
|
85
|
+
return (
|
|
86
|
+
isinstance(other, BlockPlace)
|
|
87
|
+
and self.block == other.block
|
|
88
|
+
and self.index == other.index
|
|
89
|
+
and self.offset == other.offset
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def __lt__(self, other):
|
|
93
|
+
if not isinstance(other, BlockPlace):
|
|
94
|
+
return NotImplemented
|
|
95
|
+
return str(self) < str(other)
|
|
96
|
+
|
|
97
|
+
def __le__(self, other):
|
|
98
|
+
if not isinstance(other, BlockPlace):
|
|
99
|
+
return NotImplemented
|
|
100
|
+
return str(self) <= str(other)
|
|
101
|
+
|
|
102
|
+
def __gt__(self, other):
|
|
103
|
+
if not isinstance(other, BlockPlace):
|
|
104
|
+
return NotImplemented
|
|
105
|
+
return str(self) > str(other)
|
|
106
|
+
|
|
107
|
+
def __ge__(self, other):
|
|
108
|
+
if not isinstance(other, BlockPlace):
|
|
109
|
+
return NotImplemented
|
|
110
|
+
return str(self) >= str(other)
|
|
111
|
+
|
|
112
|
+
def __hash__(self):
|
|
113
|
+
return self.__hash
|
|
114
|
+
|
|
115
|
+
def __iter__(self):
|
|
116
|
+
yield self.block
|
|
117
|
+
yield self.index
|
|
118
|
+
yield self.offset
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class SSAPlace:
|
|
122
|
+
__slots__ = ("__hash", "name", "num")
|
|
123
|
+
|
|
124
|
+
def __init__(self, name: str, num: int):
|
|
125
|
+
self.name = name
|
|
126
|
+
self.num = num
|
|
127
|
+
self.__hash = hash((name, num))
|
|
128
|
+
|
|
129
|
+
def __repr__(self):
|
|
130
|
+
return f"SSAPlace(name={self.name!r}, num={self.num!r})"
|
|
131
|
+
|
|
132
|
+
def __str__(self):
|
|
133
|
+
return f"{self.name}.{self.num}"
|
|
134
|
+
|
|
135
|
+
def __eq__(self, other):
|
|
136
|
+
return isinstance(other, SSAPlace) and self.name == other.name and self.num == other.num
|
|
137
|
+
|
|
138
|
+
def __lt__(self, other):
|
|
139
|
+
if not isinstance(other, SSAPlace):
|
|
140
|
+
return NotImplemented
|
|
141
|
+
return str(self) < str(other)
|
|
142
|
+
|
|
143
|
+
def __le__(self, other):
|
|
144
|
+
if not isinstance(other, SSAPlace):
|
|
145
|
+
return NotImplemented
|
|
146
|
+
return str(self) <= str(other)
|
|
147
|
+
|
|
148
|
+
def __gt__(self, other):
|
|
149
|
+
if not isinstance(other, SSAPlace):
|
|
150
|
+
return NotImplemented
|
|
151
|
+
return str(self) > str(other)
|
|
152
|
+
|
|
153
|
+
def __ge__(self, other):
|
|
154
|
+
if not isinstance(other, SSAPlace):
|
|
155
|
+
return NotImplemented
|
|
156
|
+
return str(self) >= str(other)
|
|
157
|
+
|
|
158
|
+
def __hash__(self):
|
|
159
|
+
return self.__hash
|
|
160
|
+
|
|
161
|
+
def __iter__(self):
|
|
162
|
+
yield self.name
|
|
163
|
+
yield self.num
|