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 Nil,
15 Bool(bool),
16 Number(f64),
17 String(RcStr),
18 MakeList(u32),
19 NewFunc(Rc<Code>),
20
21 Pop,
23 Dup,
24 Dup2,
25 Unpack(u32),
26
27 Get(VarScope, u32),
29 Set(VarScope, u32),
30 Tee(VarScope, u32),
31
32 Goto(u32),
34 GotoIfFalse(u32),
35 GotoIfFalseNoPop(u32),
36
37 Return,
39 Yield,
40 Next,
41 CallFunc(u32),
42 Binop(Binop),
43 Unop(Unop),
44 Print,
45 Disasm,
46
47 AddToTest,
49 Assert,
50 AssertEq,
51
52 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 Equal,
65 NotEqual,
66 LessThan,
67 LessThanOrEqual,
68 GreaterThan,
69 GreaterThanOrEqual,
70
71 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>, pub def: Vec<(RcStr, Val)>, pub var: Option<RcStr>, }
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 assert_eq!(size_of::<Binop>(), size_of::<ArithmeticBinop>());
272 }
273}