~tim/scheme-vm

scheme-vm/src/lib.rs -rw-r--r-- 1.5 KiB
00cdee12Tim Morgan Remove old code 3 years ago
                                                                                
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
extern crate libc;
extern crate ruby_sys;
#[macro_use]
extern crate lazy_static;

#[macro_use] mod rb;
use rb::{CallbackPtr, Value, RB_NIL};

mod atom;
mod quotes;

mod lisp {
    include!(concat!(env!("OUT_DIR"), "/lisp.rs"));
}

fn parse_native(rself: Value) -> Value {
    let code = rbstr2str!(&rb::ivar_get(&rself, "@code"));
    let filename_rbstr = rb::ivar_get(&rself, "@filename");
    let filename = rbstr2str!(&filename_rbstr);
    let newlines: Vec<usize> = code.match_indices("\n").map(|(i, _s)| i).collect();
    rb::gc_disable();
    match lisp::program(&code, &filename, &newlines) {
        Ok(ast) => {
            rb::gc_enable();
            ast
        },
        Err(err) => {
            raise_syntax_error(err, filename_rbstr);
            RB_NIL
        }
    }
}

fn raise_syntax_error(err: lisp::ParseError, filename_rbstr: Value) {
    let c_parser = rb::const_get("Parser", &RB_NIL);
    let c_parse_error = rb::const_get("ParseError", &c_parser);
    let line = int2rbnum!(err.line);
    let column = int2rbnum!(err.column);
    let mut expected = rb::ary_new();
    for token in err.expected {
        expected = rb::ary_push(expected, rb::str_new(token));
    }
    let error = rb::class_new_instance(&c_parse_error, vec![filename_rbstr, line, column, expected]);
    rb::gc_enable();
    rb::raise_instance(&error);
}

#[no_mangle]
pub extern fn init_parser() {
    let c_parser = rb::const_get("Parser", &RB_NIL);
    rb::define_method(&c_parser, "parse_native", parse_native as CallbackPtr, 0);
}