Skip to content

Commit 6de7fe4

Browse files
committed
Add bindings PoC
- added second parameter to calc: `x` and `yy` are now hard-coded - disassembled some more of the WASM byte code - improved code generation somewhat
1 parent 4b7b1e0 commit 6de7fe4

2 files changed

Lines changed: 115 additions & 37 deletions

File tree

src/ast.rs

Lines changed: 112 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ use crate::token::Tokenizer;
44

55
use 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+
715
pub(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{}\ni32.add", l.to_wat(), r.to_wat()),
3543
Self::Subtract(l, r) => format!("{}\n{}\ni32.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{}\ni32.mul", l.to_wat(), r.to_wat()),
8999
Self::Divide(l, r) => format!("{}\n{}\ni32.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
}

src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
mod ast;
22
mod token;
33

4-
use crate::ast::{Expr, add_fluff, generate_wasm};
4+
use crate::ast::{Expr, add_fluff, Bindings, generate_wasm};
55
use crate::token::Tokenizer;
66

77
use wasmtime::{Caller, Engine, Func, Instance, Module, Result, Store};
@@ -47,7 +47,8 @@ fn eval_wat(expr: &Expr) -> Result<i32> {
4747
}
4848

4949
fn eval_wasm(expr: &Expr) -> Result<i32>{
50-
let wasm = generate_wasm(expr);
50+
let bindings: &Bindings = &[ "x".to_string(), "yy".to_string() ];
51+
let wasm = generate_wasm(expr, bindings);
5152
let engine = Engine::default();
5253
let module = Module::new(&engine, wasm)?;
5354

0 commit comments

Comments
 (0)