1use crate::parser::{Node, Span, Spanned, Unspanned};
2use ariadne::{Color, Label, Report, ReportKind, Source};
3use rand::prelude::IndexedRandom;
4use rand::rng;
5use std::collections::{HashMap, HashSet};
6use std::io;
7use std::sync::LazyLock;
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum Value {
11 Integer(i64),
12 Float(f64),
13 Text(String),
14}
15
16#[derive(Debug)]
17pub struct VariableStore {
18 store: HashMap<String, (String, Value)>,
19}
20
21impl VariableStore {
22 pub fn new() -> Self {
23 Self {
24 store: HashMap::new(),
25 }
26 }
27
28 pub fn insert(&mut self, name: &str, value: Value) {
29 self.store
30 .insert(sort_ident(&normalize_ident(name)), (name.to_owned(), value));
31 }
32
33 pub fn get(&self, name: &str) -> Option<&Value> {
34 self.store
35 .get(&sort_ident(&normalize_ident(name)))
36 .map(|v| &v.1)
37 }
38}
39
40pub struct Evaluator<'a> {
41 stack: Vec<Value>,
43
44 nodes: Vec<Spanned<Node>>,
46
47 idents: HashMap<String, Spanned<Node>>,
51
52 line_index: Option<LineIndex<'a>>,
55
56 line_to_literal: HashMap<usize, Vec<Node>>,
59
60 nested_func_calls: Vec<(String, Span)>,
63}
64
65static BUILT_INS: LazyLock<HashSet<&'static str>> = LazyLock::new(|| {
66 let mut set = HashSet::new();
67 set.insert("humanely");
68 set.insert("multiply");
69 set.insert("parsingly");
70 set.insert("additionally");
71 set.insert("visibly");
72 set.insert("deductively");
73 set.insert("divisibly");
74 set.insert("beyond");
75 set.insert("debuggably");
76 set.insert("equally");
77 set.insert("alternatively");
78 set.insert("conjointly");
79 set.insert("focally");
80 set.insert("modularly");
81 set.insert("oppositely");
82 set
84});
85
86#[derive(Debug, PartialEq)]
87pub struct EvalError {
88 pub message: String,
89 pub span: Span,
90}
91
92impl<'a> Evaluator<'a> {
93 pub fn new(nodes: Vec<Spanned<Node>>, line_index: Option<LineIndex<'a>>) -> Self {
94 Self {
95 line_to_literal: collect_values(&nodes, &line_index),
96 stack: Vec::new(),
97 nodes: nodes,
98 idents: HashMap::new(),
99 line_index: line_index,
100 nested_func_calls: vec![],
101 }
102 }
103
104 fn push(&mut self, value: Value) {
105 self.stack.push(value);
106 }
107
108 fn pop(&mut self) -> Option<Value> {
109 self.stack.pop()
110 }
111
112 pub fn eval_script(&mut self) -> Result<Vec<Value>, EvalError> {
113 assert_eq!(self.idents.len(), 0);
115
116 let story: Option<usize> = collect_idents(&mut self.idents, &self.nodes)?;
121
122 match story {
124 Some(i) => match self.nodes[i].clone() {
125 (Node::Story(_, children), _) => {
127 let mut variable_store = VariableStore::new();
128
129 for child in children.iter().rev() {
130 let was_return = self.eval_node(&child, &mut variable_store)?;
131 if was_return {
132 break;
133 }
134 }
135 }
136 _ => panic!("We should never not get a Story here."),
137 },
138 _ => {
139 return Err(EvalError {
140 message: "Evaluated script needs an entrypoint".to_string(),
141 span: (0..0),
142 });
143 }
144 }
145
146 return Ok(self.stack.clone());
147 }
148
149 fn eval_node(
152 &mut self,
153 node: &Spanned<Node>,
154 variable_store: &mut VariableStore,
155 ) -> Result<bool, EvalError> {
156 match node {
157 (Node::FuncCall(ident, nodes), span) => {
158 self.eval_func_call(ident, count_words(nodes), variable_store, span)?;
159 Ok(false)
160 }
161 (Node::ValueRef(lines_below), span) => {
162 self.eval_value_ref(*lines_below, variable_store, span)?;
163 Ok(false)
164 }
165 (Node::FuncReturn, _) => {
166 let val = self.stack.pop();
167
168 match val {
169 Some(Value::Integer(1)) => Ok(true),
170 _ => Ok(false),
171 }
172 }
173 (Node::Word(_), _) => Ok(false),
174 (Node::Adverb(_), _) => Ok(false),
175 (Node::FloatLiteral(_), _) => Ok(false),
176 (Node::IntLiteral(_), _) => Ok(false),
177 (Node::StringLiteral(_), _) => Ok(false),
178 (Node::VariableAssign(ident), span) => {
179 self.eval_var_assign(ident, variable_store, span)?;
180 Ok(false)
181 }
182 (Node::VariableRead(ident, _), span) => {
183 self.eval_var_read(ident, variable_store, span)?;
184 Ok(false)
185 }
186 (Node::Hack(a, b), span) => {
187 self.eval_hack(a, b, variable_store, span)?;
188 Ok(false)
189 }
190 (Node::Chapter(_, _), _) => {
191 Ok(false)
193 }
194 (Node::FocusChange(t), span) => {
195 self.eval_focus(*t, variable_store, span)?;
196 Ok(false)
197 }
198 _ => {
199 unimplemented!("TODO {:?}", node);
200 }
201 }
202 }
203
204 fn eval_func_call(
205 &mut self,
206 raw_ident: &String,
207 word_count: usize,
208 variable_store: &VariableStore,
209 span: &Span,
210 ) -> Result<(), EvalError> {
211 if self.nested_func_calls.len() > 1000 {
216 println!("{:?}", self.nested_func_calls);
217 return Err(EvalError {
218 message: "Infinite loop detected".to_string(),
219 span: span.clone(),
220 });
221 }
222
223 self.nested_func_calls
225 .push((raw_ident.to_owned(), span.clone()));
226 let res = self.eval_func_call_impl(raw_ident, word_count, variable_store, span);
227 self.nested_func_calls.pop();
228 res
229 }
230
231 fn eval_func_call_impl(
232 &mut self,
233 raw_ident: &String,
234 word_count: usize,
235 variable_store: &VariableStore,
236 span: &Span,
237 ) -> Result<(), EvalError> {
238 let ident = normalize_ident(raw_ident);
243
244 let is_correct_words_long = ident.len() == word_count as usize;
246
247 let focus_var_value = self.get_focus_var(variable_store);
248 let focus_letter_count = count_letters_in(focus_var_value, &ident);
249 let is_correct_focus_count = word_count == focus_letter_count;
250 let is_debuggably = ident == normalize_ident("debuggably");
251 if !is_correct_words_long && !is_correct_focus_count && !is_debuggably {
252 return Err(EvalError {
253 message: format!(
254 "Invalid func call, incorrect number of words given for `{}`, got {} wanted {} or {}",
255 raw_ident,
256 word_count,
257 focus_letter_count,
258 ident.len()
259 ),
260 span: span.clone(),
261 });
262 }
263
264 let is_flat_adverb = !raw_ident.ends_with("ly");
265
266 for built_in in BUILT_INS.iter() {
268 if is_anagram(&ident, built_in) {
269 if ident == *built_in && !is_flat_adverb && !is_debuggably {
271 return Err(EvalError {
272 message: format!("Invalid func call, need an anagram of {}", ident),
273 span: span.clone(),
274 });
275 }
276
277 match *built_in {
278 "visibly" => {
279 let val = self.pop();
280 match val {
281 Some(Value::Float(v)) => print!("{}", v),
282 Some(Value::Integer(v)) => print!("{}", v),
283 Some(Value::Text(v)) => print!("{}", v),
284 None => {
285 return Err(EvalError {
286 message: "Need value on stack for `visibly`".to_string(),
287 span: span.clone(),
288 });
289 }
290 }
291 return Ok(());
292 }
293 "humanely" => {
294 let mut input = String::new();
295 io::stdin()
296 .read_line(&mut input)
297 .expect("Failed to read line");
298 self.push(Value::Text(input.trim_end().to_string()));
299 return Ok(());
300 }
301 "focally" => {
302 let val = self.pop();
303 match val {
304 Some(Value::Integer(v)) => {
305 if (0..127).contains(&v) {
306 self.push(Value::Text((v as u8 as char).into()));
307 } else {
308 return Err(EvalError {
309 message: format!("Non-ASCII integer on stack, got {}", v),
310 span: span.clone(),
311 });
312 }
313 }
314 _ => {
315 return Err(EvalError {
316 message: "Need integer value on stack for `focally`"
317 .to_string(),
318 span: span.clone(),
319 });
320 }
321 }
322 return Ok(());
323 }
324 "oppositely" => {
325 let val = self.pop();
326 match val {
327 Some(Value::Integer(0)) => {
328 self.push(Value::Integer(1));
329 }
330 Some(Value::Integer(1)) => {
331 self.push(Value::Integer(0));
332 }
333 _ => {
334 return Err(EvalError {
335 message: format!(
336 "Need boolean integer value on stack for `oppositely`, got {:?}",
337 val
338 ),
339 span: span.clone(),
340 });
341 }
342 }
343 return Ok(());
344 }
345 "multiply" => {
346 let a = self.pop();
347 let b = self.pop();
348 if a.is_none() || b.is_none() {
349 return Err(EvalError {
350 message: "Need two values on stack for `multiply`".to_string(),
351 span: span.clone(),
352 });
353 }
354
355 match (a, b) {
356 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
357 self.push(Value::Integer(a_val * b_val));
358 }
359 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
360 self.push(Value::Float(a_val * b_val as f64));
361 }
362 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
363 self.push(Value::Float(a_val as f64 * b_val));
364 }
365 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
366 self.push(Value::Float(a_val * b_val));
367 }
368 _ => {
369 unimplemented!("TODO");
370 }
371 }
372 return Ok(());
373 }
374 "additionally" => {
375 let a = self.pop();
376 let b = self.pop();
377 if a.is_none() || b.is_none() {
378 return Err(EvalError {
379 message: "Need two values on stack for `additionally`".to_string(),
380 span: span.clone(),
381 });
382 }
383
384 match (a, b) {
385 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
386 self.push(Value::Integer(a_val + b_val));
387 }
388 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
389 self.push(Value::Float(a_val + b_val as f64));
390 }
391 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
392 self.push(Value::Float(a_val as f64 + b_val));
393 }
394 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
395 self.push(Value::Float(a_val + b_val));
396 }
397 _ => {
398 unimplemented!("TODO");
399 }
400 }
401 return Ok(());
402 }
403 "deductively" => {
404 let b = self.pop();
405 let a = self.pop();
406 if a.is_none() || b.is_none() {
407 return Err(EvalError {
408 message: "Need two values on stack for `deductively`".to_string(),
409 span: span.clone(),
410 });
411 }
412
413 match (a, b) {
414 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
415 self.push(Value::Integer(a_val - b_val));
416 }
417 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
418 self.push(Value::Float(a_val - b_val as f64));
419 }
420 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
421 self.push(Value::Float(a_val as f64 - b_val));
422 }
423 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
424 self.push(Value::Float(a_val - b_val));
425 }
426 _ => {
427 unimplemented!("TODO");
428 }
429 }
430 return Ok(());
431 }
432 "divisibly" => {
433 let b = self.pop();
434 let a = self.pop();
435 if a.is_none() || b.is_none() {
436 return Err(EvalError {
437 message: "Need two values on stack for `divisibly`".to_string(),
438 span: span.clone(),
439 });
440 }
441
442 match (a, b) {
443 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
444 self.push(Value::Float(a_val as f64 / b_val as f64));
445 }
446 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
447 self.push(Value::Float(a_val / b_val as f64));
448 }
449 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
450 self.push(Value::Float(a_val as f64 / b_val));
451 }
452 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
453 self.push(Value::Float(a_val / b_val));
454 }
455 _ => {
456 unimplemented!("TODO");
457 }
458 }
459 return Ok(());
460 }
461 "beyond" => {
462 let a = self.pop();
463 let b = self.pop();
464 if a.is_none() || b.is_none() {
465 return Err(EvalError {
466 message: "Need two values on stack for `beyond`".to_string(),
467 span: span.clone(),
468 });
469 }
470
471 match (a, b) {
472 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
473 self.push(Value::Integer(if a_val > b_val { 0 } else { 1 }));
474 }
475 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
476 self.push(Value::Integer(if a_val > b_val as f64 { 0 } else { 1 }));
477 }
478 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
479 self.push(Value::Integer(if a_val as f64 > b_val { 0 } else { 1 }));
480 }
481 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
482 self.push(Value::Integer(if a_val > b_val { 0 } else { 1 }));
483 }
484 _ => {
485 return Err(EvalError {
486 message: "Unsupported types for `beyond`".to_string(),
487 span: span.clone(),
488 });
489 }
490 }
491 return Ok(());
492 }
493 "alternatively" => {
494 let a = self.pop();
495 let b = self.pop();
496 if a.is_none() || b.is_none() {
497 return Err(EvalError {
498 message: "Need two values on stack for `alternatively`".to_string(),
499 span: span.clone(),
500 });
501 }
502
503 match (a, b) {
504 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
505 self.push(Value::Integer(if a_val == 1 || b_val == 1 {
506 1
507 } else {
508 0
509 }));
510 }
511 _ => {
512 return Err(EvalError {
513 message: "Unsupported types for `alternatively`".to_string(),
514 span: span.clone(),
515 });
516 }
517 }
518 return Ok(());
519 }
520 "parsingly" => {
521 let number_value = self.pop();
522
523 match number_value {
524 Some(Value::Text(str)) => {
525 let value = if let Ok(int_val) = str.parse::<i64>() {
526 Value::Integer(int_val)
527 } else if let Ok(float_val) = str.parse::<f64>() {
528 Value::Float(float_val)
529 } else {
530 return Err(EvalError {
531 message: format!("Couldn't parse '{}'", str),
532 span: span.clone(),
533 });
534 };
535
536 self.push(value);
537 }
538 Some(Value::Integer(_)) => {
539 self.push(number_value.unwrap());
540 }
541 Some(Value::Float(_)) => {
542 self.push(number_value.unwrap());
543 }
544 None => {
545 return Err(EvalError {
546 message: "Need value on stack for `parsingly`".to_string(),
547 span: span.clone(),
548 });
549 }
550 }
551 return Ok(());
552 }
553 "equally" => {
554 let a = self.pop();
555 let b = self.pop();
556 if a.is_none() || b.is_none() {
557 return Err(EvalError {
558 message: "Need two values on stack for `equally`".to_string(),
559 span: span.clone(),
560 });
561 }
562
563 match (a, b) {
564 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
565 self.push(Value::Integer(if a_val == b_val { 1 } else { 0 }));
566 }
567 (Some(Value::Float(a_val)), Some(Value::Integer(b_val))) => {
568 self.push(Value::Integer(if a_val == b_val as f64 {
569 1
570 } else {
571 0
572 }));
573 }
574 (Some(Value::Integer(a_val)), Some(Value::Float(b_val))) => {
575 self.push(Value::Integer(if a_val as f64 == b_val {
576 1
577 } else {
578 0
579 }));
580 }
581 (Some(Value::Float(a_val)), Some(Value::Float(b_val))) => {
582 self.push(Value::Integer(if a_val == b_val { 1 } else { 0 }));
583 }
584 _ => {
585 unimplemented!("TODO");
586 }
587 }
588 return Ok(());
589 }
590 "conjointly" => {
591 let b = self.pop();
592 let a = self.pop();
593 if a.is_none() || b.is_none() {
594 return Err(EvalError {
595 message: "Need two values on stack for `conjointly`".to_string(),
596 span: span.clone(),
597 });
598 }
599
600 match (&a, &b) {
601 (Some(Value::Text(a_val)), Some(Value::Text(b_val))) => {
602 self.push(Value::Text(a_val.to_owned() + b_val));
603 }
604 _ => {
605 return Err(EvalError {
606 message: format!(
607 "Need two strings on stack for `conjointly`, got {:?} {:?}",
608 b, a
609 ),
610 span: span.clone(),
611 });
612 }
613 }
614 return Ok(());
615 }
616 "modularly" => {
617 let b = self.pop();
618 let a = self.pop();
619 if a.is_none() || b.is_none() {
620 return Err(EvalError {
621 message: "Need two values on stack for `modularly`".to_string(),
622 span: span.clone(),
623 });
624 }
625
626 match (&a, &b) {
627 (Some(Value::Integer(a_val)), Some(Value::Integer(b_val))) => {
628 if *b_val == 0 {
629 return Err(EvalError {
630 message: "Received divisor of 0 in `modularly`".to_string(),
631 span: span.clone(),
632 });
633 }
634 self.push(Value::Integer(a_val % b_val));
635 }
636 _ => {
637 return Err(EvalError {
638 message: format!(
639 "Invalid types for `modularly`, got {:?} {:?}",
640 a, b
641 ),
642 span: span.clone(),
643 });
644 }
645 }
646 return Ok(());
647 }
648 "debuggably" => {
649 let index = &self
650 .line_index
651 .as_ref()
652 .expect("Need line index for warnings");
653 let vars: String = variable_store
654 .store
655 .iter()
656 .map(|f| format!("{} -> {:?}, ", f.1.0, f.1.1))
657 .collect();
658 let _ = Report::build(ReportKind::Advice, (index.filename, span.clone()))
659 .with_code("W101")
660 .with_message("Debug")
661 .with_label(
662 Label::new((index.filename, span.clone()))
663 .with_message(format!("Stack: {:?}", self.stack))
664 .with_color(Color::Blue),
665 )
666 .with_label(
667 Label::new((index.filename, span.clone()))
668 .with_message(format!("Vars: {}", vars))
669 .with_color(Color::Blue),
670 )
671 .finish()
672 .eprint((index.filename, Source::from(index.src)));
673 return Ok(());
674 }
675 &_ => unimplemented!(),
676 }
677 }
678 }
679
680 for (ch_ident, n) in self.idents.clone() {
684 if let (Node::Chapter(_, children), _) = n {
685 if !is_anagram(&ident, &ch_ident) {
686 continue;
687 }
688
689 if ident == *ch_ident && !is_flat_adverb {
691 return Err(EvalError {
692 message: format!("Invalid func call, need an anagram of {}", ident),
693 span: span.clone(),
694 });
695 }
696
697 let mut variable_store = VariableStore::new();
698
699 for child in children.iter().rev() {
701 let was_return = self.eval_node(&child, &mut variable_store)?;
702 if was_return {
703 break;
704 }
705 }
706
707 let top = self.stack.pop();
709 self.stack.clear();
710 if let Some(t) = top {
711 self.stack.push(t);
712 }
713
714 return Ok(());
715 }
716 }
717
718 return Err(EvalError {
719 message: format!("Could not find chapter {}", ident),
720 span: span.clone(),
721 });
722 }
723
724 fn print_warning(&self, title: &str, message: &str, code: &str, span: &Span) {
725 let index = &self
726 .line_index
727 .as_ref()
728 .expect("Need line index for warnings");
729 let _ = Report::build(ReportKind::Warning, (index.filename, span.clone()))
730 .with_code(code)
731 .with_message(title)
732 .with_label(
733 Label::new((index.filename, span.clone()))
734 .with_message(message)
735 .with_color(Color::Yellow),
736 )
737 .finish()
738 .eprint((index.filename, Source::from(index.src)));
739 }
740
741 fn eval_value_ref(
742 &mut self,
743 lines_below: isize,
744 variable_store: &VariableStore,
745 span: &Span,
746 ) -> Result<(), EvalError> {
747 let our_line = self
748 .line_index
749 .as_ref()
750 .expect("Evaluator needs LineIndex")
751 .get_line(span.start);
752 let wanted_line = (our_line as isize + lines_below) as usize;
753 let wanted_nodes = self.line_to_literal.get(&wanted_line);
754
755 match wanted_nodes {
756 Some(nodes) => {
757 let mut my_rng = rng();
758 let node = (*nodes).choose(&mut my_rng);
759
760 let value = match node {
762 Some(Node::FloatLiteral(f)) => Value::Float(*f),
763 Some(Node::IntLiteral(i)) => Value::Integer(*i),
764 Some(Node::StringLiteral(s)) => Value::Text(
765 s.strip_prefix('"')
766 .unwrap()
767 .strip_suffix('"')
768 .unwrap()
769 .to_owned(),
770 ),
771 Some(Node::Adverb(a)) => {
772 let focus_var_value = self.get_focus_var(variable_store);
775 let value = count_letters_in(focus_var_value, a) as i64;
776 Value::Integer(value)
777 }
778 Some(Node::ValueRef(value)) => {
779 Value::Integer((*value as i64).abs())
783 }
784 None => {
785 let msg = if lines_below < 0 {
786 format!("No value {} lines above", -lines_below)
787 } else {
788 format!("No value {} lines below", lines_below)
789 };
790 return Err(EvalError {
791 message: msg,
792 span: span.clone(),
793 });
794 }
795 _ => {
796 panic!("Unsupported Node being pushed onto stack");
797 }
798 };
799
800 let nodes_len = nodes.len();
803 if nodes_len > 1 as usize {
804 let msg = match node {
805 Some(Node::Adverb(a)) => {
806 format!(
807 "Value deduced from Adverb (\"{}\") which was chosen at random",
808 a
809 )
810 }
811 _ => "Value deduced was chosen at random".to_owned(),
812 };
813 self.print_warning("Possible gotcha", &msg, "W102", span);
814 }
815
816 self.stack.push(value);
817 Ok(())
818 }
819 None => {
820 let msg = if lines_below < 0 {
821 format!("No value {} lines above", -lines_below)
822 } else {
823 format!("No value {} lines below", lines_below)
824 };
825 return Err(EvalError {
826 message: msg,
827 span: span.clone(),
828 });
829 }
830 }
831 }
832
833 fn eval_var_assign(
834 &mut self,
835 raw_ident: &str,
836 variable_store: &mut VariableStore,
837 span: &Span,
838 ) -> Result<(), EvalError> {
839 let val = self.stack.pop();
840 match val {
841 Some(v) => {
842 variable_store.insert(&raw_ident, v);
843 Ok(())
844 }
845 None => Err(EvalError {
846 message: "Stack empty".to_string(),
847 span: span.clone(),
848 }),
849 }
850 }
851
852 fn eval_var_read(
853 &mut self,
854 raw_ident: &str,
855 variable_store: &VariableStore,
856 span: &Span,
857 ) -> Result<(), EvalError> {
858 let ident = sort_ident(&normalize_ident(raw_ident));
860
861 let value = variable_store.get(&ident);
862 match value {
863 Some(v) => {
864 self.stack.push(v.clone());
865 Ok(())
866 }
867 None => Err(EvalError {
868 message: format!("Unknown variable {}", raw_ident),
869 span: span.clone(),
870 }),
871 }
872 }
873
874 fn eval_hack(
875 &mut self,
876 a: &String,
877 maybe_b: &Option<String>,
878 variable_store: &VariableStore,
879 span: &Span,
880 ) -> Result<(), EvalError> {
881 let val = self.stack.pop();
882
883 match val {
884 Some(Value::Integer(v)) if v == 0 => {
885 if let Some(b) = maybe_b {
886 self.eval_func_call(b, b.len(), variable_store, span)
887 } else {
888 Ok(())
889 }
890 }
891 Some(Value::Integer(v)) if v == 1 => {
892 self.eval_func_call(a, a.len(), variable_store, span)
893 }
894 _ => Err(EvalError {
895 message: format!(
896 "Bad value for hack statement, expected 1 or 0, got {:?}",
897 val
898 ),
899 span: span.clone(),
900 }),
901 }
902 }
903
904 fn eval_focus(
905 &mut self,
906 t: isize,
907 variable_store: &mut VariableStore,
908 _span: &Span,
909 ) -> Result<(), EvalError> {
910 let value = self.get_focus_var(variable_store);
911
912 variable_store.insert("intently", Value::Integer((value - (t as u8)) as i64));
913 Ok(())
914 }
915
916 fn get_focus_var(&self, variable_store: &VariableStore) -> u8 {
917 match variable_store.get("intently") {
918 Some(Value::Integer(r)) => *r as u8,
919 _ => b'r',
920 }
921 }
922}
923
924#[derive(Debug, Clone)]
926pub struct LineIndex<'a> {
927 line_starts: Vec<usize>,
928 filename: &'a str,
929 src: &'a str,
930}
931
932impl<'a> LineIndex<'a> {
933 pub fn new(src: &'a str, filename: &'a str) -> Self {
934 let mut line_starts = vec![0]; let mut last_was_newline = false;
937 for (i, c) in src.bytes().enumerate() {
938 if c == b'\n' {
939 if !last_was_newline {
940 line_starts.push(i + 1);
941 last_was_newline = true;
942 }
943 } else {
944 last_was_newline = false;
945 }
946 }
947
948 Self {
949 line_starts,
950 filename,
951 src,
952 }
953 }
954
955 fn get_line(&self, byte_offset: usize) -> usize {
956 match self.line_starts.binary_search(&byte_offset) {
957 Ok(line) => line + 1,
958 Err(line) => line,
959 }
960 }
961}
962
963fn is_anagram(a: &str, b: &str) -> bool {
966 let mut counts_a: HashMap<char, i32> = HashMap::new();
967 let mut counts_b: HashMap<char, i32> = HashMap::new();
968
969 for c in a.chars() {
970 *counts_a.entry(c).or_insert(0) += 1;
971 }
972
973 for c in b.chars() {
974 *counts_b.entry(c).or_insert(0) += 1;
975 }
976
977 return counts_a == counts_b;
978}
979
980fn count_letters_in(letter: u8, word: &str) -> usize {
981 word.bytes().filter(|x| *x == letter).count()
982}
983
984fn collect_values(
985 nodes: &Vec<Spanned<Node>>,
986 line_index: &Option<LineIndex>,
987) -> HashMap<usize, Vec<Node>> {
988 let mut line_to_literal: HashMap<usize, Vec<Node>> = HashMap::new();
989 for node in nodes {
990 match node {
992 (Node::FloatLiteral(f), span) => {
993 let line = line_index
994 .as_ref()
995 .expect("Evaluator needs LineIndex")
996 .get_line(span.start);
997 line_to_literal
998 .entry(line)
999 .or_default()
1000 .push(Node::FloatLiteral(*f));
1001 }
1002 (Node::IntLiteral(i), span) => {
1003 let line = line_index
1004 .as_ref()
1005 .expect("Evaluator needs LineIndex")
1006 .get_line(span.start);
1007 line_to_literal
1008 .entry(line)
1009 .or_default()
1010 .push(Node::IntLiteral(*i));
1011 }
1012 (Node::StringLiteral(i), span) => {
1013 let line = line_index
1014 .as_ref()
1015 .expect("Evaluator needs LineIndex")
1016 .get_line(span.start);
1017 line_to_literal
1018 .entry(line)
1019 .or_default()
1020 .push(Node::StringLiteral(i.to_owned()));
1021 }
1022 (Node::Adverb(a), span) => {
1023 let line = line_index
1024 .as_ref()
1025 .expect("Evaluator needs LineIndex")
1026 .get_line(span.start);
1027 line_to_literal
1028 .entry(line)
1029 .or_default()
1030 .push(Node::Adverb(a.to_string()));
1031 }
1032 (Node::Story(ident, children), span) => {
1033 let line = line_index
1034 .as_ref()
1035 .expect("Evaluator needs LineIndex")
1036 .get_line(span.start);
1037 line_to_literal
1038 .entry(line)
1039 .or_default()
1040 .push(Node::Adverb(ident.to_owned()));
1041 line_to_literal.extend(collect_values(children, line_index));
1042 }
1043 (Node::Chapter(ident, children), span) => {
1044 let line = line_index
1045 .as_ref()
1046 .expect("Evaluator needs LineIndex")
1047 .get_line(span.start);
1048 line_to_literal
1049 .entry(line)
1050 .or_default()
1051 .push(Node::Adverb(ident.to_owned()));
1052 line_to_literal.extend(collect_values(children, line_index));
1053 }
1054 (Node::FuncCall(ident, words), span) => {
1055 if ident != "debuggably" {
1058 let line = line_index
1059 .as_ref()
1060 .expect("Evaluator needs LineIndex")
1061 .get_line(span.start);
1062 line_to_literal
1063 .entry(line)
1064 .or_default()
1065 .push(Node::Adverb(ident.to_owned()));
1066 }
1067 line_to_literal.extend(collect_values(words, line_index));
1068 }
1069 (Node::FuncReturn, _) => (),
1070 (Node::ValueRef(_n), span) => {
1071 let line = line_index
1072 .as_ref()
1073 .expect("Evaluator needs LineIndex")
1074 .get_line(span.start);
1075 line_to_literal
1076 .entry(line)
1077 .or_default()
1078 .push(node.unspanned().clone());
1079 }
1080 (Node::Word(_), _) => (),
1081 (Node::VariableAssign(ident), span) => {
1082 let line = line_index
1083 .as_ref()
1084 .expect("Evaluator needs LineIndex")
1085 .get_line(span.start);
1086 line_to_literal
1087 .entry(line)
1088 .or_default()
1089 .push(Node::Adverb(ident.to_owned()));
1090 }
1091 (Node::VariableRead(ident, child), span) => {
1092 let children = vec![(*child).as_ref().clone()];
1093 line_to_literal.extend(collect_values(&children, line_index));
1094
1095 let line = line_index
1096 .as_ref()
1097 .expect("Evaluator needs LineIndex")
1098 .get_line(span.start);
1099 line_to_literal
1100 .entry(line)
1101 .or_default()
1102 .push(Node::Adverb(ident.to_owned()));
1103 }
1104 (Node::Hack(ident, other), span) => {
1105 let line = line_index
1106 .as_ref()
1107 .expect("Evaluator needs LineIndex")
1108 .get_line(span.start);
1109 line_to_literal
1110 .entry(line)
1111 .or_default()
1112 .push(Node::Adverb(ident.to_owned()));
1113 if let Some(o) = other {
1114 line_to_literal
1115 .entry(line)
1116 .or_default()
1117 .push(Node::Adverb(o.to_owned()));
1118 }
1119 }
1120 (Node::FocusChange(_), _) => (),
1121 }
1122 }
1123
1124 return line_to_literal;
1125}
1126
1127fn normalize_ident(ident: &str) -> String {
1128 ident
1129 .trim_matches(|c: char| c.is_ascii_punctuation())
1130 .to_ascii_lowercase()
1131}
1132
1133pub fn sort_ident(ident: &str) -> String {
1134 let mut chars: Vec<char> = ident.chars().collect();
1135 chars.sort_unstable();
1136 chars.into_iter().collect()
1137}
1138
1139fn check_ident_clash(
1140 idents: &HashMap<String, Spanned<Node>>,
1141 name: &str,
1142 span: &Span,
1143) -> Result<(), EvalError> {
1144 if BUILT_INS.contains(name) {
1145 return Err(EvalError {
1146 message: format!("Duplicate identifier {}", &name),
1147 span: span.clone(),
1148 });
1149 }
1150
1151 if idents.contains_key(name) {
1152 return Err(EvalError {
1153 message: format!("Duplicate identifier {}", &name),
1154 span: span.clone(),
1155 });
1156 }
1157
1158 return Ok(());
1159}
1160
1161fn collect_idents(
1162 idents: &mut HashMap<String, Spanned<Node>>,
1163 nodes: &Vec<Spanned<Node>>,
1164) -> Result<Option<usize>, EvalError> {
1165 let mut story: Option<usize> = None;
1166 for (i, n) in nodes.iter().enumerate() {
1167 match n {
1168 (Node::Story(name, children), span) => {
1169 story = Some(i);
1170 let ident = normalize_ident(name);
1171 check_ident_clash(idents, &ident, span)?;
1172 idents.insert(ident.to_string(), n.clone());
1173 collect_idents(idents, children)?;
1174 }
1175 (Node::Chapter(name, _children), span) => {
1176 let ident = normalize_ident(name);
1177 check_ident_clash(idents, &ident, span)?;
1178 idents.insert(ident.to_string(), n.clone());
1179 }
1180 (Node::IntLiteral(_), _span) => (),
1181 (Node::FloatLiteral(_), _span) => (),
1182 (Node::StringLiteral(_), _span) => (),
1183 (Node::Adverb(_), _span) => (),
1184 (Node::Word(_), _span) => (),
1185 (Node::FuncCall(_, _), _span) => (),
1186 (Node::ValueRef(_), _span) => (),
1187 (Node::Hack(_, _), _span) => (),
1188 (Node::VariableRead(_, _child), _span) => (),
1189 (Node::VariableAssign(_), _span) => (),
1190 (Node::FocusChange(_), _span) => (),
1191 _ => {
1192 unimplemented!("TODO {:?}", n);
1193 }
1194 }
1195 }
1196 Ok(story)
1197}
1198
1199fn count_words(nodes: &Vec<Spanned<Node>>) -> usize {
1200 let mut result = 0;
1204 for node in nodes {
1205 match node {
1206 (Node::StringLiteral(s), _) => result += s.split_whitespace().count(),
1207 (Node::Word(_), _) => result += 1,
1208 (Node::Adverb(_), _) => result += 1,
1209 (Node::FloatLiteral(_), _) => result += 1,
1210 (Node::IntLiteral(_), _) => result += 1,
1211 _ => panic!("Unexpected node type in count words"),
1212 }
1213 }
1214 result
1215}
1216
1217#[cfg(test)]
1218mod tests {
1219 use super::*;
1220 use crate::parser::lex_to_parsed_result;
1221
1222 #[test]
1223 fn test_builtin_func_call() {
1224 let nodes = vec![
1225 Node::Story(
1226 "testly".to_string(),
1227 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1228 )
1229 .spanned(0..0),
1230 ];
1231 let index = LineIndex::new("", "test.ks");
1232
1233 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1234 evaluator.push(Value::Integer(5));
1235 evaluator.push(Value::Integer(5));
1236 let res = evaluator.eval_script();
1237 assert_eq!(res, Ok(vec![Value::Integer(25)]));
1238 }
1239
1240 #[test]
1241 fn test_builtin_func_call_beyond() {
1242 let nodes = vec![
1243 Node::Story(
1244 "testly".to_string(),
1245 vec![Node::FuncCall("beyodn".to_string(), vec![]).spanned(0..0)],
1246 )
1247 .spanned(0..0),
1248 ];
1249
1250 let index = LineIndex::new("", "test.ks");
1251
1252 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1253 evaluator.push(Value::Integer(8));
1254 evaluator.push(Value::Integer(0));
1255 let res = evaluator.eval_script();
1256 assert_eq!(res, Ok(vec![Value::Integer(1)]));
1257 }
1258
1259 #[test]
1260 fn test_builtin_func_call_must_be_anagram() {
1261 let nodes = vec![
1262 Node::Story(
1263 "testly".to_string(),
1264 vec![Node::FuncCall("multiply".to_string(), vec![]).spanned(0..0)],
1265 )
1266 .spanned(0..0),
1267 ];
1268
1269 let index = LineIndex::new("", "test.ks");
1270
1271 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1272 evaluator.push(Value::Integer(5));
1273 evaluator.push(Value::Integer(5));
1274 let res = evaluator.eval_script();
1275 assert_eq!(
1276 res,
1277 Err(EvalError {
1278 message: "Invalid func call, need an anagram of multiply".to_string(),
1279 span: 0..0
1280 })
1281 );
1282 }
1283
1284 #[test]
1285 fn test_custom_func_call() {
1286 let nodes = vec![
1287 Node::Story(
1288 "testly".to_string(),
1289 vec![Node::FuncCall("styleit".to_string(), vec![]).spanned(0..0)],
1290 )
1291 .spanned(0..0),
1292 Node::Chapter(
1293 "testily".to_string(),
1294 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1295 )
1296 .spanned(0..0),
1297 ];
1298
1299 let index = LineIndex::new("", "test.ks");
1300
1301 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1302 evaluator.push(Value::Integer(5));
1303 evaluator.push(Value::Integer(5));
1304 let res = evaluator.eval_script();
1305 assert_eq!(res, Ok(vec![Value::Integer(25)]));
1306 }
1307
1308 #[test]
1309 fn test_custom_func_call_must_be_anagram() {
1310 let nodes = vec![
1311 Node::Story(
1312 "testly".to_string(),
1313 vec![Node::FuncCall("testily".to_string(), vec![]).spanned(0..0)],
1314 )
1315 .spanned(0..0),
1316 Node::Chapter("testily".to_string(), vec![]).spanned(0..0),
1317 ];
1318
1319 let index = LineIndex::new("", "test.ks");
1320
1321 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1322 let res = evaluator.eval_script();
1323 assert_eq!(
1324 res,
1325 Err(EvalError {
1326 message: "Invalid func call, need an anagram of testily".to_string(),
1327 span: 0..0
1328 })
1329 );
1330 }
1331
1332 #[test]
1333 fn test_custom_func_call_flat_adverb_no_anagram_necessary() {
1334 let nodes = vec![
1335 Node::Story(
1336 "testly".to_string(),
1337 vec![Node::FuncCall("beyond".to_string(), vec![]).spanned(0..0)],
1338 )
1339 .spanned(0..0),
1340 ];
1341
1342 let index = LineIndex::new("", "test.ks");
1343
1344 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1345 evaluator.push(Value::Integer(5));
1346 evaluator.push(Value::Integer(10));
1347 let res = evaluator.eval_script();
1348 assert_eq!(res, Ok(vec![Value::Integer(0)]));
1349 }
1350
1351 #[test]
1354 fn test_func_call_only_one_value_after_return() {
1355 let nodes = vec![
1356 Node::Story(
1357 "testly".to_string(),
1358 vec![Node::FuncCall("tesitly".to_string(), vec![]).spanned(0..0)],
1359 )
1360 .spanned(0..0),
1361 Node::Chapter("testily".to_string(), vec![]).spanned(0..0),
1362 ];
1363
1364 let index = LineIndex::new("", "test.ks");
1365
1366 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1367 evaluator.push(Value::Integer(5));
1368 evaluator.push(Value::Integer(10));
1369 let res = evaluator.eval_script();
1370 assert_eq!(res, Ok(vec![Value::Integer(10)]));
1371 }
1372
1373 #[test]
1374 fn test_value_push() {
1375 let src = "This story starts testly.\nThere is something with a value 2 lines below.\nLine one\nMy secret value is 42";
1376 let index = LineIndex::new(src, "test.ks");
1377 let nodes = vec![
1378 Node::Story(
1379 "testly".to_string(),
1380 vec![Node::ValueRef(2).spanned(26..72)],
1381 )
1382 .spanned(0..25),
1383 Node::IntLiteral(42).spanned(101..103),
1384 ];
1385
1386 let mut evaluator = Evaluator::new(nodes, Some(index));
1387 let res = evaluator.eval_script();
1388 assert_eq!(res, Ok(vec![Value::Integer(42)]));
1389 }
1390
1391 #[test]
1392 fn test_value_push_above() {
1393 let src = "This story starts testly.\nMy secret value is 42\nLine one\nThere is something with a value 2 lines above.\nLine one\nMy secret value is 1234\nThis story ends testly.";
1394 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1395 let index = LineIndex::new(src, "test.ks");
1396
1397 let mut evaluator = Evaluator::new(nodes, Some(index));
1398 let res = evaluator.eval_script();
1399 assert_eq!(res, Ok(vec![Value::Integer(42)]));
1400 }
1401
1402 #[test]
1403 fn test_value_push_using_above() {
1404 let src = "This story starts testly.\nThere is a value 2 lines below.\nLine one\nThere is something with a value 2 lines above.\nLine one\nMy secret value is 1234\nThis story ends testly.";
1405 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1406 let index = LineIndex::new(src, "test.ks");
1407
1408 let mut evaluator = Evaluator::new(nodes, Some(index));
1409 let res = evaluator.eval_script();
1410 assert_eq!(res, Ok(vec![Value::Integer(2), Value::Integer(2)]));
1411 }
1412
1413 #[test]
1414 fn test_value_push_float() {
1415 let src = "This story starts testly.\n\n\n\n\nThere is something with a value 2 lines below.\n\nLine one\n\nMy secret value is 4.2";
1417 let index = LineIndex::new(src, "test.ks");
1418 let nodes = vec![
1419 Node::Story(
1420 "testly".to_string(),
1421 vec![Node::ValueRef(2).spanned(30..76)],
1422 )
1423 .spanned(0..25),
1424 Node::FloatLiteral(4.2).spanned(107..109),
1425 ];
1426
1427 let mut evaluator = Evaluator::new(nodes, Some(index));
1428 let res = evaluator.eval_script();
1429 assert_eq!(res, Ok(vec![Value::Float(4.2)]));
1430 }
1431
1432 #[test]
1433 fn test_value_push_string() {
1434 let src = "This story starts testly.\n\n\n\n\nThere is something with a value 2 lines below.\n\nLine one\n\nMy secret value is \"hello world\"";
1436 let index = LineIndex::new(src, "test.ks");
1437 let nodes = vec![
1438 Node::Story(
1439 "testly".to_string(),
1440 vec![Node::ValueRef(2).spanned(30..76)],
1441 )
1442 .spanned(0..25),
1443 Node::StringLiteral("\"hello world\"".to_owned()).spanned(107..120),
1444 ];
1445
1446 let mut evaluator = Evaluator::new(nodes, Some(index));
1447 let res = evaluator.eval_script();
1448 assert_eq!(res, Ok(vec![Value::Text("hello world".to_owned())]));
1449 }
1450
1451 #[test]
1452 fn test_value_push_random_float() {
1453 let src = "This story starts testly.\n\n\n\n\nThere is something with a value 2 lines below.\n\nLine one\n\nMy secret value is 4.2 or is it 6.9 or maybe 95.30";
1455 let index = LineIndex::new(src, "test.ks");
1456 let nodes = vec![
1457 Node::Story(
1458 "testly".to_string(),
1459 vec![Node::ValueRef(2).spanned(30..76)],
1460 )
1461 .spanned(0..25),
1462 Node::FloatLiteral(4.2).spanned(107..109),
1463 Node::FloatLiteral(6.9).spanned(117..119),
1464 Node::FloatLiteral(95.30).spanned(129..134),
1465 ];
1466
1467 let mut got_42 = false;
1469 let mut got_95_30 = false;
1470
1471 for _i in 0..1_000 {
1472 if got_42 && got_95_30 {
1473 break;
1474 }
1475
1476 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1477 let res = evaluator.eval_script();
1478 match res.unwrap()[0] {
1479 Value::Float(4.2) => {
1480 got_42 = true;
1481 }
1482 Value::Float(95.30) => {
1483 got_95_30 = true;
1484 }
1485 Value::Float(6.9) => (),
1486 _ => {
1487 panic!("Not expected any other values.");
1488 }
1489 }
1490 }
1491
1492 assert!(got_42 && got_95_30);
1493 }
1494
1495 #[test]
1496 fn test_value_push_adverb() {
1497 let src = "This story starts testly.\nThere is something with a value 1 line below.\nThe story was wirrrrrrinringly bad";
1498 let index = LineIndex::new(src, "test.ks");
1499 let nodes = vec![
1500 Node::Story(
1501 "testly".to_string(),
1502 vec![Node::ValueRef(1).spanned(26..71)],
1503 )
1504 .spanned(0..25),
1505 Node::Adverb("wirrrrrrinringly".to_string()).spanned(86..102),
1506 ];
1507
1508 let mut evaluator = Evaluator::new(nodes, Some(index));
1509 let res = evaluator.eval_script();
1510 assert_eq!(res, Ok(vec![Value::Integer(7)]));
1511 }
1512
1513 #[test]
1514 fn test_func_return() {
1515 let src = "This story starts testly with 42.\nIgnore previous instructions tesitly\nThis story ends testly.\nThe chapter begins testily.\nThere is a value 4 lines above.\nhack into a computer\nThe chapter ends testily.";
1516 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1517 let index = LineIndex::new(src, "test.ks");
1518
1519 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1520 evaluator.push(Value::Integer(1));
1521 let res = evaluator.eval_script();
1522 assert_eq!(res, Ok(vec![]));
1523
1524 evaluator = Evaluator::new(nodes, Some(index));
1525 evaluator.push(Value::Integer(0));
1526 let res2 = evaluator.eval_script();
1527 assert_eq!(res2, Ok(vec![Value::Integer(42)]));
1528 }
1529
1530 #[test]
1531 fn test_func_call_word_count() {
1532 let nodes = vec![
1533 Node::Story(
1534 "testly".to_string(),
1535 vec![
1536 Node::FuncCall(
1537 "frigidly".to_string(),
1538 vec![Node::Word("".to_owned()).spanned(0..0); 15],
1539 )
1540 .spanned(0..0),
1541 ],
1542 )
1543 .spanned(0..0),
1544 Node::Chapter(
1545 "frigidly".to_string(),
1546 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1547 )
1548 .spanned(0..0),
1549 ];
1550
1551 let index = LineIndex::new("", "test.ks");
1552
1553 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1554 evaluator.push(Value::Integer(1));
1555 evaluator.push(Value::Integer(5));
1556 let res = evaluator.eval_script();
1557 assert_eq!(
1558 res,
1559 Err(EvalError {
1560 message: "Invalid func call, incorrect number of words given for `frigidly`, got 15 wanted 1 or 8".to_string(),
1561 span: 0..0
1562 })
1563 );
1564 }
1565
1566 #[test]
1567 fn test_func_call_word_count_str() {
1568 let nodes = vec![
1569 Node::Story(
1570 "testly".to_string(),
1571 vec![
1572 Node::FuncCall(
1573 "fyl".to_string(),
1574 vec![Node::StringLiteral("multiple words here".to_owned()).spanned(0..0)],
1575 )
1576 .spanned(0..0),
1577 ],
1578 )
1579 .spanned(0..0),
1580 Node::Chapter(
1581 "fly".to_string(),
1582 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1583 )
1584 .spanned(0..0),
1585 ];
1586
1587 let index = LineIndex::new("", "test.ks");
1588
1589 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1590 evaluator.push(Value::Integer(6));
1591 evaluator.push(Value::Integer(5));
1592 let res = evaluator.eval_script();
1593 assert_eq!(res, Ok(vec![Value::Integer(30)]));
1594 }
1595
1596 #[test]
1597 fn test_variables() {
1598 let nodes = vec![
1599 Node::Story(
1600 "testly".to_string(),
1601 vec![
1602 Node::VariableRead(
1603 "oflly".to_string(),
1604 Box::new(Node::IntLiteral(0).spanned(0..0)),
1605 )
1606 .spanned(0..0),
1607 Node::VariableRead(
1608 "oflly".to_string(),
1609 Box::new(Node::IntLiteral(0).spanned(0..0)),
1610 )
1611 .spanned(0..0),
1612 Node::VariableRead(
1613 "oflly".to_string(),
1614 Box::new(Node::IntLiteral(0).spanned(0..0)),
1615 )
1616 .spanned(0..0),
1617 Node::VariableAssign("folly".to_string()).spanned(0..0),
1618 ],
1619 )
1620 .spanned(0..0),
1621 ];
1622 let index = LineIndex::new("" , "test.ks");
1623
1624 let mut evaluator = Evaluator::new(nodes, Some(index));
1625 evaluator.push(Value::Integer(42));
1626 let res = evaluator.eval_script();
1627 assert_eq!(
1628 res,
1629 Ok(vec![
1630 Value::Integer(42),
1631 Value::Integer(42),
1632 Value::Integer(42)
1633 ])
1634 );
1635 }
1636
1637 #[test]
1638 fn test_hack_stmt() {
1639 let nodes = vec![
1640 Node::Story(
1641 "testly".to_string(),
1642 vec![Node::Hack("firgidly".to_string(), Some("fllyo".to_string())).spanned(0..0)],
1643 )
1644 .spanned(0..0),
1645 Node::Chapter(
1646 "frigidly".to_string(),
1647 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1648 )
1649 .spanned(0..0),
1650 Node::Chapter(
1651 "folly".to_string(),
1652 vec![Node::FuncCall("additioanlly".to_string(), vec![]).spanned(0..0)],
1653 )
1654 .spanned(0..0),
1655 ];
1656
1657 let index = LineIndex::new("", "test.ks");
1658
1659 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1660 evaluator.push(Value::Integer(5));
1661 evaluator.push(Value::Integer(5));
1662 evaluator.push(Value::Integer(0));
1663 let res = evaluator.eval_script();
1664 assert_eq!(res, Ok(vec![Value::Integer(10)]));
1665 }
1666
1667 #[test]
1668 fn test_hack_stmt_one() {
1669 let nodes = vec![
1670 Node::Story(
1671 "testly".to_string(),
1672 vec![Node::Hack("firgidly".to_string(), None).spanned(0..0)],
1673 )
1674 .spanned(0..0),
1675 Node::Chapter(
1676 "frigidly".to_string(),
1677 vec![Node::FuncCall("miltypul".to_string(), vec![]).spanned(0..0)],
1678 )
1679 .spanned(0..0),
1680 ];
1681
1682 let index = LineIndex::new("", "test.ks");
1683
1684 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1685 evaluator.push(Value::Integer(5));
1686 evaluator.push(Value::Integer(5));
1687 evaluator.push(Value::Integer(1));
1688 let res = evaluator.eval_script();
1689 assert_eq!(res, Ok(vec![Value::Integer(25)]));
1690 }
1691
1692 #[test]
1693 fn test_arithmetic_sub() {
1694 let nodes = vec![
1695 Node::Story(
1696 "testly".to_string(),
1697 vec![Node::FuncCall("deductviely".to_string(), vec![]).spanned(0..0)],
1698 )
1699 .spanned(0..0),
1700 ];
1701
1702 let index = LineIndex::new("", "test.ks");
1703
1704 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1705 evaluator.push(Value::Integer(5));
1706 evaluator.push(Value::Integer(1));
1707 let res = evaluator.eval_script();
1708 assert_eq!(res, Ok(vec![Value::Integer(4)]));
1709 }
1710
1711 #[test]
1712 fn test_arithmetic_div() {
1713 let nodes = vec![
1714 Node::Story(
1715 "testly".to_string(),
1716 vec![Node::FuncCall("divisibyl".to_string(), vec![]).spanned(0..0)],
1717 )
1718 .spanned(0..0),
1719 ];
1720
1721 let index = LineIndex::new("", "test.ks");
1722
1723 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1724 evaluator.push(Value::Integer(5));
1725 evaluator.push(Value::Integer(1));
1726 let res = evaluator.eval_script();
1727 assert_eq!(res, Ok(vec![Value::Float(5.0)]));
1728 }
1729
1730 #[test]
1731 fn test_focus_change() {
1732 let src = "This story starts testly with 42.\nintently = <stack>;```<content>\nThis story ends testly.";
1733 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1734 let index = LineIndex::new(src, "test.ks");
1735
1736 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1737 let res = evaluator.eval_script();
1738 assert_eq!(res, Ok(vec![Value::Integer(111)]));
1739 }
1740
1741 #[test]
1742 fn test_str_escapes() {
1743 let src = "This story starts testly with \"hello\\n\".\nThere is a value 1 line above.\nThis story ends testly.";
1744 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1745 let index = LineIndex::new(src, "test.ks");
1746
1747 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1748 let res = evaluator.eval_script();
1749 assert_eq!(res, Ok(vec![Value::Text("hello\\n".to_owned())]));
1750 }
1751
1752 #[test]
1753 fn test_str_newline() {
1754 let src = "This story starts testly with \"hello\n\".\nThere is a value 2 lines above.\nThis story ends testly.";
1755 let nodes = lex_to_parsed_result(src).into_result().unwrap();
1756 let index = LineIndex::new(src, "test.ks");
1757
1758 let mut evaluator = Evaluator::new(nodes.clone(), Some(index.clone()));
1759 let res = evaluator.eval_script();
1760 assert_eq!(res, Ok(vec![Value::Text("hello\n".to_owned())]));
1761 }
1762}