diff --git a/tools/witx/src/ast.rs b/tools/witx/src/ast.rs index 341186820..2295cc94c 100644 --- a/tools/witx/src/ast.rs +++ b/tools/witx/src/ast.rs @@ -29,27 +29,27 @@ impl Document { entries, } } - pub fn datatype(&self, name: &Id) -> Option> { + pub fn typename(&self, name: &Id) -> Option> { self.entries.get(name).and_then(|e| match e { - Entry::Datatype(d) => Some(d.upgrade().expect("always possible to upgrade entry")), + Entry::Typename(nt) => Some(nt.upgrade().expect("always possible to upgrade entry")), _ => None, }) } - pub fn datatypes<'a>(&'a self) -> impl Iterator> + 'a { + pub fn typenames<'a>(&'a self) -> impl Iterator> + 'a { self.definitions.iter().filter_map(|d| match d { - Definition::Datatype(d) => Some(d.clone()), + Definition::Typename(nt) => Some(nt.clone()), _ => None, }) } pub fn module(&self, name: &Id) -> Option> { self.entries.get(&name).and_then(|e| match e { - Entry::Module(d) => Some(d.upgrade().expect("always possible to upgrade entry")), + Entry::Module(m) => Some(m.upgrade().expect("always possible to upgrade entry")), _ => None, }) } pub fn modules<'a>(&'a self) -> impl Iterator> + 'a { self.definitions.iter().filter_map(|d| match d { - Definition::Module(d) => Some(d.clone()), + Definition::Module(m) => Some(m.clone()), _ => None, }) } @@ -66,20 +66,20 @@ impl Eq for Document {} #[derive(Debug, Clone)] pub enum Definition { - Datatype(Rc), + Typename(Rc), Module(Rc), } #[derive(Debug, Clone)] pub enum Entry { - Datatype(Weak), + Typename(Weak), Module(Weak), } impl Entry { pub fn kind(&self) -> &'static str { match self { - Entry::Datatype { .. } => "datatype", + Entry::Typename { .. } => "typename", Entry::Module { .. } => "module", } } @@ -88,10 +88,10 @@ impl Entry { impl PartialEq for Entry { fn eq(&self, rhs: &Entry) -> bool { match (self, rhs) { - (Entry::Datatype(d), Entry::Datatype(d_rhs)) => { - d.upgrade() + (Entry::Typename(t), Entry::Typename(t_rhs)) => { + t.upgrade() .expect("possible to upgrade entry when part of document") - == d_rhs + == t_rhs .upgrade() .expect("possible to upgrade entry when part of document") } @@ -108,51 +108,63 @@ impl PartialEq for Entry { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum DatatypeIdent { - Builtin(BuiltinType), - Array(Box), - Pointer(Box), - ConstPointer(Box), - Ident(Rc), +pub enum TypeRef { + Name(Rc), + Value(Rc), +} + +impl TypeRef { + pub fn type_(&self) -> Rc { + match self { + TypeRef::Name(named) => named.type_(), + TypeRef::Value(ref v) => v.clone(), + } + } } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Datatype { +pub struct NamedType { pub name: Id, - pub variant: DatatypeVariant, + pub dt: TypeRef, pub docs: String, } +impl NamedType { + pub fn type_(&self) -> Rc { + self.dt.type_() + } +} + #[derive(Debug, Clone, PartialEq, Eq)] -pub enum DatatypeVariant { - Alias(AliasDatatype), +pub enum Type { Enum(EnumDatatype), Flags(FlagsDatatype), Struct(StructDatatype), Union(UnionDatatype), Handle(HandleDatatype), + Array(TypeRef), + Pointer(TypeRef), + ConstPointer(TypeRef), + Builtin(BuiltinType), } -impl DatatypeVariant { +impl Type { pub fn kind(&self) -> &'static str { - use DatatypeVariant::*; + use Type::*; match self { - Alias(_) => "alias", Enum(_) => "enum", Flags(_) => "flags", Struct(_) => "struct", Union(_) => "union", Handle(_) => "handle", + Array(_) => "array", + Pointer(_) => "pointer", + ConstPointer(_) => "constpointer", + Builtin(_) => "builtin", } } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AliasDatatype { - pub name: Id, - pub to: DatatypeIdent, -} - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum IntRepr { U8, @@ -163,7 +175,6 @@ pub enum IntRepr { #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumDatatype { - pub name: Id, pub repr: IntRepr, pub variants: Vec, } @@ -176,7 +187,6 @@ pub struct EnumVariant { #[derive(Debug, Clone, PartialEq, Eq)] pub struct FlagsDatatype { - pub name: Id, pub repr: IntRepr, pub flags: Vec, } @@ -189,34 +199,31 @@ pub struct FlagsMember { #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructDatatype { - pub name: Id, pub members: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct StructMember { pub name: Id, - pub type_: DatatypeIdent, + pub tref: TypeRef, pub docs: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct UnionDatatype { - pub name: Id, pub variants: Vec, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct UnionVariant { pub name: Id, - pub type_: DatatypeIdent, + pub tref: TypeRef, pub docs: String, } #[derive(Debug, Clone, PartialEq, Eq)] pub struct HandleDatatype { - pub name: Id, - pub supertypes: Vec, + pub supertypes: Vec, } #[derive(Debug, Clone)] @@ -333,7 +340,7 @@ pub struct InterfaceFunc { #[derive(Debug, Clone, PartialEq, Eq)] pub struct InterfaceFuncParam { pub name: Id, - pub type_: DatatypeIdent, + pub tref: TypeRef, pub position: InterfaceFuncParamPosition, pub docs: String, } diff --git a/tools/witx/src/coretypes.rs b/tools/witx/src/coretypes.rs index f9919bc55..d772b3f54 100644 --- a/tools/witx/src/coretypes.rs +++ b/tools/witx/src/coretypes.rs @@ -1,6 +1,4 @@ -use crate::{ - BuiltinType, DatatypeIdent, DatatypeVariant, IntRepr, InterfaceFunc, InterfaceFuncParam, -}; +use crate::{BuiltinType, IntRepr, InterfaceFunc, InterfaceFuncParam, Type}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// Enumerates the types permitted for function arguments in the WebAssembly spec @@ -22,7 +20,7 @@ impl From for AtomType { #[derive(Debug, Copy, Clone, PartialEq, Eq)] /// Enumerates the strategies which may be used to pass a datatype as an argument -pub enum DatatypePassedBy { +pub enum TypePassedBy { /// Pass by value specifies the AtomType used to represent that value Value(AtomType), /// Pass by a pointer into linear memory @@ -31,36 +29,29 @@ pub enum DatatypePassedBy { PointerLengthPair, } -impl DatatypeIdent { +impl Type { /// Determine the simplest strategy by which a type may be passed. Value always preferred over /// Pointer. - pub fn passed_by(&self) -> DatatypePassedBy { - match &self { - DatatypeIdent::Builtin(b) => match b { - BuiltinType::String => DatatypePassedBy::PointerLengthPair, + pub fn passed_by(&self) -> TypePassedBy { + match self { + Type::Builtin(b) => match b { + BuiltinType::String => TypePassedBy::PointerLengthPair, BuiltinType::U8 | BuiltinType::U16 | BuiltinType::U32 | BuiltinType::S8 | BuiltinType::S16 - | BuiltinType::S32 => DatatypePassedBy::Value(AtomType::I32), - BuiltinType::U64 | BuiltinType::S64 => DatatypePassedBy::Value(AtomType::I64), - BuiltinType::F32 => DatatypePassedBy::Value(AtomType::F32), - BuiltinType::F64 => DatatypePassedBy::Value(AtomType::F64), - }, - DatatypeIdent::Array { .. } => DatatypePassedBy::PointerLengthPair, - DatatypeIdent::Pointer { .. } | DatatypeIdent::ConstPointer { .. } => { - DatatypePassedBy::Value(AtomType::I32) - } - DatatypeIdent::Ident(i) => match &i.variant { - DatatypeVariant::Alias(a) => a.to.passed_by(), - DatatypeVariant::Enum(e) => DatatypePassedBy::Value(e.repr.into()), - DatatypeVariant::Flags(f) => DatatypePassedBy::Value(f.repr.into()), - DatatypeVariant::Struct { .. } | DatatypeVariant::Union { .. } => { - DatatypePassedBy::Pointer - } - DatatypeVariant::Handle { .. } => DatatypePassedBy::Value(AtomType::I32), + | BuiltinType::S32 => TypePassedBy::Value(AtomType::I32), + BuiltinType::U64 | BuiltinType::S64 => TypePassedBy::Value(AtomType::I64), + BuiltinType::F32 => TypePassedBy::Value(AtomType::F32), + BuiltinType::F64 => TypePassedBy::Value(AtomType::F64), }, + Type::Array { .. } => TypePassedBy::PointerLengthPair, + Type::Pointer { .. } | Type::ConstPointer { .. } => TypePassedBy::Value(AtomType::I32), + Type::Enum(e) => TypePassedBy::Value(e.repr.into()), + Type::Flags(f) => TypePassedBy::Value(f.repr.into()), + Type::Struct { .. } | Type::Union { .. } => TypePassedBy::Pointer, + Type::Handle { .. } => TypePassedBy::Value(AtomType::I32), } } } @@ -108,12 +99,12 @@ impl InterfaceFuncParam { /// Gives the WebAssembly type that corresponds to passing this interface func parameter by value. /// Not all types can be passed by value: those which cannot return None pub fn pass_by_value(&self) -> Option { - match self.type_.passed_by() { - DatatypePassedBy::Value(atom) => Some(CoreParamType { + match self.tref.type_().passed_by() { + TypePassedBy::Value(atom) => Some(CoreParamType { signifies: CoreParamSignifies::Value(atom), param: self.clone(), }), - DatatypePassedBy::Pointer | DatatypePassedBy::PointerLengthPair => None, + TypePassedBy::Pointer | TypePassedBy::PointerLengthPair => None, } } @@ -121,12 +112,12 @@ impl InterfaceFuncParam { /// by reference. Some types are passed by reference using a single pointer, others /// require both a pointer and length. pub fn pass_by_reference(&self) -> Vec { - match self.type_.passed_by() { - DatatypePassedBy::Value(_) | DatatypePassedBy::Pointer => vec![CoreParamType { + match self.tref.type_().passed_by() { + TypePassedBy::Value(_) | TypePassedBy::Pointer => vec![CoreParamType { signifies: CoreParamSignifies::PointerTo, param: self.clone(), }], - DatatypePassedBy::PointerLengthPair => vec![ + TypePassedBy::PointerLengthPair => vec![ CoreParamType { signifies: CoreParamSignifies::PointerTo, param: self.clone(), diff --git a/tools/witx/src/docs.rs b/tools/witx/src/docs.rs index 0e75c1e95..511186a47 100644 --- a/tools/witx/src/docs.rs +++ b/tools/witx/src/docs.rs @@ -7,7 +7,7 @@ pub trait Documentation { impl Documentation for Document { fn to_md(&self) -> String { let mut ret = "# Types\n".to_string(); - for d in self.datatypes() { + for d in self.typenames() { ret += &d.to_md(); } @@ -20,7 +20,7 @@ impl Documentation for Document { } impl BuiltinType { - fn name(&self) -> &'static str { + fn type_name(&self) -> &'static str { match self { BuiltinType::String => "string", BuiltinType::U8 => "u8", @@ -37,48 +37,47 @@ impl BuiltinType { } } -impl DatatypeIdent { - fn name(&self) -> String { - match self { - DatatypeIdent::Builtin(b) => b.name().to_string(), - DatatypeIdent::Array(a) => format!("Array<{}>", a.name()), - DatatypeIdent::Pointer(p) => format!("Pointer<{}>", p.name()), - DatatypeIdent::ConstPointer(p) => format!("ConstPointer<{}>", p.name()), - DatatypeIdent::Ident(i) => i.name.as_str().to_string(), - } - } -} - -impl Documentation for Datatype { +impl Documentation for NamedType { fn to_md(&self) -> String { - format!( - "## `{}`\n{}\n{}\n", - self.name.as_str(), - self.docs, - self.variant.to_md() - ) + let body = match &self.dt { + TypeRef::Value(v) => match &**v { + Type::Enum(a) => a.to_md(), + Type::Flags(a) => a.to_md(), + Type::Struct(a) => a.to_md(), + Type::Union(a) => a.to_md(), + Type::Handle(a) => a.to_md(), + Type::Array(a) => format!("Array of {}", a.type_name()), + Type::Pointer(a) => format!("Pointer to {}", a.type_name()), + Type::ConstPointer(a) => format!("Constant Pointer to {}", a.type_name()), + Type::Builtin(a) => format!("Builtin type {}", a.type_name()), + }, + TypeRef::Name(n) => format!("Alias to {}", n.name.as_str()), + }; + format!("## `{}`\n{}\n{}\n", self.name.as_str(), self.docs, body,) } } -impl Documentation for DatatypeVariant { - fn to_md(&self) -> String { +impl TypeRef { + fn type_name(&self) -> String { match self { - DatatypeVariant::Alias(a) => a.to_md(), - DatatypeVariant::Enum(a) => a.to_md(), - DatatypeVariant::Flags(a) => a.to_md(), - DatatypeVariant::Struct(a) => a.to_md(), - DatatypeVariant::Union(a) => a.to_md(), - DatatypeVariant::Handle(a) => a.to_md(), + TypeRef::Name(n) => n.name.as_str().to_string(), + TypeRef::Value(ref v) => match &**v { + Type::Array(a) => format!("Array<{}>", a.type_name()), + Type::Pointer(p) => format!("Pointer<{}>", p.type_name()), + Type::ConstPointer(p) => format!("ConstPointer<{}>", p.type_name()), + Type::Builtin(b) => b.type_name().to_string(), + Type::Enum { .. } + | Type::Flags { .. } + | Type::Struct { .. } + | Type::Union { .. } + | Type::Handle { .. } => { + unimplemented!("type_name of anonymous compound datatypes") + } + }, } } } -impl Documentation for AliasDatatype { - fn to_md(&self) -> String { - format!("Alias to `{}`", self.to.name()) - } -} - impl Documentation for EnumDatatype { fn to_md(&self) -> String { let variants = self @@ -89,7 +88,7 @@ impl Documentation for EnumDatatype { .join("\n"); format!( "Enum represented by `{}`\n\n### Variants:\n{}\n", - self.repr.name(), + self.repr.type_name(), variants ) } @@ -105,7 +104,7 @@ impl Documentation for FlagsDatatype { .join("\n"); format!( "Flags represented by `{}`\n\n### Flags:\n{}", - self.repr.name(), + self.repr.type_name(), flags ) } @@ -120,7 +119,7 @@ impl Documentation for StructDatatype { format!( "#### `{}`\nMember type: `{}`\n{}", m.name.as_str(), - m.type_.name(), + m.tref.type_name(), m.docs, ) }) @@ -139,7 +138,7 @@ impl Documentation for UnionDatatype { format!( "#### `{}`\nVariant type: `{}`\n{}", v.name.as_str(), - v.type_.name(), + v.tref.type_name(), v.docs, ) }) @@ -154,14 +153,14 @@ impl Documentation for HandleDatatype { let supertypes = self .supertypes .iter() - .map(|s| format!("* {}", s.name())) + .map(|s| format!("* {}", s.type_name())) .collect::>() .join("\n"); format!("### Handle supertypes:\n{}\n", supertypes) } } impl IntRepr { - fn name(&self) -> &'static str { + fn type_name(&self) -> &'static str { match self { IntRepr::U8 => "u8", IntRepr::U16 => "u16", @@ -209,7 +208,7 @@ impl Documentation for InterfaceFunc { format!( "##### `{name}`\n`{name}` has type `{type_}`\n{docs}", name = f.name.as_str(), - type_ = f.type_.name(), + type_ = f.tref.type_name(), docs = f.docs ) }) @@ -222,7 +221,7 @@ impl Documentation for InterfaceFunc { format!( "##### `{name}`\n`{name}` has type `{type_}`\n{docs}", name = f.name.as_str(), - type_ = f.type_.name(), + type_ = f.tref.type_name(), docs = f.docs ) }) diff --git a/tools/witx/src/lib.rs b/tools/witx/src/lib.rs index a781aa09b..1c538d9da 100644 --- a/tools/witx/src/lib.rs +++ b/tools/witx/src/lib.rs @@ -16,17 +16,17 @@ mod toplevel; mod validate; pub use ast::{ - AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypeVariant, Definition, Document, - Entry, EnumDatatype, EnumVariant, FlagsDatatype, FlagsMember, HandleDatatype, Id, IntRepr, - InterfaceFunc, InterfaceFuncParam, InterfaceFuncParamPosition, Module, ModuleDefinition, - ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, UnionDatatype, + BuiltinType, Definition, Document, Entry, EnumDatatype, EnumVariant, FlagsDatatype, + FlagsMember, HandleDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, + InterfaceFuncParamPosition, Module, ModuleDefinition, ModuleEntry, ModuleImport, + ModuleImportVariant, NamedType, StructDatatype, StructMember, Type, TypeRef, UnionDatatype, UnionVariant, }; -pub use coretypes::{AtomType, CoreFuncType, CoreParamSignifies, CoreParamType, DatatypePassedBy}; +pub use coretypes::{AtomType, CoreFuncType, CoreParamSignifies, CoreParamType, TypePassedBy}; pub use docs::Documentation; pub use io::{Filesystem, MockFs, WitxIo}; pub use parser::DeclSyntax; -pub use render::{Render, SExpr as RenderSExpr}; +pub use render::SExpr; pub use validate::ValidationError; use failure::Fail; diff --git a/tools/witx/src/parser.rs b/tools/witx/src/parser.rs index 5c4e75f1d..d8088cd61 100644 --- a/tools/witx/src/parser.rs +++ b/tools/witx/src/parser.rs @@ -98,6 +98,24 @@ impl Parse<'_> for BuiltinType { } } +impl wast::parser::Peek for BuiltinType { + fn peek(cursor: wast::parser::Cursor<'_>) -> bool { + ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + || ::peek(cursor) + } + fn display() -> &'static str { + "builtin type" + } +} #[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct CommentSyntax<'a> { pub comments: Vec<&'a str>, @@ -178,41 +196,6 @@ impl<'a, T: Parse<'a>> Parse<'a> for Documented<'a, T> { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum DatatypeIdentSyntax<'a> { - Builtin(BuiltinType), - Array(Box>), - Pointer(Box>), - ConstPointer(Box>), - Ident(wast::Id<'a>), -} - -impl<'a> Parse<'a> for DatatypeIdentSyntax<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - Ok(DatatypeIdentSyntax::Ident(parser.parse()?)) - } else if parser.peek2::() { - Ok(DatatypeIdentSyntax::Array(parser.parens(|p| { - p.parse::()?; - Ok(Box::new(parser.parse()?)) - })?)) - } else if parser.peek::() { - parser.parens(|p| { - p.parse::()?; - if p.peek::() { - p.parse::()?; - Ok(DatatypeIdentSyntax::ConstPointer(Box::new(p.parse()?))) - } else { - p.parse::()?; - Ok(DatatypeIdentSyntax::Pointer(Box::new(p.parse()?))) - } - }) - } else { - Ok(DatatypeIdentSyntax::Builtin(parser.parse()?)) - } - } -} - struct AtWitx; impl Parse<'_> for AtWitx { @@ -329,36 +312,60 @@ impl<'a> Parse<'a> for TypenameSyntax<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub enum TypedefSyntax<'a> { - Ident(DatatypeIdentSyntax<'a>), Enum(EnumSyntax<'a>), Flags(FlagsSyntax<'a>), Struct(StructSyntax<'a>), Union(UnionSyntax<'a>), Handle(HandleSyntax<'a>), + Array(Box>), + Pointer(Box>), + ConstPointer(Box>), + Builtin(BuiltinType), + Ident(wast::Id<'a>), } impl<'a> Parse<'a> for TypedefSyntax<'a> { fn parse(parser: Parser<'a>) -> Result { - if !parser.peek::() || parser.peek2::() || parser.peek2::() - { - return Ok(TypedefSyntax::Ident(parser.parse()?)); + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(TypedefSyntax::Ident(parser.parse()?)) + } else if l.peek::() { + Ok(TypedefSyntax::Builtin(parser.parse()?)) + } else if l.peek::() { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(TypedefSyntax::Enum(parser.parse()?)) + } else if l.peek::() { + Ok(TypedefSyntax::Flags(parser.parse()?)) + } else if l.peek::() { + Ok(TypedefSyntax::Struct(parser.parse()?)) + } else if l.peek::() { + Ok(TypedefSyntax::Union(parser.parse()?)) + } else if l.peek::() { + Ok(TypedefSyntax::Handle(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + Ok(TypedefSyntax::Array(Box::new(parser.parse()?))) + } else if l.peek::() { + parser.parse::()?; + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(TypedefSyntax::ConstPointer(Box::new(parser.parse()?))) + } else if l.peek::() { + parser.parse::()?; + Ok(TypedefSyntax::Pointer(Box::new(parser.parse()?))) + } else { + Err(l.error()) + } + } else { + Err(l.error()) + } + }) + } else { + Err(l.error()) } - parser.parens(|parser| { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(TypedefSyntax::Enum(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Flags(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Struct(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Union(parser.parse()?)) - } else if l.peek::() { - Ok(TypedefSyntax::Handle(parser.parse()?)) - } else { - Err(l.error()) - } - }) } } @@ -419,7 +426,7 @@ impl<'a> Parse<'a> for StructSyntax<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub struct FieldSyntax<'a> { pub name: wast::Id<'a>, - pub type_: DatatypeIdentSyntax<'a>, + pub type_: TypedefSyntax<'a>, } impl<'a> Parse<'a> for FieldSyntax<'a> { diff --git a/tools/witx/src/render.rs b/tools/witx/src/render.rs index 2f2f8526f..c9ec34b1f 100644 --- a/tools/witx/src/render.rs +++ b/tools/witx/src/render.rs @@ -3,8 +3,8 @@ use std::fmt; impl fmt::Display for Document { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for d in self.datatypes() { - write!(f, "{}\n", d.to_sexpr())?; + for d in self.typenames() { + write!(f, "{}\n", d.definition_sexpr())?; } for m in self.modules() { write!(f, "{}\n", m.to_sexpr())?; @@ -68,17 +68,13 @@ impl SExpr { } } -pub trait Render { - fn to_sexpr(&self) -> SExpr; -} - -impl Render for Id { +impl Id { fn to_sexpr(&self) -> SExpr { SExpr::ident(self.as_str()) } } -impl Render for BuiltinType { +impl BuiltinType { fn to_sexpr(&self) -> SExpr { match self { BuiltinType::String => SExpr::word("string"), @@ -96,57 +92,50 @@ impl Render for BuiltinType { } } -impl Render for DatatypeIdent { - fn to_sexpr(&self) -> SExpr { - match self { - DatatypeIdent::Builtin(b) => b.to_sexpr(), - DatatypeIdent::Array(a) => SExpr::Vec(vec![SExpr::word("array"), a.to_sexpr()]), - DatatypeIdent::Pointer(p) => SExpr::Vec(vec![ - SExpr::annot("witx"), - SExpr::word("pointer"), - p.to_sexpr(), - ]), - DatatypeIdent::ConstPointer(p) => SExpr::Vec(vec![ - SExpr::annot("witx"), - SExpr::word("const_pointer"), - p.to_sexpr(), - ]), - DatatypeIdent::Ident(i) => i.name.to_sexpr(), - } - } -} - -impl Render for Datatype { - fn to_sexpr(&self) -> SExpr { - let name = self.name.to_sexpr(); - let body = self.variant.to_sexpr(); +impl NamedType { + fn definition_sexpr(&self) -> SExpr { + let body = self.dt.to_sexpr(); SExpr::docs( &self.docs, - SExpr::Vec(vec![SExpr::word("typename"), name, body]), + SExpr::Vec(vec![SExpr::word("typename"), self.name.to_sexpr(), body]), ) } } -impl Render for DatatypeVariant { +impl TypeRef { fn to_sexpr(&self) -> SExpr { match self { - DatatypeVariant::Alias(a) => a.to_sexpr(), - DatatypeVariant::Enum(a) => a.to_sexpr(), - DatatypeVariant::Flags(a) => a.to_sexpr(), - DatatypeVariant::Struct(a) => a.to_sexpr(), - DatatypeVariant::Union(a) => a.to_sexpr(), - DatatypeVariant::Handle(a) => a.to_sexpr(), + TypeRef::Name(n) => n.name.to_sexpr(), + TypeRef::Value(v) => v.to_sexpr(), } } } -impl Render for AliasDatatype { +impl Type { fn to_sexpr(&self) -> SExpr { - self.to.to_sexpr() + match self { + Type::Enum(a) => a.to_sexpr(), + Type::Flags(a) => a.to_sexpr(), + Type::Struct(a) => a.to_sexpr(), + Type::Union(a) => a.to_sexpr(), + Type::Handle(a) => a.to_sexpr(), + Type::Array(a) => SExpr::Vec(vec![SExpr::word("array"), a.to_sexpr()]), + Type::Pointer(p) => SExpr::Vec(vec![ + SExpr::annot("witx"), + SExpr::word("pointer"), + p.to_sexpr(), + ]), + Type::ConstPointer(p) => SExpr::Vec(vec![ + SExpr::annot("witx"), + SExpr::word("const_pointer"), + p.to_sexpr(), + ]), + Type::Builtin(b) => b.to_sexpr(), + } } } -impl Render for EnumDatatype { +impl EnumDatatype { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("enum"), self.repr.to_sexpr()]; let variants = self @@ -158,7 +147,7 @@ impl Render for EnumDatatype { } } -impl Render for FlagsDatatype { +impl FlagsDatatype { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("flags"), self.repr.to_sexpr()]; let flags = self @@ -170,7 +159,7 @@ impl Render for FlagsDatatype { } } -impl Render for StructDatatype { +impl StructDatatype { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("struct")]; let members = self @@ -182,7 +171,7 @@ impl Render for StructDatatype { SExpr::Vec(vec![ SExpr::word("field"), m.name.to_sexpr(), - m.type_.to_sexpr(), + m.tref.to_sexpr(), ]), ) }) @@ -191,7 +180,7 @@ impl Render for StructDatatype { } } -impl Render for UnionDatatype { +impl UnionDatatype { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("union")]; let variants = self @@ -203,7 +192,7 @@ impl Render for UnionDatatype { SExpr::Vec(vec![ SExpr::word("field"), v.name.to_sexpr(), - v.type_.to_sexpr(), + v.tref.to_sexpr(), ]), ) }) @@ -212,7 +201,7 @@ impl Render for UnionDatatype { } } -impl Render for HandleDatatype { +impl HandleDatatype { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("handle")]; let supertypes = self @@ -223,7 +212,7 @@ impl Render for HandleDatatype { SExpr::Vec([header, supertypes].concat()) } } -impl Render for IntRepr { +impl IntRepr { fn to_sexpr(&self) -> SExpr { match self { IntRepr::U8 => SExpr::word("u8"), @@ -234,7 +223,7 @@ impl Render for IntRepr { } } -impl Render for Module { +impl Module { fn to_sexpr(&self) -> SExpr { let header = vec![SExpr::word("module"), self.name.to_sexpr()]; let definitions = self @@ -246,7 +235,7 @@ impl Render for Module { } } -impl Render for ModuleImport { +impl ModuleImport { fn to_sexpr(&self) -> SExpr { let variant = match self.variant { ModuleImportVariant::Memory => SExpr::Vec(vec![SExpr::word("memory")]), @@ -262,7 +251,7 @@ impl Render for ModuleImport { } } -impl Render for InterfaceFunc { +impl InterfaceFunc { fn to_sexpr(&self) -> SExpr { let header = vec![ SExpr::annot("interface"), @@ -281,7 +270,7 @@ impl Render for InterfaceFunc { SExpr::Vec(vec![ SExpr::word("param"), f.name.to_sexpr(), - f.type_.to_sexpr(), + f.tref.to_sexpr(), ]), ) }) @@ -295,7 +284,7 @@ impl Render for InterfaceFunc { SExpr::Vec(vec![ SExpr::word("result"), f.name.to_sexpr(), - f.type_.to_sexpr(), + f.tref.to_sexpr(), ]), ) }) diff --git a/tools/witx/src/toplevel.rs b/tools/witx/src/toplevel.rs index 2e0738a6b..4fb13b8d7 100644 --- a/tools/witx/src/toplevel.rs +++ b/tools/witx/src/toplevel.rs @@ -107,21 +107,11 @@ mod test { ) .expect("parse"); - match &doc.datatype(&Id::new("b_float")).unwrap().variant { - DatatypeVariant::Alias(a) => { - assert_eq!(a.name.as_str(), "b_float"); - assert_eq!(a.to, DatatypeIdent::Builtin(BuiltinType::F64)); - } - other => panic!("expected alias, got {:?}", other), - } + let b_float = doc.typename(&Id::new("b_float")).unwrap(); + assert_eq!(*b_float.type_(), Type::Builtin(BuiltinType::F64)); - match &doc.datatype(&Id::new("c_int")).unwrap().variant { - DatatypeVariant::Alias(a) => { - assert_eq!(a.name.as_str(), "c_int"); - assert_eq!(a.to, DatatypeIdent::Builtin(BuiltinType::U32)); - } - other => panic!("expected alias, got {:?}", other), - } + let c_int = doc.typename(&Id::new("c_int")).unwrap(); + assert_eq!(*c_int.type_(), Type::Builtin(BuiltinType::U32)); } #[test] @@ -137,13 +127,8 @@ mod test { ) .expect("parse"); - match &doc.datatype(&Id::new("d_char")).unwrap().variant { - DatatypeVariant::Alias(a) => { - assert_eq!(a.name.as_str(), "d_char"); - assert_eq!(a.to, DatatypeIdent::Builtin(BuiltinType::U8)); - } - other => panic!("expected alias, got {:?}", other), - } + let d_char = doc.typename(&Id::new("d_char")).unwrap(); + assert_eq!(*d_char.type_(), Type::Builtin(BuiltinType::U8)); } #[test] diff --git a/tools/witx/src/validate.rs b/tools/witx/src/validate.rs index 5781ebd06..f9cc2a169 100644 --- a/tools/witx/src/validate.rs +++ b/tools/witx/src/validate.rs @@ -1,14 +1,13 @@ use crate::{ io::{Filesystem, WitxIo}, parser::{ - CommentSyntax, DatatypeIdentSyntax, DeclSyntax, Documented, EnumSyntax, FlagsSyntax, - HandleSyntax, ImportTypeSyntax, ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, + CommentSyntax, DeclSyntax, Documented, EnumSyntax, FlagsSyntax, HandleSyntax, + ImportTypeSyntax, ModuleDeclSyntax, StructSyntax, TypedefSyntax, UnionSyntax, }, - AliasDatatype, BuiltinType, Datatype, DatatypeIdent, DatatypePassedBy, DatatypeVariant, - Definition, Entry, EnumDatatype, EnumVariant, FlagsDatatype, FlagsMember, HandleDatatype, Id, - IntRepr, InterfaceFunc, InterfaceFuncParam, InterfaceFuncParamPosition, Location, Module, - ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, StructDatatype, StructMember, - UnionDatatype, UnionVariant, + BuiltinType, Definition, Entry, EnumDatatype, EnumVariant, FlagsDatatype, FlagsMember, + HandleDatatype, Id, IntRepr, InterfaceFunc, InterfaceFuncParam, InterfaceFuncParamPosition, + Location, Module, ModuleDefinition, ModuleEntry, ModuleImport, ModuleImportVariant, NamedType, + StructDatatype, StructMember, Type, TypePassedBy, TypeRef, UnionDatatype, UnionVariant, }; use failure::Fail; use std::collections::HashMap; @@ -168,39 +167,17 @@ impl DocValidationScope<'_> { DeclSyntax::Typename(decl) => { let name = self.introduce(&decl.ident)?; let docs = comments.docs(); - let variant = - match &decl.def { - TypedefSyntax::Ident(syntax) => DatatypeVariant::Alias(AliasDatatype { - name: name.clone(), - to: self.validate_datatype_ident(&syntax)?, - }), - TypedefSyntax::Enum(syntax) => DatatypeVariant::Enum(self.validate_enum( - &name, - &syntax, - decl.ident.span(), - )?), - TypedefSyntax::Flags(syntax) => DatatypeVariant::Flags( - self.validate_flags(&name, &syntax, decl.ident.span())?, - ), - TypedefSyntax::Struct(syntax) => DatatypeVariant::Struct( - self.validate_struct(&name, &syntax, decl.ident.span())?, - ), - TypedefSyntax::Union(syntax) => DatatypeVariant::Union( - self.validate_union(&name, &syntax, decl.ident.span())?, - ), - TypedefSyntax::Handle(syntax) => DatatypeVariant::Handle( - self.validate_handle(&name, syntax, decl.ident.span())?, - ), - }; - let rc_datatype = Rc::new(Datatype { + let dt = self.validate_datatype(&decl.def, decl.ident.span())?; + + let rc_datatype = Rc::new(NamedType { name: name.clone(), - variant, + dt, docs, }); self.doc .entries - .insert(name, Entry::Datatype(Rc::downgrade(&rc_datatype))); - Ok(Definition::Datatype(rc_datatype)) + .insert(name, Entry::Typename(Rc::downgrade(&rc_datatype))); + Ok(Definition::Typename(rc_datatype)) } DeclSyntax::Module(syntax) => { let name = self.introduce(&syntax.name)?; @@ -225,45 +202,51 @@ impl DocValidationScope<'_> { } } - fn validate_datatype_ident( + fn validate_datatype( &self, - syntax: &DatatypeIdentSyntax, - ) -> Result { + syntax: &TypedefSyntax, + span: wast::Span, + ) -> Result { match syntax { - DatatypeIdentSyntax::Builtin(b) => Ok(DatatypeIdent::Builtin(*b)), - DatatypeIdentSyntax::Array(a) => Ok(DatatypeIdent::Array(Box::new( - self.validate_datatype_ident(&a)?, - ))), - DatatypeIdentSyntax::Pointer(a) => Ok(DatatypeIdent::Pointer(Box::new( - self.validate_datatype_ident(&a)?, - ))), - DatatypeIdentSyntax::ConstPointer(a) => Ok(DatatypeIdent::ConstPointer(Box::new( - self.validate_datatype_ident(&a)?, - ))), - DatatypeIdentSyntax::Ident(i) => { - let id = self.get(i)?; - match self.doc.entries.get(&id) { - Some(Entry::Datatype(weak_d)) => Ok(DatatypeIdent::Ident( - weak_d.upgrade().expect("weak backref to defined type"), + TypedefSyntax::Ident(syntax) => { + let i = self.get(syntax)?; + match self.doc.entries.get(&i) { + Some(Entry::Typename(weak_ref)) => Ok(TypeRef::Name( + weak_ref.upgrade().expect("weak backref to defined type"), )), Some(e) => Err(ValidationError::WrongKindName { - name: i.name().to_string(), - location: self.location(i.span()), + name: i.as_str().to_string(), + location: self.location(syntax.span()), expected: "datatype", got: e.kind(), }), None => Err(ValidationError::Recursive { - name: i.name().to_string(), - location: self.location(i.span()), + name: i.as_str().to_string(), + location: self.location(syntax.span()), }), } } + other => Ok(TypeRef::Value(Rc::new(match other { + TypedefSyntax::Enum(syntax) => Type::Enum(self.validate_enum(&syntax, span)?), + TypedefSyntax::Flags(syntax) => Type::Flags(self.validate_flags(&syntax, span)?), + TypedefSyntax::Struct(syntax) => Type::Struct(self.validate_struct(&syntax, span)?), + TypedefSyntax::Union(syntax) => Type::Union(self.validate_union(&syntax, span)?), + TypedefSyntax::Handle(syntax) => Type::Handle(self.validate_handle(syntax, span)?), + TypedefSyntax::Array(syntax) => Type::Array(self.validate_datatype(syntax, span)?), + TypedefSyntax::Pointer(syntax) => { + Type::Pointer(self.validate_datatype(syntax, span)?) + } + TypedefSyntax::ConstPointer(syntax) => { + Type::ConstPointer(self.validate_datatype(syntax, span)?) + } + TypedefSyntax::Builtin(builtin) => Type::Builtin(*builtin), + TypedefSyntax::Ident { .. } => unreachable!(), + }))), } } fn validate_enum( &self, - name: &Id, syntax: &EnumSyntax, span: wast::Span, ) -> Result { @@ -279,16 +262,11 @@ impl DocValidationScope<'_> { }) .collect::, _>>()?; - Ok(EnumDatatype { - name: name.clone(), - repr, - variants, - }) + Ok(EnumDatatype { repr, variants }) } fn validate_flags( &self, - name: &Id, syntax: &FlagsSyntax, span: wast::Span, ) -> Result { @@ -304,16 +282,11 @@ impl DocValidationScope<'_> { }) .collect::, _>>()?; - Ok(FlagsDatatype { - name: name.clone(), - repr, - flags, - }) + Ok(FlagsDatatype { repr, flags }) } fn validate_struct( &self, - name: &Id, syntax: &StructSyntax, _span: wast::Span, ) -> Result { @@ -324,21 +297,17 @@ impl DocValidationScope<'_> { .map(|f| { let name = member_scope .introduce(f.item.name.name(), self.location(f.item.name.span()))?; - let type_ = self.validate_datatype_ident(&f.item.type_)?; + let tref = self.validate_datatype(&f.item.type_, f.item.name.span())?; let docs = f.comments.docs(); - Ok(StructMember { name, type_, docs }) + Ok(StructMember { name, tref, docs }) }) .collect::, _>>()?; - Ok(StructDatatype { - name: name.clone(), - members, - }) + Ok(StructDatatype { members }) } fn validate_union( &self, - name: &Id, syntax: &UnionSyntax, _span: wast::Span, ) -> Result { @@ -349,21 +318,17 @@ impl DocValidationScope<'_> { .map(|f| { let name = variant_scope .introduce(f.item.name.name(), self.location(f.item.name.span()))?; - let type_ = self.validate_datatype_ident(&f.item.type_)?; + let tref = self.validate_datatype(&f.item.type_, f.item.name.span())?; let docs = f.comments.docs(); - Ok(UnionVariant { name, type_, docs }) + Ok(UnionVariant { name, tref, docs }) }) .collect::, _>>()?; - Ok(UnionDatatype { - name: name.clone(), - variants, - }) + Ok(UnionDatatype { variants }) } fn validate_handle( &self, - name: &Id, syntax: &HandleSyntax, _span: wast::Span, ) -> Result { @@ -373,15 +338,15 @@ impl DocValidationScope<'_> { .map(|id_syntax| { let id = self.get(&id_syntax)?; match self.doc.entries.get(&id) { - Some(Entry::Datatype(weak_d)) => { - let d = weak_d.upgrade().expect("weak backref to defined type"); - match &d.variant { - DatatypeVariant::Handle { .. } => Ok(DatatypeIdent::Ident(d)), - _ => Err(ValidationError::WrongKindName { + Some(Entry::Typename(weak_ref)) => { + let named_dt = weak_ref.upgrade().expect("weak backref to defined type"); + match &*named_dt.type_() { + Type::Handle { .. } => Ok(TypeRef::Name(named_dt)), + other => Err(ValidationError::WrongKindName { name: id_syntax.name().to_string(), location: self.location(id_syntax.span()), expected: "handle", - got: d.variant.kind(), + got: other.kind(), }), } } @@ -397,12 +362,9 @@ impl DocValidationScope<'_> { }), } }) - .collect::, _>>()?; + .collect::, _>>()?; - Ok(HandleDatatype { - name: name.clone(), - supertypes, - }) + Ok(HandleDatatype { supertypes }) } fn validate_int_repr( @@ -472,7 +434,9 @@ impl<'a> ModuleValidation<'a> { f.item.name.name(), self.doc.location(f.item.name.span()), )?, - type_: self.doc.validate_datatype_ident(&f.item.type_)?, + tref: self + .doc + .validate_datatype(&f.item.type_, f.item.name.span())?, position: InterfaceFuncParamPosition::Param(ix), docs: f.comments.docs(), }) @@ -483,10 +447,12 @@ impl<'a> ModuleValidation<'a> { .iter() .enumerate() .map(|(ix, f)| { - let type_ = self.doc.validate_datatype_ident(&f.item.type_)?; + let tref = self + .doc + .validate_datatype(&f.item.type_, f.item.name.span())?; if ix == 0 { - match type_.passed_by() { - DatatypePassedBy::Value(_) => {} + match tref.type_().passed_by() { + TypePassedBy::Value(_) => {} _ => Err(ValidationError::InvalidFirstResultType { location: self.doc.location(f.item.name.span()), })?, @@ -497,7 +463,7 @@ impl<'a> ModuleValidation<'a> { f.item.name.name(), self.doc.location(f.item.name.span()), )?, - type_, + tref, position: InterfaceFuncParamPosition::Result(ix), docs: f.comments.docs(), }) diff --git a/tools/witx/tests/multimodule.rs b/tools/witx/tests/multimodule.rs index e9cc5ecb9..47fb34755 100644 --- a/tools/witx/tests/multimodule.rs +++ b/tools/witx/tests/multimodule.rs @@ -1,4 +1,4 @@ -use witx::{load, BuiltinType, DatatypeIdent, DatatypeVariant, Id}; +use witx::{load, BuiltinType, Id, Type, TypeRef}; #[test] fn validate_multimodule() { @@ -9,44 +9,35 @@ fn validate_multimodule() { ]) .unwrap_or_else(|e| panic!("failed to validate: {}", e)); - println!("{}", doc); + //println!("{}", doc); // Check that the `a` both modules use is what we expect: - let type_a = doc.datatype(&Id::new("a")).expect("type a exists"); - match &type_a.variant { - DatatypeVariant::Alias(alias) => match alias.to { - DatatypeIdent::Builtin(b) => assert_eq!(b, BuiltinType::U32), - _ => panic!("a is an alias u32"), - }, - _ => panic!("a is an alias to u32"), - } + let type_a = doc.typename(&Id::new("a")).expect("type a exists"); + assert_eq!(*type_a.type_(), Type::Builtin(BuiltinType::U32)); // `b` is a struct with a single member of type `a` - let type_b = doc.datatype(&Id::new("b")).expect("type b exists"); - match &type_b.variant { - DatatypeVariant::Struct(struct_) => { + let type_b = doc.typename(&Id::new("b")).expect("type b exists"); + match &*type_b.type_() { + Type::Struct(struct_) => { assert_eq!(struct_.members.len(), 1); - match &struct_.members.get(0).unwrap().type_ { - DatatypeIdent::Ident(member_a) => assert_eq!(*member_a, type_a), - _ => panic!("b.0 has type a"), - } + assert_eq!( + struct_.members.get(0).unwrap().tref, + TypeRef::Name(type_a.clone()) + ); } _ => panic!("b is a struct"), } // `c` is a struct with a two members of type `a` - let type_c = doc.datatype(&Id::new("c")).expect("type c exists"); - match &type_c.variant { - DatatypeVariant::Struct(struct_) => { + let type_c = doc.typename(&Id::new("c")).expect("type c exists"); + match &*type_c.type_() { + Type::Struct(struct_) => { assert_eq!(struct_.members.len(), 2); - match &struct_.members.get(0).unwrap().type_ { - DatatypeIdent::Ident(member_a) => assert_eq!(*member_a, type_a), - _ => panic!("c.0 has type a"), - } - match &struct_.members.get(1).unwrap().type_ { - DatatypeIdent::Ident(member_a) => assert_eq!(*member_a, type_a), - _ => panic!("c.1 has type a"), - } + assert_eq!( + struct_.members.get(0).unwrap().tref, + TypeRef::Name(type_a.clone()) + ); + assert_eq!(struct_.members.get(1).unwrap().tref, TypeRef::Name(type_a)); } _ => panic!("c is a struct"), } diff --git a/tools/witx/tests/wasi.rs b/tools/witx/tests/wasi.rs index 938c78067..6d6ebc120 100644 --- a/tools/witx/tests/wasi.rs +++ b/tools/witx/tests/wasi.rs @@ -33,8 +33,8 @@ fn render_roundtrip() { // I'd just assert_eq, but when it fails the debug print is thousands of lines long and impossible // to figure out where they are unequal. if doc != doc2 { - for type_ in doc.datatypes() { - let type2 = doc2.datatype(&type_.name).expect("doc2 missing datatype"); + for type_ in doc.typenames() { + let type2 = doc2.typename(&type_.name).expect("doc2 missing datatype"); assert_eq!(type_, type2); } for mod_ in doc.modules() { @@ -52,3 +52,14 @@ fn render_roundtrip() { // This should be equivelant to the above, but just in case some code changes where it isnt: assert_eq!(doc, doc2); } + +#[test] +fn document_wasi_snapshot() { + use witx::Documentation; + println!( + "{}", + witx::load(&["../../phases/snapshot/witx/wasi_snapshot_preview1.witx"]) + .unwrap_or_else(|e| panic!("failed to parse: {}", e)) + .to_md() + ); +}