// Path: src/stone/StoneException.java
// public class StoneException extends RuntimeException {
//     public StoneException(String m) { super(m); }
//     public StoneException(String m, ASTree t) {
//         super(m + " " + t.location());
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }
// 
// Path: src/stone/ast/Dot.java
// public class Dot extends Postfix {
//     public Dot(List<ASTree> c) { super(c); }
//     public String name() { return ((ASTLeaf)child(0)).token().getText(); }
//     public String toString() { return "." + name(); } 
// }
// 
// Path: src/chap6/Environment.java
// public interface Environment {
//     void put(String name, Object value);
//     Object get(String name);
// }


import java.util.List;
import stone.StoneException;
import stone.ast.ASTree;
import stone.ast.Dot;
import chap6.Environment;
import javassist.gluonj.*;
        protected int index;
        public DotEx2(List<ASTree> c) { super(c); }
        @Override public Object eval(Environment env, Object value) {
            if (value instanceof OptStoneObject) {
                OptStoneObject target = (OptStoneObject)value;
                if (target.classInfo() != classInfo)
                    updateCache(target);
                if (isField)
                    return target.read(index);
                else
                    return target.method(index);
            }
            else
                return super.eval(env, value);
        }
        protected void updateCache(OptStoneObject target) {
            String member = name();
            classInfo = target.classInfo();
            Integer i = classInfo.fieldIndex(member);
            if (i != null) {
                isField = true;
                index = i;
                return;
            }
            i = classInfo.methodIndex(member);
            if (i != null) {
                isField = false;
                index = i;
                return;
            }
// Path: src/stone/StoneException.java
// public class StoneException extends RuntimeException {
//     public StoneException(String m) { super(m); }
//     public StoneException(String m, ASTree t) {
//         super(m + " " + t.location());
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }
// 
// Path: src/stone/ast/Dot.java
// public class Dot extends Postfix {
//     public Dot(List<ASTree> c) { super(c); }
//     public String name() { return ((ASTLeaf)child(0)).token().getText(); }
//     public String toString() { return "." + name(); } 
// }
// 
// Path: src/chap6/Environment.java
// public interface Environment {
//     void put(String name, Object value);
//     Object get(String name);
// }


// Path: src/chap12/InlineCache.java
import java.util.List;
import stone.StoneException;
import stone.ast.ASTree;
import stone.ast.Dot;
import chap6.Environment;
import javassist.gluonj.*;

        protected int index;
        public DotEx2(List<ASTree> c) { super(c); }
        @Override public Object eval(Environment env, Object value) {
            if (value instanceof OptStoneObject) {
                OptStoneObject target = (OptStoneObject)value;
                if (target.classInfo() != classInfo)
                    updateCache(target);
                if (isField)
                    return target.read(index);
                else
                    return target.method(index);
            }
            else
                return super.eval(env, value);
        }
        protected void updateCache(OptStoneObject target) {
            String member = name();
            classInfo = target.classInfo();
            Integer i = classInfo.fieldIndex(member);
            if (i != null) {
                isField = true;
                index = i;
                return;
            }
            i = classInfo.methodIndex(member);
            if (i != null) {
                isField = false;
                index = i;
                return;
            }
            throw new StoneException("bad member access: " + member, this);