use crate::ast::{self, kw};
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
#[allow(missing_docs)]
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
pub enum ValType {
I32,
I64,
F32,
F64,
Anyref,
Funcref,
V128,
}
impl<'a> Parse<'a> for ValType {
fn parse(parser: Parser<'a>) -> Result<Self> {
let mut l = parser.lookahead1();
if l.peek::<kw::i32>() {
parser.parse::<kw::i32>()?;
Ok(ValType::I32)
} else if l.peek::<kw::i64>() {
parser.parse::<kw::i64>()?;
Ok(ValType::I64)
} else if l.peek::<kw::f32>() {
parser.parse::<kw::f32>()?;
Ok(ValType::F32)
} else if l.peek::<kw::f64>() {
parser.parse::<kw::f64>()?;
Ok(ValType::F64)
} else if l.peek::<kw::anyref>() {
parser.parse::<kw::anyref>()?;
Ok(ValType::Anyref)
} else if l.peek::<kw::funcref>() {
parser.parse::<kw::funcref>()?;
Ok(ValType::Funcref)
} else if l.peek::<kw::v128>() {
parser.parse::<kw::v128>()?;
Ok(ValType::V128)
} else {
Err(l.error())
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct GlobalType {
pub ty: ValType,
pub mutable: bool,
}
impl<'a> Parse<'a> for GlobalType {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek2::<kw::r#mut>() {
parser.parens(|p| {
p.parse::<kw::r#mut>()?;
Ok(GlobalType {
ty: parser.parse()?,
mutable: true,
})
})
} else {
Ok(GlobalType {
ty: parser.parse()?,
mutable: false,
})
}
}
}
#[derive(Copy, Clone, Debug)]
pub enum TableElemType {
Funcref,
Anyref,
}
impl<'a> Parse<'a> for TableElemType {
fn parse(parser: Parser<'a>) -> Result<Self> {
if parser.peek::<kw::anyfunc>() {
parser.parse::<kw::anyfunc>()?;
return Ok(TableElemType::Funcref);
}
let mut l = parser.lookahead1();
if l.peek::<kw::funcref>() {
parser.parse::<kw::funcref>()?;
Ok(TableElemType::Funcref)
} else if l.peek::<kw::anyref>() {
parser.parse::<kw::anyref>()?;
Ok(TableElemType::Anyref)
} else {
Err(l.error())
}
}
}
impl Peek for TableElemType {
fn peek(cursor: Cursor<'_>) -> bool {
kw::funcref::peek(cursor)
|| kw::anyref::peek(cursor)
|| kw::anyfunc::peek(cursor)
}
fn display() -> &'static str {
"table element type"
}
}
#[derive(Copy, Clone, Debug)]
pub struct Limits {
pub min: u32,
pub max: Option<u32>,
}
impl<'a> Parse<'a> for Limits {
fn parse(parser: Parser<'a>) -> Result<Self> {
let min = parser.parse()?;
let max = if parser.peek::<u32>() {
Some(parser.parse()?)
} else {
None
};
Ok(Limits { min, max })
}
}
#[derive(Copy, Clone, Debug)]
pub struct TableType {
pub limits: Limits,
pub elem: TableElemType,
}
impl<'a> Parse<'a> for TableType {
fn parse(parser: Parser<'a>) -> Result<Self> {
Ok(TableType {
limits: parser.parse()?,
elem: parser.parse()?,
})
}
}
#[derive(Copy, Clone, Debug)]
pub struct MemoryType {
pub limits: Limits,
pub shared: bool,
}
impl<'a> Parse<'a> for MemoryType {
fn parse(parser: Parser<'a>) -> Result<Self> {
let limits: Limits = parser.parse()?;
let shared = parser.parse::<Option<kw::shared>>()?.is_some();
Ok(MemoryType { limits, shared })
}
}
#[derive(Clone, Debug)]
pub struct FunctionType<'a> {
pub params: Vec<(Option<ast::Id<'a>>, ValType)>,
pub results: Vec<ValType>,
}
impl<'a> FunctionType<'a> {
fn finish_parse(&mut self, allow_names: bool, parser: Parser<'a>) -> Result<()> {
while parser.peek2::<kw::param>() || parser.peek2::<kw::result>() {
parser.parens(|p| {
let mut l = p.lookahead1();
if l.peek::<kw::param>() {
if self.results.len() > 0 {
return Err(p.error(
"result before parameter (or unexpected token): \
cannot list params after results",
));
}
p.parse::<kw::param>()?;
if p.is_empty() {
return Ok(());
}
let id = if allow_names {
p.parse::<Option<_>>()?
} else {
None
};
let parse_more = id.is_none();
let ty = p.parse()?;
self.params.push((id, ty));
while parse_more && !p.is_empty() {
self.params.push((None, p.parse()?));
}
} else if l.peek::<kw::result>() {
p.parse::<kw::result>()?;
while !p.is_empty() {
self.results.push(p.parse()?);
}
} else {
return Err(l.error());
}
Ok(())
})?;
}
Ok(())
}
}
impl<'a> Parse<'a> for FunctionType<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::func>()?;
let mut ret = FunctionType {
params: Vec::new(),
results: Vec::new(),
};
ret.finish_parse(true, parser)?;
Ok(ret)
}
}
#[derive(Debug)]
pub struct Type<'a> {
pub name: Option<ast::Id<'a>>,
pub func: FunctionType<'a>,
}
impl<'a> Parse<'a> for Type<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
parser.parse::<kw::r#type>()?;
let name = parser.parse()?;
let func = parser.parens(FunctionType::parse)?;
Ok(Type { name, func })
}
}
#[derive(Clone, Debug)]
pub struct TypeUse<'a> {
pub index_span: Option<ast::Span>,
pub index: Option<ast::Index<'a>>,
pub ty: ast::FunctionType<'a>,
}
impl<'a> TypeUse<'a> {
pub fn parse_no_names(parser: Parser<'a>) -> Result<Self> {
TypeUse::parse_allow_names(parser, false)
}
fn parse_allow_names(parser: Parser<'a>, allow_names: bool) -> Result<Self> {
let index = if parser.peek2::<kw::r#type>() {
Some(parser.parens(|parser| {
parser.parse::<kw::r#type>()?;
Ok((parser.cur_span(), parser.parse()?))
})?)
} else {
None
};
let (index_span, index) = match index {
Some((a, b)) => (Some(a), Some(b)),
None => (None, None),
};
let mut ty = FunctionType {
params: Vec::new(),
results: Vec::new(),
};
if parser.peek2::<kw::param>() || parser.peek2::<kw::result>() {
ty.finish_parse(allow_names, parser)?;
}
Ok(TypeUse {
index,
index_span,
ty,
})
}
}
impl<'a> Parse<'a> for TypeUse<'a> {
fn parse(parser: Parser<'a>) -> Result<Self> {
TypeUse::parse_allow_names(parser, true)
}
}