@@ -4,6 +4,14 @@ use crate::token::Tokenizer;
44
55use std:: iter:: Peekable ;
66
7+ pub type Bindings = [ String ] ; // vars
8+ pub type Wat = String ;
9+ pub type Wasm = Vec < u8 > ;
10+
11+ pub trait ToWasm {
12+ fn to_wasm ( & self , bindings : & Bindings ) -> Wasm ;
13+ }
14+
715pub ( crate ) enum Expr {
816 Add ( Box < Expr > , Box < Term > ) ,
917 Subtract ( Box < Expr > , Box < Term > ) ,
@@ -29,29 +37,31 @@ impl Expr {
2937 term
3038 }
3139
32- pub fn to_wat ( & self ) -> String {
40+ pub fn to_wat ( & self ) -> Wat {
3341 match & self {
3442 Self :: Add ( l, r) => format ! ( "{}\n {}\n i32.add" , l. to_wat( ) , r. to_wat( ) ) ,
3543 Self :: Subtract ( l, r) => format ! ( "{}\n {}\n i32.sub" , l. to_wat( ) , r. to_wat( ) ) ,
3644 Self :: Term ( t) => t. to_wat ( ) ,
3745 }
3846 }
47+ }
3948
40- fn to_wasm ( & self ) -> Vec < u8 > {
49+ impl ToWasm for Expr {
50+ fn to_wasm ( & self , bindings : & Bindings ) -> Wasm {
4151 match & self {
4252 Self :: Add ( l, r) => {
43- let mut out = l. to_wasm ( ) ;
44- out. extend ( & r. to_wasm ( ) ) ;
53+ let mut out = l. to_wasm ( bindings ) ;
54+ out. extend ( & r. to_wasm ( bindings ) ) ;
4555 out. push ( 0x6a ) ; // i32.add
4656 out
4757 } ,
4858 Self :: Subtract ( l, r) => {
49- let mut out = l. to_wasm ( ) ;
50- out. extend ( & r. to_wasm ( ) ) ;
59+ let mut out = l. to_wasm ( bindings ) ;
60+ out. extend ( & r. to_wasm ( bindings ) ) ;
5161 out. push ( 0x6b ) ; // i32.sub
5262 out
5363 } ,
54- Self :: Term ( t) => t. to_wasm ( ) ,
64+ Self :: Term ( t) => t. to_wasm ( bindings ) ,
5565 }
5666 }
5767}
@@ -83,29 +93,31 @@ impl Term {
8393 factor
8494 }
8595
86- fn to_wat ( & self ) -> String {
96+ fn to_wat ( & self ) -> Wat {
8797 match & self {
8898 Self :: Multiply ( l, r) => format ! ( "{}\n {}\n i32.mul" , l. to_wat( ) , r. to_wat( ) ) ,
8999 Self :: Divide ( l, r) => format ! ( "{}\n {}\n i32.div_u" , l. to_wat( ) , r. to_wat( ) ) ,
90100 Self :: Factor ( f) => f. to_wat ( ) ,
91101 }
92102 }
103+ }
93104
94- fn to_wasm ( & self ) -> Vec < u8 > {
105+ impl ToWasm for Term {
106+ fn to_wasm ( & self , bindings : & Bindings ) -> Wasm {
95107 match & self {
96108 Self :: Multiply ( l, r) => {
97- let mut out = l. to_wasm ( ) ;
98- out. extend ( & r. to_wasm ( ) ) ;
109+ let mut out = l. to_wasm ( bindings ) ;
110+ out. extend ( & r. to_wasm ( bindings ) ) ;
99111 out. push ( 0x6c ) ; // i32.mul
100112 out
101113 } ,
102114 Self :: Divide ( l, r) => {
103- let mut out = l. to_wasm ( ) ;
104- out. extend ( & r. to_wasm ( ) ) ;
115+ let mut out = l. to_wasm ( bindings ) ;
116+ out. extend ( & r. to_wasm ( bindings ) ) ;
105117 out. push ( 0x6e ) ; // i32.div_u
106118 out
107119 } ,
108- Self :: Factor ( f) => f. to_wasm ( ) ,
120+ Self :: Factor ( f) => f. to_wasm ( bindings ) ,
109121 }
110122 }
111123}
@@ -132,15 +144,17 @@ impl Factor {
132144 }
133145 }
134146
135- fn to_wat ( & self ) -> String {
147+ fn to_wat ( & self ) -> Wat {
136148 match & self {
137149 Self :: Const ( c) => format ! ( "i32.const {c}" ) ,
138150 Self :: Param ( p) => format ! ( "local.get ${p}" ) ,
139151 Self :: Expr ( e) => e. to_wat ( ) ,
140152 }
141153 }
154+ }
142155
143- fn to_wasm ( & self ) -> Vec < u8 > {
156+ impl ToWasm for Factor {
157+ fn to_wasm ( & self , bindings : & Bindings ) -> Wasm {
144158 match & self {
145159 Self :: Const ( c) => {
146160 let mut out = vec ! [ 0x41 ] ; // i32.const
@@ -149,11 +163,14 @@ impl Factor {
149163 } ,
150164 Self :: Param ( p) => {
151165 let mut out = vec ! [ 0x20 ] ; // local.get
152- assert_eq ! ( p, "x" ) ; // FIXME
153- out. push ( 0 ) ; // first param
166+ if let Some ( index) = bindings. iter ( ) . position ( |b| b == p) {
167+ write_leb128 ( index as i128 , & mut out) ;
168+ } else {
169+ panic ! ( "Unknown binding for local '{p}'" ) ;
170+ }
154171 out
155172 } ,
156- Self :: Expr ( e) => e. to_wasm ( ) ,
173+ Self :: Expr ( e) => e. to_wasm ( bindings ) ,
157174 }
158175 }
159176}
@@ -230,11 +247,12 @@ pub fn add_fluff(expr_wat: &str) -> String {
230247 call $host_log
231248
232249 i32.const 7 ;; <-- WASM function param `$x`
250+ i32.const 9 ;; <-- WASM function param `$yy`
233251 call $eval_expr
234252 return)
235253 "# . to_string ( ) ;
236254
237- wat. push_str ( "(func $eval_expr (param $x i32) (result i32)" ) ;
255+ wat. push_str ( "(func $eval_expr (param $x i32) (param $yy i32) ( result i32)" ) ;
238256 wat. push_str ( expr_wat) ;
239257 wat. push_str ( " return)" ) ;
240258 wat. push_str ( ")" ) ;
@@ -248,45 +266,104 @@ fn make_func(body: &[u8]) -> Vec<u8> {
248266 out
249267}
250268
251- fn make_code_section ( functions : & [ & [ u8 ] ] ) -> Vec < u8 > {
252- let function_count = functions. len ( ) ;
253- let code_section_size = 1 + functions. iter ( ) . map ( |v|v. len ( ) ) . sum :: < usize > ( ) ;
269+ const SIGNATURE_TYPE : u8 = 0x01 ; // function signatures
270+ const SIGNATURE_CODE : u8 = 0x0a ; // function bodies, locals and opcodes
271+
272+ fn make_section < const SIGNATURE : u8 > ( payloads : & [ & [ u8 ] ] ) -> Vec < u8 > {
273+ let count = payloads. len ( ) ;
274+ assert ! ( count < 63 ) ; // FIXME assume 1 byte for leb128; might overflow
275+ let payload_size = 1 + payloads. iter ( ) . map ( |v|v. len ( ) ) . sum :: < usize > ( ) ;
254276 let mut out = Vec :: new ( ) ;
255- write_leb128 ( code_section_size. try_into ( ) . unwrap ( ) , & mut out) ;
256- write_leb128 ( function_count. try_into ( ) . unwrap ( ) , & mut out) ;
257- for & function in functions {
277+ out. push ( SIGNATURE ) ;
278+ write_leb128 ( payload_size. try_into ( ) . unwrap ( ) , & mut out) ;
279+ write_leb128 ( count. try_into ( ) . unwrap ( ) , & mut out) ;
280+ for & function in payloads {
258281 out. extend ( function) ;
259282 }
260- out
283+ out
261284}
262285
263- pub fn generate_wasm ( expr : & Expr ) -> Vec < u8 > {
286+ fn make_func_type ( args : & [ u8 ] , result : & [ u8 ] ) -> Vec < u8 > {
287+ let mut payload = Vec :: new ( ) ;
288+ payload. push ( 0x60 ) ; // function signature
289+ write_leb128 ( args. len ( ) as i128 , & mut payload) ;
290+ payload. extend ( args) ;
291+ write_leb128 ( result. len ( ) as i128 , & mut payload) ;
292+ payload. extend ( result) ;
293+ payload
294+ }
295+
296+ #[ test]
297+ fn test_make_func_type ( ) {
298+ let f1 = make_func_type ( & [ 0x7f ] , & [ ] ) ;
299+ assert_eq ! ( f1, & [ 0x60 , 0x01 , 0x7f , 0x00 ] ) ;
300+ let f2 = make_func_type ( & [ ] , & [ 0x7f ] ) ;
301+ assert_eq ! ( f2, & [ 0x60 , 0x00 , 0x01 , 0x7f ] ) ;
302+ let f3 = make_func_type ( & [ 0x7f , 0x7f ] , & [ 0x7f ] ) ;
303+ assert_eq ! ( f3, & [ 0x60 , 0x02 , 0x7f , 0x7f , 0x01 , 0x7f ] ) ;
304+ let type_section = make_section :: < SIGNATURE_TYPE > ( & [ & f1, & f2, & f3] ) ;
305+ assert_eq ! ( type_section,
306+ [ 0x01 , 0x0f , 0x03 , 0x60 , 0x01 , 0x7f , 0x00 ,
307+ 0x60 , 0x00 , 0x01 , 0x7f ,
308+ 0x60 , 0x02 , 0x7f , 0x7f , 0x01 , 0x7f , ] ) ;
309+ }
310+
311+ pub fn generate_wasm ( expr : & impl ToWasm , bindings : & Bindings ) -> Vec < u8 > {
264312 let mut wasm = vec ! [
265- 0x00 , 0x61 , 0x73 , 0x6d , 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 0x0e , 0x03 , 0x60 ,
266- 0x01 , 0x7f , 0x00 , 0x60 , 0x00 , 0x01 , 0x7f , 0x60 , 0x01 , 0x7f , 0x01 , 0x7f ,
267- 0x02 , 0x0c , 0x01 , 0x04 , 0x68 , 0x6f , 0x73 , 0x74 , 0x03 , 0x6c , 0x6f , 0x67 ,
268- 0x00 , 0x00 , 0x03 , 0x03 , 0x02 , 0x01 , 0x02 , 0x07 , 0x08 , 0x01 , 0x04 , 0x63 ,
269- 0x61 , 0x6c , 0x63 , 0x00 , 0x01 , 0x0a ] ;
313+ 0x00 , 0x61 , 0x73 , 0x6d , // asm
314+ 0x01 , 0x00 , 0x00 , 0x00 , // version
315+ ] ;
316+ wasm. extend ( & make_section :: < SIGNATURE_TYPE > ( & [
317+ & make_func_type ( & [ 0x7f ] , & [ ] ) ,
318+ & make_func_type ( & [ ] , & [ 0x7f ] ) ,
319+ & make_func_type ( & [ 0x7f , 0x7f ] , & [ 0x7f ] ) ,
320+ ] ) ) ;
321+ wasm. extend ( & [
322+ 0x02 , // import section signature
323+ 0x0c , // 12B payload
324+ 0x01 , // one import
325+ 0x04 , // Module name: 4 chars
326+ 0x68 , 0x6f , 0x73 , 0x74 , // = "host"
327+ 0x03 , // Field name: 3 chars
328+ 0x6c , 0x6f , 0x67 , // == log
329+ 0x00 , // Import kind: function
330+ 0x00 , // Type kind index: 0: i32 -> ()
331+
332+ 0x03 , // function section signarure
333+ 0x03 , // 3B payload
334+ 0x02 , // 2 functions:
335+ 0x01 , // Type kind index: 1: () -> i32
336+ 0x02 , // TYpe kind index: 2: i32, i32 -> i32
337+
338+ 0x07 , // export section signature
339+ 0x08 , // 8 byte payload
340+ 0x01 , // one export
341+ 0x04 , // Field name: 4 chars
342+ 0x63 , 0x61 , 0x6c , 0x63 , // = "main"
343+ 0x00 , // Export kind: function
344+ 0x01 , // Function index: 1, () -> i32
345+ ] ) ;
270346
271347 let calc = make_func ( & [
272348 0x00 , // localdeclcount(0)
273349 0x41 , 0xfb , 0x00 , // i32.const 123
274350 0x10 , 0x00 , // call function index=0 (host_log)
275351 0x41 , 0x07 , // i32.const 7
352+ 0x41 , 0x09 , // i32.const 9
276353 0x10 , 0x02 , // call function index=2 (eval_expr)
277354 0x0f , // return
278355 0x0b , // end
279356 ] ) ;
280357
281358 let mut body = Vec :: new ( ) ;
282359 body. push ( 0x00 ) ; // no local decl count
283- body. extend ( expr. to_wasm ( ) ) ;
360+ body. extend ( expr. to_wasm ( bindings ) ) ;
284361 body. extend ( & [ 0x0f , // return
285362 0x0b , // end
286363 ] ) ;
287364 let eval_expr = make_func ( & body) ;
288365
289- let code_section = make_code_section ( & [ & calc, & eval_expr ] ) ;
366+ let code_section = make_section :: < SIGNATURE_CODE > ( & [ & calc, & eval_expr ] ) ;
290367 wasm. extend ( & code_section) ;
291368 wasm
292369}
0 commit comments