From 10bcb3dc90c30d2f2c5d38d147ce0832a5596a88 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 20 Feb 2020 15:13:11 +0100 Subject: [PATCH] feat(interface-types) Decode instructions in WIT's text format. --- src/decoders/wat.rs | 219 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 204 insertions(+), 15 deletions(-) diff --git a/src/decoders/wat.rs b/src/decoders/wat.rs index 1c85e3f..b3f3996 100644 --- a/src/decoders/wat.rs +++ b/src/decoders/wat.rs @@ -2,10 +2,10 @@ #![allow(unused)] -use crate::ast::*; +use crate::{ast::*, interpreter::Instruction}; use wast::{ parser::{Cursor, Parse, Parser, Peek, Result}, - Id, + Id, LParen, }; mod kw { @@ -14,13 +14,38 @@ mod kw { kw::{anyref, export, f32, f64, func, i32, i64, import, param, result}, }; + // New keywords. custom_keyword!(adapt); custom_keyword!(forward); + + // New types. custom_keyword!(int); custom_keyword!(float); custom_keyword!(any); custom_keyword!(string); custom_keyword!(seq); + + // Instructions. + custom_keyword!(argument_get = "arg.get"); + custom_keyword!(call); + custom_keyword!(call_export = "call-export"); + custom_keyword!(read_utf8 = "read-utf8"); + custom_keyword!(write_utf8 = "write-utf8"); + custom_keyword!(as_wasm = "as-wasm"); + custom_keyword!(as_interface = "as-interface"); + custom_keyword!(table_ref_add = "table-ref-add"); + custom_keyword!(table_ref_get = "table-ref-get"); + custom_keyword!(call_method = "call-method"); + custom_keyword!(make_record = "make-record"); + custom_keyword!(get_field = "get-field"); + custom_keyword!(r#const = "const"); + custom_keyword!(fold_seq = "fold-seq"); + custom_keyword!(add); + custom_keyword!(mem_to_seq = "mem-to-seq"); + custom_keyword!(load); + custom_keyword!(seq_new = "seq.new"); + custom_keyword!(list_push = "list.push"); + custom_keyword!(repeat_until = "repeat-until"); } /// Issue: Uppercased keyword aren't supported for the moment. @@ -74,6 +99,104 @@ impl Parse<'_> for InterfaceType { } } +impl<'a> Parse<'a> for Instruction<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut lookahead = parser.lookahead1(); + + if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::ArgumentGet { + index: parser.parse()?, + }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::Call { + function_index: parser.parse::()? as usize, + }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::CallExport { + export_name: parser.parse()?, + }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::ReadUtf8) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::WriteUtf8 { + allocator_name: parser.parse()?, + }) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::AsWasm(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::AsInterface(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::TableRefAdd) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::TableRefGet) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::CallMethod(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::MakeRecord(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::GetField(parser.parse()?, parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::Const(parser.parse()?, parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::FoldSeq(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::Add(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::MemToSeq(parser.parse()?, parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::Load(parser.parse()?, parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::SeqNew(parser.parse()?)) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::ListPush) + } else if lookahead.peek::() { + parser.parse::()?; + + Ok(Instruction::RepeatUntil(parser.parse()?, parser.parse()?)) + } else { + Err(lookahead.error()) + } + } +} + struct AtInterface; impl Peek for AtInterface { @@ -250,13 +373,18 @@ impl<'a> Parse<'a> for Adapter<'a> { })?; let mut input_types = vec![]; let mut output_types = vec![]; + let mut instructions = vec![]; while !parser.is_empty() { - let function_type = parser.parse::()?; + if parser.peek::() { + let function_type = parser.parse::()?; - match function_type { - FunctionType::Input(mut inputs) => input_types.append(&mut inputs), - FunctionType::Output(mut outputs) => output_types.append(&mut outputs), + match function_type { + FunctionType::Input(mut inputs) => input_types.append(&mut inputs), + FunctionType::Output(mut outputs) => output_types.append(&mut outputs), + } + } else { + instructions.push(parser.parse()?); } } @@ -266,14 +394,14 @@ impl<'a> Parse<'a> for Adapter<'a> { name, input_types, output_types, - instructions: vec![], + instructions, }, AdapterKind::Export => Adapter::Export { name, input_types, output_types, - instructions: vec![], + instructions, }, _ => unimplemented!("Adapter of kind “helper” is not implemented yet."), @@ -344,10 +472,69 @@ mod tests { assert_eq!(inputs.len(), outputs.len()); - for (nth, input) in inputs.iter().enumerate() { + for (input, output) in inputs.iter().zip(outputs.iter()) { assert_eq!( - parser::parse::(&buffer(input)).unwrap(), - outputs[nth] + &parser::parse::(&buffer(input)).unwrap(), + output + ); + } + } + + #[test] + fn test_instructions() { + let inputs = vec![ + "arg.get 7", + "call 7", + r#"call-export "foo""#, + "read-utf8", + r#"write-utf8 "foo""#, + "as-wasm int", + "as-interface anyref", + "table-ref-add", + "table-ref-get", + "call-method 7", + "make-record int", + "get-field int 7", + "const i32 7", + "fold-seq 7", + "add int", + r#"mem-to-seq int "foo""#, + r#"load int "foo""#, + "seq.new int", + "list.push", + "repeat-until 1 2", + ]; + let outputs = vec![ + Instruction::ArgumentGet { index: 7 }, + Instruction::Call { function_index: 7 }, + Instruction::CallExport { export_name: "foo" }, + Instruction::ReadUtf8, + Instruction::WriteUtf8 { + allocator_name: "foo", + }, + Instruction::AsWasm(InterfaceType::Int), + Instruction::AsInterface(InterfaceType::AnyRef), + Instruction::TableRefAdd, + Instruction::TableRefGet, + Instruction::CallMethod(7), + Instruction::MakeRecord(InterfaceType::Int), + Instruction::GetField(InterfaceType::Int, 7), + Instruction::Const(InterfaceType::I32, 7), + Instruction::FoldSeq(7), + Instruction::Add(InterfaceType::Int), + Instruction::MemToSeq(InterfaceType::Int, "foo"), + Instruction::Load(InterfaceType::Int, "foo"), + Instruction::SeqNew(InterfaceType::Int), + Instruction::ListPush, + Instruction::RepeatUntil(1, 2), + ]; + + assert_eq!(inputs.len(), outputs.len()); + + for (input, output) in inputs.iter().zip(outputs.iter()) { + assert_eq!( + &parser::parse::(&buffer(input)).unwrap(), + output ); } } @@ -540,9 +727,11 @@ mod tests { (@interface func $ns_bar (import "ns" "bar")) (@interface adapt (import "ns" "foo") - (param i32)) + (param i32) + arg.get 42) -(@interface adapt (export "bar")) +(@interface adapt (export "bar") + arg.get 42) (@interface forward (export "main"))"#, ); @@ -580,13 +769,13 @@ mod tests { name: "foo", input_types: vec![InterfaceType::I32], output_types: vec![], - instructions: vec![], + instructions: vec![Instruction::ArgumentGet { index: 42 }], }, Adapter::Export { name: "bar", input_types: vec![], output_types: vec![], - instructions: vec![], + instructions: vec![Instruction::ArgumentGet { index: 42 }], }, ], forwards: vec![Forward { name: "main" }],