package interpreter;

///////////////////////////////////////////////////////////////////////////////
//
//                       Evaluation environments
//
///////////////////////////////////////////////////////////////////////////////

import jazz.util.*;

public class Env<T> {
  // The universal empty environment
  public static empty: Env<T> {T} = new Env(alist = List.nil);

  // Lookup and extension of environments
  public lookup(name: String): CstExpr<T>;
  public extend(name: String, value: T): Env<T>;
  
  // Association list for the environment
  alist: List<(String, CstExpr<T>)>;
}

///////////////////////////////////////////////////////////////////////////////
//
//                           Implementation
//
///////////////////////////////////////////////////////////////////////////////

// Display
toString@Env() = alist.fold(" ", f1, f2)
{
  fun f1(t) = format("%a=%a", k, v) { (k, v) = t; }
  fun f2(t, u) = format("%s, %s", u, f1(t));
}

// Environment extension
extend@Env(name, value) = new Env(alist = alist.cons((name,
                                                      Expr.constant(value))));

// Environment lookup
lookup@Env<T>(name) = lookup(alist) 
{
  fun lookup(list: List<(String, CstExpr<T>)>): CstExpr<T>;
  lookup(list@Nil) = error("undefined variable: %s\n", name);
  lookup(list@Cons) = (name.equals(k) ? v : v')
  {
    (k, v) = list.head;
    v' = lookup(list.tail);
  }
}