sonolus.py 0.1.3__py3-none-any.whl → 0.1.5__py3-none-any.whl

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 (90) hide show
  1. sonolus/backend/blocks.py +756 -756
  2. sonolus/backend/excepthook.py +37 -37
  3. sonolus/backend/finalize.py +77 -69
  4. sonolus/backend/interpret.py +7 -7
  5. sonolus/backend/ir.py +29 -3
  6. sonolus/backend/mode.py +24 -24
  7. sonolus/backend/node.py +40 -40
  8. sonolus/backend/ops.py +197 -197
  9. sonolus/backend/optimize/__init__.py +0 -0
  10. sonolus/backend/optimize/allocate.py +126 -0
  11. sonolus/backend/optimize/constant_evaluation.py +374 -0
  12. sonolus/backend/optimize/copy_coalesce.py +85 -0
  13. sonolus/backend/optimize/dead_code.py +185 -0
  14. sonolus/backend/optimize/dominance.py +96 -0
  15. sonolus/backend/{flow.py → optimize/flow.py} +122 -92
  16. sonolus/backend/optimize/inlining.py +137 -0
  17. sonolus/backend/optimize/liveness.py +177 -0
  18. sonolus/backend/optimize/optimize.py +44 -0
  19. sonolus/backend/optimize/passes.py +52 -0
  20. sonolus/backend/optimize/simplify.py +191 -0
  21. sonolus/backend/optimize/ssa.py +200 -0
  22. sonolus/backend/place.py +17 -25
  23. sonolus/backend/utils.py +58 -48
  24. sonolus/backend/visitor.py +1151 -882
  25. sonolus/build/cli.py +7 -1
  26. sonolus/build/compile.py +88 -90
  27. sonolus/build/engine.py +10 -5
  28. sonolus/build/level.py +24 -23
  29. sonolus/build/node.py +43 -43
  30. sonolus/script/archetype.py +438 -139
  31. sonolus/script/array.py +27 -10
  32. sonolus/script/array_like.py +297 -0
  33. sonolus/script/bucket.py +253 -191
  34. sonolus/script/containers.py +257 -51
  35. sonolus/script/debug.py +26 -10
  36. sonolus/script/easing.py +365 -0
  37. sonolus/script/effect.py +191 -131
  38. sonolus/script/engine.py +71 -4
  39. sonolus/script/globals.py +303 -269
  40. sonolus/script/instruction.py +205 -151
  41. sonolus/script/internal/__init__.py +5 -5
  42. sonolus/script/internal/builtin_impls.py +255 -144
  43. sonolus/script/{callbacks.py → internal/callbacks.py} +127 -127
  44. sonolus/script/internal/constant.py +139 -0
  45. sonolus/script/internal/context.py +26 -9
  46. sonolus/script/internal/descriptor.py +17 -17
  47. sonolus/script/internal/dict_impl.py +65 -0
  48. sonolus/script/internal/generic.py +6 -9
  49. sonolus/script/internal/impl.py +38 -13
  50. sonolus/script/internal/introspection.py +17 -14
  51. sonolus/script/internal/math_impls.py +121 -0
  52. sonolus/script/internal/native.py +40 -38
  53. sonolus/script/internal/random.py +67 -0
  54. sonolus/script/internal/range.py +81 -0
  55. sonolus/script/internal/transient.py +51 -0
  56. sonolus/script/internal/tuple_impl.py +113 -0
  57. sonolus/script/internal/value.py +3 -3
  58. sonolus/script/interval.py +338 -112
  59. sonolus/script/iterator.py +167 -214
  60. sonolus/script/level.py +24 -0
  61. sonolus/script/num.py +80 -48
  62. sonolus/script/options.py +257 -191
  63. sonolus/script/particle.py +190 -157
  64. sonolus/script/pointer.py +30 -30
  65. sonolus/script/print.py +102 -81
  66. sonolus/script/project.py +8 -0
  67. sonolus/script/quad.py +263 -0
  68. sonolus/script/record.py +47 -16
  69. sonolus/script/runtime.py +52 -1
  70. sonolus/script/sprite.py +418 -333
  71. sonolus/script/text.py +409 -407
  72. sonolus/script/timing.py +114 -42
  73. sonolus/script/transform.py +332 -48
  74. sonolus/script/ui.py +216 -160
  75. sonolus/script/values.py +6 -13
  76. sonolus/script/vec.py +196 -78
  77. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/METADATA +1 -1
  78. sonolus_py-0.1.5.dist-info/RECORD +89 -0
  79. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/WHEEL +1 -1
  80. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/licenses/LICENSE +21 -21
  81. sonolus/backend/allocate.py +0 -51
  82. sonolus/backend/optimize.py +0 -9
  83. sonolus/backend/passes.py +0 -6
  84. sonolus/backend/simplify.py +0 -30
  85. sonolus/script/comptime.py +0 -160
  86. sonolus/script/graphics.py +0 -150
  87. sonolus/script/math.py +0 -92
  88. sonolus/script/range.py +0 -58
  89. sonolus_py-0.1.3.dist-info/RECORD +0 -75
  90. {sonolus_py-0.1.3.dist-info → sonolus_py-0.1.5.dist-info}/entry_points.txt +0 -0
