sonolus.py 0.3.1__tar.gz → 0.3.3__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.

Files changed (183) hide show
  1. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/.github/workflows/publish.yaml +3 -3
  2. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/.gitignore +1 -1
  3. sonolus_py-0.3.3/.python-version +1 -0
  4. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/PKG-INFO +1 -1
  5. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/builtins.md +5 -1
  6. sonolus_py-0.3.3/docs/concepts/index.md +6 -0
  7. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/project.md +27 -13
  8. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/resources.md +108 -7
  9. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/types.md +26 -7
  10. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/pyproject.toml +6 -4
  11. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/generate.py +4 -6
  12. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/finalize.py +16 -4
  13. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/node.py +13 -5
  14. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/allocate.py +41 -4
  15. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/flow.py +24 -7
  16. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/optimize.py +2 -9
  17. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/utils.py +6 -1
  18. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/visitor.py +72 -23
  19. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/cli.py +6 -1
  20. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/engine.py +1 -1
  21. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/archetype.py +52 -24
  22. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/array.py +20 -8
  23. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/array_like.py +30 -3
  24. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/containers.py +27 -7
  25. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/debug.py +66 -8
  26. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/globals.py +17 -0
  27. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/builtin_impls.py +12 -8
  28. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/context.py +55 -1
  29. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/range.py +25 -2
  30. sonolus_py-0.3.3/sonolus/script/internal/simulation_context.py +131 -0
  31. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/tuple_impl.py +18 -11
  32. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/interval.py +60 -2
  33. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/iterator.py +3 -2
  34. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/num.py +11 -2
  35. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/options.py +24 -1
  36. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/quad.py +41 -3
  37. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/record.py +24 -3
  38. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/runtime.py +411 -0
  39. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/stream.py +133 -16
  40. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/transform.py +291 -2
  41. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/values.py +9 -3
  42. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/vec.py +14 -2
  43. sonolus_py-0.3.3/tests/script/conftest.py +210 -0
  44. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_array.py +82 -26
  45. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_array_map.py +111 -29
  46. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_array_set.py +27 -17
  47. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_assert.py +7 -7
  48. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_dict.py +4 -4
  49. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_flow.py +56 -56
  50. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_functions.py +53 -53
  51. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_helpers.py +11 -11
  52. sonolus_py-0.3.3/tests/script/test_interval.py +570 -0
  53. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_match.py +11 -11
  54. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_num.py +12 -12
  55. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_operator.py +159 -26
  56. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_quad.py +17 -32
  57. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_random.py +10 -27
  58. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_range.py +82 -9
  59. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_record.py +18 -18
  60. sonolus_py-0.3.3/tests/script/test_transform.py +601 -0
  61. sonolus_py-0.3.3/tests/script/test_tuple.py +140 -0
  62. sonolus_py-0.3.3/tests/script/test_values.py +169 -0
  63. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_var_array.py +140 -68
  64. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/script/test_vec.py +15 -15
  65. sonolus_py-0.3.3/uv.lock +849 -0
  66. sonolus_py-0.3.1/.python-version +0 -1
  67. sonolus_py-0.3.1/docs/concepts/index.md +0 -2
  68. sonolus_py-0.3.1/tests/script/conftest.py +0 -126
  69. sonolus_py-0.3.1/tests/script/test_interval.py +0 -223
  70. sonolus_py-0.3.1/tests/script/test_transform.py +0 -301
  71. sonolus_py-0.3.1/tests/script/test_tuple.py +0 -70
  72. sonolus_py-0.3.1/uv.lock +0 -872
  73. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/.run/Python tests in tests.run.xml +0 -0
  74. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/LICENSE +0 -0
  75. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/README.md +0 -0
  76. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/doc_stubs/__init__.py +0 -0
  77. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/doc_stubs/builtins.pyi +0 -0
  78. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/doc_stubs/math.pyi +0 -0
  79. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/doc_stubs/num.pyi +0 -0
  80. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/doc_stubs/random.pyi +0 -0
  81. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/CNAME +0 -0
  82. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/cli.md +0 -0
  83. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/concepts/constructs.md +0 -0
  84. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/index.md +0 -0
  85. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/builtins.md +0 -0
  86. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/index.md +0 -0
  87. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/math.md +0 -0
  88. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/random.md +0 -0
  89. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.archetype.md +0 -0
  90. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.array.md +0 -0
  91. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.array_like.md +0 -0
  92. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.bucket.md +0 -0
  93. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.containers.md +0 -0
  94. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.debug.md +0 -0
  95. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.easing.md +0 -0
  96. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.effect.md +0 -0
  97. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.engine.md +0 -0
  98. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.globals.md +0 -0
  99. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.instruction.md +0 -0
  100. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.interval.md +0 -0
  101. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.iterator.md +0 -0
  102. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.level.md +0 -0
  103. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.metadata.md +0 -0
  104. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.num.md +0 -0
  105. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.options.md +0 -0
  106. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.particle.md +0 -0
  107. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.printing.md +0 -0
  108. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.project.md +0 -0
  109. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.quad.md +0 -0
  110. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.record.md +0 -0
  111. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.runtime.md +0 -0
  112. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.sprite.md +0 -0
  113. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.stream.md +0 -0
  114. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.text.md +0 -0
  115. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.timing.md +0 -0
  116. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.transform.md +0 -0
  117. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.ui.md +0 -0
  118. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.values.md +0 -0
  119. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/docs/reference/sonolus.script.vec.md +0 -0
  120. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/mkdocs.yml +1 -1
  121. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
  122. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/runtimes/Functions.json +0 -0
  123. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/runtimes/Level/Play/Blocks.json +0 -0
  124. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
  125. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
  126. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/__init__.py +0 -0
  127. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/__init__.py +0 -0
  128. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/blocks.py +0 -0
  129. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/excepthook.py +0 -0
  130. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/interpret.py +0 -0
  131. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/ir.py +0 -0
  132. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/mode.py +0 -0
  133. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/ops.py +0 -0
  134. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/__init__.py +0 -0
  135. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/constant_evaluation.py +0 -0
  136. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/copy_coalesce.py +0 -0
  137. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/dead_code.py +0 -0
  138. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/dominance.py +0 -0
  139. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/inlining.py +0 -0
  140. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/liveness.py +0 -0
  141. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/passes.py +0 -0
  142. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/simplify.py +0 -0
  143. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/optimize/ssa.py +0 -0
  144. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/backend/place.py +0 -0
  145. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/__init__.py +0 -0
  146. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/collection.py +0 -0
  147. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/compile.py +0 -0
  148. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/level.py +0 -0
  149. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/node.py +0 -0
  150. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/build/project.py +0 -0
  151. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/py.typed +0 -0
  152. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/__init__.py +0 -0
  153. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/bucket.py +0 -0
  154. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/easing.py +0 -0
  155. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/effect.py +0 -0
  156. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/engine.py +0 -0
  157. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/instruction.py +0 -0
  158. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/__init__.py +0 -0
  159. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/callbacks.py +0 -0
  160. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/constant.py +0 -0
  161. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/descriptor.py +0 -0
  162. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/dict_impl.py +0 -0
  163. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/error.py +0 -0
  164. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/generic.py +0 -0
  165. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/impl.py +0 -0
  166. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/introspection.py +0 -0
  167. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/math_impls.py +0 -0
  168. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/native.py +0 -0
  169. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/random.py +0 -0
  170. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/transient.py +0 -0
  171. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/internal/value.py +0 -0
  172. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/level.py +0 -0
  173. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/metadata.py +0 -0
  174. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/particle.py +0 -0
  175. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/pointer.py +0 -0
  176. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/printing.py +0 -0
  177. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/project.py +0 -0
  178. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/sprite.py +0 -0
  179. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/text.py +0 -0
  180. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/timing.py +0 -0
  181. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/sonolus/script/ui.py +0 -0
  182. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/tests/__init__.py +0 -0
  183. {sonolus_py-0.3.1 → sonolus_py-0.3.3}/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.5.2
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
@@ -7,7 +7,7 @@ wheels/
7
7
  *.egg-info
