sl_compiler/compile/
compile_store.rs

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
use crate::{compile, CompileState, SloshVm};
use compile_state::state::SloshVmTrait;
use slvm::*;

fn get_global_with_ns(env: &mut SloshVm, si: Interned) -> u32 {
    if env.env().get_namespace().name().is_empty() {
        env.get_reserve_global(si)
    } else {
        let mut ns = env.env().get_namespace().name().to_string();
        ns.push_str("::");
        ns.push_str(env.get_interned(si));
        let i = env.intern(&ns);
        env.get_reserve_global(i)
    }
}

pub(crate) fn compile_def(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    match (cdr.len(), cdr.first()) {
        (_, None) => return Err(VMError::new_compile("def: expected symbol")),
        (1, Some(Value::Symbol(si))) => {
            // 'def symbol' predeclares a symbol to be used later, no bytecode.
            let si_const = get_global_with_ns(env, *si);
            if let Some(doc_string) = state.doc_string {
                let key = env.intern("doc-string");
                env.set_global_property(si_const, key, doc_string);
                state.doc_string = None;
            }
        }
        (2, Some(Value::Symbol(si))) => {
            let si_const = get_global_with_ns(env, *si);
            if let Some(doc_string) = state.doc_string {
                let key = env.intern("doc-string");
                env.set_global_property(si_const, key, doc_string);
                state.doc_string = None;
            }
            compile(env, state, cdr[1], result)?;
            state
                .chunk
                .encode_def(result as u16, si_const, env.own_line(), false)?;
        }
        _ => return Err(VMError::new_compile("def: malformed")),
    }
    Ok(())
}

pub(crate) fn compile_set(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    if cdr.len() == 2 {
        if let Value::Symbol(si) = cdr[0] {
            if let Some(idx) = state.get_symbol(si) {
                compile(env, state, cdr[1], result)?;
                state
                    .chunk
                    .encode2(SET, idx as u16, result as u16, env.own_line())?;
            } else if let Some(si_const) = env.global_intern_slot(si) {
                compile(env, state, cdr[1], result)?;
                state
                    .chunk
                    .encode_def(result as u16, si_const, env.own_line(), false)?;
            } else {
                let sym = env.get_interned(si);
                return Err(VMError::new_compile(format!("Symbol {sym} not defined (maybe you need to use 'def {sym}' to pre-declare it).")));
            }
        } else {
            match cdr[0].get_pair(env) {
                Some((Value::Symbol(i), ncdr)) if i == env.specials().get => {
                    if cdr.len() != 2 {
                        return Err(VMError::new_compile(
                            "Wrong number of arguments, expected two.",
                        ));
                    }
                    compile(env, state, cdr[1], result)?;
                    let mut cdr_i = ncdr.iter(env);
                    let collection = cdr_i.next().expect("had two elements!");
                    let field = cdr_i.next().expect("had two elements!");
                    drop(cdr_i);
                    compile(env, state, collection, result + 1)?;
                    compile(env, state, field, result + 2)?;
                    state.chunk.encode3(
                        SETCOL,
                        result as u16,
                        (result + 1) as u16,
                        (result + 2) as u16,
                        env.own_line(),
                    )?;
                }
                _ => return Err(VMError::new_compile("set!: expected symbol")),
            }
        }
    } else {
        return Err(VMError::new_compile("set!: malformed"));
    }
    Ok(())
}