Skip to main content

killswitch/
eval.rs

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    // Used during evaluation.
42    stack: Vec<Value>,
43
44    // The nodes that this evaluator is evaluating.
45    nodes: Vec<Spanned<Node>>,
46
47    // A list of named nodes: chapters, stories, etc.
48    // Because of Rust's lifetimes, we use an index to refer to the Node,
49    // rather than a reference to the Node.
50    idents: HashMap<String, Spanned<Node>>,
51
52    // Helps look up line numbers for Spans. Optional to make it easier to write
53    // tests as not all nodes care about this.
54    line_index: Option<LineIndex<'a>>,
55
56    // A mapping from line number to a literal (int/float/str/adverb).
57    // Used for ValueRef evaluation.
58    line_to_literal: HashMap<usize, Vec<Node>>,
59
60    // Stack traces! We track FuncCalls here so we can print a nice stack trace
61    // if we have too many nested calls.
62    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    // TODO: Add more.
83    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        // Verification to ensure we aren't accidentally calling this function twice.
114        assert_eq!(self.idents.len(), 0);
115
116        // Pre-process nodes to find referencable elements. Like chapters, stories, values.
117        //
118        // An (index) reference to the Node containing the entry point of the
119        // script.
120        let story: Option<usize> = collect_idents(&mut self.idents, &self.nodes)?;
121
122        // Now start execution starting with children of `story`.
123        match story {
124            Some(i) => match self.nodes[i].clone() {
125                // TODO: Remove clone.
126                (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    // Returns `true` when `FuncReturn` was evaluated. Caller should use this as a signal
150    // appropriately.
151    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                // Nested chapters don't need to be evaluated.
192                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        // Handle infinite loops.
212        // For now just restrict nested loops.
213        // TODO: In future we won't be able to do this, as it will limit loops too much. Print stack on Ctrl+C instead.
214        // TODO: Also print the stacks here nicely.
215        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        // Track the function calls for stack traces.
224        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        // TODO: We can make func lookup faster here, by using the same trick as
239        // for variable reads.
240
241        // Process the ident to remove punctuation.
242        let ident = normalize_ident(raw_ident);
243
244        // Verify that this is a valid function call.
245        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        // Find the ident. Check built-ins first.
267        for built_in in BUILT_INS.iter() {
268            if is_anagram(&ident, built_in) {
269                // We cannot allow the names to match.
270                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        // If none of the built-ins match, then find a chapter with the name.
681        //
682        // TODO: Avoid the clones here.
683        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                // We cannot allow the names to match.
690                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                // Loop through nodes, back to front.
700                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                // Keep only the top value on the stack.
708                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                // Push onto the stack.
761                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                        // We look up the current focus variable, whatever char it is we count in the
773                        // adverb. Then push that as the value.
774                        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                        // We treat the number inside a value ref as a standard integer
780                        // For "above" refs we get a negative number, so we need to make
781                        // sure it's positive.
782                        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                // We print out a warning if this was chosen, because this behaviour is pretty surprising.
801                // Especially when it gets chosen randomly (as I have found).
802                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        // Process the ident to remove punctuation.
859        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// A LineIndex which ignores empty lines. Used for ValueRef evaluation.
925#[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]; // First line begins at offset 0.
935
936        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
963// Determines whether `a` is an anagram of `b`.
964// is_anagram("hunyamel", "humanely")
965fn 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        // TODO: Reduce `line` duplication here.
991        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                // Do not add `debuggably` since we use it for
1056                // debugging. We want it to have no side effects.
1057                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    // We need to handle the counting of certain words in a custom way.
1201    // As an example, string literals are a single node but can contain
1202    // multiple words.
1203    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    // Verifies that whatever is on the stack at the end of function
1352    // evaluation is cleared, with only the top of the stock preserved.
1353    #[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        // Also testing repeated newlines here. These should be ignored.
1416        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        // Also testing repeated newlines here. These should be ignored.
1435        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        // Also testing repeated newlines here. These should be ignored.
1454        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        // We expect to get a random value. Loop until we get at least two of the values.
1468        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("" /* XXX */, "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}