8
8
 
9
9
  # Virtual environments
10
- .venv
10
+ .venv*
11
11
 
12
12
  .idea/
13
13
 
@@ -0,0 +1 @@
1
+ 3.14.0b3t
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sonolus.py
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Summary: Sonolus engine development in Python
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -2,7 +2,7 @@
2
2
  Sonolus.py comes with support for a number of built-in functions.
3
3
 
4
4
  - `abs(x)`
5
- - `bool(object)` (for a num argument)
5
+ - `bool(object)`
6
6
  - `callable(object)`
7
7
  - `enumerate(iterable, start=0)`
8
8
  - `filter(function, iterable)`
@@ -38,6 +38,10 @@ Sonolus.py also comes with support for some standard library modules.
38
38
  - `ceil(x)`
39
39
  - `trunc(x)`
40
40
  - `log(x[, base])`
41
+ - `pi`
42
+ - `e`
43
+ - `tau`
44
+ - `inf`
41
45
 
42
46
  ### random
43
47
  - `randrange(stop)`, `random.randrange(start, stop[, step])`
@@ -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 should implement the [`should_spawn`][sonolus.script.archetype.PlayArchetype.should_spawn] callback. They may also implement
84
- the [`preprocess`][sonolus.script.archetype.PlayArchetype.preprocess], [`spawn_order`][sonolus.script.archetype.PlayArchetype.spawn_order], [`initialize`][sonolus.script.archetype.PlayArchetype.initialize], [`update_sequential`][sonolus.script.archetype.PlayArchetype.update_sequential], [`update_parallel`][sonolus.script.archetype.PlayArchetype.update_parallel], [`touch`][sonolus.script.archetype.PlayArchetype.touch], and
85
- [`terminate`][sonolus.script.archetype.PlayArchetype.terminate] callbacks.
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 should implement the [`spawn_time`][sonolus.script.archetype.WatchArchetype.spawn_time] and [`despawn_time`][sonolus.script.archetype.WatchArchetype.despawn_time] callbacks.
114
- They may also implement the [`preprocess`][sonolus.script.archetype.WatchArchetype.preprocess], [`initialize`][sonolus.script.archetype.WatchArchetype.initialize], [`update_sequential`][sonolus.script.archetype.WatchArchetype.update_sequential], [`update_parallel`][sonolus.script.archetype.WatchArchetype.update_parallel], and
115
- [`terminate`][sonolus.script.archetype.WatchArchetype.terminate] callbacks.
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 may implement the [`preprocess`][sonolus.script.archetype.PreviewArchetype.preprocess] and [`render`][sonolus.script.archetype.PreviewArchetype.render] callbacks.
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 it has `preprocess`, `navigate`, and `update` global callbacks.
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
- `update` is invoked every frame and should handle most of the drawing logic.
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
- ## Level Memory & Level Data
4
- Level memory and level data are defined with the [`@level_memory`][sonolus.script.globals.level_memory] and [`@level_data`][sonolus.script.globals.level_data] class decorators, respectively:
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, level_data
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, they may be called as functions as well by passing the type as an argument:
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 level_memory, level_data
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
@@ -16,7 +14,7 @@ Sonolus.py will treat any of these types as `Num`, but it's recommended to use w
16
14
  The Sonolus app uses 32-bit floating-point numbers for all numeric values, so precision may be lower compared to Python
