use super::{
parse_delimited, parse_optional, parse_token, DocComment, Error, Ident, Lookahead, PackagePath,
Parse, ParseResult, Peek,
};
use crate::lexer::{Lexer, Token};
use miette::SourceSpan;
use serde::Serialize;
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TypeStatement<'a> {
Interface(InterfaceDecl<'a>),
World(WorldDecl<'a>),
Type(TypeDecl<'a>),
}
impl<'a> Parse<'a> for TypeStatement<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if InterfaceDecl::peek(&mut lookahead) {
Ok(Self::Interface(Parse::parse(lexer)?))
} else if WorldDecl::peek(&mut lookahead) {
Ok(Self::World(Parse::parse(lexer)?))
} else if TypeDecl::peek(&mut lookahead) {
Ok(Self::Type(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for TypeStatement<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::InterfaceKeyword)
|| lookahead.peek(Token::WorldKeyword)
|| TypeDecl::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TypeDecl<'a> {
Variant(VariantDecl<'a>),
Record(RecordDecl<'a>),
Flags(FlagsDecl<'a>),
Enum(EnumDecl<'a>),
Alias(TypeAlias<'a>),
}
impl TypeDecl<'_> {
pub fn id(&self) -> &Ident {
match self {
Self::Variant(variant) => &variant.id,
Self::Record(record) => &record.id,
Self::Flags(flags) => &flags.id,
Self::Enum(e) => &e.id,
Self::Alias(alias) => &alias.id,
}
}
}
impl<'a> Parse<'a> for TypeDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::VariantKeyword) {
Ok(Self::Variant(Parse::parse(lexer)?))
} else if lookahead.peek(Token::RecordKeyword) {
Ok(Self::Record(Parse::parse(lexer)?))
} else if lookahead.peek(Token::FlagsKeyword) {
Ok(Self::Flags(Parse::parse(lexer)?))
} else if lookahead.peek(Token::EnumKeyword) {
Ok(Self::Enum(Parse::parse(lexer)?))
} else if lookahead.peek(Token::TypeKeyword) {
Ok(Self::Alias(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for TypeDecl<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::VariantKeyword)
|| lookahead.peek(Token::RecordKeyword)
|| lookahead.peek(Token::FlagsKeyword)
|| lookahead.peek(Token::EnumKeyword)
|| lookahead.peek(Token::TypeKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ResourceDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub methods: Vec<ResourceMethod<'a>>,
}
impl<'a> Parse<'a> for ResourceDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::ResourceKeyword)?;
let id = Ident::parse(lexer)?;
let mut lookahead = Lookahead::new(lexer);
let methods = if lookahead.peek(Token::Semicolon) {
lexer.next();
Default::default()
} else if lookahead.peek(Token::OpenBrace) {
parse_token(lexer, Token::OpenBrace)?;
let methods = parse_delimited(lexer, Token::CloseBrace, false)?;
parse_token(lexer, Token::CloseBrace)?;
methods
} else {
return Err(lookahead.error());
};
Ok(Self { docs, id, methods })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VariantDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub cases: Vec<VariantCase<'a>>,
}
impl<'a> Parse<'a> for VariantDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::VariantKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let cases = parse_delimited(lexer, Token::CloseBrace, true)?;
let close = parse_token(lexer, Token::CloseBrace)?;
if cases.is_empty() {
return Err(Error::EmptyType {
ty: "variant",
kind: "case",
span: close,
});
}
Ok(Self { docs, id, cases })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct VariantCase<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub ty: Option<Type<'a>>,
}
impl<'a> Parse<'a> for VariantCase<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let id = Ident::parse(lexer)?;
let ty = parse_optional(lexer, Token::OpenParen, |lexer| {
let ty = Parse::parse(lexer)?;
parse_token(lexer, Token::CloseParen)?;
Ok(ty)
})?;
Ok(Self { docs, id, ty })
}
}
impl Peek for VariantCase<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::Ident)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RecordDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub fields: Vec<Field<'a>>,
}
impl<'a> Parse<'a> for RecordDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::RecordKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let fields = parse_delimited(lexer, Token::CloseBrace, true)?;
let close = parse_token(lexer, Token::CloseBrace)?;
if fields.is_empty() {
return Err(Error::EmptyType {
ty: "record",
kind: "field",
span: close,
});
}
Ok(Self { docs, id, fields })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Field<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub ty: Type<'a>,
}
impl<'a> Parse<'a> for Field<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let named: NamedType = Parse::parse(lexer)?;
Ok(Self {
docs,
id: named.id,
ty: named.ty,
})
}
}
impl Peek for Field<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
NamedType::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FlagsDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub flags: Vec<Flag<'a>>,
}
impl<'a> Parse<'a> for FlagsDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::FlagsKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let flags = parse_delimited(lexer, Token::CloseBrace, true)?;
let close = parse_token(lexer, Token::CloseBrace)?;
if flags.is_empty() {
return Err(Error::EmptyType {
ty: "flags",
kind: "flag",
span: close,
});
}
Ok(Self { docs, id, flags })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Flag<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
}
impl<'a> Parse<'a> for Flag<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let id = Ident::parse(lexer)?;
Ok(Self { docs, id })
}
}
impl Peek for Flag<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::Ident)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EnumDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub cases: Vec<EnumCase<'a>>,
}
impl<'a> Parse<'a> for EnumDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::EnumKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let cases = parse_delimited(lexer, Token::CloseBrace, true)?;
let close = parse_token(lexer, Token::CloseBrace)?;
if cases.is_empty() {
return Err(Error::EmptyType {
ty: "enum",
kind: "case",
span: close,
});
}
Ok(Self { docs, id, cases })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct EnumCase<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
}
impl<'a> Parse<'a> for EnumCase<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let id = Ident::parse(lexer)?;
Ok(Self { docs, id })
}
}
impl Peek for EnumCase<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::Ident)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ResourceMethod<'a> {
Constructor(Constructor<'a>),
Method(Method<'a>),
}
impl<'a> Parse<'a> for ResourceMethod<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::ConstructorKeyword) {
Ok(Self::Constructor(Parse::parse(lexer)?))
} else if Ident::peek(&mut lookahead) {
Ok(Self::Method(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for ResourceMethod<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::ConstructorKeyword) || Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Constructor<'a> {
pub docs: Vec<DocComment<'a>>,
pub span: SourceSpan,
pub params: Vec<NamedType<'a>>,
}
impl<'a> Parse<'a> for Constructor<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let span = parse_token(lexer, Token::ConstructorKeyword)?;
parse_token(lexer, Token::OpenParen)?;
let params = parse_delimited(lexer, Token::CloseParen, true)?;
parse_token(lexer, Token::CloseParen)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, span, params })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Method<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub is_static: bool,
pub ty: FuncType<'a>,
}
impl<'a> Parse<'a> for Method<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::Colon)?;
let is_static = lexer
.peek()
.map(|(r, _)| matches!(r, Ok(Token::StaticKeyword)))
.unwrap_or(false);
if is_static {
lexer.next();
}
let ty = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self {
docs,
id,
is_static,
ty,
})
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum FuncTypeRef<'a> {
Func(FuncType<'a>),
Ident(Ident<'a>),
}
impl<'a> Parse<'a> for FuncTypeRef<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::FuncKeyword) {
Ok(Self::Func(Parse::parse(lexer)?))
} else if Ident::peek(&mut lookahead) {
Ok(Self::Ident(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FuncType<'a> {
pub params: Vec<NamedType<'a>>,
pub results: ResultList<'a>,
}
impl<'a> Parse<'a> for FuncType<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
parse_token(lexer, Token::FuncKeyword)?;
parse_token(lexer, Token::OpenParen)?;
let params = parse_delimited(lexer, Token::CloseParen, true)?;
parse_token(lexer, Token::CloseParen)?;
let results =
parse_optional(lexer, Token::Arrow, Parse::parse)?.unwrap_or(ResultList::Empty);
Ok(Self { params, results })
}
}
impl Peek for FuncType<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::FuncKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ResultList<'a> {
Empty,
Scalar(Type<'a>),
Named(Vec<NamedType<'a>>),
}
impl<'a> Parse<'a> for ResultList<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::OpenParen) {
parse_token(lexer, Token::OpenParen)?;
let results = parse_delimited(lexer, Token::CloseParen, true)?;
parse_token(lexer, Token::CloseParen)?;
Ok(Self::Named(results))
} else if Type::peek(&mut lookahead) {
Ok(Self::Scalar(Parse::parse(lexer)?))
} else {
Ok(Self::Empty)
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NamedType<'a> {
pub id: Ident<'a>,
pub ty: Type<'a>,
}
impl<'a> Parse<'a> for NamedType<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::Colon)?;
let ty = Parse::parse(lexer)?;
Ok(Self { id, ty })
}
}
impl Peek for NamedType<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TypeAlias<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub kind: TypeAliasKind<'a>,
}
impl<'a> Parse<'a> for TypeAlias<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::TypeKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::Equals)?;
let kind = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, id, kind })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TypeAliasKind<'a> {
Func(FuncType<'a>),
Type(Type<'a>),
}
impl<'a> Parse<'a> for TypeAliasKind<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::FuncKeyword) {
Ok(Self::Func(Parse::parse(lexer)?))
} else if Type::peek(&mut lookahead) {
Ok(Self::Type(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum Type<'a> {
U8(SourceSpan),
S8(SourceSpan),
U16(SourceSpan),
S16(SourceSpan),
U32(SourceSpan),
S32(SourceSpan),
U64(SourceSpan),
S64(SourceSpan),
F32(SourceSpan),
F64(SourceSpan),
Char(SourceSpan),
Bool(SourceSpan),
String(SourceSpan),
Tuple(Vec<Type<'a>>, SourceSpan),
List(Box<Type<'a>>, SourceSpan),
Option(Box<Type<'a>>, SourceSpan),
Result {
ok: Option<Box<Type<'a>>>,
err: Option<Box<Type<'a>>>,
span: SourceSpan,
},
Borrow(Ident<'a>, SourceSpan),
Ident(Ident<'a>),
}
impl<'a> Type<'a> {
pub fn span(&self) -> SourceSpan {
match self {
Self::U8(span)
| Self::S8(span)
| Self::U16(span)
| Self::S16(span)
| Self::U32(span)
| Self::S32(span)
| Self::U64(span)
| Self::S64(span)
| Self::F32(span)
| Self::F64(span)
| Self::Char(span)
| Self::Bool(span)
| Self::String(span)
| Self::Tuple(_, span)
| Self::List(_, span)
| Self::Option(_, span)
| Self::Result { span, .. }
| Self::Borrow(_, span) => *span,
Self::Ident(ident) => ident.span,
}
}
}
impl<'a> Parse<'a> for Type<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::U8Keyword) {
Ok(Self::U8(lexer.next().unwrap().1))
} else if lookahead.peek(Token::S8Keyword) {
Ok(Self::S8(lexer.next().unwrap().1))
} else if lookahead.peek(Token::U16Keyword) {
Ok(Self::U16(lexer.next().unwrap().1))
} else if lookahead.peek(Token::S16Keyword) {
Ok(Self::S16(lexer.next().unwrap().1))
} else if lookahead.peek(Token::U32Keyword) {
Ok(Self::U32(lexer.next().unwrap().1))
} else if lookahead.peek(Token::S32Keyword) {
Ok(Self::S32(lexer.next().unwrap().1))
} else if lookahead.peek(Token::U64Keyword) {
Ok(Self::U64(lexer.next().unwrap().1))
} else if lookahead.peek(Token::S64Keyword) {
Ok(Self::S64(lexer.next().unwrap().1))
} else if lookahead.peek(Token::F32Keyword) {
Ok(Self::F32(lexer.next().unwrap().1))
} else if lookahead.peek(Token::F64Keyword) {
Ok(Self::F64(lexer.next().unwrap().1))
} else if lookahead.peek(Token::CharKeyword) {
Ok(Self::Char(lexer.next().unwrap().1))
} else if lookahead.peek(Token::BoolKeyword) {
Ok(Self::Bool(lexer.next().unwrap().1))
} else if lookahead.peek(Token::StringKeyword) {
Ok(Self::String(lexer.next().unwrap().1))
} else if lookahead.peek(Token::TupleKeyword) {
let span = lexer.next().unwrap().1;
parse_token(lexer, Token::OpenAngle)?;
let mut lookahead = Lookahead::new(lexer);
if !Type::peek(&mut lookahead) {
return Err(lookahead.error());
}
let types = parse_delimited(lexer, Token::CloseAngle, true)?;
assert!(!types.is_empty());
let close = parse_token(lexer, Token::CloseAngle)?;
Ok(Self::Tuple(
types,
SourceSpan::new(
span.offset().into(),
(close.offset() + close.len()) - span.offset(),
),
))
} else if lookahead.peek(Token::ListKeyword) {
let span = lexer.next().unwrap().1;
parse_token(lexer, Token::OpenAngle)?;
let ty = Box::new(Parse::parse(lexer)?);
let close = parse_token(lexer, Token::CloseAngle)?;
Ok(Self::List(
ty,
SourceSpan::new(
span.offset().into(),
(close.offset() + close.len()) - span.offset(),
),
))
} else if lookahead.peek(Token::OptionKeyword) {
let span = lexer.next().unwrap().1;
parse_token(lexer, Token::OpenAngle)?;
let ty = Box::new(Parse::parse(lexer)?);
let close = parse_token(lexer, Token::CloseAngle)?;
Ok(Self::Option(
ty,
SourceSpan::new(
span.offset().into(),
(close.offset() + close.len()) - span.offset(),
),
))
} else if lookahead.peek(Token::ResultKeyword) {
let mut span = lexer.next().unwrap().1;
let parse = |lexer: &mut Lexer<'a>| {
let mut lookahead = Lookahead::new(lexer);
let ok = if lookahead.peek(Token::Underscore) {
lexer.next();
None
} else if Type::peek(&mut lookahead) {
Some(Box::new(Parse::parse(lexer)?))
} else {
return Err(lookahead.error());
};
let err = parse_optional(lexer, Token::Comma, |lexer| {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::Underscore) {
lexer.next();
Ok(None)
} else if Type::peek(&mut lookahead) {
Ok(Some(Box::new(Parse::parse(lexer)?)))
} else {
return Err(lookahead.error());
}
})?
.unwrap_or(None);
let close = parse_token(lexer, Token::CloseAngle)?;
span = SourceSpan::new(
span.offset().into(),
(close.offset() + close.len()) - span.offset(),
);
Ok((ok, err))
};
let (ok, err) = match parse_optional(lexer, Token::OpenAngle, parse)? {
Some((ok, err)) => (ok, err),
None => (None, None),
};
Ok(Self::Result { ok, err, span })
} else if lookahead.peek(Token::BorrowKeyword) {
let span = lexer.next().unwrap().1;
parse_token(lexer, Token::OpenAngle)?;
let id = Parse::parse(lexer)?;
let close = parse_token(lexer, Token::CloseAngle)?;
Ok(Self::Borrow(
id,
SourceSpan::new(
span.offset().into(),
(close.offset() + close.len()) - span.offset(),
),
))
} else if Ident::peek(&mut lookahead) {
Ok(Self::Ident(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for Type<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::U8Keyword)
|| lookahead.peek(Token::S8Keyword)
|| lookahead.peek(Token::U16Keyword)
|| lookahead.peek(Token::S16Keyword)
|| lookahead.peek(Token::U32Keyword)
|| lookahead.peek(Token::S32Keyword)
|| lookahead.peek(Token::U64Keyword)
|| lookahead.peek(Token::S64Keyword)
|| lookahead.peek(Token::F32Keyword)
|| lookahead.peek(Token::F64Keyword)
|| lookahead.peek(Token::CharKeyword)
|| lookahead.peek(Token::BoolKeyword)
|| lookahead.peek(Token::StringKeyword)
|| lookahead.peek(Token::TupleKeyword)
|| lookahead.peek(Token::ListKeyword)
|| lookahead.peek(Token::OptionKeyword)
|| lookahead.peek(Token::ResultKeyword)
|| lookahead.peek(Token::BorrowKeyword)
|| Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ItemTypeDecl<'a> {
Resource(ResourceDecl<'a>),
Variant(VariantDecl<'a>),
Record(RecordDecl<'a>),
Flags(FlagsDecl<'a>),
Enum(EnumDecl<'a>),
Alias(TypeAlias<'a>),
}
impl<'a> Parse<'a> for ItemTypeDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if lookahead.peek(Token::ResourceKeyword) {
Ok(Self::Resource(Parse::parse(lexer)?))
} else if lookahead.peek(Token::VariantKeyword) {
Ok(Self::Variant(Parse::parse(lexer)?))
} else if lookahead.peek(Token::RecordKeyword) {
Ok(Self::Record(Parse::parse(lexer)?))
} else if lookahead.peek(Token::FlagsKeyword) {
Ok(Self::Flags(Parse::parse(lexer)?))
} else if lookahead.peek(Token::EnumKeyword) {
Ok(Self::Enum(Parse::parse(lexer)?))
} else if lookahead.peek(Token::TypeKeyword) {
Ok(Self::Alias(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for ItemTypeDecl<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::ResourceKeyword)
|| lookahead.peek(Token::VariantKeyword)
|| lookahead.peek(Token::RecordKeyword)
|| lookahead.peek(Token::FlagsKeyword)
|| lookahead.peek(Token::EnumKeyword)
|| lookahead.peek(Token::TypeKeyword)
}
}
impl ItemTypeDecl<'_> {
pub fn id(&self) -> &Ident {
match self {
Self::Resource(resource) => &resource.id,
Self::Variant(variant) => &variant.id,
Self::Record(record) => &record.id,
Self::Flags(flags) => &flags.id,
Self::Enum(e) => &e.id,
Self::Alias(alias) => &alias.id,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InterfaceDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub items: Vec<InterfaceItem<'a>>,
}
impl<'a> Parse<'a> for InterfaceDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::InterfaceKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let items = parse_delimited(lexer, Token::CloseBrace, false)?;
parse_token(lexer, Token::CloseBrace)?;
Ok(Self { docs, id, items })
}
}
impl Peek for InterfaceDecl<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::InterfaceKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum InterfaceItem<'a> {
Use(Box<Use<'a>>),
Type(ItemTypeDecl<'a>),
Export(InterfaceExport<'a>),
}
impl<'a> Parse<'a> for InterfaceItem<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if Use::peek(&mut lookahead) {
Ok(Self::Use(Box::new(Parse::parse(lexer)?)))
} else if InterfaceExport::peek(&mut lookahead) {
Ok(Self::Export(Parse::parse(lexer)?))
} else if ItemTypeDecl::peek(&mut lookahead) {
Ok(Self::Type(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for InterfaceItem<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Use::peek(lookahead) || InterfaceExport::peek(lookahead) || ItemTypeDecl::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Use<'a> {
pub docs: Vec<DocComment<'a>>,
pub path: UsePath<'a>,
pub items: Vec<UseItem<'a>>,
}
impl<'a> Parse<'a> for Use<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::UseKeyword)?;
let path = Parse::parse(lexer)?;
parse_token(lexer, Token::Dot)?;
parse_token(lexer, Token::OpenBrace)?;
let items = parse_delimited(lexer, Token::CloseBrace, true)?;
parse_token(lexer, Token::CloseBrace)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, path, items })
}
}
impl Peek for Use<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::UseKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum UsePath<'a> {
Package(PackagePath<'a>),
Ident(Ident<'a>),
}
impl<'a> Parse<'a> for UsePath<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if PackagePath::peek(&mut lookahead) {
Ok(Self::Package(Parse::parse(lexer)?))
} else if Ident::peek(&mut lookahead) {
Ok(Self::Ident(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for UsePath<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
PackagePath::peek(lookahead) | Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UseItem<'a> {
pub id: Ident<'a>,
pub as_id: Option<Ident<'a>>,
}
impl<'a> Parse<'a> for UseItem<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let id = Ident::parse(lexer)?;
let as_id = parse_optional(lexer, Token::AsKeyword, Ident::parse)?;
Ok(Self { id, as_id })
}
}
impl Peek for UseItem<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InterfaceExport<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub ty: FuncTypeRef<'a>,
}
impl<'a> Parse<'a> for InterfaceExport<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::Colon)?;
let ty = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, id, ty })
}
}
impl Peek for InterfaceExport<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Ident::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorldDecl<'a> {
pub docs: Vec<DocComment<'a>>,
pub id: Ident<'a>,
pub items: Vec<WorldItem<'a>>,
}
impl<'a> Parse<'a> for WorldDecl<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::WorldKeyword)?;
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::OpenBrace)?;
let items = parse_delimited(lexer, Token::CloseBrace, false)?;
parse_token(lexer, Token::CloseBrace)?;
Ok(Self { docs, id, items })
}
}
impl Peek for WorldDecl<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::WorldKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum WorldItem<'a> {
Use(Use<'a>),
Type(ItemTypeDecl<'a>),
Import(WorldImport<'a>),
Export(WorldExport<'a>),
Include(WorldInclude<'a>),
}
impl<'a> Parse<'a> for WorldItem<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if Use::peek(&mut lookahead) {
Ok(Self::Use(Parse::parse(lexer)?))
} else if WorldImport::peek(&mut lookahead) {
Ok(Self::Import(Parse::parse(lexer)?))
} else if WorldExport::peek(&mut lookahead) {
Ok(Self::Export(Parse::parse(lexer)?))
} else if WorldInclude::peek(&mut lookahead) {
Ok(Self::Include(Parse::parse(lexer)?))
} else if ItemTypeDecl::peek(&mut lookahead) {
Ok(Self::Type(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
impl Peek for WorldItem<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Use::peek(lookahead)
|| WorldImport::peek(lookahead)
|| WorldExport::peek(lookahead)
|| WorldInclude::peek(lookahead)
|| ItemTypeDecl::peek(lookahead)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorldImport<'a> {
pub docs: Vec<DocComment<'a>>,
pub path: WorldItemPath<'a>,
}
impl<'a> Parse<'a> for WorldImport<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::ImportKeyword)?;
let path = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, path })
}
}
impl Peek for WorldImport<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::ImportKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorldExport<'a> {
pub docs: Vec<DocComment<'a>>,
pub path: WorldItemPath<'a>,
}
impl<'a> Parse<'a> for WorldExport<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::ExportKeyword)?;
let path = Parse::parse(lexer)?;
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, path })
}
}
impl Peek for WorldExport<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::ExportKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum WorldItemPath<'a> {
Named(NamedWorldItem<'a>),
Package(PackagePath<'a>),
Ident(Ident<'a>),
}
impl<'a> Parse<'a> for WorldItemPath<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if PackagePath::peek(&mut lookahead) {
Ok(Self::Package(Parse::parse(lexer)?))
} else if Ident::peek(&mut lookahead) {
if let Some((Ok(Token::Colon), _)) = lexer.peek2() {
Ok(Self::Named(Parse::parse(lexer)?))
} else {
Ok(Self::Ident(Parse::parse(lexer)?))
}
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct NamedWorldItem<'a> {
pub id: Ident<'a>,
pub ty: ExternType<'a>,
}
impl<'a> Parse<'a> for NamedWorldItem<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let id = Ident::parse(lexer)?;
parse_token(lexer, Token::Colon)?;
let ty = Parse::parse(lexer)?;
Ok(Self { id, ty })
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum ExternType<'a> {
Ident(Ident<'a>),
Func(FuncType<'a>),
Interface(InlineInterface<'a>),
}
impl<'a> Parse<'a> for ExternType<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if Ident::peek(&mut lookahead) {
Ok(Self::Ident(Parse::parse(lexer)?))
} else if FuncType::peek(&mut lookahead) {
Ok(Self::Func(Parse::parse(lexer)?))
} else if InlineInterface::peek(&mut lookahead) {
Ok(Self::Interface(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct InlineInterface<'a> {
pub items: Vec<InterfaceItem<'a>>,
}
impl<'a> Parse<'a> for InlineInterface<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
parse_token(lexer, Token::InterfaceKeyword)?;
parse_token(lexer, Token::OpenBrace)?;
let items = parse_delimited(lexer, Token::CloseBrace, false)?;
parse_token(lexer, Token::CloseBrace)?;
Ok(Self { items })
}
}
impl Peek for InlineInterface<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::InterfaceKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorldInclude<'a> {
pub docs: Vec<DocComment<'a>>,
pub world: WorldRef<'a>,
pub with: Vec<WorldIncludeItem<'a>>,
}
impl<'a> Parse<'a> for WorldInclude<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let docs = Parse::parse(lexer)?;
parse_token(lexer, Token::IncludeKeyword)?;
let world = Parse::parse(lexer)?;
let with = parse_optional(lexer, Token::WithKeyword, |lexer| {
parse_token(lexer, Token::OpenBrace)?;
let items = parse_delimited(lexer, Token::CloseBrace, true)?;
parse_token(lexer, Token::CloseBrace)?;
Ok(items)
})?
.unwrap_or_default();
parse_token(lexer, Token::Semicolon)?;
Ok(Self { docs, world, with })
}
}
impl Peek for WorldInclude<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
lookahead.peek(Token::IncludeKeyword)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum WorldRef<'a> {
Ident(Ident<'a>),
Package(PackagePath<'a>),
}
impl<'a> WorldRef<'a> {
pub fn name(&self) -> &'a str {
match self {
Self::Ident(id) => id.string,
Self::Package(path) => path.string,
}
}
pub fn span(&self) -> SourceSpan {
match self {
Self::Ident(id) => id.span,
Self::Package(path) => path.span,
}
}
}
impl<'a> Parse<'a> for WorldRef<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let mut lookahead = Lookahead::new(lexer);
if PackagePath::peek(&mut lookahead) {
Ok(Self::Package(Parse::parse(lexer)?))
} else if Ident::peek(&mut lookahead) {
Ok(Self::Ident(Parse::parse(lexer)?))
} else {
Err(lookahead.error())
}
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WorldIncludeItem<'a> {
pub from: Ident<'a>,
pub to: Ident<'a>,
}
impl<'a> Parse<'a> for WorldIncludeItem<'a> {
fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
let from = Ident::parse(lexer)?;
parse_token(lexer, Token::AsKeyword)?;
let to = Ident::parse(lexer)?;
Ok(Self { from, to })
}
}
impl Peek for WorldIncludeItem<'_> {
fn peek(lookahead: &mut Lookahead) -> bool {
Ident::peek(lookahead)
}
}
#[cfg(test)]
mod test {
use crate::ast::test::roundtrip;
#[test]
fn resource_roundtrip() {
roundtrip(
r#"package foo:bar;
interface i { resource foo-bar {
/** A constructor */
constructor(foo: u8, bar: u8);
/// A method
foo: func() -> string;
/// A method
set-foo: func(foo: string);
/// A static method
id: static func() -> u32;
}}"#,
r#"package foo:bar;
interface i {
resource foo-bar {
/// A constructor
constructor(foo: u8, bar: u8);
/// A method
foo: func() -> string;
/// A method
set-foo: func(foo: string);
/// A static method
id: static func() -> u32;
}
}
"#,
)
.unwrap();
}
#[test]
fn variant_roundtrip() {
roundtrip(
r#"package foo:bar;
variant foo {
foo,
bar(u32),
baz(bar),
qux(tuple<u8, u16, u32>)
}"#,
r#"package foo:bar;
variant foo {
foo,
bar(u32),
baz(bar),
qux(tuple<u8, u16, u32>),
}
"#,
)
.unwrap();
}
#[test]
fn record_roundtrip() {
roundtrip(
r#"package foo:bar;
record foo-bar2-baz {
foo: foo,
bar-qux: list<string>,
// A comment
jam: borrow<foo>,
}"#,
r#"package foo:bar;
record foo-bar2-baz {
foo: foo,
bar-qux: list<string>,
jam: borrow<foo>,
}
"#,
)
.unwrap();
}
#[test]
fn flags_roundtrip() {
roundtrip(
r#"package foo:bar;
flags %flags {
foo, bar, baz
}"#,
r#"package foo:bar;
flags %flags {
foo,
bar,
baz,
}
"#,
)
.unwrap();
}
#[test]
fn enum_roundtrip() {
roundtrip(
r#"package foo:bar; enum foo {
foo, bar, baz
}"#,
r#"package foo:bar;
enum foo {
foo,
bar,
baz,
}
"#,
)
.unwrap();
}
#[test]
fn func_type_alias_roundtrip() {
roundtrip(
r#"package foo:bar; type x = func(a: /* comment */ string) -> string;"#,
"package foo:bar;\n\ntype x = func(a: string) -> string;\n",
)
.unwrap();
}
#[test]
fn type_alias_roundtrip() {
roundtrip(
r#"package foo:bar; type x = tuple<u8, s8, u16, s16, u32, s32, u64, s64, f32, f64, char, bool, string, tuple<string, list<u8>>, option<list<bool>>, result, result<string>, result<_, string>, result<u8, u8>, borrow<y>, y>;"#,
"package foo:bar;\n\ntype x = tuple<u8, s8, u16, s16, u32, s32, u64, s64, f32, f64, char, bool, string, tuple<string, list<u8>>, option<list<bool>>, result, result<string>, result<_, string>, result<u8, u8>, borrow<y>, y>;\n",
)
.unwrap();
}
#[test]
fn interface_roundtrip() {
roundtrip(
r#"package foo:bar;
interface foo {
/// Type t
type t = list<string>;
/// Use x and y
use foo.{ x, y, };
/// Function a
a: func(a: string, b: string) -> string;
// not a doc comment
type x = func() -> list<string>;
/// Function b
b: x;
}
"#,
r#"package foo:bar;
interface foo {
/// Type t
type t = list<string>;
/// Use x and y
use foo.{ x, y };
/// Function a
a: func(a: string, b: string) -> string;
type x = func() -> list<string>;
/// Function b
b: x;
}
"#,
)
.unwrap();
}
#[test]
fn world_roundtrip() {
roundtrip(
r#"package foo:bar;
world foo {
/// Type t
type t = list<string>;
// not a doc comment
type x = func() -> list<string>;
use foo.{ y, };
/// Import with function type.
import a: func(a: string, b: string) -> string;
/// Import with identifier.
import b: x;
/// Import with inline interface.
import c: interface {
/// Function a
a: func(a: string, b: string) -> string;
};
/// Import with package path
import foo:bar/baz@1.0.0;
/// Export with function type.
export a: func(a: string, b: string) -> string;
/// Export with identifier.
export b: x;
/// Export with inline interface.
export c: interface {
/// Function a
a: func(a: string, b: string) -> string;
};
/// Export with package path
export foo:bar/baz@1.0.0;
/// Include world from package path with 2 renames.
include foo:bar/baz with { a as a1, b as b1 };
/// Include world from package path with 1 rename.
include foo:bar/baz with {foo as foo1};
/// Include world from package path (spacing).
include foo:bar/baz with { foo as foo1 };
/// Include world from package path newline delimited renaming.
include foo:bar/baz with {
foo as foo1,
bar as bar1
};
/// Include local world.
include foo-bar;
/// Include local world with renaming.
include foo-bar with { foo as bar };
}"#,
r#"package foo:bar;
world foo {
/// Type t
type t = list<string>;
type x = func() -> list<string>;
use foo.{ y };
/// Import with function type.
import a: func(a: string, b: string) -> string;
/// Import with identifier.
import b: x;
/// Import with inline interface.
import c: interface {
/// Function a
a: func(a: string, b: string) -> string;
};
/// Import with package path
import foo:bar/baz@1.0.0;
/// Export with function type.
export a: func(a: string, b: string) -> string;
/// Export with identifier.
export b: x;
/// Export with inline interface.
export c: interface {
/// Function a
a: func(a: string, b: string) -> string;
};
/// Export with package path
export foo:bar/baz@1.0.0;
/// Include world from package path with 2 renames.
include foo:bar/baz with {
a as a1,
b as b1,
};
/// Include world from package path with 1 rename.
include foo:bar/baz with {
foo as foo1,
};
/// Include world from package path (spacing).
include foo:bar/baz with {
foo as foo1,
};
/// Include world from package path newline delimited renaming.
include foo:bar/baz with {
foo as foo1,
bar as bar1,
};
/// Include local world.
include foo-bar;
/// Include local world with renaming.
include foo-bar with {
foo as bar,
};
}
"#,
)
.unwrap();
}
}