///|
/// WIT (WebAssembly Interface Types) 1.0 abstract syntax tree.
///
/// Supports the core subset targeted by P0:
/// `package`, `interface`, `world`, `use`, `import`/`export`,
/// `record`/`variant`/`enum`/`flags`/`resource`/`type` aliases and `func` signatures.
/// Design inspired by bytecodealliance/wit-bindgen.
///|
/// A reference to a WIT type.
pub enum WitType {
/// Named reference to a previously defined type.
Name(String)
/// `u8` — maps to MoonBit `Byte`.
U8
/// `u16` — maps to MoonBit `UInt16`.
U16
/// `u32` — maps to MoonBit `UInt`.
U32
/// `u64` — maps to MoonBit `UInt64`.
U64
/// `s8` — maps to MoonBit `Int` (widened, no `Int8` in core).
S8
/// `s16` — maps to MoonBit `Int16`.
S16
/// `s32` — maps to MoonBit `Int`.
S32
/// `s64` — maps to MoonBit `Int64`.
S64
/// `f32` — maps to MoonBit `Float`.
F32
/// `f64` — maps to MoonBit `Double`.
F64
/// `char` — maps to MoonBit `Char`.
TChar
/// `string` — maps to MoonBit `String`.
TString
/// `bool` — maps to MoonBit `Bool`.
TBool
/// `list` — maps to MoonBit `List[T]`.
List(WitType)
/// `option` — maps to MoonBit `Option[T]`.
Option(WitType)
/// `result` — maps to MoonBit `Result[T, E]`.
Result(WitType?, WitType?)
/// `tuple<...>` — maps to a MoonBit tuple.
Tuple(Array[WitType])
/// `own`.
Own(String)
/// `borrow`.
Borrow(String)
/// `future` asynchronous value handle.
Future(WitType?)
/// `stream` asynchronous stream handle.
Stream(WitType?)
}
///|
/// A named field with its type (record field or function parameter).
pub struct Field {
name : String
ty : WitType
}
///|
/// A variant case. `ty` is `None` for a unit case.
pub struct Case {
name : String
ty : WitType?
}
///|
/// A single unnamed result, or a named result (WIT named results).
pub enum FuncResult {
Unnamed(WitType)
Named(Field)
}
///|
/// `use path.{a, b as c}` declaration.
pub struct UseName {
name : String
asName : String?
}
///|
/// `use .{a, b as c}` — re-exports types from an interface.
pub struct UseDecl {
path : String
names : Array[UseName]
}
///|
/// A `func` signature with parameters and results.
pub struct FuncSig {
name : String
params : Array[Field]
results : Array[FuncResult]
}
///|
pub enum ResourceFuncKind {
Constructor
Static
Method
}
///|
pub struct ResourceFunc {
kind : ResourceFuncKind
sig : FuncSig
}
///|
/// The kind of a named type definition.
pub enum TypeDefKind {
/// `record` — a struct of named fields.
Record(Array[Field])
/// `variant` — a sum type with optional payloads.
Variant(Array[Case])
/// `enum` — a plain set of unit cases.
Enum(Array[String])
/// `flags` — a set of boolean flags.
Flags(Array[String])
/// `resource` — an opaque handle type.
Resource(Array[ResourceFunc])
/// `type X = ` — an alias.
Alias(WitType)
}
///|
/// A named type definition.
pub struct TypeDef {
name : String
kind : TypeDefKind
}
///|
/// An item inside an `interface` (or an inline interface in a world).
pub enum InterfaceItem {
Use(UseDecl)
Type(TypeDef)
Func(FuncSig)
}
///|
/// An `interface` definition.
pub struct Interface {
name : String
items : Array[InterfaceItem]
}
///|
/// An `import foo [as bar] [: interface {...}]` or `export ...` item.
pub struct ImpExp {
name : String
asName : String?
/// `Some(iface)` when this is an inline `name: interface { ... }`.
inline : Interface?
}
///|
/// An item inside a `world`.
pub enum WorldItem {
Import(ImpExp)
Export(ImpExp)
/// A direct `import name: func(...);` declaration.
ImportFunc(FuncSig)
/// A direct `export name: func(...);` declaration.
ExportFunc(FuncSig)
/// A world composition declaration, optionally with renamed exports.
Include(String, Array[UseName])
Use(UseDecl)
}
///|
/// A `world` definition.
pub struct World {
name : String
items : Array[WorldItem]
}
///|
/// An item at the top level of a WIT document.
pub enum WitItem {
Interface(Interface)
World(World)
Use(UseDecl)
}
///|
/// A parsed WIT document (the result of [`parse`](@wit)).
pub struct WitPackage {
/// The package namespace (e.g. `docs` in `package docs:hello`).
ns : String
/// The package name (e.g. `hello` in `package docs:hello`).
name : String
version : String?
items : Array[WitItem]
}
///|
/// Renders a WIT type reference back to WIT syntax.
pub fn WitType::to_string(self : WitType) -> String {
match self {
Name(n) => n
U8 => "u8"
U16 => "u16"
U32 => "u32"
U64 => "u64"
S8 => "s8"
S16 => "s16"
S32 => "s32"
S64 => "s64"
F32 => "f32"
F64 => "f64"
TChar => "char"
TString => "string"
TBool => "bool"
List(t) => "list<\{t.to_string()}>"
Option(t) => "option<\{t.to_string()}>"
Result(ok, err) => {
let mut s = "result<\{slot_to_string(ok)}"
match err {
Some(e) => s = s + ", \{slot_to_string(Some(e))}"
None => ()
}
s + ">"
}
Tuple(items) =>
"tuple<\{join_strings(items.map(fn(t) { t.to_string() }), ", ")}>"
Own(n) => "own<\{n}>"
Borrow(n) => "borrow<\{n}>"
Future(t) => "future<\{slot_to_string(t)}>"
Stream(t) => "stream<\{slot_to_string(t)}>"
}
}
///|
fn slot_to_string(slot : WitType?) -> String {
match slot {
Some(t) => t.to_string()
None => "_"
}
}
///|
fn join_strings(items : Array[String], sep : String) -> String {
let mut s = ""
let mut first = true
for item in items {
if !first {
s = s + sep
}
s = s + item
first = false
}
s
}
///|
fn indent_lines(text : String, prefix : String) -> String {
let mut s = prefix
for ch in text {
s = s + ch.to_string()
if ch == '\n' {
s = s + prefix
}
}
s
}
///|
pub fn Field::to_string(self : Field) -> String {
"\{self.name}: \{self.ty.to_string()}"
}
///|
pub fn Case::to_string(self : Case) -> String {
match self.ty {
Some(t) => "\{self.name}(\{t.to_string()})"
None => self.name
}
}
///|
pub fn FuncResult::to_string(self : FuncResult) -> String {
match self {
Unnamed(t) => t.to_string()
Named(f) => f.to_string()
}
}
///|
pub fn UseDecl::to_string(self : UseDecl) -> String {
let mut s = "use \{self.path}."
if self.names.length() == 0 {
s = s + "*"
} else {
s = s + "{\{join_strings(self.names.map(fn(n) { n.to_string() }), ", ")}"
s = s + "}"
}
s + ";"
}
///|
pub fn UseName::to_string(self : UseName) -> String {
match self.asName {
Some(a) => "\{self.name} as \{a}"
None => self.name
}
}
///|
pub fn TypeDef::to_string(self : TypeDef) -> String {
match self.kind {
Record(fields) => {
let mut s = "record \{self.name} {\n"
for f in fields {
s = s + " \{f.to_string()}\n"
}
s + "}"
}
Variant(cases) => {
let mut s = "variant \{self.name} {\n"
for c in cases {
s = s + " \{c.to_string()}\n"
}
s + "}"
}
Enum(names) => {
let mut s = "enum \{self.name} {\n"
for n in names {
s = s + " \{n}\n"
}
s + "}"
}
Flags(names) => {
let mut s = "flags \{self.name} {\n"
for n in names {
s = s + " \{n}\n"
}
s + "}"
}
Resource(funcs) => {
if funcs.length() == 0 {
return "resource \{self.name};"
}
let mut s = "resource \{self.name} {\n"
for f in funcs {
let prefix = match f.kind {
Constructor => "constructor\{f.sig.signature_to_string()}"
Static => "static \{f.sig.to_string()}"
Method => f.sig.to_string()
}
s = s + " \{prefix};\n"
}
s + "}"
}
Alias(t) => "type \{self.name} = \{t.to_string()};"
}
}
///|
pub fn FuncSig::to_string(self : FuncSig) -> String {
"\{self.name}: \{self.type_to_string()}"
}
///|
fn FuncSig::type_to_string(self : FuncSig) -> String {
"func\{self.signature_to_string()}"
}
///|
fn FuncSig::signature_to_string(self : FuncSig) -> String {
let mut s = "("
s = s + join_strings(self.params.map(fn(p) { p.to_string() }), ", ")
s = s + ")"
if self.results.length() != 0 {
s = s + " -> " + func_results_to_string(self.results)
}
s
}
///|
fn func_results_to_string(results : Array[FuncResult]) -> String {
if results.length() == 1 {
match results[0] {
Unnamed(t) => return t.to_string()
_ => ()
}
}
"(\{join_strings(results.map(fn(r) { r.to_string() }), ", ")})"
}
///|
pub fn InterfaceItem::to_string(self : InterfaceItem) -> String {
match self {
Use(u) => u.to_string()
Type(t) => t.to_string()
Func(f) => f.to_string()
}
}
///|
pub fn Interface::to_string(self : Interface) -> String {
let mut s = "interface \{self.name} {\n"
for item in self.items {
s = s + indent_lines(item.to_string(), " ") + "\n"
}
s + "}"
}
///|
pub fn ImpExp::to_string(self : ImpExp) -> String {
let mut s = self.name
match self.asName {
Some(a) => s = s + " as \{a}"
None => ()
}
match self.inline {
Some(iface) => {
s = s + ": interface {\n"
for item in iface.items {
s = s + indent_lines(item.to_string(), " ") + "\n"
}
s = s + "}"
}
None => s = s + ";"
}
s
}
///|
pub fn WorldItem::to_string(self : WorldItem) -> String {
match self {
Import(imp) => "import \{imp.to_string()}"
Export(exp) => "export \{exp.to_string()}"
ImportFunc(f) => "import \{f.to_string()};"
ExportFunc(f) => "export \{f.to_string()};"
Include(path, names) => {
let mut s = "include \{path}"
if names.length() != 0 {
s = s +
" with {\{join_strings(names.map(fn(n) { n.to_string() }), ", ")}}"
}
s + ";"
}
Use(u) => u.to_string()
}
}
///|
pub fn World::to_string(self : World) -> String {
let mut s = "world \{self.name} {\n"
for item in self.items {
s = s + indent_lines(item.to_string(), " ") + "\n"
}
s + "}"
}
///|
pub fn WitItem::to_string(self : WitItem) -> String {
match self {
Interface(i) => i.to_string()
World(w) => w.to_string()
Use(u) => u.to_string()
}
}
///|
pub fn WitPackage::to_string(self : WitPackage) -> String {
let mut s = "package \{self.ns}:\{self.name}"
match self.version {
Some(v) => s = s + "@\{v}"
None => ()
}
s = s + ";\n"
for item in self.items {
s = s + item.to_string() + "\n"
}
s
}