17
15
  when running on Sonolus.
18
16
 
19
- Infinity, NaN, and values outside the range of 32-bit floating-point numbers are not supported.
17
+ NaN and values outside the range of 32-bit floating-point numbers are not supported.
20
18
 
21
19
  You can import `Num` from `sonolus.script.num`:
22
20
 
@@ -44,8 +42,10 @@ Nums support most of the standard Python operations:
44
42
  Floating point precision may be lower when running on Sonolus compared to Python.
45
43
  Care should be taken when performing precision-sensitive operations.
46
44
 
47
- Nums are the only supported type for boolean operations and control flow conditions.
48
- As a condition, any nonzero value is considered true, and `0` is considered false.
45
+ As in regular Python, `0` is considered `False`, while any non-zero value is considered `True`.
46
+
47
+ Objects with an explicit `__bool__` method may also be used in `if`, `while`, `case ... if` expressions as well as with
48
+ the `not` operator. However, the operands of the `and` and `or` operators must be of type `Num`.
49
49
 
50
50
  - Logical operators: `and`, `or`, `not`
51
51
  - Ternary expressions: `... if <condition> else ...`
@@ -106,11 +106,12 @@ from sonolus.script.array import Array
106
106
 
107
107
  ### Declaration
108
108
 
109
- Arrays can be created using its constructor:
109
+ Arrays can be created using its constructor or the unary `+` operator.
110
110
 
111
111
  ```python
112
112
  a1 = Array[int, 3](1, 2, 3)
113
113
  a2 = Array[int, 0]()
114
+ a3 = +Array[int, 3] # Create a zero-initialized array
114
115
  ```
115
116
 
116
117
  If at least one element is provided, the element type and size can be inferred:
@@ -152,6 +153,14 @@ assert a[0] == Pair(1, 2) # The value in the array is independent of the origin
152
153
 
153
154
  ### Operations
154
155
 
