sonolus.py 0.3.0__tar.gz → 0.3.2__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.
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/.github/workflows/publish.yaml +3 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/.gitignore +1 -1
- sonolus_py-0.3.2/.python-version +1 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/PKG-INFO +1 -1
- sonolus_py-0.3.2/docs/concepts/index.md +6 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/project.md +27 -13
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/resources.md +108 -7
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/types.md +21 -4
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/pyproject.toml +6 -4
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/generate.py +4 -6
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/node.py +13 -5
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/allocate.py +41 -4
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/flow.py +24 -7
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/optimize.py +2 -9
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/utils.py +6 -1
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/visitor.py +47 -14
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/cli.py +6 -1
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/engine.py +1 -1
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/archetype.py +27 -17
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/array.py +15 -5
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/array_like.py +5 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/containers.py +3 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/debug.py +66 -8
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/globals.py +17 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/builtin_impls.py +2 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/context.py +50 -0
- sonolus_py-0.3.2/sonolus/script/internal/simulation_context.py +131 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/tuple_impl.py +15 -10
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/iterator.py +3 -2
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/num.py +13 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/options.py +24 -1
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/quad.py +2 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/record.py +22 -3
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/runtime.py +383 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/stream.py +149 -17
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/transform.py +289 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/values.py +9 -3
- sonolus_py-0.3.2/tests/script/conftest.py +210 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_array.py +26 -26
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_array_map.py +15 -29
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_array_set.py +10 -17
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_assert.py +7 -7
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_dict.py +4 -4
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_flow.py +56 -56
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_functions.py +53 -53
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_helpers.py +11 -11
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_interval.py +22 -22
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_match.py +11 -11
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_num.py +12 -12
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_operator.py +55 -26
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_quad.py +17 -32
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_random.py +10 -27
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_range.py +9 -9
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_record.py +18 -18
- sonolus_py-0.3.2/tests/script/test_transform.py +601 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_tuple.py +6 -6
- sonolus_py-0.3.2/tests/script/test_values.py +169 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_var_array.py +42 -61
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/test_vec.py +15 -15
- sonolus_py-0.3.2/uv.lock +849 -0
- sonolus_py-0.3.0/.python-version +0 -1
- sonolus_py-0.3.0/docs/concepts/index.md +0 -2
- sonolus_py-0.3.0/tests/script/conftest.py +0 -126
- sonolus_py-0.3.0/tests/script/test_transform.py +0 -301
- sonolus_py-0.3.0/uv.lock +0 -872
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/.run/Python tests in tests.run.xml +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/LICENSE +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/README.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/doc_stubs/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/doc_stubs/builtins.pyi +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/doc_stubs/math.pyi +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/doc_stubs/num.pyi +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/doc_stubs/random.pyi +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/CNAME +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/builtins.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/cli.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/concepts/constructs.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/index.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/builtins.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/index.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/math.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/random.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.archetype.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.array.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.array_like.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.bucket.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.containers.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.debug.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.easing.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.effect.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.engine.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.globals.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.instruction.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.interval.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.iterator.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.level.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.metadata.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.num.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.options.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.particle.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.printing.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.project.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.quad.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.record.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.runtime.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.sprite.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.stream.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.text.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.timing.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.transform.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.ui.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.values.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/docs/reference/sonolus.script.vec.md +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/mkdocs.yml +1 -1
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/runtimes/Functions.json +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/runtimes/Level/Play/Blocks.json +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/blocks.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/excepthook.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/finalize.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/interpret.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/ir.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/mode.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/ops.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/constant_evaluation.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/copy_coalesce.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/dead_code.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/dominance.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/inlining.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/liveness.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/passes.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/simplify.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/optimize/ssa.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/backend/place.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/collection.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/compile.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/level.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/node.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/build/project.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/py.typed +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/bucket.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/easing.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/effect.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/engine.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/instruction.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/callbacks.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/constant.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/descriptor.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/dict_impl.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/error.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/generic.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/impl.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/introspection.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/math_impls.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/native.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/random.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/range.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/transient.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/internal/value.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/interval.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/level.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/metadata.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/particle.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/pointer.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/printing.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/project.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/sprite.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/text.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/timing.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/ui.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/sonolus/script/vec.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/__init__.py +0 -0
- {sonolus_py-0.3.0 → sonolus_py-0.3.2}/tests/script/__init__.py +0 -0
|
@@ -13,16 +13,16 @@ jobs:
|
|
|
13
13
|
- name: Install uv
|
|
14
14
|
uses: astral-sh/setup-uv@v3
|
|
15
15
|
with:
|
|
16
|
-
version: 0.
|
|
16
|
+
version: 0.7.16
|
|
17
17
|
- name: Install Python
|
|
18
18
|
run: |
|
|
19
|
-
uv python install 3.12 3.13
|
|
19
|
+
uv python install 3.12 3.13 3.14
|
|
20
20
|
- name: Install project
|
|
21
21
|
run: |
|
|
22
22
|
uv sync --all-extras --dev
|
|
23
23
|
- name: Run tests
|
|
24
24
|
run: |
|
|
25
|
-
uv run tox
|
|
25
|
+
CI=true uv run tox
|
|
26
26
|
- name: Build
|
|
27
27
|
run: |
|
|
28
28
|
uv build
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14.0b3t
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Concepts
|
|
2
|
+
This section provides a reference for the concepts and features of Sonolus.py.
|
|
3
|
+
|
|
4
|
+
It is not intended to serve as a tutorial or introduction, and assumes familiarity with Python and Sonolus.py.
|
|
5
|
+
|
|
6
|
+
For information on how to get started with Sonolus.py, see the [home page](../index.md).
|
|
@@ -80,9 +80,16 @@ play_mode = PlayMode(
|
|
|
80
80
|
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
Play mode archetypes subclass [`PlayArchetype`][sonolus.script.archetype.PlayArchetype] and
|
|
84
|
-
|
|
85
|
-
[`
|
|
83
|
+
Play mode archetypes subclass [`PlayArchetype`][sonolus.script.archetype.PlayArchetype] and implement the following callbacks:
|
|
84
|
+
|
|
85
|
+
- [`should_spawn`][sonolus.script.archetype.PlayArchetype.should_spawn] (required)
|
|
86
|
+
- [`preprocess`][sonolus.script.archetype.PlayArchetype.preprocess]
|
|
87
|
+
- [`spawn_order`][sonolus.script.archetype.PlayArchetype.spawn_order]
|
|
88
|
+
- [`initialize`][sonolus.script.archetype.PlayArchetype.initialize]
|
|
89
|
+
- [`update_sequential`][sonolus.script.archetype.PlayArchetype.update_sequential]
|
|
90
|
+
- [`update_parallel`][sonolus.script.archetype.PlayArchetype.update_parallel]
|
|
91
|
+
- [`touch`][sonolus.script.archetype.PlayArchetype.touch]
|
|
92
|
+
- [`terminate`][sonolus.script.archetype.PlayArchetype.terminate]
|
|
86
93
|
|
|
87
94
|
Archetypes for scored notes should have the [`is_scored`][sonolus.script.archetype.PlayArchetype.is_scored] class variable set to `True`.
|
|
88
95
|
|
|
@@ -110,9 +117,15 @@ watch_mode = WatchMode(
|
|
|
110
117
|
)
|
|
111
118
|
```
|
|
112
119
|
|
|
113
|
-
Watch mode archetypes subclass [`WatchArchetype`][sonolus.script.archetype.WatchArchetype] and
|
|
114
|
-
|
|
115
|
-
[`
|
|
120
|
+
Watch mode archetypes subclass [`WatchArchetype`][sonolus.script.archetype.WatchArchetype] and implement the following callbacks:
|
|
121
|
+
|
|
122
|
+
- [`spawn_time`][sonolus.script.archetype.WatchArchetype.spawn_time] (required)
|
|
123
|
+
- [`despawn_time`][sonolus.script.archetype.WatchArchetype.despawn_time] (required)
|
|
124
|
+
- [`preprocess`][sonolus.script.archetype.WatchArchetype.preprocess]
|
|
125
|
+
- [`initialize`][sonolus.script.archetype.WatchArchetype.initialize]
|
|
126
|
+
- [`update_sequential`][sonolus.script.archetype.WatchArchetype.update_sequential]
|
|
127
|
+
- [`update_parallel`][sonolus.script.archetype.WatchArchetype.update_parallel]
|
|
128
|
+
- [`terminate`][sonolus.script.archetype.WatchArchetype.terminate]
|
|
116
129
|
|
|
117
130
|
Watch mode also has the `update_spawn` global callback, which is invoked every frame and should return the reference
|
|
118
131
|
time to compare against spawn and despawn times of archetypes. Typically, this can be either the current time or the
|
|
@@ -135,7 +148,10 @@ preview_mode = PreviewMode(
|
|
|
135
148
|
)
|
|
136
149
|
```
|
|
137
150
|
|
|
138
|
-
Preview mode archetypes subclass [`PreviewArchetype`][sonolus.script.archetype.PreviewArchetype] and
|
|
151
|
+
Preview mode archetypes subclass [`PreviewArchetype`][sonolus.script.archetype.PreviewArchetype] and implement the following callbacks:
|
|
152
|
+
|
|
153
|
+
- [`preprocess`][sonolus.script.archetype.PreviewArchetype.preprocess]
|
|
154
|
+
- [`render`][sonolus.script.archetype.PreviewArchetype.render]
|
|
139
155
|
|
|
140
156
|
### Tutorial Mode
|
|
141
157
|
|
|
@@ -162,13 +178,11 @@ tutorial_mode = TutorialMode(
|
|
|
162
178
|
)
|
|
163
179
|
```
|
|
164
180
|
|
|
165
|
-
Tutorial mode does not have archetypes, but
|
|
166
|
-
|
|
167
|
-
`preprocess` is invoked once before the tutorial starts.
|
|
168
|
-
|
|
169
|
-
`navigate` is invoked when the player navigates forward or backward in the tutorial.
|
|
181
|
+
Tutorial mode does not have archetypes, but has the following global callbacks:
|
|
170
182
|
|
|
171
|
-
`
|
|
183
|
+
- `preprocess` - Invoked once before the tutorial starts
|
|
184
|
+
- `navigate` - Invoked when the player navigates forward or backward in the tutorial
|
|
185
|
+
- `update` - Invoked every frame and should handle most of the drawing logic
|
|
172
186
|
|
|
173
187
|
## Levels
|
|
174
188
|
Levels are defined using the [`Level`][sonolus.script.level.Level] class:
|
|
@@ -1,32 +1,133 @@
|
|
|
1
1
|
# Resources & Declarations
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
3
|
+
## Global Variables
|
|
4
|
+
|
|
5
|
+
### Level Memory
|
|
6
|
+
Level memory is defined with the [`@level_memory`][sonolus.script.globals.level_memory] class decorator:
|
|
5
7
|
|
|
6
8
|
```python
|
|
7
|
-
from sonolus.script.globals import level_memory
|
|
9
|
+
from sonolus.script.globals import level_memory
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
@level_memory
|
|
11
13
|
class LevelMemory:
|
|
12
14
|
value: int
|
|
13
|
-
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Alternatively, it may be called as a function as well by passing the type as an argument:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from sonolus.script.globals import level_memory
|
|
21
|
+
from sonolus.script.vec import Vec2
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
level_memory_value = level_memory(Vec2)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Level memory may be modified in sequential callbacks:
|
|
28
|
+
|
|
29
|
+
- `preprocess`
|
|
30
|
+
- `update_sequential`
|
|
31
|
+
- `touch`
|
|
32
|
+
|
|
33
|
+
and may be read in any callback.
|
|
34
|
+
|
|
35
|
+
### Level Data
|
|
36
|
+
Level data is defined with the [`@level_data`][sonolus.script.globals.level_data] class decorator:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from sonolus.script.globals import level_data
|
|
40
|
+
|
|
14
41
|
|
|
15
42
|
@level_data
|
|
16
43
|
class LevelData:
|
|
17
44
|
value: int
|
|
18
45
|
```
|
|
19
46
|
|
|
20
|
-
Alternatively,
|
|
47
|
+
Alternatively, it may be called as a function as well by passing the type as an argument:
|
|
48
|
+
|
|
21
49
|
```python
|
|
22
|
-
from sonolus.script.globals import
|
|
50
|
+
from sonolus.script.globals import level_data
|
|
23
51
|
from sonolus.script.vec import Vec2
|
|
24
52
|
|
|
25
53
|
|
|
26
|
-
level_memory_value = level_memory(Vec2)
|
|
27
54
|
level_data_value = level_data(Vec2)
|
|
28
55
|
```
|
|
29
56
|
|
|
57
|
+
Level data may only be modified in the `preprocess` callback and may be read in any callback.
|
|
58
|
+
|
|
59
|
+
## Archetype Variables
|
|
60
|
+
|
|
61
|
+
### Imported
|
|
62
|
+
Imported fields are declared with [`imported()`][sonolus.script.archetype.imported]:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from sonolus.script.archetype import PlayArchetype, imported
|
|
66
|
+
|
|
67
|
+
class MyArchetype(PlayArchetype):
|
|
68
|
+
field: int = imported()
|
|
69
|
+
field_with_explicit_name: int = imported(name="field_name")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Imported fields may be loaded from the level data. In watch mode, data may also be loaded from a corresponding exported field in play mode.
|
|
73
|
+
|
|
74
|
+
Imported fields may only be updated in the `preprocess` callback, and are read-only in other callbacks.
|
|
75
|
+
|
|
76
|
+
### Exported
|
|
77
|
+
Exported fields are declared with [`exported()`][sonolus.script.archetype.exported]:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from sonolus.script.archetype import PlayArchetype, exported
|
|
81
|
+
|
|
82
|
+
class MyArchetype(PlayArchetype):
|
|
83
|
+
field: int = exported()
|
|
84
|
+
field_with_explicit_name: int = exported(name="#FIELD")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This is only usable in play mode to export data to be loaded in watch mode. Exported fields are write-only.
|
|
88
|
+
|
|
89
|
+
### Entity Data
|
|
90
|
+
Entity data fields are declared with [`entity_data()`][sonolus.script.archetype.entity_data]:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from sonolus.script.archetype import PlayArchetype, entity_data
|
|
94
|
+
|
|
95
|
+
class MyArchetype(PlayArchetype):
|
|
96
|
+
field: int = entity_data()
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Entity data is accessible from other entities, but may only be updated in the `preprocess` callback and is read-only in other callbacks.
|
|
100
|
+
|
|
101
|
+
It functions like [`imported()`][sonolus.script.archetype.imported] and shares the same underlying storage, except that it is not loaded from a level.
|
|
102
|
+
|
|
103
|
+
### Entity Memory
|
|
104
|
+
Entity memory fields are declared with [`entity_memory()`][sonolus.script.archetype.entity_memory]:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from sonolus.script.archetype import PlayArchetype, entity_memory
|
|
108
|
+
|
|
109
|
+
class MyArchetype(PlayArchetype):
|
|
110
|
+
field: int = entity_memory()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Entity memory is private to the entity and is not accessible from other entities. It may be read or updated in any callback associated with the entity.
|
|
114
|
+
|
|
115
|
+
Entity memory fields may also be set when an entity is spawned using the [`spawn()`][sonolus.script.archetype.PlayArchetype.spawn] method.
|
|
116
|
+
|
|
117
|
+
### Shared Memory
|
|
118
|
+
Shared memory fields are declared with [`shared_memory()`][sonolus.script.archetype.shared_memory]:
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from sonolus.script.archetype import PlayArchetype, shared_memory
|
|
122
|
+
|
|
123
|
+
class MyArchetype(PlayArchetype):
|
|
124
|
+
field: int = shared_memory()
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Shared memory is accessible from other entities.
|
|
128
|
+
|
|
129
|
+
Shared memory may be read in any callback, but may only be updated by sequential callbacks (`preprocess`, `update_sequential`, and `touch`).
|
|
130
|
+
|
|
30
131
|
## Streams
|
|
31
132
|
Streams are defined with the [`@streams`][sonolus.script.stream.streams] decorator:
|
|
32
133
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from sonolus.script.archetype import PlayArchetype
|
|
2
|
-
|
|
3
1
|
# Types
|
|
4
2
|
Sonolus.py has 3 core types: [`Num`](#num), [`Array`](#array), and [`Record`](#record). representing numeric values, fixed-size arrays,
|
|
5
3
|
and custom data structures, respectively. Arrays and records can be nested within each other to create complex data
|
|
@@ -106,11 +104,12 @@ from sonolus.script.array import Array
|
|
|
106
104
|
|
|
107
105
|
### Declaration
|
|
108
106
|
|
|
109
|
-
Arrays can be created using its constructor
|
|
107
|
+
Arrays can be created using its constructor or the unary `+` operator.
|
|
110
108
|
|
|
111
109
|
```python
|
|
112
110
|
a1 = Array[int, 3](1, 2, 3)
|
|
113
111
|
a2 = Array[int, 0]()
|
|
112
|
+
a3 = +Array[int, 3] # Create a zero-initialized array
|
|
114
113
|
```
|
|
115
114
|
|
|
116
115
|
If at least one element is provided, the element type and size can be inferred:
|
|
@@ -152,6 +151,14 @@ assert a[0] == Pair(1, 2) # The value in the array is independent of the origin
|
|
|
152
151
|
|
|
153
152
|
### Operations
|
|
154
153
|
|
|
154
|
+
An array can be copied with the unary `+` operator, which creates a new array with the same elements:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
a = Array(1, 2, 3)
|
|
158
|
+
b = +a
|
|
159
|
+
assert b == Array(1, 2, 3)
|
|
160
|
+
```
|
|
161
|
+
|
|
155
162
|
The value of an array can be copied from another array using the copy from operator (`@=`)[^1]:
|
|
156
163
|
|
|
157
164
|
```python
|
|
@@ -299,11 +306,13 @@ class MyPairSubclass(MyPair):
|
|
|
299
306
|
|
|
300
307
|
### Instantiation
|
|
301
308
|
|
|
302
|
-
A constructor is automatically generated for the [`Record`][sonolus.script.record.Record] class
|
|
309
|
+
A constructor is automatically generated for the [`Record`][sonolus.script.record.Record] class and the unary `+`
|
|
310
|
+
operator can also be used to create a zero-initialized record.
|
|
303
311
|
|
|
304
312
|
```python
|
|
305
313
|
pair_1 = MyPair(1, 2)
|
|
306
314
|
pair_2 = MyPair(first=1, second=2)
|
|
315
|
+
pair_3 = +MyPair # Create a zero-initialized record
|
|
307
316
|
```
|
|
308
317
|
|
|
309
318
|
### Generics
|
|
@@ -342,6 +351,14 @@ assert MyGenericRecord(1).my_type() == Num
|
|
|
342
351
|
|
|
343
352
|
### Operations
|
|
344
353
|
|
|
354
|
+
A record can be copied with the unary `+` operator, which creates a new record with the same field values:
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
pair = MyPair(1, 2)
|
|
358
|
+
copy_pair = +pair
|
|
359
|
+
assert copy_pair == MyPair(1, 2)
|
|
360
|
+
```
|
|
361
|
+
|
|
345
362
|
The value of a record can be copied from another record using the copy from operator (`@=`)[^1]:
|
|
346
363
|
|
|
347
364
|
```python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sonolus.py"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.2"
|
|
4
4
|
description = "Sonolus engine development in Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -13,12 +13,12 @@ default-groups = ["dev", "docs"]
|
|
|
13
13
|
|
|
14
14
|
[tool.ruff]
|
|
15
15
|
line-length = 120
|
|
16
|
-
target-version = "
|
|
16
|
+
target-version = "py312"
|
|
17
17
|
|
|
18
18
|
[tool.ruff.lint]
|
|
19
19
|
preview = true
|
|
20
20
|
select = ["F", "E", "W", "I", "N", "D", "UP", "YTT", "B", "A", "COM", "C4", "DTZ", "PIE", "PT", "Q", "SLOT", "SIM", "PTH", "PL", "PERF", "FURB", "LOG", "RUF"]
|
|
21
|
-
ignore = ["E402", "D1", "COM812", "PLW2901", "PLW3201", "PLR6301", "PLC0415", "PLR2004", "PLR09", "SIM108", "FURB113", "A005"]
|
|
21
|
+
ignore = ["E402", "D1", "COM812", "PLW2901", "PLW3201", "PLR6301", "PLC0415", "PLR2004", "PLR09", "SIM108", "FURB113", "A005", "B903"]
|
|
22
22
|
|
|
23
23
|
[tool.ruff.lint.pydocstyle]
|
|
24
24
|
convention = "google"
|
|
@@ -49,13 +49,15 @@ packages = ["sonolus"]
|
|
|
49
49
|
|
|
50
50
|
[tool.tox]
|
|
51
51
|
requires = ["tox>=4.19"]
|
|
52
|
-
env_list = ["py312", "py313"]
|
|
52
|
+
env_list = ["py312", "py313", "py314"]
|
|
53
53
|
|
|
54
54
|
[tool.tox.env_run_base]
|
|
55
55
|
description = "Run tests"
|
|
56
|
+
passenv = ["CI"]
|
|
56
57
|
deps = [
|
|
57
58
|
"hypothesis>=6.115.3",
|
|
58
59
|
"pytest-xdist>=3.6.1",
|
|
59
60
|
"pytest>=8.3.3",
|
|
60
61
|
]
|
|
62
|
+
uv_python_preference = "managed"
|
|
61
63
|
commands = [["pytest", "tests", "-n", "auto"]]
|
|
@@ -51,11 +51,9 @@ def block(name: str, f: TextIO, out: TextIO):
|
|
|
51
51
|
readable = block["readable"]
|
|
52
52
|
writable = block["writable"]
|
|
53
53
|
out.write(
|
|
54
|
-
f
|
|
55
|
-
|
|
56
|
-
}}}
|
|
57
|
-
", ".join(f'"{e}"' for e in writable)
|
|
58
|
-
}}})\n'
|
|
54
|
+
f" {name} = ({id_}, {{{', '.join(f'"{e}"' for e in readable)}}}, {{{
|
|
55
|
+
', '.join(f'"{e}"' for e in writable)
|
|
56
|
+
}}})\n"
|
|
59
57
|
)
|
|
60
58
|
|
|
61
59
|
|
|
@@ -78,7 +76,7 @@ def blocks():
|
|
|
78
76
|
(runtimes_dir / file).open("r", encoding="utf-8") as f,
|
|
79
77
|
):
|
|
80
78
|
block(name, f, out)
|
|
81
|
-
out.write(f"\n
|
|
79
|
+
out.write(f"\n\ntype Block = {' | '.join(f'{name}Block' for name in block_files)}\n")
|
|
82
80
|
|
|
83
81
|
|
|
84
82
|
def main():
|
|
@@ -1,26 +1,34 @@
|
|
|
1
1
|
import textwrap
|
|
2
|
-
from dataclasses import dataclass
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
3
|
|
|
4
4
|
from sonolus.backend.ops import Op
|
|
5
5
|
|
|
6
6
|
type EngineNode = ConstantNode | FunctionNode
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
@dataclass
|
|
9
|
+
@dataclass(slots=True)
|
|
10
10
|
class ConstantNode:
|
|
11
11
|
value: float
|
|
12
|
+
_hash: int = field(init=False, repr=False)
|
|
13
|
+
|
|
14
|
+
def __post_init__(self):
|
|
15
|
+
self._hash = hash(self.value)
|
|
12
16
|
|
|
13
17
|
def __hash__(self):
|
|
14
18
|
return hash(self.value)
|
|
15
19
|
|
|
16
20
|
|
|
17
|
-
@dataclass
|
|
21
|
+
@dataclass(slots=True)
|
|
18
22
|
class FunctionNode:
|
|
19
23
|
func: Op
|
|
20
24
|
args: list[EngineNode]
|
|
25
|
+
_hash: int = field(init=False, repr=False)
|
|
26
|
+
|
|
27
|
+
def __post_init__(self):
|
|
28
|
+
self._hash = hash((self.func, tuple(self.args)))
|
|
21
29
|
|
|
22
30
|
def __hash__(self):
|
|
23
|
-
return
|
|
31
|
+
return self._hash
|
|
24
32
|
|
|
25
33
|
|
|
26
34
|
def format_engine_node(node: EngineNode) -> str:
|
|
@@ -34,7 +42,7 @@ def format_engine_node(node: EngineNode) -> str:
|
|
|
34
42
|
return f"{node.func.name}({format_engine_node(node.args[0])})"
|
|
35
43
|
case _:
|
|
36
44
|
return f"{node.func.name}(\n{
|
|
37
|
-
textwrap.indent(
|
|
45
|
+
textwrap.indent('\n'.join(format_engine_node(arg) for arg in node.args), ' ')
|
|
38
46
|
}\n)"
|
|
39
47
|
else:
|
|
40
48
|
raise ValueError(f"Invalid engine node: {node}")
|
|
@@ -65,7 +65,8 @@ class Allocate(CompilerPass):
|
|
|
65
65
|
def run(self, entry: BasicBlock):
|
|
66
66
|
mapping = self.get_mapping(entry)
|
|
67
67
|
for block in traverse_cfg_preorder(entry):
|
|
68
|
-
|
|
68
|
+
updated_statements = [self.update_stmt(statement, mapping) for statement in block.statements]
|
|
69
|
+
block.statements = [stmt for stmt in updated_statements if stmt is not None]
|
|
69
70
|
block.test = self.update_stmt(block.test, mapping)
|
|
70
71
|
return entry
|
|
71
72
|
|
|
@@ -80,7 +81,19 @@ class Allocate(CompilerPass):
|
|
|
80
81
|
case IRGet(place=place):
|
|
81
82
|
return IRGet(place=self.update_stmt(place, mapping))
|
|
82
83
|
case IRSet(place=place, value=value):
|
|
83
|
-
|
|
84
|
+
# Do some dead code elimination here which is pretty much free since we already have liveness analysis,
|
|
85
|
+
# and prevents an error from the dead block place being missing from the mapping.
|
|
86
|
+
live = get_live(stmt)
|
|
87
|
+
is_live = not (
|
|
88
|
+
(isinstance(place, BlockPlace) and isinstance(place.block, TempBlock) and place.block not in live)
|
|
89
|
+
or (isinstance(value, IRGet) and place == value.place)
|
|
90
|
+
)
|
|
91
|
+
if is_live:
|
|
92
|
+
return IRSet(place=self.update_stmt(place, mapping), value=self.update_stmt(value, mapping))
|
|
93
|
+
elif isinstance(value, IRInstr) and value.op.side_effects:
|
|
94
|
+
return self.update_stmt(value, mapping)
|
|
95
|
+
else:
|
|
96
|
+
return None
|
|
84
97
|
case BlockPlace(block=block, index=index, offset=offset):
|
|
85
98
|
if isinstance(block, TempBlock):
|
|
86
99
|
if block.size == 0:
|
|
@@ -119,8 +132,32 @@ class Allocate(CompilerPass):
|
|
|
119
132
|
def get_interference(self, entry: BasicBlock) -> dict[TempBlock, set[TempBlock]]:
|
|
120
133
|
result = {}
|
|
121
134
|
for block in traverse_cfg_preorder(entry):
|
|
122
|
-
for stmt in
|
|
135
|
+
for stmt in block.statements:
|
|
136
|
+
if not isinstance(stmt, IRSet):
|
|
137
|
+
continue
|
|
123
138
|
live = {p for p in get_live(stmt) if isinstance(p, TempBlock) and p.size > 0}
|
|
124
139
|
for place in live:
|
|
125
|
-
|
|
140
|
+
if place not in result:
|
|
141
|
+
result[place] = set(live)
|
|
142
|
+
else:
|
|
143
|
+
result[place].update(live)
|
|
126
144
|
return result
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class AllocateFast(Allocate):
|
|
148
|
+
"""A bit faster than Allocate but a bit less optimal."""
|
|
149
|
+
|
|
150
|
+
def get_mapping(self, entry: BasicBlock) -> dict[TempBlock, int]:
|
|
151
|
+
interference = self.get_interference(entry)
|
|
152
|
+
offsets: dict[TempBlock, int] = dict.fromkeys(interference, 0)
|
|
153
|
+
end_offsets: dict[TempBlock, int] = dict.fromkeys(interference, 0)
|
|
154
|
+
|
|
155
|
+
for block, others in interference.items():
|
|
156
|
+
size = block.size
|
|
157
|
+
offset = max((end_offsets[other] for other in others), default=0)
|
|
158
|
+
if offset + size > TEMP_SIZE:
|
|
159
|
+
raise ValueError("Temporary memory limit exceeded")
|
|
160
|
+
offsets[block] = offset
|
|
161
|
+
end_offsets[block] = offset + size
|
|
162
|
+
|
|
163
|
+
return offsets
|
|
@@ -91,12 +91,29 @@ def cfg_to_mermaid(entry: BasicBlock):
|
|
|
91
91
|
|
|
92
92
|
lines = ["Entry([Entry]) --> 0"]
|
|
93
93
|
for block, index in block_indexes.items():
|
|
94
|
-
lines.append(
|
|
95
|
-
f"{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
lines.append(
|
|
95
|
+
f"{index}[{
|
|
96
|
+
pre(
|
|
97
|
+
fmt(
|
|
98
|
+
[
|
|
99
|
+
f'#{index}',
|
|
100
|
+
*(
|
|
101
|
+
f'{dst} := phi({
|
|
102
|
+
", ".join(
|
|
103
|
+
f"{block_indexes.get(src_block, '<dead>')}: {src_place}"
|
|
104
|
+
for src_block, src_place in sorted(
|
|
105
|
+
phis.items(), key=lambda x: block_indexes.get(x[0])
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
})'
|
|
109
|
+
for dst, phis in block.phis.items()
|
|
110
|
+
),
|
|
111
|
+
*block.statements,
|
|
112
|
+
]
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
}]"
|
|
116
|
+
)
|
|
100
117
|
|
|
101
118
|
outgoing = {edge.cond: edge.dst for edge in block.outgoing}
|
|
102
119
|
match outgoing:
|
|
@@ -114,7 +131,7 @@ def cfg_to_mermaid(entry: BasicBlock):
|
|
|
114
131
|
lines.append(f"{index} --> {index}_")
|
|
115
132
|
for cond, target in tgt.items():
|
|
116
133
|
lines.append(
|
|
117
|
-
f"{index}_ --> |{pre(fmt([cond if cond is not None else
|
|
134
|
+
f"{index}_ --> |{pre(fmt([cond if cond is not None else 'default']))}| {block_indexes[target]}"
|
|
118
135
|
)
|
|
119
136
|
lines.append("Exit([Exit])")
|
|
120
137
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from sonolus.backend.optimize.allocate import Allocate, AllocateBasic
|
|
1
|
+
from sonolus.backend.optimize.allocate import Allocate, AllocateBasic, AllocateFast
|
|
2
2
|
from sonolus.backend.optimize.constant_evaluation import SparseConditionalConstantPropagation
|
|
3
3
|
from sonolus.backend.optimize.copy_coalesce import CopyCoalesce
|
|
4
4
|
from sonolus.backend.optimize.dead_code import (
|
|
@@ -6,9 +6,7 @@ from sonolus.backend.optimize.dead_code import (
|
|
|
6
6
|
DeadCodeElimination,
|
|
7
7
|
UnreachableCodeElimination,
|
|
8
8
|
)
|
|
9
|
-
from sonolus.backend.optimize.flow import BasicBlock
|
|
10
9
|
from sonolus.backend.optimize.inlining import InlineVars
|
|
11
|
-
from sonolus.backend.optimize.passes import run_passes
|
|
12
10
|
from sonolus.backend.optimize.simplify import CoalesceFlow, NormalizeSwitch, RewriteToSwitch
|
|
13
11
|
from sonolus.backend.optimize.ssa import FromSSA, ToSSA
|
|
14
12
|
|
|
@@ -21,9 +19,8 @@ MINIMAL_PASSES = (
|
|
|
21
19
|
FAST_PASSES = (
|
|
22
20
|
CoalesceFlow(),
|
|
23
21
|
UnreachableCodeElimination(),
|
|
24
|
-
|
|
22
|
+
AllocateFast(), # Does dead code elimination too, so no need for a separate pass
|
|
25
23
|
CoalesceFlow(),
|
|
26
|
-
Allocate(),
|
|
27
24
|
)
|
|
28
25
|
|
|
29
26
|
STANDARD_PASSES = (
|
|
@@ -46,7 +43,3 @@ STANDARD_PASSES = (
|
|
|
46
43
|
NormalizeSwitch(),
|
|
47
44
|
Allocate(),
|
|
48
45
|
)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def optimize_and_allocate(cfg: BasicBlock):
|
|
52
|
-
return run_passes(cfg, STANDARD_PASSES)
|
|
@@ -11,10 +11,15 @@ def get_function(fn: Callable) -> tuple[str, ast.FunctionDef]:
|
|
|
11
11
|
# This preserves both line number and column number in the returned node
|
|
12
12
|
source_file = inspect.getsourcefile(fn)
|
|
13
13
|
_, start_line = inspect.getsourcelines(fn)
|
|
14
|
-
base_tree =
|
|
14
|
+
base_tree = get_tree_from_file(source_file)
|
|
15
15
|
return source_file, find_function(base_tree, start_line)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
@cache
|
|
19
|
+
def get_tree_from_file(file: str | Path) -> ast.Module:
|
|
20
|
+
return ast.parse(Path(file).read_text(encoding="utf-8"))
|
|
21
|
+
|
|
22
|
+
|
|
18
23
|
class FindFunction(ast.NodeVisitor):
|
|
19
24
|
def __init__(self, line):
|
|
20
25
|
self.line = line
|