kb/
code.rs

1use super::BasicError;
2use super::Mark;
3use super::RcStr;
4use super::Val;
5use super::Var;
6use super::VarScope;
7use std::collections::HashMap;
8use std::fmt;
9use std::rc::Rc;
10
11#[derive(Debug)]
12pub enum Opcode {
13    // Load constants
14    Nil,
15    Bool(bool),
16    Number(f64),
17    String(RcStr),
18    MakeList(u32),
19    NewFunc(Rc<Code>),
20
21    // stack manipulation
22    Pop,
23    Dup,
24    Dup2,
25    Unpack(u32),
26
27    // variable access
28    Get(VarScope, u32),
29    Set(VarScope, u32),
30    Tee(VarScope, u32),
31
32    // control flow
33    Goto(u32),
34    GotoIfFalse(u32),
35    GotoIfFalseNoPop(u32),
36
37    // operators
38    Return,
39    Yield,
40    Next,
41    CallFunc(u32),
42    Binop(Binop),
43    Unop(Unop),
44    Print,
45    Disasm,
46
47    // Testing
48    AddToTest,
49    Assert,
50    AssertEq,
51
52    // (should come last) unresolved control flow ops
53    Label(RcStr),
54    UnresolvedGoto(RcStr),
55    UnresolvedGotoIfFalse(RcStr),
56    UnresolvedGotoIfFalseNoPop(RcStr),
57}
58
59#[derive(Debug, Clone, Copy)]
60pub enum Binop {
61    Arithmetic(ArithmeticBinop),
62
63    // comparison
64    Equal,
65    NotEqual,
66    LessThan,
67    LessThanOrEqual,
68    GreaterThan,
69    GreaterThanOrEqual,
70
71    // list
72    Append,
73}
74
75#[derive(Debug, Clone, Copy)]
76pub enum ArithmeticBinop {
77    Add,
78    Subtract,
79    Multiply,
80    Divide,
81    TruncDivide,
82    Remainder,
83}
84
85#[derive(Debug, Clone, Copy)]
86pub enum Unop {
87    Arithmetic(ArithmeticUnop),
88
89    Len,
90}
91
92#[derive(Debug, Clone, Copy)]
93pub enum ArithmeticUnop {
94    Negative,
95    Positive,
96}
97
98#[derive(Clone)]
99pub struct ArgSpec {
100    pub req: Vec<RcStr>,        // required parameters
101    pub def: Vec<(RcStr, Val)>, // default parameters
102    pub var: Option<RcStr>,     // variadic parameter
103}
104
105impl ArgSpec {
106    pub fn empty() -> Self {
107        Self {
108            req: vec![],
109            def: vec![],
110            var: None,
111        }
112    }
113}
114
115pub struct Code {
116    generator: bool,
117    name: RcStr,
118    argspec: ArgSpec,
119    vars: Vec<Var>,
120    ops: Vec<Opcode>,
121    marks: Vec<Mark>,
122    label_map: HashMap<RcStr, u32>,
123}
124
125impl fmt::Debug for Code {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        write!(f, "Code({})", self.name)
128    }
129}
130
131fn not_found(mark: Mark, name: &RcStr) -> BasicError {
132    BasicError {
133        marks: vec![mark],
134        message: format!("Label {:?} not found", name),
135        help: None,
136    }
137}
138
139impl Code {
140    pub fn new(generator: bool, name: RcStr, argspec: ArgSpec, vars: Vec<Var>) -> Self {
141        Self {
142            generator,
143            name,
144            argspec,
145            vars,
146            ops: vec![],
147            marks: vec![],
148            label_map: HashMap::new(),
149        }
150    }
151    pub fn generator(&self) -> bool {
152        self.generator
153    }
154    pub fn resolve_labels(&mut self) -> Result<(), BasicError> {
155        let mut labels = HashMap::new();
156        let mut pos = 0;
157        for op in self.ops.iter() {
158            if let Opcode::Label(name) = op {
159                labels.insert(name.clone(), pos as u32);
160            } else {
161                pos += 1;
162            }
163        }
164        let old_ops = std::mem::replace(&mut self.ops, vec![]);
165        let old_marks = std::mem::replace(&mut self.marks, vec![]);
166        let mut new_ops = Vec::new();
167        let mut new_marks = Vec::new();
168        pos = 0;
169        for (i, (mut op, mark)) in old_ops.into_iter().zip(old_marks).enumerate() {
170            if let Opcode::Label(_) = op {
171                continue;
172            }
173            match &op {
174                Opcode::Label(_) => {}
175                Opcode::UnresolvedGoto(label) => {
176                    if let Some(pos) = labels.get(label).cloned() {
177                        op = Opcode::Goto(pos);
178                    } else {
179                        return Err(not_found(self.marks[i].clone(), label));
180                    }
181                }
182                Opcode::UnresolvedGotoIfFalse(label) => {
183                    if let Some(pos) = labels.get(label).cloned() {
184                        op = Opcode::GotoIfFalse(pos);
185                    } else {
186                        return Err(not_found(self.marks[i].clone(), label));
187                    }
188                }
189                Opcode::UnresolvedGotoIfFalseNoPop(label) => {
190                    if let Some(pos) = labels.get(label).cloned() {
191                        op = Opcode::GotoIfFalseNoPop(pos);
192                    } else {
193                        return Err(not_found(self.marks[i].clone(), &label));
194                    }
195                }
196                _ => {}
197            }
198            new_ops.push(op);
199            new_marks.push(mark);
200            pos += 1;
201        }
202        self.label_map = labels;
203        self.ops = new_ops;
204        self.marks = new_marks;
205        Ok(())
206    }
207    pub fn add(&mut self, op: Opcode, mark: Mark) {
208        self.ops.push(op);
209        self.marks.push(mark);
210        assert_eq!(self.ops.len(), self.marks.len());
211    }
212    pub fn len(&self) -> usize {
213        self.ops.len()
214    }
215    pub fn name(&self) -> &RcStr {
216        &self.name
217    }
218    pub fn argspec(&self) -> &ArgSpec {
219        &self.argspec
220    }
221    pub fn vars(&self) -> &Vec<Var> {
222        &self.vars
223    }
224    pub fn ops(&self) -> &Vec<Opcode> {
225        &self.ops
226    }
227    pub fn ops_mut(&mut self) -> &mut Vec<Opcode> {
228        &mut self.ops
229    }
230    pub fn marks(&self) -> &Vec<Mark> {
231        &self.marks
232    }
233    pub fn fetch(&self, i: usize) -> &Opcode {
234        &self.ops[i]
235    }
236    pub fn format(&self) -> RcStr {
237        use std::fmt::Write;
238        let mut ret = String::new();
239        let out = &mut ret;
240        let mut last_lineno = 0;
241        writeln!(out, "## Code for {} ##", self.name).unwrap();
242        writeln!(out, "#### labels ####").unwrap();
243        let mut labels: Vec<(RcStr, u32)> = self.label_map.clone().into_iter().collect();
244        labels.sort_by_key(|a| a.1);
245        for (label_name, label_index) in labels {
246            writeln!(out, "  {} -> {}", label_name, label_index).unwrap();
247        }
248        writeln!(out, "#### opcodes ####").unwrap();
249        for (i, op) in self.ops.iter().enumerate() {
250            let lineno = self.marks[i].lineno();
251            let ln = if lineno == last_lineno {
252                format!("")
253            } else {
254                format!("{}", lineno)
255            };
256            last_lineno = lineno;
257            writeln!(out, "  {:>4} {:>4}: {:?}", i, ln, op).unwrap();
258        }
259        ret.into()
260    }
261}
262
263#[cfg(test)]
264mod tests {
265    use super::*;
266    use std::mem::size_of;
267
268    #[test]
269    fn enum_sizes() {
270        // checking that rust will properly fold nested enums
271        assert_eq!(size_of::<Binop>(), size_of::<ArithmeticBinop>());
272    }
273}