Skip to content
28 changes: 28 additions & 0 deletions phases/ephemeral/witx/wasi_ephemeral_command.witx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
(use "wasi_ephemeral_args.witx")
(use "wasi_ephemeral_clock.witx")
(use "wasi_ephemeral_environ.witx")
(use "wasi_ephemeral_fd.witx")
(use "wasi_ephemeral_path.witx")
(use "wasi_ephemeral_poll.witx")
(use "wasi_ephemeral_proc.witx")
(use "wasi_ephemeral_random.witx")
(use "wasi_ephemeral_sched.witx")
(use "wasi_ephemeral_sock.witx")

;;; The WASI standard specifies commands as having all of the
;;; WASI modules available for import, and exporting a start function.
(profile $wasi_ephemeral_command
;;; Commands must export a start function, which takes no parameters and
;;; has no results.
(import "_start" (@interface func))
(expose $wasi_ephemeral_args)
(expose $wasi_ephemeral_clock)
(expose $wasi_ephemeral_environ)
(expose $wasi_ephemeral_fd)
(expose $wasi_ephemeral_path)
(expose $wasi_ephemeral_poll)
(expose $wasi_ephemeral_proc)
(expose $wasi_ephemeral_random)
(expose $wasi_ephemeral_sched)
(expose $wasi_ephemeral_sock)
)
11 changes: 11 additions & 0 deletions phases/snapshot/witx/wasi_snapshot_preview1.witx
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,14 @@
(result $error $errno)
)
)

;;; The WASI standard specifies commands as having all of the
;;; WASI modules available for import, and exporting a start function.
(profile $wasi_snapshot_preview1_command
;;; Commands must export a start function, which has no parameters and no
;;; results.
(import "_start" (@interface func))
;;; Can import from wasi snapshot preview1:
(expose $wasi_snapshot_preview1)
)

25 changes: 25 additions & 0 deletions tools/witx/examples/witx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ enum Command {
)]
output: Option<PathBuf>,
},
/// Parse and then render document as s-exprs - should be equivelant, modulo whitespace.
Render {
/// Path to root of witx document
#[structopt(number_of_values = 1, value_name = "INPUT", parse(from_os_str))]
input: Vec<PathBuf>,
/// Path to generated documentation in Markdown format
#[structopt(
short = "o",
long = "output",
value_name = "OUTPUT",
parse(from_os_str)
)]
output: Option<PathBuf>,
},
/// Update documentation in WASI repository to reflect witx specs
RepoDocs,
/// Examine differences between interfaces
Expand Down Expand Up @@ -88,6 +102,17 @@ pub fn main() {
println!("{}", doc.to_md())
}
}
Command::Render { input, output } => {
let doc = load_witx(&input, "input", verbose);
let rendered = format!("{}", doc);
if let Some(output) = output {
let mut file = File::create(output).expect("create output file");
file.write_all(rendered.as_str().as_bytes())
.expect("write output file");
} else {
println!("{}", rendered);
}
}
Command::RepoDocs => {
for phase in &[
phases::snapshot().unwrap(),
Expand Down
130 changes: 130 additions & 0 deletions tools/witx/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ impl Document {
_ => None,
})
}
pub fn profile(&self, name: &Id) -> Option<Rc<Profile>> {
self.entries.get(&name).and_then(|e| match e {
Entry::Profile(m) => Some(m.upgrade().expect("always possible to upgrade entry")),
_ => None,
})
}
pub fn profiles<'a>(&'a self) -> impl Iterator<Item = Rc<Profile>> + 'a {
self.definitions.iter().filter_map(|d| match d {
Definition::Profile(m) => Some(m.clone()),
_ => None,
})
}
}