sonolus/build/cli.py CHANGED
@@ -7,6 +7,7 @@ import socket
7
7
  import socketserver
8
8
  import sys
9
9
  from pathlib import Path
10
+ from time import perf_counter
10
11
 
11
12
  from sonolus.build.engine import package_engine
12
13
  from sonolus.build.level import package_level_data
@@ -163,8 +164,13 @@ def main():
163
164
  build_dir = Path(args.build_dir)
164
165
 
165
166
  if args.command == "build":
167
+ start_time = perf_counter()
166
168
  build_project(project, build_dir)
167
- print(f"Project built successfully to '{build_dir.resolve()}'")
169
+ end_time = perf_counter()
170
+ print(f"Project built successfully to '{build_dir.resolve()}' in {end_time - start_time:.2f}s")
168
171
  elif args.command == "dev":
172
+ start_time = perf_counter()
169
173
  build_collection(project, build_dir)
174
+ end_time = perf_counter()
175
+ print(f"Build finished in {end_time - start_time:.2f}s")
170
176
  run_server(build_dir / "site", port=args.port)
sonolus/build/compile.py CHANGED
@@ -1,90 +1,88 @@
1
- from collections.abc import Callable
2
-
3
- from sonolus.backend.finalize import cfg_to_engine_node
4
- from sonolus.backend.flow import BasicBlock
5
- from sonolus.backend.ir import IRConst, IRInstr
6
- from sonolus.backend.mode import Mode
7
- from sonolus.backend.ops import Op
8
- from sonolus.backend.optimize import optimize_and_allocate
9
- from sonolus.backend.visitor import compile_and_call
10
- from sonolus.build.node import OutputNodeGenerator
11
- from sonolus.script.archetype import BaseArchetype
12
- from sonolus.script.callbacks import CallbackInfo
13
- from sonolus.script.internal.context import (
14
- CallbackContextState,
15
- Context,
16
- GlobalContextState,
17
- ReadOnlyMemory,
18
- context_to_cfg,
19
- ctx,
20
- using_ctx,
21
- )
22
- from sonolus.script.num import is_num
23
-
24
-
25
- def compile_mode(
26
- mode: Mode,
27
- rom: ReadOnlyMemory,
28
- archetypes: list[type[BaseArchetype]] | None,
29
- global_callbacks: list[tuple[CallbackInfo, Callable]] | None,
30
- ) -> dict:
31
- global_state = GlobalContextState(
32
- mode, {a: i for i, a in enumerate(archetypes)} if archetypes is not None else None, rom
33
- )
34
- nodes = OutputNodeGenerator()
35
- results = {}
36
- if archetypes is not None:
37
- archetype_entries = []
38
- for archetype in archetypes:
39
- archetype_data = {
40
- "name": archetype.name,
41
- "hasInput": archetype.is_scored,
42
- }
43
- archetype_data["imports"] = [
44
- {"name": name, "index": index} for name, index in archetype._imported_keys_.items()
45
- ]
46
- if mode == Mode.PLAY:
47
- archetype_data["exports"] = [
48
- {"name": name, "index": index} for name, index in archetype._exported_keys_.items()
49
- ]
50
- for cb_name, cb_info in archetype._supported_callbacks_.items():
51
- cb = getattr(archetype, cb_name)
52
- if cb in archetype._default_callbacks_:
53
- continue
54
- cb_order = getattr(cb, "_callback_order_", 0)
55
- if not cb_info.supports_order and cb_order != 0:
56
- raise ValueError(f"Callback '{cb_name}' does not support a non-zero order")
57
- cfg = callback_to_cfg(global_state, cb, cb_info.name, archetype)
58
- cfg = optimize_and_allocate(cfg)
59
- node = cfg_to_engine_node(cfg)
60
- node_index = nodes.add(node)
61
- archetype_data[cb_info.name] = {
62
- "index": node_index,
63
- "order": cb_order,
64
- }
65
- archetype_entries.append(archetype_data)
66
- results["archetypes"] = archetype_entries
67
- if global_callbacks is not None:
68
- for cb_info, cb in global_callbacks:
69
- cfg = callback_to_cfg(global_state, cb, cb_info.name)
70
- cfg = optimize_and_allocate(cfg)
71
- node = cfg_to_engine_node(cfg)
72
- node_index = nodes.add(node)
73
- results[cb_info.name] = node_index
74
- results["nodes"] = nodes.get()
75
- return results
76
-
77
-
78
- def callback_to_cfg(
79
- global_state: GlobalContextState, callback: Callable, name: str, archetype: type[BaseArchetype] | None = None
80
- ) -> BasicBlock:
81
- callback_state = CallbackContextState(name)
82
- context = Context(global_state, callback_state)
83
- with using_ctx(context):
84
- if archetype is not None:
85
- result = compile_and_call(callback, archetype._for_compilation())
86
- else:
87
- result = compile_and_call(callback)
88
- if is_num(result):
89
- ctx().add_statements(IRInstr(Op.Break, [IRConst(1), result.ir()]))
90
- return context_to_cfg(context)
1
+ from collections.abc import Callable
2
+
3
+ from sonolus.backend.finalize import cfg_to_engine_node
4
+ from sonolus.backend.ir import IRConst, IRInstr
5
+ from sonolus.backend.mode import Mode
6
+ from sonolus.backend.ops import Op
7
+ from sonolus.backend.optimize.flow import BasicBlock
8
+ from sonolus.backend.optimize.optimize import optimize_and_allocate
9
+ from sonolus.backend.visitor import compile_and_call
10
+ from sonolus.build.node import OutputNodeGenerator
11
+ from sonolus.script.archetype import _BaseArchetype
12
+ from sonolus.script.internal.callbacks import CallbackInfo
13
+ from sonolus.script.internal.context import (
14
+ CallbackContextState,
15
+ Context,
16
+ GlobalContextState,
17
+ ReadOnlyMemory,
18
+ context_to_cfg,
19
+ ctx,
20
+ using_ctx,
21
+ )
22
+ from sonolus.script.num import _is_num
23
+
24
+
25
+ def compile_mode(
26
+ mode: Mode,
27
+ rom: ReadOnlyMemory,
28
+ archetypes: list[type[_BaseArchetype]] | None,
29
+ global_callbacks: list[tuple[CallbackInfo, Callable]] | None,
30
+ ) -> dict:
31
+ global_state = GlobalContextState(
32
+ mode, {a: i for i, a in enumerate(archetypes)} if archetypes is not None else None, rom
33
+ )
34
+ nodes = OutputNodeGenerator()
35
+ results = {}
36
+ if archetypes is not None:
37
+ archetype_entries = []
38
+ for archetype in archetypes:
39
+ archetype_data = {
40
+ "name": archetype.name,
41
+ "hasInput": archetype.is_scored,
42
+ "imports": [{"name": name, "index": index} for name, index in archetype._imported_keys_.items()],
43
+ }
44
+ if mode == Mode.PLAY:
45
+ archetype_data["exports"] = [
46
+ {"name": name, "index": index} for name, index in archetype._exported_keys_.items()
47
+ ]
48
+ for cb_name, cb_info in archetype._supported_callbacks_.items():
49
+ cb = getattr(archetype, cb_name)
50
+ if cb in archetype._default_callbacks_:
51
+ continue
52
+ cb_order = getattr(cb, "_callback_order_", 0)
53
+ if not cb_info.supports_order and cb_order != 0:
54
+ raise ValueError(f"Callback '{cb_name}' does not support a non-zero order")
55
+ cfg = callback_to_cfg(global_state, cb, cb_info.name, archetype)
56
+ cfg = optimize_and_allocate(cfg)
57
+ node = cfg_to_engine_node(cfg)
58
+ node_index = nodes.add(node)
59
+ archetype_data[cb_info.name] = {
60
+ "index": node_index,
61
+ "order": cb_order,
62
+ }
63
+ archetype_entries.append(archetype_data)
64
+ results["archetypes"] = archetype_entries
65
+ if global_callbacks is not None:
66
+ for cb_info, cb in global_callbacks:
67
+ cfg = callback_to_cfg(global_state, cb, cb_info.name)
68
+ cfg = optimize_and_allocate(cfg)
69
+ node = cfg_to_engine_node(cfg)
70
+ node_index = nodes.add(node)
71
+ results[cb_info.name] = node_index
72
+ results["nodes"] = nodes.get()
73
+ return results
74
+
75
+
76
+ def callback_to_cfg(
77
+ global_state: GlobalContextState, callback: Callable, name: str, archetype: type[_BaseArchetype] | None = None
78
+ ) -> BasicBlock:
79
+ callback_state = CallbackContextState(name)
80
+ context = Context(global_state, callback_state)
81
+ with using_ctx(context):
82
+ if archetype is not None:
83
+ result = compile_and_call(callback, archetype._for_compilation())
84
+ else:
85
+ result = compile_and_call(callback)
86
+ if _is_num(result):
87
+ ctx().add_statements(IRInstr(Op.Break, [IRConst(1), result.ir()]))
88
+ return context_to_cfg(context)
sonolus/build/engine.py CHANGED
@@ -7,15 +7,20 @@ from pathlib import Path
7
7
 
