Skip to content
Closed
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
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ jobs:
echo "##[add-path]$HOME/.cargo/bin"
if: matrix.os == 'macos-latest'
- run: cargo fetch
working-directory: tools/witx
working-directory: tools
- run: cargo build
working-directory: tools/witx
working-directory: tools
- run: cargo test
working-directory: tools/witx
working-directory: tools

rustfmt:
name: Rustfmt
Expand All @@ -33,4 +33,4 @@ jobs:
- name: Install Rust
run: rustup update stable && rustup default stable && rustup component add rustfmt
- run: cargo fmt -- --check
working-directory: tools/witx
working-directory: tools
2 changes: 2 additions & 0 deletions tools/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Cargo.lock
target
5 changes: 5 additions & 0 deletions tools/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[workspace]
members = [
"witx",
"wasi-spec",
]
2 changes: 2 additions & 0 deletions tools/wasi-spec/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
Cargo.lock
20 changes: 20 additions & 0 deletions tools/wasi-spec/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "wasi-spec"
version = "0.1.0"
description = "Describe WASI interface using witx"
homepage = "https://github.com/WebAssembly/WASI"
repository = "https://github.com/WebAssembly/WASI"
license = "Apache-2.0"
categories = ["wasm"]
authors = ["Pat Hickey <phickey@fastly.com>"]
edition = "2018"
build = "build.rs"

[lib]
crate-type=["rlib"]

[dependencies]
witx = { path = "../witx", version = "0.1.0" }

[build-dependencies]
witx = { path = "../witx", version = "0.1.0" }
33 changes: 33 additions & 0 deletions tools/wasi-spec/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use witx::{load, Document, WitxError};

const WASI_VERSIONS: &[(&str, &str)] = &[("unstable", "preview0")];

fn load_wasi_spec(phase: &str, version: &str) -> Result<Document, WitxError> {
let path = format!(
"../../phases/{phase}/witx/wasi_{phase}_{version}.witx",
phase = phase,
version = version,
);
println!("cargo:rerun-if-changed={}", path);
load(Path::new(&path))
}

fn serialize_wasi_spec(phase: &str, version: &str, doc: &Document) {
let out_dir = env::var("OUT_DIR").expect("cargo outdir available");
let witx_path = Path::new(&out_dir).join(format!("wasi_{}_{}.witx", phase, version));
let mut f = File::create(witx_path).expect("create file");
f.write_all(format!("{}", doc).as_bytes())
.expect("write data");
}

fn main() {
for (phase, version) in WASI_VERSIONS {
let doc =
load_wasi_spec(phase, version).expect(&format!("load wasi {} {}", phase, version));
serialize_wasi_spec(phase, version, &doc);
}
}
19 changes: 19 additions & 0 deletions tools/wasi-spec/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
pub mod unstable {
use witx;
pub fn preview0() -> witx::Document {
witx::parse(include_str!(concat!(
env!("OUT_DIR"),
"/wasi_unstable_preview0.witx"
)))
.expect("parses")
}

#[cfg(test)]
#[test]
fn preview0_works() {
let packaged = preview0();
let canon = witx::load("../../phases/unstable/witx/wasi_unstable_preview0.witx")
.expect("load canonical");
assert_eq!(packaged, canon);
}
}
165 changes: 146 additions & 19 deletions tools/witx/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,71 @@ impl Id {

#[derive(Debug, Clone)]
pub struct Document {
pub definitions: Vec<Definition>,
pub entries: HashMap<Id, Entry>,
definitions: Vec<Definition>,
entries: HashMap<Id, Entry>,
}

impl Document {
pub(crate) fn new(definitions: Vec<Definition>, entries: HashMap<Id, Entry>) -> Self {
Document {
definitions,
entries,
}
}
pub fn datatype(&self, name: &Id) -> Option<Rc<Datatype>> {
self.entries.get(name).and_then(|e| match e {
Entry::Datatype(d) => Some(d.upgrade().expect("always possible to upgrade entry")),
_ => None,
})
}
pub fn datatypes<'a>(&'a self) -> impl Iterator<Item = Rc<Datatype>> + 'a {
self.definitions.iter().filter_map(|d| match d {
Definition::Datatype(d) => Some(d.clone()),
_ => None,
})
}
pub fn module(&self, name: &Id) -> Option<Rc<Module>> {
self.entries.get(&name).and_then(|e| match e {
Entry::Module(d) => Some(d.upgrade().expect("always possible to upgrade entry")),
_ => None,
})
}
pub fn modules<'a>(&'a self) -> impl Iterator<Item = Rc<Module>> + 'a {
self.definitions.iter().filter_map(|d| match d {
Definition::Module(d) => Some(d.clone()),
_ => None,
})
}
}

