v2 / examples / wasm_codegen / bf_compiler.v
140 lines · 127 sloc · 3.15 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1import os
2import wasm
3
4const runtime_page = 1024 * 64 // 64 KiBs
5
6fn generate_ciovec(mut start wasm.Function, sp wasm.LocalIndex) {
7 // construct struct __wasi_ciovec_t
8 //
9 // field, `const uint8_t *buf`
10 start.i32_const(runtime_page)
11 start.local_get(sp)
12 start.store(.i32_t, 2, 0)
13 // field, `__wasi_size_t buf_len`
14 start.i32_const(runtime_page)
15 start.i32_const(1) // len
16 start.store(.i32_t, 2, 4)
17}
18
19fn generate_code(mut start wasm.Function, bf_expr string) {
20 // locals are initialised to zero, by spec
21 sp := start.new_local_named(.i32_t, 'sp')
22
23 mut loop_labels := []wasm.LabelIndex{}
24 mut block_labels := []wasm.LabelIndex{}
25
26 // our page, the second one
27
28 for ch in bf_expr {
29 match ch {
30 `>` {
31 start.local_get(sp)
32 start.i32_const(1)
33 start.add(.i32_t)
34 start.local_set(sp)
35 }
36 `<` {
37 start.local_get(sp)
38 start.i32_const(1)
39 start.sub(.i32_t)
40 start.local_set(sp)
41 }
42 `+` {
43 start.local_get(sp)
44 {
45 start.local_get(sp)
46 start.load8(.i32_t, false, 0, 0)
47 start.i32_const(1)
48 start.add(.i32_t)
49 }
50 start.store8(.i32_t, 0, 0)
51 }
52 `-` {
53 start.local_get(sp)
54 {
55 start.local_get(sp)
56 start.load8(.i32_t, false, 0, 0)
57 start.i32_const(1)
58 start.sub(.i32_t)
59 }
60 start.store8(.i32_t, 0, 0)
61 }
62 `.` {
63 generate_ciovec(mut start, sp)
64
65 start.i32_const(1) // stdout
66 start.i32_const(runtime_page) // *iovs
67 start.i32_const(1) // iovs_len
68 start.i32_const(runtime_page + 1024) // *nwritten
69 start.call_import('wasi_unstable', 'fd_write')
70 start.drop() // ignore errno
71 }
72 `,` {
73 generate_ciovec(mut start, sp)
74
75 start.i32_const(0) // stdin
76 start.i32_const(runtime_page) // *iovs
77 start.i32_const(1) // iovs_len
78 start.i32_const(runtime_page + 1024) // *nwritten
79 start.call_import('wasi_unstable', 'fd_read')
80 start.drop() // ignore errno
81 }
82 `[` {
83 block_lbl := start.c_block([], [])
84 loop_lbl := start.c_loop([], [])
85 {
86 start.local_get(sp)
87 start.load8(.i32_t, false, 0, 0)
88 start.eqz(.i32_t)
89 start.c_br_if(block_lbl)
90 }
91 loop_labels << loop_lbl
92 block_labels << block_lbl
93 }
94 `]` {
95 loop_lbl := loop_labels.pop()
96 start.c_br(loop_lbl) // jump back to top
97 start.c_end(loop_lbl)
98 start.c_end(block_labels.pop())
99 }
100 else {}
101 }
102 }
103}
104
105@[noreturn]
106fn usage() {
107 eprintln('Usage: bf <expr> <outfile.wasm>')
108 eprintln(' or: bf <path/input.b> <outfile.wasm> (note the `.b` extension)')
109 exit(1)
110}
111
112fn main() {
113 mut bf_expr := os.args[1] or { usage() }
114 if bf_expr.ends_with('.b') {
115 bf_expr = os.read_file(bf_expr) or {
116 eprintln('file ${bf_expr} could not be read, error: ${err}')
117 usage()
118 }
119 }
120 outfile := os.args[2] or { usage() }
121
122 mut m := wasm.Module{}
123 m.enable_debug('wasm bf')
124 m.new_function_import('wasi_unstable', 'fd_write', [.i32_t, .i32_t, .i32_t, .i32_t], [
125 .i32_t,
126 ])
127 m.new_function_import('wasi_unstable', 'fd_read', [.i32_t, .i32_t, .i32_t, .i32_t], [
128 .i32_t,
129 ])
130 m.assign_memory('memory', true, 2, none)
131
132 mut start := m.new_function('_start', [], [])
133 {
134 generate_code(mut start, bf_expr)
135 }
136 m.commit(start, true)
137
138 bytes := m.compile()
139 os.write_file_array(outfile, bytes)!
140}
141