8
8
  from sonolus.backend.mode import Mode
9
9
  from sonolus.build.compile import compile_mode
10
- from sonolus.script.archetype import BaseArchetype
10
+ from sonolus.script.archetype import _BaseArchetype
11
11
  from sonolus.script.bucket import Buckets
12
- from sonolus.script.callbacks import navigate_callback, preprocess_callback, update_callback, update_spawn_callback
13
12
  from sonolus.script.effect import Effects
14
13
  from sonolus.script.engine import EngineData
15
14
  from sonolus.script.instruction import (
16
15
  TutorialInstructionIcons,
17
16
  TutorialInstructions,
18
17
  )
18
+ from sonolus.script.internal.callbacks import (
19
+ navigate_callback,
20
+ preprocess_callback,
21
+ update_callback,
22
+ update_spawn_callback,
23
+ )
19
24
  from sonolus.script.internal.context import ReadOnlyMemory
20
25
  from sonolus.script.options import Options
21
26
  from sonolus.script.particle import Particles
@@ -101,7 +106,7 @@ def build_engine_configuration(
101
106
 
102
107
 
103
108
  def build_play_mode(
104
- archetypes: list[type[BaseArchetype]],
109
+ archetypes: list[type[_BaseArchetype]],
105
110
  skin: Skin,
106
111
  effects: Effects,
107
112
  particles: Particles,
@@ -118,7 +123,7 @@ def build_play_mode(
118
123
 
119
124
 
120
125
  def build_watch_mode(
121
- archetypes: list[type[BaseArchetype]],
126
+ archetypes: list[type[_BaseArchetype]],
122
127
  skin: Skin,
123
128
  effects: Effects,
124
129
  particles: Particles,
@@ -138,7 +143,7 @@ def build_watch_mode(
138
143
 
139
144
 
140
145
  def build_preview_mode(
141
- archetypes: list[type[BaseArchetype]],
146
+ archetypes: list[type[_BaseArchetype]],
142
147
  skin: Skin,
143
148
  rom: ReadOnlyMemory,
144
149
  ):
sonolus/build/level.py CHANGED
@@ -1,23 +1,24 @@
1
- from sonolus.build.engine import package_output
2
- from sonolus.script.level import LevelData
3
-
4
-
5
- def package_level_data(
6
- level_data: LevelData,
7
- ):
8
- return package_output(build_level_data(level_data))
9
-
10
-
11
- def build_level_data(
12
- level_data: LevelData,
13
- ):
14
- return {
15
- "bgmOffset": level_data.bgm_offset,
16
- "entities": [
17
- {
18
- "archetype": entity.name,
19
- "data": entity._level_data_entries(),
20
- }
21
- for entity in level_data.entities
22
- ],
23
- }
1
+ from sonolus.build.engine import package_output
2
+ from sonolus.script.level import LevelData
3
+
4
+
5
+ def package_level_data(
6
+ level_data: LevelData,
7
+ ):
8
+ return package_output(build_level_data(level_data))
9
+
10
+
11
+ def build_level_data(
12
+ level_data: LevelData,
13
+ ):
14
+ level_refs = {entity: i for i, entity in enumerate(level_data.entities)}
15
+ return {
16
+ "bgmOffset": level_data.bgm_offset,
17
+ "entities": [
18
+ {
19
+ "archetype": entity.name,
20
+ "data": entity._level_data_entries(level_refs),
21
+ }
22
+ for entity in level_data.entities
23
+ ],
24
+ }
sonolus/build/node.py CHANGED
@@ -1,43 +1,43 @@
1
- from typing import TypedDict
2
-
3
- from sonolus.backend.node import ConstantNode, EngineNode, FunctionNode
4
-
5
-
6
- class ValueOutputNode(TypedDict):
7
- value: float
8
-
9
-
10
- class FunctionOutputNode(TypedDict):
11
- func: str
12
- args: list[int]
13
-
14
-
15
- class OutputNodeGenerator:
16
- nodes: list[ValueOutputNode | FunctionOutputNode]
17
- indexes: dict[EngineNode, int]
18
-
19
- def __init__(self):
20
- self.nodes = []
21
- self.indexes = {}
22
-
23
- def add(self, node: EngineNode):
24
- if node in self.indexes:
25
- return self.indexes[node]
26
-
27
- match node:
28
- case ConstantNode(value):
29
- index = len(self.nodes)
30
- self.nodes.append({"value": value})
31
- self.indexes[node] = index
32
- return index
33
- case FunctionNode(func, args):
34
- arg_indexes = [self.add(arg) for arg in args]
35
- index = len(self.nodes)
36
- self.nodes.append({"func": func.value, "args": arg_indexes})
37
- self.indexes[node] = index
38
- return index
39
- case _:
40
- raise ValueError("Invalid node")
41
-
42
- def get(self):
43
- return self.nodes
1
+ from typing import TypedDict
2
+
3
+ from sonolus.backend.node import ConstantNode, EngineNode, FunctionNode
4
+
5
+
6
+ class ValueOutputNode(TypedDict):
7
+ value: float
8
+
9
+
10
+ class FunctionOutputNode(TypedDict):
11
+ func: str
12
+ args: list[int]
13
+
14
+
15
+ class OutputNodeGenerator:
16
+ nodes: list[ValueOutputNode | FunctionOutputNode]
17
+ indexes: dict[EngineNode, int]
18
+
19
+ def __init__(self):
20
+ self.nodes = []
21
+ self.indexes = {}
22
+
23
+ def add(self, node: EngineNode):
24
+ if node in self.indexes:
25
+ return self.indexes[node]
26
+
27
+ match node:
28
+ case ConstantNode(value):
29
+ index = len(self.nodes)
30
+ self.nodes.append({"value": value})
31
+ self.indexes[node] = index
32
+ return index
33
+ case FunctionNode(func, args):
34
+ arg_indexes = [self.add(arg) for arg in args]
35
+ index = len(self.nodes)
36
+ self.nodes.append({"func": func.value, "args": arg_indexes})
37
+ self.indexes[node] = index
38
+ return index
39
+ case _:
40
+ raise ValueError("Invalid node")
41
+
42
+ def get(self):
43
+ return self.nodes