1use crate::{
4 lexer::{self, Lexer, LexerResult, Token},
5 resolution::{AstResolver, Resolution, ResolutionResult},
6};
7use indexmap::IndexMap;
8use miette::{Diagnostic, SourceSpan};
9use serde::Serialize;
10use std::fmt;
11use wac_graph::types::BorrowedPackageKey;
12
13mod export;
14mod expr;
15mod import;
16mod r#let;
17mod printer;
18mod r#type;
19
20pub use export::*;
21pub use expr::*;
22pub use import::*;
23pub use printer::*;
24pub use r#let::*;
25pub use r#type::*;
26
27struct Found(Option<Token>);
28
29impl fmt::Display for Found {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 match self.0 {
32 Some(t) => t.fmt(f),
33 None => write!(f, "end of input"),
34 }
35 }
36}
37
38struct Expected<'a> {
39 expected: &'a [Option<Token>],
40 count: usize,
41}
42
43impl fmt::Display for Expected<'_> {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 let mut expected = self.expected.iter().enumerate();
46 while let Some((i, Some(token))) = expected.next() {
47 if i > 0 {
48 write!(f, ", ")?;
49 }
50
51 if i == self.count - 1 {
52 write!(f, "or ")?;
53 }
54
55 token.fmt(f)?;
56 }
57
58 if self.count > self.expected.len() {
59 write!(f, ", or more...")?;
60 }
61
62 Ok(())
63 }
64}
65
66#[derive(thiserror::Error, Diagnostic, Debug)]
68#[diagnostic(code("failed to parse document"))]
69pub enum Error {
70 #[error("{error}")]
72 Lexer {
73 error: crate::lexer::Error,
75 #[label(primary)]
77 span: SourceSpan,
78 },
79 #[error("expected {expected}, found {found}", found = Found(*.found))]
81 Expected {
82 expected: Token,
84 found: Option<Token>,
86 #[label(primary, "unexpected {found}", found = Found(*.found))]
88 span: SourceSpan,
89 },
90 #[error("expected {first} or {second}, found {found}", found = Found(*.found))]
92 ExpectedEither {
93 first: Token,
95 second: Token,
97 found: Option<Token>,
99 #[label(primary, "unexpected {found}", found = Found(*.found))]
101 span: SourceSpan,
102 },
103 #[error("expected either {expected}, found {found}", expected = Expected { expected, count: *.count }, found = Found(*.found))]
105 ExpectedMultiple {
106 expected: [Option<Token>; 10],
108 count: usize,
110 found: Option<Token>,
112 #[label(primary, "unexpected {found}", found = Found(*.found))]
114 span: SourceSpan,
115 },
116 #[error("{ty} must contain at least one {kind}")]
118 EmptyType {
119 ty: &'static str,
121 kind: &'static str,
123 #[label(primary, "empty {ty}")]
125 span: SourceSpan,
126 },
127 #[error("`{version}` is not a valid semantic version")]
129 InvalidVersion {
130 version: std::string::String,
132 #[label(primary, "invalid version")]
134 span: SourceSpan,
135 },
136}
137
138pub type ParseResult<T> = Result<T, Error>;
140
141impl From<(lexer::Error, SourceSpan)> for Error {
142 fn from((e, s): (lexer::Error, SourceSpan)) -> Self {
143 Self::Lexer { error: e, span: s }
144 }
145}
146
147pub fn parse_token(lexer: &mut Lexer, expected: Token) -> ParseResult<SourceSpan> {
149 let (result, span) = lexer.next().ok_or_else(|| Error::Expected {
150 expected,
151 found: None,
152 span: lexer.span(),
153 })?;
154
155 match result {
156 Ok(found) if found == expected => Ok(span),
157 Ok(found) => Err(Error::Expected {
158 expected,
159 found: Some(found),
160 span,
161 }),
162 Err(e) => Err((e, span).into()),
163 }
164}
165
166pub fn parse_optional<'a, F, R>(
170 lexer: &mut Lexer<'a>,
171 expected: Token,
172 cb: F,
173) -> ParseResult<Option<R>>
174where
175 F: FnOnce(&mut Lexer<'a>) -> ParseResult<R>,
176{
177 match lexer.peek() {
178 Some((Ok(token), _)) => {
179 if token == expected {
180 lexer.next();
181 Ok(Some(cb(lexer)?))
182 } else {
183 Ok(None)
184 }
185 }
186 Some((Err(e), s)) => Err((e, s).into()),
187 None => Ok(None),
188 }
189}
190
191pub fn parse_optional_payload<'a>(
194 lexer: &mut Lexer<'a>,
195 ctor: impl FnOnce(Option<Box<Type<'a>>>, SourceSpan) -> Type<'a>,
196) -> ParseResult<Type<'a>> {
197 let span = lexer.next().unwrap().1;
198 let ty = parse_optional(lexer, Token::OpenAngle, |lexer| {
199 let ty = Box::new(Parse::parse(lexer)?);
200 let close = parse_token(lexer, Token::CloseAngle)?;
201 Ok((ty, close))
202 })?;
203 Ok(match ty {
204 Some((ty, close)) => ctor(
205 Some(ty),
206 SourceSpan::new(
207 span.offset().into(),
208 (close.offset() + close.len()) - span.offset(),
209 ),
210 ),
211 None => ctor(None, span),
212 })
213}
214
215pub struct Lookahead {
219 next: Option<(LexerResult<Token>, SourceSpan)>,
220 attempts: [Option<Token>; 10],
221 span: SourceSpan,
222 count: usize,
223}
224
225impl Lookahead {
226 pub fn new(lexer: &Lexer) -> Self {
228 Self {
229 next: lexer.peek(),
230 span: lexer.span(),
231 attempts: Default::default(),
232 count: 0,
233 }
234 }
235
236 pub fn peek(&mut self, expected: Token) -> bool {
238 match &self.next {
239 Some((Ok(t), _)) if *t == expected => true,
240 _ => {
241 if self.count < self.attempts.len() {
242 self.attempts[self.count] = Some(expected);
243 }
244
245 self.count += 1;
246 false
247 }
248 }
249 }
250
251 pub fn error(self) -> Error {
255 let (found, span) = match self.next {
256 Some((Ok(token), span)) => (Some(token), span),
257 Some((Err(e), s)) => return (e, s).into(),
258 None => (None, self.span),
259 };
260
261 match self.count {
262 0 => unreachable!("lookahead had no attempts"),
263 1 => Error::Expected {
264 expected: self.attempts[0].unwrap(),
265 found,
266 span,
267 },
268 2 => Error::ExpectedEither {
269 first: self.attempts[0].unwrap(),
270 second: self.attempts[1].unwrap(),
271 found,
272 span,
273 },
274 _ => Error::ExpectedMultiple {
275 expected: self.attempts,
276 count: self.count,
277 found,
278 span,
279 },
280 }
281 }
282}
283
284pub(crate) trait Parse<'a>: Sized {
285 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self>;
286}
287
288trait Peek {
289 fn peek(lookahead: &mut Lookahead) -> bool;
290}
291
292fn parse_delimited<'a, T: Parse<'a> + Peek>(
293 lexer: &mut Lexer<'a>,
294 until: Token,
295 with_commas: bool,
296) -> ParseResult<Vec<T>> {
297 let mut items = Vec::new();
298 loop {
299 let mut lookahead = Lookahead::new(lexer);
300 if lookahead.peek(until) {
301 break;
302 }
303
304 if !T::peek(&mut lookahead) {
305 return Err(lookahead.error());
306 }
307
308 items.push(Parse::parse(lexer)?);
309
310 if let Some((Ok(next), _)) = lexer.peek() {
311 if next == until {
312 break;
313 }
314
315 if with_commas {
316 parse_token(lexer, Token::Comma)?;
317 }
318 }
319 }
320
321 Ok(items)
322}
323
324#[derive(Debug, Clone, Serialize)]
326#[serde(rename_all = "camelCase")]
327pub struct PackageDirective<'a> {
328 pub package: PackageName<'a>,
330 #[serde(skip_serializing_if = "Option::is_none")]
332 pub targets: Option<PackagePath<'a>>,
333}
334
335impl<'a> Parse<'a> for PackageDirective<'a> {
336 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
337 parse_token(lexer, Token::PackageKeyword)?;
338 let package = Parse::parse(lexer)?;
339 let targets = parse_optional(lexer, Token::TargetsKeyword, Parse::parse)?;
340 parse_token(lexer, Token::Semicolon)?;
341 Ok(Self { package, targets })
342 }
343}
344
345#[derive(Debug, Clone, Serialize)]
347#[serde(rename_all = "camelCase")]
348pub struct Document<'a> {
349 pub docs: Vec<DocComment<'a>>,
351 pub directive: PackageDirective<'a>,
353 pub statements: Vec<Statement<'a>>,
355}
356
357impl<'a> Document<'a> {
358 pub fn parse(source: &'a str) -> ParseResult<Self> {
362 let mut lexer = Lexer::new(source).map_err(Error::from)?;
363
364 let docs = Parse::parse(&mut lexer)?;
365 let directive = Parse::parse(&mut lexer)?;
366
367 let mut statements: Vec<Statement> = Default::default();
368 while lexer.peek().is_some() {
369 statements.push(Parse::parse(&mut lexer)?);
370 }
371
372 assert!(lexer.next().is_none(), "expected all tokens to be consumed");
373 Ok(Self {
374 docs,
375 directive,
376 statements,
377 })
378 }
379
380 pub fn resolve(
384 &self,
385 packages: IndexMap<BorrowedPackageKey<'a>, Vec<u8>>,
386 ) -> ResolutionResult<Resolution<'_>> {
387 AstResolver::new(self).resolve(packages)
388 }
389}
390
391#[derive(Debug, Clone, Serialize)]
393pub enum Statement<'a> {
394 Import(ImportStatement<'a>),
396 Type(TypeStatement<'a>),
398 Let(LetStatement<'a>),
400 Export(ExportStatement<'a>),
402}
403
404impl<'a> Parse<'a> for Statement<'a> {
405 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
406 let mut lookahead = Lookahead::new(lexer);
407 if ImportStatement::peek(&mut lookahead) {
408 Ok(Self::Import(Parse::parse(lexer)?))
409 } else if LetStatement::peek(&mut lookahead) {
410 Ok(Self::Let(Parse::parse(lexer)?))
411 } else if ExportStatement::peek(&mut lookahead) {
412 Ok(Self::Export(Parse::parse(lexer)?))
413 } else if TypeStatement::peek(&mut lookahead) {
414 Ok(Self::Type(Parse::parse(lexer)?))
415 } else {
416 Err(lookahead.error())
417 }
418 }
419}
420
421#[derive(Debug, Clone, Copy, Serialize)]
423#[serde(rename_all = "camelCase")]
424pub struct Ident<'a> {
425 pub string: &'a str,
427 pub span: SourceSpan,
429}
430
431impl<'a> Parse<'a> for Ident<'a> {
432 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
433 let span = parse_token(lexer, Token::Ident)?;
434 let id = lexer.source(span);
435 Ok(Self {
436 string: id.strip_prefix('%').unwrap_or(id),
437 span,
438 })
439 }
440}
441
442impl Peek for Ident<'_> {
443 fn peek(lookahead: &mut Lookahead) -> bool {
444 lookahead.peek(Token::Ident)
445 }
446}
447
448#[derive(Debug, Copy, Clone, Serialize)]
450#[serde(rename_all = "camelCase")]
451pub struct String<'a> {
452 pub value: &'a str,
454 pub span: SourceSpan,
456}
457
458impl<'a> Parse<'a> for String<'a> {
459 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Self> {
460 let span = parse_token(lexer, Token::String)?;
461 let s = lexer.source(span);
462 Ok(Self {
463 value: s.strip_prefix('"').unwrap().strip_suffix('"').unwrap(),
464 span,
465 })
466 }
467}
468
469impl Peek for String<'_> {
470 fn peek(lookahead: &mut Lookahead) -> bool {
471 lookahead.peek(Token::String)
472 }
473}
474
475#[derive(Debug, Clone, Serialize)]
477#[serde(rename_all = "camelCase")]
478pub struct DocComment<'a> {
479 pub comment: &'a str,
481 pub span: SourceSpan,
483}
484
485impl<'a> Parse<'a> for Vec<DocComment<'a>> {
486 fn parse(lexer: &mut Lexer<'a>) -> ParseResult<Vec<DocComment<'a>>> {
487 Ok(lexer
488 .comments()
489 .map_err(Error::from)?
490 .into_iter()
491 .map(|(comment, span)| DocComment { comment, span })
492 .collect())
493 }
494}
495
496#[cfg(test)]
497mod test {
498 use super::*;
499 use pretty_assertions::assert_eq;
500
501 pub(crate) fn roundtrip(source: &str, expected: &str) -> ParseResult<()> {
510 let doc = Document::parse(source)?;
511 let mut s = std::string::String::new();
512 DocumentPrinter::new(&mut s, source, None)
513 .document(&doc)
514 .unwrap();
515 assert_eq!(s, expected, "unexpected AST output");
516 Ok(())
517 }
518
519 #[test]
520 fn document_roundtrip() {
521 roundtrip(
522 r#"/* ignore me */
523/// Doc comment for the package!
524package test:foo:bar@1.0.0;
525/// Doc comment #1!
526import foo: foo:bar/baz;
527/// Doc comment #2!
528type a = u32;
529/// Doc comment #3!
530record r {
531 x: string
532}
533/// Doc comment #4!
534interface i {
535 /// Doc comment #5!
536 f: func() -> r;
537}
538/// Doc comment #6!
539world w {
540 /// Doc comment #7!
541 import i;
542 /// Doc comment #8!
543 export f: func() -> a;
544}
545/// Doc comment #9!
546let x = new foo:bar { };
547/// Doc comment #10!
548export x as "foo";
549"#,
550 r#"/// Doc comment for the package!
551package test:foo:bar@1.0.0;
552
553/// Doc comment #1!
554import foo: foo:bar/baz;
555
556/// Doc comment #2!
557type a = u32;
558
559/// Doc comment #3!
560record r {
561 x: string,
562}
563
564/// Doc comment #4!
565interface i {
566 /// Doc comment #5!
567 f: func() -> r;
568}
569
570/// Doc comment #6!
571world w {
572 /// Doc comment #7!
573 import i;
574
575 /// Doc comment #8!
576 export f: func() -> a;
577}
578
579/// Doc comment #9!
580let x = new foo:bar {};
581
582/// Doc comment #10!
583export x as "foo";
584"#,
585 )
586 .unwrap()
587 }
588}