1#![deny(missing_docs)]
10
11use crate::{
12 ast::{Assignable, AssignableKind, Block, Expr, Spanned, Stmt},
13 consts::ablescript_consts,
14 error::{Error, ErrorKind},
15 host_interface::HostInterface,
16 value::{Functio, Value, ValueRef, Variable},
17};
18use rand::random;
19use std::{
20 cmp::Ordering,
21 collections::{HashMap, VecDeque},
22 mem::take,
23 ops::Range,
24};
25
26pub struct ExecEnv<H> {
28 stack: Vec<Scope>,
32
33 read_buf: VecDeque<bool>,
39
40 host_interface: H,
42
43 finalisers: Vec<Block>,
45}
46
47struct Scope {
50 variables: HashMap<String, Variable>,
52}
53
54impl<H> Default for ExecEnv<H>
55where
56 H: Default + HostInterface,
57{
58 fn default() -> Self {
59 Self::with_host_interface(H::default())
60 }
61}
62
63impl Default for Scope {
64 fn default() -> Self {
65 Self {
66 variables: ablescript_consts(),
67 }
68 }
69}
70
71enum HaltStatus {
73 Finished,
75
76 Enough(Range<usize>),
79
80 AndAgain(Range<usize>),
83}
84
85pub const READ_BITS: u8 = 3;
88
89impl<H: HostInterface> ExecEnv<H> {
90 pub fn with_host_interface(mut host_interface: H) -> Self {
93 Self {
94 stack: vec![
95 Default::default(),
96 Scope {
97 variables: host_interface.initial_vars(),
98 },
99 ],
100 read_buf: Default::default(),
101 finalisers: vec![],
102 host_interface,
103 }
104 }
105
106 pub fn new_with_vars<I>(mut host_interface: H, vars: I) -> Self
108 where
109 I: IntoIterator<Item = (String, Variable)>,
110 {
111 Self {
112 stack: vec![
113 Scope {
114 variables: ablescript_consts().into_iter().chain(vars).collect(),
115 },
116 Scope {
117 variables: host_interface.initial_vars(),
118 },
119 ],
120 read_buf: Default::default(),
121 finalisers: vec![],
122 host_interface,
123 }
124 }
125
126 pub fn eval_stmts(&mut self, stmts: &[Spanned<Stmt>]) -> Result<(), Error> {
130 match self.eval_stmts_hs(stmts, false)? {
131 HaltStatus::Finished => Ok(()),
132 HaltStatus::Enough(span) | HaltStatus::AndAgain(span) => Err(Error {
133 kind: ErrorKind::LoopOpOutsideLoop,
136 span,
137 }),
138 }?;
139
140 while !self.finalisers.is_empty() {
141 for block in std::mem::take(&mut self.finalisers) {
142 self.eval_stmts_hs(&block, true)?;
143 }
144 }
145
146 Ok(())
147 }
148
149 fn eval_stmts_hs(
156 &mut self,
157 stmts: &[Spanned<Stmt>],
158 stackframe: bool,
159 ) -> Result<HaltStatus, Error> {
160 let init_depth = self.stack.len();
161
162 if stackframe {
163 self.stack.push(Default::default());
164 }
165
166 let mut final_result = Ok(HaltStatus::Finished);
167 for stmt in stmts {
168 final_result = self.eval_stmt(stmt);
169 if !matches!(final_result, Ok(HaltStatus::Finished)) {
170 break;
171 }
172 }
173
174 if stackframe {
175 self.stack.pop();
176 }
177
178 debug_assert_eq!(self.stack.len(), init_depth);
180 final_result
181 }
182
183 fn eval_expr(&self, expr: &Spanned<Expr>) -> Result<Value, Error> {
185 use crate::ast::BinOpKind::*;
186 use crate::ast::Expr::*;
187
188 Ok(match &expr.item {
189 BinOp { lhs, rhs, kind } => {
190 let lhs = self.eval_expr(lhs)?;
191 let rhs = self.eval_expr(rhs)?;
192 match kind {
193 Add => lhs + rhs,
194 Subtract => lhs - rhs,
195 Multiply => lhs * rhs,
196 Divide => lhs / rhs,
197 Greater => Value::Abool((lhs > rhs).into()),
198 Less => Value::Abool((lhs < rhs).into()),
199 Equal => Value::Abool((lhs == rhs).into()),
200 NotEqual => Value::Abool((lhs != rhs).into()),
201 }
202 }
203 Aint(expr) => !self.eval_expr(expr)?,
204 Literal(lit) => lit.clone().into(),
205 Expr::Cart(members) => Value::Cart(
206 members
207 .iter()
208 .map(|(value, key)| {
209 self.eval_expr(value).and_then(|value| {
210 self.eval_expr(key).map(|key| (key, ValueRef::new(value)))
211 })
212 })
213 .collect::<Result<HashMap<_, _>, _>>()?,
214 ),
215 Index { expr, index } => {
216 let value = self.eval_expr(expr)?;
217 let index = self.eval_expr(index)?;
218
219 value
220 .into_cart()
221 .get(&index)
222 .map(|x| x.borrow().clone())
223 .unwrap_or(Value::Nul)
224 }
225 Len(expr) => Value::Int(self.eval_expr(expr)?.length()),
226 Keys(expr) => Value::Cart(
227 self.eval_expr(expr)?
228 .into_cart()
229 .into_keys()
230 .enumerate()
231 .map(|(i, k)| (Value::Int(i as isize + 1), ValueRef::new(k)))
232 .collect(),
233 ),
234 Variable(name) => {
237 self.get_var_value(&Spanned::new(name.to_owned(), expr.span.clone()))?
238 }
239 })
240 }
241
242 fn eval_stmt(&mut self, stmt: &Spanned<Stmt>) -> Result<HaltStatus, Error> {
244 match &stmt.item {
245 Stmt::Print { expr, newline } => {
246 let value = self.eval_expr(expr)?;
247 self.host_interface
248 .print(&value.to_string(), *newline)
249 .map_err(|e| Error::new(e.into(), stmt.span.clone()))?;
250 }
251 Stmt::Dim { ident, init } => {
252 let init = match init {
253 Some(e) => self.eval_expr(e)?,
254 None => Value::Nul,
255 };
256
257 self.decl_var(&ident.item, init);
258 }
259 Stmt::Functio {
260 ident,
261 params,
262 body,
263 } => {
264 self.decl_var(
265 &ident.item,
266 Value::Functio(Functio::Able {
267 params: params.iter().map(|ident| ident.item.to_owned()).collect(),
268 body: body.to_owned(),
269 }),
270 );
271 }
272 Stmt::BfFunctio {
273 ident,
274 tape_len,
275 code,
276 } => {
277 self.decl_var(
278 &ident.item,
279 Value::Functio(Functio::Bf {
280 instructions: code.to_owned(),
281 tape_len: tape_len
282 .as_ref()
283 .map(|tape_len| {
284 self.eval_expr(tape_len).map(|v| v.into_isize() as usize)
285 })
286 .unwrap_or(Ok(crate::brian::DEFAULT_TAPE_SIZE_LIMIT))?,
287 }),
288 );
289 }
290 Stmt::Unless { cond, body } => {
291 if !self.eval_expr(cond)?.into_abool().to_bool() {
292 return self.eval_stmts_hs(body, true);
293 }
294 }
295 Stmt::Call { expr, args } => {
296 let func = self.eval_expr(expr)?.into_functio();
297 return self.fn_call(func, args, &stmt.span);
298 }
299 Stmt::Loop { body } => loop {
300 let res = self.eval_stmts_hs(body, true)?;
301 match res {
302 HaltStatus::Finished => (),
303 HaltStatus::Enough(_) => break,
304 HaltStatus::AndAgain(_) => continue,
305 }
306 },
307 Stmt::Assign { assignable, value } => {
308 self.assign(assignable, self.eval_expr(value)?)?;
309 }
310 Stmt::Enough => {
311 return Ok(HaltStatus::Enough(stmt.span.clone()));
312 }
313 Stmt::AndAgain => {
314 return Ok(HaltStatus::AndAgain(stmt.span.clone()));
315 }
316 Stmt::Melo(ident) => match self.get_var_mut(ident)? {
317 var @ Variable::Ref(_) => *var = Variable::Melo,
318 Variable::Melo => {
319 for s in &mut self.stack {
320 if s.variables.remove(&ident.item).is_some() {
321 break;
322 }
323 }
324 }
325 },
326 Stmt::Finally(block) => self.finalisers.push(block.clone()),
327 Stmt::Rlyeh => {
328 let code = random();
331 self.host_interface.exit(code);
332 return Err(Error::new(
333 ErrorKind::NonExitingRlyeh(code),
334 stmt.span.clone(),
335 ));
336 }
337 Stmt::Rickroll => {
338 self.host_interface
339 .print(include_str!("rickroll"), false)
340 .map_err(|e| Error::new(e.into(), stmt.span.clone()))?;
341 }
342 Stmt::Read(assignable) => {
343 let mut value = 0;
344 for _ in 0..READ_BITS {
345 value <<= 1;
346 value += self
347 .get_bit()
348 .map_err(|e| Error::new(e, stmt.span.clone()))?
349 as isize;
350 }
351
352 self.assign(assignable, Value::Int(value))?;
353 }
354 }
355
356 Ok(HaltStatus::Finished)
357 }
358
359 fn assign(&mut self, dest: &Assignable, value: Value) -> Result<(), Error> {
361 match dest.kind {
362 AssignableKind::Variable => {
363 self.get_var_rc_mut(&dest.ident)?.replace(value);
364 }
365 AssignableKind::Index { ref indices } => {
366 let mut cell = self.get_var_rc_mut(&dest.ident)?.clone();
367 for index in indices {
368 let index = self.eval_expr(index)?;
369
370 let next_cell = match &mut *cell.borrow_mut() {
371 Value::Cart(c) => {
372 if let Some(x) = c.get(&index) {
375 ValueRef::clone(x)
378 } else {
379 let next_cell = ValueRef::new(Value::Cart(Default::default()));
383 c.insert(index, ValueRef::clone(&next_cell));
384 next_cell
385 }
386 }
387 x => {
388 let mut cart = take(x).into_cart();
392 let next_cell = ValueRef::new(Value::Cart(Default::default()));
393 cart.insert(index, ValueRef::clone(&next_cell));
394 *x = Value::Cart(cart);
395 next_cell
396 }
397 };
398 cell = next_cell;
399 }
400 cell.replace(value);
401 }
402 }
403
404 Ok(())
405 }
406
407 fn fn_call(
411 &mut self,
412 func: Functio,
413 args: &[Spanned<Expr>],
414 span: &Range<usize>,
415 ) -> Result<HaltStatus, Error> {
416 let args = args
419 .iter()
420 .map(|arg| {
421 if let Expr::Variable(name) = &arg.item {
422 self.get_var_rc_mut(&Spanned::new(name.to_owned(), arg.span.clone()))
423 .cloned()
424 } else {
425 self.eval_expr(arg).map(ValueRef::new)
426 }
427 })
428 .collect::<Result<Vec<_>, Error>>()?;
429
430 self.fn_call_with_values(func, &args, span)
431 }
432
433 fn fn_call_with_values(
434 &mut self,
435 func: Functio,
436 args: &[ValueRef],
437 span: &Range<usize>,
438 ) -> Result<HaltStatus, Error> {
439 match func {
440 Functio::Bf {
441 instructions,
442 tape_len,
443 } => {
444 let mut input: Vec<u8> = vec![];
445 for arg in args {
446 arg.borrow().bf_write(&mut input);
447 }
448
449 let mut output = vec![];
450
451 crate::brian::Interpreter::from_ascii_with_tape_limit(
452 &instructions,
453 &input as &[_],
454 tape_len,
455 )
456 .interpret_with_output(&mut output)
457 .map_err(|e| Error {
458 kind: ErrorKind::Brian(e),
459 span: span.to_owned(),
460 })?;
461
462 match String::from_utf8(output) {
463 Ok(string) => self.host_interface.print(&string, false),
464 Err(e) => self
465 .host_interface
466 .print(&format!("{:?}", e.as_bytes()), true),
467 }
468 .map_err(|e| Error::new(e.into(), span.clone()))?;
469
470 Ok(HaltStatus::Finished)
471 }
472 Functio::Able { params, body } => {
473 self.stack.push(Default::default());
474
475 for (param, arg) in params.iter().zip(args.iter()) {
476 self.decl_var_shared(param, arg.to_owned());
477 }
478
479 let res = self.eval_stmts_hs(&body, false);
480
481 self.stack.pop();
482 res
483 }
484 Functio::Builtin(b) => {
485 b.call(args).map_err(|e| Error::new(e, span.clone()))?;
486 Ok(HaltStatus::Finished)
487 }
488 Functio::Chain { functios, kind } => {
489 use crate::value::functio::FunctioChainKind;
490 let (left_functio, right_functio) = *functios;
491 Ok(
492 match match kind {
493 FunctioChainKind::Equal => {
494 let (l, r) = args.split_at(args.len() / 2);
495
496 (
497 self.fn_call_with_values(left_functio, l, span)?,
498 self.fn_call_with_values(right_functio, r, span)?,
499 )
500 }
501 FunctioChainKind::ByArity => {
502 let (l, r) = Self::deinterlace(
503 args,
504 (left_functio.arity(), right_functio.arity()),
505 );
506
507 (
508 self.fn_call_with_values(left_functio, &l, span)?,
509 self.fn_call_with_values(right_functio, &r, span)?,
510 )
511 }
512 } {
513 (s, HaltStatus::Finished) => s,
514 (HaltStatus::Finished, s) => s,
515 (_, r) => r,
516 },
517 )
518 }
519 Functio::Eval(code) => self.eval_stmts_hs(&crate::parser::parse(&code)?, false),
520 }
521 }
522
523 fn deinterlace(args: &[ValueRef], arities: (usize, usize)) -> (Vec<ValueRef>, Vec<ValueRef>) {
524 let n_alternations = usize::min(arities.0, arities.1);
525 let (extra_l, extra_r) = match Ord::cmp(&arities.0, &arities.1) {
526 Ordering::Less => (0, arities.1 - arities.0),
527 Ordering::Equal => (0, 0),
528 Ordering::Greater => (arities.0 - arities.1, 0),
529 };
530
531 (
532 args.chunks(2)
533 .take(n_alternations)
534 .map(|chunk| ValueRef::clone(&chunk[0]))
535 .chain(
536 args.get(2 * n_alternations..)
537 .iter()
538 .copied()
539 .flatten()
540 .map(ValueRef::clone)
541 .take(extra_l),
542 )
543 .collect(),
544 args.chunks(2)
545 .take(n_alternations)
546 .flat_map(|chunk| chunk.get(1))
547 .map(ValueRef::clone)
548 .chain(
549 args.get(2 * n_alternations..)
550 .iter()
551 .copied()
552 .flatten()
553 .map(ValueRef::clone)
554 .take(extra_r),
555 )
556 .collect(),
557 )
558 }
559
560 fn get_bit(&mut self) -> Result<bool, ErrorKind> {
563 const BITS_PER_BYTE: u8 = 8;
564
565 if self.read_buf.is_empty() {
566 let byte = self.host_interface.read_byte()?;
567
568 for n in (0..BITS_PER_BYTE).rev() {
569 self.read_buf.push_back(((byte >> n) & 1) != 0);
570 }
571 }
572
573 Ok(self
574 .read_buf
575 .pop_front()
576 .expect("We just pushed to the buffer if it was empty"))
577 }
578
579 fn get_var_value(&self, name: &Spanned<String>) -> Result<Value, Error> {
582 match self
584 .stack
585 .iter()
586 .rev()
587 .find_map(|scope| scope.variables.get(&name.item))
588 {
589 Some(Variable::Ref(r)) => Ok(r.borrow().clone()),
590 Some(Variable::Melo) => Err(Error {
591 kind: ErrorKind::MeloVariable(name.item.to_owned()),
592 span: name.span.clone(),
593 }),
594 None => Ok(Value::Undefined),
595 }
596 }
597
598 fn get_var_mut(&mut self, name: &Spanned<String>) -> Result<&mut Variable, Error> {
600 match self
603 .stack
604 .iter_mut()
605 .rev()
606 .find_map(|scope| scope.variables.get_mut(&name.item))
607 {
608 Some(var) => Ok(var),
609 None => Err(Error {
610 kind: ErrorKind::UnknownVariable(name.item.to_owned()),
611 span: name.span.clone(),
612 }),
613 }
614 }
615
616 fn get_var_rc_mut(&mut self, name: &Spanned<String>) -> Result<&mut ValueRef, Error> {
619 match self.get_var_mut(name)? {
620 Variable::Ref(r) => Ok(r),
621 Variable::Melo => Err(Error {
622 kind: ErrorKind::MeloVariable(name.item.to_owned()),
623 span: name.span.clone(),
624 }),
625 }
626 }
627
628 fn decl_var(&mut self, name: &str, value: Value) {
630 self.decl_var_shared(name, ValueRef::new(value));
631 }
632
633 fn decl_var_shared(&mut self, name: &str, value: ValueRef) {
635 self.stack
636 .iter_mut()
637 .last()
638 .expect("Declaring variable on empty stack")
639 .variables
640 .insert(name.to_owned(), Variable::Ref(value));
641 }
642}
643
644#[cfg(test)]
645mod tests {
646 use super::*;
647 use crate::{
648 ast::{Expr, Literal},
649 host_interface::Standard,
650 };
651
652 #[test]
653 fn basic_expression_test() {
654 let env = ExecEnv::<Standard>::default();
656 assert_eq!(
657 env.eval_expr(&Spanned {
658 item: Expr::BinOp {
659 lhs: Box::new(Spanned {
660 item: Expr::Literal(Literal::Int(2)),
661 span: 1..1,
662 }),
663 rhs: Box::new(Spanned {
664 item: Expr::Literal(Literal::Int(2)),
665 span: 1..1,
666 }),
667 kind: crate::ast::BinOpKind::Add,
668 },
669 span: 1..1
670 })
671 .unwrap(),
672 Value::Int(4)
673 )
674 }
675
676 #[test]
677 fn type_coercions() {
678 let env = ExecEnv::<Standard>::default();
682 assert_eq!(
683 env.eval_expr(&Spanned {
684 item: Expr::BinOp {
685 lhs: Box::new(Spanned {
686 item: Expr::Literal(Literal::Int(2)),
687 span: 1..1,
688 }),
689 rhs: Box::new(Spanned {
690 item: Expr::Variable("always".to_owned()),
691 span: 1..1,
692 }),
693 kind: crate::ast::BinOpKind::Add,
694 },
695 span: 1..1
696 })
697 .unwrap(),
698 Value::Int(3)
699 );
700 }
701
702 #[test]
703 fn overflow_should_not_panic() {
704 let env = ExecEnv::<Standard>::default();
707 assert_eq!(
708 env.eval_expr(&Spanned {
709 item: Expr::BinOp {
710 lhs: Box::new(Spanned {
711 item: Expr::Literal(Literal::Int(isize::MAX)),
712 span: 1..1,
713 }),
714 rhs: Box::new(Spanned {
715 item: Expr::Literal(Literal::Int(1)),
716 span: 1..1,
717 }),
718 kind: crate::ast::BinOpKind::Add,
719 },
720 span: 1..1
721 })
722 .unwrap(),
723 Value::Int(-9223372036854775808)
724 );
725
726 assert_eq!(
728 env.eval_expr(&Spanned {
729 item: Expr::BinOp {
730 lhs: Box::new(Spanned {
731 item: Expr::Literal(Literal::Int(84)),
732 span: 1..1,
733 }),
734 rhs: Box::new(Spanned {
735 item: Expr::Literal(Literal::Int(0)),
736 span: 1..1,
737 }),
738 kind: crate::ast::BinOpKind::Divide,
739 },
740 span: 1..1
741 })
742 .unwrap(),
743 Value::Int(2)
744 );
745 }
746
747 fn eval(env: &mut ExecEnv<Standard>, src: &str) -> Result<Value, Error> {
751 let ast = crate::parser::parse(src).unwrap();
754 env.eval_stmts(&ast).map(|()| Value::Nul)
755 }
756
757 #[test]
758 fn variable_decl_and_assignment() {
759 let mut env = ExecEnv::<Standard>::default();
763
764 eval(&mut env, "foo dim 32; bar dim foo + 1;").unwrap();
766 assert_eq!(
767 env.get_var_value(&Spanned {
768 item: "bar".to_owned(),
769 span: 1..1,
770 })
771 .unwrap(),
772 Value::Int(33)
773 );
774
775 eval(&mut env, "/*hi*/ =: foo;").unwrap();
777 assert_eq!(
778 env.get_var_value(&Spanned {
779 item: "foo".to_owned(),
780 span: 1..1,
781 })
782 .unwrap(),
783 Value::Str("hi".to_owned())
784 );
785
786 eval(&mut env, "bar + 1 =: invalid;").unwrap_err();
789 }
790
791 #[test]
792 fn scope_visibility_rules() {
793 let mut env = ExecEnv::<Standard>::default();
797 eval(
798 &mut env,
799 "foo dim 1; 2 =: foo; unless (never) { foo dim 3; 4 =: foo; }",
800 )
801 .unwrap();
802
803 assert_eq!(
804 env.get_var_value(&Spanned {
805 item: "foo".to_owned(),
806 span: 1..1,
807 })
808 .unwrap(),
809 Value::Int(2)
810 );
811 }
812}