moonscratch 0.1.1 → 0.1.2

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.
Files changed (149) hide show
  1. package/dist/chunk-DQk6qfdC.mjs +18 -0
  2. package/dist/index.d.mts +1173 -0
  3. package/dist/index.mjs +27135 -0
  4. package/package.json +6 -1
  5. package/.agents/skills/moonbit-agent-guide/LICENSE +0 -202
  6. package/.agents/skills/moonbit-agent-guide/SKILL.mbt.md +0 -1126
  7. package/.agents/skills/moonbit-agent-guide/SKILL.md +0 -1126
  8. package/.agents/skills/moonbit-agent-guide/ide.md +0 -116
  9. package/.agents/skills/moonbit-agent-guide/references/advanced-moonbit-build.md +0 -106
  10. package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.mbt.md +0 -422
  11. package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.md +0 -422
  12. package/.agents/skills/moonbit-practice/SKILL.md +0 -258
  13. package/.agents/skills/moonbit-practice/assets/ci.yaml +0 -25
  14. package/.agents/skills/moonbit-practice/reference/agents.md +0 -1469
  15. package/.agents/skills/moonbit-practice/reference/configuration.md +0 -228
  16. package/.agents/skills/moonbit-practice/reference/ffi.md +0 -229
  17. package/.agents/skills/moonbit-practice/reference/ide.md +0 -189
  18. package/.agents/skills/moonbit-practice/reference/performance.md +0 -217
  19. package/.agents/skills/moonbit-practice/reference/refactor.md +0 -154
  20. package/.agents/skills/moonbit-practice/reference/stdlib.md +0 -351
  21. package/.agents/skills/moonbit-practice/reference/testing.md +0 -228
  22. package/.agents/skills/moonbit-refactoring/LICENSE +0 -21
  23. package/.agents/skills/moonbit-refactoring/SKILL.md +0 -323
  24. package/.githooks/README.md +0 -23
  25. package/.githooks/pre-commit +0 -3
  26. package/.github/workflows/copilot-setup-steps.yml +0 -40
  27. package/AGENTS.md +0 -91
  28. package/PLAN.md +0 -64
  29. package/TODO.md +0 -120
  30. package/benchmarks/calc.bench.ts +0 -144
  31. package/benchmarks/draw.bench.ts +0 -215
  32. package/benchmarks/load.bench.ts +0 -28
  33. package/benchmarks/render.bench.ts +0 -53
  34. package/benchmarks/run.bench.ts +0 -8
  35. package/benchmarks/types.d.ts +0 -15
  36. package/docs/scratch-vm-specs/eventloop.md +0 -103
  37. package/docs/scratch-vm-specs/moonscratch-time-separation.md +0 -50
  38. package/index.html +0 -91
  39. package/js/AGENTS.md +0 -5
  40. package/js/a.ts +0 -52
  41. package/js/assets/AGENTS.md +0 -5
  42. package/js/assets/base64.test.ts +0 -14
  43. package/js/assets/base64.ts +0 -21
  44. package/js/assets/build-asset.test.ts +0 -26
  45. package/js/assets/build-asset.ts +0 -28
  46. package/js/assets/create.test.ts +0 -142
  47. package/js/assets/create.ts +0 -122
  48. package/js/assets/index.test.ts +0 -15
  49. package/js/assets/index.ts +0 -2
  50. package/js/assets/types.ts +0 -26
  51. package/js/assets/validation.test.ts +0 -34
  52. package/js/assets/validation.ts +0 -25
  53. package/js/assets.test.ts +0 -14
  54. package/js/assets.ts +0 -1
  55. package/js/index.test.ts +0 -26
  56. package/js/index.ts +0 -3
  57. package/js/render/index.test.ts +0 -65
  58. package/js/render/index.ts +0 -13
  59. package/js/render/sharp.ts +0 -87
  60. package/js/render/svg.ts +0 -68
  61. package/js/render/types.ts +0 -35
  62. package/js/render/utils.ts +0 -108
  63. package/js/render/webgl.ts +0 -274
  64. package/js/sharp-optional.d.ts +0 -16
  65. package/js/test/helpers.ts +0 -116
  66. package/js/test/hikkaku-sample.test.ts +0 -37
  67. package/js/test/rubik-components.input-motion.test.ts +0 -60
  68. package/js/test/rubik-components.lists.test.ts +0 -49
  69. package/js/test/rubik-components.operators.test.ts +0 -104
  70. package/js/test/rubik-components.pen.test.ts +0 -112
  71. package/js/test/rubik-components.procedures-loops.test.ts +0 -72
  72. package/js/test/rubik-components.variables-branches.test.ts +0 -57
  73. package/js/test/rubik-components.visibility-entry.test.ts +0 -31
  74. package/js/test/test-projects.ts +0 -598
  75. package/js/test/variable.ts +0 -200
  76. package/js/test/warp.test.ts +0 -59
  77. package/js/vm/AGENTS.md +0 -6
  78. package/js/vm/README.md +0 -183
  79. package/js/vm/bindings.test.ts +0 -13
  80. package/js/vm/bindings.ts +0 -5
  81. package/js/vm/compare-operators.test.ts +0 -145
  82. package/js/vm/constants.test.ts +0 -11
  83. package/js/vm/constants.ts +0 -4
  84. package/js/vm/effect-guards.test.ts +0 -68
  85. package/js/vm/effect-guards.ts +0 -44
  86. package/js/vm/factory.test.ts +0 -486
  87. package/js/vm/factory.ts +0 -615
  88. package/js/vm/headless-vm.test.ts +0 -131
  89. package/js/vm/headless-vm.ts +0 -342
  90. package/js/vm/index.test.ts +0 -28
  91. package/js/vm/index.ts +0 -5
  92. package/js/vm/internal-types.ts +0 -32
  93. package/js/vm/json.test.ts +0 -40
  94. package/js/vm/json.ts +0 -273
  95. package/js/vm/normalize.test.ts +0 -48
  96. package/js/vm/normalize.ts +0 -65
  97. package/js/vm/options.test.ts +0 -30
  98. package/js/vm/options.ts +0 -55
  99. package/js/vm/pen-transparency.test.ts +0 -115
  100. package/js/vm/program-wasm.ts +0 -322
  101. package/js/vm/scheduler-render.test.ts +0 -401
  102. package/js/vm/scratch-assets.test.ts +0 -136
  103. package/js/vm/scratch-assets.ts +0 -202
  104. package/js/vm/types.ts +0 -358
  105. package/js/vm/value-guards.test.ts +0 -25
  106. package/js/vm/value-guards.ts +0 -18
  107. package/moon.mod.json +0 -10
  108. package/scripts/preinstall.ts +0 -4
  109. package/src/AGENTS.md +0 -6
  110. package/src/api.mbt +0 -161
  111. package/src/api_aot_commands.mbt +0 -184
  112. package/src/api_effects_json.mbt +0 -72
  113. package/src/api_options.mbt +0 -60
  114. package/src/api_program_wasm.mbt +0 -1647
  115. package/src/api_program_wat.mbt +0 -2206
  116. package/src/api_snapshot_json.mbt +0 -44
  117. package/src/cmd/AGENTS.md +0 -5
  118. package/src/cmd/main/AGENTS.md +0 -5
  119. package/src/cmd/main/main.mbt +0 -29
  120. package/src/cmd/main/moon.pkg +0 -7
  121. package/src/cmd/main/pkg.generated.mbti +0 -13
  122. package/src/json_helpers.mbt +0 -176
  123. package/src/moon.pkg +0 -65
  124. package/src/moonscratch.mbt +0 -3
  125. package/src/moonscratch_wbtest.mbt +0 -40
  126. package/src/parser_sb3.mbt +0 -890
  127. package/src/pkg.generated.mbti +0 -479
  128. package/src/runtime_eval.mbt +0 -2844
  129. package/src/runtime_exec.mbt +0 -3850
  130. package/src/runtime_render.mbt +0 -2550
  131. package/src/runtime_state.mbt +0 -870
  132. package/src/test/AGENTS.md +0 -3
  133. package/src/test/projects/AGENTS.md +0 -6
  134. package/src/test/projects/moon.pkg +0 -4
  135. package/src/test/projects/moonscratch_compat_test.mbt +0 -642
  136. package/src/test/projects/moonscratch_core_test.mbt +0 -1332
  137. package/src/test/projects/moonscratch_runtime_test.mbt +0 -1087
  138. package/src/test/projects/pkg.generated.mbti +0 -13
  139. package/src/test/projects/test_support.mbt +0 -35
  140. package/src/types_effects.mbt +0 -20
  141. package/src/types_error.mbt +0 -4
  142. package/src/types_options.mbt +0 -31
  143. package/src/types_runtime_structs.mbt +0 -254
  144. package/src/types_vm.mbt +0 -109
  145. package/tsconfig.json +0 -29
  146. package/viewer/index.ts +0 -399
  147. package/viewer/vite.d.ts +0 -1
  148. package/viewer/worker.ts +0 -161
  149. package/vite.config.ts +0 -61
