1use super::ArgSpec;
2use super::ArithmeticBinop;
3use super::ArithmeticUnop;
4use super::Binop;
5use super::Code;
6use super::Func;
7use super::GenObjPtr;
8use super::Handler;
9use super::Mark;
10use super::Opcode;
11use super::RcStr;
12use super::Unop;
13use super::Val;
14use super::Var;
15use std::cell::RefCell;
16use std::collections::HashMap;
17use std::rc::Rc;
18
19pub struct Vm<H: Handler> {
20 scope: Scope,
21 handler: H,
22}
23
24impl<H: Handler> Vm<H> {
25 pub fn new(handler: H) -> Self {
26 Self {
27 scope: Scope::new(),
28 handler,
29 }
30 }
31 pub fn exec(&mut self, code: &Code) -> Result<(), Val> {
32 for var in code.vars() {
33 self.scope.globals.insert(var.name.clone(), Val::Nil);
34 }
35 exec(&mut self.scope, &mut self.handler, code)?;
36 Ok(())
37 }
38 pub fn run_tests(&mut self, prefixes: &Vec<RcStr>) -> Result<(), Val> {
39 let tests = std::mem::replace(&mut self.scope.tests, vec![]);
40 for test in tests {
41 if prefixes
42 .iter()
43 .any(|prefix| test.name().starts_with(prefix.as_ref()))
44 {
45 print!(" test {}... ", test.name());
46 callfunc(&mut self.scope, &mut self.handler, &test, vec![])?;
47 println!("ok");
48 }
49 }
50 Ok(())
51 }
52 pub fn exec_and_run_tests(&mut self, code: &Code, prefixes: &Vec<RcStr>) -> Result<(), Val> {
53 self.exec(code)?;
54 self.run_tests(prefixes)
55 }
56 pub fn trace(&self) -> &Vec<Mark> {
57 &self.scope.trace
58 }
59}
60
61pub fn callfunc<H: Handler>(
62 scope: &mut Scope,
63 handler: &mut H,
64 func: &Code,
65 mut args: Vec<Val>,
66) -> Result<Val, Val> {
67 let spec = func.argspec();
69 prepare_args(spec, &mut args)?;
70
71 scope.push(func.vars());
73 for (i, arg) in args.into_iter().enumerate() {
74 scope.set(VarScope::Local, i as u32, arg);
75 }
76 let ret = exec(scope, handler, func)?;
77 scope.pop();
78 Ok(ret)
79}
80
81fn mkgenobj(func: Rc<Code>, mut args: Vec<Val>) -> Result<Val, Val> {
82 prepare_args(func.argspec(), &mut args)?;
83 let mut locals = new_locals_from_vars(func.vars());
84 for (i, arg) in args.into_iter().enumerate() {
85 locals.set_by_index(i as u32, arg);
86 }
87 let genobj = GenObj {
88 code: func,
89 locals,
90 i: 0,
91 stack: vec![],
92 };
93
94 Ok(Val::GenObj(GenObjPtr(Rc::new(RefCell::new(genobj)))))
95}
96
97fn prepare_args(spec: &ArgSpec, args: &mut Vec<Val>) -> Result<(), Val> {
98 if spec.var.is_some() || spec.def.len() > 0 {
99 let argc = args.len();
101 let argmin = spec.req.len();
102 let argmax = argmin + spec.def.len();
103 if spec.var.is_some() {
104 if argc < argmin {
105 return Err(Val::String(
106 format!("Expected at least {} args but got {}", argmin, argc).into(),
107 ));
108 }
109 } else {
110 if argc < argmin || argc > argmax {
111 return Err(Val::String(
112 format!("Expected {} to {} args but got {}", argmin, argmax, argc).into(),
113 ));
114 }
115 }
116 let def = &spec.def;
117 for i in argc..argmax {
118 let default_val = def[i - argmin].1.clone();
119 args.push(default_val);
120 }
121 if spec.var.is_some() {
122 let rem_args: Vec<Val> = if argmax < argc {
123 args.drain(argmax..argc).collect()
124 } else {
125 vec![]
126 };
127 args.push(rem_args.into());
128 }
129 } else {
130 if args.len() != spec.req.len() {
132 return Err(Val::String(
133 format!("Expected {} args but got {}", spec.req.len(), args.len()).into(),
134 ));
135 }
136 }
137 Ok(())
138}
139
140pub fn exec<H: Handler>(scope: &mut Scope, handler: &mut H, code: &Code) -> Result<Val, Val> {
141 let mut i = 0;
142 let mut stack = Vec::new();
143 while i < code.len() {
144 match step(scope, handler, code, &mut i, &mut stack)? {
145 StepVal::Return(val) => return Ok(val),
146 StepVal::Yield(_) => return Err("Yielding does not make sense here".into()),
147 StepVal::None => {}
148 }
149 }
150 assert!(stack.is_empty());
151 Ok(Val::Nil)
152}
153
154enum StepVal {
155 Return(Val),
156 Yield(Val),
157 None,
158}
159
160fn step<H: Handler>(
161 scope: &mut Scope,
162 handler: &mut H,
163 code: &Code,
164 i: &mut usize,
165 stack: &mut Vec<Val>,
166) -> Result<StepVal, Val> {
167 let op = code.fetch(*i);
168 *i += 1;
169 match op {
170 Opcode::Nil => {
171 stack.push(Val::Nil);
172 }
173 Opcode::Bool(x) => {
174 stack.push(Val::Bool(*x));
175 }
176 Opcode::Number(x) => {
177 stack.push(Val::Number(*x));
178 }
179 Opcode::String(x) => {
180 stack.push(Val::String(x.clone()));
181 }
182 Opcode::MakeList(len) => {
183 let start = stack.len() - *len as usize;
184 let list: Vec<_> = stack.drain(start..).collect();
185 stack.push(list.into());
186 }
187 Opcode::NewFunc(code) => {
188 stack.push(Val::Func(Func(code.clone())));
189 }
190 Opcode::Pop => {
191 stack.pop().unwrap();
192 }
193 Opcode::Dup => {
194 let x = stack.last().unwrap().clone();
195 stack.push(x);
196 }
197 Opcode::Dup2 => {
198 let len = stack.len();
199 let a = stack[len - 2].clone();
200 let b = stack[len - 1].clone();
201 stack.push(a);
202 stack.push(b);
203 }
204 Opcode::Unpack(n) => {
205 let elements = stack.pop().unwrap();
206 if let Some(list) = elements.list() {
207 if list.borrow().len() != *n as usize {
208 scope.push_trace(code.marks()[*i - 1].clone());
209 return Err(Val::String(
210 format!(
211 "Expected {} values, but got a list with {} values",
212 n,
213 list.borrow().len(),
214 )
215 .into(),
216 ));
217 }
218 for item in list.borrow().iter() {
219 stack.push(item.clone());
220 }
221 } else {
222 let genobj = elements.expect_genobj()?;
223 let mut genobj = genobj.0.borrow_mut();
224 let vec = genobj.to_vec(scope, handler)?;
225 if vec.len() != *n as usize {
226 scope.push_trace(code.marks()[*i - 1].clone());
227 return Err(Val::String(
228 format!("Expected {} values, but got {} values", n, vec.len(),).into(),
229 ));
230 }
231 stack.extend(vec);
232 }
233 }
234 Opcode::Get(vscope, index) => {
235 let val = scope.get(*vscope, *index).clone();
236 if let Val::Invalid = val {
237 return Err(Val::String(
238 format!(
239 "Variable {} used before being set",
240 scope.get_name(*vscope, *index)
241 )
242 .into(),
243 ));
244 }
245 stack.push(val);
246 }
247 Opcode::Set(vscope, index) => {
248 let val = stack.pop().unwrap();
249 scope.set(*vscope, *index, val);
250 }
251 Opcode::Tee(vscope, index) => {
252 let val = stack.last().unwrap().clone();
253 scope.set(*vscope, *index, val);
254 }
255 Opcode::Return => {
256 let val = stack.pop().unwrap();
257 return Ok(StepVal::Return(val));
258 }
259 Opcode::Yield => {
260 let val = stack.pop().unwrap();
261 return Ok(StepVal::Yield(val));
262 }
263 Opcode::Next => {
264 let genobj = stack.last().unwrap().clone();
265 let genobj = genobj.expect_genobj()?;
266 let mut genobj = genobj.0.borrow_mut();
267 match genobj.resume(scope, handler, Val::Nil)? {
268 Some(val) => {
269 stack.push(val);
270 stack.push(true.into());
271 }
272 None => {
273 stack.push(Val::Nil);
274 stack.push(false.into());
275 }
276 }
277 }
278 Opcode::CallFunc(argc) => {
279 let old_len = stack.len();
280 let new_len = old_len - (*argc as usize);
281 let args: Vec<Val> = stack.drain(new_len..).collect();
282 let func = stack.pop().unwrap();
283 let func = if let Some(func) = func.func() {
284 func
285 } else {
286 scope.push_trace(code.marks()[*i - 1].clone());
287 return Err(format!("{} is not a function", func).into());
288 };
289
290 scope.push_trace(code.marks()[*i - 1].clone());
291 if func.generator() {
292 let genobj = mkgenobj(func.clone(), args)?;
294 stack.push(genobj);
295 } else {
296 let ret = callfunc(scope, handler, &func, args)?;
298 stack.push(ret);
299 }
300 scope.pop_trace();
301 }
302 Opcode::Binop(op) => {
303 let rhs = stack.pop().unwrap();
304 let lhs = stack.pop().unwrap();
305 let ret = match op {
306 Binop::Arithmetic(aop) => {
308 let lhs = if let Some(lhs) = lhs.number() {
309 lhs
310 } else {
311 scope.push_trace(code.marks()[*i - 1].clone());
312 return Err(format!(
313 concat!(
314 "The left hand side of this arithmetic operation ",
315 "should be a number but got {:?}"
316 ),
317 lhs
318 )
319 .into());
320 };
321 let rhs = if let Some(rhs) = rhs.number() {
322 rhs
323 } else {
324 scope.push_trace(code.marks()[*i - 1].clone());
325 return Err(format!(
326 concat!(
327 "The right hand side of this arithmetic operation ",
328 "should be a number but got {:?}"
329 ),
330 rhs
331 )
332 .into());
333 };
334 match aop {
335 ArithmeticBinop::Add => Val::Number(lhs + rhs),
336 ArithmeticBinop::Subtract => Val::Number(lhs - rhs),
337 ArithmeticBinop::Multiply => Val::Number(lhs * rhs),
338 ArithmeticBinop::Divide => Val::Number(lhs / rhs),
339 ArithmeticBinop::TruncDivide => Val::Number((lhs / rhs).trunc()),
340 ArithmeticBinop::Remainder => Val::Number(lhs % rhs),
341 }
342 }
343
344 Binop::Equal => Val::Bool(lhs == rhs),
346 Binop::NotEqual => Val::Bool(lhs != rhs),
347 Binop::LessThan => Val::Bool(lhs.lt(&rhs)?),
348 Binop::LessThanOrEqual => Val::Bool(!rhs.lt(&lhs)?),
349 Binop::GreaterThan => Val::Bool(rhs.lt(&lhs)?),
350 Binop::GreaterThanOrEqual => Val::Bool(!lhs.lt(&rhs)?),
351
352 Binop::Append => {
354 let list = lhs.expect_list()?;
355 list.borrow_mut().push(rhs);
356 lhs
357 }
358 };
359 stack.push(ret);
360 }
361 Opcode::Unop(op) => {
362 let val = stack.pop().unwrap();
363 let ret = match op {
364 Unop::Arithmetic(aop) => {
365 let val = if let Some(val) = val.number() {
366 val
367 } else {
368 scope.push_trace(code.marks()[*i - 1].clone());
369 return Err(format!(
370 concat!(
371 "The argument to this unary arithmetic operator ",
372 "should be a number but got {:?}"
373 ),
374 val
375 )
376 .into());
377 };
378 match aop {
379 ArithmeticUnop::Negative => Val::Number(-val),
380 ArithmeticUnop::Positive => Val::Number(val),
381 }
382 }
383 Unop::Len => match val {
384 Val::String(s) => Val::Number(s.charlen() as f64),
385 Val::List(list) => Val::Number(list.borrow().len() as f64),
386 _ => {
387 scope.push_trace(code.marks()[*i - 1].clone());
388 return Err(format!(
389 concat!("LEN requires a string or list argument but got {}"),
390 val,
391 )
392 .into());
393 }
394 },
395 };
396 stack.push(ret);
397 }
398 Opcode::Print => {
399 let x = stack.pop().unwrap();
400 handler.print(scope, x)?;
401 }
402 Opcode::Disasm => {
403 let f = stack.pop().unwrap();
404 if let Val::Func(func) = &f {
405 stack.push(func.0.format().into());
406 } else {
407 scope.push_trace(code.marks()[*i - 1].clone());
408 return Err(
409 format!(concat!("DISASM requires a function argument but got {}"), f,).into(),
410 );
411 }
412 }
413 Opcode::AddToTest => {
414 let val = stack.last().unwrap().clone();
415 if let Val::Func(code) = &val {
416 scope.tests.push(code.0.clone());
417 } else {
418 scope.push_trace(code.marks()[*i - 1].clone());
419 return Err(format!(
420 concat!("Tests need to be functions, but {} is not a function"),
421 val,
422 )
423 .into());
424 }
425 }
426 Opcode::Assert => {
427 let val = stack.pop().unwrap();
428 if !val.truthy() {
429 scope.push_trace(code.marks()[*i - 1].clone());
430 return Err(format!(concat!("Assertion failed"),).into());
431 }
432 }
433 Opcode::AssertEq => {
434 let rhs = stack.pop().unwrap();
435 let lhs = stack.pop().unwrap();
436 if lhs != rhs {
437 scope.push_trace(code.marks()[*i - 1].clone());
438 return Err(format!(
439 concat!("Assertion failed: expected {} to equal {}"),
440 lhs, rhs,
441 )
442 .into());
443 }
444 }
445 Opcode::Goto(pos) => {
446 *i = *pos as usize;
447 }
448 Opcode::GotoIfFalse(pos) => {
449 let item = stack.pop().unwrap();
450 if !item.truthy() {
451 *i = *pos as usize;
452 }
453 }
454 Opcode::GotoIfFalseNoPop(pos) => {
455 let item = stack.last().unwrap();
456 if !item.truthy() {
457 *i = *pos as usize;
458 }
459 }
460 Opcode::Label(_)
461 | Opcode::UnresolvedGoto(_)
462 | Opcode::UnresolvedGotoIfFalse(_)
463 | Opcode::UnresolvedGotoIfFalseNoPop(_) => {
464 panic!("Unresolved opcode: {:?}", op);
465 }
466 }
467 Ok(StepVal::None)
468}
469
470#[derive(Debug, Clone, Copy)]
471pub enum VarScope {
472 Local,
473 Global,
474}
475
476pub struct Scope {
477 globals: IndexedMap,
478 locals: Vec<IndexedMap>,
479 trace: Vec<Mark>,
480 tests: Vec<Rc<Code>>,
481}
482
483impl Scope {
484 pub fn new() -> Self {
485 Self {
486 globals: IndexedMap::new(),
487 locals: vec![],
488 trace: vec![],
489 tests: vec![],
490 }
491 }
492 pub fn get_name(&self, vscope: VarScope, index: u32) -> &RcStr {
493 match vscope {
494 VarScope::Global => self.globals.get_key(index).unwrap(),
495 VarScope::Local => self.locals.last().unwrap().get_key(index).unwrap(),
496 }
497 }
498 pub fn get(&self, vscope: VarScope, index: u32) -> &Val {
499 match vscope {
500 VarScope::Global => &self.globals.values[index as usize],
501 VarScope::Local => &self.locals.last().unwrap().values[index as usize],
502 }
503 }
504 pub fn set(&mut self, vscope: VarScope, index: u32, val: Val) {
505 match vscope {
506 VarScope::Global => self.globals.values[index as usize] = val,
507 VarScope::Local => self.locals.last_mut().unwrap().values[index as usize] = val,
508 }
509 }
510 pub fn push(&mut self, locals: &Vec<Var>) {
511 self.locals.push(new_locals_from_vars(locals));
512 }
513 pub fn push_existing_locals(&mut self, map: IndexedMap) {
514 self.locals.push(map);
515 }
516 pub fn pop(&mut self) -> IndexedMap {
517 self.locals.pop().unwrap()
518 }
519 pub fn push_trace(&mut self, mark: Mark) {
520 self.trace.push(mark);
521 }
522 pub fn pop_trace(&mut self) {
523 self.trace.pop();
524 }
525}
526
527fn new_locals_from_vars(vars: &Vec<Var>) -> IndexedMap {
528 let mut map = IndexedMap::new();
529 for var in vars {
530 let index = map.insert(var.name.clone(), Val::Nil);
531 assert_eq!(index, var.index);
532 }
533 map
534}
535
536pub struct IndexedMap {
537 values: Vec<Val>,
538 map: HashMap<RcStr, u32>,
539}
540
541impl IndexedMap {
542 pub fn new() -> Self {
543 Self {
544 values: vec![],
545 map: HashMap::new(),
546 }
547 }
548 pub fn insert(&mut self, key: RcStr, val: Val) -> u32 {
549 let i = self.values.len() as u32;
550 self.values.push(val);
551 self.map.insert(key, i);
552 i
553 }
554 pub fn set_by_index(&mut self, i: u32, val: Val) {
555 self.values[i as usize] = val;
556 }
557 pub fn get_by_key(&self, key: &RcStr) -> Option<&Val> {
558 self.map.get(key).map(|i| &self.values[*i as usize])
559 }
560 pub fn get_by_index(&self, i: u32) -> Option<&Val> {
561 self.values.get(i as usize)
562 }
563 pub fn get_key(&self, index: u32) -> Option<&RcStr> {
564 for (key, i) in &self.map {
565 if *i == index {
566 return Some(key);
567 }
568 }
569 None
570 }
571 pub fn len(&self) -> usize {
572 self.values.len()
573 }
574}
575
576pub struct GenObj {
579 code: Rc<Code>,
580 locals: IndexedMap,
581 i: usize,
582 stack: Vec<Val>,
583}
584
585impl GenObj {
586 pub fn resume<H: Handler>(
587 &mut self,
588 scope: &mut Scope,
589 handler: &mut H,
590 val: Val,
591 ) -> Result<Option<Val>, Val> {
592 if self.i >= self.code.len() {
593 return Ok(None);
594 }
595 scope.push_existing_locals(std::mem::replace(&mut self.locals, IndexedMap::new()));
596 self.stack.push(val);
597 let result = self.loop_(scope, handler);
598 self.locals = scope.pop();
599 result
600 }
601 pub fn to_vec<H: Handler>(
602 &mut self,
603 scope: &mut Scope,
604 handler: &mut H,
605 ) -> Result<Vec<Val>, Val> {
606 let mut ret = Vec::new();
607 while let Some(val) = self.resume(scope, handler, Val::Nil)? {
608 ret.push(val);
609 }
610 Ok(ret)
611 }
612 fn loop_<H: Handler>(
613 &mut self,
614 scope: &mut Scope,
615 handler: &mut H,
616 ) -> Result<Option<Val>, Val> {
617 while self.i < self.code.len() {
618 match step(scope, handler, &self.code, &mut self.i, &mut self.stack)? {
619 StepVal::Return(_) => {
620 self.i = self.code.len();
621 self.clear(); return Ok(None);
623 }
624 StepVal::Yield(val) => return Ok(Some(val)),
625 StepVal::None => {}
626 }
627 }
628 self.clear();
629 Ok(None)
630 }
631 fn clear(&mut self) {
632 self.stack = vec![];
633 self.locals = IndexedMap::new();
634 }
635}