smol lang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#![feature(iter_intersperse, let_chains)]
use chumsky::error::RichReason;
use comat::cformat as cmt;
use std::process::ExitCode;
mod lexer;
mod parser;

fn main() -> ExitCode {
    let Some(Ok(code)) = std::env::args().nth(1).map(std::fs::read_to_string) else {
        comat::cprintln!("{bold_red}error{reset}: where file?");
        return ExitCode::FAILURE;
    };
    let lexer = lexer::lex(&code);
    match parser::parse(lexer, code.len()) {
        Ok(x) => dbg!(x),
        Err(e) => {
            for e in e.into_iter().map(|e| e.map_token(|c| c.to_string())) {
                let mut o = lerr::Error::new(&code);
                o.label((e.span().into_range(), "here"));
                match e.reason() {
                    RichReason::Custom(x) => {
                        o.message(cmt!("{red}error{reset}: {x}"));
                    }
                    RichReason::ExpectedFound { .. } => {
                        o.message(cmt!("{red}error{reset}: {e}"));
                    }
                    RichReason::Many(x) => {
                        match &x[..] {
                            [x, rest @ ..] => {
                                o.message(cmt!("{red}error{reset}: {x}"));
                                for elem in rest {
                                    o.note(cmt!("{yellow}also{reset}: {elem}"));
                                }
                            }
                            _ => unreachable!(),
                        };
                    }
                }
                for (l, span) in e.contexts() {
                    o.label((
                        span.into_range(),
                        cmt!("{yellow}while parsing this{reset}: {l}"),
                    ));
                }
                eprintln!("{o}");
            }
            return ExitCode::FAILURE;
        }
    };

    ExitCode::SUCCESS
}