ソースを参照

make tuples lazy

Getty Ritter 2 年 前
コミット
feef074452
1 ファイル変更29 行追加24 行削除
  1. 29 24
      src/interp.rs

+ 29 - 24
src/interp.rs

@@ -13,7 +13,7 @@ macro_rules! bail {
 #[derive(Debug, Clone)]
 pub enum Value {
     Lit(Literal),
-    Tup(Vec<Value>),
+    Tup(Vec<Thunk>),
     Builtin(&'static BuiltinFunc),
     Closure(Closure),
     Nil,
@@ -47,7 +47,12 @@ impl Value {
                     if i > 0 {
                         buf.push_str(", ");
                     }
-                    buf.push_str(&val.to_string());
+                    match val {
+                        Thunk::Value(v) => buf.push_str(&v.to_string()),
+                        Thunk::Expr(..) => buf.push_str("#<unevaluated>"),
+                        Thunk::Builtin(func) =>
+                            buf.push_str(&format!("#<builtin {}>", func.name)),
+                    }
                 }
                 buf.push('>');
                 f(&buf)
@@ -151,8 +156,8 @@ impl fmt::Debug for BuiltinFunc {
 }
 
 #[derive(Debug, Clone)]
-enum NamedItem {
-    Expr(ExprRef),
+pub enum Thunk {
+    Expr(ExprRef, Env),
     Value(Value),
     Builtin(&'static BuiltinFunc),
 }
@@ -160,7 +165,7 @@ enum NamedItem {
 type Env = Option<Rc<Scope>>;
 #[derive(Debug)]
 pub struct Scope {
-    vars: HashMap<Name, NamedItem>,
+    vars: HashMap<Name, Thunk>,
     parent: Env,
 }
 
@@ -172,7 +177,7 @@ pub struct Closure {
 
 pub struct State {
     ast: RefCell<ASTArena>,
-    root_scope: RefCell<HashMap<Name, NamedItem>>,
+    root_scope: RefCell<HashMap<Name, Thunk>>,
     rand: RefCell<rand::rngs::ThreadRng>,
     parser: crate::grammar::StmtsParser,
 }
@@ -195,12 +200,12 @@ impl State {
             let sym = s.ast.borrow_mut().add_string(builtin.name);
             s.root_scope
                 .borrow_mut()
-                .insert(sym, NamedItem::Builtin(builtin));
+                .insert(sym, Thunk::Builtin(builtin));
         }
         s
     }
 
-    fn lookup(&self, env: &Env, name: Name) -> Result<NamedItem, Error> {
+    fn lookup(&self, env: &Env, name: Name) -> Result<Thunk, Error> {
         if let Some(env) = env {
             if let Some(ne) = env.vars.get(&name) {
                 Ok(ne.clone())
@@ -269,23 +274,23 @@ impl State {
             }
 
             Stmt::Fix(name) => {
-                let expr = match self.lookup(&None, *name)? {
-                    NamedItem::Expr(e) => e,
+                let (expr, env) = match self.lookup(&None, *name)? {
+                    Thunk::Expr(e, env) => (e, env),
                     // if it's not an expr, then our work here is done
                     _ => return Ok(()),
                 };
-                let val = self.eval(expr, &None)?;
-                self.root_scope.borrow_mut().insert(*name, NamedItem::Value(val));
+                let val = self.eval(expr, &env)?;
+                self.root_scope.borrow_mut().insert(*name, Thunk::Value(val));
             }
 
             Stmt::Assn(fixed, name, expr) => {
                 if *fixed {
                     let val = self.eval(*expr, &None)?;
-                    self.root_scope.borrow_mut().insert(*name, NamedItem::Value(val));
+                    self.root_scope.borrow_mut().insert(*name, Thunk::Value(val));
                 } else {
                     self.root_scope
                         .borrow_mut()
-                        .insert(*name, NamedItem::Expr(*expr));
+                        .insert(*name, Thunk::Expr(*expr, None));
                 }
             }
 
@@ -294,7 +299,7 @@ impl State {
                     let choice = &strs[self.rand.borrow_mut().gen_range(0..strs.len())];
                     self.root_scope.borrow_mut().insert(
                         *name,
-                        NamedItem::Value(Value::Lit(Literal::Str(choice.clone()))),
+                        Thunk::Value(Value::Lit(Literal::Str(choice.clone()))),
                     );
                     return Ok(());
                 }
@@ -312,7 +317,7 @@ impl State {
                 let choices = self.ast.borrow_mut().add_expr(Expr::Chc(choices));
                 self.root_scope
                     .borrow_mut()
-                    .insert(*name, NamedItem::Expr(choices));
+                    .insert(*name, Thunk::Expr(choices, None));
             }
         }
         Ok(())
@@ -325,12 +330,12 @@ impl State {
             Expr::Nil => Ok(Value::Nil),
 
             Expr::Var(v) => {
-                let e = match self.lookup(env, *v)? {
-                    NamedItem::Expr(e) => e,
-                    NamedItem::Value(v) => return Ok(v.clone()),
-                    NamedItem::Builtin(b) => return Ok(Value::Builtin(b)),
+                let (e, env) = match self.lookup(env, *v)? {
+                    Thunk::Expr(e, env) => (e, env),
+                    Thunk::Value(v) => return Ok(v.clone()),
+                    Thunk::Builtin(b) => return Ok(Value::Builtin(b)),
                 };
-                self.eval(e, env)
+                self.eval(e, &env)
             }
 
             Expr::Cat(cat) => {
@@ -357,8 +362,8 @@ impl State {
             Expr::Tup(values) => Ok(Value::Tup(
                 values
                     .iter()
-                    .map(|v| self.eval(*v, env))
-                    .collect::<Result<Vec<Value>, Error>>()?,
+                    .map(|v| Thunk::Expr(*v, env.clone()))
+                    .collect::<Vec<Thunk>>()
             )),
 
             Expr::Range(from, to) => {
@@ -397,7 +402,7 @@ impl State {
                     bail!("UNIMPLEMENTED: patterns");
                 };
                 let mut new_scope = HashMap::new();
-                new_scope.insert(var, NamedItem::Expr(*val));
+                new_scope.insert(var, Thunk::Expr(*val, env.clone()));
                 let new_scope = Rc::new(Scope {
                     vars: new_scope,
                     parent: closure.scope,