package edu.neu.ccs.demeterf.examples;
/** Functional Transformation Test Class.  This includes structural duplication,
 *  <code>Num2Str</code>, and a more complicated type unifying traversal,
 *  <code>Eval</code>, demonstrating transformations and Builders with
 *  Traversal Arguments.
 */

// Import the Transformation Package
import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.IDf;
import edu.neu.ccs.demeterf.ID;
import edu.neu.ccs.demeterf.IDb;
import edu.neu.ccs.demeterf.Augmentor;
import edu.neu.ccs.demeterf.control.EdgeControl;
import edu.neu.ccs.demeterf.control.Fields;

// Simple Arithmetic Expressions
class Exp{}

// The usual operators for Binary Expressions... 
abstract class Op extends Exp{
    abstract String op();
    Exp left, right;
    Op(Exp l, Exp r){ left = l; right = r; }
    public String toString(){ return "("+op()+" "+left+" "+right+")"; }
}
class Plus extends Op{
    String op(){ return "+"; }
    Plus(Exp l, Exp r){ super(l,r); }
}
class Minus extends Op{
    String op(){ return "-"; }
    Minus(Exp l, Exp r){ super(l,r); }
}
class Times extends Op{
    String op(){ return "*"; }
    Times(Exp l, Exp r){ super(l,r); }
}
class Div extends Op{
    String op(){ return "/"; }
    Div(Exp l, Exp r){ super(l,r); }
}

// The Leafs... Numbers or Strings
class Num extends Exp{
    int num;
    Num(int i){ num = i; } 
    public String toString(){ return ""+num; }
}

// Adds one to each leaf, and reconstruct the Tree
class AddOne extends IDf{
    int apply(int i){ return i+1; }    
}

// Evaluates the Tree, 'Unifies' to an int
class Eval extends IDb{
    int combine(Num n, int i){ return i; }
    int combine(Plus p, int l, int r){ return l+r; }
    int combine(Minus p, int l, int r){ return l-r; }
    int combine(Times p, int l, int r){ return l*r; }
    int combine(Div p, int l, int r){ return l/r; }
}

// Calculated the Max depth of the Tree, using an Argument
//   this close to an implementation of my earlier Functional Visitors
class Depth extends ID{
    int update(Op o, Fields.any f, int i){ return i+1; }
    int apply(Exp o, int a){ return a; }
    int combine(Exp n, int i, int a){ return a; }
    int combine(Exp o, int l, int r, int a){ return Math.max(l,r); }
}

// A form of String Expressions with Tree Depth
class Str extends Exp{
    String str;
    int depth;
    Str(String s, int d){ str = s; depth = d; } 
    public String toString(){ return "\""+str+"\":"+depth; }
}

//Converts a Number Expression into a String + Depth
class Num2Str extends IDf{
    Str apply(Num n, int d){ return new Str(""+n,d); }    
}

// Main Test Class
public class EvalTest{
    private EvalTest(){}
    static void print(String s){ System.out.println(s); }
    static public void main(String[] args){
        //util.Util.setDebug(true);
        Exp p = new Div(new Plus(new Plus(new Times(new Num(9), new Num(6)),
                                        new Num(8)),
                               new Minus(new Num(5), new Num(7))),
                      new Num(4));
        
        print("  Before: "+p);
        print("  AddOne: "+new Traversal(new AddOne()).traverse(p));
        print("    Eval: "+new Traversal(new Eval()).traverse(p));
        
        Depth d = new Depth();
        print(" Num2Str: "+new Traversal(new Num2Str(), (Augmentor)d,
                                         EdgeControl.builtIns(Num.class)).traverse(p, 0));
        print("   Depth: "+new Traversal(d).traverse(p, 0));
    }
}