diff --git a/Cargo.lock b/Cargo.lock index ebd44d3..62e1c25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,15 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + [[package]] name = "beef" version = "0.5.2" @@ -415,6 +424,37 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miette" +version = "5.10.0" +source = "git+https://github.com/zkat/miette#7ff4f874d693a665af4df40f4e94505013e3e262" +dependencies = [ + "backtrace", + "backtrace-ext", + "is-terminal", + "miette-derive", + "once_cell", + "owo-colors", + "serde", + "supports-color 2.1.0", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "git+https://github.com/zkat/miette#7ff4f874d693a665af4df40f4e94505013e3e262" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -443,13 +483,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + [[package]] name = "owo-colors" version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" dependencies = [ - "supports-color", + "supports-color 1.3.1", ] [[package]] @@ -628,6 +674,12 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + [[package]] name = "spdx" version = "0.10.2" @@ -653,6 +705,34 @@ dependencies = [ "is_ci", ] +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "supports-unicode" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" +dependencies = [ + "is-terminal", +] + [[package]] name = "syn" version = "2.0.39" @@ -673,6 +753,27 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.50" @@ -722,6 +823,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-width" version = "0.1.11" @@ -747,10 +854,12 @@ dependencies = [ "anyhow", "clap", "log", + "miette", "owo-colors", "pretty_env_logger", "serde", "serde_json", + "thiserror", "tokio", "wac-parser", "wasmparser", @@ -767,6 +876,7 @@ dependencies = [ "indexmap", "log", "logos", + "miette", "owo-colors", "pretty_assertions", "pretty_env_logger", diff --git a/Cargo.toml b/Cargo.toml index 4b36e9a..d89c604 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ serde_json = { workspace = true } wat = { workspace = true } wasmparser = { workspace = true } wasmprinter = { workspace = true } +thiserror = { workspace = true } +# TODO: use the next release which has support for primary labels +miette = { git = "https://github.com/zkat/miette", features = ["fancy"] } [features] default = [] diff --git a/crates/wac-parser/Cargo.toml b/crates/wac-parser/Cargo.toml index 1ed1e35..beb7c68 100644 --- a/crates/wac-parser/Cargo.toml +++ b/crates/wac-parser/Cargo.toml @@ -24,17 +24,21 @@ wit-component = { workspace = true } wasm-encoder = { workspace = true } wasm-metadata = { workspace = true } wat = { workspace = true, optional = true } -owo-colors = { workspace = true } +# TODO: use the next release which has support for primary labels +miette = { git = "https://github.com/zkat/miette", features = ["serde"] } [features] default = ["wat"] [dev-dependencies] +owo-colors = "3.5.0" pretty_assertions = "1.4.0" pretty_env_logger = { workspace = true } rayon = "1.8.0" serde_json = { workspace = true } wasmprinter = { workspace = true } +# TODO: use the next release which has support for primary labels +miette = { git = "https://github.com/zkat/miette", features = ["serde", "fancy"] } [[test]] name = "parser" diff --git a/crates/wac-parser/src/ast.rs b/crates/wac-parser/src/ast.rs index ebdc585..c40dde0 100644 --- a/crates/wac-parser/src/ast.rs +++ b/crates/wac-parser/src/ast.rs @@ -1,11 +1,9 @@ //! Module for the AST implementation. -use crate::{ - lexer::{self, Lexer, LexerResult, Span, Token}, - Spanned, -}; +use crate::lexer::{self, Lexer, LexerResult, Token}; +use miette::{Diagnostic, SourceSpan}; use serde::Serialize; -use std::{fmt, path::Path}; +use std::fmt; mod export; mod expr; @@ -61,15 +59,17 @@ impl fmt::Display for Expected<'_> { } /// Represents a parse error. -#[derive(thiserror::Error, Debug)] -pub enum Error<'a> { +#[derive(thiserror::Error, Diagnostic, Debug)] +#[diagnostic(code("failed to parse document"))] +pub enum Error { /// A lexer error occurred. #[error("{error}")] Lexer { /// The lexer error that occurred. error: crate::lexer::Error, /// The span where the error occurred. - span: Span<'a>, + #[label(primary)] + span: SourceSpan, }, /// An unexpected token was encountered when a single token was expected. #[error("expected {expected}, found {found}", found = Found(*.found))] @@ -79,7 +79,8 @@ pub enum Error<'a> { /// The found token (`None` for end of input). found: Option, /// The span of the found token. - span: Span<'a>, + #[label(primary, "unexpected {found}", found = Found(*.found))] + span: SourceSpan, }, /// An unexpected token was encountered when either one of two tokens was expected. #[error("expected {first} or {second}, found {found}", found = Found(*.found))] @@ -91,7 +92,8 @@ pub enum Error<'a> { /// The found token. found: Option, /// The span of the found token. - span: Span<'a>, + #[label(primary, "unexpected {found}", found = Found(*.found))] + span: SourceSpan, }, /// An unexpected token was encountered when multiple tokens were expected. #[error("expected either {expected}, found {found}", expected = Expected { expected, count: *.count }, found = Found(*.found))] @@ -103,7 +105,8 @@ pub enum Error<'a> { /// The found token. found: Option, /// The span of the found token. - span: Span<'a>, + #[label(primary, "unexpected {found}", found = Found(*.found))] + span: SourceSpan, }, /// An empty type was encountered. #[error("{ty} must contain at least one {kind}")] @@ -113,42 +116,31 @@ pub enum Error<'a> { /// The kind of item that was empty (e.g. "field", "case", etc.) kind: &'static str, /// The span of the empty type. - span: Span<'a>, + #[label(primary, "empty {ty}")] + span: SourceSpan, }, /// An invalid semantic version was encountered. #[error("`{version}` is not a valid semantic version")] InvalidVersion { /// The invalid version. - version: &'a str, + version: std::string::String, /// The span of the version. - span: Span<'a>, + #[label(primary, "invalid version")] + span: SourceSpan, }, } -impl Spanned for Error<'_> { - fn span(&self) -> Span<'_> { - match self { - Error::Lexer { span, .. } - | Error::Expected { span, .. } - | Error::ExpectedEither { span, .. } - | Error::ExpectedMultiple { span, .. } - | Error::EmptyType { span, .. } - | Error::InvalidVersion { span, .. } => *span, - } - } -} - /// Represents a parse result. -pub type ParseResult<'a, T> = Result>; +pub type ParseResult = Result; -impl<'a> From<(lexer::Error, Span<'a>)> for Error<'a> { - fn from((e, s): (lexer::Error, Span<'a>)) -> Self { +impl From<(lexer::Error, SourceSpan)> for Error { + fn from((e, s): (lexer::Error, SourceSpan)) -> Self { Self::Lexer { error: e, span: s } } } /// Expects a given token from the lexer. -pub fn parse_token<'a>(lexer: &mut Lexer<'a>, expected: Token) -> ParseResult<'a, Span<'a>> { +pub fn parse_token(lexer: &mut Lexer, expected: Token) -> ParseResult { let (result, span) = lexer.next().ok_or_else(|| Error::Expected { expected, found: None, @@ -173,9 +165,9 @@ pub fn parse_optional<'a, F, R>( lexer: &mut Lexer<'a>, expected: Token, cb: F, -) -> ParseResult<'a, Option> +) -> ParseResult> where - F: FnOnce(&mut Lexer<'a>) -> ParseResult<'a, R>, + F: FnOnce(&mut Lexer<'a>) -> ParseResult, { match lexer.peek() { Some((Ok(token), _)) => { @@ -194,19 +186,19 @@ where /// Used to look ahead one token in the lexer. /// /// The lookahead stores up to 10 attempted tokens. -pub struct Lookahead<'a> { - next: Option<(LexerResult<'a, Token>, Span<'a>)>, - source: &'a str, +pub struct Lookahead { + next: Option<(LexerResult, SourceSpan)>, attempts: [Option; 10], + span: SourceSpan, count: usize, } -impl<'a> Lookahead<'a> { +impl Lookahead { /// Creates a new lookahead from the given lexer. - pub fn new(lexer: &Lexer<'a>) -> Self { + pub fn new(lexer: &Lexer) -> Self { Self { next: lexer.peek(), - source: lexer.source(), + span: lexer.span(), attempts: Default::default(), count: 0, } @@ -230,14 +222,11 @@ impl<'a> Lookahead<'a> { /// Returns an error based on the attempted tokens. /// /// Panics if no peeks were attempted. - pub fn error(self) -> Error<'a> { + pub fn error(self) -> Error { let (found, span) = match self.next { Some((Ok(token), span)) => (Some(token), span), Some((Err(e), s)) => return (e, s).into(), - None => ( - None, - Span::from_span(self.source, &(self.source.len()..self.source.len())), - ), + None => (None, self.span), }; match self.count { @@ -264,14 +253,14 @@ impl<'a> Lookahead<'a> { } pub(crate) trait Parse<'a>: Sized { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self>; + fn parse(lexer: &mut Lexer<'a>) -> ParseResult; } fn parse_delimited<'a, T: Parse<'a> + Peek>( lexer: &mut Lexer<'a>, until: &[Token], with_commas: bool, -) -> ParseResult<'a, Vec> { +) -> ParseResult> { assert!( !until.is_empty(), "must have at least one token to parse until" @@ -304,26 +293,10 @@ trait Peek { fn peek(lookahead: &mut Lookahead) -> bool; } -macro_rules! display { - ($name:ident, $method:ident) => { - impl std::fmt::Display for $name<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut printer = crate::ast::DocumentPrinter::new(f, None); - printer.$method(self) - } - } - }; -} - -pub(crate) use display; - /// Represents a top-level WAC document. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct Document<'a> { - /// The path to the document, used for error reporting. - #[serde(skip)] - pub path: &'a Path, /// The doc comments for the package. pub docs: Vec>, /// The package name of the document. @@ -336,7 +309,7 @@ impl<'a> Document<'a> { /// Parses the given source string as a document. /// /// The given path is used for error reporting. - pub fn parse(source: &'a str, path: &'a Path) -> ParseResult<'a, Self> { + pub fn parse(source: &'a str) -> ParseResult { let mut lexer = Lexer::new(source).map_err(Error::from)?; let docs = Parse::parse(&mut lexer)?; @@ -352,7 +325,6 @@ impl<'a> Document<'a> { assert!(lexer.next().is_none(), "expected all tokens to be consumed"); Ok(Self { - path, docs, package, statements, @@ -360,8 +332,6 @@ impl<'a> Document<'a> { } } -display!(Document, document); - /// Represents a statement in the AST. #[derive(Debug, Clone, Serialize)] pub enum Statement<'a> { @@ -376,7 +346,7 @@ pub enum Statement<'a> { } impl<'a> Parse<'a> for Statement<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if ImportStatement::peek(&mut lookahead) { Ok(Self::Import(Parse::parse(lexer)?)) @@ -399,13 +369,13 @@ pub struct Ident<'a> { /// The identifier string. pub string: &'a str, /// The span of the identifier. - pub span: Span<'a>, + pub span: SourceSpan, } impl<'a> Parse<'a> for Ident<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let span = parse_token(lexer, Token::Ident)?; - let id = span.as_str(); + let id = lexer.source(span); Ok(Self { string: id.strip_prefix('%').unwrap_or(id), span, @@ -426,13 +396,13 @@ pub struct String<'a> { /// The value of the string (without quotes). pub value: &'a str, /// The span of the string. - pub span: Span<'a>, + pub span: SourceSpan, } impl<'a> Parse<'a> for String<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let span = parse_token(lexer, Token::String)?; - let s = span.as_str(); + let s = lexer.source(span); Ok(Self { value: s.strip_prefix('"').unwrap().strip_suffix('"').unwrap(), span, @@ -453,11 +423,11 @@ pub struct DocComment<'a> { /// The comment string. pub comment: &'a str, /// The span of the comment. - pub span: Span<'a>, + pub span: SourceSpan, } impl<'a> Parse<'a> for Vec> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Vec>> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult>> { Ok(lexer .comments() .map_err(Error::from)? @@ -480,19 +450,19 @@ mod test { /// as the output string, since the input string may contain /// extra whitespace and comments that are not preserved in /// the AST. - pub(crate) fn roundtrip<'a, T: Parse<'a> + fmt::Display>( - source: &'a str, - expected: &str, - ) -> ParseResult<'a, ()> { - let mut lexer = Lexer::new(source).map_err(Error::from)?; - let node: T = Parse::parse(&mut lexer)?; - assert_eq!(node.to_string(), expected, "unexpected AST output"); + pub(crate) fn roundtrip(source: &str, expected: &str) -> ParseResult<()> { + let doc = Document::parse(source)?; + let mut s = std::string::String::new(); + DocumentPrinter::new(&mut s, source, None) + .document(&doc) + .unwrap(); + assert_eq!(s, expected, "unexpected AST output"); Ok(()) } #[test] fn document_roundtrip() { - let document = Document::parse( + roundtrip( r#"/* ignore me */ /// Doc comment for the package! package test:foo:bar@1.0.0; @@ -521,12 +491,6 @@ let x = new foo:bar { }; /// Doc comment #10! export x with "foo"; "#, - Path::new("test"), - ) - .unwrap(); - - assert_eq!( - document.to_string(), r#"/// Doc comment for the package! package test:foo:bar@1.0.0; @@ -561,7 +525,8 @@ let x = new foo:bar {}; /// Doc comment #10! export x with "foo"; -"# - ); +"#, + ) + .unwrap() } } diff --git a/crates/wac-parser/src/ast/export.rs b/crates/wac-parser/src/ast/export.rs index 35abcb8..ff18176 100644 --- a/crates/wac-parser/src/ast/export.rs +++ b/crates/wac-parser/src/ast/export.rs @@ -1,8 +1,8 @@ use super::{ - display, expr::Expr, parse_optional, parse_token, DocComment, Lookahead, Parse, ParseResult, - Peek, + expr::Expr, parse_optional, parse_token, DocComment, Lookahead, Parse, ParseResult, Peek, }; -use crate::lexer::{Lexer, Span, Token}; +use crate::lexer::{Lexer, Token}; +use miette::SourceSpan; use serde::Serialize; /// Represents an export statement in the AST. @@ -12,7 +12,7 @@ pub struct ExportStatement<'a> { /// The doc comments for the statement. pub docs: Vec>, /// The span of the export keyword. - pub span: Span<'a>, + pub span: SourceSpan, /// The optional `with` string. pub with: Option>, /// The expression to export. @@ -20,7 +20,7 @@ pub struct ExportStatement<'a> { } impl<'a> Parse<'a> for ExportStatement<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let span = parse_token(lexer, Token::ExportKeyword)?; let expr = Parse::parse(lexer)?; @@ -41,54 +41,74 @@ impl Peek for ExportStatement<'_> { } } -display!(ExportStatement, export_statement); - #[cfg(test)] mod test { - use super::*; use crate::ast::test::roundtrip; #[test] fn export_statement_roundtrip() { - roundtrip::("export y;", "export y;").unwrap(); - roundtrip::( - "export foo.%with with \"foo\";", - "export foo.%with with \"foo\";", + roundtrip( + "package foo:bar; export y;", + "package foo:bar;\n\nexport y;\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; export foo.%with with \"foo\";", + "package foo:bar;\n\nexport foo.%with with \"foo\";\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; export y.x.z;", + "package foo:bar;\n\nexport y.x.z;\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; export y.x.z with \"baz\";", + "package foo:bar;\n\nexport y.x.z with \"baz\";\n", ) .unwrap(); - roundtrip::("export y.x.z;", "export y.x.z;").unwrap(); - roundtrip::("export y.x.z with \"baz\";", "export y.x.z with \"baz\";") - .unwrap(); - roundtrip::("export y[\"x\"][\"z\"];", "export y[\"x\"][\"z\"];").unwrap(); - roundtrip::( - "export y[\"x\"][\"z\"] with \"x\";", - "export y[\"x\"][\"z\"] with \"x\";", + roundtrip( + "package foo:bar; export y[\"x\"][\"z\"];", + "package foo:bar;\n\nexport y[\"x\"][\"z\"];\n", ) .unwrap(); - roundtrip::( - "export foo[\"bar\"].baz[\"qux\"];", - "export foo[\"bar\"].baz[\"qux\"];", + roundtrip( + "package foo:bar; export y[\"x\"][\"z\"] with \"x\";", + "package foo:bar;\n\nexport y[\"x\"][\"z\"] with \"x\";\n", ) .unwrap(); - roundtrip::( - "export foo[\"bar\"].baz[\"qux\"] with \"qux\";", - "export foo[\"bar\"].baz[\"qux\"] with \"qux\";", + roundtrip( + "package foo:bar; export foo[\"bar\"].baz[\"qux\"];", + "package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"];\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; export foo[\"bar\"].baz[\"qux\"] with \"qux\";", + "package foo:bar;\n\nexport foo[\"bar\"].baz[\"qux\"] with \"qux\";\n", ) .unwrap(); - roundtrip::("export (y);", "export (y);").unwrap(); + roundtrip( + "package foo:bar; export (y);", + "package foo:bar;\n\nexport (y);\n", + ) + .unwrap(); - roundtrip::("export new foo:bar {};", "export new foo:bar {};").unwrap(); + roundtrip( + "package foo:bar; export new foo:bar {};", + "package foo:bar;\n\nexport new foo:bar {};\n", + ) + .unwrap(); - roundtrip::( - "export new foo:bar {} /* foo */ with \"foo\";", - "export new foo:bar {} with \"foo\";", + roundtrip( + "package foo:bar; export new foo:bar {} /* foo */ with \"foo\";", + "package foo:bar;\n\nexport new foo:bar {} with \"foo\";\n", ) .unwrap(); - roundtrip::( - "export new foo:bar { foo, \"bar\": (new baz:qux {a, ...}), \"baz\": foo[\"baz\"].qux };", - "export new foo:bar {\n foo,\n \"bar\": (new baz:qux {\n a,\n ...\n }),\n \"baz\": foo[\"baz\"].qux,\n};", + roundtrip( + "package foo:bar; export new foo:bar { foo, \"bar\": (new baz:qux {a, ...}), \"baz\": foo[\"baz\"].qux };", + "package foo:bar;\n\nexport new foo:bar {\n foo,\n \"bar\": (new baz:qux {\n a,\n ...\n }),\n \"baz\": foo[\"baz\"].qux,\n};\n", ) .unwrap(); } diff --git a/crates/wac-parser/src/ast/expr.rs b/crates/wac-parser/src/ast/expr.rs index 1e5abb5..c0ad7f3 100644 --- a/crates/wac-parser/src/ast/expr.rs +++ b/crates/wac-parser/src/ast/expr.rs @@ -1,8 +1,9 @@ use super::{ - display, parse_delimited, parse_optional, parse_token, Ident, Lookahead, PackageName, Parse, + parse_delimited, parse_optional, parse_token, Ident, Lookahead, PackageName, Parse, ParseResult, Peek, }; -use crate::lexer::{Lexer, Span, Token}; +use crate::lexer::{Lexer, Token}; +use miette::SourceSpan; use serde::Serialize; /// Represents an expression in the AST. @@ -16,7 +17,7 @@ pub struct Expr<'a> { } impl<'a> Parse<'a> for Expr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let primary = Parse::parse(lexer)?; // Currently, only the access expressions are supported for postfix expressions. // As they have the same precedence, we don't need to perform climbing. @@ -36,8 +37,6 @@ impl<'a> Parse<'a> for Expr<'a> { } } -display!(Expr, expr); - /// Represents a primary expression in the AST. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] @@ -51,7 +50,7 @@ pub enum PrimaryExpr<'a> { } impl<'a> Parse<'a> for PrimaryExpr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if NewExpr::peek(&mut lookahead) { Ok(Self::New(Parse::parse(lexer)?)) @@ -78,7 +77,7 @@ pub struct NewExpr<'a> { } impl<'a> Parse<'a> for NewExpr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { parse_token(lexer, Token::NewKeyword)?; let package = PackageName::parse(lexer)?; parse_token(lexer, Token::OpenBrace)?; @@ -110,7 +109,7 @@ pub enum InstantiationArgument<'a> { } impl<'a> Parse<'a> for InstantiationArgument<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if NamedInstantiationArgument::peek(&mut lookahead) { // Peek again to see if this is really a named instantiation argument. @@ -142,7 +141,7 @@ pub struct NamedInstantiationArgument<'a> { } impl<'a> Parse<'a> for NamedInstantiationArgument<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let name = Parse::parse(lexer)?; parse_token(lexer, Token::Colon)?; let expr = Parse::parse(lexer)?; @@ -167,7 +166,7 @@ pub enum InstantiationArgumentName<'a> { } impl<'a> Parse<'a> for InstantiationArgumentName<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if Ident::peek(&mut lookahead) { Ok(Self::Ident(Parse::parse(lexer)?)) @@ -187,7 +186,7 @@ impl Peek for InstantiationArgumentName<'_> { impl<'a> InstantiationArgumentName<'a> { /// Gets the span of the instantiation argument name. - pub fn span(&self) -> Span<'a> { + pub fn span(&self) -> SourceSpan { match self { Self::Ident(ident) => ident.span, Self::String(string) => string.span, @@ -201,7 +200,7 @@ impl<'a> InstantiationArgumentName<'a> { pub struct NestedExpr<'a>(pub Box>); impl<'a> Parse<'a> for NestedExpr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { parse_token(lexer, Token::OpenParen)?; let expr = Box::new(Parse::parse(lexer)?); parse_token(lexer, Token::CloseParen)?; @@ -227,7 +226,7 @@ pub enum PostfixExpr<'a> { impl<'a> PostfixExpr<'a> { /// Gets the span of the postfix expression. - pub fn span(&self) -> Span<'a> { + pub fn span(&self) -> SourceSpan { match self { PostfixExpr::Access(access) => access.span, PostfixExpr::NamedAccess(access) => access.span, @@ -240,17 +239,19 @@ impl<'a> PostfixExpr<'a> { #[serde(rename_all = "camelCase")] pub struct AccessExpr<'a> { /// The span of the access expression. - pub span: Span<'a>, + pub span: SourceSpan, /// The identifier in the expression. pub id: Ident<'a>, } impl<'a> Parse<'a> for AccessExpr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { - let mut span = parse_token(lexer, Token::Dot)?; + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { + let span = parse_token(lexer, Token::Dot)?; let id: Ident = Parse::parse(lexer)?; - span.end = id.span.end; - Ok(Self { span, id }) + Ok(Self { + span: SourceSpan::new(span.offset().into(), (id.span.len() + 1).into()), + id, + }) } } @@ -265,18 +266,23 @@ impl Peek for AccessExpr<'_> { #[serde(rename_all = "camelCase")] pub struct NamedAccessExpr<'a> { /// The span of the access expression. - pub span: Span<'a>, + pub span: SourceSpan, /// The name string in the expression. pub string: super::String<'a>, } impl<'a> Parse<'a> for NamedAccessExpr<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { - let mut span = parse_token(lexer, Token::OpenBracket)?; + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { + let opening = parse_token(lexer, Token::OpenBracket)?; let string = Parse::parse(lexer)?; let closing = parse_token(lexer, Token::CloseBracket)?; - span.end = closing.end; - Ok(Self { span, string }) + Ok(Self { + span: SourceSpan::new( + opening.offset().into(), + ((closing.offset() + closing.len()) - opening.offset()).into(), + ), + string, + }) } } @@ -285,24 +291,3 @@ impl Peek for NamedAccessExpr<'_> { lookahead.peek(Token::OpenBracket) } } - -#[cfg(test)] -mod test { - use super::*; - use crate::ast::test::roundtrip; - - #[test] - fn primary_expr_roundtrip() { - roundtrip::("x", "x").unwrap(); - roundtrip::("y.x.z", "y.x.z").unwrap(); - roundtrip::("y[\"x\"][\"z\"]", "y[\"x\"][\"z\"]").unwrap(); - roundtrip::("foo[\"bar\"].baz[\"qux\"]", "foo[\"bar\"].baz[\"qux\"]").unwrap(); - roundtrip::("(foo-bar-baz)", "(foo-bar-baz)").unwrap(); - roundtrip::("new foo:bar {}", "new foo:bar {}").unwrap(); - roundtrip::( - "new foo:bar { foo, \"bar\": (new baz:qux {...}), \"baz\": foo[\"baz\"].qux }", - "new foo:bar {\n foo,\n \"bar\": (new baz:qux { ... }),\n \"baz\": foo[\"baz\"].qux,\n}", - ) - .unwrap(); - } -} diff --git a/crates/wac-parser/src/ast/import.rs b/crates/wac-parser/src/ast/import.rs index 4761183..68a7cd3 100644 --- a/crates/wac-parser/src/ast/import.rs +++ b/crates/wac-parser/src/ast/import.rs @@ -1,8 +1,9 @@ use super::{ - display, parse_optional, parse_token, DocComment, Error, FuncType, Ident, InlineInterface, - Lookahead, Parse, ParseResult, Peek, + parse_optional, parse_token, DocComment, Error, FuncType, Ident, InlineInterface, Lookahead, + Parse, ParseResult, Peek, }; -use crate::lexer::{Lexer, Span, Token}; +use crate::lexer::{Lexer, Token}; +use miette::SourceSpan; use semver::Version; use serde::Serialize; @@ -21,7 +22,7 @@ pub struct ImportStatement<'a> { } impl<'a> Parse<'a> for ImportStatement<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::ImportKeyword)?; let id = Parse::parse(lexer)?; @@ -39,8 +40,6 @@ impl Peek for ImportStatement<'_> { } } -display!(ImportStatement, import_statement); - /// Represents an import type in the AST. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] @@ -56,7 +55,7 @@ pub enum ImportType<'a> { } impl<'a> Parse<'a> for ImportType<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if FuncType::peek(&mut lookahead) { Ok(Self::Func(Parse::parse(lexer)?)) @@ -77,7 +76,9 @@ impl<'a> Parse<'a> for ImportType<'a> { #[serde(rename_all = "camelCase")] pub struct PackagePath<'a> { /// The span of the package path. - pub span: Span<'a>, + pub span: SourceSpan, + /// The entire path string. + pub string: &'a str, /// The name of the package. pub name: &'a str, /// The path segments. @@ -88,27 +89,23 @@ pub struct PackagePath<'a> { impl<'a> PackagePath<'a> { /// Gets the span of only the package name. - pub fn package_name_span(&self) -> Span<'a> { - Span::from_span( - self.span.source(), - &(self.span.start..self.span.start + self.name.len()), - ) + pub fn package_name_span(&self) -> SourceSpan { + SourceSpan::new(self.span.offset().into(), self.name.len().into()) } /// Iterates over the segments of the package path. - pub fn segment_spans<'b>(&'b self) -> impl Iterator)> + 'b { + pub fn segment_spans<'b>(&'b self) -> impl Iterator + 'b { self.segments.split('/').map(|s| { - let start = self.span.start + s.as_ptr() as usize - self.name.as_ptr() as usize; - let end = start + s.len(); - (s, Span::from_span(self.span.source(), &(start..end))) + let start = self.span.offset() + s.as_ptr() as usize - self.name.as_ptr() as usize; + (s, SourceSpan::new(start.into(), s.len().into())) }) } } impl<'a> Parse<'a> for PackagePath<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let span = parse_token(lexer, Token::PackagePath)?; - let s = span.as_str(); + let s = lexer.source(span); let slash = s.find('/').unwrap(); let at = s.find('@'); let name = &s[..slash]; @@ -116,15 +113,20 @@ impl<'a> Parse<'a> for PackagePath<'a> { let version = at .map(|at| { let version = &s[at + 1..]; + let start = span.offset() + at + 1; version.parse().map_err(|_| Error::InvalidVersion { - version, - span: Span::from_span(span.source(), &(span.start + at + 1..span.end)), + version: version.to_owned(), + span: SourceSpan::new( + start.into(), + ((span.offset() + span.len()) - start).into(), + ), }) }) .transpose()?; Ok(Self { span, + string: lexer.source(span), name, segments, version, @@ -142,30 +144,37 @@ impl Peek for PackagePath<'_> { #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] pub struct PackageName<'a> { + /// The entire package name as a string. + pub string: &'a str, /// The name of the package. pub name: &'a str, /// The optional version of the package. pub version: Option, /// The span of the package name, - pub span: Span<'a>, + pub span: SourceSpan, } impl<'a> Parse<'a> for PackageName<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let span = parse_token(lexer, Token::PackageName)?; - let s = span.as_str(); + let s = lexer.source(span); let at = s.find('@'); let name = at.map(|at| &s[..at]).unwrap_or(s); let version = at .map(|at| { let version = &s[at + 1..]; + let start = span.offset() + at + 1; version.parse().map_err(|_| Error::InvalidVersion { - version, - span: Span::from_span(span.source(), &(span.start + at + 1..span.end)), + version: version.to_string(), + span: SourceSpan::new( + start.into(), + ((span.offset() + span.len()) - start).into(), + ), }) }) .transpose()?; Ok(Self { + string: lexer.source(span), name, version, span, @@ -175,61 +184,64 @@ impl<'a> Parse<'a> for PackageName<'a> { #[cfg(test)] mod test { - use super::*; use crate::ast::test::roundtrip; #[test] fn import_via_package_roundtrip() { - roundtrip::( - "import x: foo:bar:baz/qux/jam@1.2.3-preview+abc;", - "import x: foo:bar:baz/qux/jam@1.2.3-preview+abc;", + roundtrip( + "package foo:bar; import x: foo:bar:baz/qux/jam@1.2.3-preview+abc;", + "package foo:bar;\n\nimport x: foo:bar:baz/qux/jam@1.2.3-preview+abc;\n", ) .unwrap(); - roundtrip::( - "import x with \"y\": foo:bar:baz/qux/jam@1.2.3-preview+abc;", - "import x with \"y\": foo:bar:baz/qux/jam@1.2.3-preview+abc;", + roundtrip( + "package foo:bar; import x with \"y\": foo:bar:baz/qux/jam@1.2.3-preview+abc;", + "package foo:bar;\n\nimport x with \"y\": foo:bar:baz/qux/jam@1.2.3-preview+abc;\n", ) .unwrap(); } #[test] fn import_function_roundtrip() { - roundtrip::( - "import x: func(x: string) -> string;", - "import x: func(x: string) -> string;", + roundtrip( + "package foo:bar; import x: func(x: string) -> string;", + "package foo:bar;\n\nimport x: func(x: string) -> string;\n", ) .unwrap(); - roundtrip::( - "import x with \"foo\": func(x: string) -> string;", - "import x with \"foo\": func(x: string) -> string;", + roundtrip( + "package foo:bar; import x with \"foo\": func(x: string) -> string;", + "package foo:bar;\n\nimport x with \"foo\": func(x: string) -> string;\n", ) .unwrap(); } #[test] fn import_interface_roundtrip() { - roundtrip::( - "import x: interface { x: func(x: string) -> string; };", - "import x: interface {\n x: func(x: string) -> string;\n};", + roundtrip( + "package foo:bar; import x: interface { x: func(x: string) -> string; };", + "package foo:bar;\n\nimport x: interface {\n x: func(x: string) -> string;\n};\n", ) .unwrap(); - roundtrip::( - "import x with \"foo\": interface { x: func(x: string) -> string; };", - "import x with \"foo\": interface {\n x: func(x: string) -> string;\n};", + roundtrip( + "package foo:bar; import x with \"foo\": interface { x: func(x: string) -> string; };", + "package foo:bar;\n\nimport x with \"foo\": interface {\n x: func(x: string) -> string;\n};\n", ) .unwrap(); } #[test] fn import_via_ident_roundtrip() { - roundtrip::("import x: y;", "import x: y;").unwrap(); + roundtrip( + "package foo:bar; import x: y;", + "package foo:bar;\n\nimport x: y;\n", + ) + .unwrap(); - roundtrip::( - "import x /*foo */ with \"foo\": y;", - "import x with \"foo\": y;", + roundtrip( + "package foo:bar; import x /*foo */ with \"foo\": y;", + "package foo:bar;\n\nimport x with \"foo\": y;\n", ) .unwrap(); } diff --git a/crates/wac-parser/src/ast/let.rs b/crates/wac-parser/src/ast/let.rs index 7824fb4..c537827 100644 --- a/crates/wac-parser/src/ast/let.rs +++ b/crates/wac-parser/src/ast/let.rs @@ -1,6 +1,5 @@ +use super::{parse_token, DocComment, Expr, Ident, Lookahead, Parse, ParseResult, Peek}; use crate::lexer::{Lexer, Token}; - -use super::{display, parse_token, DocComment, Expr, Ident, Lookahead, Parse, ParseResult, Peek}; use serde::Serialize; /// Represents a let statement in the AST. @@ -16,7 +15,7 @@ pub struct LetStatement<'a> { } impl<'a> Parse<'a> for LetStatement<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::LetKeyword)?; let id = Parse::parse(lexer)?; @@ -33,31 +32,48 @@ impl Peek for LetStatement<'_> { } } -display!(LetStatement, let_statement); - #[cfg(test)] mod test { - use super::*; use crate::ast::test::roundtrip; #[test] fn let_statement_roundtrip() { - roundtrip::("let x= y;", "let x = y;").unwrap(); - roundtrip::("let x =y.x.z;", "let x = y.x.z;").unwrap(); - roundtrip::("let x=y[\"x\"][\"z\"];", "let x = y[\"x\"][\"z\"];").unwrap(); - roundtrip::( - "let x = foo[\"bar\"].baz[\"qux\"];", - "let x = foo[\"bar\"].baz[\"qux\"];", + roundtrip( + "package foo:bar; let x= y;", + "package foo:bar;\n\nlet x = y;\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; let x =y.x.z;", + "package foo:bar;\n\nlet x = y.x.z;\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; let x=y[\"x\"][\"z\"];", + "package foo:bar;\n\nlet x = y[\"x\"][\"z\"];\n", + ) + .unwrap(); + roundtrip( + "package foo:bar; let x = foo[\"bar\"].baz[\"qux\"];", + "package foo:bar;\n\nlet x = foo[\"bar\"].baz[\"qux\"];\n", ) .unwrap(); - roundtrip::("let x = (y);", "let x = (y);").unwrap(); + roundtrip( + "package foo:bar; let x = (y);", + "package foo:bar;\n\nlet x = (y);\n", + ) + .unwrap(); - roundtrip::("let x = new foo:bar {};", "let x = new foo:bar {};").unwrap(); + roundtrip( + "package foo:bar; let x = new foo:bar {};", + "package foo:bar;\n\nlet x = new foo:bar {};\n", + ) + .unwrap(); - roundtrip::( - "let x = new foo:bar { foo, \"bar\": (new baz:qux {...}), \"baz\": foo[\"baz\"].qux };", - "let x = new foo:bar {\n foo,\n \"bar\": (new baz:qux { ... }),\n \"baz\": foo[\"baz\"].qux,\n};", + roundtrip( + "package foo:bar; let x = new foo:bar { foo, \"bar\": (new baz:qux {...}), \"baz\": foo[\"baz\"].qux };", + "package foo:bar;\n\nlet x = new foo:bar {\n foo,\n \"bar\": (new baz:qux { ... }),\n \"baz\": foo[\"baz\"].qux,\n};\n", ) .unwrap(); } diff --git a/crates/wac-parser/src/ast/printer.rs b/crates/wac-parser/src/ast/printer.rs index 1996ea9..9ea2d86 100644 --- a/crates/wac-parser/src/ast/printer.rs +++ b/crates/wac-parser/src/ast/printer.rs @@ -4,21 +4,23 @@ use crate::ast::*; use std::fmt::Write; /// A printer for WAC documents. -pub struct DocumentPrinter { +pub struct DocumentPrinter<'a, W: Write> { writer: W, + source: &'a str, space: &'static str, indent: usize, indented: bool, } -impl DocumentPrinter { +impl<'a, W: Write> DocumentPrinter<'a, W> { /// Creates a new document printer for the given write. /// /// If `space` is `None`, then the printer will use four spaces for /// indentation. - pub fn new(writer: W, space: Option<&'static str>) -> Self { + pub fn new(writer: W, source: &'a str, space: Option<&'static str>) -> Self { Self { writer, + source, space: space.unwrap_or(" "), indent: 0, indented: false, @@ -31,7 +33,7 @@ impl DocumentPrinter { writeln!( self.writer, "package {package};", - package = doc.package.span.as_str() + package = self.source(doc.package.span), )?; self.newline()?; @@ -75,10 +77,14 @@ impl DocumentPrinter { self.docs(&statement.docs)?; self.indent()?; - write!(self.writer, "import {id}", id = statement.id.span.as_str())?; + write!( + self.writer, + "import {id}", + id = self.source(statement.id.span) + )?; if let Some(with) = &statement.with { - write!(self.writer, " with {with}", with = with.span.as_str())?; + write!(self.writer, " with {with}", with = self.source(with.span))?; } write!(self.writer, ": ")?; @@ -94,13 +100,13 @@ impl DocumentPrinter { ImportType::Package(p) => self.package_path(p), ImportType::Func(f) => self.func_type(f), ImportType::Interface(i) => self.inline_interface(i), - ImportType::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + ImportType::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } /// Prints the given package path. pub fn package_path(&mut self, path: &PackagePath) -> std::fmt::Result { - write!(self.writer, "{path}", path = path.span.as_str())?; + write!(self.writer, "{path}", path = self.source(path.span))?; Ok(()) } @@ -130,7 +136,7 @@ impl DocumentPrinter { write!(self.writer, ", ")?; } - write!(self.writer, "{id}: ", id = param.id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(param.id.span))?; self.ty(¶m.ty)?; } @@ -196,9 +202,9 @@ impl DocumentPrinter { } }, Type::Borrow(id, _) => { - write!(self.writer, "borrow<{id}>", id = id.span.as_str()) + write!(self.writer, "borrow<{id}>", id = self.source(id.span)) } - Type::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + Type::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } @@ -245,9 +251,9 @@ impl DocumentPrinter { write!(self.writer, ", ")?; } - write!(self.writer, "{id}", id = item.id.span.as_str())?; + write!(self.writer, "{id}", id = self.source(item.id.span))?; if let Some(as_id) = &item.as_id { - write!(self.writer, " as {as_id}", as_id = as_id.span.as_str())?; + write!(self.writer, " as {as_id}", as_id = self.source(as_id.span))?; } } @@ -258,7 +264,7 @@ impl DocumentPrinter { pub fn use_path(&mut self, path: &UsePath) -> std::fmt::Result { match path { UsePath::Package(p) => self.package_path(p), - UsePath::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + UsePath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } @@ -278,7 +284,11 @@ impl DocumentPrinter { pub fn resource_decl(&mut self, decl: &ResourceDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "resource {id} {{", id = decl.id.span.as_str())?; + write!( + self.writer, + "resource {id} {{", + id = self.source(decl.id.span) + )?; self.newline()?; self.inc(); @@ -317,7 +327,7 @@ impl DocumentPrinter { pub fn method(&mut self, method: &Method) -> std::fmt::Result { self.docs(&method.docs)?; self.indent()?; - write!(self.writer, "{id}: ", id = method.id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(method.id.span))?; if method.is_static { write!(self.writer, "static ")?; @@ -331,7 +341,7 @@ impl DocumentPrinter { pub fn func_type_ref(&mut self, ty: &FuncTypeRef) -> std::fmt::Result { match ty { FuncTypeRef::Func(ty) => self.func_type(ty), - FuncTypeRef::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + FuncTypeRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } @@ -339,7 +349,11 @@ impl DocumentPrinter { pub fn variant_decl(&mut self, decl: &VariantDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "variant {id} {{", id = decl.id.span.as_str())?; + write!( + self.writer, + "variant {id} {{", + id = self.source(decl.id.span) + )?; self.newline()?; self.inc(); @@ -359,7 +373,7 @@ impl DocumentPrinter { pub fn variant_case(&mut self, case: &VariantCase) -> std::fmt::Result { self.docs(&case.docs)?; self.indent()?; - write!(self.writer, "{id}", id = case.id.span.as_str())?; + write!(self.writer, "{id}", id = self.source(case.id.span))?; if let Some(ty) = &case.ty { write!(self.writer, "(")?; @@ -374,14 +388,18 @@ impl DocumentPrinter { pub fn record_decl(&mut self, decl: &RecordDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "record {id} {{", id = decl.id.span.as_str())?; + write!( + self.writer, + "record {id} {{", + id = self.source(decl.id.span) + )?; self.newline()?; self.inc(); for field in &decl.fields { self.docs(&field.docs)?; self.indent()?; - write!(self.writer, "{id}: ", id = field.id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(field.id.span))?; self.ty(&field.ty)?; write!(self.writer, ",")?; self.newline()?; @@ -396,14 +414,14 @@ impl DocumentPrinter { pub fn flags_decl(&mut self, decl: &FlagsDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "flags {id} {{", id = decl.id.span.as_str())?; + write!(self.writer, "flags {id} {{", id = self.source(decl.id.span))?; self.newline()?; self.inc(); for flag in &decl.flags { self.docs(&flag.docs)?; self.indent()?; - write!(self.writer, "{id},", id = flag.id.span.as_str())?; + write!(self.writer, "{id},", id = self.source(flag.id.span))?; self.newline()?; } @@ -416,14 +434,14 @@ impl DocumentPrinter { pub fn enum_decl(&mut self, decl: &EnumDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "enum {id} {{", id = decl.id.span.as_str())?; + write!(self.writer, "enum {id} {{", id = self.source(decl.id.span))?; self.newline()?; self.inc(); for case in &decl.cases { self.docs(&case.docs)?; self.indent()?; - write!(self.writer, "{id},", id = case.id.span.as_str())?; + write!(self.writer, "{id},", id = self.source(case.id.span))?; self.newline()?; } @@ -436,7 +454,7 @@ impl DocumentPrinter { pub fn type_alias(&mut self, alias: &TypeAlias) -> std::fmt::Result { self.docs(&alias.docs)?; self.indent()?; - write!(self.writer, "type {id} = ", id = alias.id.span.as_str())?; + write!(self.writer, "type {id} = ", id = self.source(alias.id.span))?; match &alias.kind { TypeAliasKind::Func(ty) => self.func_type(ty)?, TypeAliasKind::Type(ty) => self.ty(ty)?, @@ -449,7 +467,7 @@ impl DocumentPrinter { pub fn interface_export(&mut self, export: &InterfaceExport) -> std::fmt::Result { self.docs(&export.docs)?; self.indent()?; - write!(self.writer, "{id}: ", id = export.id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(export.id.span))?; self.func_type_ref(&export.ty)?; write!(self.writer, ";") } @@ -467,7 +485,11 @@ impl DocumentPrinter { pub fn interface_decl(&mut self, decl: &InterfaceDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "interface {id} {{", id = decl.id.span.as_str())?; + write!( + self.writer, + "interface {id} {{", + id = self.source(decl.id.span) + )?; self.newline()?; self.inc(); @@ -489,7 +511,7 @@ impl DocumentPrinter { pub fn world_decl(&mut self, decl: &WorldDecl) -> std::fmt::Result { self.docs(&decl.docs)?; self.indent()?; - write!(self.writer, "world {id} {{", id = decl.id.span.as_str())?; + write!(self.writer, "world {id} {{", id = self.source(decl.id.span))?; self.newline()?; self.inc(); @@ -543,20 +565,20 @@ impl DocumentPrinter { match path { WorldItemPath::Named(n) => self.named_world_item(n), WorldItemPath::Package(p) => self.package_path(p), - WorldItemPath::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + WorldItemPath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } /// Prints the given named world item. pub fn named_world_item(&mut self, item: &NamedWorldItem) -> std::fmt::Result { - write!(self.writer, "{id}: ", id = item.id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(item.id.span))?; self.extern_type(&item.ty) } /// Prints the given extern type. pub fn extern_type(&mut self, ty: &ExternType) -> std::fmt::Result { match ty { - ExternType::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + ExternType::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), ExternType::Func(ty) => self.func_type(ty), ExternType::Interface(i) => self.inline_interface(i), } @@ -579,8 +601,8 @@ impl DocumentPrinter { write!( self.writer, "{source} as {target},", - source = item.from.span.as_str(), - target = item.to.span.as_str() + source = self.source(item.from.span), + target = self.source(item.to.span) )?; self.newline()?; } @@ -596,7 +618,7 @@ impl DocumentPrinter { /// Prints the given world reference. pub fn world_ref(&mut self, reference: &WorldRef) -> std::fmt::Result { match reference { - WorldRef::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + WorldRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), WorldRef::Package(p) => self.package_path(p), } } @@ -616,7 +638,7 @@ impl DocumentPrinter { pub fn let_statement(&mut self, stmt: &LetStatement) -> std::fmt::Result { self.docs(&stmt.docs)?; self.indent()?; - write!(self.writer, "let {id} = ", id = stmt.id.span.as_str())?; + write!(self.writer, "let {id} = ", id = self.source(stmt.id.span))?; self.expr(&stmt.expr)?; write!(self.writer, ";") } @@ -640,7 +662,7 @@ impl DocumentPrinter { self.expr(&e.0)?; write!(self.writer, ")") } - PrimaryExpr::Ident(id) => write!(self.writer, "{id}", id = id.span.as_str()), + PrimaryExpr::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)), } } @@ -649,7 +671,7 @@ impl DocumentPrinter { write!( self.writer, "new {name} {{", - name = expr.package.span.as_str() + name = self.source(expr.package.span) )?; if expr.arguments.is_empty() { @@ -671,16 +693,16 @@ impl DocumentPrinter { InstantiationArgument::Named(arg) => { match &arg.name { InstantiationArgumentName::Ident(id) => { - write!(self.writer, "{id}: ", id = id.span.as_str())?; + write!(self.writer, "{id}: ", id = self.source(id.span))?; } InstantiationArgumentName::String(s) => { - write!(self.writer, "{s}: ", s = s.span.as_str())?; + write!(self.writer, "{s}: ", s = self.source(s.span))?; } } self.expr(&arg.expr)?; } InstantiationArgument::Ident(id) => { - write!(self.writer, "{id}", id = id.span.as_str())? + write!(self.writer, "{id}", id = self.source(id.span))? } } @@ -709,12 +731,16 @@ impl DocumentPrinter { /// Prints the given access expression. pub fn access_expr(&mut self, expr: &AccessExpr) -> std::fmt::Result { - write!(self.writer, ".{id}", id = expr.id.span.as_str()) + write!(self.writer, ".{id}", id = self.source(expr.id.span)) } /// Prints the given named access expression. pub fn named_access_expr(&mut self, expr: &NamedAccessExpr) -> std::fmt::Result { - write!(self.writer, "[{name}]", name = expr.string.span.as_str()) + write!( + self.writer, + "[{name}]", + name = self.source(expr.string.span) + ) } /// Prints the given export statement. @@ -726,7 +752,7 @@ impl DocumentPrinter { self.expr(&stmt.expr)?; if let Some(with) = &stmt.with { - write!(self.writer, " with {with}", with = with.span.as_str())?; + write!(self.writer, " with {with}", with = self.source(with.span))?; } write!(self.writer, ";") @@ -757,4 +783,8 @@ impl DocumentPrinter { fn dec(&mut self) { self.indent = self.indent.saturating_sub(1); } + + fn source(&self, span: SourceSpan) -> &'a str { + &self.source[span.offset()..span.offset() + span.len()] + } } diff --git a/crates/wac-parser/src/ast/type.rs b/crates/wac-parser/src/ast/type.rs index ff679fe..fabe679 100644 --- a/crates/wac-parser/src/ast/type.rs +++ b/crates/wac-parser/src/ast/type.rs @@ -1,8 +1,9 @@ use super::{ - display, parse_delimited, parse_optional, parse_token, DocComment, Error, Ident, Lookahead, - PackagePath, Parse, ParseResult, Peek, + parse_delimited, parse_optional, parse_token, DocComment, Error, Ident, Lookahead, PackagePath, + Parse, ParseResult, Peek, }; -use crate::lexer::{Lexer, Span, Token}; +use crate::lexer::{Lexer, Token}; +use miette::SourceSpan; use serde::Serialize; /// Represents a type statement in the AST. @@ -18,7 +19,7 @@ pub enum TypeStatement<'a> { } impl<'a> Parse<'a> for TypeStatement<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if InterfaceDecl::peek(&mut lookahead) { Ok(Self::Interface(Parse::parse(lexer)?)) @@ -40,8 +41,6 @@ impl Peek for TypeStatement<'_> { } } -display!(TypeStatement, type_statement); - /// Represents a top-level type declaration in the AST. /// /// Unlike tin interfaces and worlds, resources cannot @@ -75,7 +74,7 @@ impl TypeDecl<'_> { } impl<'a> Parse<'a> for TypeDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::VariantKeyword) { Ok(Self::Variant(Parse::parse(lexer)?)) @@ -116,7 +115,7 @@ pub struct ResourceDecl<'a> { } impl<'a> Parse<'a> for ResourceDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::ResourceKeyword)?; let id = Ident::parse(lexer)?; @@ -150,7 +149,7 @@ pub struct VariantDecl<'a> { } impl<'a> Parse<'a> for VariantDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::VariantKeyword)?; let id = Ident::parse(lexer)?; @@ -183,7 +182,7 @@ pub struct VariantCase<'a> { } impl<'a> Parse<'a> for VariantCase<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let id = Ident::parse(lexer)?; let ty = parse_optional(lexer, Token::OpenParen, |lexer| { @@ -214,7 +213,7 @@ pub struct RecordDecl<'a> { } impl<'a> Parse<'a> for RecordDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::RecordKeyword)?; let id = Ident::parse(lexer)?; @@ -247,7 +246,7 @@ pub struct Field<'a> { } impl<'a> Parse<'a> for Field<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let named: NamedType = Parse::parse(lexer)?; Ok(Self { @@ -277,7 +276,7 @@ pub struct FlagsDecl<'a> { } impl<'a> Parse<'a> for FlagsDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::FlagsKeyword)?; let id = Ident::parse(lexer)?; @@ -308,7 +307,7 @@ pub struct Flag<'a> { } impl<'a> Parse<'a> for Flag<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let id = Ident::parse(lexer)?; Ok(Self { docs, id }) @@ -334,7 +333,7 @@ pub struct EnumDecl<'a> { } impl<'a> Parse<'a> for EnumDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::EnumKeyword)?; let id = Ident::parse(lexer)?; @@ -365,7 +364,7 @@ pub struct EnumCase<'a> { } impl<'a> Parse<'a> for EnumCase<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let id = Ident::parse(lexer)?; Ok(Self { docs, id }) @@ -389,7 +388,7 @@ pub enum ResourceMethod<'a> { } impl<'a> Parse<'a> for ResourceMethod<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::ConstructorKeyword) { Ok(Self::Constructor(Parse::parse(lexer)?)) @@ -414,13 +413,13 @@ pub struct Constructor<'a> { /// The doc comments for the constructor. pub docs: Vec>, /// The span of the constructor keyword. - pub span: Span<'a>, + pub span: SourceSpan, /// The parameters of the constructor. pub params: Vec>, } impl<'a> Parse<'a> for Constructor<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let span = parse_token(lexer, Token::ConstructorKeyword)?; parse_token(lexer, Token::OpenParen)?; @@ -446,7 +445,7 @@ pub struct Method<'a> { } impl<'a> Parse<'a> for Method<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let id = Ident::parse(lexer)?; parse_token(lexer, Token::Colon)?; @@ -481,7 +480,7 @@ pub enum FuncTypeRef<'a> { } impl<'a> Parse<'a> for FuncTypeRef<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::FuncKeyword) { Ok(Self::Func(Parse::parse(lexer)?)) @@ -504,7 +503,7 @@ pub struct FuncType<'a> { } impl<'a> Parse<'a> for FuncType<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { parse_token(lexer, Token::FuncKeyword)?; parse_token(lexer, Token::OpenParen)?; let params = parse_delimited(lexer, &[Token::CloseParen], true)?; @@ -535,7 +534,7 @@ pub enum ResultList<'a> { } impl<'a> Parse<'a> for ResultList<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::OpenParen) { parse_token(lexer, Token::OpenParen)?; @@ -561,7 +560,7 @@ pub struct NamedType<'a> { } impl<'a> Parse<'a> for NamedType<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let id = Ident::parse(lexer)?; parse_token(lexer, Token::Colon)?; let ty = Parse::parse(lexer)?; @@ -588,7 +587,7 @@ pub struct TypeAlias<'a> { } impl<'a> Parse<'a> for TypeAlias<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::TypeKeyword)?; let id = Ident::parse(lexer)?; @@ -610,7 +609,7 @@ pub enum TypeAliasKind<'a> { } impl<'a> Parse<'a> for TypeAliasKind<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::FuncKeyword) { Ok(Self::Func(Parse::parse(lexer)?)) @@ -627,37 +626,37 @@ impl<'a> Parse<'a> for TypeAliasKind<'a> { #[serde(rename_all = "camelCase")] pub enum Type<'a> { /// A `u8` type. - U8(Span<'a>), + U8(SourceSpan), /// A `s8` type. - S8(Span<'a>), + S8(SourceSpan), /// A `u16` type. - U16(Span<'a>), + U16(SourceSpan), /// A `s16` type. - S16(Span<'a>), + S16(SourceSpan), /// A `u32` type. - U32(Span<'a>), + U32(SourceSpan), /// A `s32` type. - S32(Span<'a>), + S32(SourceSpan), /// A `u64` type. - U64(Span<'a>), + U64(SourceSpan), /// A `s64` type. - S64(Span<'a>), + S64(SourceSpan), /// A `float32` type. - Float32(Span<'a>), + Float32(SourceSpan), /// A `float64` type. - Float64(Span<'a>), + Float64(SourceSpan), /// A `char` type. - Char(Span<'a>), + Char(SourceSpan), /// A `bool` type. - Bool(Span<'a>), + Bool(SourceSpan), /// A `string` type. - String(Span<'a>), + String(SourceSpan), /// A tuple type. - Tuple(Vec>, Span<'a>), + Tuple(Vec>, SourceSpan), /// A list type. - List(Box>, Span<'a>), + List(Box>, SourceSpan), /// An option type. - Option(Box>, Span<'a>), + Option(Box>, SourceSpan), /// A result type. Result { /// The `ok` of the result type. @@ -665,17 +664,17 @@ pub enum Type<'a> { /// The `err` of the result type. err: Option>>, /// The span of the result type. - span: Span<'a>, + span: SourceSpan, }, /// A borrow type. - Borrow(Ident<'a>, Span<'a>), + Borrow(Ident<'a>, SourceSpan), /// An identifier to a value type. Ident(Ident<'a>), } impl<'a> Type<'a> { /// Gets the span of the type. - pub fn span(&self) -> Span<'a> { + pub fn span(&self) -> SourceSpan { match self { Self::U8(span) | Self::S8(span) @@ -701,7 +700,7 @@ impl<'a> Type<'a> { } impl<'a> Parse<'a> for Type<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::U8Keyword) { Ok(Self::U8(lexer.next().unwrap().1)) @@ -730,7 +729,7 @@ impl<'a> Parse<'a> for Type<'a> { } else if lookahead.peek(Token::StringKeyword) { Ok(Self::String(lexer.next().unwrap().1)) } else if lookahead.peek(Token::TupleKeyword) { - let mut span = lexer.next().unwrap().1; + let span = lexer.next().unwrap().1; parse_token(lexer, Token::OpenAngle)?; // There must be at least one type in the tuple. @@ -742,22 +741,37 @@ impl<'a> Parse<'a> for Type<'a> { let types = parse_delimited(lexer, &[Token::CloseAngle], true)?; assert!(!types.is_empty()); let close = parse_token(lexer, Token::CloseAngle)?; - span.end = close.end; - Ok(Self::Tuple(types, span)) + Ok(Self::Tuple( + types, + SourceSpan::new( + span.offset().into(), + ((close.offset() + close.len()) - span.offset()).into(), + ), + )) } else if lookahead.peek(Token::ListKeyword) { - let mut span = lexer.next().unwrap().1; + let span = lexer.next().unwrap().1; parse_token(lexer, Token::OpenAngle)?; let ty = Box::new(Parse::parse(lexer)?); let close = parse_token(lexer, Token::CloseAngle)?; - span.end = close.end; - Ok(Self::List(ty, span)) + Ok(Self::List( + ty, + SourceSpan::new( + span.offset().into(), + ((close.offset() + close.len()) - span.offset()).into(), + ), + )) } else if lookahead.peek(Token::OptionKeyword) { - let mut span = lexer.next().unwrap().1; + let span = lexer.next().unwrap().1; parse_token(lexer, Token::OpenAngle)?; let ty = Box::new(Parse::parse(lexer)?); let close = parse_token(lexer, Token::CloseAngle)?; - span.end = close.end; - Ok(Self::Option(ty, span)) + Ok(Self::Option( + ty, + SourceSpan::new( + span.offset().into(), + ((close.offset() + close.len()) - span.offset()).into(), + ), + )) } else if lookahead.peek(Token::ResultKeyword) { let mut span = lexer.next().unwrap().1; let (ok, err) = match parse_optional(lexer, Token::OpenAngle, |lexer| { @@ -785,7 +799,10 @@ impl<'a> Parse<'a> for Type<'a> { .unwrap_or(None); let close = parse_token(lexer, Token::CloseAngle)?; - span.end = close.end; + span = SourceSpan::new( + span.offset().into(), + ((close.offset() + close.len()) - span.offset()).into(), + ); Ok((ok, err)) })? { Some((ok, err)) => (ok, err), @@ -793,12 +810,17 @@ impl<'a> Parse<'a> for Type<'a> { }; Ok(Self::Result { ok, err, span }) } else if lookahead.peek(Token::BorrowKeyword) { - let mut span = lexer.next().unwrap().1; + let span = lexer.next().unwrap().1; parse_token(lexer, Token::OpenAngle)?; let id = Parse::parse(lexer)?; let close = parse_token(lexer, Token::CloseAngle)?; - span.end = close.end; - Ok(Self::Borrow(id, span)) + Ok(Self::Borrow( + id, + SourceSpan::new( + span.offset().into(), + ((close.offset() + close.len()) - span.offset()).into(), + ), + )) } else if Ident::peek(&mut lookahead) { Ok(Self::Ident(Parse::parse(lexer)?)) } else { @@ -853,7 +875,7 @@ pub enum ItemTypeDecl<'a> { } impl<'a> Parse<'a> for ItemTypeDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if lookahead.peek(Token::ResourceKeyword) { Ok(Self::Resource(Parse::parse(lexer)?)) @@ -911,7 +933,7 @@ pub struct InterfaceDecl<'a> { } impl<'a> Parse<'a> for InterfaceDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::InterfaceKeyword)?; let id = Ident::parse(lexer)?; @@ -928,8 +950,6 @@ impl Peek for InterfaceDecl<'_> { } } -display!(InterfaceDecl, interface_decl); - /// Represents an interface item in the AST. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] @@ -943,7 +963,7 @@ pub enum InterfaceItem<'a> { } impl<'a> Parse<'a> for InterfaceItem<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if Use::peek(&mut lookahead) { Ok(Self::Use(Box::new(Parse::parse(lexer)?))) @@ -976,7 +996,7 @@ pub struct Use<'a> { } impl<'a> Parse<'a> for Use<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::UseKeyword)?; let path = Parse::parse(lexer)?; @@ -1006,8 +1026,8 @@ pub enum UsePath<'a> { } impl<'a> Parse<'a> for UsePath<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { - let mut lookahead: Lookahead<'_> = Lookahead::new(lexer); + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { + let mut lookahead = Lookahead::new(lexer); if PackagePath::peek(&mut lookahead) { Ok(Self::Package(Parse::parse(lexer)?)) } else if Ident::peek(&mut lookahead) { @@ -1035,7 +1055,7 @@ pub struct UseItem<'a> { } impl<'a> Parse<'a> for UseItem<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let id = Ident::parse(lexer)?; let as_id = parse_optional(lexer, Token::AsKeyword, Ident::parse)?; Ok(Self { id, as_id }) @@ -1061,7 +1081,7 @@ pub struct InterfaceExport<'a> { } impl<'a> Parse<'a> for InterfaceExport<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; let id = Ident::parse(lexer)?; parse_token(lexer, Token::Colon)?; @@ -1090,7 +1110,7 @@ pub struct WorldDecl<'a> { } impl<'a> Parse<'a> for WorldDecl<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::WorldKeyword)?; let id = Ident::parse(lexer)?; @@ -1107,8 +1127,6 @@ impl Peek for WorldDecl<'_> { } } -display!(WorldDecl, world_decl); - /// Represents a world item in the AST. #[derive(Debug, Clone, Serialize)] #[serde(rename_all = "camelCase")] @@ -1126,7 +1144,7 @@ pub enum WorldItem<'a> { } impl<'a> Parse<'a> for WorldItem<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if Use::peek(&mut lookahead) { Ok(Self::Use(Parse::parse(lexer)?)) @@ -1165,7 +1183,7 @@ pub struct WorldImport<'a> { } impl<'a> Parse<'a> for WorldImport<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::ImportKeyword)?; let path = Parse::parse(lexer)?; @@ -1191,7 +1209,7 @@ pub struct WorldExport<'a> { } impl<'a> Parse<'a> for WorldExport<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::ExportKeyword)?; let path = Parse::parse(lexer)?; @@ -1219,7 +1237,7 @@ pub enum WorldItemPath<'a> { } impl<'a> Parse<'a> for WorldItemPath<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if PackagePath::peek(&mut lookahead) { Ok(Self::Package(Parse::parse(lexer)?)) @@ -1247,7 +1265,7 @@ pub struct NamedWorldItem<'a> { } impl<'a> Parse<'a> for NamedWorldItem<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let id = Ident::parse(lexer)?; parse_token(lexer, Token::Colon)?; let ty = Parse::parse(lexer)?; @@ -1268,7 +1286,7 @@ pub enum ExternType<'a> { } impl<'a> Parse<'a> for ExternType<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if Ident::peek(&mut lookahead) { Ok(Self::Ident(Parse::parse(lexer)?)) @@ -1291,7 +1309,7 @@ pub struct InlineInterface<'a> { } impl<'a> Parse<'a> for InlineInterface<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { parse_token(lexer, Token::InterfaceKeyword)?; parse_token(lexer, Token::OpenBrace)?; let items = parse_delimited(lexer, &[Token::CloseBrace], false)?; @@ -1319,7 +1337,7 @@ pub struct WorldInclude<'a> { } impl<'a> Parse<'a> for WorldInclude<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let docs = Parse::parse(lexer)?; parse_token(lexer, Token::IncludeKeyword)?; let world = Parse::parse(lexer)?; @@ -1356,12 +1374,12 @@ impl<'a> WorldRef<'a> { pub fn name(&self) -> &'a str { match self { Self::Ident(id) => id.string, - Self::Package(path) => path.span.as_str(), + Self::Package(path) => path.string, } } /// Gets the span of the world reference. - pub fn span(&self) -> Span<'a> { + pub fn span(&self) -> SourceSpan { match self { Self::Ident(id) => id.span, Self::Package(path) => path.span, @@ -1370,7 +1388,7 @@ impl<'a> WorldRef<'a> { } impl<'a> Parse<'a> for WorldRef<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let mut lookahead = Lookahead::new(lexer); if PackagePath::peek(&mut lookahead) { Ok(Self::Package(Parse::parse(lexer)?)) @@ -1393,7 +1411,7 @@ pub struct WorldIncludeItem<'a> { } impl<'a> Parse<'a> for WorldIncludeItem<'a> { - fn parse(lexer: &mut Lexer<'a>) -> ParseResult<'a, Self> { + fn parse(lexer: &mut Lexer<'a>) -> ParseResult { let from = Ident::parse(lexer)?; parse_token(lexer, Token::AsKeyword)?; let to = Ident::parse(lexer)?; @@ -1409,13 +1427,13 @@ impl Peek for WorldIncludeItem<'_> { #[cfg(test)] mod test { - use super::*; use crate::ast::test::roundtrip; #[test] fn resource_roundtrip() { - roundtrip::( - r#"interface i { resource foo-bar { + roundtrip( + r#"package foo:bar; +interface i { resource foo-bar { /** A constructor */ constructor(foo: u8, bar: u8); /// A method @@ -1425,7 +1443,9 @@ mod test { /// A static method id: static func() -> u32; }}"#, - r#"interface i { + r#"package foo:bar; + +interface i { resource foo-bar { /// A constructor constructor(foo: u8, bar: u8); @@ -1439,117 +1459,137 @@ mod test { /// A static method id: static func() -> u32; } -}"#, +} +"#, ) .unwrap(); } #[test] fn variant_roundtrip() { - roundtrip::( - r#"variant foo { + roundtrip( + r#"package foo:bar; +variant foo { foo, bar(u32), baz(bar), qux(tuple) }"#, - r#"variant foo { + r#"package foo:bar; + +variant foo { foo, bar(u32), baz(bar), qux(tuple), -}"#, +} +"#, ) .unwrap(); } #[test] fn record_roundtrip() { - roundtrip::( - r#"record foo-bar2-baz { + roundtrip( + r#"package foo:bar; +record foo-bar2-baz { foo: foo, bar-qux: list, // A comment jam: borrow, }"#, - r#"record foo-bar2-baz { + r#"package foo:bar; + +record foo-bar2-baz { foo: foo, bar-qux: list, jam: borrow, -}"#, +} +"#, ) .unwrap(); } #[test] fn flags_roundtrip() { - roundtrip::( - r#"flags %flags { + roundtrip( + r#"package foo:bar; +flags %flags { foo, bar, baz }"#, - r#"flags %flags { + r#"package foo:bar; + +flags %flags { foo, bar, baz, -}"#, +} +"#, ) .unwrap(); } #[test] fn enum_roundtrip() { - roundtrip::( - r#"enum foo { + roundtrip( + r#"package foo:bar; enum foo { foo, bar, baz }"#, - r#"enum foo { + r#"package foo:bar; + +enum foo { foo, bar, baz, -}"#, +} +"#, ) .unwrap(); } #[test] fn func_type_alias_roundtrip() { - roundtrip::( - r#"type x = func(a: /* comment */ string) -> string;"#, - r#"type x = func(a: string) -> string;"#, + roundtrip( + r#"package foo:bar; type x = func(a: /* comment */ string) -> string;"#, + "package foo:bar;\n\ntype x = func(a: string) -> string;\n", ) .unwrap(); } #[test] fn type_alias_roundtrip() { - roundtrip::( - r#"type x = tuple>, option>, result, result, result<_, string>, result, borrow, y>;"#, - r#"type x = tuple>, option>, result, result, result<_, string>, result, borrow, y>;"#, + roundtrip( + r#"package foo:bar; type x = tuple>, option>, result, result, result<_, string>, result, borrow, y>;"#, + "package foo:bar;\n\ntype x = tuple>, option>, result, result, result<_, string>, result, borrow, y>;\n", ) .unwrap(); } #[test] fn interface_roundtrip() { - roundtrip::( - r#"interface foo { - /// Type t - type t = list; + roundtrip( + r#"package foo:bar; + +interface foo { + /// Type t + type t = list; - /// Use x and y - use foo.{ x, y, }; + /// Use x and y + use foo.{ x, y, }; - /// Function a - a: func(a: string, b: string) -> string; + /// Function a + a: func(a: string, b: string) -> string; - // not a doc comment - type x = func() -> list; + // not a doc comment + type x = func() -> list; - /// Function b - b: x; + /// Function b + b: x; } "#, - r#"interface foo { + r#"package foo:bar; + +interface foo { /// Type t type t = list; @@ -1563,79 +1603,80 @@ mod test { /// Function b b: x; -}"#, +} +"#, ) .unwrap(); } #[test] fn world_roundtrip() { - roundtrip::( - r#"world foo { - /// Type t - type t = list; + roundtrip( + r#"package foo:bar; - // not a doc comment - type x = func() -> list; +world foo { + /// Type t + type t = list; - use foo.{ y, }; + // not a doc comment + type x = func() -> list; - /// Import with function type. - import a: func(a: string, b: string) -> string; + use foo.{ y, }; + + /// Import with function type. + import a: func(a: string, b: string) -> string; - /// Import with identifier. - import b: x; + /// Import with identifier. + import b: x; - /// Import with inline interface. - import c: interface { - /// Function a - a: func(a: string, b: string) -> string; - }; + /// Import with inline interface. + import c: interface { + /// Function a + a: func(a: string, b: string) -> string; + }; - /// Import with package path - import foo:bar/baz@1.0.0; + /// Import with package path + import foo:bar/baz@1.0.0; - /// Export with function type. - export a: func(a: string, b: string) -> string; + /// Export with function type. + export a: func(a: string, b: string) -> string; - /// Export with identifier. - export b: x; + /// Export with identifier. + export b: x; - /// Export with inline interface. - export c: interface { - /// Function a - a: func(a: string, b: string) -> string; - }; + /// Export with inline interface. + export c: interface { + /// Function a + a: func(a: string, b: string) -> string; + }; - /// Export with package path - export foo:bar/baz@1.0.0; + /// Export with package path + export foo:bar/baz@1.0.0; - /// Include world from package path with 2 renames. - include foo:bar/baz with { a as a1, b as b1 }; + /// Include world from package path with 2 renames. + include foo:bar/baz with { a as a1, b as b1 }; - /// Include world from package path with 1 rename. - include foo:bar/baz with {foo as foo1}; + /// Include world from package path with 1 rename. + include foo:bar/baz with {foo as foo1}; - /// Include world from package path (spacing). - include foo:bar/baz with { foo as foo1 }; + /// Include world from package path (spacing). + include foo:bar/baz with { foo as foo1 }; - /// Include world from package path newline delimited renaming. - include foo:bar/baz with { - foo as foo1, - bar as bar1 - }; + /// Include world from package path newline delimited renaming. + include foo:bar/baz with { + foo as foo1, + bar as bar1 + }; - /// Include local world. - include foo-bar; + /// Include local world. + include foo-bar; - /// Include local world with renaming. - include foo-bar with { foo as bar }; -}; + /// Include local world with renaming. + include foo-bar with { foo as bar }; +}"#, + r#"package foo:bar; -include my-world; -} - "#, - r#"world foo { +world foo { /// Type t type t = list; @@ -1702,7 +1743,8 @@ include my-world; include foo-bar with { foo as bar, }; -}"#, +} +"#, ) .unwrap(); } diff --git a/crates/wac-parser/src/lexer.rs b/crates/wac-parser/src/lexer.rs index efa15a1..de0b531 100644 --- a/crates/wac-parser/src/lexer.rs +++ b/crates/wac-parser/src/lexer.rs @@ -1,65 +1,11 @@ //! Module for the lexer implementation. use logos::{Logos, SpannedIter}; -use serde::{Serialize, Serializer}; +use miette::SourceSpan; use std::fmt; -/// Represents a span in a source string. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct Span<'a> { - source: &'a str, - /// The start of the span. - pub start: usize, - /// The end of the span. - pub end: usize, -} - -impl<'a> Span<'a> { - fn from_lexer(lexer: &logos::Lexer<'a, T>) -> Self - where - T: logos::Logos<'a, Source = str>, - { - let source = lexer.source(); - let span = lexer.span(); - Self { - source, - start: span.start, - end: span.end, - } - } - - pub(crate) fn from_span(source: &'a str, span: &logos::Span) -> Self { - Self { - source, - start: span.start, - end: span.end, - } - } - - /// Gets the source code associated with the span. - pub fn source(&self) -> &'a str { - self.source - } - - /// Returns the spanned string. - pub fn as_str(&self) -> &'a str { - &self.source[self.start..self.end] - } -} - -impl Serialize for Span<'_> { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - use serde::ser::SerializeStruct; - - let mut s = serializer.serialize_struct("Span", 3)?; - s.serialize_field("str", self.as_str())?; - s.serialize_field("start", &self.start)?; - s.serialize_field("end", &self.end)?; - s.end() - } +fn to_source_span(span: logos::Span) -> SourceSpan { + SourceSpan::new(span.start.into(), (span.end - span.start).into()) } /// Represents a lexer error. @@ -92,7 +38,7 @@ impl From<()> for Error { } } -fn detect_invalid_input(source: &str) -> Result<(), (Error, Span)> { +fn detect_invalid_input(source: &str) -> Result<(), (Error, SourceSpan)> { for (offset, ch) in source.char_indices() { match ch { '\r' | '\t' | '\n' => {} @@ -106,7 +52,7 @@ fn detect_invalid_input(source: &str) -> Result<(), (Error, Span)> { | '\u{2067}' | '\u{2068}' | '\u{2069}' => { return Err(( Error::DisallowedBidirectionalOverride(ch), - Span::from_span(source, &(offset..offset + ch.len_utf8())), + SourceSpan::new(offset.into(), ch.len_utf8().into()), )); } @@ -121,7 +67,7 @@ fn detect_invalid_input(source: &str) -> Result<(), (Error, Span)> { | '\u{17b4}' | '\u{17b5}' => { return Err(( Error::DiscouragedUnicodeCodepoint(ch), - Span::from_span(source, &(offset..offset + ch.len_utf8())), + SourceSpan::new(offset.into(), ch.len_utf8().into()), )); } @@ -131,7 +77,7 @@ fn detect_invalid_input(source: &str) -> Result<(), (Error, Span)> { ch if ch.is_control() => { return Err(( Error::DisallowedControlCode(ch), - Span::from_span(source, &(offset..offset + ch.len_utf8())), + SourceSpan::new(offset.into(), ch.len_utf8().into()), )); } @@ -494,47 +440,54 @@ mod helpers { } /// The result type for the lexer. -pub type LexerResult<'a, T> = Result; +pub type LexerResult = Result; /// Implements a WAC lexer. pub struct Lexer<'a>(SpannedIter<'a, Token>); impl<'a> Lexer<'a> { /// Creates a new lexer for the given source string. - pub fn new(source: &'a str) -> Result)> { + pub fn new(source: &'a str) -> Result { detect_invalid_input(source)?; Ok(Self(Token::lexer(source).spanned())) } - /// Source from which this lexer is reading tokens. - pub fn source<'b>(&'b self) -> &'a str { - self.0.source() + /// Gets the source string of the given span. + pub fn source(&self, span: SourceSpan) -> &'a str { + &self.0.source()[span.offset()..span.offset() + span.len()] } /// Gets the current span of the lexer. - pub fn span<'b>(&'b self) -> Span<'a> { - Span::from_lexer(&self.0) + pub fn span(&self) -> SourceSpan { + let mut span = self.0.span(); + if span.end == self.0.source().len() { + // Currently miette silently fails to display a label + // if the span is at the end of the source; this means + // we can't properly show the "end of input" span. + // For now, have the span point at the last byte in the source. + // See: https://github.com/zkat/miette/issues/219 + span.start -= 1; + span.end = span.start + 1; + } + + to_source_span(span) } /// Peeks at the next token. - pub fn peek<'b>(&'b self) -> Option<(LexerResult<'a, Token>, Span<'a>)> { + pub fn peek(&self) -> Option<(LexerResult, SourceSpan)> { let mut lexer = self.0.clone().spanned(); - lexer - .next() - .map(|(r, s)| (r, Span::from_span(self.0.source(), &s))) + lexer.next().map(|(r, s)| (r, to_source_span(s))) } /// Peeks at the token after the next token. - pub fn peek2<'b>(&'b self) -> Option<(LexerResult<'a, Token>, Span<'a>)> { + pub fn peek2(&self) -> Option<(LexerResult, SourceSpan)> { let mut lexer = self.0.clone().spanned(); lexer.next(); - lexer - .next() - .map(|(r, s)| (r, Span::from_span(self.0.source(), &s))) + lexer.next().map(|(r, s)| (r, to_source_span(s))) } /// Consumes available documentation comment tokens. - pub fn comments<'b>(&'b self) -> Result)>, (Error, Span<'a>)> { + pub fn comments<'b>(&'b self) -> Result, (Error, SourceSpan)> { let mut comments = Vec::new(); let mut lexer = self.0.clone().morph::().spanned(); while let Some((Ok(token), span)) = lexer.next() { @@ -550,14 +503,7 @@ impl<'a> Lexer<'a> { } else { continue; }; - comments.push(( - c, - Span { - source: self.0.source(), - start: span.start, - end: span.end, - }, - )); + comments.push((c, to_source_span(span))); } } } @@ -566,12 +512,10 @@ impl<'a> Lexer<'a> { } impl<'a> Iterator for Lexer<'a> { - type Item = (LexerResult<'a, Token>, Span<'a>); + type Item = (LexerResult, SourceSpan); fn next(&mut self) -> Option { - self.0 - .next() - .map(|(r, s)| (r, Span::from_span(self.0.source(), &s))) + self.0.next().map(|(r, s)| (r, to_source_span(s))) } } diff --git a/crates/wac-parser/src/lib.rs b/crates/wac-parser/src/lib.rs index 39be82e..c786f08 100644 --- a/crates/wac-parser/src/lib.rs +++ b/crates/wac-parser/src/lib.rs @@ -2,156 +2,8 @@ #![deny(missing_docs)] -use anyhow::Chain; -use lexer::Span; -use owo_colors::{OwoColorize, Style}; -use std::{ - fmt::{self, Write}, - path::Path, -}; - pub mod ast; pub mod lexer; mod resolution; pub use resolution::*; - -/// Gets the 1-based line and column of a position within a source. -pub(crate) fn line_column(source: &str, pos: usize) -> (usize, usize) { - let mut cur = 0; - // Use split_terminator instead of lines so that if there is a `\r`, - // it is included in the offset calculation. The `+1` values below - // account for the `\n`. - for (i, line) in source.split_terminator('\n').enumerate() { - if cur + line.len() + 1 > pos { - return (i + 1, pos - cur + 1); - } - - cur += line.len() + 1; - } - - (source.lines().count() + 1, 1) -} - -/// Implemented on spanned error types. -pub trait Spanned { - /// Gets the span of the error. - fn span(&self) -> Span; -} - -/// A formatter for spanned errors. -pub struct ErrorFormatter { - path: P, - error: E, - colorize: bool, -} - -impl ErrorFormatter -where - P: AsRef, - E: std::error::Error + Spanned, -{ - /// Creates a new error formatter. - pub fn new(path: P, error: E, colorize: bool) -> Self { - Self { - path, - error, - colorize, - } - } -} - -struct Indented<'a, D> { - inner: &'a mut D, - number: Option, - started: bool, -} - -// Copied from anyhow's error formatter -// https://github.com/dtolnay/anyhow/blob/05e413219e97f101d8f39a90902e5c5d39f951fe/src/fmt.rs#L73 -impl Write for Indented<'_, T> -where - T: Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - for (i, line) in s.split('\n').enumerate() { - if !self.started { - self.started = true; - match self.number { - Some(number) => write!(self.inner, "{: >5}: ", number)?, - None => self.inner.write_str(" ")?, - } - } else if i > 0 { - self.inner.write_char('\n')?; - if self.number.is_some() { - self.inner.write_str(" ")?; - } else { - self.inner.write_str(" ")?; - } - } - - self.inner.write_str(line)?; - } - - Ok(()) - } -} - -impl fmt::Display for ErrorFormatter -where - P: AsRef, - E: std::error::Error + Spanned, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let span = self.error.span(); - let (line, column) = line_column(span.source(), span.start); - let snippet = span.source().lines().nth(line - 1).unwrap_or(""); - - let (bold, blue) = if self.colorize { - (Style::new().bold(), Style::new().blue().bold()) - } else { - (Style::new(), Style::new()) - }; - - write!( - f, - "{error}\n {arrow} {path}:{lineno}:{column}\n {bar}\n{line:4} {bar} {snippet}\n {bar} {marker:>0$}", - column, - error = self.error.style(bold), - arrow = "-->".style(blue), - path = self.path.as_ref().display(), - lineno = line, - bar = "|".style(blue), - line = line.style(blue), - marker = "^".style(blue), - )?; - - if let Some(s) = span.source().get(span.start..span.end) { - for _ in s.chars().skip(2) { - write!(f, "{}", "-".style(blue))?; - } - - if s.len() > 1 { - write!(f, "{}", "^".style(blue))?; - } - } - - writeln!(f)?; - - if let Some(cause) = self.error.source() { - write!(f, "\nCaused by:")?; - let multiple = cause.source().is_some(); - for (n, error) in Chain::new(cause).enumerate() { - writeln!(f)?; - let mut indented = Indented { - inner: f, - number: if multiple { Some(n) } else { None }, - started: false, - }; - write!(indented, "{}", error)?; - } - } - - Ok(()) - } -} diff --git a/crates/wac-parser/src/resolution.rs b/crates/wac-parser/src/resolution.rs index 4fd0ab3..8a43003 100644 --- a/crates/wac-parser/src/resolution.rs +++ b/crates/wac-parser/src/resolution.rs @@ -1,17 +1,14 @@ //! Module for resolving WAC documents. use self::{encoding::Encoder, package::Package}; -use crate::{lexer::Span, resolution::ast::AstResolver, Spanned}; +use crate::resolution::ast::AstResolver; use anyhow::Context; use id_arena::{Arena, Id}; use indexmap::IndexMap; +use miette::{Diagnostic, SourceSpan}; use semver::Version; use serde::{Serialize, Serializer}; -use std::{ - collections::HashMap, - fmt, fs, - path::{Path, PathBuf}, -}; +use std::{collections::HashMap, fmt, fs, path::PathBuf}; use wit_parser::Resolve; mod ast; @@ -115,7 +112,7 @@ impl fmt::Display for ExternKind { } } -struct InterfaceNameDisplay<'a>(Option<&'a str>); +struct InterfaceNameDisplay<'a>(&'a Option); impl fmt::Display for InterfaceNameDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -126,7 +123,7 @@ impl fmt::Display for InterfaceNameDisplay<'_> { } } -struct ParentPathDisplay<'a>(Option<&'static str>, &'a str); +struct ParentPathDisplay<'a>(&'a Option, &'a str); impl fmt::Display for ParentPathDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -140,39 +137,40 @@ impl fmt::Display for ParentPathDisplay<'_> { } /// Represents a resolution error. -#[derive(thiserror::Error, Debug)] -pub enum Error<'a> { +#[derive(thiserror::Error, Diagnostic, Debug)] +#[diagnostic(code("failed to resolve document"))] +pub enum Error { /// An undefined name was encountered. #[error("undefined name `{name}`")] UndefinedName { /// The name that was undefined. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "undefined name `{name}`")] + span: SourceSpan, }, /// A duplicate name was encountered. - #[error("`{name}` was previously defined at {path}:{line}:{column}", path = .path.display())] + #[error("`{name}` is already defined")] DuplicateName { /// The duplicate name. - name: &'a str, - /// The path to the source file. - path: &'a Path, - /// The line where the identifier was previously defined. - line: usize, - /// The column where the identifier was previously defined. - column: usize, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` redefined here")] + span: SourceSpan, + /// The span where the name was previously defined. + #[label("`{name}` previously defined here")] + previous: SourceSpan, }, /// Duplicate interface export. - #[error("duplicate interface export `{name}`{iface}", iface = InterfaceNameDisplay(*.interface_name))] + #[error("duplicate interface export `{name}`{iface}", iface = InterfaceNameDisplay(.interface_name))] DuplicateInterfaceExport { /// The name of the duplicate export. - name: &'a str, + name: String, /// The name of the interface. - interface_name: Option<&'a str>, + interface_name: Option, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate export `{name}`")] + span: SourceSpan, }, /// Duplicate world item. #[error("{kind} `{name}` conflicts with existing {kind} of the same name in world `{world}`")] @@ -182,227 +180,251 @@ pub enum Error<'a> { /// The name of the item. name: String, /// The name of the world. - world: &'a str, + world: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting name `{name}`")] + span: SourceSpan, }, /// The name is not a function type or interface. #[error("`{name}` ({kind}) is not a function type or interface")] NotFuncOrInterface { /// The name that is not a function type or interface. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a function type or interface")] + span: SourceSpan, }, /// The name is not an interface. #[error("`{name}` ({kind}) is not an interface")] NotInterface { /// The name that is not an interface. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not an interface")] + span: SourceSpan, }, /// Duplicate name in a world include. #[error("duplicate `{name}` in world include `with` clause")] DuplicateWorldIncludeName { /// The name of the duplicate include. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate name `{name}`")] + span: SourceSpan, }, /// The name is not a world. #[error("`{name}` ({kind}) is not a world")] NotWorld { /// The name that is not a world. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a world")] + span: SourceSpan, }, /// Missing source item for `with` clause in world include. #[error("world `{world}` does not have an import or export named `{name}`")] MissingWorldInclude { /// The name of the world. - world: &'a str, + world: String, /// The name of the missing item. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "no import or export named `{name}`")] + span: SourceSpan, }, /// A conflict was encountered in a world include. - #[error("{kind} `{name}` from world `{from}` conflicts with {kind} of the same name in world `{to}`{hint}")] + #[error("{kind} `{name}` from world `{from}` conflicts with {kind} of the same name in world `{to}`")] WorldIncludeConflict { /// The extern kind of the item. kind: ExternKind, /// The name of the item. name: String, /// The name of the source world. - from: &'a str, + from: String, /// The name of the target world. - to: &'a str, + to: String, /// The span where the error occurred. - span: Span<'a>, - /// The hint for the error. - hint: &'static str, + #[label(primary, "conflicting name `{name}`")] + span: SourceSpan, + /// The help for the error. + #[help] + help: Option, }, /// A name is not a type defined in an interface. - #[error("type `{name}` is not defined in interface `{interface_name}`")] + #[error("a type named `{name}` is not defined in interface `{interface_name}`")] UndefinedInterfaceType { /// The name of the type. - name: &'a str, + name: String, /// The name of the interface. - interface_name: &'a str, + interface_name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a type in interface `{interface_name}`")] + span: SourceSpan, }, /// A name is not a value type defined in an interface. #[error("`{name}` ({kind}) is not a value type in interface `{interface_name}`")] NotInterfaceValueType { /// The name that is not a value type. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The name of the interface. - interface_name: &'a str, + interface_name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a value type")] + span: SourceSpan, }, /// A duplicate resource constructor was encountered. #[error("duplicate constructor for resource `{resource}`")] DuplicateResourceConstructor { /// The name of the resource. - resource: &'a str, + resource: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate constructor")] + span: SourceSpan, }, /// A duplicate resource method was encountered. #[error("duplicate method `{name}` for resource `{resource}`")] DuplicateResourceMethod { /// The name of the method. - name: &'a str, + name: String, /// The name of the resource. - resource: &'a str, + resource: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate method `{name}`")] + span: SourceSpan, }, /// A duplicate variant case was encountered. #[error("duplicate case `{case}` for variant type `{name}`")] DuplicateVariantCase { /// The name of the case. - case: &'a str, + case: String, /// The name of the variant type. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate case `{case}`")] + span: SourceSpan, }, /// A duplicate record field was encountered. #[error("duplicate field `{field}` for record type `{name}`")] DuplicateRecordField { /// The name of the field. - field: &'a str, + field: String, /// The name of the record type. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate field `{field}`")] + span: SourceSpan, }, /// A duplicate enum case was encountered. #[error("duplicate case `{case}` for enum type `{name}`")] DuplicateEnumCase { /// The name of the case. - case: &'a str, + case: String, /// The name of the enum type. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate case `{case}`")] + span: SourceSpan, }, /// A duplicate flag was encountered. #[error("duplicate flag `{flag}` for flags type `{name}`")] DuplicateFlag { /// The name of the flag. - flag: &'a str, + flag: String, /// The name of the flags type. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate flag `{flag}`")] + span: SourceSpan, }, /// The name cannot be used as an alias type. #[error("`{name}` ({kind}) cannot be used in a type alias")] InvalidAliasType { /// The name that cannot be used as an alias type. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` cannot be aliased")] + span: SourceSpan, }, /// The name is not a function type. #[error("`{name}` ({kind}) is not a function type")] NotFuncType { /// The name that is not a function type. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a function type")] + span: SourceSpan, }, /// The name is not a resource type. #[error("`{name}` ({kind}) is not a resource type")] NotResourceType { /// The name that is not a resource type. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` is not a resource type")] + span: SourceSpan, }, /// The name is not a value type. #[error("`{name}` ({kind}) cannot be used as a value type")] NotValueType { /// The name that is not a value type. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "`{name}` not a value type")] + span: SourceSpan, }, /// A duplicate function parameter was encountered. #[error("duplicate {kind} parameter `{name}`")] DuplicateParameter { /// The name of the parameter. - name: &'a str, + name: String, /// The kind of the function. kind: FuncKind, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate parameter `{name}`")] + span: SourceSpan, }, /// A duplicate result was encountered. #[error("duplicate {kind} result `{name}`")] DuplicateResult { /// The name of the result. - name: &'a str, + name: String, /// The kind of the function. kind: FuncKind, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate result `{name}`")] + span: SourceSpan, }, /// A borrow type was encountered in a function result. #[error("function result cannot recursively contain a borrow type")] BorrowInResult { /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "borrow type in result")] + span: SourceSpan, }, /// A package failed to resolve. #[error("failed to resolve package `{name}`")] PackageResolutionFailure { /// The name of the package. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "package `{name}` failed to resolve")] + span: SourceSpan, /// The underlying error. #[source] source: anyhow::Error, @@ -411,9 +433,10 @@ pub enum Error<'a> { #[error("failed to parse package `{name}`")] PackageParseFailure { /// The name of the package. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "package `{name}` failed to parse")] + span: SourceSpan, /// The underlying error. #[source] source: anyhow::Error, @@ -422,45 +445,49 @@ pub enum Error<'a> { #[error("unknown package `{name}`")] UnknownPackage { /// The name of the package. - name: &'a str, + name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "unknown package `{name}`")] + span: SourceSpan, }, /// A package is missing an export. - #[error("{prev}package `{name}` has no export named `{export}`", prev = ParentPathDisplay(*.kind, .path))] + #[error("{prev}package `{name}` has no export named `{export}`", prev = ParentPathDisplay(.kind, .path))] PackageMissingExport { /// The name of the package. - name: &'a str, + name: String, /// The name of the export. - export: &'a str, + export: String, /// The kind of the item being accessed. - kind: Option<&'static str>, + kind: Option, /// The path to the current item. path: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "unknown export `{export}`")] + span: SourceSpan, }, /// A missing export in a package path was encountered. #[error("`{name}` ({kind}) has no export named `{export}`")] PackagePathMissingExport { /// The name that has no matching export. - name: &'a str, + name: String, /// The kind of the item. - kind: &'static str, + kind: String, /// The name of the export. - export: &'a str, + export: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "unknown export `{export}`")] + span: SourceSpan, }, /// A missing import on a component was encountered. #[error("component `{package}` has no import named `{import}`")] MissingComponentImport { /// The name of the package. - package: &'a str, + package: String, /// The name of the import. import: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "unknown import `{import}`")] + span: SourceSpan, }, /// A mismatched instantiation argument was encountered. #[error("mismatched instantiation argument `{name}`")] @@ -468,7 +495,8 @@ pub enum Error<'a> { /// The name of the argument. name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "mismatched argument `{name}`")] + span: SourceSpan, /// The source of the error. #[source] source: anyhow::Error, @@ -479,7 +507,8 @@ pub enum Error<'a> { /// The name of the argument. name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate argument `{name}`")] + span: SourceSpan, }, /// A missing instantiation argument was encountered. #[error("missing instantiation argument `{name}` for package `{package}`")] @@ -487,94 +516,89 @@ pub enum Error<'a> { /// The name of the argument. name: String, /// The name of the package. - package: &'a str, + package: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "missing argument `{name}`")] + span: SourceSpan, }, /// An instantiation argument conflict was encountered. - #[error("implicit instantiation argument `{name}` ({kind}) conflicts with an explicit import at {path}:{line}:{column}", path = .path.display())] + #[error("implicit instantiation argument `{name}` ({kind}) conflicts with an explicit import")] InstantiationArgConflict { /// The name of the argument. name: String, - /// The path of the source file. - path: &'a Path, /// The kind of the argument. - kind: &'static str, - /// The line of the original instantiation. - line: usize, - /// The column of the original instantiation. - column: usize, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting instantiation here")] + span: SourceSpan, + /// The span where the explicit import occurred. + #[label("explicit import here")] + import: SourceSpan, }, /// An explicitly imported item conflicts with an implicit import from an instantiation. - #[error("import name `{name}` conflicts with an instance that was implicitly imported by the instantiation of `{package}` at {path}:{line}:{column}", path = .path.display())] + #[error("import name `{name}` conflicts with an instance that was implicitly imported by an instantiation of `{package}`")] ImportConflict { /// The name of the argument. name: String, /// The package that first introduced the import. - package: &'a str, - /// The path of the source file. - path: &'a Path, - /// The line of the original instantiation. - line: usize, - /// The column of the original instantiation. - column: usize, + package: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting import here")] + span: SourceSpan, + /// The span where the previous instantiation occurred. + #[label("previous instantiation here")] + instantiation: SourceSpan, }, /// An instantiation argument conflict was encountered. - #[error("failed to merge instantiation argument `{name}` with an instance that was implicitly imported by the instantiation of `{package}` at {path}:{line}:{column}", path = .path.display())] + #[error("failed to merge instantiation argument `{name}` with an instance that was implicitly imported by the instantiation of `{package}`")] InstantiationArgMergeFailure { /// The name of the argument. name: String, /// The name of the package that first introduced the import. - package: &'a str, - /// The path of the source file. - path: &'a Path, + package: String, /// The kind of the argument. - kind: &'static str, - /// The line of the original instantiation. - line: usize, - /// The column of the original instantiation. - column: usize, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting instantiation here")] + span: SourceSpan, + /// The span where the previous instantiation occurred. + #[label("previous instantiation here")] + instantiation: SourceSpan, /// The underlying merge error. #[source] source: anyhow::Error, }, /// An unmergeable instantiation argument was encountered. - #[error("implicit instantiation argument `{name}` ({kind}) conflicts with an implicitly imported argument from the instantiation of `{package}` at {path}:{line}:{column}", path = .path.display())] + #[error("implicit instantiation argument `{name}` ({kind}) conflicts with an implicitly imported argument from the instantiation of `{package}`")] UnmergeableInstantiationArg { /// The name of the argument. name: String, /// The name of the package that first introduced the import. - package: &'a str, - /// The path of the source file. - path: &'a Path, + package: String, /// The kind of the argument. - kind: &'static str, - /// The line of the original instantiation. - line: usize, - /// The column of the original instantiation. - column: usize, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting instantiation here")] + span: SourceSpan, + /// The span where the previous instantiation occurred. + #[label("previous instantiation here")] + instantiation: SourceSpan, }, /// An access expression on an inaccessible value was encountered. #[error("a {kind} cannot be accessed")] Inaccessible { /// The kind of the item. - kind: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "a {kind} cannot be accessed")] + span: SourceSpan, }, /// An access on an interface was encountered. #[error("an interface cannot be accessed")] InaccessibleInterface { /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "an interface cannot be accessed")] + span: SourceSpan, }, /// An instance is missing an export. #[error("the instance has no export named `{name}`")] @@ -582,31 +606,32 @@ pub enum Error<'a> { /// The name of the export. name: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "unknown export `{name}`")] + span: SourceSpan, }, /// An export requires a with clause. #[error("export statement requires a `with` clause as the export name cannot be inferred")] ExportRequiresWith { /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "a `with` clause is required")] + span: SourceSpan, }, /// An export conflicts with a definition. - #[error("export `{name}` conflicts with {kind} definition at {path}:{line}:{column}{hint}", path = .path.display())] + #[error("export `{name}` conflicts with {kind} definition")] ExportConflict { /// The name of the export. name: String, - /// The path of the source file. - path: &'a Path, /// The kind of the definition. - kind: &'static str, - /// The line of the definition. - line: usize, - /// The column of the definition. - column: usize, - /// The hint of the error. - hint: &'static str, + kind: String, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting export of `{name}`")] + span: SourceSpan, + /// The span of the previous definition. + #[label("previous definition is here")] + definition: SourceSpan, + /// The help of the error. + #[help] + help: Option, }, /// A duplicate extern name was encountered. #[error("duplicate {kind} `{name}`")] @@ -616,7 +641,11 @@ pub enum Error<'a> { /// The kind of extern name. kind: ExternKind, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "duplicate {kind} name `{name}`")] + span: SourceSpan, + /// The span where the error occurred. + #[label("previous {kind} here")] + previous: SourceSpan, }, /// An invalid extern name was encountered. #[error("{kind} name `{name}` is not valid")] @@ -626,7 +655,8 @@ pub enum Error<'a> { /// The kind of extern. kind: ExternKind, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "invalid name `{name}`")] + span: SourceSpan, /// The underlying validation error. #[source] source: anyhow::Error, @@ -635,78 +665,27 @@ pub enum Error<'a> { #[error("cannot instantiate the package being defined")] CannotInstantiateSelf { /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "cannot instantiate self")] + span: SourceSpan, }, /// A use of a type conflicts with an extern item. - #[error("use of type `{name}` conflicts with an {kind} of the same name{hint}")] + #[error("use of type `{name}` conflicts with an {kind} of the same name")] UseConflict { /// The name of the used type. - name: &'a str, + name: String, /// The extern kind of the conflicting item. kind: ExternKind, - /// The hint for the error. - hint: &'static str, /// The span where the error occurred. - span: Span<'a>, + #[label(primary, "conflicting name `{name}`")] + span: SourceSpan, + /// The help message for the error. + #[help] + help: Option, }, } -impl Spanned for Error<'_> { - fn span(&self) -> Span { - match self { - Error::UndefinedName { span, .. } - | Error::DuplicateName { span, .. } - | Error::DuplicateInterfaceExport { span, .. } - | Error::DuplicateWorldItem { span, .. } - | Error::NotFuncOrInterface { span, .. } - | Error::NotInterface { span, .. } - | Error::DuplicateWorldIncludeName { span, .. } - | Error::NotWorld { span, .. } - | Error::MissingWorldInclude { span, .. } - | Error::WorldIncludeConflict { span, .. } - | Error::UndefinedInterfaceType { span, .. } - | Error::NotInterfaceValueType { span, .. } - | Error::DuplicateResourceConstructor { span, .. } - | Error::DuplicateResourceMethod { span, .. } - | Error::DuplicateVariantCase { span, .. } - | Error::DuplicateRecordField { span, .. } - | Error::DuplicateEnumCase { span, .. } - | Error::DuplicateFlag { span, .. } - | Error::InvalidAliasType { span, .. } - | Error::NotFuncType { span, .. } - | Error::NotResourceType { span, .. } - | Error::NotValueType { span, .. } - | Error::DuplicateParameter { span, .. } - | Error::DuplicateResult { span, .. } - | Error::BorrowInResult { span } - | Error::PackageResolutionFailure { span, .. } - | Error::PackageParseFailure { span, .. } - | Error::UnknownPackage { span, .. } - | Error::PackageMissingExport { span, .. } - | Error::PackagePathMissingExport { span, .. } - | Error::MissingComponentImport { span, .. } - | Error::MismatchedInstantiationArg { span, .. } - | Error::DuplicateInstantiationArg { span, .. } - | Error::MissingInstantiationArg { span, .. } - | Error::InstantiationArgConflict { span, .. } - | Error::ImportConflict { span, .. } - | Error::InstantiationArgMergeFailure { span, .. } - | Error::UnmergeableInstantiationArg { span, .. } - | Error::Inaccessible { span, .. } - | Error::InaccessibleInterface { span, .. } - | Error::MissingInstanceExport { span, .. } - | Error::ExportRequiresWith { span } - | Error::ExportConflict { span, .. } - | Error::DuplicateExternName { span, .. } - | Error::InvalidExternName { span, .. } - | Error::CannotInstantiateSelf { span } - | Error::UseConflict { span, .. } => *span, - } - } -} - /// Represents a resolution result. -pub type ResolutionResult<'a, T> = std::result::Result>; +pub type ResolutionResult = std::result::Result; /// A trait implemented by package resolvers. /// @@ -985,7 +964,7 @@ impl Composition { pub fn from_ast<'a>( document: &'a crate::ast::Document<'a>, resolver: Option>, - ) -> ResolutionResult<'a, Self> { + ) -> ResolutionResult { AstResolver::new(document).resolve(resolver) } diff --git a/crates/wac-parser/src/resolution/ast.rs b/crates/wac-parser/src/resolution/ast.rs index bbda725..b6a1ee7 100644 --- a/crates/wac-parser/src/resolution/ast.rs +++ b/crates/wac-parser/src/resolution/ast.rs @@ -4,22 +4,23 @@ use super::{ Record, ResolutionResult, Resource, ResourceId, SubtypeChecker, Type, ValueType, Variant, World, WorldId, }; -use crate::{ast, lexer::Span, line_column, method_extern_name, Item, ItemId, PackageId}; +use crate::{ast, method_extern_name, Item, ItemId, PackageId}; use anyhow::Context; use id_arena::Arena; use indexmap::{IndexMap, IndexSet}; +use miette::SourceSpan; use semver::Version; use std::collections::{hash_map, HashMap, HashSet}; use wasmparser::names::{ComponentName, ComponentNameKind}; #[derive(Default)] -struct Scope<'a> { - names: IndexMap)>, +struct Scope { + names: IndexMap, items: Arena, } -impl<'a> Scope<'a> { - fn get(&self, name: &str) -> Option<(ItemId, Span<'a>)> { +impl Scope { + fn get(&self, name: &str) -> Option<(ItemId, SourceSpan)> { self.names.get(name).copied() } } @@ -29,16 +30,22 @@ struct Import<'a> { /// This is `None` for explicit imports. package: Option<&'a str>, /// The span where the import was first introduced. - span: Span<'a>, + span: SourceSpan, /// The imported item. item: ItemId, } +struct Export { + /// The span where the export was first introduced. + span: SourceSpan, + /// The exported item. + item: ItemId, +} + struct State<'a> { - document: &'a ast::Document<'a>, resolver: Option>, - scopes: Vec>, - current: Scope<'a>, + scopes: Vec, + current: Scope, packages: Arena, /// The map of package name to id. package_map: HashMap, @@ -47,12 +54,13 @@ struct State<'a> { /// The map of imported items. /// This is used to keep track of implicit imports and merge them together. imports: IndexMap>, + /// The map of exported items. + exports: IndexMap, } impl<'a> State<'a> { - fn new(document: &'a ast::Document<'a>, resolver: Option>) -> Self { + fn new(resolver: Option>) -> Self { Self { - document, resolver, scopes: Default::default(), current: Default::default(), @@ -60,17 +68,18 @@ impl<'a> State<'a> { package_map: Default::default(), aliases: Default::default(), imports: Default::default(), + exports: Default::default(), } } // Gets an item by identifier from the root scope. - fn root_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<'a, (ItemId, &Item)> { + fn root_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<(ItemId, &Item)> { let scope = self.root_scope(); let id = scope .get(id.string) .ok_or(Error::UndefinedName { - name: id.string, + name: id.string.to_owned(), span: id.span, })? .0; @@ -79,12 +88,12 @@ impl<'a> State<'a> { } /// Gets an item by identifier from the local (current) scope. - fn local_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<'a, (ItemId, &Item)> { + fn local_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<(ItemId, &Item)> { let id = self .current .get(id.string) .ok_or(Error::UndefinedName { - name: id.string, + name: id.string.to_owned(), span: id.span, })? .0; @@ -93,7 +102,7 @@ impl<'a> State<'a> { } /// Gets an item by identifier from the local (current) scope or the root scope. - fn local_or_root_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<'a, (ItemId, &Item)> { + fn local_or_root_item(&self, id: &ast::Ident<'a>) -> ResolutionResult<(ItemId, &Item)> { if self.scopes.is_empty() { return self.local_item(id); } @@ -115,11 +124,11 @@ impl<'a> State<'a> { std::mem::replace(&mut self.current, self.scopes.pop().unwrap()) } - fn root_scope(&self) -> &Scope<'a> { + fn root_scope(&self) -> &Scope { self.scopes.first().unwrap_or(&self.current) } - fn register_name(&mut self, id: ast::Ident<'a>, item: ItemId) -> ResolutionResult<'a, ()> { + fn register_name(&mut self, id: ast::Ident<'a>, item: ItemId) -> ResolutionResult<()> { log::debug!( "registering name `{id}` for item {item} in the current scope", id = id.string, @@ -130,13 +139,10 @@ impl<'a> State<'a> { .names .insert(id.string.to_owned(), (item, id.span)) { - let (line, column) = line_column(id.span.source(), span.start); return Err(Error::DuplicateName { - name: id.string, - path: self.document.path, - line, - column, + name: id.string.to_owned(), span: id.span, + previous: span, }); } @@ -147,7 +153,6 @@ impl<'a> State<'a> { pub struct AstResolver<'a> { document: &'a ast::Document<'a>, definitions: Definitions, - exports: IndexMap, } impl<'a> AstResolver<'a> { @@ -155,15 +160,14 @@ impl<'a> AstResolver<'a> { Self { document, definitions: Default::default(), - exports: Default::default(), } } pub fn resolve( mut self, resolver: Option>, - ) -> ResolutionResult<'a, Composition> { - let mut state = State::new(self.document, resolver); + ) -> ResolutionResult { + let mut state = State::new(resolver); for stmt in &self.document.statements { match stmt { @@ -187,7 +191,11 @@ impl<'a> AstResolver<'a> { .into_iter() .map(|(k, v)| (k, v.item)) .collect(), - exports: self.exports, + exports: state + .exports + .into_iter() + .map(|(k, v)| (k, v.item)) + .collect(), }) } @@ -195,7 +203,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, stmt: &'a ast::ImportStatement<'a>, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { log::debug!( "resolving import statement for id `{id}`", id = stmt.id.string @@ -259,14 +267,11 @@ impl<'a> AstResolver<'a> { .. }) = state.imports.get(name) { - let (line, column) = line_column(span.source(), prev_span.start); return Err(Error::ImportConflict { - name: name.to_owned(), - package, - path: state.document.path, - line, - column, + name: name.to_string(), + package: package.to_string(), span, + instantiation: *prev_span, }); } @@ -275,6 +280,7 @@ impl<'a> AstResolver<'a> { name: name.to_owned(), kind: ExternKind::Import, span, + previous: existing.span, }); } _ => unreachable!(), @@ -302,16 +308,22 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, stmt: &'a ast::TypeStatement<'a>, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { log::debug!("resolving type statement"); - let (name, item) = match stmt { - ast::TypeStatement::Interface(i) => (i.id.string, self.interface_decl(state, i)?), - ast::TypeStatement::World(w) => (w.id.string, self.world_decl(state, w)?), - ast::TypeStatement::Type(t) => (t.id().string, self.type_decl(state, t)?), + let (id, item) = match stmt { + ast::TypeStatement::Interface(i) => (i.id, self.interface_decl(state, i)?), + ast::TypeStatement::World(w) => (w.id, self.world_decl(state, w)?), + ast::TypeStatement::Type(t) => (*t.id(), self.type_decl(state, t)?), }; - let prev = self.exports.insert(name.to_owned(), item); + let prev = state.exports.insert( + id.string.to_owned(), + Export { + span: id.span, + item, + }, + ); assert!(prev.is_none()); Ok(()) } @@ -320,7 +332,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, stmt: &'a ast::LetStatement<'a>, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { log::debug!( "resolving type statement for id `{id}`", id = stmt.id.string @@ -333,7 +345,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, stmt: &'a ast::ExportStatement<'a>, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { log::debug!("resolving export statement"); let item = self.expr(state, &stmt.expr)?; let (name, span) = if let Some(name) = stmt.with { @@ -380,32 +392,30 @@ impl<'a> AstResolver<'a> { if let Some((item_id, prev_span)) = state.root_scope().get(name) { let item = &state.current.items[item_id]; if let Item::Definition(definition) = item { - let (line, column) = line_column(stmt.span.source(), prev_span.start); return Err(Error::ExportConflict { name: name.to_owned(), - path: state.document.path, - kind: definition.kind.as_str(&self.definitions), - line, - column, - hint: if stmt.with.is_some() { - "" + kind: definition.kind.as_str(&self.definitions).to_string(), + span, + definition: prev_span, + help: if stmt.with.is_some() { + None } else { - " (consider using a `with` clause to use a different name)" + Some("consider using a `with` clause to use a different name".into()) }, - span, }); } } - if self.exports.contains_key(name) { + if let Some(existing) = state.exports.get(name) { return Err(Error::DuplicateExternName { name: name.to_owned(), kind: ExternKind::Export, span, + previous: existing.span, }); } - let prev = self.exports.insert(name.to_owned(), item); + let prev = state.exports.insert(name.to_owned(), Export { span, item }); assert!(prev.is_none()); Ok(()) @@ -415,7 +425,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, iface: &'a ast::InlineInterface<'a>, - ) -> ResolutionResult<'a, ItemKind> { + ) -> ResolutionResult { log::debug!("resolving inline interface"); state.push_scope(); @@ -451,7 +461,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &'a ast::InterfaceDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving interface declaration for id `{id}`", id = decl.id.string @@ -486,7 +496,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &'a ast::WorldDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving world declaration for id `{id}`", id = decl.id.string @@ -524,7 +534,7 @@ impl<'a> AstResolver<'a> { name: Option<&'a str>, items: &'a [ast::InterfaceItem<'a>], ty: &mut Interface, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { for item in items { match item { ast::InterfaceItem::Use(u) => { @@ -537,8 +547,8 @@ impl<'a> AstResolver<'a> { let kind = ItemKind::Func(self.func_type_ref(state, &e.ty, FuncKind::Free)?); if ty.exports.insert(e.id.string.into(), kind).is_some() { return Err(Error::DuplicateInterfaceExport { - name: e.id.string, - interface_name: name, + name: e.id.string.to_owned(), + interface_name: name.map(ToOwned::to_owned), span: e.id.span, }); } @@ -555,7 +565,7 @@ impl<'a> AstResolver<'a> { world: &'a str, items: &'a [ast::WorldItem<'a>], ty: &mut World, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { let mut includes = Vec::new(); for item in items { match item { @@ -594,7 +604,7 @@ impl<'a> AstResolver<'a> { kind: ExternKind, world: &'a str, ty: &mut World, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { let (k, v) = match path { ast::WorldItemPath::Named(named) => { check_name(named.id.string, named.id.span, ty, world, kind)?; @@ -609,8 +619,8 @@ impl<'a> AstResolver<'a> { ItemKind::Type(Type::Func(id)) => ItemKind::Func(id), kind => { return Err(Error::NotFuncOrInterface { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: id.span, }); } @@ -640,8 +650,8 @@ impl<'a> AstResolver<'a> { } kind => { return Err(Error::NotInterface { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: id.span, }); } @@ -659,8 +669,8 @@ impl<'a> AstResolver<'a> { } kind => { return Err(Error::NotInterface { - name: p.span.as_str(), - kind: kind.as_str(&self.definitions), + name: p.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: p.span, }); } @@ -675,13 +685,13 @@ impl<'a> AstResolver<'a> { return Ok(()); - fn check_name<'a>( + fn check_name( name: &str, - span: Span<'a>, + span: SourceSpan, ty: &World, - world: &'a str, + world: &str, kind: ExternKind, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { let exists: bool = if kind == ExternKind::Import { ty.imports.contains_key(name) } else { @@ -692,7 +702,7 @@ impl<'a> AstResolver<'a> { return Err(Error::DuplicateWorldItem { kind, name: name.to_owned(), - world, + world: world.to_owned(), span, }); } @@ -707,14 +717,14 @@ impl<'a> AstResolver<'a> { include: &ast::WorldInclude<'a>, world: &'a str, ty: &mut World, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { log::debug!("resolving include of world `{world}`"); let mut replacements = HashMap::new(); for item in &include.with { let prev = replacements.insert(item.from.string, item); if prev.is_some() { return Err(Error::DuplicateWorldIncludeName { - name: item.from.string, + name: item.from.string.to_owned(), span: item.from.span, }); } @@ -727,8 +737,8 @@ impl<'a> AstResolver<'a> { ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id, kind => { return Err(Error::NotWorld { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: id.span, }); } @@ -738,8 +748,8 @@ impl<'a> AstResolver<'a> { ItemKind::Type(Type::World(id)) | ItemKind::Component(id) => id, kind => { return Err(Error::NotWorld { - name: path.span.as_str(), - kind: kind.as_str(&self.definitions), + name: path.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: path.span, }); } @@ -773,8 +783,8 @@ impl<'a> AstResolver<'a> { if let Some(missing) = replacements.values().next() { return Err(Error::MissingWorldInclude { - world: include.world.name(), - name: missing.from.string, + world: include.world.name().to_owned(), + name: missing.from.string.to_owned(), span: missing.from.span, }); } @@ -788,7 +798,7 @@ impl<'a> AstResolver<'a> { name: &str, kind: ExternKind, replacements: &mut HashMap<&str, &ast::WorldIncludeItem<'a>>, - ) -> ResolutionResult<'a, String> { + ) -> ResolutionResult { // Check for a id, which doesn't get replaced. if name.contains(':') { return Ok(name.to_owned()); @@ -809,13 +819,13 @@ impl<'a> AstResolver<'a> { return Err(Error::WorldIncludeConflict { kind, name: name.to_owned(), - from: include.world.name(), - to: world, + from: include.world.name().to_owned(), + to: world.to_owned(), span, - hint: if !include.with.is_empty() { - "" + help: if !include.with.is_empty() { + None } else { - " (consider using a `with` clause to use a different name)" + Some("consider using a `with` clause to use a different name".into()) }, }); } @@ -831,14 +841,14 @@ impl<'a> AstResolver<'a> { uses: &mut IndexMap>, externs: &mut IndexMap, in_world: bool, - ) -> ResolutionResult<'a, ()> { + ) -> ResolutionResult<()> { let (interface, name) = match &use_type.path { ast::UsePath::Package(path) => match self.resolve_package_export(state, path)? { - ItemKind::Type(Type::Interface(id)) => (id, path.span.as_str()), + ItemKind::Type(Type::Interface(id)) => (id, path.string), kind => { return Err(Error::NotInterface { - name: path.span.as_str(), - kind: kind.as_str(&self.definitions), + name: path.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: path.span, }); } @@ -849,8 +859,8 @@ impl<'a> AstResolver<'a> { ItemKind::Type(Type::Interface(iface_ty_id)) => (iface_ty_id, id.string), kind => { return Err(Error::NotInterface { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_owned(), + kind: kind.as_str(&self.definitions).to_owned(), span: id.span, }); } @@ -864,8 +874,8 @@ impl<'a> AstResolver<'a> { .exports .get_full(item.id.string) .ok_or(Error::UndefinedInterfaceType { - name: item.id.string, - interface_name: name, + name: item.id.string.to_string(), + interface_name: name.to_string(), span: item.id.span, })?; @@ -873,18 +883,18 @@ impl<'a> AstResolver<'a> { ItemKind::Resource(_) | ItemKind::Type(Type::Value(_)) => { if externs.contains_key(ident.string) { return Err(Error::UseConflict { - name: ident.string, + name: ident.string.to_string(), kind: if in_world { ExternKind::Import } else { ExternKind::Export }, - hint: if item.as_id.is_some() { - "" + span: ident.span, + help: if item.as_id.is_some() { + None } else { - " (consider using an `as` clause to use a different name)" + Some("consider using an `as` clause to use a different name".into()) }, - span: ident.span, }); } @@ -896,9 +906,9 @@ impl<'a> AstResolver<'a> { } _ => { return Err(Error::NotInterfaceValueType { - name: item.id.string, - kind: kind.as_str(&self.definitions), - interface_name: name, + name: item.id.string.to_string(), + kind: kind.as_str(&self.definitions).to_string(), + interface_name: name.to_string(), span: item.id.span, }); } @@ -912,7 +922,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &'a ast::TypeDecl, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { match decl { ast::TypeDecl::Variant(v) => self.variant_decl(state, v), ast::TypeDecl::Record(r) => self.record_decl(state, r), @@ -927,7 +937,7 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, decl: &'a ast::ItemTypeDecl, externs: &mut IndexMap, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { let (insert, item) = match decl { ast::ItemTypeDecl::Resource(r) => (false, self.resource_decl(state, r, externs)?), ast::ItemTypeDecl::Variant(v) => (true, self.variant_decl(state, v)?), @@ -950,7 +960,7 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, decl: &ast::ResourceDecl<'a>, externs: &mut IndexMap, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving resource declaration for id `{id}`", id = decl.id.string @@ -983,7 +993,7 @@ impl<'a> AstResolver<'a> { ast::ResourceMethod::Constructor(ast::Constructor { span, params, .. }) => { if !names.insert("") { return Err(Error::DuplicateResourceConstructor { - resource: decl.id.string, + resource: decl.id.string.to_string(), span: *span, }); } @@ -1013,8 +1023,8 @@ impl<'a> AstResolver<'a> { if !names.insert(method_id.string) { return Err(Error::DuplicateResourceMethod { - name: method_id.string, - resource: decl.id.string, + name: method_id.string.to_string(), + resource: decl.id.string.to_string(), span: method_id.span, }); } @@ -1037,7 +1047,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &ast::VariantDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving variant declaration for id `{id}`", id = decl.id.string @@ -1050,8 +1060,8 @@ impl<'a> AstResolver<'a> { contains_borrow |= ty.as_ref().map_or(false, |ty| ty.contains_borrow()); if cases.insert(case.id.string.into(), ty).is_some() { return Err(Error::DuplicateVariantCase { - case: case.id.string, - name: decl.id.string, + case: case.id.string.to_string(), + name: decl.id.string.to_string(), span: case.id.span, }); } @@ -1079,7 +1089,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &ast::RecordDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving record declaration for id `{id}`", id = decl.id.string @@ -1092,8 +1102,8 @@ impl<'a> AstResolver<'a> { contains_borrow |= ty.contains_borrow(); if fields.insert(field.id.string.into(), ty).is_some() { return Err(Error::DuplicateRecordField { - field: field.id.string, - name: decl.id.string, + field: field.id.string.to_string(), + name: decl.id.string.to_string(), span: field.id.span, }); } @@ -1121,7 +1131,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &ast::FlagsDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving flags declaration for id `{id}`", id = decl.id.string @@ -1131,8 +1141,8 @@ impl<'a> AstResolver<'a> { for flag in &decl.flags { if !flags.insert(flag.id.string.into()) { return Err(Error::DuplicateFlag { - flag: flag.id.string, - name: decl.id.string, + flag: flag.id.string.to_string(), + name: decl.id.string.to_string(), span: flag.id.span, }); } @@ -1160,7 +1170,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, decl: &ast::EnumDecl<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!( "resolving enum declaration for id `{id}`", id = decl.id.string @@ -1170,8 +1180,8 @@ impl<'a> AstResolver<'a> { for case in &decl.cases { if !cases.insert(case.id.string.to_owned()) { return Err(Error::DuplicateEnumCase { - case: case.id.string, - name: decl.id.string, + case: case.id.string.to_string(), + name: decl.id.string.to_string(), span: case.id.span, }); } @@ -1197,7 +1207,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, alias: &ast::TypeAlias<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { log::debug!("resolving type alias for id `{id}`", id = alias.id.string); let kind = match &alias.kind { @@ -1229,8 +1239,8 @@ impl<'a> AstResolver<'a> { } kind => { return Err(Error::InvalidAliasType { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_string(), + kind: kind.as_str(&self.definitions).to_string(), span: id.span, }); } @@ -1262,7 +1272,7 @@ impl<'a> AstResolver<'a> { state: &State<'a>, r: &ast::FuncTypeRef<'a>, kind: FuncKind, - ) -> ResolutionResult<'a, FuncId> { + ) -> ResolutionResult { match r { ast::FuncTypeRef::Func(ty) => { self.func_type(state, &ty.params, &ty.results, kind, None) @@ -1272,8 +1282,8 @@ impl<'a> AstResolver<'a> { match item.kind() { ItemKind::Type(Type::Func(id)) | ItemKind::Func(id) => Ok(id), kind => Err(Error::NotFuncType { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_string(), + kind: kind.as_str(&self.definitions).to_string(), span: id.span, }), } @@ -1281,7 +1291,7 @@ impl<'a> AstResolver<'a> { } } - fn ty(&mut self, state: &State<'a>, ty: &ast::Type<'a>) -> ResolutionResult<'a, ValueType> { + fn ty(&mut self, state: &State<'a>, ty: &ast::Type<'a>) -> ResolutionResult { match ty { ast::Type::U8(_) => Ok(ValueType::Primitive(PrimitiveType::U8)), ast::Type::S8(_) => Ok(ValueType::Primitive(PrimitiveType::S8)), @@ -1346,8 +1356,8 @@ impl<'a> AstResolver<'a> { } Err(Error::NotResourceType { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_string(), + kind: kind.as_str(&self.definitions).to_string(), span: id.span, }) } @@ -1357,8 +1367,8 @@ impl<'a> AstResolver<'a> { ItemKind::Resource(id) => Ok(ValueType::Own(id)), ItemKind::Type(Type::Value(ty)) => Ok(ty), kind => Err(Error::NotValueType { - name: id.string, - kind: kind.as_str(&self.definitions), + name: id.string.to_string(), + kind: kind.as_str(&self.definitions).to_string(), span: id.span, }), } @@ -1373,7 +1383,7 @@ impl<'a> AstResolver<'a> { func_results: &ast::ResultList<'a>, kind: FuncKind, resource: Option, - ) -> ResolutionResult<'a, FuncId> { + ) -> ResolutionResult { let mut params = IndexMap::new(); if kind == FuncKind::Method { @@ -1386,7 +1396,7 @@ impl<'a> AstResolver<'a> { .is_some() { return Err(Error::DuplicateParameter { - name: param.id.string, + name: param.id.string.to_string(), kind, span: param.id.span, }); @@ -1416,7 +1426,7 @@ impl<'a> AstResolver<'a> { .is_some() { return Err(Error::DuplicateResult { - name: result.id.string, + name: result.id.string.to_string(), kind, span: result.id.span, }); @@ -1441,8 +1451,8 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, name: &'a str, version: Option<&Version>, - span: Span<'a>, - ) -> ResolutionResult<'a, PackageId> { + span: SourceSpan, + ) -> ResolutionResult { match state.package_map.entry(if let Some(version) = version { format!("{name}@{version}") } else { @@ -1457,7 +1467,7 @@ impl<'a> AstResolver<'a> { .and_then(|r| r.resolve(name, version).transpose()) .transpose() .map_err(|e| Error::PackageResolutionFailure { - name, + name: name.to_string(), span, source: e, })? { @@ -1465,7 +1475,7 @@ impl<'a> AstResolver<'a> { let id = state.packages.alloc( Package::parse(&mut self.definitions, name, version, bytes).map_err( |e| Error::PackageParseFailure { - name, + name: name.to_string(), span, source: e, }, @@ -1473,7 +1483,10 @@ impl<'a> AstResolver<'a> { ); Ok(*e.insert(id)) } - None => Err(Error::UnknownPackage { name, span }), + None => Err(Error::UnknownPackage { + name: name.to_string(), + span, + }), } } } @@ -1483,7 +1496,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, path: &ast::PackagePath<'a>, - ) -> ResolutionResult<'a, ItemKind> { + ) -> ResolutionResult { // Check for reference to local item if path.name == self.document.package.name { return self.resolve_local_export(state, path); @@ -1537,9 +1550,9 @@ impl<'a> AstResolver<'a> { for (i, (segment, span)) in segments { if i == current { return Error::PackageMissingExport { - name: path.span.as_str(), - export: segment, - kind: parent_ty, + name: path.string.to_string(), + export: segment.to_string(), + kind: parent_ty.map(ToOwned::to_owned), path: prev_path, span, }; @@ -1560,8 +1573,8 @@ impl<'a> AstResolver<'a> { &self, state: &State<'a>, path: &ast::PackagePath<'a>, - ) -> ResolutionResult<'a, ItemKind> { - log::debug!("resolving local path `{path}`", path = path.span.as_str()); + ) -> ResolutionResult { + log::debug!("resolving local path `{path}`", path = path.string); let mut segments = path.segment_spans(); let (segment, span) = segments.next().unwrap(); @@ -1584,9 +1597,9 @@ impl<'a> AstResolver<'a> { } _ => { return Err(Error::PackagePathMissingExport { - name: current, - kind: kind.as_str(&self.definitions), - export: segment, + name: current.to_string(), + kind: kind.as_str(&self.definitions).to_string(), + export: segment.to_string(), span, }); } @@ -1597,9 +1610,9 @@ impl<'a> AstResolver<'a> { .get(segment) .copied() .ok_or_else(|| Error::PackagePathMissingExport { - name: current, - kind: kind.as_str(&self.definitions), - export: segment, + name: current.to_string(), + kind: kind.as_str(&self.definitions).to_string(), + export: segment.to_string(), span, })?; @@ -1609,7 +1622,7 @@ impl<'a> AstResolver<'a> { Ok(kind) } - fn expr(&mut self, state: &mut State<'a>, expr: &'a ast::Expr) -> ResolutionResult<'a, ItemId> { + fn expr(&mut self, state: &mut State<'a>, expr: &'a ast::Expr) -> ResolutionResult { let mut item = self.primary_expr(state, &expr.primary)?; for expr in &expr.postfix { @@ -1623,7 +1636,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, expr: &'a ast::PrimaryExpr<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { match expr { ast::PrimaryExpr::New(e) => self.new_expr(state, e), ast::PrimaryExpr::Nested(e) => self.expr(state, &e.0), @@ -1635,7 +1648,7 @@ impl<'a> AstResolver<'a> { &mut self, state: &mut State<'a>, expr: &'a ast::NewExpr<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { if expr.package.name == self.document.package.name { return Err(Error::CannotInstantiateSelf { span: expr.package.span, @@ -1668,7 +1681,7 @@ impl<'a> AstResolver<'a> { .imports .get(&name) .ok_or_else(|| Error::MissingComponentImport { - package: expr.package.span.as_str(), + package: expr.package.string.to_string(), import: name.clone(), span, })?; @@ -1705,7 +1718,7 @@ impl<'a> AstResolver<'a> { if require_all { return Err(Error::MissingInstantiationArg { name: name.clone(), - package: expr.package.span.as_str(), + package: expr.package.string.to_string(), span: expr.package.span, }); } @@ -1736,8 +1749,8 @@ impl<'a> AstResolver<'a> { name: String, mut kind: ItemKind, package: &'a str, - span: Span<'a>, - ) -> ResolutionResult<'a, ItemId> { + span: SourceSpan, + ) -> ResolutionResult { assert!(state.scopes.is_empty()); // If the item is an instance, we need to recurse on its dependencies @@ -1765,14 +1778,11 @@ impl<'a> AstResolver<'a> { if let Some(import) = state.imports.get(&name) { // Check if the implicit import would conflict with an explicit import if import.package.is_none() { - let (line, column) = line_column(span.source(), import.span.start); return Err(Error::InstantiationArgConflict { name: name.to_owned(), - path: state.document.path, - kind: kind.as_str(&self.definitions), - line, - column, + kind: kind.as_str(&self.definitions).to_string(), span, + import: import.span, }); }; @@ -1781,15 +1791,12 @@ impl<'a> AstResolver<'a> { let id = match (kind, state.current.items[import.item].kind()) { (ItemKind::Instance(id), ItemKind::Instance(_)) => id, (_, kind) => { - let (line, column) = line_column(span.source(), import.span.start); return Err(Error::UnmergeableInstantiationArg { name: name.to_owned(), - package: import.package.unwrap(), - path: state.document.path, - kind: kind.as_str(&self.definitions), - line, - column, + package: import.package.unwrap().to_string(), + kind: kind.as_str(&self.definitions).to_string(), span, + instantiation: import.span, }); } }; @@ -1844,8 +1851,8 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, name: &str, source_id: InterfaceId, - span: Span<'a>, - ) -> ResolutionResult<'a, ()> { + span: SourceSpan, + ) -> ResolutionResult<()> { let import = state.imports.get(name).unwrap(); let import_span = import.span; let target_id = match state.current.items[import.item].kind() { @@ -1882,15 +1889,12 @@ impl<'a> AstResolver<'a> { } (Err(e), _) | (_, Err(e)) => { // Neither is a subtype of the other, so error - let (line, column) = line_column(span.source(), import_span.start); return Err(Error::InstantiationArgMergeFailure { name: name.to_owned(), - package: import.package.unwrap(), - path: state.document.path, - kind: "instance", - line, - column, + package: import.package.unwrap().to_string(), + kind: "instance".to_string(), span, + instantiation: import_span, source: e, }); } @@ -1953,7 +1957,7 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, arg: &'a ast::NamedInstantiationArgument<'a>, world: WorldId, - ) -> ResolutionResult<'a, (String, ItemId, Span<'a>)> { + ) -> ResolutionResult<(String, ItemId, SourceSpan)> { let item = self.expr(state, &arg.expr)?; let name = match &arg.name { @@ -1973,7 +1977,7 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, ident: &ast::Ident<'a>, world: WorldId, - ) -> ResolutionResult<'a, (String, ItemId, Span<'a>)> { + ) -> ResolutionResult<(String, ItemId, SourceSpan)> { let (item_id, item) = state.local_item(ident)?; let world = &self.definitions.worlds[world]; @@ -2061,7 +2065,7 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, item: ItemId, expr: &ast::PostfixExpr<'a>, - ) -> ResolutionResult<'a, ItemId> { + ) -> ResolutionResult { match expr { ast::PostfixExpr::Access(expr) => { let exports = self.instance_exports(state, item, expr.span)?; @@ -2080,8 +2084,8 @@ impl<'a> AstResolver<'a> { &self, state: &State, item: ItemId, - span: Span<'a>, - ) -> ResolutionResult<'a, &IndexMap> { + span: SourceSpan, + ) -> ResolutionResult<&IndexMap> { match state.current.items[item].kind() { ItemKind::Instance(id) => Ok(&self.definitions.interfaces[id].exports), ItemKind::Instantiation(id) => { @@ -2089,7 +2093,7 @@ impl<'a> AstResolver<'a> { } ItemKind::Type(Type::Interface(_)) => Err(Error::InaccessibleInterface { span }), kind => Err(Error::Inaccessible { - kind: kind.as_str(&self.definitions), + kind: kind.as_str(&self.definitions).to_string(), span, }), } @@ -2100,8 +2104,8 @@ impl<'a> AstResolver<'a> { state: &mut State<'a>, item: ItemId, name: String, - span: Span<'a>, - ) -> ResolutionResult<'a, ItemId> { + span: SourceSpan, + ) -> ResolutionResult { let exports = self.instance_exports(state, item, span)?; let kind = exports .get(&name) diff --git a/crates/wac-parser/tests/encoding.rs b/crates/wac-parser/tests/encoding.rs index 12f10c6..78a4e87 100644 --- a/crates/wac-parser/tests/encoding.rs +++ b/crates/wac-parser/tests/encoding.rs @@ -10,9 +10,10 @@ use std::{ process::exit, sync::atomic::{AtomicUsize, Ordering}, }; -use wac_parser::{ - ast::Document, Composition, EncodingOptions, ErrorFormatter, FileSystemPackageResolver, -}; +use support::fmt_err; +use wac_parser::{ast::Document, Composition, EncodingOptions, FileSystemPackageResolver}; + +mod support; #[cfg(not(feature = "wat"))] compile_error!("the `wat` feature must be enabled for this test to run"); @@ -75,8 +76,9 @@ fn compare_result(test: &Path, result: &str) -> Result<()> { fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { let source = std::fs::read_to_string(test)?.replace("\r\n", "\n"); - let document = Document::parse(&source, test) - .map_err(|e| anyhow!("{e}", e = ErrorFormatter::new(test, e, false)))?; + + let document = Document::parse(&source).map_err(|e| anyhow!(fmt_err(e, test, &source)))?; + let bytes = Composition::from_ast( &document, Some(Box::new(FileSystemPackageResolver::new( @@ -84,12 +86,7 @@ fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { Default::default(), ))), ) - .map_err(|e| { - anyhow!( - "the resolution failed but it was expected to succeed: {e}", - e = ErrorFormatter::new(test, e, false) - ) - })? + .map_err(|e| anyhow!(fmt_err(e, test, &source)))? .encode(EncodingOptions::default()) .with_context(|| { format!( diff --git a/crates/wac-parser/tests/parser.rs b/crates/wac-parser/tests/parser.rs index 43642a3..28878a1 100644 --- a/crates/wac-parser/tests/parser.rs +++ b/crates/wac-parser/tests/parser.rs @@ -10,7 +10,10 @@ use std::{ process::exit, sync::atomic::{AtomicUsize, Ordering}, }; -use wac_parser::{ast::Document, ErrorFormatter}; +use support::fmt_err; +use wac_parser::ast::Document; + +mod support; fn find_tests() -> Vec { let mut tests = Vec::new(); @@ -77,7 +80,7 @@ fn compare_result(test: &Path, result: &str, should_fail: bool) -> Result<()> { fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { let should_fail = test.parent().map(|p| p.ends_with("fail")).unwrap_or(false); let source = std::fs::read_to_string(test)?.replace("\r\n", "\n"); - let result = match Document::parse(&source, test) { + let result = match Document::parse(&source) { Ok(doc) => { if should_fail { bail!("the parse was successful but it was expected to fail"); @@ -87,13 +90,11 @@ fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { } Err(e) => { if !should_fail { - bail!( - "the parse failed but it was expected to succeed: {e}", - e = ErrorFormatter::new(test, e, false) - ); + return Err(anyhow!(fmt_err(e, test, &source)) + .context("the parse failed but it was expected to succeed")); } - format!("{e}", e = ErrorFormatter::new(test, e, false)) + fmt_err(e, test, &source) } }; diff --git a/crates/wac-parser/tests/parser/export.wac.result b/crates/wac-parser/tests/parser/export.wac.result index cc0da3e..342a487 100644 --- a/crates/wac-parser/tests/parser/export.wac.result +++ b/crates/wac-parser/tests/parser/export.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -16,16 +16,14 @@ { "comment": "Export an item (default name)", "span": { - "str": "/// Export an item (default name)", - "start": 20, - "end": 53 + "offset": 20, + "length": 33 } } ], "span": { - "str": "export", - "start": 54, - "end": 60 + "offset": 54, + "length": 6 }, "with": null, "expr": { @@ -33,9 +31,8 @@ "ident": { "string": "e", "span": { - "str": "e", - "start": 61, - "end": 62 + "offset": 61, + "length": 1 } } }, @@ -49,16 +46,14 @@ { "comment": "Export an alias of an item (default name)", "span": { - "str": "/// Export an alias of an item (default name)", - "start": 65, - "end": 110 + "offset": 65, + "length": 45 } } ], "span": { - "str": "export", - "start": 111, - "end": 117 + "offset": 111, + "length": 6 }, "with": null, "expr": { @@ -66,9 +61,8 @@ "ident": { "string": "e", "span": { - "str": "e", - "start": 118, - "end": 119 + "offset": 118, + "length": 1 } } }, @@ -76,16 +70,14 @@ { "namedAccess": { "span": { - "str": "[\"foo\"]", - "start": 119, - "end": 126 + "offset": 119, + "length": 7 }, "string": { "value": "foo", "span": { - "str": "\"foo\"", - "start": 120, - "end": 125 + "offset": 120, + "length": 5 } } } @@ -100,23 +92,20 @@ { "comment": "Export an alias of an item with a different name", "span": { - "str": "/// Export an alias of an item with a different name", - "start": 129, - "end": 181 + "offset": 129, + "length": 52 } } ], "span": { - "str": "export", - "start": 182, - "end": 188 + "offset": 182, + "length": 6 }, "with": { "value": "bar", "span": { - "str": "\"bar\"", - "start": 203, - "end": 208 + "offset": 203, + "length": 5 } }, "expr": { @@ -124,9 +113,8 @@ "ident": { "string": "e", "span": { - "str": "e", - "start": 189, - "end": 190 + "offset": 189, + "length": 1 } } }, @@ -134,16 +122,14 @@ { "namedAccess": { "span": { - "str": "[\"foo\"]", - "start": 190, - "end": 197 + "offset": 190, + "length": 7 }, "string": { "value": "foo", "span": { - "str": "\"foo\"", - "start": 191, - "end": 196 + "offset": 191, + "length": 5 } } } diff --git a/crates/wac-parser/tests/parser/fail/bad-alias.wac.result b/crates/wac-parser/tests/parser/fail/bad-alias.wac.result index 0856c40..2626df1 100644 --- a/crates/wac-parser/tests/parser/fail/bad-alias.wac.result +++ b/crates/wac-parser/tests/parser/fail/bad-alias.wac.result @@ -1,5 +1,9 @@ -expected identifier, found `u32` keyword - --> tests/parser/fail/bad-alias.wac:3:6 - | - 3 | type u32 = x; - | ^-^ +failed to parse document + + × expected identifier, found `u32` keyword + ╭─[tests/parser/fail/bad-alias.wac:3:6] + 2 │ + 3 │ type u32 = x; + · ─┬─ + · ╰── unexpected `u32` keyword + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/duplicate-package-decl.wac.result b/crates/wac-parser/tests/parser/fail/duplicate-package-decl.wac.result index 5d42498..6fc485c 100644 --- a/crates/wac-parser/tests/parser/fail/duplicate-package-decl.wac.result +++ b/crates/wac-parser/tests/parser/fail/duplicate-package-decl.wac.result @@ -1,5 +1,10 @@ -expected either `import` keyword, `let` keyword, `export` keyword, `interface` keyword, `world` keyword, `variant` keyword, `record` keyword, `flags` keyword, `enum` keyword, or `type` keyword, found `package` keyword - --> tests/parser/fail/duplicate-package-decl.wac:2:1 - | - 2 | package test:comp; - | ^-----^ +failed to parse document + + × expected either `import` keyword, `let` keyword, `export` keyword, `interface` keyword, `world` keyword, `variant` keyword, `record` keyword, `flags` keyword, `enum` keyword, or `type` keyword, + │ found `package` keyword + ╭─[tests/parser/fail/duplicate-package-decl.wac:2:1] + 1 │ package test:comp; + 2 │ package test:comp; + · ───┬─── + · ╰── unexpected `package` keyword + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/empty-enum.wac.result b/crates/wac-parser/tests/parser/fail/empty-enum.wac.result index 492cb1a..823fd45 100644 --- a/crates/wac-parser/tests/parser/fail/empty-enum.wac.result +++ b/crates/wac-parser/tests/parser/fail/empty-enum.wac.result @@ -1,5 +1,9 @@ -enum must contain at least one case - --> tests/parser/fail/empty-enum.wac:3:9 - | - 3 | enum e {} - | ^ +failed to parse document + + × enum must contain at least one case + ╭─[tests/parser/fail/empty-enum.wac:3:9] + 2 │ + 3 │ enum e {} + · ┬ + · ╰── empty enum + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/empty-flags.wac.result b/crates/wac-parser/tests/parser/fail/empty-flags.wac.result index 0122950..8c6c9e7 100644 --- a/crates/wac-parser/tests/parser/fail/empty-flags.wac.result +++ b/crates/wac-parser/tests/parser/fail/empty-flags.wac.result @@ -1,5 +1,9 @@ -flags must contain at least one flag - --> tests/parser/fail/empty-flags.wac:3:10 - | - 3 | flags f {} - | ^ +failed to parse document + + × flags must contain at least one flag + ╭─[tests/parser/fail/empty-flags.wac:3:10] + 2 │ + 3 │ flags f {} + · ┬ + · ╰── empty flags + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/empty-record.wac.result b/crates/wac-parser/tests/parser/fail/empty-record.wac.result index f0e0b8e..387a2b0 100644 --- a/crates/wac-parser/tests/parser/fail/empty-record.wac.result +++ b/crates/wac-parser/tests/parser/fail/empty-record.wac.result @@ -1,5 +1,9 @@ -record must contain at least one field - --> tests/parser/fail/empty-record.wac:3:11 - | - 3 | record r {} - | ^ +failed to parse document + + × record must contain at least one field + ╭─[tests/parser/fail/empty-record.wac:3:11] + 2 │ + 3 │ record r {} + · ┬ + · ╰── empty record + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/empty-variant.wac.result b/crates/wac-parser/tests/parser/fail/empty-variant.wac.result index b933988..2197689 100644 --- a/crates/wac-parser/tests/parser/fail/empty-variant.wac.result +++ b/crates/wac-parser/tests/parser/fail/empty-variant.wac.result @@ -1,5 +1,9 @@ -variant must contain at least one case - --> tests/parser/fail/empty-variant.wac:3:12 - | - 3 | variant v {} - | ^ +failed to parse document + + × variant must contain at least one case + ╭─[tests/parser/fail/empty-variant.wac:3:12] + 2 │ + 3 │ variant v {} + · ┬ + · ╰── empty variant + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/expected-multiple.wac.result b/crates/wac-parser/tests/parser/fail/expected-multiple.wac.result index a03f1e5..1c60486 100644 --- a/crates/wac-parser/tests/parser/fail/expected-multiple.wac.result +++ b/crates/wac-parser/tests/parser/fail/expected-multiple.wac.result @@ -1,5 +1,10 @@ -expected either `func` keyword, `u8` keyword, `s8` keyword, `u16` keyword, `s16` keyword, `u32` keyword, `s32` keyword, `u64` keyword, `s64` keyword, `float32` keyword, or more..., found end of input - --> tests/parser/fail/expected-multiple.wac:3:10 - | - 3 | type x = - | ^ +failed to parse document + + × expected either `func` keyword, `u8` keyword, `s8` keyword, `u16` keyword, `s16` keyword, `u32` keyword, `s32` keyword, `u64` keyword, `s64` keyword, `float32` keyword, or more..., found end + │ of input + ╭─[tests/parser/fail/expected-multiple.wac:3:8] + 2 │ + 3 │ type x = + · ┬ + · ╰── unexpected end of input + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/expected-two.wac.result b/crates/wac-parser/tests/parser/fail/expected-two.wac.result index c6f3619..5359f67 100644 --- a/crates/wac-parser/tests/parser/fail/expected-two.wac.result +++ b/crates/wac-parser/tests/parser/fail/expected-two.wac.result @@ -1,5 +1,9 @@ -expected `}` or identifier, found end of input - --> tests/parser/fail/expected-two.wac:4:1 - | - 4 | - | ^ +failed to parse document + + × expected `}` or identifier, found end of input + ╭─[tests/parser/fail/expected-two.wac:3:12] + 2 │ + 3 │ record foo { + · ┬ + · ╰── unexpected end of input + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/invalid-path-semver.wac.result b/crates/wac-parser/tests/parser/fail/invalid-path-semver.wac.result index 1ab16a3..bf58c91 100644 --- a/crates/wac-parser/tests/parser/fail/invalid-path-semver.wac.result +++ b/crates/wac-parser/tests/parser/fail/invalid-path-semver.wac.result @@ -1,5 +1,9 @@ -`1` is not a valid semantic version - --> tests/parser/fail/invalid-path-semver.wac:3:23 - | - 3 | import i: foo:bar/baz@1; - | ^ +failed to parse document + + × `1` is not a valid semantic version + ╭─[tests/parser/fail/invalid-path-semver.wac:3:23] + 2 │ + 3 │ import i: foo:bar/baz@1; + · ┬ + · ╰── invalid version + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/invalid-semver.wac.result b/crates/wac-parser/tests/parser/fail/invalid-semver.wac.result index b52f511..67b126c 100644 --- a/crates/wac-parser/tests/parser/fail/invalid-semver.wac.result +++ b/crates/wac-parser/tests/parser/fail/invalid-semver.wac.result @@ -1,5 +1,8 @@ -`1` is not a valid semantic version - --> tests/parser/fail/invalid-semver.wac:1:17 - | - 1 | package foo:bar@1; - | ^ +failed to parse document + + × `1` is not a valid semantic version + ╭─[tests/parser/fail/invalid-semver.wac:1:17] + 1 │ package foo:bar@1; + · ┬ + · ╰── invalid version + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/missing-package-decl.wac.result b/crates/wac-parser/tests/parser/fail/missing-package-decl.wac.result index aa11bcb..f1de97b 100644 --- a/crates/wac-parser/tests/parser/fail/missing-package-decl.wac.result +++ b/crates/wac-parser/tests/parser/fail/missing-package-decl.wac.result @@ -1,5 +1,8 @@ -expected `package` keyword, found `import` keyword - --> tests/parser/fail/missing-package-decl.wac:1:1 - | - 1 | import f: func(); - | ^----^ +failed to parse document + + × expected `package` keyword, found `import` keyword + ╭─[tests/parser/fail/missing-package-decl.wac:1:1] + 1 │ import f: func(); + · ───┬── + · ╰── unexpected `import` keyword + ╰──── diff --git a/crates/wac-parser/tests/parser/fail/missing-semi.wac.result b/crates/wac-parser/tests/parser/fail/missing-semi.wac.result index 950872b..05f87e8 100644 --- a/crates/wac-parser/tests/parser/fail/missing-semi.wac.result +++ b/crates/wac-parser/tests/parser/fail/missing-semi.wac.result @@ -1,5 +1,9 @@ -expected `;`, found end of input - --> tests/parser/fail/missing-semi.wac:3:13 - | - 3 | type x = u32 - | ^ +failed to parse document + + × expected `;`, found end of input + ╭─[tests/parser/fail/missing-semi.wac:3:12] + 2 │ + 3 │ type x = u32 + · ┬ + · ╰── unexpected end of input + ╰──── diff --git a/crates/wac-parser/tests/parser/import.wac.result b/crates/wac-parser/tests/parser/import.wac.result index aab3390..d421811 100644 --- a/crates/wac-parser/tests/parser/import.wac.result +++ b/crates/wac-parser/tests/parser/import.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -16,18 +16,16 @@ { "comment": "Import by func type", "span": { - "str": "/// Import by func type", - "start": 20, - "end": 43 + "offset": 20, + "length": 23 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 51, - "end": 52 + "offset": 51, + "length": 1 } }, "with": null, @@ -45,18 +43,16 @@ { "comment": "Import by ident", "span": { - "str": "/// Import by ident", - "start": 63, - "end": 82 + "offset": 63, + "length": 19 } } ], "id": { "string": "b", "span": { - "str": "b", - "start": 90, - "end": 91 + "offset": 90, + "length": 1 } }, "with": null, @@ -64,9 +60,8 @@ "ident": { "string": "x", "span": { - "str": "x", - "start": 93, - "end": 94 + "offset": 93, + "length": 1 } } } @@ -78,28 +73,26 @@ { "comment": "Import by package path", "span": { - "str": "/// Import by package path", - "start": 97, - "end": 123 + "offset": 97, + "length": 26 } } ], "id": { "string": "c", "span": { - "str": "c", - "start": 131, - "end": 132 + "offset": 131, + "length": 1 } }, "with": null, "ty": { "package": { "span": { - "str": "foo:bar/baz", - "start": 134, - "end": 145 + "offset": 134, + "length": 11 }, + "string": "foo:bar/baz", "name": "foo:bar", "segments": "baz", "version": null @@ -113,26 +106,23 @@ { "comment": "Import by func type with kebab name", "span": { - "str": "/// Import by func type with kebab name ", - "start": 148, - "end": 188 + "offset": 148, + "length": 40 } } ], "id": { "string": "d", "span": { - "str": "d", - "start": 196, - "end": 197 + "offset": 196, + "length": 1 } }, "with": { "value": "hello-world", "span": { - "str": "\"hello-world\"", - "start": 203, - "end": 216 + "offset": 203, + "length": 13 } }, "ty": { @@ -142,16 +132,14 @@ "id": { "string": "name", "span": { - "str": "name", - "start": 223, - "end": 227 + "offset": 223, + "length": 4 } }, "ty": { "string": { - "str": "string", - "start": 229, - "end": 235 + "offset": 229, + "length": 6 } } } @@ -167,18 +155,16 @@ { "comment": "Import by inline interface", "span": { - "str": "/// Import by inline interface", - "start": 239, - "end": 269 + "offset": 239, + "length": 30 } } ], "id": { "string": "e", "span": { - "str": "e", - "start": 277, - "end": 278 + "offset": 277, + "length": 1 } }, "with": null, @@ -191,9 +177,8 @@ "id": { "string": "x", "span": { - "str": "x", - "start": 296, - "end": 297 + "offset": 296, + "length": 1 } }, "ty": { @@ -215,28 +200,26 @@ { "comment": "Import by package path with version", "span": { - "str": "/// Import by package path with version", - "start": 311, - "end": 350 + "offset": 311, + "length": 39 } } ], "id": { "string": "f", "span": { - "str": "f", - "start": 358, - "end": 359 + "offset": 358, + "length": 1 } }, "with": null, "ty": { "package": { "span": { - "str": "foo:bar/baz@1.0.0", - "start": 361, - "end": 378 + "offset": 361, + "length": 17 }, + "string": "foo:bar/baz@1.0.0", "name": "foo:bar", "segments": "baz", "version": "1.0.0" diff --git a/crates/wac-parser/tests/parser/let.wac.result b/crates/wac-parser/tests/parser/let.wac.result index a683b67..1f876cb 100644 --- a/crates/wac-parser/tests/parser/let.wac.result +++ b/crates/wac-parser/tests/parser/let.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -16,30 +16,28 @@ { "comment": "Instantiate without args", "span": { - "str": "/// Instantiate without args", - "start": 20, - "end": 48 + "offset": 20, + "length": 28 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 53, - "end": 54 + "offset": 53, + "length": 1 } }, "expr": { "primary": { "new": { "package": { + "string": "foo:bar", "name": "foo:bar", "version": null, "span": { - "str": "foo:bar", - "start": 61, - "end": 68 + "offset": 61, + "length": 7 } }, "arguments": [], @@ -56,30 +54,28 @@ { "comment": "Instantiation with import-propagation.", "span": { - "str": "/// Instantiation with import-propagation.", - "start": 74, - "end": 116 + "offset": 74, + "length": 42 } } ], "id": { "string": "b", "span": { - "str": "b", - "start": 121, - "end": 122 + "offset": 121, + "length": 1 } }, "expr": { "primary": { "new": { "package": { + "string": "foo:bar@1.0.0", "name": "foo:bar", "version": "1.0.0", "span": { - "str": "foo:bar@1.0.0", - "start": 129, - "end": 142 + "offset": 129, + "length": 13 } }, "arguments": [], @@ -96,30 +92,28 @@ { "comment": "Instantiation with arguments", "span": { - "str": "/// Instantiation with arguments", - "start": 153, - "end": 185 + "offset": 153, + "length": 32 } } ], "id": { "string": "c", "span": { - "str": "c", - "start": 190, - "end": 191 + "offset": 190, + "length": 1 } }, "expr": { "primary": { "new": { "package": { + "string": "foo:bar@2.0.0", "name": "foo:bar", "version": "2.0.0", "span": { - "str": "foo:bar@2.0.0", - "start": 198, - "end": 211 + "offset": 198, + "length": 13 } }, "arguments": [ @@ -127,9 +121,8 @@ "ident": { "string": "a", "span": { - "str": "a", - "start": 214, - "end": 215 + "offset": 214, + "length": 1 } } }, @@ -137,9 +130,8 @@ "ident": { "string": "b", "span": { - "str": "b", - "start": 217, - "end": 218 + "offset": 217, + "length": 1 } } }, @@ -149,9 +141,8 @@ "string": { "value": "c", "span": { - "str": "\"c\"", - "start": 220, - "end": 223 + "offset": 220, + "length": 3 } } }, @@ -160,9 +151,8 @@ "ident": { "string": "c", "span": { - "str": "c", - "start": 225, - "end": 226 + "offset": 225, + "length": 1 } } }, @@ -184,30 +174,28 @@ { "comment": "Instantiation with arguments and import-propagation.", "span": { - "str": "/// Instantiation with arguments and import-propagation.", - "start": 232, - "end": 288 + "offset": 232, + "length": 56 } } ], "id": { "string": "d", "span": { - "str": "d", - "start": 293, - "end": 294 + "offset": 293, + "length": 1 } }, "expr": { "primary": { "new": { "package": { + "string": "foo:bar@3.0.0", "name": "foo:bar", "version": "3.0.0", "span": { - "str": "foo:bar@3.0.0", - "start": 301, - "end": 314 + "offset": 301, + "length": 13 } }, "arguments": [ @@ -215,9 +203,8 @@ "ident": { "string": "a", "span": { - "str": "a", - "start": 317, - "end": 318 + "offset": 317, + "length": 1 } } }, @@ -227,9 +214,8 @@ "string": { "value": "b", "span": { - "str": "\"b\"", - "start": 320, - "end": 323 + "offset": 320, + "length": 3 } } }, @@ -239,12 +225,12 @@ "primary": { "new": { "package": { + "string": "foo:bar", "name": "foo:bar", "version": null, "span": { - "str": "foo:bar", - "start": 330, - "end": 337 + "offset": 330, + "length": 7 } }, "arguments": [], @@ -264,9 +250,8 @@ "ident": { "string": "c", "span": { - "str": "c", - "start": 344, - "end": 345 + "offset": 344, + "length": 1 } } }, @@ -275,9 +260,8 @@ "ident": { "string": "c", "span": { - "str": "c", - "start": 347, - "end": 348 + "offset": 347, + "length": 1 } } }, @@ -299,18 +283,16 @@ { "comment": "Nested expression", "span": { - "str": "/// Nested expression", - "start": 358, - "end": 379 + "offset": 358, + "length": 21 } } ], "id": { "string": "e", "span": { - "str": "e", - "start": 384, - "end": 385 + "offset": 384, + "length": 1 } }, "expr": { @@ -320,9 +302,8 @@ "ident": { "string": "b", "span": { - "str": "b", - "start": 389, - "end": 390 + "offset": 389, + "length": 1 } } }, @@ -339,18 +320,16 @@ { "comment": "Access expression", "span": { - "str": "/// Access expression", - "start": 394, - "end": 415 + "offset": 394, + "length": 21 } } ], "id": { "string": "f", "span": { - "str": "f", - "start": 420, - "end": 421 + "offset": 420, + "length": 1 } }, "expr": { @@ -358,9 +337,8 @@ "ident": { "string": "e", "span": { - "str": "e", - "start": 424, - "end": 425 + "offset": 424, + "length": 1 } } }, @@ -368,16 +346,14 @@ { "namedAccess": { "span": { - "str": "[\"b-c\"]", - "start": 425, - "end": 432 + "offset": 425, + "length": 7 }, "string": { "value": "b-c", "span": { - "str": "\"b-c\"", - "start": 426, - "end": 431 + "offset": 426, + "length": 5 } } } @@ -385,16 +361,14 @@ { "access": { "span": { - "str": ".c", - "start": 432, - "end": 434 + "offset": 432, + "length": 2 }, "id": { "string": "c", "span": { - "str": "c", - "start": 433, - "end": 434 + "offset": 433, + "length": 1 } } } @@ -402,16 +376,14 @@ { "access": { "span": { - "str": ".d", - "start": 434, - "end": 436 + "offset": 434, + "length": 2 }, "id": { "string": "d", "span": { - "str": "d", - "start": 435, - "end": 436 + "offset": 435, + "length": 1 } } } @@ -419,16 +391,14 @@ { "namedAccess": { "span": { - "str": "[\"foo:bar/baz\"]", - "start": 436, - "end": 451 + "offset": 436, + "length": 15 }, "string": { "value": "foo:bar/baz", "span": { - "str": "\"foo:bar/baz\"", - "start": 437, - "end": 450 + "offset": 437, + "length": 13 } } } @@ -436,16 +406,14 @@ { "access": { "span": { - "str": ".e", - "start": 451, - "end": 453 + "offset": 451, + "length": 2 }, "id": { "string": "e", "span": { - "str": "e", - "start": 452, - "end": 453 + "offset": 452, + "length": 1 } } } diff --git a/crates/wac-parser/tests/parser/resource.wac.result b/crates/wac-parser/tests/parser/resource.wac.result index 84be44e..80de0b7 100644 --- a/crates/wac-parser/tests/parser/resource.wac.result +++ b/crates/wac-parser/tests/parser/resource.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -17,9 +17,8 @@ "id": { "string": "foo", "span": { - "str": "foo", - "start": 30, - "end": 33 + "offset": 30, + "length": 3 } }, "items": [ @@ -30,18 +29,16 @@ { "comment": "Resource without methods", "span": { - "str": "/// Resource without methods", - "start": 40, - "end": 68 + "offset": 40, + "length": 28 } } ], "id": { "string": "r1", "span": { - "str": "r1", - "start": 82, - "end": 84 + "offset": 82, + "length": 2 } }, "methods": [] @@ -55,18 +52,16 @@ { "comment": "Resource with only constructor", "span": { - "str": "/// Resource with only constructor", - "start": 91, - "end": 125 + "offset": 91, + "length": 34 } } ], "id": { "string": "r2", "span": { - "str": "r2", - "start": 139, - "end": 141 + "offset": 139, + "length": 2 } }, "methods": [ @@ -76,16 +71,14 @@ { "comment": "Constructor", "span": { - "str": "/// Constructor", - "start": 152, - "end": 167 + "offset": 152, + "length": 15 } } ], "span": { - "str": "constructor", - "start": 176, - "end": 187 + "offset": 176, + "length": 11 }, "params": [] } @@ -101,18 +94,16 @@ { "comment": "Resource with constructor, instance method, and static method", "span": { - "str": "/// Resource with constructor, instance method, and static method", - "start": 202, - "end": 267 + "offset": 202, + "length": 65 } } ], "id": { "string": "r3", "span": { - "str": "r3", - "start": 281, - "end": 283 + "offset": 281, + "length": 2 } }, "methods": [ @@ -122,32 +113,28 @@ { "comment": "Constructor", "span": { - "str": "/// Constructor", - "start": 294, - "end": 309 + "offset": 294, + "length": 15 } } ], "span": { - "str": "constructor", - "start": 318, - "end": 329 + "offset": 318, + "length": 11 }, "params": [ { "id": { "string": "a", "span": { - "str": "a", - "start": 330, - "end": 331 + "offset": 330, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 333, - "end": 336 + "offset": 333, + "length": 3 } } } @@ -160,18 +147,16 @@ { "comment": "Method", "span": { - "str": "/// Method", - "start": 347, - "end": 357 + "offset": 347, + "length": 10 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 366, - "end": 367 + "offset": 366, + "length": 1 } }, "isStatic": false, @@ -181,16 +166,14 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 374, - "end": 375 + "offset": 374, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 377, - "end": 380 + "offset": 377, + "length": 3 } } } @@ -205,18 +188,16 @@ { "comment": "Static method", "span": { - "str": "/// Static method", - "start": 391, - "end": 408 + "offset": 391, + "length": 17 } } ], "id": { "string": "b", "span": { - "str": "b", - "start": 417, - "end": 418 + "offset": 417, + "length": 1 } }, "isStatic": true, @@ -226,16 +207,14 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 432, - "end": 433 + "offset": 432, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 435, - "end": 438 + "offset": 435, + "length": 3 } } } @@ -259,9 +238,8 @@ "id": { "string": "bar", "span": { - "str": "bar", - "start": 456, - "end": 459 + "offset": 456, + "length": 3 } }, "items": [ @@ -272,18 +250,16 @@ { "comment": "Resource without methods", "span": { - "str": "/// Resource without methods", - "start": 466, - "end": 494 + "offset": 466, + "length": 28 } } ], "id": { "string": "r1", "span": { - "str": "r1", - "start": 508, - "end": 510 + "offset": 508, + "length": 2 } }, "methods": [] @@ -297,18 +273,16 @@ { "comment": "Resource with only constructor", "span": { - "str": "/// Resource with only constructor", - "start": 517, - "end": 551 + "offset": 517, + "length": 34 } } ], "id": { "string": "r2", "span": { - "str": "r2", - "start": 565, - "end": 567 + "offset": 565, + "length": 2 } }, "methods": [ @@ -318,16 +292,14 @@ { "comment": "Constructor", "span": { - "str": "/// Constructor", - "start": 578, - "end": 593 + "offset": 578, + "length": 15 } } ], "span": { - "str": "constructor", - "start": 602, - "end": 613 + "offset": 602, + "length": 11 }, "params": [] } @@ -343,18 +315,16 @@ { "comment": "Resource with constructor, instance method, and static method", "span": { - "str": "/// Resource with constructor, instance method, and static method", - "start": 628, - "end": 693 + "offset": 628, + "length": 65 } } ], "id": { "string": "r3", "span": { - "str": "r3", - "start": 707, - "end": 709 + "offset": 707, + "length": 2 } }, "methods": [ @@ -364,32 +334,28 @@ { "comment": "Constructor", "span": { - "str": "/// Constructor", - "start": 720, - "end": 735 + "offset": 720, + "length": 15 } } ], "span": { - "str": "constructor", - "start": 744, - "end": 755 + "offset": 744, + "length": 11 }, "params": [ { "id": { "string": "a", "span": { - "str": "a", - "start": 756, - "end": 757 + "offset": 756, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 759, - "end": 762 + "offset": 759, + "length": 3 } } } @@ -402,18 +368,16 @@ { "comment": "Method", "span": { - "str": "/// Method", - "start": 773, - "end": 783 + "offset": 773, + "length": 10 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 792, - "end": 793 + "offset": 792, + "length": 1 } }, "isStatic": false, @@ -423,16 +387,14 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 800, - "end": 801 + "offset": 800, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 803, - "end": 806 + "offset": 803, + "length": 3 } } } @@ -447,18 +409,16 @@ { "comment": "Static method", "span": { - "str": "/// Static method", - "start": 817, - "end": 834 + "offset": 817, + "length": 17 } } ], "id": { "string": "b", "span": { - "str": "b", - "start": 843, - "end": 844 + "offset": 843, + "length": 1 } }, "isStatic": true, @@ -468,16 +428,14 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 858, - "end": 859 + "offset": 858, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 861, - "end": 864 + "offset": 861, + "length": 3 } } } diff --git a/crates/wac-parser/tests/parser/type-alias.wac.result b/crates/wac-parser/tests/parser/type-alias.wac.result index ff40f41..9440d13 100644 --- a/crates/wac-parser/tests/parser/type-alias.wac.result +++ b/crates/wac-parser/tests/parser/type-alias.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -18,26 +18,23 @@ { "comment": "u8", "span": { - "str": "/// u8", - "start": 20, - "end": 26 + "offset": 20, + "length": 6 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 32, - "end": 33 + "offset": 32, + "length": 1 } }, "kind": { "type": { "u8": { - "str": "u8", - "start": 36, - "end": 38 + "offset": 36, + "length": 2 } } } @@ -53,26 +50,23 @@ { "comment": "s8", "span": { - "str": "/// s8", - "start": 40, - "end": 46 + "offset": 40, + "length": 6 } } ], "id": { "string": "b", "span": { - "str": "b", - "start": 52, - "end": 53 + "offset": 52, + "length": 1 } }, "kind": { "type": { "s8": { - "str": "s8", - "start": 56, - "end": 58 + "offset": 56, + "length": 2 } } } @@ -88,26 +82,23 @@ { "comment": "u16", "span": { - "str": "/// u16", - "start": 60, - "end": 67 + "offset": 60, + "length": 7 } } ], "id": { "string": "c", "span": { - "str": "c", - "start": 73, - "end": 74 + "offset": 73, + "length": 1 } }, "kind": { "type": { "u16": { - "str": "u16", - "start": 77, - "end": 80 + "offset": 77, + "length": 3 } } } @@ -123,26 +114,23 @@ { "comment": "s16", "span": { - "str": "/// s16", - "start": 82, - "end": 89 + "offset": 82, + "length": 7 } } ], "id": { "string": "d", "span": { - "str": "d", - "start": 95, - "end": 96 + "offset": 95, + "length": 1 } }, "kind": { "type": { "s16": { - "str": "s16", - "start": 99, - "end": 102 + "offset": 99, + "length": 3 } } } @@ -158,26 +146,23 @@ { "comment": "u32", "span": { - "str": "/// u32", - "start": 104, - "end": 111 + "offset": 104, + "length": 7 } } ], "id": { "string": "e", "span": { - "str": "e", - "start": 117, - "end": 118 + "offset": 117, + "length": 1 } }, "kind": { "type": { "u32": { - "str": "u32", - "start": 121, - "end": 124 + "offset": 121, + "length": 3 } } } @@ -193,26 +178,23 @@ { "comment": "s32", "span": { - "str": "/// s32", - "start": 126, - "end": 133 + "offset": 126, + "length": 7 } } ], "id": { "string": "f", "span": { - "str": "f", - "start": 139, - "end": 140 + "offset": 139, + "length": 1 } }, "kind": { "type": { "s32": { - "str": "s32", - "start": 143, - "end": 146 + "offset": 143, + "length": 3 } } } @@ -228,26 +210,23 @@ { "comment": "u64", "span": { - "str": "/// u64", - "start": 148, - "end": 155 + "offset": 148, + "length": 7 } } ], "id": { "string": "g", "span": { - "str": "g", - "start": 161, - "end": 162 + "offset": 161, + "length": 1 } }, "kind": { "type": { "u64": { - "str": "u64", - "start": 165, - "end": 168 + "offset": 165, + "length": 3 } } } @@ -263,26 +242,23 @@ { "comment": "s64", "span": { - "str": "/// s64", - "start": 170, - "end": 177 + "offset": 170, + "length": 7 } } ], "id": { "string": "h", "span": { - "str": "h", - "start": 183, - "end": 184 + "offset": 183, + "length": 1 } }, "kind": { "type": { "s64": { - "str": "s64", - "start": 187, - "end": 190 + "offset": 187, + "length": 3 } } } @@ -298,26 +274,23 @@ { "comment": "float32", "span": { - "str": "/// float32", - "start": 192, - "end": 203 + "offset": 192, + "length": 11 } } ], "id": { "string": "i", "span": { - "str": "i", - "start": 209, - "end": 210 + "offset": 209, + "length": 1 } }, "kind": { "type": { "float32": { - "str": "float32", - "start": 213, - "end": 220 + "offset": 213, + "length": 7 } } } @@ -333,26 +306,23 @@ { "comment": "float64", "span": { - "str": "/// float64", - "start": 222, - "end": 233 + "offset": 222, + "length": 11 } } ], "id": { "string": "j", "span": { - "str": "j", - "start": 239, - "end": 240 + "offset": 239, + "length": 1 } }, "kind": { "type": { "float64": { - "str": "float64", - "start": 243, - "end": 250 + "offset": 243, + "length": 7 } } } @@ -368,26 +338,23 @@ { "comment": "bool", "span": { - "str": "/// bool", - "start": 252, - "end": 260 + "offset": 252, + "length": 8 } } ], "id": { "string": "k", "span": { - "str": "k", - "start": 266, - "end": 267 + "offset": 266, + "length": 1 } }, "kind": { "type": { "bool": { - "str": "bool", - "start": 270, - "end": 274 + "offset": 270, + "length": 4 } } } @@ -403,26 +370,23 @@ { "comment": "char", "span": { - "str": "/// char", - "start": 276, - "end": 284 + "offset": 276, + "length": 8 } } ], "id": { "string": "l", "span": { - "str": "l", - "start": 290, - "end": 291 + "offset": 290, + "length": 1 } }, "kind": { "type": { "char": { - "str": "char", - "start": 294, - "end": 298 + "offset": 294, + "length": 4 } } } @@ -438,26 +402,23 @@ { "comment": "string", "span": { - "str": "/// string", - "start": 300, - "end": 310 + "offset": 300, + "length": 10 } } ], "id": { "string": "m", "span": { - "str": "m", - "start": 316, - "end": 317 + "offset": 316, + "length": 1 } }, "kind": { "type": { "string": { - "str": "string", - "start": 320, - "end": 326 + "offset": 320, + "length": 6 } } } @@ -473,18 +434,16 @@ { "comment": "tuple", "span": { - "str": "/// tuple", - "start": 328, - "end": 345 + "offset": 328, + "length": 17 } } ], "id": { "string": "n", "span": { - "str": "n", - "start": 351, - "end": 352 + "offset": 351, + "length": 1 } }, "kind": { @@ -493,23 +452,20 @@ [ { "u8": { - "str": "u8", - "start": 361, - "end": 363 + "offset": 361, + "length": 2 } }, { "s8": { - "str": "s8", - "start": 365, - "end": 367 + "offset": 365, + "length": 2 } } ], { - "str": "tuple", - "start": 355, - "end": 368 + "offset": 355, + "length": 13 } ] } @@ -526,18 +482,16 @@ { "comment": "list>", "span": { - "str": "/// list>", - "start": 370, - "end": 389 + "offset": 370, + "length": 19 } } ], "id": { "string": "o", "span": { - "str": "o", - "start": 395, - "end": 396 + "offset": 395, + "length": 1 } }, "kind": { @@ -548,23 +502,20 @@ [ { "u8": { - "str": "u8", - "start": 410, - "end": 412 + "offset": 410, + "length": 2 } } ], { - "str": "tuple", - "start": 404, - "end": 413 + "offset": 404, + "length": 9 } ] }, { - "str": "list>", - "start": 399, - "end": 414 + "offset": 399, + "length": 15 } ] } @@ -581,18 +532,16 @@ { "comment": "option", "span": { - "str": "/// option", - "start": 416, - "end": 434 + "offset": 416, + "length": 18 } } ], "id": { "string": "p", "span": { - "str": "p", - "start": 440, - "end": 441 + "offset": 440, + "length": 1 } }, "kind": { @@ -600,15 +549,13 @@ "option": [ { "string": { - "str": "string", - "start": 451, - "end": 457 + "offset": 451, + "length": 6 } }, { - "str": "option", - "start": 444, - "end": 458 + "offset": 444, + "length": 14 } ] } @@ -625,18 +572,16 @@ { "comment": "result", "span": { - "str": "/// result", - "start": 460, - "end": 470 + "offset": 460, + "length": 10 } } ], "id": { "string": "q", "span": { - "str": "q", - "start": 476, - "end": 477 + "offset": 476, + "length": 1 } }, "kind": { @@ -645,9 +590,8 @@ "ok": null, "err": null, "span": { - "str": "result", - "start": 480, - "end": 486 + "offset": 480, + "length": 6 } } } @@ -664,18 +608,16 @@ { "comment": "result", "span": { - "str": "/// result", - "start": 488, - "end": 502 + "offset": 488, + "length": 14 } } ], "id": { "string": "r", "span": { - "str": "r", - "start": 508, - "end": 509 + "offset": 508, + "length": 1 } }, "kind": { @@ -683,16 +625,14 @@ "result": { "ok": { "u8": { - "str": "u8", - "start": 519, - "end": 521 + "offset": 519, + "length": 2 } }, "err": null, "span": { - "str": "result", - "start": 512, - "end": 522 + "offset": 512, + "length": 10 } } } @@ -709,18 +649,16 @@ { "comment": "result<_, s8>", "span": { - "str": "/// result<_, s8>", - "start": 524, - "end": 541 + "offset": 524, + "length": 17 } } ], "id": { "string": "s", "span": { - "str": "s", - "start": 547, - "end": 548 + "offset": 547, + "length": 1 } }, "kind": { @@ -729,15 +667,13 @@ "ok": null, "err": { "s8": { - "str": "s8", - "start": 561, - "end": 563 + "offset": 561, + "length": 2 } }, "span": { - "str": "result<_, s8>", - "start": 551, - "end": 564 + "offset": 551, + "length": 13 } } } @@ -754,18 +690,16 @@ { "comment": "result", "span": { - "str": "/// result", - "start": 566, - "end": 588 + "offset": 566, + "length": 22 } } ], "id": { "string": "t", "span": { - "str": "t", - "start": 594, - "end": 595 + "offset": 594, + "length": 1 } }, "kind": { @@ -773,22 +707,19 @@ "result": { "ok": { "u8": { - "str": "u8", - "start": 605, - "end": 607 + "offset": 605, + "length": 2 } }, "err": { "string": { - "str": "string", - "start": 609, - "end": 615 + "offset": 609, + "length": 6 } }, "span": { - "str": "result", - "start": 598, - "end": 616 + "offset": 598, + "length": 18 } } } @@ -805,18 +736,16 @@ { "comment": "borrow", "span": { - "str": "/// borrow", - "start": 618, - "end": 631 + "offset": 618, + "length": 13 } } ], "id": { "string": "u", "span": { - "str": "u", - "start": 637, - "end": 638 + "offset": 637, + "length": 1 } }, "kind": { @@ -825,15 +754,13 @@ { "string": "x", "span": { - "str": "x", - "start": 648, - "end": 649 + "offset": 648, + "length": 1 } }, { - "str": "borrow", - "start": 641, - "end": 650 + "offset": 641, + "length": 9 } ] } @@ -850,18 +777,16 @@ { "comment": "x", "span": { - "str": "/// x", - "start": 652, - "end": 657 + "offset": 652, + "length": 5 } } ], "id": { "string": "v", "span": { - "str": "v", - "start": 663, - "end": 664 + "offset": 663, + "length": 1 } }, "kind": { @@ -869,9 +794,8 @@ "ident": { "string": "x", "span": { - "str": "x", - "start": 667, - "end": 668 + "offset": 667, + "length": 1 } } } @@ -888,18 +812,16 @@ { "comment": "keyword", "span": { - "str": "/// keyword", - "start": 670, - "end": 681 + "offset": 670, + "length": 11 } } ], "id": { "string": "type", "span": { - "str": "%type", - "start": 687, - "end": 692 + "offset": 687, + "length": 5 } }, "kind": { @@ -907,9 +829,8 @@ "ident": { "string": "v", "span": { - "str": "v", - "start": 695, - "end": 696 + "offset": 695, + "length": 1 } } } diff --git a/crates/wac-parser/tests/parser/types.wac.result b/crates/wac-parser/tests/parser/types.wac.result index 6d2db30..f67d4cf 100644 --- a/crates/wac-parser/tests/parser/types.wac.result +++ b/crates/wac-parser/tests/parser/types.wac.result @@ -1,12 +1,12 @@ { "docs": [], "package": { + "string": "test:comp", "name": "test:comp", "version": null, "span": { - "str": "test:comp", - "start": 8, - "end": 17 + "offset": 8, + "length": 9 } }, "statements": [ @@ -17,18 +17,16 @@ { "comment": "Defining an interface", "span": { - "str": "/// Defining an interface", - "start": 20, - "end": 45 + "offset": 20, + "length": 25 } } ], "id": { "string": "i", "span": { - "str": "i", - "start": 56, - "end": 57 + "offset": 56, + "length": 1 } }, "items": [ @@ -39,18 +37,16 @@ { "comment": "Defining a resource", "span": { - "str": "/// Defining a resource", - "start": 64, - "end": 87 + "offset": 64, + "length": 23 } } ], "id": { "string": "res", "span": { - "str": "res", - "start": 101, - "end": 104 + "offset": 101, + "length": 3 } }, "methods": [ @@ -58,9 +54,8 @@ "constructor": { "docs": [], "span": { - "str": "constructor", - "start": 115, - "end": 126 + "offset": 115, + "length": 11 }, "params": [] } @@ -76,18 +71,16 @@ { "comment": "Type alias a", "span": { - "str": "/// Type alias a", - "start": 141, - "end": 157 + "offset": 141, + "length": 16 } } ], "id": { "string": "a", "span": { - "str": "a", - "start": 167, - "end": 168 + "offset": 167, + "length": 1 } }, "kind": { @@ -106,18 +99,16 @@ { "comment": "Record type", "span": { - "str": "/// Record type", - "start": 183, - "end": 198 + "offset": 183, + "length": 15 } } ], "id": { "string": "r", "span": { - "str": "r", - "start": 210, - "end": 211 + "offset": 210, + "length": 1 } }, "fields": [ @@ -126,16 +117,14 @@ "id": { "string": "x", "span": { - "str": "x", - "start": 222, - "end": 223 + "offset": 222, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 225, - "end": 228 + "offset": 225, + "length": 3 } } } @@ -149,18 +138,16 @@ { "comment": "Export func", "span": { - "str": "/// Export func", - "start": 239, - "end": 254 + "offset": 239, + "length": 15 } } ], "id": { "string": "x", "span": { - "str": "x", - "start": 259, - "end": 260 + "offset": 259, + "length": 1 } }, "ty": { @@ -177,27 +164,24 @@ { "comment": "Export func of type a", "span": { - "str": "/// Export func of type a", - "start": 274, - "end": 299 + "offset": 274, + "length": 25 } } ], "id": { "string": "y", "span": { - "str": "y", - "start": 304, - "end": 305 + "offset": 304, + "length": 1 } }, "ty": { "ident": { "string": "a", "span": { - "str": "a", - "start": 307, - "end": 308 + "offset": 307, + "length": 1 } } } @@ -214,18 +198,16 @@ { "comment": "Defining a second interface", "span": { - "str": "/// Defining a second interface", - "start": 313, - "end": 344 + "offset": 313, + "length": 31 } } ], "id": { "string": "i2", "span": { - "str": "i2", - "start": 355, - "end": 357 + "offset": 355, + "length": 2 } }, "items": [ @@ -235,9 +217,8 @@ { "comment": "Use type r from i", "span": { - "str": "/// Use type r from i", - "start": 364, - "end": 385 + "offset": 364, + "length": 21 } } ], @@ -245,9 +226,8 @@ "ident": { "string": "i", "span": { - "str": "i", - "start": 394, - "end": 395 + "offset": 394, + "length": 1 } } }, @@ -256,9 +236,8 @@ "id": { "string": "r", "span": { - "str": "r", - "start": 397, - "end": 398 + "offset": 397, + "length": 1 } }, "asId": null @@ -272,9 +251,8 @@ { "comment": "Use type r from i with alias z", "span": { - "str": "/// Use type r from i with alias z", - "start": 406, - "end": 440 + "offset": 406, + "length": 34 } } ], @@ -282,9 +260,8 @@ "ident": { "string": "i", "span": { - "str": "i", - "start": 449, - "end": 450 + "offset": 449, + "length": 1 } } }, @@ -293,17 +270,15 @@ "id": { "string": "r", "span": { - "str": "r", - "start": 452, - "end": 453 + "offset": 452, + "length": 1 } }, "asId": { "string": "z", "span": { - "str": "z", - "start": 457, - "end": 458 + "offset": 457, + "length": 1 } } } @@ -321,18 +296,16 @@ { "comment": "Defining a world", "span": { - "str": "/// Defining a world", - "start": 464, - "end": 484 + "offset": 464, + "length": 20 } } ], "id": { "string": "w1", "span": { - "str": "w1", - "start": 491, - "end": 493 + "offset": 491, + "length": 2 } }, "items": [ @@ -342,19 +315,18 @@ { "comment": "Use type r from foo:bar/i", "span": { - "str": "/// Use type r from foo:bar/i", - "start": 500, - "end": 529 + "offset": 500, + "length": 29 } } ], "path": { "package": { "span": { - "str": "foo:bar/i", - "start": 538, - "end": 547 + "offset": 538, + "length": 9 }, + "string": "foo:bar/i", "name": "foo:bar", "segments": "i", "version": null @@ -365,9 +337,8 @@ "id": { "string": "r", "span": { - "str": "r", - "start": 549, - "end": 550 + "offset": 549, + "length": 1 } }, "asId": null @@ -381,9 +352,8 @@ { "comment": "Import a function", "span": { - "str": "/// Import a function", - "start": 558, - "end": 579 + "offset": 558, + "length": 21 } } ], @@ -392,9 +362,8 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 591, - "end": 592 + "offset": 591, + "length": 1 } }, "ty": { @@ -413,9 +382,8 @@ { "comment": "Import an interface", "span": { - "str": "/// Import an interface", - "start": 606, - "end": 629 + "offset": 606, + "length": 23 } } ], @@ -423,9 +391,8 @@ "ident": { "string": "i", "span": { - "str": "i", - "start": 641, - "end": 642 + "offset": 641, + "length": 1 } } } @@ -437,9 +404,8 @@ { "comment": "Import by name with type `c`", "span": { - "str": "/// Import by name with type `c`", - "start": 648, - "end": 680 + "offset": 648, + "length": 32 } } ], @@ -448,18 +414,16 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 692, - "end": 693 + "offset": 692, + "length": 1 } }, "ty": { "ident": { "string": "c", "span": { - "str": "c", - "start": 695, - "end": 696 + "offset": 695, + "length": 1 } } } @@ -473,9 +437,8 @@ { "comment": "Export an inline interface", "span": { - "str": "/// Export an inline interface", - "start": 703, - "end": 733 + "offset": 703, + "length": 30 } } ], @@ -484,9 +447,8 @@ "id": { "string": "d", "span": { - "str": "d", - "start": 745, - "end": 746 + "offset": 745, + "length": 1 } }, "ty": { @@ -498,9 +460,8 @@ "id": { "string": "x", "span": { - "str": "x", - "start": 768, - "end": 769 + "offset": 768, + "length": 1 } }, "ty": { @@ -524,9 +485,8 @@ { "comment": "Export an interface", "span": { - "str": "/// Export an interface", - "start": 790, - "end": 813 + "offset": 790, + "length": 23 } } ], @@ -534,9 +494,8 @@ "ident": { "string": "i2", "span": { - "str": "i2", - "start": 825, - "end": 827 + "offset": 825, + "length": 2 } } } @@ -548,9 +507,8 @@ { "comment": "Export by name with type `f`", "span": { - "str": "/// Export by name with type `f`", - "start": 833, - "end": 865 + "offset": 833, + "length": 32 } } ], @@ -559,18 +517,16 @@ "id": { "string": "f", "span": { - "str": "f", - "start": 877, - "end": 878 + "offset": 877, + "length": 1 } }, "ty": { "ident": { "string": "f", "span": { - "str": "f", - "start": 880, - "end": 881 + "offset": 880, + "length": 1 } } } @@ -589,18 +545,16 @@ { "comment": "Defining a second world", "span": { - "str": "/// Defining a second world", - "start": 886, - "end": 913 + "offset": 886, + "length": 27 } } ], "id": { "string": "w2", "span": { - "str": "w2", - "start": 920, - "end": 922 + "offset": 920, + "length": 2 } }, "items": [ @@ -610,9 +564,8 @@ { "comment": "Include the first world", "span": { - "str": "/// Include the first world", - "start": 929, - "end": 956 + "offset": 929, + "length": 27 } } ], @@ -620,9 +573,8 @@ "ident": { "string": "w1", "span": { - "str": "w1", - "start": 969, - "end": 971 + "offset": 969, + "length": 2 } } }, @@ -635,19 +587,18 @@ { "comment": "Include a world by path", "span": { - "str": "/// Include a world by path", - "start": 978, - "end": 1005 + "offset": 978, + "length": 27 } } ], "world": { "package": { "span": { - "str": "foo:bar/baz", - "start": 1018, - "end": 1029 + "offset": 1018, + "length": 11 }, + "string": "foo:bar/baz", "name": "foo:bar", "segments": "baz", "version": null @@ -668,18 +619,16 @@ { "comment": "Defining a variant", "span": { - "str": "/// Defining a variant", - "start": 1034, - "end": 1056 + "offset": 1034, + "length": 22 } } ], "id": { "string": "v", "span": { - "str": "v", - "start": 1065, - "end": 1066 + "offset": 1065, + "length": 1 } }, "cases": [ @@ -688,18 +637,16 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 1073, - "end": 1074 + "offset": 1073, + "length": 1 } }, "ty": { "ident": { "string": "x", "span": { - "str": "x", - "start": 1075, - "end": 1076 + "offset": 1075, + "length": 1 } } } @@ -709,16 +656,14 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 1083, - "end": 1084 + "offset": 1083, + "length": 1 } }, "ty": { "string": { - "str": "string", - "start": 1085, - "end": 1091 + "offset": 1085, + "length": 6 } } }, @@ -727,16 +672,14 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 1098, - "end": 1099 + "offset": 1098, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 1100, - "end": 1103 + "offset": 1100, + "length": 3 } } }, @@ -745,9 +688,8 @@ "id": { "string": "d", "span": { - "str": "d", - "start": 1110, - "end": 1111 + "offset": 1110, + "length": 1 } }, "ty": null @@ -765,18 +707,16 @@ { "comment": "Defining a record", "span": { - "str": "/// Defining a record", - "start": 1116, - "end": 1137 + "offset": 1116, + "length": 21 } } ], "id": { "string": "r", "span": { - "str": "r", - "start": 1145, - "end": 1146 + "offset": 1145, + "length": 1 } }, "fields": [ @@ -785,16 +725,14 @@ "id": { "string": "x", "span": { - "str": "x", - "start": 1153, - "end": 1154 + "offset": 1153, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 1156, - "end": 1159 + "offset": 1156, + "length": 3 } } }, @@ -803,16 +741,14 @@ "id": { "string": "y", "span": { - "str": "y", - "start": 1165, - "end": 1166 + "offset": 1165, + "length": 1 } }, "ty": { "string": { - "str": "string", - "start": 1168, - "end": 1174 + "offset": 1168, + "length": 6 } } }, @@ -821,18 +757,16 @@ "id": { "string": "z", "span": { - "str": "z", - "start": 1180, - "end": 1181 + "offset": 1180, + "length": 1 } }, "ty": { "ident": { "string": "v", "span": { - "str": "v", - "start": 1183, - "end": 1184 + "offset": 1183, + "length": 1 } } } @@ -850,18 +784,16 @@ { "comment": "Defining flags", "span": { - "str": "/// Defining flags", - "start": 1190, - "end": 1208 + "offset": 1190, + "length": 18 } } ], "id": { "string": "f", "span": { - "str": "f", - "start": 1215, - "end": 1216 + "offset": 1215, + "length": 1 } }, "flags": [ @@ -870,9 +802,8 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 1223, - "end": 1224 + "offset": 1223, + "length": 1 } } }, @@ -881,9 +812,8 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 1230, - "end": 1231 + "offset": 1230, + "length": 1 } } }, @@ -892,9 +822,8 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 1237, - "end": 1238 + "offset": 1237, + "length": 1 } } } @@ -911,18 +840,16 @@ { "comment": "Defining an enum", "span": { - "str": "/// Defining an enum", - "start": 1243, - "end": 1263 + "offset": 1243, + "length": 20 } } ], "id": { "string": "e", "span": { - "str": "e", - "start": 1269, - "end": 1270 + "offset": 1269, + "length": 1 } }, "cases": [ @@ -931,9 +858,8 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 1277, - "end": 1278 + "offset": 1277, + "length": 1 } } }, @@ -942,9 +868,8 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 1284, - "end": 1285 + "offset": 1284, + "length": 1 } } }, @@ -953,9 +878,8 @@ "id": { "string": "c", "span": { - "str": "c", - "start": 1291, - "end": 1292 + "offset": 1291, + "length": 1 } } } @@ -972,18 +896,16 @@ { "comment": "Type aliases", "span": { - "str": "/// Type aliases", - "start": 1297, - "end": 1313 + "offset": 1297, + "length": 16 } } ], "id": { "string": "t", "span": { - "str": "t", - "start": 1319, - "end": 1320 + "offset": 1319, + "length": 1 } }, "kind": { @@ -991,9 +913,8 @@ "ident": { "string": "e", "span": { - "str": "e", - "start": 1323, - "end": 1324 + "offset": 1323, + "length": 1 } } } @@ -1010,17 +931,15 @@ "id": { "string": "t2", "span": { - "str": "t2", - "start": 1331, - "end": 1333 + "offset": 1331, + "length": 2 } }, "kind": { "type": { "string": { - "str": "string", - "start": 1336, - "end": 1342 + "offset": 1336, + "length": 6 } } } @@ -1036,9 +955,8 @@ "id": { "string": "t3", "span": { - "str": "t3", - "start": 1349, - "end": 1351 + "offset": 1349, + "length": 2 } }, "kind": { @@ -1048,16 +966,14 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 1359, - "end": 1360 + "offset": 1359, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 1362, - "end": 1365 + "offset": 1362, + "length": 3 } } }, @@ -1065,18 +981,16 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 1367, - "end": 1368 + "offset": 1367, + "length": 1 } }, "ty": { "ident": { "string": "r", "span": { - "str": "r", - "start": 1370, - "end": 1371 + "offset": 1370, + "length": 1 } } } @@ -1085,9 +999,8 @@ "results": { "scalar": { "u32": { - "str": "u32", - "start": 1376, - "end": 1379 + "offset": 1376, + "length": 3 } } } @@ -1105,9 +1018,8 @@ "id": { "string": "t4", "span": { - "str": "t4", - "start": 1386, - "end": 1388 + "offset": 1386, + "length": 2 } }, "kind": { @@ -1119,16 +1031,14 @@ "id": { "string": "a", "span": { - "str": "a", - "start": 1402, - "end": 1403 + "offset": 1402, + "length": 1 } }, "ty": { "u32": { - "str": "u32", - "start": 1405, - "end": 1408 + "offset": 1405, + "length": 3 } } }, @@ -1136,16 +1046,14 @@ "id": { "string": "b", "span": { - "str": "b", - "start": 1410, - "end": 1411 + "offset": 1410, + "length": 1 } }, "ty": { "string": { - "str": "string", - "start": 1413, - "end": 1419 + "offset": 1413, + "length": 6 } } } diff --git a/crates/wac-parser/tests/resolution.rs b/crates/wac-parser/tests/resolution.rs index aa3f879..92546f2 100644 --- a/crates/wac-parser/tests/resolution.rs +++ b/crates/wac-parser/tests/resolution.rs @@ -10,7 +10,10 @@ use std::{ process::exit, sync::atomic::{AtomicUsize, Ordering}, }; -use wac_parser::{ast::Document, Composition, ErrorFormatter, FileSystemPackageResolver}; +use support::fmt_err; +use wac_parser::{ast::Document, Composition, FileSystemPackageResolver}; + +mod support; #[cfg(not(feature = "wat"))] compile_error!("the `wat` feature must be enabled for this test to run"); @@ -80,8 +83,9 @@ fn compare_result(test: &Path, result: &str, should_fail: bool) -> Result<()> { fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { let should_fail = test.parent().map(|p| p.ends_with("fail")).unwrap_or(false); let source = std::fs::read_to_string(test)?.replace("\r\n", "\n"); - let document = Document::parse(&source, test) - .map_err(|e| anyhow!("{e}", e = ErrorFormatter::new(test, e, false)))?; + + let document = Document::parse(&source).map_err(|e| anyhow!(fmt_err(e, test, &source)))?; + let result = match Composition::from_ast( &document, Some(Box::new(FileSystemPackageResolver::new( @@ -98,13 +102,11 @@ fn run_test(test: &Path, ntests: &AtomicUsize) -> Result<()> { } Err(e) => { if !should_fail { - bail!( - "the resolution failed but it was expected to succeed: {e}", - e = ErrorFormatter::new(test, e, false) - ); + return Err(anyhow!(fmt_err(e, test, &source)) + .context("the resolution failed but it was expected to succeed")); } - format!("{e}", e = ErrorFormatter::new(test, e, false)) + fmt_err(e, test, &source) } }; diff --git a/crates/wac-parser/tests/resolution/fail/arg-merge-failure.wac.result b/crates/wac-parser/tests/resolution/fail/arg-merge-failure.wac.result index 2155f32..96b89e5 100644 --- a/crates/wac-parser/tests/resolution/fail/arg-merge-failure.wac.result +++ b/crates/wac-parser/tests/resolution/fail/arg-merge-failure.wac.result @@ -1,5 +1,12 @@ -implicit instantiation argument `foo` (instance) conflicts with an implicitly imported argument from the instantiation of `foo:bar` at tests/resolution/fail/arg-merge-failure.wac:3:13 - --> tests/resolution/fail/arg-merge-failure.wac:4:13 - | - 4 | let b = new bar:baz { ... }; - | ^-----^ +failed to resolve document + + × implicit instantiation argument `foo` (instance) conflicts with an implicitly imported argument from the instantiation of `foo:bar` + ╭─[tests/resolution/fail/arg-merge-failure.wac:4:13] + 2 │ + 3 │ let a = new foo:bar { ... }; + · ───┬─── + · ╰── previous instantiation here + 4 │ let b = new bar:baz { ... }; + · ───┬─── + · ╰── conflicting instantiation here + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/borrow-in-func-result.wac.result b/crates/wac-parser/tests/resolution/fail/borrow-in-func-result.wac.result index fd746b4..a44c0a8 100644 --- a/crates/wac-parser/tests/resolution/fail/borrow-in-func-result.wac.result +++ b/crates/wac-parser/tests/resolution/fail/borrow-in-func-result.wac.result @@ -1,5 +1,10 @@ -function result cannot recursively contain a borrow type - --> tests/resolution/fail/borrow-in-func-result.wac:6:18 - | - 6 | f: func() -> result; - | ^-------^ +failed to resolve document + + × function result cannot recursively contain a borrow type + ╭─[tests/resolution/fail/borrow-in-func-result.wac:6:18] + 5 │ type a = borrow; + 6 │ f: func() -> result; + · ────┬──── + · ╰── borrow type in result + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-enum-case.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-enum-case.wac.result index 33d8ef8..70f1835 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-enum-case.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-enum-case.wac.result @@ -1,5 +1,10 @@ -duplicate case `b` for enum type `e` - --> tests/resolution/fail/duplicate-enum-case.wac:7:5 - | - 7 | b, - | ^ +failed to resolve document + + × duplicate case `b` for enum type `e` + ╭─[tests/resolution/fail/duplicate-enum-case.wac:7:5] + 6 │ c, + 7 │ b, + · ┬ + · ╰── duplicate case `b` + 8 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-flag.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-flag.wac.result index 26b7380..7782614 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-flag.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-flag.wac.result @@ -1,5 +1,10 @@ -duplicate flag `a` for flags type `f` - --> tests/resolution/fail/duplicate-flag.wac:8:5 - | - 8 | a, - | ^ +failed to resolve document + + × duplicate flag `a` for flags type `f` + ╭─[tests/resolution/fail/duplicate-flag.wac:8:5] + 7 │ d, + 8 │ a, + · ┬ + · ╰── duplicate flag `a` + 9 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-func-param.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-func-param.wac.result index 484bd29..7c62202 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-func-param.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-func-param.wac.result @@ -1,5 +1,9 @@ -duplicate function parameter `x` - --> tests/resolution/fail/duplicate-func-param.wac:3:23 - | - 3 | type f = func(x: u32, x: string); - | ^ +failed to resolve document + + × duplicate function parameter `x` + ╭─[tests/resolution/fail/duplicate-func-param.wac:3:23] + 2 │ + 3 │ type f = func(x: u32, x: string); + · ┬ + · ╰── duplicate parameter `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-func-result.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-func-result.wac.result index fd9c8a3..d50af8b 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-func-result.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-func-result.wac.result @@ -1,5 +1,9 @@ -duplicate function result `a` - --> tests/resolution/fail/duplicate-func-result.wac:3:29 - | - 3 | type f = func() -> (a: u32, a: s8); - | ^ +failed to resolve document + + × duplicate function result `a` + ╭─[tests/resolution/fail/duplicate-func-result.wac:3:29] + 2 │ + 3 │ type f = func() -> (a: u32, a: s8); + · ┬ + · ╰── duplicate result `a` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-inst-args.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-inst-args.wac.result index 39d4582..190a9f7 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-inst-args.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-inst-args.wac.result @@ -1,5 +1,9 @@ -duplicate instantiation argument `foo` - --> tests/resolution/fail/duplicate-inst-args.wac:5:33 - | - 5 | let x = new foo:bar { foo: bar, foo: bar }; - | ^-^ +failed to resolve document + + × duplicate instantiation argument `foo` + ╭─[tests/resolution/fail/duplicate-inst-args.wac:5:33] + 4 │ + 5 │ let x = new foo:bar { foo: bar, foo: bar }; + · ─┬─ + · ╰── duplicate argument `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-interface-export.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-interface-export.wac.result index b4d6647..c88b507 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-interface-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-interface-export.wac.result @@ -1,5 +1,10 @@ -duplicate interface export `x` for interface `x` - --> tests/resolution/fail/duplicate-interface-export.wac:5:5 - | - 5 | x: func(); - | ^ +failed to resolve document + + × duplicate interface export `x` for interface `x` + ╭─[tests/resolution/fail/duplicate-interface-export.wac:5:5] + 4 │ x: func(); + 5 │ x: func(); + · ┬ + · ╰── duplicate export `x` + 6 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-name-in-include.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-name-in-include.wac.result index 9ed0555..adb1643 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-name-in-include.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-name-in-include.wac.result @@ -1,5 +1,10 @@ -duplicate `a` in world include `with` clause - --> tests/resolution/fail/duplicate-name-in-include.wac:8:31 - | - 8 | include w1 with { a as b, a as c}; - | ^ +failed to resolve document + + × duplicate `a` in world include `with` clause + ╭─[tests/resolution/fail/duplicate-name-in-include.wac:8:31] + 7 │ world w2 { + 8 │ include w1 with { a as b, a as c}; + · ┬ + · ╰── duplicate name `a` + 9 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-record-field.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-record-field.wac.result index 8d35d0f..9ced61c 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-record-field.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-record-field.wac.result @@ -1,5 +1,10 @@ -duplicate field `b` for record type `r` - --> tests/resolution/fail/duplicate-record-field.wac:9:5 - | - 9 | b: string, - | ^ +failed to resolve document + + × duplicate field `b` for record type `r` + ╭─[tests/resolution/fail/duplicate-record-field.wac:9:5] + 8 │ c: x, + 9 │ b: string, + · ┬ + · ╰── duplicate field `b` + 10 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor-param.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor-param.wac.result index 42c2bb1..08fa3cf 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor-param.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor-param.wac.result @@ -1,5 +1,10 @@ -duplicate constructor parameter `a` - --> tests/resolution/fail/duplicate-resource-constructor-param.wac:5:29 - | - 5 | constructor(a: u32, a: string); - | ^ +failed to resolve document + + × duplicate constructor parameter `a` + ╭─[tests/resolution/fail/duplicate-resource-constructor-param.wac:5:29] + 4 │ resource x { + 5 │ constructor(a: u32, a: string); + · ┬ + · ╰── duplicate parameter `a` + 6 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor.wac.result index dee2969..1f03251 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-resource-constructor.wac.result @@ -1,5 +1,10 @@ -duplicate constructor for resource `x` - --> tests/resolution/fail/duplicate-resource-constructor.wac:6:9 - | - 6 | constructor(x: u32); - | ^---------^ +failed to resolve document + + × duplicate constructor for resource `x` + ╭─[tests/resolution/fail/duplicate-resource-constructor.wac:6:9] + 5 │ constructor(); + 6 │ constructor(x: u32); + · ─────┬───── + · ╰── duplicate constructor + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-resource-method.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-resource-method.wac.result index 27d2ce0..e6d22db 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-resource-method.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-resource-method.wac.result @@ -1,5 +1,10 @@ -duplicate method `x` for resource `x` - --> tests/resolution/fail/duplicate-resource-method.wac:6:9 - | - 6 | x: static func(); - | ^ +failed to resolve document + + × duplicate method `x` for resource `x` + ╭─[tests/resolution/fail/duplicate-resource-method.wac:6:9] + 5 │ x: func(); + 6 │ x: static func(); + · ┬ + · ╰── duplicate method `x` + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-use-in-interface.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-use-in-interface.wac.result index 20156ce..0cdd39b 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-use-in-interface.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-use-in-interface.wac.result @@ -1,5 +1,11 @@ -use of type `x` conflicts with an export of the same name (consider using an `as` clause to use a different name) - --> tests/resolution/fail/duplicate-use-in-interface.wac:9:12 - | - 9 | use i.{x}; - | ^ +failed to resolve document + + × use of type `x` conflicts with an export of the same name + ╭─[tests/resolution/fail/duplicate-use-in-interface.wac:9:12] + 8 │ x: func(); + 9 │ use i.{x}; + · ┬ + · ╰── conflicting name `x` + 10 │ } + ╰──── + help: consider using an `as` clause to use a different name diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-use-in-world.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-use-in-world.wac.result index dbd7336..140e518 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-use-in-world.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-use-in-world.wac.result @@ -1,5 +1,11 @@ -use of type `x` conflicts with an import of the same name (consider using an `as` clause to use a different name) - --> tests/resolution/fail/duplicate-use-in-world.wac:9:12 - | - 9 | use i.{x}; - | ^ +failed to resolve document + + × use of type `x` conflicts with an import of the same name + ╭─[tests/resolution/fail/duplicate-use-in-world.wac:9:12] + 8 │ import x: func(); + 9 │ use i.{x}; + · ┬ + · ╰── conflicting name `x` + 10 │ } + ╰──── + help: consider using an `as` clause to use a different name diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-variant-case.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-variant-case.wac.result index b17a7c6..883bf04 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-variant-case.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-variant-case.wac.result @@ -1,5 +1,10 @@ -duplicate case `a` for variant type `x` - --> tests/resolution/fail/duplicate-variant-case.wac:8:5 - | - 8 | a, - | ^ +failed to resolve document + + × duplicate case `a` for variant type `x` + ╭─[tests/resolution/fail/duplicate-variant-case.wac:8:5] + 7 │ b, + 8 │ a, + · ┬ + · ╰── duplicate case `a` + 9 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-world-export.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-world-export.wac.result index df513d6..bf6abde 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-world-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-world-export.wac.result @@ -1,5 +1,10 @@ -export `x` conflicts with existing export of the same name in world `w` - --> tests/resolution/fail/duplicate-world-export.wac:5:12 - | - 5 | export x: func(); - | ^ +failed to resolve document + + × export `x` conflicts with existing export of the same name in world `w` + ╭─[tests/resolution/fail/duplicate-world-export.wac:5:12] + 4 │ export x: func(); + 5 │ export x: func(); + · ┬ + · ╰── conflicting name `x` + 6 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/duplicate-world-import.wac.result b/crates/wac-parser/tests/resolution/fail/duplicate-world-import.wac.result index 098bd47..e3684e1 100644 --- a/crates/wac-parser/tests/resolution/fail/duplicate-world-import.wac.result +++ b/crates/wac-parser/tests/resolution/fail/duplicate-world-import.wac.result @@ -1,5 +1,10 @@ -import `x` conflicts with existing import of the same name in world `w` - --> tests/resolution/fail/duplicate-world-import.wac:5:12 - | - 5 | import x: func(); - | ^ +failed to resolve document + + × import `x` conflicts with existing import of the same name in world `w` + ╭─[tests/resolution/fail/duplicate-world-import.wac:5:12] + 4 │ import x: func(); + 5 │ import x: func(); + · ┬ + · ╰── conflicting name `x` + 6 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/expected-result-named.wac.result b/crates/wac-parser/tests/resolution/fail/expected-result-named.wac.result index 8440bec..83a4f6c 100644 --- a/crates/wac-parser/tests/resolution/fail/expected-result-named.wac.result +++ b/crates/wac-parser/tests/resolution/fail/expected-result-named.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/expected-result-named.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function with named results, found function with scalar result \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function with named results, found function with scalar result + ╭─[tests/resolution/fail/expected-result-named.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/expected-result-scalar.wac.result b/crates/wac-parser/tests/resolution/fail/expected-result-scalar.wac.result index c3150be..6a02c35 100644 --- a/crates/wac-parser/tests/resolution/fail/expected-result-scalar.wac.result +++ b/crates/wac-parser/tests/resolution/fail/expected-result-scalar.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/expected-result-scalar.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function with scalar result, found function with named results \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function with scalar result, found function with named results + ╭─[tests/resolution/fail/expected-result-scalar.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-conflict-alias.wac.result b/crates/wac-parser/tests/resolution/fail/export-conflict-alias.wac.result index 161573f..6136f05 100644 --- a/crates/wac-parser/tests/resolution/fail/export-conflict-alias.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-conflict-alias.wac.result @@ -1,5 +1,14 @@ -export `x` conflicts with u32 definition at tests/resolution/fail/export-conflict-alias.wac:5:6 (consider using a `with` clause to use a different name) - --> tests/resolution/fail/export-conflict-alias.wac:7:1 - | - 7 | export f; - | ^----^ +failed to resolve document + + × export `x` conflicts with u32 definition + ╭─[tests/resolution/fail/export-conflict-alias.wac:7:1] + 4 │ + 5 │ type x = u32; + · ┬ + · ╰── previous definition is here + 6 │ + 7 │ export f; + · ───┬── + · ╰── conflicting export of `x` + ╰──── + help: consider using a `with` clause to use a different name diff --git a/crates/wac-parser/tests/resolution/fail/export-conflict-interface.wac.result b/crates/wac-parser/tests/resolution/fail/export-conflict-interface.wac.result index d53d5d7..b671daf 100644 --- a/crates/wac-parser/tests/resolution/fail/export-conflict-interface.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-conflict-interface.wac.result @@ -1,5 +1,15 @@ -export `foo` conflicts with interface definition at tests/resolution/fail/export-conflict-interface.wac:5:11 - --> tests/resolution/fail/export-conflict-interface.wac:9:15 - | - 9 | export f with "foo"; - | ^---^ +failed to resolve document + + × export `foo` conflicts with interface definition + ╭─[tests/resolution/fail/export-conflict-interface.wac:9:15] + 4 │ + 5 │ interface foo { + · ─┬─ + · ╰── previous definition is here + 6 │ + 7 │ } + 8 │ + 9 │ export f with "foo"; + · ──┬── + · ╰── conflicting export of `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-conflict-type.wac.result b/crates/wac-parser/tests/resolution/fail/export-conflict-type.wac.result index 8bc969f..319976f 100644 --- a/crates/wac-parser/tests/resolution/fail/export-conflict-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-conflict-type.wac.result @@ -1,5 +1,15 @@ -export `x` conflicts with record definition at tests/resolution/fail/export-conflict-type.wac:5:8 - --> tests/resolution/fail/export-conflict-type.wac:9:15 - | - 9 | export f with "x"; - | ^-^ +failed to resolve document + + × export `x` conflicts with record definition + ╭─[tests/resolution/fail/export-conflict-type.wac:9:15] + 4 │ + 5 │ record x { + · ┬ + · ╰── previous definition is here + 6 │ a: u32 + 7 │ } + 8 │ + 9 │ export f with "x"; + · ─┬─ + · ╰── conflicting export of `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-conflict-world.wac.result b/crates/wac-parser/tests/resolution/fail/export-conflict-world.wac.result index 2952462..ca24b14 100644 --- a/crates/wac-parser/tests/resolution/fail/export-conflict-world.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-conflict-world.wac.result @@ -1,5 +1,15 @@ -export `foo` conflicts with world definition at tests/resolution/fail/export-conflict-world.wac:5:7 - --> tests/resolution/fail/export-conflict-world.wac:9:15 - | - 9 | export f with "foo"; - | ^---^ +failed to resolve document + + × export `foo` conflicts with world definition + ╭─[tests/resolution/fail/export-conflict-world.wac:9:15] + 4 │ + 5 │ world foo { + · ─┬─ + · ╰── previous definition is here + 6 │ + 7 │ } + 8 │ + 9 │ export f with "foo"; + · ──┬── + · ╰── conflicting export of `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-dep-name.wac.result b/crates/wac-parser/tests/resolution/fail/export-dep-name.wac.result index 5376c5b..95fa44d 100644 --- a/crates/wac-parser/tests/resolution/fail/export-dep-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-dep-name.wac.result @@ -1,8 +1,10 @@ -export name `locked-dep=` is not valid - --> tests/resolution/fail/export-dep-name.wac:4:15 - | - 4 | export f with "locked-dep="; - | ^--------------------^ +failed to resolve document -Caused by: - export name cannot be a hash, url, or dependency \ No newline at end of file + × export name `locked-dep=` is not valid + ╰─▶ export name cannot be a hash, url, or dependency + ╭─[tests/resolution/fail/export-dep-name.wac:4:15] + 3 │ import f: func(); + 4 │ export f with "locked-dep="; + · ───────────┬────────── + · ╰── invalid name `locked-dep=` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-duplicate-name.wac.result b/crates/wac-parser/tests/resolution/fail/export-duplicate-name.wac.result index c933482..2b2dea9 100644 --- a/crates/wac-parser/tests/resolution/fail/export-duplicate-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-duplicate-name.wac.result @@ -1,5 +1,12 @@ -duplicate export `x` - --> tests/resolution/fail/export-duplicate-name.wac:5:15 - | - 5 | export f with "x"; - | ^-^ +failed to resolve document + + × duplicate export `x` + ╭─[tests/resolution/fail/export-duplicate-name.wac:5:15] + 3 │ import f: func(); + 4 │ export f with "x"; + · ─┬─ + · ╰── previous export here + 5 │ export f with "x"; + · ─┬─ + · ╰── duplicate export name `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-hash-name.wac.result b/crates/wac-parser/tests/resolution/fail/export-hash-name.wac.result index 6aa8b6c..3045782 100644 --- a/crates/wac-parser/tests/resolution/fail/export-hash-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-hash-name.wac.result @@ -1,8 +1,10 @@ -export name `integrity=` is not valid - --> tests/resolution/fail/export-hash-name.wac:4:15 - | - 4 | export f with "integrity="; - | ^-----------------------------------------------------------------------------------^ +failed to resolve document -Caused by: - export name cannot be a hash, url, or dependency \ No newline at end of file + × export name `integrity=` is not valid + ╰─▶ export name cannot be a hash, url, or dependency + ╭─[tests/resolution/fail/export-hash-name.wac:4:15] + 3 │ import f: func(); + 4 │ export f with "integrity="; + · ──────────────────────────────────────────┬────────────────────────────────────────── + · ╰── invalid name `integrity=` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-invalid-name.wac.result b/crates/wac-parser/tests/resolution/fail/export-invalid-name.wac.result index 560ed75..002cece 100644 --- a/crates/wac-parser/tests/resolution/fail/export-invalid-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-invalid-name.wac.result @@ -1,8 +1,10 @@ -export name `INVALID!` is not valid - --> tests/resolution/fail/export-invalid-name.wac:4:15 - | - 4 | export f with "INVALID!"; - | ^--------^ +failed to resolve document -Caused by: - `INVALID!` is not in kebab case \ No newline at end of file + × export name `INVALID!` is not valid + ╰─▶ `INVALID!` is not in kebab case + ╭─[tests/resolution/fail/export-invalid-name.wac:4:15] + 3 │ import f: func(); + 4 │ export f with "INVALID!"; + · ─────┬──── + · ╰── invalid name `INVALID!` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-needs-with.wac.result b/crates/wac-parser/tests/resolution/fail/export-needs-with.wac.result index 3f4df1a..03151bc 100644 --- a/crates/wac-parser/tests/resolution/fail/export-needs-with.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-needs-with.wac.result @@ -1,5 +1,9 @@ -export statement requires a `with` clause as the export name cannot be inferred - --> tests/resolution/fail/export-needs-with.wac:4:1 - | - 4 | export i; - | ^----^ +failed to resolve document + + × export statement requires a `with` clause as the export name cannot be inferred + ╭─[tests/resolution/fail/export-needs-with.wac:4:1] + 3 │ let i = new foo:bar {}; + 4 │ export i; + · ───┬── + · ╰── a `with` clause is required + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/export-url-name.wac.result b/crates/wac-parser/tests/resolution/fail/export-url-name.wac.result index c8933be..a24b205 100644 --- a/crates/wac-parser/tests/resolution/fail/export-url-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/export-url-name.wac.result @@ -1,8 +1,10 @@ -export name `url=` is not valid - --> tests/resolution/fail/export-url-name.wac:4:15 - | - 4 | export f with "url="; - | ^-----------------------------^ +failed to resolve document -Caused by: - export name cannot be a hash, url, or dependency \ No newline at end of file + × export name `url=` is not valid + ╰─▶ export name cannot be a hash, url, or dependency + ╭─[tests/resolution/fail/export-url-name.wac:4:15] + 3 │ import f: func(); + 4 │ export f with "url="; + · ───────────────┬─────────────── + · ╰── invalid name `url=` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/func-results-not-present.wac.result b/crates/wac-parser/tests/resolution/fail/func-results-not-present.wac.result index f6c1478..80f5423 100644 --- a/crates/wac-parser/tests/resolution/fail/func-results-not-present.wac.result +++ b/crates/wac-parser/tests/resolution/fail/func-results-not-present.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/func-results-not-present.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function with results, found function without results \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function with results, found function without results + ╭─[tests/resolution/fail/func-results-not-present.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/func-results-present.wac.result b/crates/wac-parser/tests/resolution/fail/func-results-present.wac.result index 2d10fe5..9d0b2a5 100644 --- a/crates/wac-parser/tests/resolution/fail/func-results-present.wac.result +++ b/crates/wac-parser/tests/resolution/fail/func-results-present.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/func-results-present.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function without results, found function with results \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function without results, found function with results + ╭─[tests/resolution/fail/func-results-present.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/implicit-arg-conflict.wac.result b/crates/wac-parser/tests/resolution/fail/implicit-arg-conflict.wac.result index 4ba9917..57f0f4f 100644 --- a/crates/wac-parser/tests/resolution/fail/implicit-arg-conflict.wac.result +++ b/crates/wac-parser/tests/resolution/fail/implicit-arg-conflict.wac.result @@ -1,5 +1,13 @@ -implicit instantiation argument `foo` (function) conflicts with an explicit import at tests/resolution/fail/implicit-arg-conflict.wac:3:8 - --> tests/resolution/fail/implicit-arg-conflict.wac:5:13 - | - 5 | let x = new foo:bar { ... }; - | ^-----^ +failed to resolve document + + × implicit instantiation argument `foo` (function) conflicts with an explicit import + ╭─[tests/resolution/fail/implicit-arg-conflict.wac:5:13] + 2 │ + 3 │ import foo: func(); + · ─┬─ + · ╰── explicit import here + 4 │ + 5 │ let x = new foo:bar { ... }; + · ───┬─── + · ╰── conflicting instantiation here + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/import-conflict.wac.result b/crates/wac-parser/tests/resolution/fail/import-conflict.wac.result index da6060b..b8f654c 100644 --- a/crates/wac-parser/tests/resolution/fail/import-conflict.wac.result +++ b/crates/wac-parser/tests/resolution/fail/import-conflict.wac.result @@ -1,5 +1,13 @@ -import name `foo` conflicts with an instance that was implicitly imported by the instantiation of `foo:bar` at tests/resolution/fail/import-conflict.wac:3:13 - --> tests/resolution/fail/import-conflict.wac:5:8 - | - 5 | import foo: func(); - | ^-^ +failed to resolve document + + × import name `foo` conflicts with an instance that was implicitly imported by an instantiation of `foo:bar` + ╭─[tests/resolution/fail/import-conflict.wac:5:8] + 2 │ + 3 │ let x = new foo:bar { ... }; + · ───┬─── + · ╰── previous instantiation here + 4 │ + 5 │ import foo: func(); + · ─┬─ + · ╰── conflicting import here + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/import-duplicate-name.wac.result b/crates/wac-parser/tests/resolution/fail/import-duplicate-name.wac.result index 7c16990..4174359 100644 --- a/crates/wac-parser/tests/resolution/fail/import-duplicate-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/import-duplicate-name.wac.result @@ -1,5 +1,12 @@ -duplicate import `foo` - --> tests/resolution/fail/import-duplicate-name.wac:4:15 - | - 4 | import y with "foo": interface {}; - | ^---^ +failed to resolve document + + × duplicate import `foo` + ╭─[tests/resolution/fail/import-duplicate-name.wac:4:15] + 2 │ + 3 │ import x with "foo": func(); + · ──┬── + · ╰── previous import here + 4 │ import y with "foo": interface {}; + · ──┬── + · ╰── duplicate import name `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/import-invalid-name.wac.result b/crates/wac-parser/tests/resolution/fail/import-invalid-name.wac.result index e581f79..d0c9e6a 100644 --- a/crates/wac-parser/tests/resolution/fail/import-invalid-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/import-invalid-name.wac.result @@ -1,8 +1,10 @@ -import name `NOT-VALID-NAME!` is not valid - --> tests/resolution/fail/import-invalid-name.wac:3:15 - | - 3 | import x with "NOT-VALID-NAME!": func(); - | ^---------------^ +failed to resolve document -Caused by: - `NOT-VALID-NAME!` is not in kebab case \ No newline at end of file + × import name `NOT-VALID-NAME!` is not valid + ╰─▶ `NOT-VALID-NAME!` is not in kebab case + ╭─[tests/resolution/fail/import-invalid-name.wac:3:15] + 2 │ + 3 │ import x with "NOT-VALID-NAME!": func(); + · ────────┬──────── + · ╰── invalid name `NOT-VALID-NAME!` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/inaccessible.wac.result b/crates/wac-parser/tests/resolution/fail/inaccessible.wac.result index 5cdb005..c185c84 100644 --- a/crates/wac-parser/tests/resolution/fail/inaccessible.wac.result +++ b/crates/wac-parser/tests/resolution/fail/inaccessible.wac.result @@ -1,5 +1,9 @@ -a function cannot be accessed - --> tests/resolution/fail/inaccessible.wac:5:10 - | - 5 | let x = f.foo; - | ^--^ +failed to resolve document + + × a function cannot be accessed + ╭─[tests/resolution/fail/inaccessible.wac:5:10] + 4 │ + 5 │ let x = f.foo; + · ──┬─ + · ╰── a function cannot be accessed + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-alias.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-alias.wac.result index b8e8707..9504986 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-alias.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-alias.wac.result @@ -1,5 +1,9 @@ -`a` (interface) cannot be used in a type alias - --> tests/resolution/fail/invalid-alias.wac:7:10 - | - 7 | type x = a; - | ^ +failed to resolve document + + × `a` (interface) cannot be used in a type alias + ╭─[tests/resolution/fail/invalid-alias.wac:7:10] + 6 │ + 7 │ type x = a; + · ┬ + · ╰── `a` cannot be aliased + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-borrow.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-borrow.wac.result index 7afa4ef..6e58ab2 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-borrow.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-borrow.wac.result @@ -1,5 +1,9 @@ -`x` (u32) is not a resource type - --> tests/resolution/fail/invalid-borrow.wac:5:17 - | - 5 | type y = borrow; - | ^ +failed to resolve document + + × `x` (u32) is not a resource type + ╭─[tests/resolution/fail/invalid-borrow.wac:5:17] + 4 │ + 5 │ type y = borrow; + · ┬ + · ╰── `x` is not a resource type + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-func-type-ref.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-func-type-ref.wac.result index d97cbeb..2e33eb8 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-func-type-ref.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-func-type-ref.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not a function type - --> tests/resolution/fail/invalid-func-type-ref.wac:6:8 - | - 6 | x: x; - | ^ +failed to resolve document + + × `x` (u32) is not a function type + ╭─[tests/resolution/fail/invalid-func-type-ref.wac:6:8] + 5 │ + 6 │ x: x; + · ┬ + · ╰── `x` is not a function type + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-use-alias.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-use-alias.wac.result index fccb432..634f7f3 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-use-alias.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-use-alias.wac.result @@ -1,5 +1,10 @@ -use of type `b` conflicts with an export of the same name - --> tests/resolution/fail/invalid-use-alias.wac:9:17 - | - 9 | use a.{a as b}; - | ^ +failed to resolve document + + × use of type `b` conflicts with an export of the same name + ╭─[tests/resolution/fail/invalid-use-alias.wac:9:17] + 8 │ type b = u32; + 9 │ use a.{a as b}; + · ┬ + · ╰── conflicting name `b` + 10 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-use.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-use.wac.result index cfafb63..39d55cd 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-use.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-use.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not an interface - --> tests/resolution/fail/invalid-use.wac:6:9 - | - 6 | use x.{a}; - | ^ +failed to resolve document + + × `x` (u32) is not an interface + ╭─[tests/resolution/fail/invalid-use.wac:6:9] + 5 │ interface a { + 6 │ use x.{a}; + · ┬ + · ╰── `x` is not an interface + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-value-type.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-value-type.wac.result index ae6aad9..368e139 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-value-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-value-type.wac.result @@ -1,5 +1,9 @@ -`i` (interface) cannot be used as a value type - --> tests/resolution/fail/invalid-value-type.wac:7:18 - | - 7 | type x = func(i: i); - | ^ +failed to resolve document + + × `i` (interface) cannot be used as a value type + ╭─[tests/resolution/fail/invalid-value-type.wac:7:18] + 6 │ + 7 │ type x = func(i: i); + · ┬ + · ╰── `i` not a value type + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-world-export.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-world-export.wac.result index 93770c9..7d05ffa 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-world-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-world-export.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not a function type or interface - --> tests/resolution/fail/invalid-world-export.wac:6:15 - | - 6 | import x: x; - | ^ +failed to resolve document + + × `x` (u32) is not a function type or interface + ╭─[tests/resolution/fail/invalid-world-export.wac:6:15] + 5 │ world w { + 6 │ import x: x; + · ┬ + · ╰── `x` is not a function type or interface + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-world-import.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-world-import.wac.result index 6c17fda..95489ef 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-world-import.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-world-import.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not a function type or interface - --> tests/resolution/fail/invalid-world-import.wac:6:15 - | - 6 | import x: x; - | ^ +failed to resolve document + + × `x` (u32) is not a function type or interface + ╭─[tests/resolution/fail/invalid-world-import.wac:6:15] + 5 │ world w { + 6 │ import x: x; + · ┬ + · ╰── `x` is not a function type or interface + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-world-include.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-world-include.wac.result index 53c4f37..fc71937 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-world-include.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-world-include.wac.result @@ -1,5 +1,10 @@ -`x` (function type) is not a world - --> tests/resolution/fail/invalid-world-include.wac:6:13 - | - 6 | include x; - | ^ +failed to resolve document + + × `x` (function type) is not a world + ╭─[tests/resolution/fail/invalid-world-include.wac:6:13] + 5 │ world w { + 6 │ include x; + · ┬ + · ╰── `x` is not a world + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-world-interface-export.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-world-interface-export.wac.result index 2b5922c..68d110a 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-world-interface-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-world-interface-export.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not an interface - --> tests/resolution/fail/invalid-world-interface-export.wac:6:12 - | - 6 | export x; - | ^ +failed to resolve document + + × `x` (u32) is not an interface + ╭─[tests/resolution/fail/invalid-world-interface-export.wac:6:12] + 5 │ world w { + 6 │ export x; + · ┬ + · ╰── `x` is not an interface + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/invalid-world-interface-import.wac.result b/crates/wac-parser/tests/resolution/fail/invalid-world-interface-import.wac.result index a402633..b066888 100644 --- a/crates/wac-parser/tests/resolution/fail/invalid-world-interface-import.wac.result +++ b/crates/wac-parser/tests/resolution/fail/invalid-world-interface-import.wac.result @@ -1,5 +1,10 @@ -`x` (u32) is not an interface - --> tests/resolution/fail/invalid-world-interface-import.wac:6:12 - | - 6 | import x; - | ^ +failed to resolve document + + × `x` (u32) is not an interface + ╭─[tests/resolution/fail/invalid-world-interface-import.wac:6:12] + 5 │ world w { + 6 │ import x; + · ┬ + · ╰── `x` is not an interface + 7 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-enum-cases.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-enum-cases.wac.result index 5b7404a..187f7b7 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-enum-cases.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-enum-cases.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-enum-cases.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `e` - 1: expected enum case 1 to be named `b`, found an enum case named `c` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `e` + ╰─▶ expected enum case 1 to be named `b`, found an enum case named `c` + ╭─[tests/resolution/fail/mismatched-enum-cases.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-enum-count.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-enum-count.wac.result index f6a04fc..e182186 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-enum-count.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-enum-count.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-enum-count.wac:12:23 - | - 12 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `e` - 1: expected an enum type case count of 3, found a count of 4 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `e` + ╰─▶ expected an enum type case count of 3, found a count of 4 + ╭─[tests/resolution/fail/mismatched-enum-count.wac:12:23] + 11 │ + 12 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-err-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-err-result-type.wac.result index 8c0c99a..ca2d5e9 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-err-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-err-result-type.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-err-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: mismatched type for result `err` - 3: expected u8, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ├─▶ mismatched type for result `err` + ╰─▶ expected u8, found string + ╭─[tests/resolution/fail/mismatched-err-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-flags-count.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-flags-count.wac.result index a8e41ba..130c0f8 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-flags-count.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-flags-count.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-flags-count.wac:12:23 - | - 12 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected a flags type flag count of 3, found a count of 4 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected a flags type flag count of 3, found a count of 4 + ╭─[tests/resolution/fail/mismatched-flags-count.wac:12:23] + 11 │ + 12 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-flags.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-flags.wac.result index 0e66126..5097a56 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-flags.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-flags.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-flags.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected flag 1 to be named `b`, found a flag named `c` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected flag 1 to be named `b`, found a flag named `c` + ╭─[tests/resolution/fail/mismatched-flags.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-param-name.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-param-name.wac.result index 2d965aa..0bc8bfc 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-param-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-param-name.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-param-name.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function parameter 0 to be named `a`, found name `b` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function parameter 0 to be named `a`, found name `b` + ╭─[tests/resolution/fail/mismatched-func-param-name.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-param-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-param-type.wac.result index d44f4d8..d261863 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-param-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-param-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-param-type.wac:8:23 - | - 8 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function parameter `r` - 2: expected borrow, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function parameter `r` + ╰─▶ expected borrow, found string + ╭─[tests/resolution/fail/mismatched-func-param-type.wac:8:23] + 7 │ + 8 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-params.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-params.wac.result index 6debf64..a9d170a 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-params.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-params.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-params.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function with parameter count 1, found parameter count 0 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function with parameter count 1, found parameter count 0 + ╭─[tests/resolution/fail/mismatched-func-params.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-result-name.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-result-name.wac.result index 050441e..f63006e 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-result-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-result-name.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-result-name.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: expected function result 1 to be named `b`, found name `c` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ╰─▶ expected function result 1 to be named `b`, found name `c` + ╭─[tests/resolution/fail/mismatched-func-result-name.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-result-type.wac.result index 2c288b2..1fd6527 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-result-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result `b` - 2: expected u32, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result `b` + ╰─▶ expected u32, found string + ╭─[tests/resolution/fail/mismatched-func-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-func-scalar-result.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-func-scalar-result.wac.result index c82ea23..1603fdf 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-func-scalar-result.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-func-scalar-result.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-func-scalar-result.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: expected u8, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ╰─▶ expected u8, found string + ╭─[tests/resolution/fail/mismatched-func-scalar-result.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-kind.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-kind.wac.result index f078616..dee15e6 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-kind.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-kind.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-kind.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `x` - 1: expected function, found u32 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `x` + ╰─▶ expected function, found u32 + ╭─[tests/resolution/fail/mismatched-kind.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-list-element.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-list-element.wac.result index ea18522..5b9ee6e 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-list-element.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-list-element.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-list-element.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function parameter `l` - 2: mismatched type for list element - 3: expected u8, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function parameter `l` + ├─▶ mismatched type for list element + ╰─▶ expected u8, found string + ╭─[tests/resolution/fail/mismatched-list-element.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-ok-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-ok-result-type.wac.result index ccb1df1..9f5d999 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-ok-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-ok-result-type.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-ok-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: mismatched type for result `ok` - 3: expected u8, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ├─▶ mismatched type for result `ok` + ╰─▶ expected u8, found string + ╭─[tests/resolution/fail/mismatched-ok-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-option.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-option.wac.result index 262dc55..c28cb83 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-option.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-option.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-option.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function parameter `o` - 2: mismatched type for option - 3: expected string, found u8 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function parameter `o` + ├─▶ mismatched type for option + ╰─▶ expected string, found u8 + ╭─[tests/resolution/fail/mismatched-option.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-count.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-count.wac.result index 7435eba..ecaa0f8 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-count.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-count.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-record-field-count.wac:12:23 - | - 12 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `r` - 1: expected a record field count of 3, found a count of 4 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `r` + ╰─▶ expected a record field count of 3, found a count of 4 + ╭─[tests/resolution/fail/mismatched-record-field-count.wac:12:23] + 11 │ + 12 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-name.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-name.wac.result index b22678a..464d4f6 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-name.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-record-field-name.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `r` - 1: expected record field 1 to be named `b`, found a field named `c` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `r` + ╰─▶ expected record field 1 to be named `b`, found a field named `c` + ╭─[tests/resolution/fail/mismatched-record-field-name.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-type.wac.result index fe34baa..956bdf5 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-record-field-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-record-field-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-record-field-type.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `r` - 1: mismatched type for record field `b` - 2: expected u16, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `r` + ├─▶ mismatched type for record field `b` + ╰─▶ expected u16, found string + ╭─[tests/resolution/fail/mismatched-record-field-type.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-resource-types.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-resource-types.wac.result index 14f0cd2..b641c2b 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-resource-types.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-resource-types.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-resource-types.wac:9:23 - | - 9 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function parameter `x` - 2: expected resource `x`, found resource `y` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function parameter `x` + ╰─▶ expected resource `x`, found resource `y` + ╭─[tests/resolution/fail/mismatched-resource-types.wac:9:23] + 8 │ + 9 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-tuple-size.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-tuple-size.wac.result index 247357f..3ebb488 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-tuple-size.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-tuple-size.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-tuple-size.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `t` - 1: expected a tuple of size 3, found a tuple of size 4 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `t` + ╰─▶ expected a tuple of size 3, found a tuple of size 4 + ╭─[tests/resolution/fail/mismatched-tuple-size.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-tuple-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-tuple-type.wac.result index 3a6907f..a6177f7 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-tuple-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-tuple-type.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-tuple-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `t` - 1: mismatched type for tuple item 2 - 2: mismatched type for tuple item 0 - 3: expected u32, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `t` + ├─▶ mismatched type for tuple item 2 + ├─▶ mismatched type for tuple item 0 + ╰─▶ expected u32, found string + ╭─[tests/resolution/fail/mismatched-tuple-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-count.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-count.wac.result index 457ec06..d3450d5 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-count.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-count.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-variant-case-count.wac:12:23 - | - 12 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `v` - 1: expected a variant case count of 3, found a count of 4 \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `v` + ╰─▶ expected a variant case count of 3, found a count of 4 + ╭─[tests/resolution/fail/mismatched-variant-case-count.wac:12:23] + 11 │ + 12 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-name.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-name.wac.result index 5f6ca08..8ad6f60 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-name.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-variant-case-name.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `v` - 1: expected variant case 1 to be named `b`, found a case named `c` \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `v` + ╰─▶ expected variant case 1 to be named `b`, found a case named `c` + ╭─[tests/resolution/fail/mismatched-variant-case-name.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-type.wac.result b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-type.wac.result index 120f0d8..18fbb1f 100644 --- a/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/mismatched-variant-case-type.wac.result @@ -1,11 +1,13 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/mismatched-variant-case-type.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `v` - 1: mismatched type for variant case `c` - 2: mismatched type for tuple item 1 - 3: expected u16, found string \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `v` + ├─▶ mismatched type for variant case `c` + ├─▶ mismatched type for tuple item 1 + ╰─▶ expected u16, found string + ╭─[tests/resolution/fail/mismatched-variant-case-type.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-access-export.wac.result b/crates/wac-parser/tests/resolution/fail/missing-access-export.wac.result index 09b3ebf..bc554a8 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-access-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-access-export.wac.result @@ -1,5 +1,9 @@ -the instance has no export named `foo` - --> tests/resolution/fail/missing-access-export.wac:7:10 - | - 7 | let x = i.foo; - | ^--^ +failed to resolve document + + × the instance has no export named `foo` + ╭─[tests/resolution/fail/missing-access-export.wac:7:10] + 6 │ + 7 │ let x = i.foo; + · ──┬─ + · ╰── unknown export `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-constructor.wac.result b/crates/wac-parser/tests/resolution/fail/missing-constructor.wac.result index 68852d1..e9500af 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-constructor.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-constructor.wac.result @@ -1,8 +1,10 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-constructor.wac:8:23 - | - 8 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - instance is missing expected export `[constructor]r` \ No newline at end of file + × mismatched instantiation argument `x` + ╰─▶ instance is missing expected export `[constructor]r` + ╭─[tests/resolution/fail/missing-constructor.wac:8:23] + 7 │ + 8 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-err-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/missing-err-result-type.wac.result index 0d8ee68..0af4a95 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-err-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-err-result-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-err-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: expected an `err` for result type \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ╰─▶ expected an `err` for result type + ╭─[tests/resolution/fail/missing-err-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-inst-arg.wac.result b/crates/wac-parser/tests/resolution/fail/missing-inst-arg.wac.result index ec577e5..42903b5 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-inst-arg.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-inst-arg.wac.result @@ -1,5 +1,9 @@ -missing instantiation argument `foo` for package `foo:bar` - --> tests/resolution/fail/missing-inst-arg.wac:3:13 - | - 3 | let x = new foo:bar {}; - | ^-----^ +failed to resolve document + + × missing instantiation argument `foo` for package `foo:bar` + ╭─[tests/resolution/fail/missing-inst-arg.wac:3:13] + 2 │ + 3 │ let x = new foo:bar {}; + · ───┬─── + · ╰── missing argument `foo` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-interface-export.wac.result b/crates/wac-parser/tests/resolution/fail/missing-interface-export.wac.result index 9467824..ba6ca9d 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-interface-export.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-interface-export.wac.result @@ -1,8 +1,10 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-interface-export.wac:6:23 - | - 6 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - instance is missing expected export `f` \ No newline at end of file + × mismatched instantiation argument `x` + ╰─▶ instance is missing expected export `f` + ╭─[tests/resolution/fail/missing-interface-export.wac:6:23] + 5 │ + 6 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-method.wac.result b/crates/wac-parser/tests/resolution/fail/missing-method.wac.result index 8b538ab..4de188a 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-method.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-method.wac.result @@ -1,8 +1,10 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-method.wac:8:23 - | - 8 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - instance is missing expected export `[method]r.foo` \ No newline at end of file + × mismatched instantiation argument `x` + ╰─▶ instance is missing expected export `[method]r.foo` + ╭─[tests/resolution/fail/missing-method.wac:8:23] + 7 │ + 8 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-ok-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/missing-ok-result-type.wac.result index f6d7570..527a839 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-ok-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-ok-result-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-ok-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: expected an `ok` for result type \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ╰─▶ expected an `ok` for result type + ╭─[tests/resolution/fail/missing-ok-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-static-method.wac.result b/crates/wac-parser/tests/resolution/fail/missing-static-method.wac.result index 7fbfc3b..eaf2f0d 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-static-method.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-static-method.wac.result @@ -1,8 +1,10 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/missing-static-method.wac:8:23 - | - 8 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - instance is missing expected export `[static]r.foo` \ No newline at end of file + × mismatched instantiation argument `x` + ╰─▶ instance is missing expected export `[static]r.foo` + ╭─[tests/resolution/fail/missing-static-method.wac:8:23] + 7 │ + 8 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-type-in-use.wac.result b/crates/wac-parser/tests/resolution/fail/missing-type-in-use.wac.result index 98ef317..06cb848 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-type-in-use.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-type-in-use.wac.result @@ -1,5 +1,10 @@ -type `x` is not defined in interface `a` - --> tests/resolution/fail/missing-type-in-use.wac:8:12 - | - 8 | use a.{x}; - | ^ +failed to resolve document + + × a type named `x` is not defined in interface `a` + ╭─[tests/resolution/fail/missing-type-in-use.wac:8:12] + 7 │ interface b { + 8 │ use a.{x}; + · ┬ + · ╰── `x` is not a type in interface `a` + 9 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/missing-world-include-name.wac.result b/crates/wac-parser/tests/resolution/fail/missing-world-include-name.wac.result index 1aa2ddc..4ba4b12 100644 --- a/crates/wac-parser/tests/resolution/fail/missing-world-include-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/missing-world-include-name.wac.result @@ -1,5 +1,10 @@ -world `w1` does not have an import or export named `a` - --> tests/resolution/fail/missing-world-include-name.wac:8:23 - | - 8 | include w1 with { a as b }; - | ^ +failed to resolve document + + × world `w1` does not have an import or export named `a` + ╭─[tests/resolution/fail/missing-world-include-name.wac:8:23] + 7 │ world w2 { + 8 │ include w1 with { a as b }; + · ┬ + · ╰── no import or export named `a` + 9 │ } + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/no-err-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/no-err-result-type.wac.result index 3c6c7ae..bad8035 100644 --- a/crates/wac-parser/tests/resolution/fail/no-err-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/no-err-result-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/no-err-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: expected no `err` for result type \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ╰─▶ expected no `err` for result type + ╭─[tests/resolution/fail/no-err-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/no-import.wac.result b/crates/wac-parser/tests/resolution/fail/no-import.wac.result index c57fbe7..261edf7 100644 --- a/crates/wac-parser/tests/resolution/fail/no-import.wac.result +++ b/crates/wac-parser/tests/resolution/fail/no-import.wac.result @@ -1,5 +1,9 @@ -component `foo:bar` has no import named `x` - --> tests/resolution/fail/no-import.wac:4:23 - | - 4 | let i = new foo:bar { x }; - | ^ +failed to resolve document + + × component `foo:bar` has no import named `x` + ╭─[tests/resolution/fail/no-import.wac:4:23] + 3 │ import x: interface {}; + 4 │ let i = new foo:bar { x }; + · ┬ + · ╰── unknown import `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/no-ok-result-type.wac.result b/crates/wac-parser/tests/resolution/fail/no-ok-result-type.wac.result index 4692bef..de644e7 100644 --- a/crates/wac-parser/tests/resolution/fail/no-ok-result-type.wac.result +++ b/crates/wac-parser/tests/resolution/fail/no-ok-result-type.wac.result @@ -1,10 +1,12 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/no-ok-result-type.wac:7:23 - | - 7 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `f` - 1: mismatched type for function result - 2: expected no `ok` for result type \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `f` + ├─▶ mismatched type for function result + ╰─▶ expected no `ok` for result type + ╭─[tests/resolution/fail/no-ok-result-type.wac:7:23] + 6 │ + 7 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/package-invalid-wasm.wac.result b/crates/wac-parser/tests/resolution/fail/package-invalid-wasm.wac.result index acee35d..07f28cf 100644 --- a/crates/wac-parser/tests/resolution/fail/package-invalid-wasm.wac.result +++ b/crates/wac-parser/tests/resolution/fail/package-invalid-wasm.wac.result @@ -1,8 +1,10 @@ -failed to parse package `foo:bar` - --> tests/resolution/fail/package-invalid-wasm.wac:3:13 - | - 3 | import foo: foo:bar/qux; - | ^-----^ +failed to resolve document -Caused by: - unknown type 0: type index out of bounds (at offset 0xb) \ No newline at end of file + × failed to parse package `foo:bar` + ╰─▶ unknown type 0: type index out of bounds (at offset 0xb) + ╭─[tests/resolution/fail/package-invalid-wasm.wac:3:13] + 2 │ + 3 │ import foo: foo:bar/qux; + · ───┬─── + · ╰── package `foo:bar` failed to parse + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/package-not-component.wac.result b/crates/wac-parser/tests/resolution/fail/package-not-component.wac.result index 4b6bb75..704f57a 100644 --- a/crates/wac-parser/tests/resolution/fail/package-not-component.wac.result +++ b/crates/wac-parser/tests/resolution/fail/package-not-component.wac.result @@ -1,8 +1,10 @@ -failed to parse package `foo:bar` - --> tests/resolution/fail/package-not-component.wac:3:13 - | - 3 | import foo: foo:bar/qux; - | ^-----^ +failed to resolve document -Caused by: - input is not a WebAssembly component \ No newline at end of file + × failed to parse package `foo:bar` + ╰─▶ input is not a WebAssembly component + ╭─[tests/resolution/fail/package-not-component.wac:3:13] + 2 │ + 3 │ import foo: foo:bar/qux; + · ───┬─── + · ╰── package `foo:bar` failed to parse + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/package-not-wasm.wac.result b/crates/wac-parser/tests/resolution/fail/package-not-wasm.wac.result index f398f8e..924be6c 100644 --- a/crates/wac-parser/tests/resolution/fail/package-not-wasm.wac.result +++ b/crates/wac-parser/tests/resolution/fail/package-not-wasm.wac.result @@ -1,8 +1,10 @@ -failed to parse package `foo:bar` - --> tests/resolution/fail/package-not-wasm.wac:3:13 - | - 3 | import foo: foo:bar/qux; - | ^-----^ +failed to resolve document -Caused by: - magic header not detected: bad magic number (at offset 0x0) \ No newline at end of file + × failed to parse package `foo:bar` + ╰─▶ magic header not detected: bad magic number (at offset 0x0) + ╭─[tests/resolution/fail/package-not-wasm.wac:3:13] + 2 │ + 3 │ import foo: foo:bar/qux; + · ───┬─── + · ╰── package `foo:bar` failed to parse + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/redefined-name.wac.result b/crates/wac-parser/tests/resolution/fail/redefined-name.wac.result index 8aaeefd..15e7778 100644 --- a/crates/wac-parser/tests/resolution/fail/redefined-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/redefined-name.wac.result @@ -1,5 +1,12 @@ -`x` was previously defined at tests/resolution/fail/redefined-name.wac:3:6 - --> tests/resolution/fail/redefined-name.wac:4:6 - | - 4 | type x = string; - | ^ +failed to resolve document + + × `x` is already defined + ╭─[tests/resolution/fail/redefined-name.wac:4:6] + 2 │ + 3 │ type x = u32; + · ┬ + · ╰── `x` previously defined here + 4 │ type x = string; + · ┬ + · ╰── `x` redefined here + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/self-instantiation.wac.result b/crates/wac-parser/tests/resolution/fail/self-instantiation.wac.result index db97185..4397078 100644 --- a/crates/wac-parser/tests/resolution/fail/self-instantiation.wac.result +++ b/crates/wac-parser/tests/resolution/fail/self-instantiation.wac.result @@ -1,5 +1,9 @@ -cannot instantiate the package being defined - --> tests/resolution/fail/self-instantiation.wac:3:13 - | - 3 | let i = new foo:bar {}; - | ^-----^ +failed to resolve document + + × cannot instantiate the package being defined + ╭─[tests/resolution/fail/self-instantiation.wac:3:13] + 2 │ + 3 │ let i = new foo:bar {}; + · ───┬─── + · ╰── cannot instantiate self + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/undefined-name.wac.result b/crates/wac-parser/tests/resolution/fail/undefined-name.wac.result index 55dca04..5721f74 100644 --- a/crates/wac-parser/tests/resolution/fail/undefined-name.wac.result +++ b/crates/wac-parser/tests/resolution/fail/undefined-name.wac.result @@ -1,5 +1,9 @@ -undefined name `x` - --> tests/resolution/fail/undefined-name.wac:3:10 - | - 3 | type x = x; - | ^ +failed to resolve document + + × undefined name `x` + ╭─[tests/resolution/fail/undefined-name.wac:3:10] + 2 │ + 3 │ type x = x; + · ┬ + · ╰── undefined name `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/unknown-package.wac.result b/crates/wac-parser/tests/resolution/fail/unknown-package.wac.result index 8f16d0d..8e011d3 100644 --- a/crates/wac-parser/tests/resolution/fail/unknown-package.wac.result +++ b/crates/wac-parser/tests/resolution/fail/unknown-package.wac.result @@ -1,5 +1,9 @@ -unknown package `bar:baz` - --> tests/resolution/fail/unknown-package.wac:3:13 - | - 3 | import foo: bar:baz/qux; - | ^-----^ +failed to resolve document + + × unknown package `bar:baz` + ╭─[tests/resolution/fail/unknown-package.wac:3:13] + 2 │ + 3 │ import foo: bar:baz/qux; + · ───┬─── + · ╰── unknown package `bar:baz` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/unmergeable-args.wac.result b/crates/wac-parser/tests/resolution/fail/unmergeable-args.wac.result index dc536d1..4d47767 100644 --- a/crates/wac-parser/tests/resolution/fail/unmergeable-args.wac.result +++ b/crates/wac-parser/tests/resolution/fail/unmergeable-args.wac.result @@ -1,5 +1,12 @@ -implicit instantiation argument `foo` (function) conflicts with an implicitly imported argument from the instantiation of `bar:baz` at tests/resolution/fail/unmergeable-args.wac:3:13 - --> tests/resolution/fail/unmergeable-args.wac:4:13 - | - 4 | let b = new foo:bar { ... }; - | ^-----^ +failed to resolve document + + × implicit instantiation argument `foo` (function) conflicts with an implicitly imported argument from the instantiation of `bar:baz` + ╭─[tests/resolution/fail/unmergeable-args.wac:4:13] + 2 │ + 3 │ let a = new bar:baz { ... }; + · ───┬─── + · ╰── previous instantiation here + 4 │ let b = new foo:bar { ... }; + · ───┬─── + · ╰── conflicting instantiation here + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/variant-case-typed.wac.result b/crates/wac-parser/tests/resolution/fail/variant-case-typed.wac.result index 4f4213d..b5e07a8 100644 --- a/crates/wac-parser/tests/resolution/fail/variant-case-typed.wac.result +++ b/crates/wac-parser/tests/resolution/fail/variant-case-typed.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/variant-case-typed.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `v` - 1: expected variant case `b` to be typed, found an untyped case \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `v` + ╰─▶ expected variant case `b` to be typed, found an untyped case + ╭─[tests/resolution/fail/variant-case-typed.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/variant-case-untyped.wac.result b/crates/wac-parser/tests/resolution/fail/variant-case-untyped.wac.result index ea699f8..6289029 100644 --- a/crates/wac-parser/tests/resolution/fail/variant-case-untyped.wac.result +++ b/crates/wac-parser/tests/resolution/fail/variant-case-untyped.wac.result @@ -1,9 +1,11 @@ -mismatched instantiation argument `x` - --> tests/resolution/fail/variant-case-untyped.wac:11:23 - | - 11 | let i = new foo:bar { x }; - | ^ +failed to resolve document -Caused by: - 0: mismatched type for export `v` - 1: expected variant case `a` to be untyped, found a typed case \ No newline at end of file + × mismatched instantiation argument `x` + ├─▶ mismatched type for export `v` + ╰─▶ expected variant case `a` to be untyped, found a typed case + ╭─[tests/resolution/fail/variant-case-untyped.wac:11:23] + 10 │ + 11 │ let i = new foo:bar { x }; + · ┬ + · ╰── mismatched argument `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/windows-file.wac.result b/crates/wac-parser/tests/resolution/fail/windows-file.wac.result index 16ea9f9..df1b5d3 100644 --- a/crates/wac-parser/tests/resolution/fail/windows-file.wac.result +++ b/crates/wac-parser/tests/resolution/fail/windows-file.wac.result @@ -1,5 +1,12 @@ -duplicate import `x` - --> tests/resolution/fail/windows-file.wac:4:8 - | - 4 | import x: func(); - | ^ +failed to resolve document + + × duplicate import `x` + ╭─[tests/resolution/fail/windows-file.wac:4:8] + 2 │ + 3 │ import x: func(); + · ┬ + · ╰── previous import here + 4 │ import x: func(); + · ┬ + · ╰── duplicate import name `x` + ╰──── diff --git a/crates/wac-parser/tests/resolution/fail/world-include-conflict.wac.result b/crates/wac-parser/tests/resolution/fail/world-include-conflict.wac.result index 375874d..c0b4fd8 100644 --- a/crates/wac-parser/tests/resolution/fail/world-include-conflict.wac.result +++ b/crates/wac-parser/tests/resolution/fail/world-include-conflict.wac.result @@ -1,5 +1,11 @@ -export `a` from world `w1` conflicts with export of the same name in world `w2` (consider using a `with` clause to use a different name) - --> tests/resolution/fail/world-include-conflict.wac:8:13 - | - 8 | include w1; - | ^^ +failed to resolve document + + × export `a` from world `w1` conflicts with export of the same name in world `w2` + ╭─[tests/resolution/fail/world-include-conflict.wac:8:13] + 7 │ world w2 { + 8 │ include w1; + · ─┬ + · ╰── conflicting name `a` + 9 │ export a: interface { + ╰──── + help: consider using a `with` clause to use a different name diff --git a/crates/wac-parser/tests/resolution/fail/world-include-with-conflict.wac.result b/crates/wac-parser/tests/resolution/fail/world-include-with-conflict.wac.result index 86beef4..cdbad05 100644 --- a/crates/wac-parser/tests/resolution/fail/world-include-with-conflict.wac.result +++ b/crates/wac-parser/tests/resolution/fail/world-include-with-conflict.wac.result @@ -1,5 +1,10 @@ -export `x` from world `w1` conflicts with export of the same name in world `w2` - --> tests/resolution/fail/world-include-with-conflict.wac:8:28 - | - 8 | include w1 with { a as x }; - | ^ +failed to resolve document + + × export `x` from world `w1` conflicts with export of the same name in world `w2` + ╭─[tests/resolution/fail/world-include-with-conflict.wac:8:28] + 7 │ world w2 { + 8 │ include w1 with { a as x }; + · ┬ + · ╰── conflicting name `x` + 9 │ export x: interface { + ╰──── diff --git a/crates/wac-parser/tests/support/mod.rs b/crates/wac-parser/tests/support/mod.rs new file mode 100644 index 0000000..b99a3e0 --- /dev/null +++ b/crates/wac-parser/tests/support/mod.rs @@ -0,0 +1,17 @@ +use miette::{GraphicalReportHandler, GraphicalTheme, NamedSource, Report}; +use std::path::Path; + +pub fn fmt_err(e: impl Into, path: &Path, source: &str) -> String { + let mut s = String::new(); + let e = e.into(); + GraphicalReportHandler::new() + .with_cause_chain() + .with_theme(GraphicalTheme::unicode_nocolor()) + .render_report( + &mut s, + e.with_source_code(NamedSource::new(path.to_string_lossy(), source.to_string())) + .as_ref(), + ) + .expect("failed to render diagnostic"); + s +} diff --git a/src/commands/encode.rs b/src/commands/encode.rs index 7f8ac64..2395269 100644 --- a/src/commands/encode.rs +++ b/src/commands/encode.rs @@ -1,13 +1,12 @@ -use anyhow::{anyhow, bail, Context, Result}; +use crate::fmt_err; +use anyhow::{bail, Context, Result}; use clap::Args; use std::{ fs, io::{IsTerminal, Write}, path::PathBuf, }; -use wac_parser::{ - ast::Document, Composition, EncodingOptions, ErrorFormatter, FileSystemPackageResolver, -}; +use wac_parser::{ast::Document, Composition, EncodingOptions, FileSystemPackageResolver}; use wasmparser::{Validator, WasmFeatures}; use wasmprinter::print_bytes; @@ -71,12 +70,7 @@ impl EncodeCommand { let contents = fs::read_to_string(&self.path) .with_context(|| format!("failed to read file `{path}`", path = self.path.display()))?; - let document = Document::parse(&contents, &self.path).map_err(|e| { - anyhow!( - "{e}", - e = ErrorFormatter::new(&self.path, e, std::io::stderr().is_terminal()) - ) - })?; + let document = Document::parse(&contents).map_err(|e| fmt_err(e, &self.path, &contents))?; let resolved = Composition::from_ast( &document, @@ -85,12 +79,7 @@ impl EncodeCommand { self.deps.into_iter().collect(), ))), ) - .map_err(|e| { - anyhow!( - "{e}", - e = ErrorFormatter::new(&self.path, e, std::io::stderr().is_terminal()) - ) - })?; + .map_err(|e| fmt_err(e, &self.path, &contents))?; if !self.wat && self.output.is_none() && std::io::stdout().is_terminal() { bail!("cannot print binary wasm output to a terminal; pass the `-t` flag to print the text format instead"); diff --git a/src/commands/parse.rs b/src/commands/parse.rs index aee4614..fa8690a 100644 --- a/src/commands/parse.rs +++ b/src/commands/parse.rs @@ -1,7 +1,8 @@ -use anyhow::{anyhow, Context, Result}; +use crate::fmt_err; +use anyhow::{Context, Result}; use clap::Args; -use std::{fs, io::IsTerminal, path::PathBuf}; -use wac_parser::{ast::Document, ErrorFormatter}; +use std::{fs, path::PathBuf}; +use wac_parser::ast::Document; /// Parses a composition into a JSON AST representation. #[derive(Args)] @@ -20,12 +21,7 @@ impl ParseCommand { let contents = fs::read_to_string(&self.path) .with_context(|| format!("failed to read file `{path}`", path = self.path.display()))?; - let document = Document::parse(&contents, &self.path).map_err(|e| { - anyhow!( - "{e}", - e = ErrorFormatter::new(&self.path, e, std::io::stderr().is_terminal()) - ) - })?; + let document = Document::parse(&contents).map_err(|e| fmt_err(e, &self.path, &contents))?; serde_json::to_writer_pretty(std::io::stdout(), &document)?; println!(); diff --git a/src/commands/resolve.rs b/src/commands/resolve.rs index f12e2bf..af55820 100644 --- a/src/commands/resolve.rs +++ b/src/commands/resolve.rs @@ -1,7 +1,8 @@ -use anyhow::{anyhow, Context, Result}; +use crate::fmt_err; +use anyhow::{Context, Result}; use clap::Args; -use std::{fs, io::IsTerminal, path::PathBuf}; -use wac_parser::{ast::Document, Composition, ErrorFormatter, FileSystemPackageResolver}; +use std::{fs, path::PathBuf}; +use wac_parser::{ast::Document, Composition, FileSystemPackageResolver}; fn parse(s: &str) -> Result<(T, U)> where @@ -43,12 +44,7 @@ impl ResolveCommand { let contents = fs::read_to_string(&self.path) .with_context(|| format!("failed to read file `{path}`", path = self.path.display()))?; - let document = Document::parse(&contents, &self.path).map_err(|e| { - anyhow!( - "{e}", - e = ErrorFormatter::new(&self.path, e, std::io::stderr().is_terminal()) - ) - })?; + let document = Document::parse(&contents).map_err(|e| fmt_err(e, &self.path, &contents))?; let resolved = Composition::from_ast( &document, @@ -57,12 +53,7 @@ impl ResolveCommand { self.deps.into_iter().collect(), ))), ) - .map_err(|e| { - anyhow!( - "{e}", - e = ErrorFormatter::new(&self.path, e, std::io::stderr().is_terminal()) - ) - })?; + .map_err(|e| fmt_err(e, &self.path, &contents))?; serde_json::to_writer_pretty(std::io::stdout(), &resolved)?; println!(); diff --git a/src/lib.rs b/src/lib.rs index bf5e806..48bfb1a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,4 +2,26 @@ #![deny(missing_docs)] +use miette::{GraphicalReportHandler, GraphicalTheme, NamedSource, Report}; +use std::{io::IsTerminal, path::Path}; + pub mod commands; + +fn fmt_err(e: impl Into, path: &Path, source: &str) -> anyhow::Error { + let mut s = String::new(); + let e = e.into(); + GraphicalReportHandler::new() + .with_cause_chain() + .with_theme(if std::io::stderr().is_terminal() { + GraphicalTheme::unicode() + } else { + GraphicalTheme::unicode_nocolor() + }) + .render_report( + &mut s, + e.with_source_code(NamedSource::new(path.to_string_lossy(), source.to_string())) + .as_ref(), + ) + .expect("failed to render diagnostic"); + anyhow::Error::msg(s) +}