aboutsummaryrefslogtreecommitdiffstats
path: root/src/main.rs
blob: 0f67aa423fd0519e88dfce6a56a7c75dd22bee97 (plain)
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

use std::io;
use std::env;
use std::io::Write;
use std::path::Path;

mod sexpr;
mod cexpr;

use cexpr::CExpr;

fn repl(verbose: bool) {

    let stdin = io::stdin();
    let mut stdout = io::stdout();

    loop {
        let raw_input = &mut String::new();
        stdout.write(b"\ncasual> ").unwrap();
        stdout.flush().unwrap();
        stdin.read_line(raw_input).unwrap();
        let raw_input = raw_input; // mutable to immutable reference
        if raw_input.len() == 0 {
            // end-of-line, aka Ctrl-D. Blank line will still have newline char
            stdout.write(b"\nCiao!\n").unwrap();
            return;
        }
        // TODO: use debug or something instead of "verbose"?
        let tokens = match sexpr::sexpr_tokenize(&raw_input) {
            Ok(tokens) => {
                if verbose { println!("Tokens: {}", tokens.join(", ")); };
                tokens
            },
            Err(e) => {
                println!("couldn't tokenize: {}", e);
                continue;
            }
        };
        let ast = match sexpr::sexpr_parse(&tokens, 0) {
            Ok((mut ast_list, _)) => {
                if verbose {
                    for ast in &ast_list {
                        println!("AST: {}", sexpr::sexpr_repr(ast).unwrap());
                    };
                };
                // We're a REPL, so only one expression at a time
                if ast_list.len() > 1 {
                    println!("one expression at a time on the REPL, please!");
                    continue;
                } else if ast_list.len() == 0 {
                    sexpr::SExpr::SNull
                } else {
                    let ast = ast_list.pop().unwrap();
                    ast
                }
            },
            Err(e) => {
                println!("couldn't parse: {}", e);
                continue;
            }
        };
        let expr = match CExpr::from_sexpr(&ast) {
            Ok(v) => v,
            Err(e) => {
                println!("couldn't parse as math: {}", e);
                continue;
            },
        };
        match expr.to_sexpr() {
            Ok(out) => println!("{}", sexpr::sexpr_repr(&ast).unwrap()),
            Err(e) => {
                println!("couldn't return to sexpr: {}", e);
                continue;
            },

        }
    }
}

fn usage() {
    println!("usage:\tcasual [-h] [-v] [--no-repl] [<files>]");
    println!("");
    println!("Files will be loaded in order, then drop to REPL (unless \"--no-repl\" is passed).");
    println!("Verbose flag (\"-v\") will result in lexed tokens and parsed AST \
        being dumped to stdout (when on REPL).");
}

fn main() {

    let mut verbose: bool = false;
    let mut no_repl: bool = false;

    let mut file_list = Vec::<String>::new();

    for arg in env::args().skip(1) {
        match &*arg {
            "-v" | "--verbose"  => { verbose = true; },
            "--no-repl"         => { no_repl = true; },
            "-h" | "--help"     => { usage(); return; },
            _ if arg.starts_with("-") => {
                println!("Unknown option: {}", arg);
                println!("");
                usage();
                return;
            },
            _ => {
                file_list.push(arg.clone());
            }
        }
    }

    for fname in file_list {
        let fpath = Path::new(&fname);
        if !fpath.is_file() {
            println!("File not found (or not file): {}", fname);
            return;
        }
        println!("Loading {}...", fname);
        match sexpr::sexpr_parse_file(&fpath) {
            Err(e) => {
                println!("Error loading file: {}\n    {}", fname, e);
                return;
            },
            Ok(_) => ()
        }
    }

    if !no_repl {
        repl(verbose);
    }
}