Skip to main content

wasm_wave/
parser.rs

1//! Parsing types
2
3use core::{error::Error, fmt::Display};
4
5use alloc::{
6    boxed::Box,
7    collections::{BTreeMap, btree_set::BTreeSet},
8    format,
9    string::{String, ToString},
10    vec::Vec,
11};
12
13use crate::{
14    WasmValue,
15    ast::{Node, NodeType},
16    lex::{FuncNameLexer, FuncNameToken, Keyword, Lexer, Span, Token},
17    untyped::{UntypedFuncCall, UntypedValue},
18};
19
20/// A Web Assembly Value Encoding parser.
21pub struct Parser<'source> {
22    lex: Lexer<'source>,
23    curr: Option<Token>,
24}
25
26impl<'source> Parser<'source> {
27    /// Returns a new Parser of the given source.
28    pub fn new(source: &'source str) -> Self {
29        Self::with_lexer(Lexer::new(source))
30    }
31
32    /// Returns a new Parser with the given [`Lexer`].
33    pub fn with_lexer(lexer: Lexer<'source>) -> Self {
34        Self {
35            lex: lexer,
36            curr: None,
37        }
38    }
39
40    /// Parses a WAVE-encoded value of the given [`crate::wasm::WasmType`] into a
41    /// corresponding [`WasmValue`].
42    pub fn parse_value<V: WasmValue>(&mut self, ty: &V::Type) -> Result<V, ParserError> {
43        let node = self.parse_node()?;
44        node.to_wasm_value(ty, self.lex.source())
45    }
46
47    /// Parses a WAVE-encoded value into an [`UntypedValue`].
48    pub fn parse_raw_value(&mut self) -> Result<UntypedValue<'source>, ParserError> {
49        let node = self.parse_node()?;
50        Ok(UntypedValue::new(self.lex.source(), node))
51    }
52
53    /// Returns an error if any significant input remains unparsed.
54    pub fn finish(&mut self) -> Result<(), ParserError> {
55        match self.lex.clone().spanned().next() {
56            None => Ok(()),
57            Some((_, span)) => Err(ParserError::new(
58                ParserErrorKind::TrailingCharacters,
59                span.clone(),
60            )),
61        }
62    }
63
64    fn parse_node(&mut self) -> Result<Node, ParserError> {
65        Ok(match self.advance()? {
66            Token::Number => self.leaf_node(NodeType::Number),
67            Token::Char => self.leaf_node(NodeType::Char),
68            Token::String => self.leaf_node(NodeType::String),
69            Token::MultilineString => self.leaf_node(NodeType::MultilineString),
70            Token::ParenOpen => self.parse_tuple()?,
71            Token::BracketOpen => self.parse_list()?,
72            Token::BraceOpen => self.parse_record_or_flags()?,
73            Token::LabelOrKeyword => match Keyword::decode(self.slice()) {
74                Some(Keyword::True) => self.leaf_node(NodeType::BoolTrue),
75                Some(Keyword::False) => self.leaf_node(NodeType::BoolFalse),
76                Some(Keyword::Some) => self.parse_option(NodeType::OptionSome)?,
77                Some(Keyword::None) => self.parse_option(NodeType::OptionNone)?,
78                Some(Keyword::Ok) => self.parse_result(NodeType::ResultOk)?,
79                Some(Keyword::Err) => self.parse_result(NodeType::ResultErr)?,
80                Some(Keyword::Inf | Keyword::Nan) => self.leaf_node(NodeType::Number),
81                None => self.parse_label_maybe_payload()?,
82            },
83            Token::BraceClose
84            | Token::ParenClose
85            | Token::BracketClose
86            | Token::Colon
87            | Token::Comma => return Err(self.unexpected_token()),
88        })
89    }
90
91    fn parse_tuple(&mut self) -> Result<Node, ParserError> {
92        let start = self.span().start;
93        let children = self.parse_comma_separated_nodes(Token::ParenClose)?;
94        let span = start..self.span().end;
95        if children.is_empty() {
96            return Err(ParserError::new(ParserErrorKind::EmptyTuple, span));
97        }
98        Ok(Node::new(NodeType::Tuple, span, children))
99    }
100
101    fn parse_list(&mut self) -> Result<Node, ParserError> {
102        let start = self.span().start;
103        let children = self.parse_comma_separated_nodes(Token::BracketClose)?;
104        Ok(Node::new(NodeType::List, start..self.span().end, children))
105    }
106
107    fn parse_record_or_flags(&mut self) -> Result<Node, ParserError> {
108        let start = self.span().start;
109        self.advance()?;
110
111        match self.token() {
112            // Handle empty record (`{:}`)
113            Token::Colon => {
114                self.advance()?; // Advance to `}`
115                self.expect_token(Token::BraceClose)?;
116                return Ok(Node::new(NodeType::Record, start..self.span().end, []));
117            }
118            // Handle empty flags (`{}`)
119            Token::BraceClose => return Ok(Node::new(NodeType::Flags, start..self.span().end, [])),
120            _ => (),
121        }
122
123        // Check for a following `:` to distinguish records from flags
124        if self.next_is(Token::Colon) {
125            self.finish_record(start)
126        } else {
127            self.finish_flags(start)
128        }
129    }
130
131    fn finish_record(&mut self, start: usize) -> Result<Node, ParserError> {
132        let mut seen = BTreeSet::new();
133        let mut children = Vec::with_capacity(2);
134        loop {
135            // Parse field label
136            let label = self.parse_label()?;
137            // Check for duplicate fields
138            let field = self.slice().trim_start_matches('%');
139            if !seen.insert(field) {
140                return Err(ParserError::with_detail(
141                    ParserErrorKind::DuplicateField,
142                    label.span(),
143                    format!("{field:?}"),
144                ));
145            }
146            // Parse colon
147            self.advance()?;
148            self.expect_token(Token::Colon)?;
149            // Parse value
150            let value = self.parse_node()?;
151            children.extend([label, value]);
152            // Parse comma and/or end of record
153            if self.advance()? == Token::Comma {
154                self.advance()?;
155            }
156            if self.token() == Token::BraceClose {
157                break;
158            }
159        }
160        Ok(Node::new(
161            NodeType::Record,
162            start..self.span().end,
163            children,
164        ))
165    }
166
167    fn finish_flags(&mut self, start: usize) -> Result<Node, ParserError> {
168        let mut flags = BTreeMap::new();
169        loop {
170            // Parse flag label
171            let label = self.parse_label()?;
172            // Insert and check for duplicate flags
173            let span = label.span();
174            let flag = self.slice().trim_start_matches('%');
175            if flags.insert(flag, label).is_some() {
176                return Err(ParserError::with_detail(
177                    ParserErrorKind::DuplicateFlag,
178                    span,
179                    format!("{flag:?}"),
180                ));
181            }
182            // Parse comma and/or end of flags
183            if self.advance()? == Token::Comma {
184                self.advance()?;
185            }
186            if self.token() == Token::BraceClose {
187                break;
188            }
189        }
190        Ok(Node::new(
191            NodeType::Flags,
192            start..self.span().end,
193            flags.into_values(),
194        ))
195    }
196
197    fn parse_label_maybe_payload(&mut self) -> Result<Node, ParserError> {
198        let start = self.span().start;
199        let label = self.parse_label()?;
200        if self.next_is(Token::ParenOpen) {
201            self.advance()?;
202            let payload = self.parse_node()?;
203            self.advance()?;
204            self.expect_token(Token::ParenClose)?;
205            Ok(Node::new(
206                NodeType::VariantWithPayload,
207                start..self.span().end,
208                [label, payload],
209            ))
210        } else {
211            Ok(label)
212        }
213    }
214
215    fn parse_option(&mut self, ty: NodeType) -> Result<Node, ParserError> {
216        let start = self.span().start;
217        let payload = match ty {
218            NodeType::OptionSome => {
219                self.advance()?;
220                self.expect_token(Token::ParenOpen)?;
221                let payload = self.parse_node()?;
222                self.advance()?;
223                self.expect_token(Token::ParenClose)?;
224                Some(payload)
225            }
226            NodeType::OptionNone => None,
227            _ => unreachable!(),
228        };
229        Ok(Node::new(ty, start..self.span().end, payload))
230    }
231
232    fn parse_result(&mut self, ty: NodeType) -> Result<Node, ParserError> {
233        let start = self.span().start;
234        let mut payload = None;
235        if self.next_is(Token::ParenOpen) {
236            self.advance()?;
237            self.expect_token(Token::ParenOpen)?;
238            payload = Some(self.parse_node()?);
239            self.advance()?;
240            self.expect_token(Token::ParenClose)?;
241        }
242        Ok(Node::new(ty, start..self.span().end, payload))
243    }
244
245    fn parse_label(&mut self) -> Result<Node, ParserError> {
246        self.expect_token(Token::LabelOrKeyword)?;
247        Ok(self.leaf_node(NodeType::Label))
248    }
249
250    fn advance(&mut self) -> Result<Token, ParserError> {
251        let token = match self.lex.next() {
252            Some(Ok(token)) => token,
253            Some(Err(span)) => {
254                let span = span.unwrap_or_else(|| self.lex.span());
255                return Err(ParserError::new(ParserErrorKind::InvalidToken, span));
256            }
257            None => {
258                return Err(ParserError::new(
259                    ParserErrorKind::UnexpectedEnd,
260                    self.lex.span(),
261                ));
262            }
263        };
264        self.curr = Some(token);
265        Ok(token)
266    }
267
268    fn token(&self) -> Token {
269        self.curr.unwrap()
270    }
271
272    fn span(&self) -> Span {
273        self.lex.span()
274    }
275
276    fn slice(&self) -> &'source str {
277        &self.lex.source()[self.span()]
278    }
279
280    fn next_is(&mut self, token: Token) -> bool {
281        self.lex.clone().next().and_then(|res| res.ok()) == Some(token)
282    }
283
284    fn expect_token(&self, token: Token) -> Result<(), ParserError> {
285        if self.token() == token {
286            Ok(())
287        } else {
288            Err(self.unexpected_token())
289        }
290    }
291
292    fn unexpected_token(&self) -> ParserError {
293        ParserError::with_detail(ParserErrorKind::UnexpectedToken, self.span(), self.token())
294    }
295
296    fn parse_comma_separated_nodes(&mut self, end_token: Token) -> Result<Vec<Node>, ParserError> {
297        let mut nodes = Vec::new();
298        if self.next_is(end_token) {
299            self.advance()?;
300            return Ok(nodes);
301        }
302        loop {
303            nodes.push(self.parse_node()?);
304
305            match self.advance()? {
306                Token::Comma => {
307                    if self.next_is(end_token) {
308                        self.advance()?;
309                        break;
310                    }
311                }
312                _ => {
313                    self.expect_token(end_token)?;
314                    break;
315                }
316            }
317        }
318        Ok(nodes)
319    }
320
321    fn leaf_node(&self, ty: NodeType) -> Node {
322        Node::new(ty, self.span(), [])
323    }
324}
325
326/// A WAVE parsing error.
327#[derive(Debug)]
328pub struct ParserError {
329    kind: ParserErrorKind,
330    span: Span,
331    detail: Option<String>,
332    source: Option<Box<dyn Error + Send + Sync + 'static>>,
333}
334
335impl ParserError {
336    pub(crate) fn new(kind: ParserErrorKind, span: Span) -> Self {
337        Self {
338            kind,
339            span,
340            detail: None,
341            source: None,
342        }
343    }
344
345    pub(crate) fn with_detail(kind: ParserErrorKind, span: Span, detail: impl Display) -> Self {
346        Self {
347            kind,
348            span,
349            detail: Some(detail.to_string()),
350            source: None,
351        }
352    }
353
354    pub(crate) fn with_source(
355        kind: ParserErrorKind,
356        span: Span,
357        source: impl Into<Box<dyn Error + Send + Sync>>,
358    ) -> Self {
359        Self {
360            kind,
361            span,
362            detail: None,
363            source: Some(source.into()),
364        }
365    }
366
367    /// Returns the [`ParserErrorKind`] of this error.
368    pub fn kind(&self) -> ParserErrorKind {
369        self.kind
370    }
371
372    /// Returns the [`Span`] of this error.
373    pub fn span(&self) -> Span {
374        self.span.clone()
375    }
376
377    /// Returns any detail string for this error.
378    pub fn detail(&self) -> Option<&str> {
379        self.detail.as_deref()
380    }
381}
382
383impl Display for ParserError {
384    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
385        if let Some(source) = &self.source {
386            write!(f, "{}: {} at {:?}", self.kind, source, self.span)
387        } else if let Some(detail) = &self.detail {
388            write!(f, "{}: {} at {:?}", self.kind, detail, self.span)
389        } else {
390            write!(f, "{} at {:?}", self.kind, self.span)
391        }
392    }
393}
394
395impl Error for ParserError {
396    fn source(&self) -> Option<&(dyn Error + 'static)> {
397        Some(self.source.as_deref()? as _)
398    }
399}
400
401/// Parses a function name followed by a WAVE-encoded, parenthesized,
402/// comma-separated sequence of values into an [`UntypedFuncCall`].
403pub fn parse_raw_func_call<'source>(
404    source: &'source str,
405) -> Result<UntypedFuncCall<'source>, ParserError> {
406    let mut name_parser = FuncNameParser::with_lexer(FuncNameLexer::new(source));
407    let _func_name = name_parser.advance()?;
408    let name = name_parser.lex.span();
409
410    let mut params_parser = Parser::with_lexer(name_parser.lex.morph());
411    params_parser.advance()?;
412    params_parser.expect_token(Token::ParenOpen)?;
413
414    let params = if params_parser.next_is(Token::ParenClose) {
415        params_parser.advance()?;
416        None
417    } else {
418        Some(params_parser.parse_tuple()?)
419    };
420    params_parser.finish()?;
421    Ok(UntypedFuncCall::new(source, name, params))
422}
423
424struct FuncNameParser<'source> {
425    lex: FuncNameLexer<'source>,
426    curr: Option<FuncNameToken>,
427}
428impl<'source> FuncNameParser<'source> {
429    fn with_lexer(lex: FuncNameLexer<'source>) -> Self {
430        Self { lex, curr: None }
431    }
432    fn advance(&mut self) -> Result<FuncNameToken, ParserError> {
433        let token = match self.lex.next() {
434            Some(Ok(token)) => token,
435            Some(Err(span)) => {
436                let span = span.unwrap_or_else(|| self.lex.span());
437                return Err(ParserError::new(ParserErrorKind::InvalidToken, span));
438            }
439            None => {
440                return Err(ParserError::new(
441                    ParserErrorKind::UnexpectedEnd,
442                    self.lex.span(),
443                ));
444            }
445        };
446        self.curr = Some(token);
447        Ok(token)
448    }
449}
450/// The kind of a WAVE parsing error.
451#[derive(Clone, Copy, Debug, PartialEq)]
452#[non_exhaustive]
453#[allow(missing_docs)]
454pub enum ParserErrorKind {
455    EmptyTuple,
456    MultipleChars,
457    InvalidEscape,
458    InvalidMultilineString,
459    InvalidParams,
460    InvalidToken,
461    InvalidType,
462    InvalidValue,
463    TrailingCharacters,
464    UnexpectedEnd,
465    UnexpectedToken,
466    DuplicateField,
467    DuplicateFlag,
468    WasmValueError,
469}
470
471impl Display for ParserErrorKind {
472    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
473        let msg = match self {
474            ParserErrorKind::EmptyTuple => "empty tuple",
475            ParserErrorKind::MultipleChars => "multiple characters in char value",
476            ParserErrorKind::InvalidEscape => "invalid character escape",
477            ParserErrorKind::InvalidMultilineString => "invalid multiline string",
478            ParserErrorKind::InvalidParams => "invalid params",
479            ParserErrorKind::InvalidToken => "invalid token",
480            ParserErrorKind::InvalidType => "invalid value type",
481            ParserErrorKind::InvalidValue => "invalid value",
482            ParserErrorKind::TrailingCharacters => "trailing characters after value",
483            ParserErrorKind::UnexpectedEnd => "unexpected end of input",
484            ParserErrorKind::UnexpectedToken => "unexpected token",
485            ParserErrorKind::DuplicateField => "duplicate field",
486            ParserErrorKind::DuplicateFlag => "duplicate flag",
487            ParserErrorKind::WasmValueError => "error converting Wasm value",
488        };
489        write!(f, "{msg}")
490    }
491}
492
493#[cfg(test)]
494mod tests {
495    use super::*;
496    use crate::value::{Type, Value};
497
498    #[test]
499    fn parse_option_or_result() {
500        let ty = Type::option(Type::BOOL);
501        assert_eq!(
502            parse_value("some(true)", &ty),
503            Value::make_option(&ty, Some(Value::make_bool(true))).unwrap()
504        );
505        let ty = Type::result(Some(Type::BOOL), None);
506        assert_eq!(
507            parse_value("ok(false)", &ty),
508            Value::make_result(&ty, Ok(Some(Value::make_bool(false)))).unwrap()
509        );
510    }
511
512    #[test]
513    fn parse_flat_option_or_result() {
514        let ty = Type::option(Type::BOOL);
515        assert_eq!(
516            parse_value("true", &ty),
517            Value::make_option(&ty, Some(Value::make_bool(true))).unwrap()
518        );
519        let ty = Type::result(Some(Type::BOOL), None);
520        assert_eq!(
521            parse_value("false", &ty),
522            Value::make_result(&ty, Ok(Some(Value::make_bool(false)))).unwrap()
523        );
524    }
525
526    #[test]
527    fn parse_record_reordering() {
528        let ty = Type::record([("red", Type::S32), ("green", Type::CHAR)]).unwrap();
529        // Parse the fields in the order they appear in the type.
530        assert_eq!(
531            parse_value("{red: 0, green: 'a'}", &ty),
532            Value::make_record(
533                &ty,
534                [
535                    ("red", Value::make_s32(0)),
536                    ("green", Value::make_char('a'))
537                ]
538            )
539            .unwrap()
540        );
541        // Parse the fields in reverse order.
542        assert_eq!(
543            parse_value("{green: 'a', red: 0}", &ty),
544            Value::make_record(
545                &ty,
546                [
547                    ("red", Value::make_s32(0)),
548                    ("green", Value::make_char('a'))
549                ]
550            )
551            .unwrap()
552        );
553    }
554
555    #[test]
556    fn parse_record_with_optional_fields() {
557        let field_ty = Type::option(Type::CHAR);
558        let ty = Type::record([("red", Type::S32), ("green", field_ty.clone())]).unwrap();
559        // Explicit `some`.
560        assert_eq!(
561            parse_value("{red: 0, green: some('a')}", &ty),
562            Value::make_record(
563                &ty,
564                [
565                    ("red", Value::make_s32(0)),
566                    (
567                        "green",
568                        Value::make_option(&field_ty, Some(Value::make_char('a'))).unwrap()
569                    )
570                ]
571            )
572            .unwrap()
573        );
574        // Flattened `some`.
575        assert_eq!(
576            parse_value("{red: 0, green: 'a'}", &ty),
577            Value::make_record(
578                &ty,
579                [
580                    ("red", Value::make_s32(0)),
581                    (
582                        "green",
583                        Value::make_option(&field_ty, Some(Value::make_char('a'))).unwrap()
584                    )
585                ]
586            )
587            .unwrap()
588        );
589        // Explicit `none`.
590        assert_eq!(
591            parse_value("{red: 0, green: none}", &ty),
592            Value::make_record(
593                &ty,
594                [
595                    ("red", Value::make_s32(0)),
596                    ("green", Value::make_option(&field_ty, None).unwrap())
597                ]
598            )
599            .unwrap()
600        );
601        // Implied `none`.
602        assert_eq!(
603            parse_value("{red: 0}", &ty),
604            Value::make_record(
605                &ty,
606                [
607                    ("red", Value::make_s32(0)),
608                    ("green", Value::make_option(&field_ty, None).unwrap())
609                ]
610            )
611            .unwrap()
612        );
613    }
614
615    #[test]
616    fn parse_flag_reordering() {
617        let ty = Type::flags(["hot", "cold"]).unwrap();
618        // Parse the flags in the order they appear in the type.
619        assert_eq!(
620            parse_value("{hot, cold}", &ty),
621            Value::make_flags(&ty, ["hot", "cold"]).unwrap()
622        );
623        // Parse the flags in reverse order.
624        assert_eq!(
625            parse_value("{cold, hot}", &ty),
626            Value::make_flags(&ty, ["hot", "cold"]).unwrap()
627        );
628    }
629
630    #[test]
631    fn parse_percent_identifiers() {
632        let ty = Type::record([
633            ("red", Type::S32),
634            ("green", Type::CHAR),
635            ("color-42-2A-5d", Type::BOOL),
636        ])
637        .unwrap();
638        // Test identifiers with '%' prefixes.
639        assert_eq!(
640            parse_value("{ %red: 0, %green: 'a', %color-42-2A-5d: true }", &ty),
641            Value::make_record(
642                &ty,
643                [
644                    ("red", Value::make_s32(0)),
645                    ("green", Value::make_char('a')),
646                    ("color-42-2A-5d", Value::make_bool(true))
647                ]
648            )
649            .unwrap()
650        );
651    }
652
653    #[test]
654    fn parse_prefixed_keyword_variant_cases() {
655        let ty = Type::list(
656            Type::variant([
657                ("true", Some(Type::U8)),
658                ("false", None),
659                ("inf", Some(Type::U8)),
660                ("nan", None),
661                ("some", Some(Type::U8)),
662                ("none", None),
663                ("ok", Some(Type::U8)),
664                ("err", None),
665            ])
666            .unwrap(),
667        );
668        parse_value(
669            "[%true(1), %false, %inf(1), %nan, %some(1), %none, %ok(1), %err]",
670            &ty,
671        );
672    }
673
674    #[test]
675    fn reject_unprefixed_keyword_enum_cases() {
676        let cases = ["true", "false", "inf", "nan", "none", "ok", "err"];
677        let ty = Type::enum_ty(cases).unwrap();
678        for case in cases {
679            let err = Parser::new(case).parse_value::<Value>(&ty).unwrap_err();
680            assert_eq!(err.kind(), ParserErrorKind::InvalidType);
681        }
682    }
683
684    #[test]
685    fn parse_unprefixed_keyword_fields() {
686        let ty = Type::record([
687            ("true", Type::U8),
688            ("false", Type::U8),
689            ("inf", Type::U8),
690            ("nan", Type::U8),
691            ("some", Type::U8),
692            ("none", Type::U8),
693            ("ok", Type::U8),
694            ("err", Type::U8),
695        ])
696        .unwrap();
697        parse_value(
698            "{true: 1, false: 1, inf: 1, nan: 1, some: 1, none: 1, ok: 1, err: 1}",
699            &ty,
700        );
701    }
702
703    #[test]
704    fn parse_unprefixed_keyword_flags() {
705        let ty = Type::flags(["true", "false", "inf", "nan", "some", "none", "ok", "err"]).unwrap();
706        parse_value("{true, false, inf, nan, some, none, ok, err}", &ty);
707    }
708
709    #[test]
710    fn reject_unprefixed_some_variant_case() {
711        let ty = Type::variant([("some", Some(Type::U8))]).unwrap();
712        let err = Parser::new("some(1)")
713            .parse_value::<Value>(&ty)
714            .unwrap_err();
715        assert_eq!(err.kind(), ParserErrorKind::InvalidType);
716    }
717
718    fn parse_value(input: &str, ty: &Type) -> Value {
719        Parser::new(input)
720            .parse_value(ty)
721            .unwrap_or_else(|err| panic!("error decoding {input:?}: {err}"))
722    }
723}