1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
/// Types describing a validated witx document
mod ast;
/// Map witx types to core (wasm standard) types
mod coretypes;
/// Render documentation
mod docs;
/// Interface for filesystem or mock IO
mod io;
/// Calculate memory layout of types
mod layout;
/// Witx syntax parsing from SExprs
mod parser;
/// Paths to witx documents for various proposal phases
pub mod phases;
/// Calculate required polyfill between interfaces
pub mod polyfill;
/// Render ast to text
mod render;
/// Representational equality of types
mod representation;
/// Resolve toplevel `use` declarations across files
mod toplevel;
/// Validate declarations into ast
mod validate;

pub use ast::{
    BuiltinType, Definition, Document, Entry, EnumDatatype, EnumVariant, FlagsDatatype,
    FlagsMember, HandleDatatype, Id, IntConst, IntDatatype, IntRepr, InterfaceFunc,
    InterfaceFuncParam, InterfaceFuncParamPosition, Module, ModuleDefinition, ModuleEntry,
    ModuleImport, ModuleImportVariant, NamedType, StructDatatype, StructMember, Type, TypeRef,
    UnionDatatype, UnionVariant,
};
pub use coretypes::{AtomType, CoreFuncType, CoreParamSignifies, CoreParamType, TypePassedBy};
pub use docs::Documentation;
pub use io::{Filesystem, MockFs, WitxIo};
pub use layout::{Layout, SizeAlign, StructMemberLayout, UnionLayout};
pub use parser::DeclSyntax;
pub use render::SExpr;
pub use representation::{RepEquality, Representable};
pub use validate::ValidationError;

use std::path::{Path, PathBuf};
use thiserror::Error;

/// Load a witx document from the filesystem
pub fn load<P: AsRef<Path>>(paths: &[P]) -> Result<Document, WitxError> {
    toplevel::parse_witx(paths)
}

/// Parse a witx document from a str. `(use ...)` directives are not permitted.
pub fn parse(source: &str) -> Result<Document, WitxError> {
    let mockfs = MockFs::new(&[("-", source)]);
    toplevel::parse_witx_with(&[Path::new("-")], &mockfs)
}

/// Location in the source text
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Location {
    pub path: PathBuf,
    pub line: usize,
    pub column: usize,
}

#[derive(Debug, Error)]
pub enum WitxError {
    #[error("IO error with file {0:?}")]
    Io(PathBuf, #[source] ::std::io::Error),
    #[error("Parse error")]
    Parse(#[from] wast::Error),
    #[error("Validation error")]
    Validation(#[from] ValidationError),
}

impl WitxError {
    pub fn report_with(&self, witxio: &dyn WitxIo) -> String {
        use WitxError::*;
        match self {
            Io(path, ioerr) => format!("with file {:?}: {}", path, ioerr),
            Parse(parse) => parse.to_string(),
            Validation(validation) => validation.report_with(witxio),
        }
    }
    pub fn report(&self) -> String {
        self.report_with(&Filesystem)
    }
}

impl Location {
    pub fn highlight_source_with(&self, witxio: &dyn WitxIo) -> String {
        let mut msg = format!("in {:?}:\n", self.path);
        if let Ok(src_line) = witxio.fget_line(&self.path, self.line) {
            msg += &format!(
                "{line_num: >5} | {src_line}\n{blank: >5}    {caret: >column$}",
                line_num = self.line,
                src_line = src_line,
                blank = " ",
                caret = "^",
                column = self.column,
            );
        }
        msg
    }
    pub fn highlight_source(&self) -> String {
        self.highlight_source_with(&Filesystem)
    }
}