sonolus.py 0.2.0__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.0 → sonolus_py-0.2.1}/PKG-INFO +2 -2
- sonolus_py-0.2.1/README.md +2 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/doc_stubs/builtins.pyi +3 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/constructs.md +18 -13
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/resources.md +3 -2
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/types.md +2 -1
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/index.md +1 -1
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/pyproject.toml +12 -11
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/archetype.py +44 -6
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/array.py +3 -3
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/array_like.py +6 -2
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/containers.py +166 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/debug.py +20 -2
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/engine.py +2 -2
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/constant.py +3 -3
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/transient.py +3 -3
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/value.py +27 -11
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/interval.py +3 -14
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/num.py +26 -15
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/options.py +18 -3
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/pointer.py +9 -1
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/quad.py +55 -1
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/record.py +3 -3
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/runtime.py +17 -6
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/text.py +9 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/ui.py +13 -4
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/values.py +1 -1
- sonolus_py-0.2.1/tests/script/test_array_set.py +150 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_quad.py +21 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/uv.lock +1 -1
- sonolus_py-0.2.0/.python-version +0 -1
- sonolus_py-0.2.0/README.md +0 -2
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/.github/workflows/publish.yaml +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/.gitignore +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/LICENSE +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/doc_stubs/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/doc_stubs/math.pyi +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/doc_stubs/num.pyi +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/doc_stubs/random.pyi +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/CNAME +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/builtins.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/cli.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/index.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/concepts/project.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/builtins.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/index.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/math.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/random.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.archetype.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.array.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.array_like.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.bucket.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.containers.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.debug.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.easing.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.effect.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.engine.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.globals.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.instruction.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.interval.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.iterator.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.level.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.metadata.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.num.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.options.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.particle.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.printing.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.project.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.quad.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.record.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.runtime.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.sprite.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.text.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.timing.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.transform.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.ui.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.values.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/docs/reference/sonolus.script.vec.md +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/mkdocs.yml +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/generate.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/runtimes/Functions.json +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/runtimes/Level/Play/Blocks.json +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/blocks.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/excepthook.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/finalize.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/interpret.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/ir.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/mode.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/node.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/ops.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/allocate.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/constant_evaluation.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/copy_coalesce.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/dead_code.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/dominance.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/flow.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/inlining.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/liveness.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/optimize.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/passes.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/simplify.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/optimize/ssa.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/place.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/utils.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/backend/visitor.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/cli.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/collection.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/compile.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/engine.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/level.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/node.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/build/project.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/py.typed +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/bucket.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/easing.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/effect.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/globals.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/instruction.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/builtin_impls.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/callbacks.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/context.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/descriptor.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/dict_impl.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/error.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/generic.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/impl.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/introspection.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/math_impls.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/native.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/random.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/range.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/internal/tuple_impl.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/iterator.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/level.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/metadata.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/particle.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/printing.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/project.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/sprite.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/timing.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/transform.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/sonolus/script/vec.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/__init__.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/conftest.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_array.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_array_map.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_assert.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_dict.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_flow.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_functions.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_helpers.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_interval.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_match.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_num.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_operator.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_random.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_range.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_record.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_transform.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_tuple.py +0 -0
- {sonolus_py-0.2.0 → sonolus_py-0.2.1}/tests/script/test_var_array.py +0 -0
- {sonolus_py-0.2.0 → 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>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sonolus.py
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Sonolus engine development in Python
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
|
|
9
9
|
# Sonolus.py
|
|
10
|
-
Sonolus engine development in Python.
|
|
10
|
+
Sonolus engine development in Python. See [docs](https://sonolus.py.qwewqa.xyz) for more information.
|
|
@@ -148,6 +148,9 @@ def len(s: object) -> builtins.int:
|
|
|
148
148
|
def map[T, S](function: Callable[[T], S], iterable: Iterable[T]) -> Iterator[S]:
|
|
149
149
|
"""Apply a function to every item of an iterable and return an iterator.
|
|
150
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
|
+
|
|
151
154
|
Args:
|
|
152
155
|
function: The function to apply.
|
|
153
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'
|
|
@@ -153,6 +153,7 @@ class Options:
|
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
There are three types of options available:
|
|
156
|
+
|
|
156
157
|
1. `slider_option`: A slider control for numeric values
|
|
157
158
|
2. `toggle_option`: A toggle switch for boolean values
|
|
158
159
|
3. `select_option`: A dropdown menu for selecting from predefined values
|
|
@@ -236,8 +237,8 @@ ui_config = UiConfig(
|
|
|
236
237
|
ease=EaseType.NONE,
|
|
237
238
|
),
|
|
238
239
|
),
|
|
239
|
-
judgment_error_style=UiJudgmentErrorStyle.
|
|
240
|
-
judgment_error_placement=UiJudgmentErrorPlacement.
|
|
240
|
+
judgment_error_style=UiJudgmentErrorStyle.LATE,
|
|
241
|
+
judgment_error_placement=UiJudgmentErrorPlacement.TOP,
|
|
241
242
|
judgment_error_min=0.0,
|
|
242
243
|
)
|
|
243
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sonolus.py"
|
|
3
|
-
version = "0.2.
|
|
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",
|
|
@@ -8,10 +8,9 @@ from enum import Enum, StrEnum
|
|
|
8
8
|
from types import FunctionType
|
|
9
9
|
from typing import Annotated, Any, ClassVar, Self, TypedDict, get_origin
|
|
10
10
|
|
|
11
|
-
from sonolus.backend.ir import IRConst, IRInstr
|
|
11
|
+
from sonolus.backend.ir import IRConst, IRExpr, IRInstr, IRPureInstr, IRStmt
|
|
12
12
|
from sonolus.backend.mode import Mode
|
|
13
13
|
from sonolus.backend.ops import Op
|
|
14
|
-
from sonolus.backend.place import BlockPlace
|
|
15
14
|
from sonolus.script.bucket import Bucket, Judgment
|
|
16
15
|
from sonolus.script.internal.callbacks import PLAY_CALLBACKS, PREVIEW_CALLBACKS, WATCH_ARCHETYPE_CALLBACKS, CallbackInfo
|
|
17
16
|
from sonolus.script.internal.context import ctx
|
|
@@ -20,9 +19,9 @@ from sonolus.script.internal.generic import validate_concrete_type
|
|
|
20
19
|
from sonolus.script.internal.impl import meta_fn, validate_value
|
|
21
20
|
from sonolus.script.internal.introspection import get_field_specifiers
|
|
22
21
|
from sonolus.script.internal.native import native_call
|
|
23
|
-
from sonolus.script.internal.value import Value
|
|
22
|
+
from sonolus.script.internal.value import BackingValue, DataValue, Value
|
|
24
23
|
from sonolus.script.num import Num
|
|
25
|
-
from sonolus.script.pointer import _deref
|
|
24
|
+
from sonolus.script.pointer import _backing_deref, _deref
|
|
26
25
|
from sonolus.script.record import Record
|
|
27
26
|
from sonolus.script.values import zeros
|
|
28
27
|
|
|
@@ -44,6 +43,17 @@ class _ArchetypeFieldInfo:
|
|
|
44
43
|
storage: _StorageType
|
|
45
44
|
|
|
46
45
|
|
|
46
|
+
class _ExportBackingValue(BackingValue):
|
|
47
|
+
def __init__(self, index: IRExpr):
|
|
48
|
+
self.index = index
|
|
49
|
+
|
|
50
|
+
def read(self) -> IRExpr:
|
|
51
|
+
raise NotImplementedError("Exported fields are write-only")
|
|
52
|
+
|
|
53
|
+
def write(self, value: IRExpr) -> IRStmt:
|
|
54
|
+
return IRInstr(Op.ExportValue, [self.index, value])
|
|
55
|
+
|
|
56
|
+
|
|
47
57
|
class _ArchetypeField(SonolusDescriptor):
|
|
48
58
|
def __init__(self, name: str, data_name: str, storage: _StorageType, offset: int, type_: type[Value]):
|
|
49
59
|
self.name = name
|
|
@@ -70,7 +80,20 @@ class _ArchetypeField(SonolusDescriptor):
|
|
|
70
80
|
case _ArchetypeLevelData(values=values):
|
|
71
81
|
result = values[self.name]
|
|
72
82
|
case _StorageType.EXPORTED:
|
|
73
|
-
|
|
83
|
+
match instance._data_:
|
|
84
|
+
case _ArchetypeSelfData():
|
|
85
|
+
|
|
86
|
+
def backing_source(i: IRExpr):
|
|
87
|
+
return _ExportBackingValue(IRPureInstr(Op.Add, [i, IRConst(self.offset)]))
|
|
88
|
+
|
|
89
|
+
result = _backing_deref(
|
|
90
|
+
backing_source,
|
|
91
|
+
self.type,
|
|
92
|
+
)
|
|
93
|
+
case _ArchetypeReferenceData():
|
|
94
|
+
raise RuntimeError("Exported fields of other entities are not accessible")
|
|
95
|
+
case _ArchetypeLevelData():
|
|
96
|
+
raise RuntimeError("Exported fields are not available in level data")
|
|
74
97
|
case _StorageType.MEMORY:
|
|
75
98
|
match instance._data_:
|
|
76
99
|
case _ArchetypeSelfData():
|
|
@@ -584,6 +607,7 @@ class _BaseArchetype:
|
|
|
584
607
|
cls._spawn_signature_ = inspect.Signature(
|
|
585
608
|
[inspect.Parameter(name, inspect.Parameter.POSITIONAL_OR_KEYWORD) for name in cls._memory_fields_]
|
|
586
609
|
)
|
|
610
|
+
cls._post_init_fields()
|
|
587
611
|
|
|
588
612
|
@property
|
|
589
613
|
@abstractmethod
|
|
@@ -609,6 +633,10 @@ class _BaseArchetype:
|
|
|
609
633
|
case _:
|
|
610
634
|
raise RuntimeError("Invalid entity data")
|
|
611
635
|
|
|
636
|
+
@classmethod
|
|
637
|
+
def _post_init_fields(cls):
|
|
638
|
+
pass
|
|
639
|
+
|
|
612
640
|
|
|
613
641
|
class PlayArchetype(_BaseArchetype):
|
|
614
642
|
"""Base class for play mode archetypes.
|
|
@@ -885,6 +913,11 @@ class WatchArchetype(_BaseArchetype):
|
|
|
885
913
|
case _:
|
|
886
914
|
raise RuntimeError("Result is only accessible from the entity itself")
|
|
887
915
|
|
|
916
|
+
@classmethod
|
|
917
|
+
def _post_init_fields(cls):
|
|
918
|
+
if cls._exported_fields_:
|
|
919
|
+
raise RuntimeError("Watch archetypes cannot have exported fields")
|
|
920
|
+
|
|
888
921
|
|
|
889
922
|
class PreviewArchetype(_BaseArchetype):
|
|
890
923
|
"""Base class for preview mode archetypes.
|
|
@@ -934,6 +967,11 @@ class PreviewArchetype(_BaseArchetype):
|
|
|
934
967
|
"""The index of this entity."""
|
|
935
968
|
return self._info.index
|
|
936
969
|
|
|
970
|
+
@classmethod
|
|
971
|
+
def _post_init_fields(cls):
|
|
972
|
+
if cls._exported_fields_:
|
|
973
|
+
raise RuntimeError("Preview archetypes cannot have exported fields")
|
|
974
|
+
|
|
937
975
|
|
|
938
976
|
@meta_fn
|
|
939
977
|
def entity_info_at(index: Num) -> PlayEntityInfo | WatchEntityInfo | PreviewEntityInfo:
|
|
@@ -1066,7 +1104,7 @@ class EntityRef[A: _BaseArchetype](Record):
|
|
|
1066
1104
|
"""Check if entity at the index is precisely of the archetype."""
|
|
1067
1105
|
return self.index >= 0 and self.archetype().is_at(self.index)
|
|
1068
1106
|
|
|
1069
|
-
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[
|
|
1107
|
+
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[DataValue | str]:
|
|
1070
1108
|
ref = getattr(self, "_ref_", None)
|
|
1071
1109
|
if ref is None:
|
|
1072
1110
|
return [self.index]
|
|
@@ -12,7 +12,7 @@ from sonolus.script.internal.context import ctx
|
|
|
12
12
|
from sonolus.script.internal.error import InternalError
|
|
13
13
|
from sonolus.script.internal.generic import GenericValue
|
|
14
14
|
from sonolus.script.internal.impl import meta_fn, validate_value
|
|
15
|
-
from sonolus.script.internal.value import Value
|
|
15
|
+
from sonolus.script.internal.value import DataValue, Value
|
|
16
16
|
from sonolus.script.num import Num
|
|
17
17
|
|
|
18
18
|
|
|
@@ -108,11 +108,11 @@ class Array[T, Size](GenericValue, ArrayLike[T]):
|
|
|
108
108
|
return self
|
|
109
109
|
|
|
110
110
|
@classmethod
|
|
111
|
-
def _from_list_(cls, values: Iterable[
|
|
111
|
+
def _from_list_(cls, values: Iterable[DataValue]) -> Self:
|
|
112
112
|
iterator = iter(values)
|
|
113
113
|
return cls(*(cls.element_type()._from_list_(iterator) for _ in range(cls.size())))
|
|
114
114
|
|
|
115
|
-
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[
|
|
115
|
+
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[DataValue | str]:
|
|
116
116
|
match self._value:
|
|
117
117
|
case list():
|
|
118
118
|
return [entry for value in self._value for entry in value._to_list_(level_refs)]
|
|
@@ -158,10 +158,14 @@ class ArrayLike[T](Sequence, ABC):
|
|
|
158
158
|
return min_index
|
|
159
159
|
|
|
160
160
|
def _max_(self, key: Callable[T, Any] | None = None) -> T:
|
|
161
|
-
|
|
161
|
+
index = self.index_of_max(key=key)
|
|
162
|
+
assert index != -1
|
|
163
|
+
return self[index]
|
|
162
164
|
|
|
163
165
|
def _min_(self, key: Callable[T, Any] | None = None) -> T:
|
|
164
|
-
|
|
166
|
+
index = self.index_of_min(key=key)
|
|
167
|
+
assert index != -1
|
|
168
|
+
return self[index]
|
|
165
169
|
|
|
166
170
|
def swap(self, i: Num, j: Num, /):
|
|
167
171
|
"""Swap the values at the given indices.
|
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from sonolus.backend.visitor import compile_and_call
|
|
3
4
|
from sonolus.script.array import Array
|
|
4
5
|
from sonolus.script.array_like import ArrayLike
|
|
5
6
|
from sonolus.script.debug import error
|
|
7
|
+
from sonolus.script.internal.context import ctx
|
|
8
|
+
from sonolus.script.internal.impl import meta_fn
|
|
6
9
|
from sonolus.script.iterator import SonolusIterator
|
|
10
|
+
from sonolus.script.num import Num
|
|
11
|
+
from sonolus.script.pointer import _deref
|
|
7
12
|
from sonolus.script.record import Record
|
|
8
13
|
from sonolus.script.values import alloc, copy
|
|
9
14
|
|
|
10
15
|
|
|
16
|
+
class Box[T](Record):
|
|
17
|
+
"""A box that contains a value.
|
|
18
|
+
|
|
19
|
+
This can be helpful for generic code that can handle both Num and non-Num types.
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
```python
|
|
23
|
+
Box[T](value: T)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
```python
|
|
28
|
+
box = Box(1)
|
|
29
|
+
box = Box[int](2)
|
|
30
|
+
|
|
31
|
+
x: T = ...
|
|
32
|
+
y: T = ...
|
|
33
|
+
box = Box(x)
|
|
34
|
+
box.value = y # Works regardless of whether x is a Num or not
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
value: T
|
|
39
|
+
"""The value contained in the box."""
|
|
40
|
+
|
|
41
|
+
|
|
11
42
|
class Pair[T, U](Record):
|
|
12
43
|
"""A generic pair of values.
|
|
13
44
|
|
|
@@ -129,6 +160,17 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
129
160
|
self._array[self._size] = value
|
|
130
161
|
self._size += 1
|
|
131
162
|
|
|
163
|
+
def append_unchecked(self, value: T):
|
|
164
|
+
"""Append the given value to the end of the array without checking the capacity.
|
|
165
|
+
|
|
166
|
+
Use with caution as this may cause hard to debug issues if the array is full.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
value: The value to append.
|
|
170
|
+
"""
|
|
171
|
+
self._array[self._size] = value
|
|
172
|
+
self._size += 1
|
|
173
|
+
|
|
132
174
|
def extend(self, values: ArrayLike[T]):
|
|
133
175
|
"""Appends copies of the values in the given array to the end of the array.
|
|
134
176
|
|
|
@@ -258,6 +300,130 @@ class VarArray[T, Capacity](Record, ArrayLike[T]):
|
|
|
258
300
|
raise TypeError("unhashable type: 'VarArray'")
|
|
259
301
|
|
|
260
302
|
|
|
303
|
+
class ArrayPointer[T](Record, ArrayLike[T]):
|
|
304
|
+
"""An array defined by a size and pointer to the first element.
|
|
305
|
+
|
|
306
|
+
This is intended to be created internally and improper use may result in hard to debug issues.
|
|
307
|
+
|
|
308
|
+
Usage:
|
|
309
|
+
```python
|
|
310
|
+
ArrayPointer[T](size: int, block: int, offset: int)
|
|
311
|
+
```
|
|
312
|
+
"""
|
|
313
|
+
|
|
314
|
+
size: int
|
|
315
|
+
block: int
|
|
316
|
+
offset: int
|
|
317
|
+
|
|
318
|
+
def __len__(self) -> int:
|
|
319
|
+
"""Return the number of elements in the array."""
|
|
320
|
+
return self.size
|
|
321
|
+
|
|
322
|
+
@classmethod
|
|
323
|
+
def element_type(cls) -> type[T]:
|
|
324
|
+
"""Return the type of the elements in the array."""
|
|
325
|
+
return cls.type_var_value(T)
|
|
326
|
+
|
|
327
|
+
def _check_index(self, index: int):
|
|
328
|
+
assert 0 <= index < self.size
|
|
329
|
+
|
|
330
|
+
@meta_fn
|
|
331
|
+
def _get_item(self, item: int) -> T:
|
|
332
|
+
if not ctx():
|
|
333
|
+
raise TypeError("ArrayPointer values cannot be accessed outside of a context")
|
|
334
|
+
return _deref(
|
|
335
|
+
self.block,
|
|
336
|
+
self.offset + Num._accept_(item) * Num._accept_(self.element_type()._size_()),
|
|
337
|
+
self.element_type(),
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
@meta_fn
|
|
341
|
+
def __getitem__(self, item: int) -> T:
|
|
342
|
+
compile_and_call(self._check_index, item)
|
|
343
|
+
return self._get_item(item)._get_()
|
|
344
|
+
|
|
345
|
+
@meta_fn
|
|
346
|
+
def __setitem__(self, key: int, value: T):
|
|
347
|
+
compile_and_call(self._check_index, key)
|
|
348
|
+
dst = self._get_item(key)
|
|
349
|
+
if self.element_type()._is_value_type_():
|
|
350
|
+
dst._set_(value)
|
|
351
|
+
else:
|
|
352
|
+
dst._copy_from__(value)
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
class ArraySet[T, Capacity](Record):
|
|
356
|
+
"""A set implemented as an array with a fixed maximum capacity.
|
|
357
|
+
|
|
358
|
+
Usage:
|
|
359
|
+
```python
|
|
360
|
+
ArraySet[T, Capacity].new() # Create a new empty set
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Examples:
|
|
364
|
+
```python
|
|
365
|
+
s = ArraySet[int, 10].new()
|
|
366
|
+
s.add(1)
|
|
367
|
+
s.add(2)
|
|
368
|
+
assert 1 in s
|
|
369
|
+
assert 3 not in s
|
|
370
|
+
s.remove(1)
|
|
371
|
+
assert 1 not in s
|
|
372
|
+
```
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
_values: VarArray[T, Capacity]
|
|
376
|
+
|
|
377
|
+
@classmethod
|
|
378
|
+
def new(cls):
|
|
379
|
+
"""Create a new empty set."""
|
|
380
|
+
element_type = cls.type_var_value(T)
|
|
381
|
+
capacity = cls.type_var_value(Capacity)
|
|
382
|
+
return cls(VarArray[element_type, capacity].new())
|
|
383
|
+
|
|
384
|
+
def __len__(self):
|
|
385
|
+
"""Return the number of elements in the set."""
|
|
386
|
+
return len(self._values)
|
|
387
|
+
|
|
388
|
+
def __contains__(self, value):
|
|
389
|
+
"""Return whether the given value is present in the set."""
|
|
390
|
+
return value in self._values
|
|
391
|
+
|
|
392
|
+
def __iter__(self):
|
|
393
|
+
"""Return an iterator over the values in the set."""
|
|
394
|
+
return self._values.__iter__()
|
|
395
|
+
|
|
396
|
+
def add(self, value: T) -> bool:
|
|
397
|
+
"""Add a copy of the given value to the set.
|
|
398
|
+
|
|
399
|
+
This has no effect and returns False if the value is already present or if the set is full.
|
|
400
|
+
|
|
401
|
+
Args:
|
|
402
|
+
value: The value to add.
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
True if the value was added, False otherwise.
|
|
406
|
+
"""
|
|
407
|
+
return self._values.set_add(value)
|
|
408
|
+
|
|
409
|
+
def remove(self, value: T) -> bool:
|
|
410
|
+
"""Remove the given value from the set.
|
|
411
|
+
|
|
412
|
+
This has no effect and returns False if the value is not present.
|
|
413
|
+
|
|
414
|
+
Args:
|
|
415
|
+
value: The value to remove.
|
|
416
|
+
|
|
417
|
+
Returns:
|
|
418
|
+
True if the value was removed, False otherwise.
|
|
419
|
+
"""
|
|
420
|
+
return self._values.set_remove(value)
|
|
421
|
+
|
|
422
|
+
def clear(self):
|
|
423
|
+
"""Clear the set, removing all elements."""
|
|
424
|
+
self._values.clear()
|
|
425
|
+
|
|
426
|
+
|
|
261
427
|
class _ArrayMapEntry[K, V](Record):
|
|
262
428
|
key: K
|
|
263
429
|
value: V
|
|
@@ -16,8 +16,13 @@ debug_log_callback = ContextVar[Callable[[Num], None]]("debug_log_callback")
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@meta_fn
|
|
19
|
-
def error(message: str | None = None) ->
|
|
20
|
-
|
|
19
|
+
def error(message: str | None = None) -> Never:
|
|
20
|
+
"""Raise an error.
|
|
21
|
+
|
|
22
|
+
This function is used to raise an error during runtime.
|
|
23
|
+
When this happens, the game will pause in debug mode. The current callback will also immediately return 0.
|
|
24
|
+
"""
|
|
25
|
+
message = validate_value(message)._as_py_() if message is not None else "Error"
|
|
21
26
|
if not isinstance(message, str):
|
|
22
27
|
raise ValueError("Expected a string")
|
|
23
28
|
if ctx():
|
|
@@ -28,6 +33,19 @@ def error(message: str | None = None) -> None:
|
|
|
28
33
|
raise RuntimeError(message)
|
|
29
34
|
|
|
30
35
|
|
|
36
|
+
@meta_fn
|
|
37
|
+
def static_error(message: str | None = None) -> Never:
|
|
38
|
+
"""Raise a static error.
|
|
39
|
+
|
|
40
|
+
This function is used to raise an error during compile-time if the compiler cannot guarantee that
|
|
41
|
+
this function will not be called during runtime.
|
|
42
|
+
"""
|
|
43
|
+
message = validate_value(message)._as_py_() if message is not None else "Error"
|
|
44
|
+
if not isinstance(message, str):
|
|
45
|
+
raise ValueError("Expected a string")
|
|
46
|
+
raise RuntimeError(message)
|
|
47
|
+
|
|
48
|
+
|
|
31
49
|
@meta_fn
|
|
32
50
|
def debug_log(value: Num):
|
|
33
51
|
"""Log a value in debug mode."""
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
from collections.abc import Callable
|
|
5
5
|
from os import PathLike
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any
|
|
7
|
+
from typing import Any, Literal
|
|
8
8
|
|
|
9
9
|
from sonolus.build.collection import Asset, load_asset
|
|
10
10
|
from sonolus.script.archetype import PlayArchetype, PreviewArchetype, WatchArchetype, _BaseArchetype
|
|
@@ -81,7 +81,7 @@ class Engine:
|
|
|
81
81
|
meta: Additional metadata of the engine.
|
|
82
82
|
"""
|
|
83
83
|
|
|
84
|
-
version =
|
|
84
|
+
version: Literal[13] = 13
|
|
85
85
|
|
|
86
86
|
def __init__(
|
|
87
87
|
self,
|
|
@@ -3,7 +3,7 @@ from typing import Any, ClassVar, Self
|
|
|
3
3
|
|
|
4
4
|
from sonolus.backend.place import BlockPlace
|
|
5
5
|
from sonolus.script.internal.impl import meta_fn
|
|
6
|
-
from sonolus.script.internal.value import Value
|
|
6
|
+
from sonolus.script.internal.value import DataValue, Value
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class _Missing:
|
|
@@ -94,10 +94,10 @@ class ConstantValue(Value):
|
|
|
94
94
|
return self.value()
|
|
95
95
|
|
|
96
96
|
@classmethod
|
|
97
|
-
def _from_list_(cls, values: Iterable[
|
|
97
|
+
def _from_list_(cls, values: Iterable[DataValue]) -> Self:
|
|
98
98
|
return cls()
|
|
99
99
|
|
|
100
|
-
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[
|
|
100
|
+
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[DataValue | str]:
|
|
101
101
|
return []
|
|
102
102
|
|
|
103
103
|
@classmethod
|
|
@@ -2,7 +2,7 @@ from collections.abc import Iterable
|
|
|
2
2
|
from typing import Any, Self
|
|
3
3
|
|
|
4
4
|
from sonolus.backend.place import BlockPlace
|
|
5
|
-
from sonolus.script.internal.value import Value
|
|
5
|
+
from sonolus.script.internal.value import DataValue, Value
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class TransientValue(Value):
|
|
@@ -23,10 +23,10 @@ class TransientValue(Value):
|
|
|
23
23
|
raise TypeError(f"{cls.__name__} cannot be dereferenced")
|
|
24
24
|
|
|
25
25
|
@classmethod
|
|
26
|
-
def _from_list_(cls, values: Iterable[
|
|
26
|
+
def _from_list_(cls, values: Iterable[DataValue]) -> Self:
|
|
27
27
|
raise TypeError(f"{cls.__name__} cannot be constructed from list")
|
|
28
28
|
|
|
29
|
-
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[
|
|
29
|
+
def _to_list_(self, level_refs: dict[Any, str] | None = None) -> list[DataValue | str]:
|
|
30
30
|
raise TypeError(f"{type(self).__name__} cannot be deconstructed to list")
|
|
31
31
|
|
|
32
32
|
@classmethod
|