impl PartialEq for Document {
fn eq(&self, rhs: &Document) -> bool {
if self.definitions.len() != rhs.definitions.len() {
return false;
}
for d in self.datatypes() {
if let Some(d_rhs) = rhs.datatype(&d.name) {
if d != d_rhs {
return false;
}
} else {
return false;
}
}
for m in self.modules() {
if let Some(m_rhs) = rhs.module(&m.name) {
if m != m_rhs {
return false;
}
} else {
return false;
}
}
true
}
}
impl Eq for Document {}

#[derive(Debug, Clone)]
pub enum Definition {
Datatype(Rc<Datatype>),
Expand All @@ -43,7 +104,7 @@ impl Entry {
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DatatypeIdent {
Builtin(BuiltinType),
Array(Box<DatatypeIdent>),
Expand All @@ -52,13 +113,13 @@ pub enum DatatypeIdent {
Ident(Rc<Datatype>),
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Datatype {
pub name: Id,
pub variant: DatatypeVariant,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DatatypeVariant {
Alias(AliasDatatype),
Enum(EnumDatatype),
Expand All @@ -67,53 +128,53 @@ pub enum DatatypeVariant {
Union(UnionDatatype),
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AliasDatatype {
pub name: Id,
pub to: DatatypeIdent,
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IntRepr {
I8,
I16,
I32,
I64,
}

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

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

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

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StructMember {
pub name: Id,
pub type_: DatatypeIdent,
}

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

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnionVariant {
pub name: Id,
pub type_: DatatypeIdent,
Expand All @@ -122,10 +183,76 @@ pub struct UnionVariant {
#[derive(Debug, Clone)]
pub struct Module {
pub name: Id,
pub definitions: Vec<ModuleDefinition>,
pub entries: HashMap<Id, ModuleEntry>,
definitions: Vec<ModuleDefinition>,
entries: HashMap<Id, ModuleEntry>,
}

impl Module {
pub(crate) fn new(
name: Id,
definitions: Vec<ModuleDefinition>,
entries: HashMap<Id, ModuleEntry>,
) -> Self {
Module {
name,
definitions,
entries,
}
}
pub fn import(&self, name: &Id) -> Option<Rc<ModuleImport>> {
self.entries.get(name).and_then(|e| match e {
ModuleEntry::Import(d) => Some(d.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 {
ModuleDefinition::Import(d) => Some(d.clone()),
_ => None,
})
}
pub fn func(&self, name: &Id) -> Option<Rc<InterfaceFunc>> {
self.entries.get(name).and_then(|e| match e {
ModuleEntry::Func(d) => Some(d.upgrade().expect("always possible to upgrade entry")),
_ => None,
})
}
pub fn funcs<'a>(&'a self) -> impl Iterator<Item = Rc<InterfaceFunc>> + 'a {
self.definitions.iter().filter_map(|d| match d {
ModuleDefinition::Func(d) => Some(d.clone()),
_ => None,
})
}
}

impl PartialEq for Module {
fn eq(&self, rhs: &Module) -> bool {
if self.definitions.len() != rhs.definitions.len() {
return false;
}
for i in self.imports() {
if let Some(i_rhs) = rhs.import(&i.name) {
if i != i_rhs {
return false;
}
} else {
return false;
}
}
for f in self.funcs() {
if let Some(f_rhs) = rhs.func(&f.name) {
if f != f_rhs {
return false;
}
} else {
return false;
}
}
true
}
}
impl Eq for Module {}

#[derive(Debug, Clone)]
pub enum ModuleDefinition {
Import(Rc<ModuleImport>),
Expand All @@ -138,25 +265,25 @@ pub enum ModuleEntry {
Func(Weak<InterfaceFunc>),
}

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

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

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

#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InterfaceFuncParam {
pub name: Id,
pub type_: DatatypeIdent,
Expand Down
Loading