oris 0.2.1

An interpreter for Monkey
Documentation
use super::{error, token::Kind, Lexer};

macro_rules! t {
    ($input:literal, $tokens:expr) => {
        let mut lexer = Lexer::new($input.as_bytes().into());
        for token in $tokens {
            match lexer.next() {
                Some(Ok(tk)) => assert_eq!(tk.kind, token),
                Some(Err(err)) => panic!("expect token {:?}, found error: {:?}", token, err),
                None => panic!("expect token {:?}, found EOF", token),
            }
        }
        assert!(lexer.next().is_none());
    };
}

#[test]
fn tokens() {
    t!(
        r#"
let
true
false
fn
return
if
else
foo
0
01
42
"bar"
,
:
;
()
[]
{}
+ - * /
= !
== !=
< >
<= >=
"#,
        vec![
            Kind::Let,
            Kind::True,
            Kind::False,
            Kind::Fn,
            Kind::Return,
            Kind::If,
            Kind::Else,
            Kind::Ident,
            Kind::Int,
            Kind::Int,
            Kind::Int,
            Kind::Str,
            Kind::Comma,
            Kind::Colon,
            Kind::Semicolon,
            Kind::LeftParen,
            Kind::RightParen,
            Kind::LeftBracket,
            Kind::RightBracket,
            Kind::LeftBrace,
            Kind::RightBrace,
            Kind::Plus,
            Kind::Hyphen,
            Kind::Asterisk,
            Kind::Slash,
            Kind::Assign,
            Kind::Bang,
            Kind::Eq,
            Kind::Ne,
            Kind::Lt,
            Kind::Gt,
            Kind::Le,
            Kind::Ge,
        ]
    );
}

#[test]
fn stmts() {
    t!(
        "let answer = 42;",
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::Int,
            Kind::Semicolon,
        ]
    );

    t!(
        "let is = true;",
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::True,
            Kind::Semicolon
        ]
    );

    t!(
        "let not = false;",
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::False,
            Kind::Semicolon
        ]
    );

    t!(
        "let arith = 1 + 4 * 3 / 2;",
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::Int,
            Kind::Plus,
            Kind::Int,
            Kind::Asterisk,
            Kind::Int,
            Kind::Slash,
            Kind::Int,
            Kind::Semicolon,
        ]
    );

    t!(
        "let min = fn(x, y) { if x < y { x } else { y } };",
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::Fn,
            Kind::LeftParen,
            Kind::Ident,
            Kind::Comma,
            Kind::Ident,
            Kind::RightParen,
            Kind::LeftBrace,
            Kind::If,
            Kind::Ident,
            Kind::Lt,
            Kind::Ident,
            Kind::LeftBrace,
            Kind::Ident,
            Kind::RightBrace,
            Kind::Else,
            Kind::LeftBrace,
            Kind::Ident,
            Kind::RightBrace,
            Kind::RightBrace,
            Kind::Semicolon,
        ]
    );

    t!(
        r#"let seq = [true, "==", !false];"#,
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::LeftBracket,
            Kind::True,
            Kind::Comma,
            Kind::Str,
            Kind::Comma,
            Kind::Bang,
            Kind::False,
            Kind::RightBracket,
            Kind::Semicolon,
        ]
    );

    t!(
        r#"let map = {"not true": false, 2: "two", false: 4, "seq": []};"#,
        vec![
            Kind::Let,
            Kind::Ident,
            Kind::Assign,
            Kind::LeftBrace,
            Kind::Str,
            Kind::Colon,
            Kind::False,
            Kind::Comma,
            Kind::Int,
            Kind::Colon,
            Kind::Str,
            Kind::Comma,
            Kind::False,
            Kind::Colon,
            Kind::Int,
            Kind::Comma,
            Kind::Str,
            Kind::Colon,
            Kind::LeftBracket,
            Kind::RightBracket,
            Kind::RightBrace,
            Kind::Semicolon,
        ]
    );
}

macro_rules! t_err {
    ($input:literal, $error:expr) => {
        let mut lexer = Lexer::new($input.as_bytes().into());
        assert_eq!(lexer.next().unwrap().unwrap_err().kind, $error);
    };
}

#[test]
fn errors() {
    t_err!("\"abc", error::Kind::Quote);
    t_err!("123456789123456789", error::Kind::Overflow);
    t_err!("12g", error::Kind::BadDigit);
    t_err!("0x", error::Kind::BadDigit);
    t_err!("$", error::Kind::Unexpected);
}