impl PartialEq for Document {
Expand All @@ -84,19 +96,22 @@ impl std::hash::Hash for Document {
pub enum Definition {
Typename(Rc<NamedType>),
Module(Rc<Module>),
Profile(Rc<Profile>),
}

#[derive(Debug, Clone)]
pub enum Entry {
Typename(Weak<NamedType>),
Module(Weak<Module>),
Profile(Weak<Profile>),
}

impl Entry {
pub fn kind(&self) -> &'static str {
match self {
Entry::Typename { .. } => "typename",
Entry::Module { .. } => "module",
Entry::Profile { .. } => "profile",
}
}
}
Expand All @@ -118,6 +133,13 @@ impl PartialEq for Entry {
.upgrade()
.expect("possible to upgrade entry when part of document")
}
(Entry::Profile(p), Entry::Profile(p_rhs)) => {
p.upgrade()
.expect("possible to upgrade entry when part of document")
== p_rhs
.upgrade()
.expect("possible to upgrade entry when part of document")
}
_ => false,
}
}
Expand Down Expand Up @@ -384,6 +406,7 @@ pub struct ModuleImport {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ModuleImportVariant {
Memory,
Func(InterfaceFunc),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand All @@ -408,3 +431,110 @@ pub enum InterfaceFuncParamPosition {
Param(usize),
Result(usize),
}

#[derive(Debug, Clone)]
pub struct Profile {
pub name: Id,
definitions: Vec<ProfileDefinition>,
entries: HashMap<Id, ProfileEntry>,
pub docs: String,
}

impl Profile {
pub fn new(
name: Id,
definitions: Vec<ProfileDefinition>,
entries: HashMap<Id, ProfileEntry>,
docs: String,
) -> Self {
Self {
name,
definitions,
entries,
docs,
}
}
pub fn expose(&self, name: &Id) -> Option<Rc<ExposedModule>> {
self.entries.get(name).and_then(|e| match e {
ProfileEntry::Expose(weak) => {
Some(weak.upgrade().expect("always possible to upgrade entry"))
}
_ => None,
})
}
pub fn exposes<'a>(&'a self) -> impl Iterator<Item = Rc<ExposedModule>> + 'a {
self.definitions.iter().filter_map(|d| match d {
ProfileDefinition::Expose(def) => Some(def.clone()),
_ => None,
})
}
pub fn import(&self, name: &Id) -> Option<Rc<ModuleImport>> {
self.entries.get(name).and_then(|e| match e {
ProfileEntry::Import(weak) => {
Some(weak.upgrade().expect("always possible to upgrade entry"))
}
_ => None,
})
}
pub fn imports<'a>(&'a self) -> impl Iterator<Item = Rc<ModuleImport>> + 'a {
self.definitions.iter().filter_map(|d| match d {
ProfileDefinition::Import(def) => Some(def.clone()),
_ => None,
})
}
}

impl PartialEq for Profile {
fn eq(&self, rhs: &Profile) -> 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
}
}
impl Eq for Profile {}

impl std::hash::Hash for Profile {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::hash::Hash::hash(&self.definitions, state);
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ExposedModule {
pub module: Rc<Module>,
pub docs: String,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ProfileDefinition {
Expose(Rc<ExposedModule>),
Import(Rc<ModuleImport>),
}

#[derive(Debug, Clone)]
pub enum ProfileEntry {
Expose(Weak<ExposedModule>),
Import(Weak<ModuleImport>),
}

impl PartialEq for ProfileEntry {
fn eq(&self, rhs: &ProfileEntry) -> bool {
match (self, rhs) {
(ProfileEntry::Expose(i), ProfileEntry::Expose(i_rhs)) => {
i.upgrade()
.expect("always possible to upgrade profileentry when part of profile")
== i_rhs
.upgrade()
.expect("always possible to upgrade profileentry when part of profile")
}
(ProfileEntry::Import(i), ProfileEntry::Import(i_rhs)) => {
i.upgrade()
.expect("always possible to upgrade profileentry when part of profile")
== i_rhs
.upgrade()
.expect("always possible to upgrade profileentry when part of profile")
}
_ => false,
}
}
}
1 change: 1 addition & 0 deletions tools/witx/src/docs/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl ToMarkdown for ModuleImport {
ModuleImportVariant::Memory => {
node.content_ref_mut::<MdSection>().title = "Memory".to_owned();
}
ModuleImportVariant::Func(_) => unimplemented!(), // FIXME
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions tools/witx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ mod toplevel;
mod validate;

pub use ast::{
BuiltinType, Definition, Document, Entry, EnumDatatype, EnumVariant, FlagsDatatype,
FlagsMember, HandleDatatype, Id, IntConst, IntDatatype, IntRepr, InterfaceFunc,
BuiltinType, Definition, Document, Entry, EnumDatatype, EnumVariant, ExposedModule,
FlagsDatatype, FlagsMember, HandleDatatype, Id, IntConst, IntDatatype, IntRepr, InterfaceFunc,
InterfaceFuncParam, InterfaceFuncParamPosition, Module, ModuleDefinition, ModuleEntry,
ModuleImport, ModuleImportVariant, NamedType, StructDatatype, StructMember, Type, TypeRef,
UnionDatatype, UnionVariant,
ModuleImport, ModuleImportVariant, NamedType, Profile, ProfileDefinition, ProfileEntry,
StructDatatype, StructMember, Type, TypeRef, UnionDatatype, UnionVariant,
};
pub use coretypes::{AtomType, CoreFuncType, CoreParamSignifies, CoreParamType, TypePassedBy};
pub use docs::Documentation;
Expand Down
Loading