156
+ An array can be copied with the unary `+` operator, which creates a new array with the same elements:
157
+
158
+ ```python
159
+ a = Array(1, 2, 3)
160
+ b = +a
161
+ assert b == Array(1, 2, 3)
162
+ ```
163
+
155
164
  The value of an array can be copied from another array using the copy from operator (`@=`)[^1]:
156
165
 
157
166
  ```python
@@ -299,11 +308,13 @@ class MyPairSubclass(MyPair):
299
308
 
300
309
  ### Instantiation
301
310
 
302
- A constructor is automatically generated for the [`Record`][sonolus.script.record.Record] class:
311
+ A constructor is automatically generated for the [`Record`][sonolus.script.record.Record] class and the unary `+`
312
+ operator can also be used to create a zero-initialized record.
303
313
 
304
314
  ```python
305
315
  pair_1 = MyPair(1, 2)
306
316
  pair_2 = MyPair(first=1, second=2)
317
+ pair_3 = +MyPair # Create a zero-initialized record
307
318
  ```
308
319
 
309
320
  ### Generics
@@ -342,6 +353,14 @@ assert MyGenericRecord(1).my_type() == Num
342
353
 
343
354
  ### Operations
344
355
 
356
+ A record can be copied with the unary `+` operator, which creates a new record with the same field values:
357
+
358
+ ```python
359
+ pair = MyPair(1, 2)
360
+ copy_pair = +pair
361
+ assert copy_pair == MyPair(1, 2)
362
+ ```
363
+
345
364
  The value of a record can be copied from another record using the copy from operator (`@=`)[^1]:
346
365
 
347
366
  ```python
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sonolus.py"
3
- version = "0.3.1"
3
+ version = "0.3.3"
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 = "py313"
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' {name} = ({id_}, {{{
55
- ", ".join(f'"{e}"' for e in readable)
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" f"\n" f"type Block = {" | ".join(f'{name}Block' for name in block_files)}\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,3 +1,5 @@
1
+ from math import isfinite, isinf, isnan
2
+
1
3
  from sonolus.backend.ir import IRConst, IRGet, IRInstr, IRPureInstr, IRSet
2
4
  from sonolus.backend.node import ConstantNode, EngineNode, FunctionNode
3
5
  from sonolus.backend.ops import Op
@@ -54,10 +56,20 @@ def cfg_to_engine_node(entry: BasicBlock):
54
56
 
55
57
  def ir_to_engine_node(stmt) -> EngineNode:
56
58
  match stmt:
57
- case int() | float():
58
- return ConstantNode(value=float(stmt))
59
- case IRConst(value=int(value) | float(value)):
60
- return ConstantNode(value=value)
59
+ case int(value) | float(value) | IRConst(value=int(value) | float(value)):
60
+ value = float(value)
61
+ if value.is_integer():
62
+ return ConstantNode(value=int(value))
63
+ elif isfinite(value):
64
+ return ConstantNode(value=value)
65
+ elif isinf(value):
66
+ # Read values from ROM
67
+ return FunctionNode(Op.Get, args=[ConstantNode(value=3000), ConstantNode(value=1 if value > 0 else 2)])
68
+ elif isnan(value):
69
+ # Read value from ROM
70
+ return FunctionNode(Op.Get, args=[ConstantNode(value=3000), ConstantNode(value=0)])
71
+ else:
72
+ raise ValueError(f"Invalid constant value: {value}")
61
73
  case IRPureInstr(op=op, args=args) | IRInstr(op=op, args=args):
62
74
  return FunctionNode(func=op, args=[ir_to_engine_node(arg) for arg in args])
63
75
  case IRGet(place=place):
@@ -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 hash((self.func, tuple(self.args)))
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("\n".join(format_engine_node(arg) for arg in node.args), " ")
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
- block.statements = [self.update_stmt(statement, mapping) for statement in block.statements]
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
- return IRSet(place=self.update_stmt(place, mapping), value=self.update_stmt(value, mapping))
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 [*block.statements, block.test]:
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
- result.setdefault(place, set()).update(live - {place})
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(f"{index}[{pre(fmt([f'#{index}', *(
95
- f"{dst} := phi({", ".join(f"{block_indexes.get(src_block, "<dead>")}: {src_place}"
96
- for src_block, src_place
97
- in sorted(phis.items(), key=lambda x: block_indexes.get(x[0])))})"
98
- for dst, phis in block.phis.items()
99
- ), *block.statements]))}]")
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 "default"]))}| {block_indexes[target]}"
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
- AdvancedDeadCodeElimination(),
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)