wright/parser/
ty.rs

1//! Parser implementation for parsing types.
2
3use crate::{
4    ast::{
5        // identifier::Identifier,
6        ty::{AtomicTy, ReferenceTy, Type},
7    },
8    lexer::token::TokenTy,
9};
10
11use super::{
12    Parser,
13    error::{ParserError, ParserErrorKind},
14};
15
16mod constrained_ty;
17mod primitive;
18mod reference;
19
20impl Type {
21    /// Parse a type signature in source code.
22    pub fn parse(parser: &mut Parser) -> Result<Self, ParserError> {
23        // First try to parse a type, then check to see if the `constrain` keyword follows it,
24        // since that's effectively a type suffix.
25
26        // Atempt to parse atomic types first -- they're the simplest. If we fail to parse, the parser doesn't advance.
27        // Since they're all keywords we don't have to worry at all about under-greedy parsing (yet).
28        let atomic_ty_parse_fn = |parser: &mut Parser| AtomicTy::parse(parser).map(Type::Atomic);
29        let reference_ty_parse_fn =
30            |parser: &mut Parser| ReferenceTy::parse(parser).map(Type::Reference);
31
32        let order = [atomic_ty_parse_fn, reference_ty_parse_fn];
33
34        for parse_fn in order {
35            let initial_bytes_remaining = parser.bytes_remaining();
36
37            match (parse_fn)(parser) {
38                // Successful parse, constraint clause follows.
39                Ok(_t)
40                    if parser
41                        .peek_next_not_whitespace()
42                        .is_some_and(|t| t.variant == TokenTy::KwConstrain) =>
43                {
44                    // Consume whitespace
45                    parser.consume_at_least_one_whitespace()?;
46
47                    // consume constrain keyword
48                    assert_eq!(parser.next_token().unwrap().unwrap().variant, TokenTy::KwConstrain);
49
50                    // let mut constraints: Vec<Identifier> = Vec::new();
51
52                    // FIXME: This sucks for parsing and I'm increasingly thinking the syntax for constraints
53                    // should be `type ~ a ~ b ~ c...` rather than `type constrain a, b, c`
54                    while let Some(peek) = parser.peek_next_not_whitespace()
55                        && peek.variant == TokenTy::Identifier
56                    {}
57                }
58
59                // Successful parse, no constraint clause.
60                Ok(t) => return Ok(t),
61
62                // Partial parse with error.
63                Err(err) if parser.bytes_remaining() != initial_bytes_remaining => return Err(err),
64
65                // Parsing error with no tokens consumed.
66                Err(_) => continue,
67            }
68        }
69
70        Err(ParserErrorKind::ExpectedTypeSignature.at(parser.peek_fragment_or_rest_cloned()))
71    }
72}