interp.rs 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. use crate::ast::*;
  2. use std::collections::HashMap;
  3. use rand::Rng;
  4. #[derive(Debug)]
  5. pub enum Value {
  6. Lit(Literal),
  7. }
  8. impl Value {
  9. fn to_string(&self) -> String {
  10. match self {
  11. Value::Lit(Literal::Str(s)) => s.clone(),
  12. Value::Lit(Literal::Atom(s)) => s.clone(),
  13. Value::Lit(Literal::Num(n)) => format!("{}", n),
  14. }
  15. }
  16. }
  17. pub struct State {
  18. scope: HashMap<String, Expr>,
  19. rand: rand::rngs::ThreadRng,
  20. }
  21. impl State {
  22. pub fn new() -> State {
  23. State {
  24. scope: HashMap::new(),
  25. rand: rand::thread_rng(),
  26. }
  27. }
  28. pub fn execute(&mut self, stmt: &Stmt) {
  29. match stmt {
  30. Stmt::Puts(expr) => {
  31. let val = self.eval(expr);
  32. println!("{}", val.to_string());
  33. }
  34. Stmt::Assn(name, expr) => {
  35. self.scope.insert(name.to_string(), expr.clone());
  36. }
  37. _ => panic!("unimplemented"),
  38. }
  39. }
  40. fn eval(&mut self, expr: &Expr) -> Value {
  41. match expr {
  42. Expr::Lit(l) => Value::Lit(l.clone()),
  43. Expr::Var(v) => {
  44. let e = if let Some(x) = self.scope.get(v) {
  45. x.clone()
  46. } else {
  47. panic!("no such thing: {}", v);
  48. };
  49. self.eval(&e)
  50. }
  51. Expr::Cat(cat) => {
  52. if cat.len() == 1 {
  53. self.eval(&cat[0])
  54. } else {
  55. let mut buf = String::new();
  56. for expr in cat {
  57. let val = self.eval(expr);
  58. buf.push_str(&val.to_string());
  59. }
  60. Value::Lit(Literal::Str(buf))
  61. }
  62. }
  63. Expr::Chc(choices) => {
  64. if choices.len() == 1 {
  65. self.eval(&choices[0].value)
  66. } else {
  67. self.choose(choices)
  68. }
  69. }
  70. _ => panic!("unimplemented: {:?}", expr),
  71. }
  72. }
  73. fn choose(&mut self, choices: &[Choice]) -> Value {
  74. let max = choices.iter().map(Choice::weight).sum();
  75. let mut choice = self.rand.gen_range(0..max);
  76. for ch in choices {
  77. if choice < ch.weight() {
  78. return self.eval(&ch.value);
  79. }
  80. choice -= ch.weight();
  81. }
  82. panic!("unreachable")
  83. }
  84. }