sylt_parser/
parser.rs

1use self::expression::expression;
2use self::statement::outer_statement;
3use std::collections::{HashMap, HashSet};
4use std::fmt::Debug;
5use std::path::{Path, PathBuf};
6use std::rc::Rc;
7use sylt_common::error::Error;
8use sylt_common::Type as RuntimeType;
9use sylt_tokenizer::{PlacedToken, Token, ZERO_SPAN, file_to_tokens};
10
11pub mod expression;
12pub mod statement;
13pub use self::expression::{Expression, ExpressionKind};
14pub use self::statement::{Statement, StatementKind};
15
16pub use sylt_tokenizer::Span;
17
18type T = Token;
19
20pub trait Next {
21    fn next(&self) -> Self;
22}
23
24pub trait Numbered {
25    fn to_number(&self) -> usize;
26}
27
28/// Contains modules.
29#[derive(Debug, Clone)]
30pub struct AST {
31    pub modules: Vec<(PathBuf, Module)>,
32}
33
34/// Contains statements.
35#[derive(Debug, Clone)]
36pub struct Module {
37    pub span: Span,
38    pub statements: Vec<Statement>,
39}
40
41/// The precedence of an operator.
42///
43/// A higher precedence means that something should be more tightly bound. For
44/// example, multiplication has higher precedence than addition and as such is
45/// evaluated first.
46///
47/// Prec-variants can be compared to each other. A proc-macro ensures that the
48/// comparison follows the ordering here such that
49/// `prec_i < prec_j` for all `j > i`.
50#[derive(sylt_macro::Next, PartialEq, PartialOrd, Clone, Copy, Debug)]
51pub enum Prec {
52    No,
53    Assert,
54    BoolOr,
55    BoolAnd,
56    Comp,
57    Term,
58    Factor,
59    Index,
60    Arrow,
61}
62
63/// Variables can be any combination of `{Force,}{Const,Mutable}`.
64///
65/// Forced variable kinds are a signal to the type checker that the type is
66/// assumed and shouldn't be checked.
67#[derive(Debug, Copy, Clone)]
68pub enum VarKind {
69    Const,
70    Mutable,
71    ForceConst,
72    ForceMutable,
73}
74
75impl VarKind {
76    pub fn immutable(&self) -> bool {
77        matches!(self, VarKind::Const | VarKind::ForceConst)
78    }
79
80    pub fn force(&self) -> bool {
81        matches!(self, VarKind::ForceConst | VarKind::ForceMutable)
82    }
83}
84
85/// The different kinds of assignment operators: `+=`, `-=`, `*=`, `/=` and `=`.
86#[derive(Debug, Copy, Clone)]
87pub enum Op {
88    Nop,
89    Add,
90    Sub,
91    Mul,
92    Div,
93}
94
95#[derive(Debug, Clone)]
96pub struct Identifier {
97    pub span: Span,
98    pub name: String,
99}
100
101/// The different kinds of [Assignable]s.
102///
103/// Assignables are the left hand side of a [StatementKind::Assignment].
104///
105/// # Example
106///
107/// The recursive structure means that `a[2].b(1).c(2, 3)` is evaluated to
108/// ```ignored
109/// Access(
110///     Index(
111///         Read(a), 2
112///     ),
113///     Access(
114///         Call(
115///             Read(b), [1]
116///         ),
117///         Call(
118///             Read(c), [2, 3]
119///         )
120///     )
121/// )
122/// ```
123#[derive(Debug, Clone)]
124pub enum AssignableKind {
125    Read(Identifier),
126    /// A function call.
127    Call(Box<Assignable>, Vec<Expression>),
128    /// An arrow function call. `a -> f' b`
129    ArrowCall(Box<Expression>, Box<Assignable>, Vec<Expression>),
130    Access(Box<Assignable>, Identifier),
131    Index(Box<Assignable>, Box<Expression>),
132}
133
134/// Something that can be assigned to. The assignable value can be read if the
135/// assignable is in an expression. Contains any [AssignableKind].
136///
137/// Note that assignables can occur both in the left hand side and the right hand
138/// side of assignment statements, so something like `a = b` will be evaluated as
139/// ```ignored
140/// Statement::Assignment(
141///     Assignable::Read(a),
142///     Expression::Get(Assignable::Read(b))
143/// )
144/// ```
145#[derive(Debug, Clone)]
146pub struct Assignable {
147    pub span: Span,
148    pub kind: AssignableKind,
149}
150
151#[derive(Debug, Clone)]
152pub enum TypeKind {
153    /// An unspecified type that is left to the type checker.
154    Implied,
155    /// A specified type by the user.
156    Resolved(RuntimeType),
157    /// I.e. blobs.
158    UserDefined(Assignable),
159    /// A type that can be either `a` or `b`.
160    Union(Box<Type>, Box<Type>),
161    /// `(params, return)`.
162    Fn(Vec<Type>, Box<Type>),
163    /// Tuples can mix types since the length is constant.
164    Tuple(Vec<Type>),
165    /// Lists only contain a single type.
166    List(Box<Type>),
167    /// Sets only contain a single type.
168    Set(Box<Type>),
169    /// `(key, value)`.
170    Dict(Box<Type>, Box<Type>),
171}
172
173/// A parsed type. Contains any [TypeKind].
174#[derive(Debug, Clone)]
175pub struct Type {
176    pub span: Span,
177    pub kind: TypeKind,
178}
179
180type ParseResult<'t, T> = Result<(Context<'t>, T), (Context<'t>, Vec<Error>)>;
181
182/// Keeps track of where the parser is currently parsing.
183#[derive(Debug, Copy, Clone)]
184pub struct Context<'a> {
185    pub skip_newlines: bool,
186    /// All tokens to be parsed.
187    pub tokens: &'a [Token],
188    /// The corresponding span for each token. Matches 1:1 with the tokens.
189    pub spans: &'a [Span],
190    /// The index of the curren token in the token slice.
191    pub curr: usize,
192    /// The file we're currently parsing.
193    pub file: &'a Path,
194}
195
196impl<'a> Context<'a> {
197    fn new(tokens: &'a [Token], spans: &'a [Span], file: &'a Path) -> Self {
198        Self {
199            skip_newlines: false,
200            tokens,
201            spans,
202            curr: 0,
203            file,
204        }
205    }
206
207    /// Get a [Span] representing the current location of the parser.
208    fn span(&self) -> Span {
209        *self.peek().1
210    }
211
212    /// Move to the next nth token.
213    fn skip(&self, n: usize) -> Self {
214        let mut new = *self;
215        new.curr += n;
216        while self.skip_newlines && matches!(new.token(), T::Newline) {
217            new.curr += 1;
218        }
219        new
220    }
221
222    /// Signals that newlines should be skipped until [pop_skip_newlines].
223    fn push_skip_newlines(&self, skip_newlines: bool) -> (Self, bool) {
224        let mut new = *self;
225        new.skip_newlines = skip_newlines;
226        // If currently on a newline token - we want to skip it.
227        (new.skip(0), self.skip_newlines)
228    }
229
230    /// Reset to old newline skipping state.
231    fn pop_skip_newlines(&self, skip_newlines: bool) -> Self {
232        let mut new = *self;
233        new.skip_newlines = skip_newlines;
234        new
235    }
236
237    fn skip_if(&self, token: T) -> Self {
238        if self.token() == &token {
239            self.skip(1)
240        } else {
241            *self
242        }
243    }
244
245    fn _skip_if_any<const N: usize>(&self, tokens: [T; N]) -> Self {
246        if tokens.iter().any(|t| self.token() == t) {
247            self.skip(1)
248        } else {
249            *self
250        }
251    }
252
253    /// Return the current [Token] and [Span].
254    fn peek(&self) -> (&Token, &Span) {
255        let token = self.tokens.get(self.curr).unwrap_or(&T::EOF);
256        let span = self.spans.get(self.curr).unwrap_or(&ZERO_SPAN);
257        (token, span)
258    }
259
260    /// Return the current [Token].
261    fn token(&self) -> &T {
262        &self.peek().0
263    }
264
265    /// Eat a [Token] and move to the next.
266    fn eat(&self) -> (&T, Span, Self) {
267        (self.token(), self.span(), self.skip(1))
268    }
269}
270
271//TODO(gu) None if no message?
272
273/// Construct a syntax error at the current token with a message.
274#[macro_export]
275macro_rules! syntax_error {
276    ($ctx:expr, $( $msg:expr ),* ) => {
277        {
278            let msg = format!($( $msg ),*).into();
279            Error::SyntaxError {
280                file: $ctx.file.to_path_buf(),
281                span: $ctx.span(),
282                message: Some(msg),
283            }
284        }
285    };
286}
287
288/// Raise a syntax error at the current token with a message.
289#[macro_export]
290macro_rules! raise_syntax_error {
291    ($ctx:expr, $( $msg:expr ),* ) => {
292        return Err(($ctx.skip(1), vec![syntax_error!($ctx, $( $msg ),*)]))
293    };
294}
295
296/// Eat any one of the specified tokens and raise a syntax error if none is found.
297#[macro_export]
298macro_rules! expect {
299    ($ctx:expr, $( $token:pat )|+ , $( $msg:expr ),+ ) => {
300        {
301            if !matches!($ctx.token(), $( $token )|* ) {
302                raise_syntax_error!($ctx, $( $msg ),*);
303            }
304            $ctx.skip(1)
305        }
306    };
307
308    ($ctx:expr, $( $token:pat )|+ ) => {
309        expect!($ctx, $( $token )|*, concat!("Expected ", stringify!($( $token )|*)))
310    };
311}
312
313/// Parse a [Type] definition, e.g. `fn int, int, bool -> bool`.
314fn parse_type<'t>(ctx: Context<'t>) -> ParseResult<'t, Type> {
315    use RuntimeType::{Bool, Float, Int, String, Void};
316    use TypeKind::*;
317    let span = ctx.span();
318    let (ctx, kind) = match ctx.token() {
319        T::Identifier(name) => match name.as_str() {
320            "void" => (ctx.skip(1), Resolved(Void)),
321            "int" => (ctx.skip(1), Resolved(Int)),
322            "float" => (ctx.skip(1), Resolved(Float)),
323            "bool" => (ctx.skip(1), Resolved(Bool)),
324            "str" => (ctx.skip(1), Resolved(String)),
325            _ => {
326                let (ctx, assignable) = assignable(ctx)?;
327                (ctx, UserDefined(assignable))
328            }
329        },
330
331        // Function type
332        T::Fn => {
333            let mut ctx = ctx.skip(1);
334            let mut params = Vec::new();
335            // There might be multiple parameters.
336            let ret = loop {
337                match ctx.token() {
338                    // Arrow implies only one type (the return type) is left.
339                    T::Arrow => {
340                        ctx = ctx.skip(1);
341                        break if let Ok((_ctx, ret)) = parse_type(ctx) {
342                            ctx = _ctx; // assign to outer
343                            ret
344                        } else {
345                            // If we couldn't parse the return type, we assume `-> Void`.
346                            Type {
347                                span: ctx.span(),
348                                kind: Resolved(Void),
349                            }
350                        };
351                    }
352
353                    T::EOF => {
354                        raise_syntax_error!(ctx, "Didn't expect EOF in type definition");
355                    }
356
357                    // Parse a single parameter type.
358                    _ => {
359                        let (_ctx, param) = parse_type(ctx)?;
360                        ctx = _ctx; // assign to outer
361                        params.push(param);
362
363                        ctx = if matches!(ctx.token(), T::Comma | T::Arrow) {
364                            ctx.skip_if(T::Comma)
365                        } else {
366                            raise_syntax_error!(ctx, "Expected ',' or '->' after type parameter")
367                        };
368                    }
369                }
370            };
371            (ctx, Fn(params, Box::new(ret)))
372        }
373
374        // Tuple
375        T::LeftParen => {
376            let mut ctx = ctx.skip(1);
377            let mut types = Vec::new();
378            // Tuples may (and probably will) contain multiple types.
379            loop {
380                match ctx.token() {
381                    // Done parsing this tuple.
382                    T::RightParen => {
383                        ctx = ctx.skip(1);
384                        break;
385                    }
386
387                    T::EOF => {
388                        raise_syntax_error!(ctx, "Didn't expect EOF in type definition");
389                    }
390
391                    // Parse a single contained type.
392                    _ => {
393                        let (_ctx, param) = parse_type(ctx)?;
394                        ctx = _ctx; // assign to outer
395                        types.push(param);
396
397                        ctx = if matches!(ctx.token(), T::Comma | T::RightParen) {
398                            ctx.skip_if(T::Comma)
399                        } else {
400                            raise_syntax_error!(ctx, "Expected ',' or ')' after tuple field")
401                        };
402                    }
403                }
404            }
405            (ctx, Tuple(types))
406        }
407
408        // List
409        T::LeftBracket => {
410            // Lists only contain a single type.
411            let (ctx, ty) = parse_type(ctx.skip(1))?;
412            let ctx = expect!(ctx, T::RightBracket, "Expected ']' after list type");
413            (ctx, List(Box::new(ty)))
414        }
415
416        // Dict or set
417        T::LeftBrace => {
418            // { a } -> set
419            // { a: b } -> dict
420            // This means we can parse the first type unambiguously.
421            let (ctx, ty) = parse_type(ctx.skip(1))?;
422            if matches!(ctx.token(), T::Colon) {
423                // Dict, parse another type.
424                let (ctx, value) = parse_type(ctx.skip(1))?;
425                let ctx = expect!(ctx, T::RightBrace, "Expected '}}' after dict type");
426                (ctx, Dict(Box::new(ty), Box::new(value)))
427            } else {
428                // Set, done.
429                let ctx = expect!(ctx, T::RightBrace, "Expected '}}' after set type");
430                (ctx, Set(Box::new(ty)))
431            }
432        }
433
434        t => {
435            raise_syntax_error!(ctx, "No type starts with '{:?}'", t);
436        }
437    };
438
439    // Wrap it in a syntax tree node.
440    let ty = Type { span, kind };
441
442    // Union type, `a | b`
443    let (ctx, ty) = if matches!(ctx.token(), T::Pipe) {
444        // Parse the other type.
445        let (ctx, rest) = parse_type(ctx.skip(1))?;
446        (
447            ctx,
448            Type {
449                span,
450                kind: Union(Box::new(ty), Box::new(rest)),
451            },
452        )
453    } else {
454        (ctx, ty)
455    };
456
457    // Nullable type. Compiles to `a | Void`.
458    let (ctx, ty) = if matches!(ctx.token(), T::QuestionMark) {
459        let void = Type {
460            span: ctx.span(),
461            kind: Resolved(Void),
462        };
463        (
464            ctx.skip(1),
465            Type {
466                span,
467                kind: Union(Box::new(ty), Box::new(void)),
468            },
469        )
470    } else {
471        (ctx, ty)
472    };
473
474    Ok((ctx, ty))
475}
476
477/// Parse an [AssignableKind::Call]
478fn assignable_call<'t>(ctx: Context<'t>, callee: Assignable) -> ParseResult<'t, Assignable> {
479    let span = ctx.span();
480    let primer = matches!(ctx.token(), T::Prime); // `f' 1, 2`
481    let mut ctx = expect!(
482        ctx,
483        T::Prime | T::LeftParen,
484        "Expected '(' or ' when calling function"
485    );
486    let mut args = Vec::new();
487
488    // Arguments
489    loop {
490        match (ctx.token(), primer) {
491            // Done with arguments.
492            (T::EOF, _)
493            | (T::Else, _)
494            | (T::RightParen, false)
495            | (T::Dot, true)
496            | (T::Newline, true)
497            | (T::Arrow, true) => {
498                break;
499            }
500
501            // Parse a single argument.
502            _ => {
503                let (_ctx, expr) = expression(ctx)?;
504                ctx = _ctx; // assign to outer
505                args.push(expr);
506
507                ctx = ctx.skip_if(T::Comma);
508            }
509        }
510    }
511
512    let ctx = if !primer {
513        expect!(ctx, T::RightParen, "Expected ')' after calling function")
514    } else {
515        ctx
516    };
517
518    use AssignableKind::Call;
519    let result = Assignable {
520        span,
521        kind: Call(Box::new(callee), args),
522    };
523    sub_assignable(ctx, result)
524}
525
526/// Parse an [AssignableKind::Index].
527fn assignable_index<'t>(ctx: Context<'t>, indexed: Assignable) -> ParseResult<'t, Assignable> {
528    let span = ctx.span();
529    let mut ctx = expect!(ctx, T::LeftBracket, "Expected '[' when indexing");
530
531    let (_ctx, expr) = expression(ctx)?;
532    ctx = _ctx; // assign to outer
533    let ctx = expect!(ctx, T::RightBracket, "Expected ']' after index");
534
535    use AssignableKind::Index;
536    let result = Assignable {
537        span,
538        kind: Index(Box::new(indexed), Box::new(expr)),
539    };
540    sub_assignable(ctx, result)
541}
542
543/// Parse an [AssignableKind::Access].
544fn assignable_dot<'t>(ctx: Context<'t>, accessed: Assignable) -> ParseResult<'t, Assignable> {
545    use AssignableKind::Access;
546    let (ctx, ident) = if let (T::Identifier(name), span, ctx) = ctx.skip(1).eat() {
547        (
548            ctx,
549            Identifier {
550                name: name.clone(),
551                span,
552            },
553        )
554    } else {
555        raise_syntax_error!(
556            ctx,
557            "Assignable expressions have to start with an identifier"
558        );
559    };
560
561    let access = Assignable {
562        span: ctx.span(),
563        kind: Access(Box::new(accessed), ident),
564    };
565    sub_assignable(ctx, access)
566}
567
568/// Parse a (maybe empty) "sub-assignable", i.e. either a call or indexable.
569fn sub_assignable<'t>(ctx: Context<'t>, assignable: Assignable) -> ParseResult<'t, Assignable> {
570    match ctx.token() {
571        T::Prime | T::LeftParen => assignable_call(ctx, assignable),
572        T::LeftBracket => assignable_index(ctx, assignable),
573        T::Dot => assignable_dot(ctx, assignable),
574        _ => Ok((ctx, assignable)),
575    }
576}
577
578/// Parse an [Assignable].
579///
580/// [Assignable]s can be quite complex, e.g. `a[2].b(1).c(2, 3)`. They're parsed
581/// one "step" at a time recursively, so this example will go through three calls
582/// to [assignable].
583///
584/// 1. Parse `c(2, 3)` into `Call(Read(c), [2, 3])`.
585/// 2. Parse `b(1).c(2, 3)` into `Access(Call(Read(b), [1]), <parsed c(2, 3)>)`.
586/// 3. Parse `a[2].b(1).c(2, 3)` into `Access(Index(Read(a), 2), <parsed b(1).c(2, 3)>)`.
587fn assignable<'t>(ctx: Context<'t>) -> ParseResult<'t, Assignable> {
588    use AssignableKind::*;
589    let outer_span = ctx.span();
590
591    // Get the identifier.
592    let ident = if let (T::Identifier(name), span) = (ctx.token(), ctx.span()) {
593        Assignable {
594            span: outer_span,
595            kind: Read(Identifier {
596                span,
597                name: name.clone(),
598            }),
599        }
600    } else {
601        raise_syntax_error!(
602            ctx,
603            "Assignable expressions have to start with an identifier"
604        );
605    };
606
607    // Parse chained [], . and ().
608    sub_assignable(ctx.skip(1), ident)
609}
610
611/// Parses a file's tokens. Returns a list of files it refers to (via `use`s) and
612/// the parsed statements.
613///
614/// # Errors
615///
616/// Returns any errors that occured when parsing the file. Basic error
617/// continuation is performed, so errored statements are skipped until a newline
618/// or EOF.
619fn module(path: &Path, token_stream: &[PlacedToken]) -> (Vec<PathBuf>, Result<Module, Vec<Error>>) {
620    let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
621    let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
622    let mut ctx = Context::new(&tokens, &spans, path);
623    let mut errors = Vec::new();
624    let mut use_files = Vec::new();
625    let mut statements = Vec::new();
626    while !matches!(ctx.token(), T::EOF) {
627        // Ignore newlines.
628        if matches!(ctx.token(), T::Newline) {
629            ctx = ctx.skip(1);
630            continue;
631        }
632        // Parse an outer statement.
633        ctx = match outer_statement(ctx) {
634            Ok((ctx, statement)) => {
635                use StatementKind::*;
636                // Yank `use`s and add it to the used-files list.
637                if let Use { file, .. } = &statement.kind {
638                    let file = PathBuf::from(format!("{}.sy", file.name));
639                    use_files.push(file);
640                }
641                // Only push non-empty statements.
642                if !matches!(statement.kind, EmptyStatement) {
643                    statements.push(statement);
644                }
645                ctx
646            }
647            Err((mut ctx, mut errs)) => {
648                errors.append(&mut errs);
649
650                // "Error recovery"
651                while !matches!(ctx.token(), T::EOF | T::Newline) {
652                    ctx = ctx.skip(1);
653                }
654                ctx
655            }
656        }
657    }
658
659    if errors.is_empty() {
660        (
661            use_files,
662            Ok(Module {
663                span: Span::zero(),
664                statements,
665            }),
666        )
667    } else {
668        (use_files, Err(errors))
669    }
670}
671
672/// Look for git conflict markers (`<<<<<<<`) in a file.
673///
674/// Since conflict markers might be present anywhere, we don't even try to save
675/// the parsing if we find any.
676///
677/// # Errors
678///
679/// Returns a [Vec] of all errors found.
680///
681/// - [Error::FileNotFound] if the file couldn't be found.
682/// - [Error::GitConflictError] if conflict markers were found.
683/// - Any [Error::IOError] that occured when reading the file.
684pub fn find_conflict_markers(file: &Path) -> Vec<Error> {
685    let s = match std::fs::read_to_string(file) {
686        Ok(s) => s,
687        Err(e) => {
688            return vec![if matches!(e.kind(), std::io::ErrorKind::NotFound) {
689                Error::FileNotFound(file.to_path_buf())
690            } else {
691                Error::IOError(Rc::new(e))
692            }]
693        }
694    };
695    let mut errs = Vec::new();
696    // Search line by line and push any errors we find.
697    for (i, line) in s.lines().enumerate() {
698        if line.starts_with("<<<<<<<") {
699            errs.push(Error::GitConflictError {
700                file: file.to_path_buf(),
701                span: Span {
702                    line: i + 1,
703                    col_start: 0,
704                    col_end: "<<<<<<<".len(),
705                }
706            });
707        }
708    }
709    errs
710}
711
712/// Parses the contents of a file as well as all files this file refers to and so
713/// on.
714///
715/// Returns the resulting [Program](Prog) (list of [Module]s).
716///
717/// # Errors
718///
719/// Returns any errors that occured when parsing the file(s). Basic error
720/// continuation is performed as documented in [module].
721pub fn tree(path: &Path) -> Result<AST, Vec<Error>> {
722    // Files we've already parsed. This ensures circular includes don't parse infinitely.
723    let mut visited = HashSet::new();
724    // Files we want to parse but haven't yet.
725    let mut to_visit = Vec::new();
726    let root = path.parent().unwrap();
727    to_visit.push(PathBuf::from(path.file_name().unwrap()));
728
729    let mut modules = Vec::new();
730    let mut errors = Vec::new();
731    while let Some(file) = to_visit.pop() {
732        let file = root.join(file);
733        if visited.contains(&file) {
734            continue;
735        }
736        // Look for conflict markers
737        let mut conflict_errors = find_conflict_markers(&file);
738        if !conflict_errors.is_empty() {
739            errors.append(&mut conflict_errors);
740            visited.insert(file);
741            continue;
742        }
743        // Lex into tokens.
744        match file_to_tokens(&file) {
745            Ok(tokens) => {
746                // Parse the module.
747                let (mut next, result) = module(&file, &tokens);
748                match result {
749                    Ok(module) => modules.push((file.clone(), module)),
750                    Err(mut errs) => errors.append(&mut errs),
751                }
752                to_visit.append(&mut next);
753            }
754            Err(_) => {
755                errors.push(Error::FileNotFound(file.clone()));
756            }
757        }
758        visited.insert(file);
759    }
760
761    if errors.is_empty() {
762        Ok(AST { modules })
763    } else {
764        Err(errors)
765    }
766}
767
768#[cfg(test)]
769mod test {
770    use super::*;
771
772    #[macro_export]
773    macro_rules! test {
774        ($f:ident, $name:ident: $str:expr => $ans:pat) => {
775            #[test]
776            fn $name() {
777                let token_stream = ::sylt_tokenizer::string_to_tokens($str);
778                let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
779                let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
780                let path = ::std::path::PathBuf::from(stringify!($name));
781                let result = $f($crate::Context::new(&tokens, &spans, &path));
782                assert!(
783                    result.is_ok(),
784                    "\nSyntax tree test didn't parse for:\n{}\nErrs: {:?}",
785                    $str,
786                    result.unwrap_err().1
787                );
788                let (ctx, result) = result.unwrap();
789                assert!(
790                    matches!(result.kind, $ans),
791                    "\nExpected: {}, but got: {:?}",
792                    stringify!($ans),
793                    result
794                );
795                assert_eq!(
796                    ctx.curr,
797                    ctx.tokens.len(),
798                    "Parsed too few or too many tokens:\n{}",
799                    $str
800                );
801            }
802        };
803    }
804
805    #[macro_export]
806    macro_rules! fail {
807        ($f:ident, $name:ident: $str:expr => $ans:pat) => {
808            #[test]
809            fn $name() {
810                let token_stream = ::sylt_tokenizer::string_to_tokens($str);
811                let tokens: Vec<_> = token_stream.iter().map(|p| p.token.clone()).collect();
812                let spans: Vec<_> = token_stream.iter().map(|p| p.span).collect();
813                let path = ::std::path::PathBuf::from(stringify!($name));
814                let result = $f($crate::Context::new(&tokens, &spans, &path));
815                assert!(
816                    result.is_err(),
817                    "\nSyntax tree test parsed - when it should have failed - for:\n{}\n",
818                    $str,
819                );
820                let (_, result) = result.unwrap_err();
821                assert!(
822                    matches!(result, $ans),
823                    "\nExpected: {}, but got: {:?}",
824                    stringify!($ans),
825                    result
826                );
827            }
828        };
829    }
830
831    mod parse_type {
832        use super::*;
833        use RuntimeType as RT;
834        use TypeKind::*;
835
836        test!(parse_type, type_void: "void" => Resolved(RT::Void));
837        test!(parse_type, type_int: "int" => Resolved(RT::Int));
838        test!(parse_type, type_float: "float" => Resolved(RT::Float));
839        test!(parse_type, type_str: "str" => Resolved(RT::String));
840        test!(parse_type, type_unknown_access: "a.A | int" => Union(_, _));
841        test!(parse_type, type_unknown_access_call: "a.b().A | int" => Union(_, _));
842        test!(parse_type, type_unknown: "blargh" => UserDefined(_));
843        test!(parse_type, type_union: "int | int" => Union(_, _));
844        test!(parse_type, type_question: "int?" => Union(_, _));
845        test!(parse_type, type_union_and_question: "int | void | str?" => Union(_, _));
846
847        test!(parse_type, type_fn_no_params: "fn ->" => Fn(_, _));
848        test!(parse_type, type_fn_one_param: "fn int? -> bool" => Fn(_, _));
849        test!(parse_type, type_fn_two_params: "fn int | void, int? -> str?" => Fn(_, _));
850        test!(parse_type, type_fn_only_ret: "fn -> bool?" => Fn(_, _));
851
852        test!(parse_type, type_tuple_one: "(int)" => Tuple(_));
853        test!(parse_type, type_tuple_complex: "(int | float?, str, str,)" => Tuple(_));
854
855        test!(parse_type, type_list_one: "[int]" => List(_));
856        test!(parse_type, type_list_complex: "[int | float?]" => List(_));
857
858        test!(parse_type, type_set_one: "{int}" => Set(_));
859        test!(parse_type, type_set_complex: "{int | float?}" => Set(_));
860
861        test!(parse_type, type_dict_one: "{int : int}" => Dict(_, _));
862        test!(parse_type, type_dict_complex: "{int | float? : int | int | int?}" => Dict(_, _));
863    }
864}