feat(interface-types) Parse Import in the WAT decoders.

This commit is contained in:
Ivan Enderlin 2020-02-19 17:20:18 +01:00
parent c97122899d
commit 2e78cf1fc0

View File

@ -7,11 +7,11 @@ use nom::{
branch::alt,
bytes::complete::{escaped, tag, take_while1},
character::complete::{alphanumeric1, char, one_of},
combinator::{cut, opt, value},
combinator::{cut, map, opt, value},
error::ParseError,
multi::many0,
sequence::{delimited, preceded, terminated, tuple},
IResult,
AsChar, IResult,
};
/// Parse a whitespace.
@ -82,24 +82,22 @@ fn result<'input, E: ParseError<&'input str>>(
fn export<'input, E: ParseError<&'input str>>(
input: &'input str,
) -> IResult<&'input str, Export, E> {
//(@interface export "name")
let (remains, (export_name, input_types, output_types)): (
&str,
(&str, Option<Vec<InterfaceType>>, Option<Vec<InterfaceType>>),
) = delimited(
char('('),
preceded(
opt(whitespace),
map(
delimited(
char('('),
preceded(
tag("@interface"),
opt(whitespace),
preceded(
whitespace,
tag("@interface"),
preceded(
tag("export"),
whitespace,
preceded(
whitespace,
tag("export"),
tuple((
preceded(char('"'), cut(terminated(string, char('"')))),
preceded(
whitespace,
preceded(char('"'), cut(terminated(string, char('"')))),
),
opt(preceded(whitespace, param)),
opt(preceded(whitespace, result)),
)),
@ -107,18 +105,86 @@ fn export<'input, E: ParseError<&'input str>>(
),
),
),
char(')'),
),
char(')'),
)(input)?;
Ok((
remains,
Export {
name: export_name,
|(name, input_types, output_types)| Export {
name,
input_types: input_types.unwrap_or_else(|| vec![]),
output_types: output_types.unwrap_or_else(|| vec![]),
},
))
)(input)
}
/// Parse a `(import …)`.
fn import_qualifier<'input, E: ParseError<&'input str>>(
input: &'input str,
) -> IResult<&'input str, (&'input str, &'input str), E> {
delimited(
char('('),
preceded(
opt(whitespace),
preceded(
tag("import"),
tuple((
preceded(
whitespace,
preceded(char('"'), cut(terminated(string, char('"')))),
),
preceded(
whitespace,
preceded(char('"'), cut(terminated(string, char('"')))),
),
)),
),
),
char(')'),
)(input)
}
/// Parse a `$…`.
fn index_variable<'input, E: ParseError<&'input str>>(
input: &'input str,
) -> IResult<&'input str, &'input str, E> {
preceded(
char('$'),
take_while1(move |c: char| c.is_alphanum() || c == '_'),
)(input)
}
/// Parse an `Import`.
fn import<'input, E: ParseError<&'input str>>(
input: &'input str,
) -> IResult<&'input str, Import, E> {
map(
delimited(
char('('),
preceded(
opt(whitespace),
preceded(
tag("@interface"),
preceded(
whitespace,
preceded(
tag("func"),
tuple((
opt(preceded(whitespace, index_variable)),
preceded(whitespace, import_qualifier),
opt(preceded(whitespace, param)),
opt(preceded(whitespace, result)),
)),
),
),
),
),
char(')'),
),
|(_index, (namespace, name), input_types, output_types)| Import {
namespace,
name,
input_types: input_types.unwrap_or_else(|| vec![]),
output_types: output_types.unwrap_or_else(|| vec![]),
},
)(input)
}
#[cfg(test)]
@ -239,4 +305,90 @@ mod tests {
assert_eq!(export::<()>(input), Ok(("", output)));
}
#[test]
fn test_export_escaped_name() {
let input = r#"(@interface export "fo\"o")"#;
let output = Export {
name: r#"fo\"o"#,
input_types: vec![],
output_types: vec![],
};
assert_eq!(export::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_qualifier() {
let input = r#"(import "ns" "name")"#;
let output = ("ns", "name");
assert_eq!(import_qualifier::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_with_no_param_no_result() {
let input = r#"(@interface func $ns_foo (import "ns" "foo"))"#;
let output = Import {
namespace: "ns",
name: "foo",
input_types: vec![],
output_types: vec![],
};
assert_eq!(import::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_with_no_index_variable_no_param_no_result() {
let input = r#"(@interface func (import "ns" "foo"))"#;
let output = Import {
namespace: "ns",
name: "foo",
input_types: vec![],
output_types: vec![],
};
assert_eq!(import::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_with_some_param_no_result() {
let input = r#"(@interface func $ns_foo (import "ns" "foo") (param i32))"#;
let output = Import {
namespace: "ns",
name: "foo",
input_types: vec![InterfaceType::I32],
output_types: vec![],
};
assert_eq!(import::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_with_no_param_some_result() {
let input = r#"(@interface func $ns_foo (import "ns" "foo") (result i32))"#;
let output = Import {
namespace: "ns",
name: "foo",
input_types: vec![],
output_types: vec![InterfaceType::I32],
};
assert_eq!(import::<()>(input), Ok(("", output)));
}
#[test]
fn test_import_with_some_param_some_result() {
let input =
r#"(@interface func $ns_foo (import "ns" "foo") (param String) (result i32 i32))"#;
let output = Import {
namespace: "ns",
name: "foo",
input_types: vec![InterfaceType::String],
output_types: vec![InterfaceType::I32, InterfaceType::I32],
};
assert_eq!(import::<()>(input), Ok(("", output)));
}
}