sl_compiler/compile/
compile_cond.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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::{compile, CompileState, SloshVm};
use compile_state::state::SloshVmTrait;
use slvm::*;

pub(crate) fn compile_if(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    if cdr.is_empty() {
        return Err(VMError::new_compile(format!(
            "requires at least one argument, got 0, line {}",
            env.line_num()
        )));
    }
    let tail = state.tail;
    state.tail = false;
    let mut cdr_i = cdr.iter().peekable();
    let jmp_idx = state.chunk.add_jump(0);
    while let Some(r) = cdr_i.next() {
        let next = cdr_i.next();
        if next.is_none() {
            state.tail = tail;
        }
        compile(env, state, *r, result)?;
        if let Some(r) = next {
            state.tail = tail;
            let jmp2_idx = state.chunk.add_jump(0);
            state
                .chunk
                .encode2(JMPF, result as u16, jmp2_idx as u16, env.own_line())?;
            compile(env, state, *r, result)?;
            if cdr_i.peek().is_some() {
                state.chunk.encode1(JMP, jmp_idx as u16, env.own_line())?;
            }
            state
                .chunk
                .update_jump(jmp2_idx, state.chunk.code.len() as u32);
        }
        state.tail = false;
    }
    state
        .chunk
        .update_jump(jmp_idx, state.chunk.code.len() as u32);
    Ok(())
}

pub(crate) fn compile_while(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    let mut cdr_i = cdr.iter();
    if let Some(conditional) = cdr_i.next() {
        let jmp_cond = state.chunk.add_jump(0);
        state.chunk.encode1(JMP, jmp_cond as u16, env.own_line())?;
        let jmp_loop_start = state.chunk.add_jump(state.chunk.code.len() as u32);
        for r in cdr_i {
            compile(env, state, *r, result)?;
        }

        state
            .chunk
            .update_jump(jmp_cond, state.chunk.code.len() as u32);
        compile(env, state, *conditional, result)?;
        state
            .chunk
            .encode2(JMPT, result as u16, jmp_loop_start as u16, env.own_line())?;
        Ok(())
    } else {
        Err(VMError::new_compile(format!(
            "requires at least one argument, got 0, line {}",
            env.line_num()
        )))
    }
}

pub(crate) fn compile_and(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    if cdr.is_empty() {
        return Err(VMError::new_compile(format!(
            "requires at least one argument, got 0, line {}",
            env.line_num()
        )));
    }
    let tail = state.tail;
    state.tail = false;
    let mut cdr_i = cdr.iter().peekable();
    let mut next = cdr_i.next();
    let jmp_idx = state.chunk.add_jump(0);
    while let Some(r) = next {
        next = cdr_i.next();
        if next.is_none() {
            state.tail = tail;
        }
        compile(env, state, *r, result)?;
        if next.is_some() {
            state
                .chunk
                .encode2(JMPF, result as u16, jmp_idx as u16, env.own_line())?;
        }
        state.tail = false;
    }
    let end_ip = state.chunk.code.len();
    state.chunk.update_jump(jmp_idx, end_ip as u32);
    Ok(())
}

pub(crate) fn compile_or(
    env: &mut SloshVm,
    state: &mut CompileState,
    cdr: &[Value],
    result: usize,
) -> VMResult<()> {
    if cdr.is_empty() {
        return Err(VMError::new_compile(format!(
            "requires at least one argument, got 0, line {}",
            env.line_num()
        )));
    }
    let tail = state.tail;
    state.tail = false;
    let mut cdr_i = cdr.iter().peekable();
    let mut next = cdr_i.next();
    let jmp_idx = state.chunk.add_jump(0);
    while let Some(r) = next {
        next = cdr_i.next();
        if next.is_none() {
            state.tail = tail;
        }
        compile(env, state, *r, result)?;
        if next.is_some() {
            state
                .chunk
                .encode2(JMPT, result as u16, jmp_idx as u16, env.own_line())?;
        }
        state.tail = false;
    }
    let end_ip = state.chunk.code.len();
    state.chunk.update_jump(jmp_idx, end_ip as u32);
    Ok(())
}