aboutsummaryrefslogtreecommitdiffstats
path: root/minimal.rs
blob: 34b3172eba48f77a0bef0c3159e7b54abe22131b (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

// A partial Scheme implementation in Rust
// Build with: rustc minimal.rs -o minimal-rust

use std::io;
use std::io::Write;

// There doesn't seem to be a symbole or quote type in Rust, so i'm going to use strings and
// vectors

// "list of tokens" implemented as a vector of String.
// AST implemented as nested tuples (immutable).

//let const SCHEME_BUILTINS = ("lambda", "quote", "cond", "else", "cons", "car", "cdr", "null?", "eq?", "atom?", "zero?", "number?", "+", "-", "*", "/");

#[allow(dead_code)]
enum SchemeExpr<'a> {
    SchemeNull,
    SchemeTrue,
    SchemeFalse,
    SchemeNum(f64),
    SchemeBuiltin(&'a str),
    SchemeStr(&'a str),
    SchemeList(Vec<SchemeExpr<'a>>),
}

///////////////////////////////////

fn is_zero(n: f64) -> bool {
    return n == 0.;
}

///////////////////////////////////

//let sep = ('(', ')');
//let ws = (' ', '\t', '\n');
// TODO: this doesn't handle strings properly. Eg:
//   (quote "this ) will ( fail")
fn scheme_tokenize<'a>(raw_str: &'a str) -> Result<Vec<&'a str>, &'static str> {
    let mut ret = Vec::<&str>::new();
    for s in raw_str.split_whitespace() {
        if s.len() > 1 && s.starts_with('(') {
            let (paren, el) = s.split_at(1);
            ret.push("(");
            ret.push(el);
        } else if s.len() > 1 && s.ends_with(')') {
            let (el, paren) = s.split_at(s.len() - 1);
            ret.push(el);
            ret.push(")");
        } else if s.len() > 0 {
            ret.push(s);
        }
    }
    return Ok(ret);
}

fn scheme_parse_num(s: &String) -> Result<f64, &'static str> {
    let num = 0.;
    return Ok(num);
}

fn scheme_parse_sexpr<'a>(sexpr: &Vec<&'a str>) -> Result<SchemeExpr<'a>, &'static str> {
    let ret = sexpr.into_iter().map(|el| SchemeExpr::SchemeStr(el)).collect();
    return Ok(SchemeExpr::SchemeList(ret))
}

fn scheme_parse<'a>(tokens: &SchemeExpr) -> Result<SchemeExpr<'a>, &'static str> {
    return Ok(SchemeExpr::SchemeNull);
}

fn scheme_eval<'a>(ast: &SchemeExpr) -> Result<SchemeExpr<'a>, &'static str> {
    return Ok(SchemeExpr::SchemeNull);
}

fn scheme_repr<'a>(ast: &SchemeExpr) -> Result<String, &'static str> {
    return match ast {
        &SchemeExpr::SchemeTrue => Ok("#t".to_string()),
        &SchemeExpr::SchemeFalse => Ok("#t".to_string()),
        &SchemeExpr::SchemeNull => Ok("'()".to_string()),
        &SchemeExpr::SchemeList(ref list) => {
            let mut ret: String =
                list.iter().fold("(".to_string(),
                                 |acc, ref el| acc + &scheme_repr(&el).unwrap());
            ret.push_str(")");
            Ok(ret)
        },
        _ => Err("don't know how to repr something"),
    }
}

fn main() {

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

    loop {
        let raw_input = &mut String::new();
        stdout.write(b"\nminimal-rust> ").unwrap();
        stdout.flush().unwrap();
        stdin.read_line(raw_input).unwrap();
        let raw_input = raw_input;  // UGH
        if raw_input.len() == 0 {
            stdout.write(b"\nCiao!\n").unwrap();
            return;
        }
        let tokens = scheme_tokenize(&raw_input).unwrap();
        println!("Tokens: {}", tokens.join(", "));
        let sexpr = scheme_parse_sexpr(&tokens).unwrap();
        let ast = scheme_parse(&sexpr).unwrap();
        let resp = scheme_eval(&ast).unwrap();
        println!("{}", scheme_repr(&resp).unwrap());
    }
}