@@ -1,2206 +0,0 @@
1
- ///|
2
- const PROGRAM_ABI_VERSION : Int = 2
3
-
4
- ///|
5
- fn page_count_for_bytes(total_bytes : Int) -> Int {
6
- if total_bytes <= 0 {
7
- 1
8
- } else {
9
- (total_bytes + 65535) / 65536
10
- }
11
- }
12
-
13
- ///|
14
- fn base64_utf8(raw : String) -> String {
15
- let encoded = @utf8.encode(raw.view())
16
- @base64.encode(encoded[:])
17
- }
18
-
19
- ///|
20
- fn json_number_or_null(value : Int?) -> Json {
21
- match value {
22
- Some(v) => json_number(Double::from_int(v))
23
- None => Json::null()
24
- }
25
- }
26
-
27
- ///|
28
- fn command_json_opcode_catalog(
29
- target_index : Int,
30
- pc : Int,
31
- block : ScratchBlock,
32
- meta : BlockFastMeta,
33
- ) -> Json {
34
- json_object({
35
- "op": json_string("opcode"),
36
- "target": json_number(Double::from_int(target_index)),
37
- "pc": json_number(Double::from_int(pc)),
38
- "id": json_string(block.id),
39
- "opcode": json_string(block.opcode),
40
- "top_level": json_bool(block.top_level),
41
- "next_pc": json_number_or_null(meta.next_pc),
42
- "substack_pc": json_number_or_null(meta.substack_pc),
43
- "substack2_pc": json_number_or_null(meta.substack2_pc),
44
- })
45
- }
46
-
47
- ///|
48
- fn command_json_full_green_flag_start_entry(
49
- target_index : Int,
50
- start_pcs : Array[Int],
51
- ) -> Json {
52
- let pcs = start_pcs.map(fn(pc) { json_number(Double::from_int(pc)) })
53
- json_object({
54
- "target": json_number(Double::from_int(target_index)),
55
- "pcs": json_array(pcs),
56
- })
57
- }
58
-
59
- ///|
60
- fn target_is_aot_eligible(target : TargetState) -> Bool {
61
- target.top_level_hats.length() == target.green_flag_starts.length() &&
62
- target.stage_clicked_starts.is_empty() &&
63
- target.sprite_clicked_starts.is_empty() &&
64
- target.clone_start_starts.is_empty() &&
65
- target.key_pressed_hats.is_empty() &&
66
- target.broadcast_hats.is_empty() &&
67
- target.backdrop_hats.is_empty() &&
68
- target.predicate_hats.is_empty()
69
- }
70
-
71
- ///|
72
- priv enum AotCompileStmtResult {
73
- Noop
74
- Emit(Json)
75
- EmitAndStop(Json)
76
- }
77
-
78
- ///|
79
- fn expr_json_num(value : Double) -> Json {
80
- json_object({ "kind": json_string("num"), "value": json_number(value) })
81
- }
82
-
83
- ///|
84
- fn expr_json_var_num(target_index : Int, variable_id : String) -> Json {
85
- json_object({
86
- "kind": json_string("var_num"),
87
- "target": json_number(Double::from_int(target_index)),
88
- "id": json_string(variable_id),
89
- })
90
- }
91
-
92
- ///|
93
- fn expr_json_bin_num(op : String, left : Json, right : Json) -> Json {
94
- json_object({
95
- "kind": json_string("bin_num"),
96
- "op": json_string(op),
97
- "left": left,
98
- "right": right,
99
- })
100
- }
101
-
102
- ///|
103
- fn expr_json_unary_num(op : String, value : Json) -> Json {
104
- json_object({
105
- "kind": json_string("unary_num"),
106
- "op": json_string(op),
107
- "value": value,
108
- })
109
- }
110
-
111
- ///|
112
- fn expr_json_bool(value : Bool) -> Json {
113
- json_object({ "kind": json_string("bool"), "value": json_bool(value) })
114
- }
115
-
116
- ///|
117
- fn expr_json_cmp_num(op : String, left : Json, right : Json) -> Json {
118
- json_object({
119
- "kind": json_string("cmp_num"),
120
- "op": json_string(op),
121
- "left": left,
122
- "right": right,
123
- })
124
- }
125
-
126
- ///|
127
- fn expr_json_bin_bool(op : String, left : Json, right : Json) -> Json {
128
- json_object({
129
- "kind": json_string("bin_bool"),
130
- "op": json_string(op),
131
- "left": left,
132
- "right": right,
133
- })
134
- }
135
-
136
- ///|
137
- fn expr_json_not(value : Json) -> Json {
138
- json_object({ "kind": json_string("not"), "value": value })
139
- }
140
-
141
- ///|
142
- fn expr_json_bool_from_number(expr : Json) -> Json {
143
- expr_json_cmp_num("ne", expr, expr_json_num(0.0))
144
- }
145
-
146
- ///|
147
- fn command_json_set_var_num_expr(
148
- target_index : Int,
149
- variable_id : String,
150
- expr : Json,
151
- ) -> Json {
152
- json_object({
153
- "op": json_string("set_var_num_expr"),
154
- "target": json_number(Double::from_int(target_index)),
155
- "id": json_string(variable_id),
156
- "expr": expr,
157
- })
158
- }
159
-
160
- ///|
161
- fn command_json_set_var_json_const(
162
- target_index : Int,
163
- variable_id : String,
164
- value : Json,
165
- ) -> Json {
166
- json_object({
167
- "op": json_string("set_var_json_const"),
168
- "target": json_number(Double::from_int(target_index)),
169
- "id": json_string(variable_id),
170
- "value": value,
171
- })
172
- }
173
-
174
- ///|
175
- fn command_json_change_var_num_expr(
176
- target_index : Int,
177
- variable_id : String,
178
- expr : Json,
179
- ) -> Json {
180
- json_object({
181
- "op": json_string("change_var_num_expr"),
182
- "target": json_number(Double::from_int(target_index)),
183
- "id": json_string(variable_id),
184
- "expr": expr,
185
- })
186
- }
187
-
188
- ///|
189
- fn command_json_if(cond : Json, then_commands : Array[Json]) -> Json {
190
- json_object({
191
- "op": json_string("if"),
192
- "cond": cond,
193
- "then": json_array(then_commands),
194
- })
195
- }
196
-
197
- ///|
198
- fn command_json_if_else(
199
- cond : Json,
200
- then_commands : Array[Json],
201
- else_commands : Array[Json],
202
- ) -> Json {
203
- json_object({
204
- "op": json_string("if_else"),
205
- "cond": cond,
206
- "then": json_array(then_commands),
207
- "else": json_array(else_commands),
208
- })
209
- }
210
-
211
- ///|
212
- fn command_json_repeat(times : Json, body_commands : Array[Json]) -> Json {
213
- json_object({
214
- "op": json_string("repeat"),
215
- "times": times,
216
- "body": json_array(body_commands),
217
- })
218
- }
219
-
220
- ///|
221
- fn command_json_repeat_until(cond : Json, body_commands : Array[Json]) -> Json {
222
- json_object({
223
- "op": json_string("repeat_until"),
224
- "cond": cond,
225
- "body": json_array(body_commands),
226
- })
227
- }
228
-
229
- ///|
230
- fn command_json_while(cond : Json, body_commands : Array[Json]) -> Json {
231
- json_object({
232
- "op": json_string("while"),
233
- "cond": cond,
234
- "body": json_array(body_commands),
235
- })
236
- }
237
-
238
- ///|
239
- fn command_json_host_tail(target_index : Int, start_pc : Int) -> Json {
240
- json_object({
241
- "op": json_string("host_tail"),
242
- "target": json_number(Double::from_int(target_index)),
243
- "pc": json_number(Double::from_int(start_pc)),
244
- })
245
- }
246
-
247
- ///|
248
- fn command_json_host_opcode(target_index : Int, pc : Int) -> Json {
249
- json_object({
250
- "op": json_string("host_opcode"),
251
- "target": json_number(Double::from_int(target_index)),
252
- "pc": json_number(Double::from_int(pc)),
253
- })
254
- }
255
-
256
- ///|
257
- fn command_json_draw_opcode(
258
- target_index : Int,
259
- opcode : String,
260
- arg0 : Json,
261
- arg1 : Json,
262
- extra : Int,
263
- ) -> Json {
264
- json_object({
265
- "op": json_string("draw_opcode"),
266
- "target": json_number(Double::from_int(target_index)),
267
- "opcode": json_string(opcode),
268
- "arg0": arg0,
269
- "arg1": arg1,
270
- "extra": json_number(Double::from_int(extra)),
271
- })
272
- }
273
-
274
- ///|
275
- fn normalize_looks_effect_name_for_draw(raw : String) -> Int? {
276
- match raw.trim().to_lower() {
277
- "color" => Some(1)
278
- "fisheye" => Some(2)
279
- "whirl" => Some(3)
280
- "pixelate" => Some(4)
281
- "mosaic" => Some(5)
282
- "brightness" => Some(6)
283
- "ghost" => Some(7)
284
- _ => None
285
- }
286
- }
287
-
288
- ///|
289
- fn normalize_pen_color_param_for_draw(raw : String) -> Int? {
290
- match raw.trim().to_lower() {
291
- "color" => Some(1)
292
- "saturation" => Some(2)
293
- "brightness" => Some(3)
294
- "transparency" => Some(4)
295
- _ => None
296
- }
297
- }
298
-
299
- ///|
300
- fn literal_string_from_input_or_field(
301
- block : ScratchBlock,
302
- input_name : String,
303
- field_name : String,
304
- ) -> String? {
305
- let from_input = match block.input_block_ids.get(input_name) {
306
- Some(_) => None
307
- None =>
308
- match block.inputs.get(input_name) {
309
- Some(raw_input) =>
310
- match input_payload(raw_input) {
311
- Some(payload) =>
312
- match literal_value_from_payload(payload) {
313
- Some(value) => {
314
- let text = json_to_string_value(value).trim().to_string()
315
- if text == "" {
316
- None
317
- } else {
318
- Some(text)
319
- }
320
- }
321
- None => None
322
- }
323
- None => None
324
- }
325
- None => None
326
- }
327
- }
328
- match from_input {
329
- Some(value) => Some(value)
330
- None =>
331
- match field_value(block, field_name) {
332
- Some((raw, _)) => {
333
- let text = raw.trim().to_string()
334
- if text == "" {
335
- None
336
- } else {
337
- Some(text)
338
- }
339
- }
340
- None => None
341
- }
342
- }
343
- }
344
-
345
- ///|
346
- fn command_is_host_tail(command : Json) -> Bool {
347
- match command {
348
- Object(obj) =>
349
- match obj.get("op") {
350
- Some(String("host_tail")) => true
351
- Some(String("if")) =>
352
- match obj.get("then") {
353
- Some(Array(children)) => command_list_contains_host_tail(children)
354
- _ => false
355
- }
356
- Some(String("if_else")) =>
357
- match (obj.get("then"), obj.get("else")) {
358
- (Some(Array(then_children)), Some(Array(else_children))) =>
359
- command_list_contains_host_tail(then_children) ||
360
- command_list_contains_host_tail(else_children)
361
- _ => false
362
- }
363
- Some(String("repeat"))
364
- | Some(String("repeat_until"))
365
- | Some(String("while")) =>
366
- match obj.get("body") {
367
- Some(Array(children)) => command_list_contains_host_tail(children)
368
- _ => false
369
- }
370
- _ => false
371
- }
372
- _ => false
373
- }
374
- }
375
-
376
- ///|
377
- fn command_list_contains_host_tail(commands : Array[Json]) -> Bool {
378
- for command in commands {
379
- if command_is_host_tail(command) {
380
- return true
381
- }
382
- }
383
- false
384
- }
385
-
386
- ///|
387
- fn opcode_uses_safe_host_opcode(opcode : String) -> Bool {
388
- match opcode {
389
- "music_setInstrument"
390
- | "music_midiSetInstrument"
391
- | "music_setTempo"
392
- | "music_changeTempo"
393
- | "text2speech_setVoice"
394
- | "text2speech_setLanguage"
395
- | "sound_play"
396
- | "sound_playuntildone"
397
- | "sound_stopallsounds"
398
- | "sound_setvolumeto"
399
- | "sound_changevolumeby"
400
- | "sound_seteffectto"
401
- | "sound_changeeffectby"
402
- | "sound_cleareffects"
403
- | "data_setvariableto"
404
- | "data_changevariableby"
405
- | "data_addtolist"
406
- | "data_deleteoflist"
407
- | "data_deletealloflist"
408
- | "data_insertatlist"
409
- | "data_replaceitemoflist"
410
- | "data_showvariable"
411
- | "data_hidevariable"
412
- | "data_showlist"
413
- | "data_hidelist"
414
- | "event_broadcast"
415
- | "sensing_resettimer"
416
- | "sensing_setdragmode"
417
- | "control_clear_counter"
418
- | "control_incr_counter"
419
- | "motion_movesteps"
420
- | "motion_turnright"
421
- | "motion_turnleft"
422
- | "motion_pointindirection"
423
- | "motion_pointtowards"
424
- | "motion_changexby"
425
- | "motion_changeyby"
426
- | "motion_setx"
427
- | "motion_sety"
428
- | "motion_gotoxy"
429
- | "motion_goto"
430
- | "motion_ifonedgebounce"
431
- | "motion_setrotationstyle"
432
- | "motion_align_scene"
433
- | "motion_scroll_right"
434
- | "motion_scroll_up"
435
- | "looks_show"
436
- | "looks_hide"
437
- | "looks_hideallsprites"
438
- | "looks_switchcostumeto"
439
- | "looks_nextcostume"
440
- | "looks_switchbackdropto"
441
- | "looks_nextbackdrop"
442
- | "looks_changeeffectby"
443
- | "looks_seteffectto"
444
- | "looks_cleargraphiceffects"
445
- | "looks_changestretchby"
446
- | "looks_setstretchto"
447
- | "looks_gotofrontback"
448
- | "looks_goforwardbackwardlayers"
449
- | "looks_changesizeby"
450
- | "looks_setsizeto"
451
- | "looks_say"
452
- | "looks_think"
453
- | "pen_clear"
454
- | "pen_stamp"
455
- | "pen_penDown"
456
- | "pen_penUp"
457
- | "pen_setPenColorToColor"
458
- | "pen_changePenColorParamBy"
459
- | "pen_setPenColorParamTo"
460
- | "pen_changePenSizeBy"
461
- | "pen_setPenSizeTo"
462
- | "pen_setPenHueToNumber"
463
- | "pen_changePenHueBy"
464
- | "pen_setPenShadeToNumber"
465
- | "pen_changePenShadeBy" => true
466
- _ => false
467
- }
468
- }
469
-
470
- ///|
471
- fn opcode_fallback_stmt(
472
- opcode : String,
473
- target_index : Int,
474
- pc : Int,
475
- ) -> AotCompileStmtResult {
476
- if opcode_uses_safe_host_opcode(opcode) {
477
- AotCompileStmtResult::Emit(command_json_host_opcode(target_index, pc))
478
- } else {
479
- AotCompileStmtResult::EmitAndStop(command_json_host_tail(target_index, pc))
480
- }
481
- }
482
-
483
- ///|
484
- fn variable_id_from_field(block : ScratchBlock) -> String? {
485
- match field_value(block, "VARIABLE") {
486
- Some((_, Some(id))) if id != "" => Some(id)
487
- _ => None
488
- }
489
- }
490
-
491
- ///|
492
- fn literal_value_from_payload(payload : Json) -> Json? {
493
- match payload {
494
- Array(primitive) =>
495
- if primitive.length() >= 2 {
496
- let kind = json_to_number_value(primitive[0]).to_int()
497
- if kind >= 4 && kind <= 8 {
498
- Some(json_number(json_to_number_value(primitive[1])))
499
- } else if kind == 10 || kind == 11 {
500
- Some(json_string(json_to_string_value(primitive[1])))
501
- } else if kind == 12 || kind == 13 {
502
- None
503
- } else {
504
- match primitive[1] {
505
- String(_) | Number(_, ..) | True | False | Null =>
506
- Some(primitive[1])
507
- _ => None
508
- }
509
- }
510
- } else {
511
- None
512
- }
513
- String(_) | Number(_, ..) | True | False | Null => Some(payload)
514
- _ => None
515
- }
516
- }
517
-
518
- ///|
519
- fn literal_value_from_input(block : ScratchBlock, input_name : String) -> Json? {
520
- match block.input_block_ids.get(input_name) {
521
- Some(_) => None
522
- None =>
523
- match block.inputs.get(input_name) {
524
- Some(raw_input) =>
525
- match input_payload(raw_input) {
526
- Some(payload) => literal_value_from_payload(payload)
527
- None => None
528
- }
529
- None => None
530
- }
531
- }
532
- }
533
-
534
- ///|
535
- fn json_finite_number_or_none(value : Json) -> Double? {
536
- match value {
537
- Number(n, ..) => if n.is_nan() || n.is_inf() { None } else { Some(n) }
538
- _ => None
539
- }
540
- }
541
-
542
- ///|
543
- fn resolve_reporter_block_id(
544
- block : ScratchBlock,
545
- input_name : String,
546
- ) -> String? {
547
- match block.input_block_ids.get(input_name) {
548
- Some(id) => Some(id)
549
- None =>
550
- match block.inputs.get(input_name) {
551
- Some(raw_input) =>
552
- match input_payload(raw_input) {
553
- Some(String(id)) => Some(id)
554
- _ => None
555
- }
556
- None => None
557
- }
558
- }
559
- }
560
-
561
- ///|
562
- fn variable_id_from_primitive(primitive : Array[Json]) -> String? {
563
- if primitive.length() >= 3 {
564
- let id = json_to_string_value(primitive[2])
565
- if id != "" {
566
- return Some(id)
567
- }
568
- }
569
- None
570
- }
571
-
572
- ///|
573
- fn json_is_numeric_comparable_for_aot(value : Json) -> Bool {
574
- match value {
575
- Number(n, ..) => n == n
576
- String(s) =>
577
- match parse_double_or_none(s) {
578
- Some(number) => number == number
579
- None => false
580
- }
581
- True => true
582
- False => true
583
- _ => false
584
- }
585
- }
586
-
587
- ///|
588
- fn build_aot_variable_numeric_map(
589
- targets : Array[TargetState],
590
- ) -> Map[String, Bool] {
591
- let out = {}
592
- for target in targets {
593
- target.variables.each((variable_id, value) => {
594
- out[variable_id] = json_is_numeric_comparable_for_aot(value)
595
- })
596
- }
597
- out
598
- }
599
-
600
- ///|
601
- fn number_expr_uses_only_numeric_variables(
602
- expr : Json,
603
- variable_numeric_by_id : Map[String, Bool],
604
- depth : Int,
605
- ) -> Bool {
606
- if depth > 64 {
607
- return false
608
- }
609
- match expr {
610
- Object(obj) =>
611
- match obj.get("kind") {
612
- Some(String("num")) => true
613
- Some(String("var_num")) =>
614
- match obj.get("id") {
615
- Some(String(variable_id)) =>
616
- match variable_numeric_by_id.get(variable_id) {
617
- Some(is_numeric) => is_numeric
618
- None => false
619
- }
620
- _ => false
621
- }
622
- Some(String("bin_num")) =>
623
- match (obj.get("left"), obj.get("right")) {
624
- (Some(left), Some(right)) =>
625
- number_expr_uses_only_numeric_variables(
626
- left,
627
- variable_numeric_by_id,
628
- depth + 1,
629
- ) &&
630
- number_expr_uses_only_numeric_variables(
631
- right,
632
- variable_numeric_by_id,
633
- depth + 1,
634
- )
635
- _ => false
636
- }
637
- Some(String("unary_num")) =>
638
- match obj.get("value") {
639
- Some(value) =>
640
- number_expr_uses_only_numeric_variables(
641
- value,
642
- variable_numeric_by_id,
643
- depth + 1,
644
- )
645
- None => false
646
- }
647
- _ => false
648
- }
649
- _ => false
650
- }
651
- }
652
-
653
- ///|
654
- fn compile_number_expr_from_payload(
655
- target_index : Int,
656
- payload : Json,
657
- allow_variable : Bool,
658
- ) -> Json? {
659
- match payload {
660
- Array(primitive) =>
661
- if primitive.length() >= 2 {
662
- let kind = json_to_number_value(primitive[0]).to_int()
663
- if kind >= 4 && kind <= 8 {
664
- Some(expr_json_num(json_to_number_value(primitive[1])))
665
- } else if kind == 10 || kind == 11 {
666
- None
667
- } else if kind == 12 {
668
- if !allow_variable {
669
- None
670
- } else {
671
- match variable_id_from_primitive(primitive) {
672
- Some(id) => Some(expr_json_var_num(target_index, id))
673
- None => None
674
- }
675
- }
676
- } else {
677
- match primitive[1] {
678
- String(_) => None
679
- _ => Some(expr_json_num(json_to_number_value(primitive[1])))
680
- }
681
- }
682
- } else {
683
- None
684
- }
685
- String(_) => None
686
- _ => Some(expr_json_num(json_to_number_value(payload)))
687
- }
688
- }
689
-
690
- ///|
691
- fn compile_bool_expr_from_payload(target_index : Int, payload : Json) -> Json? {
692
- match payload {
693
- Array(primitive) =>
694
- if primitive.length() >= 2 {
695
- let kind = json_to_number_value(primitive[0]).to_int()
696
- if kind == 12 {
697
- match variable_id_from_primitive(primitive) {
698
- Some(id) =>
699
- Some(
700
- expr_json_bool_from_number(expr_json_var_num(target_index, id)),
701
- )
702
- None => None
703
- }
704
- } else {
705
- Some(expr_json_bool(json_to_bool_value(primitive[1])))
706
- }
707
- } else {
708
- None
709
- }
710
- _ => Some(expr_json_bool(json_to_bool_value(payload)))
711
- }
712
- }
713
-
714
- ///|
715
- fn compile_number_expr_from_block(
716
- target : TargetState,
717
- target_index : Int,
718
- block_id : String,
719
- depth : Int,
720
- allow_variable : Bool,
721
- ) -> Json? {
722
- if depth > 64 {
723
- return None
724
- }
725
- let block = match target.blocks.get(block_id) {
726
- Some(value) => value
727
- None => return None
728
- }
729
- match block.opcode {
730
- "math_number"
731
- | "math_integer"
732
- | "math_whole_number"
733
- | "math_positive_number"
734
- | "math_angle" =>
735
- match field_value(block, "NUM") {
736
- Some((raw, _)) =>
737
- Some(
738
- expr_json_num(
739
- match parse_double_or_none(raw) {
740
- Some(value) => value
741
- None => 0.0
742
- },
743
- ),
744
- )
745
- None => Some(expr_json_num(0.0))
746
- }
747
- "data_variable" =>
748
- if !allow_variable {
749
- None
750
- } else {
751
- match field_value(block, "VARIABLE") {
752
- Some((_, Some(id))) if id != "" =>
753
- Some(expr_json_var_num(target_index, id))
754
- _ => None
755
- }
756
- }
757
- "operator_add" =>
758
- match
759
- (
760
- compile_number_expr_from_input(
761
- target,
762
- target_index,
763
- block,
764
- "NUM1",
765
- depth + 1,
766
- allow_variable,
767
- ),
768
- compile_number_expr_from_input(
769
- target,
770
- target_index,
771
- block,
772
- "NUM2",
773
- depth + 1,
774
- allow_variable,
775
- ),
776
- ) {
777
- (Some(left), Some(right)) => Some(expr_json_bin_num("add", left, right))
778
- _ => None
779
- }
780
- "operator_subtract" =>
781
- match
782
- (
783
- compile_number_expr_from_input(
784
- target,
785
- target_index,
786
- block,
787
- "NUM1",
788
- depth + 1,
789
- allow_variable,
790
- ),
791
- compile_number_expr_from_input(
792
- target,
793
- target_index,
794
- block,
795
- "NUM2",
796
- depth + 1,
797
- allow_variable,
798
- ),
799
- ) {
800
- (Some(left), Some(right)) => Some(expr_json_bin_num("sub", left, right))
801
- _ => None
802
- }
803
- "operator_multiply" =>
804
- match
805
- (
806
- compile_number_expr_from_input(
807
- target,
808
- target_index,
809
- block,
810
- "NUM1",
811
- depth + 1,
812
- allow_variable,
813
- ),
814
- compile_number_expr_from_input(
815
- target,
816
- target_index,
817
- block,
818
- "NUM2",
819
- depth + 1,
820
- allow_variable,
821
- ),
822
- ) {
823
- (Some(left), Some(right)) => Some(expr_json_bin_num("mul", left, right))
824
- _ => None
825
- }
826
- "operator_divide" =>
827
- match
828
- (
829
- compile_number_expr_from_input(
830
- target,
831
- target_index,
832
- block,
833
- "NUM1",
834
- depth + 1,
835
- allow_variable,
836
- ),
837
- compile_number_expr_from_input(
838
- target,
839
- target_index,
840
- block,
841
- "NUM2",
842
- depth + 1,
843
- allow_variable,
844
- ),
845
- ) {
846
- (Some(left), Some(right)) => Some(expr_json_bin_num("div", left, right))
847
- _ => None
848
- }
849
- "operator_mod" =>
850
- match
851
- (
852
- compile_number_expr_from_input(
853
- target,
854
- target_index,
855
- block,
856
- "NUM1",
857
- depth + 1,
858
- allow_variable,
859
- ),
860
- compile_number_expr_from_input(
861
- target,
862
- target_index,
863
- block,
864
- "NUM2",
865
- depth + 1,
866
- allow_variable,
867
- ),
868
- ) {
869
- (Some(left), Some(right)) => Some(expr_json_bin_num("mod", left, right))
870
- _ => None
871
- }
872
- "operator_round" =>
873
- match
874
- compile_number_expr_from_input(
875
- target,
876
- target_index,
877
- block,
878
- "NUM",
879
- depth + 1,
880
- allow_variable,
881
- ) {
882
- Some(value) => Some(expr_json_unary_num("round", value))
883
- None => None
884
- }
885
- "operator_mathop" =>
886
- match
887
- (
888
- field_value(block, "OPERATOR"),
889
- compile_number_expr_from_input(
890
- target,
891
- target_index,
892
- block,
893
- "NUM",
894
- depth + 1,
895
- allow_variable,
896
- ),
897
- ) {
898
- (Some((raw_op, _)), Some(value)) =>
899
- match raw_op.trim().to_lower() {
900
- "abs" => Some(expr_json_unary_num("abs", value))
901
- "floor" => Some(expr_json_unary_num("floor", value))
902
- "ceiling" => Some(expr_json_unary_num("ceil", value))
903
- "sqrt" => Some(expr_json_unary_num("sqrt", value))
904
- "round" => Some(expr_json_unary_num("round", value))
905
- _ => None
906
- }
907
- _ => None
908
- }
909
- _ => None
910
- }
911
- }
912
-
913
- ///|
914
- fn compile_number_expr_from_input(
915
- target : TargetState,
916
- target_index : Int,
917
- block : ScratchBlock,
918
- input_name : String,
919
- depth : Int,
920
- allow_variable : Bool,
921
- ) -> Json? {
922
- if depth > 64 {
923
- return None
924
- }
925
- match resolve_reporter_block_id(block, input_name) {
926
- Some(block_id) =>
927
- compile_number_expr_from_block(
928
- target,
929
- target_index,
930
- block_id,
931
- depth + 1,
932
- allow_variable,
933
- )
934
- None =>
935
- match block.inputs.get(input_name) {
936
- Some(raw_input) =>
937
- match input_payload(raw_input) {
938
- Some(payload) =>
939
- compile_number_expr_from_payload(
940
- target_index, payload, allow_variable,
941
- )
942
- None => Some(expr_json_num(0.0))
943
- }
944
- None => Some(expr_json_num(0.0))
945
- }
946
- }
947
- }
948
-
949
- ///|
950
- fn compile_bool_expr_from_block(
951
- target : TargetState,
952
- target_index : Int,
953
- block_id : String,
954
- depth : Int,
955
- variable_numeric_by_id : Map[String, Bool],
956
- ) -> Json? {
957
- if depth > 64 {
958
- return None
959
- }
960
- let block = match target.blocks.get(block_id) {
961
- Some(value) => value
962
- None => return None
963
- }
964
- match block.opcode {
965
- "operator_lt" =>
966
- match
967
- (
968
- compile_number_expr_from_input(
969
- target,
970
- target_index,
971
- block,
972
- "OPERAND1",
973
- depth + 1,
974
- true,
975
- ),
976
- compile_number_expr_from_input(
977
- target,
978
- target_index,
979
- block,
980
- "OPERAND2",
981
- depth + 1,
982
- true,
983
- ),
984
- ) {
985
- (Some(left), Some(right)) =>
986
- if number_expr_uses_only_numeric_variables(
987
- left, variable_numeric_by_id, 0,
988
- ) &&
989
- number_expr_uses_only_numeric_variables(
990
- right, variable_numeric_by_id, 0,
991
- ) {
992
- Some(expr_json_cmp_num("lt", left, right))
993
- } else {
994
- None
995
- }
996
- _ => None
997
- }
998
- "operator_gt" =>
999
- match
1000
- (
1001
- compile_number_expr_from_input(
1002
- target,
1003
- target_index,
1004
- block,
1005
- "OPERAND1",
1006
- depth + 1,
1007
- true,
1008
- ),
1009
- compile_number_expr_from_input(
1010
- target,
1011
- target_index,
1012
- block,
1013
- "OPERAND2",
1014
- depth + 1,
1015
- true,
1016
- ),
1017
- ) {
1018
- (Some(left), Some(right)) =>
1019
- if number_expr_uses_only_numeric_variables(
1020
- left, variable_numeric_by_id, 0,
1021
- ) &&
1022
- number_expr_uses_only_numeric_variables(
1023
- right, variable_numeric_by_id, 0,
1024
- ) {
1025
- Some(expr_json_cmp_num("gt", left, right))
1026
- } else {
1027
- None
1028
- }
1029
- _ => None
1030
- }
1031
- "operator_equals" =>
1032
- match
1033
- (
1034
- compile_number_expr_from_input(
1035
- target,
1036
- target_index,
1037
- block,
1038
- "OPERAND1",
1039
- depth + 1,
1040
- true,
1041
- ),
1042
- compile_number_expr_from_input(
1043
- target,
1044
- target_index,
1045
- block,
1046
- "OPERAND2",
1047
- depth + 1,
1048
- true,
1049
- ),
1050
- ) {
1051
- (Some(left), Some(right)) =>
1052
- if number_expr_uses_only_numeric_variables(
1053
- left, variable_numeric_by_id, 0,
1054
- ) &&
1055
- number_expr_uses_only_numeric_variables(
1056
- right, variable_numeric_by_id, 0,
1057
- ) {
1058
- Some(expr_json_cmp_num("eq", left, right))
1059
- } else {
1060
- None
1061
- }
1062
- _ => None
1063
- }
1064
- "operator_and" =>
1065
- match
1066
- (
1067
- compile_bool_expr_from_input(
1068
- target,
1069
- target_index,
1070
- block,
1071
- "OPERAND1",
1072
- depth + 1,
1073
- variable_numeric_by_id,
1074
- ),
1075
- compile_bool_expr_from_input(
1076
- target,
1077
- target_index,
1078
- block,
1079
- "OPERAND2",
1080
- depth + 1,
1081
- variable_numeric_by_id,
1082
- ),
1083
- ) {
1084
- (Some(left), Some(right)) =>
1085
- Some(expr_json_bin_bool("and", left, right))
1086
- _ => None
1087
- }
1088
- "operator_or" =>
1089
- match
1090
- (
1091
- compile_bool_expr_from_input(
1092
- target,
1093
- target_index,
1094
- block,
1095
- "OPERAND1",
1096
- depth + 1,
1097
- variable_numeric_by_id,
1098
- ),
1099
- compile_bool_expr_from_input(
1100
- target,
1101
- target_index,
1102
- block,
1103
- "OPERAND2",
1104
- depth + 1,
1105
- variable_numeric_by_id,
1106
- ),
1107
- ) {
1108
- (Some(left), Some(right)) => Some(expr_json_bin_bool("or", left, right))
1109
- _ => None
1110
- }
1111
- "operator_not" =>
1112
- match
1113
- compile_bool_expr_from_input(
1114
- target,
1115
- target_index,
1116
- block,
1117
- "OPERAND",
1118
- depth + 1,
1119
- variable_numeric_by_id,
1120
- ) {
1121
- Some(value) => Some(expr_json_not(value))
1122
- None => None
1123
- }
1124
- _ =>
1125
- match
1126
- compile_number_expr_from_block(
1127
- target,
1128
- target_index,
1129
- block_id,
1130
- depth + 1,
1131
- true,
1132
- ) {
1133
- Some(num_expr) => Some(expr_json_bool_from_number(num_expr))
1134
- None => None
1135
- }
1136
- }
1137
- }
1138
-
1139
- ///|
1140
- fn compile_bool_expr_from_input(
1141
- target : TargetState,
1142
- target_index : Int,
1143
- block : ScratchBlock,
1144
- input_name : String,
1145
- depth : Int,
1146
- variable_numeric_by_id : Map[String, Bool],
1147
- ) -> Json? {
1148
- if depth > 64 {
1149
- return None
1150
- }
1151
- match resolve_reporter_block_id(block, input_name) {
1152
- Some(block_id) =>
1153
- compile_bool_expr_from_block(
1154
- target,
1155
- target_index,
1156
- block_id,
1157
- depth + 1,
1158
- variable_numeric_by_id,
1159
- )
1160
- None =>
1161
- match block.inputs.get(input_name) {
1162
- Some(raw_input) =>
1163
- match input_payload(raw_input) {
1164
- Some(payload) =>
1165
- compile_bool_expr_from_payload(target_index, payload)
1166
- None => Some(expr_json_bool(false))
1167
- }
1168
- None => Some(expr_json_bool(false))
1169
- }
1170
- }
1171
- }
1172
-
1173
- ///|
1174
- fn compile_sequence_from_pc(
1175
- target : TargetState,
1176
- target_index : Int,
1177
- start_pc : Int?,
1178
- depth : Int,
1179
- variable_numeric_by_id : Map[String, Bool],
1180
- ) -> Array[Json]? {
1181
- if depth > 96 {
1182
- return None
1183
- }
1184
- let out = []
1185
- let mut cursor = start_pc
1186
- let mut steps = 0
1187
- while true {
1188
- match cursor {
1189
- Some(pc) => {
1190
- if pc < 0 || pc >= target.blocks_by_pc.length() {
1191
- return None
1192
- }
1193
- if steps > target.blocks_by_pc.length() * 4 {
1194
- return None
1195
- }
1196
- steps += 1
1197
- let block = target.blocks_by_pc[pc]
1198
- let fast_meta = target.block_fast_meta_by_pc[pc]
1199
- let host_fallback_stmt = opcode_fallback_stmt(
1200
- block.opcode,
1201
- target_index,
1202
- pc,
1203
- )
1204
- let host_tail_stmt = AotCompileStmtResult::EmitAndStop(
1205
- command_json_host_tail(target_index, pc),
1206
- )
1207
- let stmt = match block.opcode {
1208
- "event_whenflagclicked" => AotCompileStmtResult::Noop
1209
- "data_setvariableto" =>
1210
- match variable_id_from_field(block) {
1211
- Some(variable_id) =>
1212
- match literal_value_from_input(block, "VALUE") {
1213
- Some(value) =>
1214
- match json_finite_number_or_none(value) {
1215
- Some(number_value) =>
1216
- AotCompileStmtResult::Emit(
1217
- command_json_set_var_num_expr(
1218
- target_index,
1219
- variable_id,
1220
- expr_json_num(number_value),
1221
- ),
1222
- )
1223
- None =>
1224
- AotCompileStmtResult::Emit(
1225
- command_json_set_var_json_const(
1226
- target_index, variable_id, value,
1227
- ),
1228
- )
1229
- }
1230
- None =>
1231
- match
1232
- compile_number_expr_from_input(
1233
- target,
1234
- target_index,
1235
- block,
1236
- "VALUE",
1237
- depth + 1,
1238
- true,
1239
- ) {
1240
- Some(expr) =>
1241
- AotCompileStmtResult::Emit(
1242
- command_json_set_var_num_expr(
1243
- target_index, variable_id, expr,
1244
- ),
1245
- )
1246
- None => host_fallback_stmt
1247
- }
1248
- }
1249
- None => host_fallback_stmt
1250
- }
1251
- "data_changevariableby" =>
1252
- match variable_id_from_field(block) {
1253
- Some(variable_id) =>
1254
- match
1255
- compile_number_expr_from_input(
1256
- target,
1257
- target_index,
1258
- block,
1259
- "VALUE",
1260
- depth + 1,
1261
- true,
1262
- ) {
1263
- Some(expr) =>
1264
- AotCompileStmtResult::Emit(
1265
- command_json_change_var_num_expr(
1266
- target_index, variable_id, expr,
1267
- ),
1268
- )
1269
- None => host_fallback_stmt
1270
- }
1271
- None => host_fallback_stmt
1272
- }
1273
- "motion_movesteps" =>
1274
- match
1275
- compile_number_expr_from_input(
1276
- target,
1277
- target_index,
1278
- block,
1279
- "STEPS",
1280
- depth + 1,
1281
- true,
1282
- ) {
1283
- Some(steps_expr) =>
1284
- AotCompileStmtResult::Emit(
1285
- command_json_draw_opcode(
1286
- target_index,
1287
- "motion_movesteps",
1288
- steps_expr,
1289
- expr_json_num(0.0),
1290
- 0,
1291
- ),
1292
- )
1293
- None => host_fallback_stmt
1294
- }
1295
- "motion_turnright" =>
1296
- match
1297
- compile_number_expr_from_input(
1298
- target,
1299
- target_index,
1300
- block,
1301
- "DEGREES",
1302
- depth + 1,
1303
- true,
1304
- ) {
1305
- Some(degrees_expr) =>
1306
- AotCompileStmtResult::Emit(
1307
- command_json_draw_opcode(
1308
- target_index,
1309
- "motion_turnright",
1310
- degrees_expr,
1311
- expr_json_num(0.0),
1312
- 0,
1313
- ),
1314
- )
1315
- None => host_fallback_stmt
1316
- }
1317
- "motion_turnleft" =>
1318
- match
1319
- compile_number_expr_from_input(
1320
- target,
1321
- target_index,
1322
- block,
1323
- "DEGREES",
1324
- depth + 1,
1325
- true,
1326
- ) {
1327
- Some(degrees_expr) =>
1328
- AotCompileStmtResult::Emit(
1329
- command_json_draw_opcode(
1330
- target_index,
1331
- "motion_turnleft",
1332
- degrees_expr,
1333
- expr_json_num(0.0),
1334
- 0,
1335
- ),
1336
- )
1337
- None => host_fallback_stmt
1338
- }
1339
- "motion_pointindirection" =>
1340
- match
1341
- compile_number_expr_from_input(
1342
- target,
1343
- target_index,
1344
- block,
1345
- "DIRECTION",
1346
- depth + 1,
1347
- true,
1348
- ) {
1349
- Some(direction_expr) =>
1350
- AotCompileStmtResult::Emit(
1351
- command_json_draw_opcode(
1352
- target_index,
1353
- "motion_pointindirection",
1354
- direction_expr,
1355
- expr_json_num(0.0),
1356
- 0,
1357
- ),
1358
- )
1359
- None => host_fallback_stmt
1360
- }
1361
- "motion_changexby" =>
1362
- match
1363
- compile_number_expr_from_input(
1364
- target,
1365
- target_index,
1366
- block,
1367
- "DX",
1368
- depth + 1,
1369
- true,
1370
- ) {
1371
- Some(dx_expr) =>
1372
- AotCompileStmtResult::Emit(
1373
- command_json_draw_opcode(
1374
- target_index,
1375
- "motion_changexby",
1376
- dx_expr,
1377
- expr_json_num(0.0),
1378
- 0,
1379
- ),
1380
- )
1381
- None => host_fallback_stmt
1382
- }
1383
- "motion_changeyby" =>
1384
- match
1385
- compile_number_expr_from_input(
1386
- target,
1387
- target_index,
1388
- block,
1389
- "DY",
1390
- depth + 1,
1391
- true,
1392
- ) {
1393
- Some(dy_expr) =>
1394
- AotCompileStmtResult::Emit(
1395
- command_json_draw_opcode(
1396
- target_index,
1397
- "motion_changeyby",
1398
- dy_expr,
1399
- expr_json_num(0.0),
1400
- 0,
1401
- ),
1402
- )
1403
- None => host_fallback_stmt
1404
- }
1405
- "motion_setx" =>
1406
- match
1407
- compile_number_expr_from_input(
1408
- target,
1409
- target_index,
1410
- block,
1411
- "X",
1412
- depth + 1,
1413
- true,
1414
- ) {
1415
- Some(x_expr) =>
1416
- AotCompileStmtResult::Emit(
1417
- command_json_draw_opcode(
1418
- target_index,
1419
- "motion_setx",
1420
- x_expr,
1421
- expr_json_num(0.0),
1422
- 0,
1423
- ),
1424
- )
1425
- None => host_fallback_stmt
1426
- }
1427
- "motion_sety" =>
1428
- match
1429
- compile_number_expr_from_input(
1430
- target,
1431
- target_index,
1432
- block,
1433
- "Y",
1434
- depth + 1,
1435
- true,
1436
- ) {
1437
- Some(y_expr) =>
1438
- AotCompileStmtResult::Emit(
1439
- command_json_draw_opcode(
1440
- target_index,
1441
- "motion_sety",
1442
- y_expr,
1443
- expr_json_num(0.0),
1444
- 0,
1445
- ),
1446
- )
1447
- None => host_fallback_stmt
1448
- }
1449
- "motion_gotoxy" =>
1450
- match
1451
- (
1452
- compile_number_expr_from_input(
1453
- target,
1454
- target_index,
1455
- block,
1456
- "X",
1457
- depth + 1,
1458
- true,
1459
- ),
1460
- compile_number_expr_from_input(
1461
- target,
1462
- target_index,
1463
- block,
1464
- "Y",
1465
- depth + 1,
1466
- true,
1467
- ),
1468
- ) {
1469
- (Some(x_expr), Some(y_expr)) =>
1470
- AotCompileStmtResult::Emit(
1471
- command_json_draw_opcode(
1472
- target_index, "motion_gotoxy", x_expr, y_expr, 0,
1473
- ),
1474
- )
1475
- _ => host_fallback_stmt
1476
- }
1477
- "motion_ifonedgebounce" =>
1478
- AotCompileStmtResult::Emit(
1479
- command_json_draw_opcode(
1480
- target_index,
1481
- "motion_ifonedgebounce",
1482
- expr_json_num(0.0),
1483
- expr_json_num(0.0),
1484
- 0,
1485
- ),
1486
- )
1487
- "looks_show" =>
1488
- AotCompileStmtResult::Emit(
1489
- command_json_draw_opcode(
1490
- target_index,
1491
- "looks_show",
1492
- expr_json_num(0.0),
1493
- expr_json_num(0.0),
1494
- 0,
1495
- ),
1496
- )
1497
- "looks_hide" =>
1498
- AotCompileStmtResult::Emit(
1499
- command_json_draw_opcode(
1500
- target_index,
1501
- "looks_hide",
1502
- expr_json_num(0.0),
1503
- expr_json_num(0.0),
1504
- 0,
1505
- ),
1506
- )
1507
- "looks_hideallsprites" =>
1508
- AotCompileStmtResult::Emit(
1509
- command_json_draw_opcode(
1510
- target_index,
1511
- "looks_hideallsprites",
1512
- expr_json_num(0.0),
1513
- expr_json_num(0.0),
1514
- 0,
1515
- ),
1516
- )
1517
- "looks_nextcostume" =>
1518
- AotCompileStmtResult::Emit(
1519
- command_json_draw_opcode(
1520
- target_index,
1521
- "looks_nextcostume",
1522
- expr_json_num(0.0),
1523
- expr_json_num(0.0),
1524
- 0,
1525
- ),
1526
- )
1527
- "looks_changesizeby" =>
1528
- match
1529
- compile_number_expr_from_input(
1530
- target,
1531
- target_index,
1532
- block,
1533
- "CHANGE",
1534
- depth + 1,
1535
- true,
1536
- ) {
1537
- Some(delta_expr) =>
1538
- AotCompileStmtResult::Emit(
1539
- command_json_draw_opcode(
1540
- target_index,
1541
- "looks_changesizeby",
1542
- delta_expr,
1543
- expr_json_num(0.0),
1544
- 0,
1545
- ),
1546
- )
1547
- None => host_fallback_stmt
1548
- }
1549
- "looks_setsizeto" =>
1550
- match
1551
- compile_number_expr_from_input(
1552
- target,
1553
- target_index,
1554
- block,
1555
- "SIZE",
1556
- depth + 1,
1557
- true,
1558
- ) {
1559
- Some(size_expr) =>
1560
- AotCompileStmtResult::Emit(
1561
- command_json_draw_opcode(
1562
- target_index,
1563
- "looks_setsizeto",
1564
- size_expr,
1565
- expr_json_num(0.0),
1566
- 0,
1567
- ),
1568
- )
1569
- None => host_fallback_stmt
1570
- }
1571
- "looks_changeeffectby" =>
1572
- match
1573
- (
1574
- literal_string_from_input_or_field(block, "EFFECT", "EFFECT"),
1575
- compile_number_expr_from_input(
1576
- target,
1577
- target_index,
1578
- block,
1579
- "CHANGE",
1580
- depth + 1,
1581
- true,
1582
- ),
1583
- ) {
1584
- (Some(effect_name), Some(amount_expr)) =>
1585
- match normalize_looks_effect_name_for_draw(effect_name) {
1586
- Some(effect_id) =>
1587
- AotCompileStmtResult::Emit(
1588
- command_json_draw_opcode(
1589
- target_index,
1590
- "looks_changeeffectby",
1591
- amount_expr,
1592
- expr_json_num(0.0),
1593
- effect_id,
1594
- ),
1595
- )
1596
- None => host_fallback_stmt
1597
- }
1598
- _ => host_fallback_stmt
1599
- }
1600
- "looks_seteffectto" =>
1601
- match
1602
- (
1603
- literal_string_from_input_or_field(block, "EFFECT", "EFFECT"),
1604
- compile_number_expr_from_input(
1605
- target,
1606
- target_index,
1607
- block,
1608
- "VALUE",
1609
- depth + 1,
1610
- true,
1611
- ),
1612
- ) {
1613
- (Some(effect_name), Some(amount_expr)) =>
1614
- match normalize_looks_effect_name_for_draw(effect_name) {
1615
- Some(effect_id) =>
1616
- AotCompileStmtResult::Emit(
1617
- command_json_draw_opcode(
1618
- target_index,
1619
- "looks_seteffectto",
1620
- amount_expr,
1621
- expr_json_num(0.0),
1622
- effect_id,
1623
- ),
1624
- )
1625
- None => host_fallback_stmt
1626
- }
1627
- _ => host_fallback_stmt
1628
- }
1629
- "looks_cleargraphiceffects" =>
1630
- AotCompileStmtResult::Emit(
1631
- command_json_draw_opcode(
1632
- target_index,
1633
- "looks_cleargraphiceffects",
1634
- expr_json_num(0.0),
1635
- expr_json_num(0.0),
1636
- 0,
1637
- ),
1638
- )
1639
- "pen_clear" =>
1640
- AotCompileStmtResult::Emit(
1641
- command_json_draw_opcode(
1642
- target_index,
1643
- "pen_clear",
1644
- expr_json_num(0.0),
1645
- expr_json_num(0.0),
1646
- 0,
1647
- ),
1648
- )
1649
- "pen_stamp" =>
1650
- AotCompileStmtResult::Emit(
1651
- command_json_draw_opcode(
1652
- target_index,
1653
- "pen_stamp",
1654
- expr_json_num(0.0),
1655
- expr_json_num(0.0),
1656
- 0,
1657
- ),
1658
- )
1659
- "pen_penDown" =>
1660
- AotCompileStmtResult::Emit(
1661
- command_json_draw_opcode(
1662
- target_index,
1663
- "pen_penDown",
1664
- expr_json_num(0.0),
1665
- expr_json_num(0.0),
1666
- 0,
1667
- ),
1668
- )
1669
- "pen_penUp" =>
1670
- AotCompileStmtResult::Emit(
1671
- command_json_draw_opcode(
1672
- target_index,
1673
- "pen_penUp",
1674
- expr_json_num(0.0),
1675
- expr_json_num(0.0),
1676
- 0,
1677
- ),
1678
- )
1679
- "pen_changePenColorParamBy" =>
1680
- match
1681
- (
1682
- literal_string_from_input_or_field(
1683
- block, "COLOR_PARAM", "COLOR_PARAM",
1684
- ),
1685
- compile_number_expr_from_input(
1686
- target,
1687
- target_index,
1688
- block,
1689
- "VALUE",
1690
- depth + 1,
1691
- true,
1692
- ),
1693
- ) {
1694
- (Some(param_name), Some(value_expr)) =>
1695
- match normalize_pen_color_param_for_draw(param_name) {
1696
- Some(param_id) =>
1697
- AotCompileStmtResult::Emit(
1698
- command_json_draw_opcode(
1699
- target_index,
1700
- "pen_changePenColorParamBy",
1701
- value_expr,
1702
- expr_json_num(0.0),
1703
- param_id,
1704
- ),
1705
- )
1706
- None => host_fallback_stmt
1707
- }
1708
- _ => host_fallback_stmt
1709
- }
1710
- "pen_setPenColorParamTo" =>
1711
- match
1712
- (
1713
- literal_string_from_input_or_field(
1714
- block, "COLOR_PARAM", "COLOR_PARAM",
1715
- ),
1716
- compile_number_expr_from_input(
1717
- target,
1718
- target_index,
1719
- block,
1720
- "VALUE",
1721
- depth + 1,
1722
- true,
1723
- ),
1724
- ) {
1725
- (Some(param_name), Some(value_expr)) =>
1726
- match normalize_pen_color_param_for_draw(param_name) {
1727
- Some(param_id) =>
1728
- AotCompileStmtResult::Emit(
1729
- command_json_draw_opcode(
1730
- target_index,
1731
- "pen_setPenColorParamTo",
1732
- value_expr,
1733
- expr_json_num(0.0),
1734
- param_id,
1735
- ),
1736
- )
1737
- None => host_fallback_stmt
1738
- }
1739
- _ => host_fallback_stmt
1740
- }
1741
- "pen_changePenSizeBy" =>
1742
- match
1743
- compile_number_expr_from_input(
1744
- target,
1745
- target_index,
1746
- block,
1747
- "SIZE",
1748
- depth + 1,
1749
- true,
1750
- ) {
1751
- Some(delta_expr) =>
1752
- AotCompileStmtResult::Emit(
1753
- command_json_draw_opcode(
1754
- target_index,
1755
- "pen_changePenSizeBy",
1756
- delta_expr,
1757
- expr_json_num(0.0),
1758
- 0,
1759
- ),
1760
- )
1761
- None => host_fallback_stmt
1762
- }
1763
- "pen_setPenSizeTo" =>
1764
- match
1765
- compile_number_expr_from_input(
1766
- target,
1767
- target_index,
1768
- block,
1769
- "SIZE",
1770
- depth + 1,
1771
- true,
1772
- ) {
1773
- Some(size_expr) =>
1774
- AotCompileStmtResult::Emit(
1775
- command_json_draw_opcode(
1776
- target_index,
1777
- "pen_setPenSizeTo",
1778
- size_expr,
1779
- expr_json_num(0.0),
1780
- 0,
1781
- ),
1782
- )
1783
- None => host_fallback_stmt
1784
- }
1785
- "pen_setPenHueToNumber" =>
1786
- match
1787
- compile_number_expr_from_input(
1788
- target,
1789
- target_index,
1790
- block,
1791
- "HUE",
1792
- depth + 1,
1793
- true,
1794
- ) {
1795
- Some(hue_expr) =>
1796
- AotCompileStmtResult::Emit(
1797
- command_json_draw_opcode(
1798
- target_index,
1799
- "pen_setPenHueToNumber",
1800
- hue_expr,
1801
- expr_json_num(0.0),
1802
- 0,
1803
- ),
1804
- )
1805
- None => host_fallback_stmt
1806
- }
1807
- "pen_changePenHueBy" =>
1808
- match
1809
- compile_number_expr_from_input(
1810
- target,
1811
- target_index,
1812
- block,
1813
- "HUE",
1814
- depth + 1,
1815
- true,
1816
- ) {
1817
- Some(hue_expr) =>
1818
- AotCompileStmtResult::Emit(
1819
- command_json_draw_opcode(
1820
- target_index,
1821
- "pen_changePenHueBy",
1822
- hue_expr,
1823
- expr_json_num(0.0),
1824
- 0,
1825
- ),
1826
- )
1827
- None => host_fallback_stmt
1828
- }
1829
- "pen_setPenShadeToNumber" =>
1830
- match
1831
- compile_number_expr_from_input(
1832
- target,
1833
- target_index,
1834
- block,
1835
- "SHADE",
1836
- depth + 1,
1837
- true,
1838
- ) {
1839
- Some(shade_expr) =>
1840
- AotCompileStmtResult::Emit(
1841
- command_json_draw_opcode(
1842
- target_index,
1843
- "pen_setPenShadeToNumber",
1844
- shade_expr,
1845
- expr_json_num(0.0),
1846
- 0,
1847
- ),
1848
- )
1849
- None => host_fallback_stmt
1850
- }
1851
- "pen_changePenShadeBy" =>
1852
- match
1853
- compile_number_expr_from_input(
1854
- target,
1855
- target_index,
1856
- block,
1857
- "SHADE",
1858
- depth + 1,
1859
- true,
1860
- ) {
1861
- Some(shade_expr) =>
1862
- AotCompileStmtResult::Emit(
1863
- command_json_draw_opcode(
1864
- target_index,
1865
- "pen_changePenShadeBy",
1866
- shade_expr,
1867
- expr_json_num(0.0),
1868
- 0,
1869
- ),
1870
- )
1871
- None => host_fallback_stmt
1872
- }
1873
- "control_if" =>
1874
- match
1875
- (
1876
- compile_bool_expr_from_input(
1877
- target,
1878
- target_index,
1879
- block,
1880
- "CONDITION",
1881
- depth + 1,
1882
- variable_numeric_by_id,
1883
- ),
1884
- compile_sequence_from_pc(
1885
- target,
1886
- target_index,
1887
- fast_meta.substack_pc,
1888
- depth + 1,
1889
- variable_numeric_by_id,
1890
- ),
1891
- ) {
1892
- (Some(cond), Some(body)) =>
1893
- if command_list_contains_host_tail(body) {
1894
- host_tail_stmt
1895
- } else {
1896
- AotCompileStmtResult::Emit(command_json_if(cond, body))
1897
- }
1898
- _ => host_fallback_stmt
1899
- }
1900
- "control_if_else" =>
1901
- match
1902
- (
1903
- compile_bool_expr_from_input(
1904
- target,
1905
- target_index,
1906
- block,
1907
- "CONDITION",
1908
- depth + 1,
1909
- variable_numeric_by_id,
1910
- ),
1911
- compile_sequence_from_pc(
1912
- target,
1913
- target_index,
1914
- fast_meta.substack_pc,
1915
- depth + 1,
1916
- variable_numeric_by_id,
1917
- ),
1918
- compile_sequence_from_pc(
1919
- target,
1920
- target_index,
1921
- fast_meta.substack2_pc,
1922
- depth + 1,
1923
- variable_numeric_by_id,
1924
- ),
1925
- ) {
1926
- (Some(cond), Some(then_body), Some(else_body)) =>
1927
- if command_list_contains_host_tail(then_body) ||
1928
- command_list_contains_host_tail(else_body) {
1929
- host_tail_stmt
1930
- } else {
1931
- AotCompileStmtResult::Emit(
1932
- command_json_if_else(cond, then_body, else_body),
1933
- )
1934
- }
1935
- _ => host_fallback_stmt
1936
- }
1937
- "control_repeat" =>
1938
- match
1939
- (
1940
- compile_number_expr_from_input(
1941
- target,
1942
- target_index,
1943
- block,
1944
- "TIMES",
1945
- depth + 1,
1946
- true,
1947
- ),
1948
- compile_sequence_from_pc(
1949
- target,
1950
- target_index,
1951
- fast_meta.substack_pc,
1952
- depth + 1,
1953
- variable_numeric_by_id,
1954
- ),
1955
- ) {
1956
- (Some(times), Some(body)) =>
1957
- if command_list_contains_host_tail(body) {
1958
- host_tail_stmt
1959
- } else {
1960
- AotCompileStmtResult::Emit(command_json_repeat(times, body))
1961
- }
1962
- _ => host_fallback_stmt
1963
- }
1964
- "control_repeat_until" =>
1965
- match
1966
- (
1967
- compile_bool_expr_from_input(
1968
- target,
1969
- target_index,
1970
- block,
1971
- "CONDITION",
1972
- depth + 1,
1973
- variable_numeric_by_id,
1974
- ),
1975
- compile_sequence_from_pc(
1976
- target,
1977
- target_index,
1978
- fast_meta.substack_pc,
1979
- depth + 1,
1980
- variable_numeric_by_id,
1981
- ),
1982
- ) {
1983
- (Some(cond), Some(body)) =>
1984
- if command_list_contains_host_tail(body) {
1985
- host_tail_stmt
1986
- } else {
1987
- AotCompileStmtResult::Emit(
1988
- command_json_repeat_until(cond, body),
1989
- )
1990
- }
1991
- _ => host_fallback_stmt
1992
- }
1993
- "control_while" =>
1994
- match
1995
- (
1996
- compile_bool_expr_from_input(
1997
- target,
1998
- target_index,
1999
- block,
2000
- "CONDITION",
2001
- depth + 1,
2002
- variable_numeric_by_id,
2003
- ),
2004
- compile_sequence_from_pc(
2005
- target,
2006
- target_index,
2007
- fast_meta.substack_pc,
2008
- depth + 1,
2009
- variable_numeric_by_id,
2010
- ),
2011
- ) {
2012
- (Some(cond), Some(body)) =>
2013
- if command_list_contains_host_tail(body) {
2014
- host_tail_stmt
2015
- } else {
2016
- AotCompileStmtResult::Emit(command_json_while(cond, body))
2017
- }
2018
- _ => host_fallback_stmt
2019
- }
2020
- _ => host_fallback_stmt
2021
- }
2022
- match stmt {
2023
- AotCompileStmtResult::Noop => ()
2024
- AotCompileStmtResult::Emit(command) => out.push(command)
2025
- AotCompileStmtResult::EmitAndStop(command) => {
2026
- out.push(command)
2027
- return Some(out)
2028
- }
2029
- }
2030
- cursor = fast_meta.next_pc
2031
- }
2032
- None => break
2033
- }
2034
- }
2035
- Some(out)
2036
- }
2037
-
2038
- ///|
2039
- fn append_compiled_green_flag_commands(
2040
- target : TargetState,
2041
- target_index : Int,
2042
- variable_numeric_by_id : Map[String, Bool],
2043
- out : Array[Json],
2044
- ) -> Bool {
2045
- for start_id in target.green_flag_starts {
2046
- let start_pc = match target.block_pc_by_id.get(start_id) {
2047
- Some(pc) => Some(pc)
2048
- None => return false
2049
- }
2050
- let commands = match
2051
- compile_sequence_from_pc(
2052
- target, target_index, start_pc, 0, variable_numeric_by_id,
2053
- ) {
2054
- Some(value) => value
2055
- None => return false
2056
- }
2057
- for command in commands {
2058
- out.push(command)
2059
- }
2060
- }
2061
- true
2062
- }
2063
-
2064
- ///|
2065
- fn compile_aot_full_green_flag_starts_json(
2066
- targets : Array[TargetState],
2067
- ) -> (Array[Json], Bool) {
2068
- let starts = []
2069
- let mut has_any_start = false
2070
- for target_index, target in targets {
2071
- let pcs = []
2072
- for start_id in target.green_flag_starts {
2073
- match target.block_pc_by_id.get(start_id) {
2074
- Some(pc) => pcs.push(pc)
2075
- None => ()
2076
- }
2077
- }
2078
- if !pcs.is_empty() {
2079
- starts.push(command_json_full_green_flag_start_entry(target_index, pcs))
2080
- has_any_start = true
2081
- }
2082
- }
2083
- (starts, has_any_start)
2084
- }
2085
-
2086
- ///|
2087
- fn compile_aot_commands_json(targets : Array[TargetState]) -> String? {
2088
- let commands = []
2089
- let variable_numeric_by_id = build_aot_variable_numeric_map(targets)
2090
- for target_index, target in targets {
2091
- if !target_is_aot_eligible(target) {
2092
- commands.clear()
2093
- break
2094
- }
2095
- if !append_compiled_green_flag_commands(
2096
- target, target_index, variable_numeric_by_id, commands,
2097
- ) {
2098
- commands.clear()
2099
- break
2100
- }
2101
- }
2102
- let opcode_catalog = []
2103
- for target_index, target in targets {
2104
- for pc, block in target.blocks_by_pc {
2105
- opcode_catalog.push(
2106
- command_json_opcode_catalog(
2107
- target_index,
2108
- pc,
2109
- block,
2110
- target.block_fast_meta_by_pc[pc],
2111
- ),
2112
- )
2113
- }
2114
- }
2115
- let (full_green_flag_starts, has_any_start) = compile_aot_full_green_flag_starts_json(
2116
- targets,
2117
- )
2118
- let exec_mode = if !commands.is_empty() {
2119
- "linear"
2120
- } else if has_any_start {
2121
- "full"
2122
- } else {
2123
- "linear"
2124
- }
2125
- Some(
2126
- json_object({
2127
- "exec": json_array(commands),
2128
- "exec_mode": json_string(exec_mode),
2129
- "full_green_flag_starts": json_array(full_green_flag_starts),
2130
- "catalog": json_array(opcode_catalog),
2131
- }).stringify(),
2132
- )
2133
- }
2134
-
2135
- ///|
2136
- fn program_wat_from_payload(
2137
- project_base64 : String,
2138
- assets_base64 : String,
2139
- commands_base64 : String,
2140
- ) -> String {
2141
- let project_len = project_base64.length()
2142
- let assets_offset = project_len
2143
- let assets_len = assets_base64.length()
2144
- let commands_offset = assets_offset + assets_len
2145
- let commands_len = commands_base64.length()
2146
- let memory_pages = page_count_for_bytes(
2147
- project_len + assets_len + commands_len,
2148
- )
2149
- (
2150
- $|;; moonscratch_program_v1
2151
- $|;; abi_version=\{PROGRAM_ABI_VERSION}
2152
- $|;; project_base64=\{project_base64}
2153
- $|;; assets_base64=\{assets_base64}
2154
- $|;; commands_base64=\{commands_base64}
2155
- $|(module
2156
- $| (memory (export "memory") \{memory_pages})
2157
- $| (data (i32.const 0) "\{project_base64}")
2158
- $| (data (i32.const \{assets_offset}) "\{assets_base64}")
2159
- $| (data (i32.const \{commands_offset}) "\{commands_base64}")
2160
- $| (func (export "ms_abi_version") (result i32)
2161
- $| i32.const \{PROGRAM_ABI_VERSION}
2162
- $| )
2163
- $| (func (export "ms_project_ptr") (result i32)
2164
- $| i32.const 0
2165
- $| )
2166
- $| (func (export "ms_project_len") (result i32)
2167
- $| i32.const \{project_len}
2168
- $| )
2169
- $| (func (export "ms_assets_ptr") (result i32)
2170
- $| i32.const \{assets_offset}
2171
- $| )
2172
- $| (func (export "ms_assets_len") (result i32)
2173
- $| i32.const \{assets_len}
2174
- $| )
2175
- $| (func (export "ms_commands_ptr") (result i32)
2176
- $| i32.const \{commands_offset}
2177
- $| )
2178
- $| (func (export "ms_commands_len") (result i32)
2179
- $| i32.const \{commands_len}
2180
- $| )
2181
- $|)
2182
- $|
2183
- )
2184
- }
2185
-
2186
- ///|
2187
- pub fn vm_abi_version() -> Int {
2188
- PROGRAM_ABI_VERSION
2189
- }
2190
-
2191
- ///|
2192
- pub fn vm_compile_project_to_wat(
2193
- project_json : String,
2194
- assets_json? : String,
2195
- ) -> String raise VmError {
2196
- let bundle = parse_bundle(project_json, assets_json)
2197
- let (targets, _) = parse_project_targets(bundle.project_json, bundle.assets)
2198
- let project_base64 = base64_utf8(bundle.project_json)
2199
- let assets_raw = json_object(bundle.assets).stringify()
2200
- let assets_base64 = base64_utf8(assets_raw)
2201
- let commands_base64 = match compile_aot_commands_json(targets) {
2202
- Some(commands_json) => base64_utf8(commands_json)
2203
- None => ""
2204
- }
2205
- program_wat_from_payload(project_base64, assets_base64, commands_base64)
2206
- }