package akin.lang;
import java.util.HashMap;
import java.util.ArrayList;
import java.io.Reader;
import java.io.StringReader;
import java.io.IOException;
import org.antlr.runtime.ANTLRReaderStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import akin.lang.nodes.Node;
/**
Evaluation context. Determines how a node will be evaluated.
A context tracks local variables, self, and the current class under which
methods and constants will be added.
There are three different types of context:
1) In the root of the script, self = main object, class = Object
2) Inside a method body, self = instance of the class, class = method class
3) Inside a class definition self = the class, class = the class
*/
public class Context {
private AkinObject currentSelf;
private AkinClass currentClass;
private HashMap<String, AkinObject> locals;
// A context can share local variables with a parent. For example, in the
// try block.
private Context parent;
public Context(AkinObject currentSelf, AkinClass currentClass, Context parent) {
this.currentSelf = currentSelf;
this.currentClass = currentClass;
this.parent = parent;
if (parent == null) {
locals = new HashMap<String, AkinObject>();
} else {
locals = parent.locals;
}
}
public Context(AkinObject currentSelf, AkinClass currentClass) {
this(currentSelf, currentClass, null);
}
public Context(AkinObject currentSelf) {
this(currentSelf, currentSelf.getAkinClass());
}
public Context() {
this(AkinRuntime.getMainObject());
}
public AkinObject getCurrentSelf() {
return currentSelf;
}
public AkinClass getCurrentClass() {
return currentClass;
}
public AkinObject getLocal(String name) {
return locals.get(name);
}
public boolean hasLocal(String name) {
return locals.containsKey(name);
}
public void setLocal(String name, AkinObject value) {
locals.put(name, value);
}
/**
Creates a context that will share the same attributes (locals, self, class)
as the current one.
*/
public Context makeChildContext() {
return new Context(currentSelf, currentClass, this);
}
/**
Parse and evaluate the content red from the reader (eg.: FileReader, StringReader).
*/
public AkinObject eval(Reader reader) throws AkinException {
try {
AkinLexer lexer = new AkinLexer(new ANTLRReaderStream(reader));
AkinParser parser = new AkinParser(new CommonTokenStream(lexer));
Node node = parser.parse();
if (node == null) return AkinRuntime.getNil();
return node.eval(this);
} catch (AkinException e) {
throw e;
} catch (Exception e) {
throw new AkinException(e);
}
}
public AkinObject eval(String code) throws AkinException {
return eval(new StringReader(code));
}
}