package de.skuzzle.polly.core.parser;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import de.skuzzle.polly.core.parser.ast.Root;
import de.skuzzle.polly.core.parser.ast.declarations.Namespace;
import de.skuzzle.polly.core.parser.ast.visitor.ASTTraversalException;
import de.skuzzle.polly.core.parser.ast.visitor.ASTVisitor;
import de.skuzzle.polly.core.parser.ast.visitor.DebugExecutionVisitor;
import de.skuzzle.polly.core.parser.ast.visitor.ExecutionVisitor;
import de.skuzzle.polly.core.parser.ast.visitor.ParentSetter;
import de.skuzzle.polly.core.parser.ast.visitor.Unparser;
import de.skuzzle.polly.core.parser.ast.visitor.resolving.TypeResolver;
import de.skuzzle.polly.core.parser.problems.ProblemReporter;
/**
* This is the main class for accessing the most often used parser feature: evaluating
* an input String. It parses the String, resolves all types and executes the input in
* the context of a provided {@link Namespace}. Evaluation may be either successful or
* fail. In the latter case, you can retrieve the Exception that caused the fail using
* {@link #getLastError()}. If no exception occurred, you may retrieve the result using
* {@link #getRoot()}.
*
* @author Simon Taddiken
*/
public class Evaluator {
private final static ExecutionVisitor getExecutor(Namespace rootNs,
Namespace workingNs, ProblemReporter reporter) {
if (ParserProperties.should(ParserProperties.ENABLE_EXECUTION_DEBUGGING)) {
return new DebugExecutionVisitor(rootNs, workingNs, reporter);
} else {
return new ExecutionVisitor(rootNs, workingNs, reporter);
}
}
private final String input;
private final String encoding;
private final ProblemReporter reporter;
private Root lastResult;
private ASTTraversalException lastError;
public Evaluator(String input, String encoding, ProblemReporter reporter)
throws UnsupportedEncodingException {
if (!Charset.isSupported(encoding)) {
throw new UnsupportedEncodingException(encoding);
}
this.reporter = reporter;
this.input = input;
this.encoding = encoding;
}
/**
* Gets the input String which is parsed by this evaluator.
*
* @return The input string.
*/
public String getInput() {
return this.input;
}
/**
* Tries to evaluate the input that this instance was created with. Success of
* evaluation can be queried using {@link #errorOccurred()}. If an error occurred,
* the exception can be obtained using {@link #getLastError()}. If evaluation was
* successful, the result can be obtained using {@link #getRoot()}.
*
* @param rootNs The namespace to which ne declarations will be stored.
* @param workingNs The initial namespace to work with.
*/
public void evaluate(Namespace rootNs, Namespace workingNs) {
try {
final InputParser parser = new InputParser(this.input, this.encoding,
this.reporter);
this.lastResult = parser.parse();
if (this.lastResult == null) {
return;
}
// set parent attributes for all nodes
final ASTVisitor parentSetter = new ParentSetter();
this.lastResult.visit(parentSetter);
final ProblemReporter reporter = this.reporter.subReporter(
this.lastResult.getPosition());
// resolve types
TypeResolver.resolveAST(this.lastResult, workingNs, reporter);
if (!this.reporter.hasProblems()) {
final ASTVisitor executor = getExecutor(rootNs, workingNs, reporter);
this.lastResult.visit(executor);
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("This should not have happened", e); //$NON-NLS-1$
} catch (ASTTraversalException e) {
e.printStackTrace();
this.lastError = e;
}
}
public boolean errorOccurred() {
return this.reporter.hasProblems();
}
public ASTTraversalException getLastError() {
return this.lastError;
}
public Root getRoot() {
/*if (this.errorOccurred()) {
throw new IllegalStateException("no valid result available");
}*/
return this.lastResult;
}
public String unparse() {
return Unparser.toString(this.getRoot());
}
}