moonscratch 0.1.0-alpha.0
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.
- package/.agents/skills/moonbit-agent-guide/LICENSE +202 -0
- package/.agents/skills/moonbit-agent-guide/SKILL.mbt.md +1126 -0
- package/.agents/skills/moonbit-agent-guide/SKILL.md +1126 -0
- package/.agents/skills/moonbit-agent-guide/ide.md +116 -0
- package/.agents/skills/moonbit-agent-guide/references/advanced-moonbit-build.md +106 -0
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.mbt.md +422 -0
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.md +422 -0
- package/.agents/skills/moonbit-practice/SKILL.md +258 -0
- package/.agents/skills/moonbit-practice/assets/ci.yaml +25 -0
- package/.agents/skills/moonbit-practice/reference/agents.md +1469 -0
- package/.agents/skills/moonbit-practice/reference/configuration.md +228 -0
- package/.agents/skills/moonbit-practice/reference/ffi.md +229 -0
- package/.agents/skills/moonbit-practice/reference/ide.md +189 -0
- package/.agents/skills/moonbit-practice/reference/performance.md +217 -0
- package/.agents/skills/moonbit-practice/reference/refactor.md +154 -0
- package/.agents/skills/moonbit-practice/reference/stdlib.md +351 -0
- package/.agents/skills/moonbit-practice/reference/testing.md +228 -0
- package/.agents/skills/moonbit-refactoring/LICENSE +21 -0
- package/.agents/skills/moonbit-refactoring/SKILL.md +323 -0
- package/.githooks/README.md +23 -0
- package/.githooks/pre-commit +3 -0
- package/.github/workflows/copilot-setup-steps.yml +40 -0
- package/.turbo/turbo-typecheck.log +2 -0
- package/AGENTS.md +91 -0
- package/LICENSE +21 -0
- package/PLAN.md +64 -0
- package/README.mbt.md +77 -0
- package/README.md +84 -0
- package/TODO.md +120 -0
- package/a.png +0 -0
- package/benchmarks/calc.bench.ts +144 -0
- package/benchmarks/draw.bench.ts +215 -0
- package/benchmarks/load.bench.ts +28 -0
- package/benchmarks/render.bench.ts +53 -0
- package/benchmarks/run.bench.ts +8 -0
- package/benchmarks/types.d.ts +15 -0
- package/docs/scratch-vm-specs/eventloop.md +103 -0
- package/docs/scratch-vm-specs/moonscratch-time-separation.md +50 -0
- package/index.html +91 -0
- package/js/AGENTS.md +5 -0
- package/js/a.ts +52 -0
- package/js/assets/AGENTS.md +5 -0
- package/js/assets/base64.test.ts +14 -0
- package/js/assets/base64.ts +21 -0
- package/js/assets/build-asset.test.ts +26 -0
- package/js/assets/build-asset.ts +28 -0
- package/js/assets/create.test.ts +142 -0
- package/js/assets/create.ts +122 -0
- package/js/assets/index.test.ts +15 -0
- package/js/assets/index.ts +2 -0
- package/js/assets/types.ts +26 -0
- package/js/assets/validation.test.ts +34 -0
- package/js/assets/validation.ts +25 -0
- package/js/assets.test.ts +14 -0
- package/js/assets.ts +1 -0
- package/js/index.test.ts +26 -0
- package/js/index.ts +3 -0
- package/js/render/index.test.ts +65 -0
- package/js/render/index.ts +13 -0
- package/js/render/sharp.ts +87 -0
- package/js/render/svg.ts +68 -0
- package/js/render/types.ts +35 -0
- package/js/render/utils.ts +108 -0
- package/js/render/webgl.ts +274 -0
- package/js/sharp-optional.d.ts +16 -0
- package/js/test/helpers.ts +116 -0
- package/js/test/hikkaku-sample.test.ts +37 -0
- package/js/test/rubik-components.input-motion.test.ts +60 -0
- package/js/test/rubik-components.lists.test.ts +49 -0
- package/js/test/rubik-components.operators.test.ts +104 -0
- package/js/test/rubik-components.pen.test.ts +112 -0
- package/js/test/rubik-components.procedures-loops.test.ts +72 -0
- package/js/test/rubik-components.variables-branches.test.ts +57 -0
- package/js/test/rubik-components.visibility-entry.test.ts +31 -0
- package/js/test/test-projects.ts +598 -0
- package/js/test/variable.ts +200 -0
- package/js/test/warp.test.ts +59 -0
- package/js/vm/AGENTS.md +6 -0
- package/js/vm/README.md +183 -0
- package/js/vm/bindings.test.ts +13 -0
- package/js/vm/bindings.ts +5 -0
- package/js/vm/compare-operators.test.ts +145 -0
- package/js/vm/constants.test.ts +11 -0
- package/js/vm/constants.ts +4 -0
- package/js/vm/effect-guards.test.ts +68 -0
- package/js/vm/effect-guards.ts +44 -0
- package/js/vm/factory.test.ts +486 -0
- package/js/vm/factory.ts +615 -0
- package/js/vm/headless-vm.test.ts +131 -0
- package/js/vm/headless-vm.ts +342 -0
- package/js/vm/index.test.ts +28 -0
- package/js/vm/index.ts +5 -0
- package/js/vm/internal-types.ts +32 -0
- package/js/vm/json.test.ts +40 -0
- package/js/vm/json.ts +273 -0
- package/js/vm/normalize.test.ts +48 -0
- package/js/vm/normalize.ts +65 -0
- package/js/vm/options.test.ts +30 -0
- package/js/vm/options.ts +55 -0
- package/js/vm/pen-transparency.test.ts +115 -0
- package/js/vm/program-wasm.ts +322 -0
- package/js/vm/scheduler-render.test.ts +401 -0
- package/js/vm/scratch-assets.test.ts +136 -0
- package/js/vm/scratch-assets.ts +202 -0
- package/js/vm/types.ts +358 -0
- package/js/vm/value-guards.test.ts +25 -0
- package/js/vm/value-guards.ts +18 -0
- package/moon.mod.json +10 -0
- package/package.json +33 -0
- package/scripts/preinstall.ts +4 -0
- package/src/AGENTS.md +6 -0
- package/src/api.mbt +161 -0
- package/src/api_aot_commands.mbt +184 -0
- package/src/api_effects_json.mbt +72 -0
- package/src/api_options.mbt +60 -0
- package/src/api_program_wasm.mbt +1647 -0
- package/src/api_program_wat.mbt +2206 -0
- package/src/api_snapshot_json.mbt +44 -0
- package/src/cmd/AGENTS.md +5 -0
- package/src/cmd/main/AGENTS.md +5 -0
- package/src/cmd/main/main.mbt +29 -0
- package/src/cmd/main/moon.pkg +7 -0
- package/src/cmd/main/pkg.generated.mbti +13 -0
- package/src/json_helpers.mbt +176 -0
- package/src/moon.pkg +65 -0
- package/src/moonscratch.mbt +3 -0
- package/src/moonscratch_wbtest.mbt +40 -0
- package/src/parser_sb3.mbt +890 -0
- package/src/pkg.generated.mbti +479 -0
- package/src/runtime_eval.mbt +2844 -0
- package/src/runtime_exec.mbt +3850 -0
- package/src/runtime_render.mbt +2550 -0
- package/src/runtime_state.mbt +870 -0
- package/src/test/AGENTS.md +3 -0
- package/src/test/projects/AGENTS.md +6 -0
- package/src/test/projects/moon.pkg +4 -0
- package/src/test/projects/moonscratch_compat_test.mbt +642 -0
- package/src/test/projects/moonscratch_core_test.mbt +1332 -0
- package/src/test/projects/moonscratch_runtime_test.mbt +1087 -0
- package/src/test/projects/pkg.generated.mbti +13 -0
- package/src/test/projects/test_support.mbt +35 -0
- package/src/types_effects.mbt +20 -0
- package/src/types_error.mbt +4 -0
- package/src/types_options.mbt +31 -0
- package/src/types_runtime_structs.mbt +254 -0
- package/src/types_vm.mbt +109 -0
- package/tsconfig.json +29 -0
- package/viewer/index.ts +399 -0
- package/viewer/vite.d.ts +1 -0
- package/viewer/worker.ts +161 -0
- package/vite.config.ts +11 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
///|
|
|
2
|
+
fn target_snapshot_json(target : TargetState) -> Json {
|
|
3
|
+
let lists_json = {}
|
|
4
|
+
target.lists.each((list_id, items) => lists_json[list_id] = json_array(items))
|
|
5
|
+
|
|
6
|
+
json_object({
|
|
7
|
+
"id": json_string(target.id),
|
|
8
|
+
"name": json_string(target.name),
|
|
9
|
+
"isStage": json_bool(target.is_stage),
|
|
10
|
+
"x": json_number(target.x),
|
|
11
|
+
"y": json_number(target.y),
|
|
12
|
+
"direction": json_number(target.direction),
|
|
13
|
+
"size": json_number(target.size),
|
|
14
|
+
"volume": json_number(target.volume),
|
|
15
|
+
"musicInstrument": json_number(
|
|
16
|
+
Double::from_int(target.music_instrument + 1),
|
|
17
|
+
),
|
|
18
|
+
"textToSpeechVoice": json_string(target.tts_voice),
|
|
19
|
+
"visible": json_bool(target.visible),
|
|
20
|
+
"currentCostume": json_number(Double::from_int(target.current_costume)),
|
|
21
|
+
"variables": json_object(target.variables),
|
|
22
|
+
"lists": json_object(lists_json),
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
///|
|
|
27
|
+
fn snapshot_to_json(vm : Vm) -> Json {
|
|
28
|
+
let targets = []
|
|
29
|
+
for target in vm.targets {
|
|
30
|
+
if !target.deleted {
|
|
31
|
+
targets.push(target_snapshot_json(target))
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
json_object({
|
|
35
|
+
"runId": json_number(Double::from_int(vm.run_id)),
|
|
36
|
+
"nowMs": json_number(Double::from_int(vm.now_ms)),
|
|
37
|
+
"running": json_bool(vm.running),
|
|
38
|
+
"answer": json_string(vm.answer),
|
|
39
|
+
"musicTempo": json_number(vm.music_tempo),
|
|
40
|
+
"textToSpeechLanguage": json_string(vm.tts_language),
|
|
41
|
+
"activeThreads": json_number(Double::from_int(vm.threads.length())),
|
|
42
|
+
"targets": json_array(targets),
|
|
43
|
+
})
|
|
44
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
///|
|
|
2
|
+
fn main {
|
|
3
|
+
let minimal_project =
|
|
4
|
+
#|{
|
|
5
|
+
#| "targets": [
|
|
6
|
+
#| {
|
|
7
|
+
#| "isStage": true,
|
|
8
|
+
#| "name": "Stage",
|
|
9
|
+
#| "variables": {},
|
|
10
|
+
#| "lists": {},
|
|
11
|
+
#| "blocks": {}
|
|
12
|
+
#| }
|
|
13
|
+
#| ]
|
|
14
|
+
#|}
|
|
15
|
+
|
|
16
|
+
let vm_result = try? ({
|
|
17
|
+
let precompiled = @moonscratch.vm_compile_from_json(minimal_project)
|
|
18
|
+
@moonscratch.vm_new_from_compiled(precompiled)
|
|
19
|
+
})
|
|
20
|
+
match vm_result {
|
|
21
|
+
Ok(vm) => {
|
|
22
|
+
@moonscratch.vm_start(vm)
|
|
23
|
+
@moonscratch.vm_set_time(vm, 16)
|
|
24
|
+
let report = @moonscratch.vm_step_frame(vm)
|
|
25
|
+
println("step report: \{report}")
|
|
26
|
+
}
|
|
27
|
+
Err(_) => println("failed to initialize vm")
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
///|
|
|
2
|
+
fn[T] invalid_project(message : String) -> T raise VmError {
|
|
3
|
+
raise VmError::InvalidProject(message)
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
///|
|
|
7
|
+
fn parse_json_or_fail(raw : String) -> Json raise VmError {
|
|
8
|
+
let parsed = try? @json.parse(raw)
|
|
9
|
+
match parsed {
|
|
10
|
+
Ok(json) => json
|
|
11
|
+
Err(err) => invalid_project("failed to parse json: \{err}")
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
///|
|
|
16
|
+
fn expect_object(
|
|
17
|
+
json : Json,
|
|
18
|
+
context : String,
|
|
19
|
+
) -> Map[String, Json] raise VmError {
|
|
20
|
+
match json {
|
|
21
|
+
Object(map) => map
|
|
22
|
+
_ => invalid_project("\{context} must be a JSON object")
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
///|
|
|
27
|
+
fn expect_array(json : Json, context : String) -> Array[Json] raise VmError {
|
|
28
|
+
match json {
|
|
29
|
+
Array(values) => values
|
|
30
|
+
_ => invalid_project("\{context} must be a JSON array")
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
///|
|
|
35
|
+
fn object_get(obj : Map[String, Json], key : String) -> Json? {
|
|
36
|
+
obj.get(key)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
///|
|
|
40
|
+
fn object_get_or(
|
|
41
|
+
obj : Map[String, Json],
|
|
42
|
+
key : String,
|
|
43
|
+
fallback : Json,
|
|
44
|
+
) -> Json {
|
|
45
|
+
obj.get_or_default(key, fallback)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
///|
|
|
49
|
+
fn object_get_string_or(
|
|
50
|
+
obj : Map[String, Json],
|
|
51
|
+
key : String,
|
|
52
|
+
fallback : String,
|
|
53
|
+
) -> String {
|
|
54
|
+
match obj.get(key) {
|
|
55
|
+
Some(String(s)) => s
|
|
56
|
+
_ => fallback
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
///|
|
|
61
|
+
fn object_get_bool_or(
|
|
62
|
+
obj : Map[String, Json],
|
|
63
|
+
key : String,
|
|
64
|
+
fallback : Bool,
|
|
65
|
+
) -> Bool {
|
|
66
|
+
match obj.get(key) {
|
|
67
|
+
Some(True) => true
|
|
68
|
+
Some(False) => false
|
|
69
|
+
_ => fallback
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
///|
|
|
74
|
+
fn object_get_number_or(
|
|
75
|
+
obj : Map[String, Json],
|
|
76
|
+
key : String,
|
|
77
|
+
fallback : Double,
|
|
78
|
+
) -> Double {
|
|
79
|
+
match obj.get(key) {
|
|
80
|
+
Some(Number(n, ..)) => n
|
|
81
|
+
_ => fallback
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
///|
|
|
86
|
+
fn object_get_object_or_empty(
|
|
87
|
+
obj : Map[String, Json],
|
|
88
|
+
key : String,
|
|
89
|
+
) -> Map[String, Json] {
|
|
90
|
+
match obj.get(key) {
|
|
91
|
+
Some(Object(map)) => map
|
|
92
|
+
_ => {}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
///|
|
|
97
|
+
fn json_to_string_value(json : Json) -> String {
|
|
98
|
+
match json {
|
|
99
|
+
String(s) => s
|
|
100
|
+
Number(n, ..) => n.to_string()
|
|
101
|
+
True => "true"
|
|
102
|
+
False => "false"
|
|
103
|
+
Null => ""
|
|
104
|
+
_ => json.stringify()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
///|
|
|
109
|
+
fn parse_double_or_none(s : String) -> Double? {
|
|
110
|
+
let trimmed = s.trim().to_string()
|
|
111
|
+
if trimmed.is_empty() {
|
|
112
|
+
None
|
|
113
|
+
} else {
|
|
114
|
+
let parsed = try? @strconv.parse_double(trimmed)
|
|
115
|
+
match parsed {
|
|
116
|
+
Ok(value) => Some(value)
|
|
117
|
+
Err(_) => None
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
///|
|
|
123
|
+
fn json_to_number_value(json : Json) -> Double {
|
|
124
|
+
match json {
|
|
125
|
+
Number(n, ..) => n
|
|
126
|
+
String(s) =>
|
|
127
|
+
match parse_double_or_none(s) {
|
|
128
|
+
Some(value) => value
|
|
129
|
+
None => 0.0
|
|
130
|
+
}
|
|
131
|
+
True => 1.0
|
|
132
|
+
False => 0.0
|
|
133
|
+
Null => 0.0
|
|
134
|
+
_ => 0.0
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
///|
|
|
139
|
+
fn json_to_bool_value(json : Json) -> Bool {
|
|
140
|
+
match json {
|
|
141
|
+
True => true
|
|
142
|
+
False => false
|
|
143
|
+
Number(n, ..) => n != 0.0
|
|
144
|
+
String(s) => {
|
|
145
|
+
let lowered = s.trim().to_lower()
|
|
146
|
+
lowered != "" && lowered != "0" && lowered != "false"
|
|
147
|
+
}
|
|
148
|
+
Null => false
|
|
149
|
+
_ => true
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
///|
|
|
154
|
+
fn json_number(value : Double) -> Json {
|
|
155
|
+
Json::number(value)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
///|
|
|
159
|
+
fn json_string(value : String) -> Json {
|
|
160
|
+
Json::string(value)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
///|
|
|
164
|
+
fn json_bool(value : Bool) -> Json {
|
|
165
|
+
Json::boolean(value)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
///|
|
|
169
|
+
fn json_array(values : Array[Json]) -> Json {
|
|
170
|
+
Json::array(values)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
///|
|
|
174
|
+
fn json_object(values : Map[String, Json]) -> Json {
|
|
175
|
+
Json::object(values)
|
|
176
|
+
}
|
package/src/moon.pkg
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
"moonbitlang/core/encoding/base64" @base64,
|
|
3
|
+
"moonbitlang/core/encoding/utf8" @utf8,
|
|
4
|
+
"moonbitlang/core/json" @json,
|
|
5
|
+
"moonbitlang/core/math" @math,
|
|
6
|
+
"moonbitlang/core/strconv" @strconv,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
options(
|
|
10
|
+
link: {
|
|
11
|
+
"js": {
|
|
12
|
+
"exports": [
|
|
13
|
+
"vm_compile_from_json",
|
|
14
|
+
"vm_compile_project_to_wat",
|
|
15
|
+
"vm_compile_project_to_wasm",
|
|
16
|
+
"vm_abi_version",
|
|
17
|
+
"vm_new_from_compiled",
|
|
18
|
+
"vm_start",
|
|
19
|
+
"vm_green_flag",
|
|
20
|
+
"vm_step_frame",
|
|
21
|
+
"vm_set_time",
|
|
22
|
+
"vm_set_aot_commands_json",
|
|
23
|
+
"vm_get_variable_number_by_id",
|
|
24
|
+
"vm_set_variable_number_by_id",
|
|
25
|
+
"vm_set_variable_json_by_id",
|
|
26
|
+
"vm_exec_script_tail_by_pc",
|
|
27
|
+
"vm_exec_opcode_once_by_pc",
|
|
28
|
+
"vm_exec_draw_opcode",
|
|
29
|
+
"vm_post_io_json",
|
|
30
|
+
"vm_broadcast",
|
|
31
|
+
"vm_stop_all",
|
|
32
|
+
"vm_take_effects_json",
|
|
33
|
+
"vm_snapshot_json",
|
|
34
|
+
"vm_render_frame",
|
|
35
|
+
],
|
|
36
|
+
"format": "esm",
|
|
37
|
+
},
|
|
38
|
+
"wasm-gc": {
|
|
39
|
+
"exports": [
|
|
40
|
+
"vm_compile_from_json",
|
|
41
|
+
"vm_compile_project_to_wat",
|
|
42
|
+
"vm_compile_project_to_wasm",
|
|
43
|
+
"vm_abi_version",
|
|
44
|
+
"vm_new_from_compiled",
|
|
45
|
+
"vm_start",
|
|
46
|
+
"vm_green_flag",
|
|
47
|
+
"vm_step_frame",
|
|
48
|
+
"vm_set_time",
|
|
49
|
+
"vm_set_aot_commands_json",
|
|
50
|
+
"vm_get_variable_number_by_id",
|
|
51
|
+
"vm_set_variable_number_by_id",
|
|
52
|
+
"vm_set_variable_json_by_id",
|
|
53
|
+
"vm_exec_script_tail_by_pc",
|
|
54
|
+
"vm_exec_opcode_once_by_pc",
|
|
55
|
+
"vm_exec_draw_opcode",
|
|
56
|
+
"vm_post_io_json",
|
|
57
|
+
"vm_broadcast",
|
|
58
|
+
"vm_stop_all",
|
|
59
|
+
"vm_take_effects_json",
|
|
60
|
+
"vm_snapshot_json",
|
|
61
|
+
"vm_render_frame",
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
///|
|
|
2
|
+
test "default options" {
|
|
3
|
+
let options = default_vm_options()
|
|
4
|
+
inspect(options.max_clones, content="300")
|
|
5
|
+
inspect(options.turbo, content="false")
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
///|
|
|
9
|
+
test "compile project to generated wat metadata" {
|
|
10
|
+
let minimal_project = "{\"targets\":[{\"isStage\":true,\"name\":\"Stage\",\"variables\":{},\"lists\":{},\"blocks\":{},\"costumes\":[]}]}"
|
|
11
|
+
let wat_result = try? vm_compile_project_to_wat(minimal_project)
|
|
12
|
+
let wat = match wat_result {
|
|
13
|
+
Ok(value) => value
|
|
14
|
+
Err(_) => fail("vm_compile_project_to_wat failed")
|
|
15
|
+
}
|
|
16
|
+
inspect(wat.contains(";; moonscratch_program_v1"), content="true")
|
|
17
|
+
inspect(wat.contains("(export \"ms_abi_version\")"), content="true")
|
|
18
|
+
inspect(wat.contains("(export \"ms_commands_len\")"), content="true")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
///|
|
|
22
|
+
test "compile project to generated wasm bytes" {
|
|
23
|
+
let minimal_project = "{\"targets\":[{\"isStage\":true,\"name\":\"Stage\",\"variables\":{},\"lists\":{},\"blocks\":{},\"costumes\":[]}]}"
|
|
24
|
+
let wasm_result = try? vm_compile_project_to_wasm(minimal_project)
|
|
25
|
+
let wasm_base64 = match wasm_result {
|
|
26
|
+
Ok(value) => value
|
|
27
|
+
Err(_) => fail("vm_compile_project_to_wasm failed")
|
|
28
|
+
}
|
|
29
|
+
let decoded = @base64.decode(wasm_base64.view()) catch {
|
|
30
|
+
_ => fail("vm_compile_project_to_wasm returned invalid base64")
|
|
31
|
+
}
|
|
32
|
+
let bytes = decoded.to_array()
|
|
33
|
+
if bytes.length() < 4 {
|
|
34
|
+
fail("wasm bytes are too short")
|
|
35
|
+
}
|
|
36
|
+
inspect(bytes[0] == (0x00).to_byte(), content="true")
|
|
37
|
+
inspect(bytes[1] == (0x61).to_byte(), content="true")
|
|
38
|
+
inspect(bytes[2] == (0x73).to_byte(), content="true")
|
|
39
|
+
inspect(bytes[3] == (0x6d).to_byte(), content="true")
|
|
40
|
+
}
|