sonolus.py 0.1.9__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

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