Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 52 additions & 25 deletions tools/witx/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
use std::collections::HashMap;
use std::rc::{Rc, Weak};

pub use crate::parser::BuiltinType;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Id(String);

Expand Down Expand Up @@ -64,7 +62,13 @@ impl PartialEq for Document {
}
impl Eq for Document {}

#[derive(Debug, Clone)]
impl std::hash::Hash for Document {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&self.definitions, state);
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Definition {
Typename(Rc<NamedType>),
Module(Rc<Module>),
Expand Down Expand Up @@ -107,7 +111,7 @@ impl PartialEq for Entry {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TypeRef {
Name(Rc<NamedType>),
Value(Rc<Type>),
Expand All @@ -122,20 +126,20 @@ impl TypeRef {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NamedType {
pub name: Id,
pub dt: TypeRef,
pub tref: TypeRef,
pub docs: String,
}

impl NamedType {
pub fn type_(&self) -> Rc<Type> {
self.dt.type_()
self.tref.type_()
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Type {
Enum(EnumDatatype),
Flags(FlagsDatatype),
Expand Down Expand Up @@ -165,63 +169,78 @@ impl Type {
}
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinType {
String,
U8,
U16,
U32,
U64,
S8,
S16,
S32,
S64,
F32,
F64,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum IntRepr {
U8,
U16,
U32,
U64,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumDatatype {
pub repr: IntRepr,
pub variants: Vec<EnumVariant>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumVariant {
pub name: Id,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FlagsDatatype {
pub repr: IntRepr,
pub flags: Vec<FlagsMember>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FlagsMember {
pub name: Id,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructDatatype {
pub members: Vec<StructMember>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructMember {
pub name: Id,
pub tref: TypeRef,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnionDatatype {
pub variants: Vec<UnionVariant>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnionVariant {
pub name: Id,
pub tref: TypeRef,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct HandleDatatype {
pub supertypes: Vec<TypeRef>,
}
Expand Down Expand Up @@ -278,12 +297,20 @@ impl PartialEq for Module {
fn eq(&self, rhs: &Module) -> bool {
// For equality, we don't care about the ordering of definitions,
// so we only need to check that the entries map is equal
self.entries == rhs.entries
self.name == rhs.name && self.entries == rhs.entries && self.docs == rhs.docs
}
}
impl Eq for Module {}

#[derive(Debug, Clone)]
impl std::hash::Hash for Module {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&self.name, state);
std::hash::Hash::hash(&self.definitions, state);
std::hash::Hash::hash(&self.docs, state);
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ModuleDefinition {
Import(Rc<ModuleImport>),
Func(Rc<InterfaceFunc>),
Expand Down Expand Up @@ -317,35 +344,35 @@ impl PartialEq for ModuleEntry {
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ModuleImport {
pub name: Id,
pub variant: ModuleImportVariant,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ModuleImportVariant {
Memory,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InterfaceFunc {
pub name: Id,
pub params: Vec<InterfaceFuncParam>,
pub results: Vec<InterfaceFuncParam>,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InterfaceFuncParam {
pub name: Id,
pub tref: TypeRef,
pub position: InterfaceFuncParamPosition,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum InterfaceFuncParamPosition {
Param(usize),
Result(usize),
Expand Down
157 changes: 154 additions & 3 deletions tools/witx/src/docs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::ast::*;
use crate::polyfill::*;
use crate::RepEquality;

pub trait Documentation {
fn to_md(&self) -> String;
Expand All @@ -20,7 +22,7 @@ impl Documentation for Document {
}

impl BuiltinType {
fn type_name(&self) -> &'static str {
pub fn type_name(&self) -> &'static str {
match self {
BuiltinType::String => "string",
BuiltinType::U8 => "u8",
Expand All @@ -39,7 +41,7 @@ impl BuiltinType {

impl Documentation for NamedType {
fn to_md(&self) -> String {
let body = match &self.dt {
let body = match &self.tref {
TypeRef::Value(v) => match &**v {
Type::Enum(a) => a.to_md(),
Type::Flags(a) => a.to_md(),
Expand All @@ -58,7 +60,7 @@ impl Documentation for NamedType {
}

impl TypeRef {
fn type_name(&self) -> String {
pub fn type_name(&self) -> String {
match self {
TypeRef::Name(n) => n.name.as_str().to_string(),
TypeRef::Value(ref v) => match &**v {
Expand Down Expand Up @@ -236,3 +238,152 @@ impl Documentation for InterfaceFunc {
)
}
}

impl Documentation for Polyfill {
fn to_md(&self) -> String {
let module_docs = self
.modules
.iter()
.map(|m| m.to_md())
.collect::<Vec<String>>()
.join("\n");
let type_docs = self
.type_polyfills()
.iter()
.filter_map(|t| {
if t.repeq() == RepEquality::Eq {
None
} else {
Some(t.to_md())
}
})
.collect::<Vec<String>>()
.join("\n");
format!(
"# Modules\n{}\n# Type Conversions\n{}\n",
module_docs, type_docs
)
}
}

impl Documentation for ModulePolyfill {
fn to_md(&self) -> String {
format!(
"## `{}` in terms of `{}`\n{}",
self.new.name.as_str(),
self.old.name.as_str(),
self.funcs
.iter()
.map(|f| f.to_md())
.collect::<Vec<String>>()
.join("\n"),
)
}
}

impl Documentation for FuncPolyfill {
fn to_md(&self) -> String {
if self.full_compat() {
format!("* `{}`: full compatibility", self.new.name.as_str())
} else {
let name = if self.new.name != self.old.name {
format!(
"* `{}` => `{}`",
self.old.name.as_str(),
self.new.name.as_str()
)
} else {
format!("* `{}`", self.new.name.as_str())
};
let mut contents = Vec::new();
for p in self.mapped_params.iter() {
contents.push(if !p.full_compat() {
format!("param {}", p.to_md())
} else {
format!("param `{}`: compatible", p.new.name.as_str())
})
}
for u in self.unknown_params.iter() {
contents.push(format!(
"{} param `{}`: no corresponding result!",
u.which(),
u.param().name.as_str()
))
}
for r in self.mapped_results.iter() {
contents.push(if !r.full_compat() {
format!("result {}", r.to_md())
} else {
format!("result `{}`: compatible", r.new.name.as_str())
})
}
for u in self.unknown_results.iter() {
contents.push(format!(
"{} result `{}`: no corresponding result!",
u.which(),
u.param().name.as_str()
))
}
let contents = if contents.is_empty() {
String::new()
} else {
format!(":\n - {}", contents.join("\n - "))
};
format!("{}{}", name, contents)
}
}
}

impl Documentation for ParamPolyfill {
fn to_md(&self) -> String {
let name = if self.new.name != self.old.name {
format!(
"`{}` => `{}`",
self.old.name.as_str(),
self.new.name.as_str()
)
} else {
format!("`{}`", self.new.name.as_str())
};
let repr = match self.repeq() {
RepEquality::Eq => "compatible types".to_string(),
RepEquality::Superset => format!(
"`{}` is superset-compatible with `{}`",
self.old.tref.type_name(),
self.new.tref.type_name()
),
RepEquality::NotEq => format!(
"`{}` is incompatible with new `{}`",
self.old.tref.type_name(),
self.new.tref.type_name()
),
};
format!("{}: {}", name, repr)
}
}

impl Documentation for TypePolyfill {
fn to_md(&self) -> String {
fn repeq_name(r: RepEquality) -> &'static str {
match r {
RepEquality::Eq => ": compatible",
RepEquality::Superset => ": superset",
RepEquality::NotEq => "",
}
}
match self {
TypePolyfill::OldToNew(o, n) => format!(
"* old `{}` => new `{}`{}",
o.type_name(),
n.type_name(),
repeq_name(self.repeq())
),
TypePolyfill::NewToOld(n, o) => format!(
"* new `{}` => old `{}`{}",
n.type_name(),
o.type_name(),
repeq_name(self.repeq())
),
}
}
}
Loading