aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
blob: fd9c094b9225946fb387b18d73e5ce5d800e14de (plain) (blame)
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::path::Path;
use std::rc::Rc;

pub mod compiler;
pub mod tokenizer;
pub mod vm;

mod error;

use error::Error;
use tokenizer::TokenStream;

pub fn run_file(path: &Path) -> Result<(), Vec<Error>> {
    run(tokenizer::file_to_tokens(path), path)
}

pub fn run_string(s: &str) -> Result<(), Vec<Error>> {
    run(tokenizer::string_to_tokens(s), Path::new("builtin"))
}

pub fn run(tokens: TokenStream, path: &Path) -> Result<(), Vec<Error>> {
    match compiler::compile("main", path, tokens) {
        Ok(block) => vm::run_block(Rc::new(block)).or_else(|e| Err(vec![e])),
        Err(errors) => Err(errors),
    }
}

#[cfg(test)]
mod tests {
    use super::{run_file, run_string};
    use crate::error::{Error, ErrorKind};
    use std::path::Path;

    macro_rules! assert_errs {
        ($result:expr, [ $( $kind:pat ),* ]) => {
            println!("{} => {:?}", stringify!($result), $result);
            assert!(matches!(
                $result.unwrap_err().as_slice(),
                &[$(Error {
                    kind: $kind,
                    file: _,
                    line: _,
                    message: _,
                },
                )*]
            ))
        };
    }

    #[test]
    fn unreachable_token() {
        assert_errs!(run_string("<!>\n"), [ErrorKind::Unreachable]);
    }

    macro_rules! test_file {
        ($fn:ident, $path:literal) => {
            #[test]
            fn $fn() {
                let file = Path::new($path);
                assert!(run_file(&file).is_ok());
            }
        };
    }

    test_file!(order_of_operations, "tests/order-of-operations.tdy");
    test_file!(variables, "tests/variables.tdy");
    test_file!(scoping, "tests/scoping.tdy");
    test_file!(if_, "tests/if.tdy");
    test_file!(for_, "tests/for.tdy");
    test_file!(fun, "tests/fun.tdy");
}