Homework B (benchmarks)

This commit is contained in:
Carlos Galindo 2020-01-15 22:38:07 +01:00
parent 72cc3206c4
commit 76fbabdf53
Signed by: kauron
GPG key ID: 83E68706DEE119A3
141 changed files with 7540 additions and 2032 deletions

View file

@ -0,0 +1,32 @@
package cd.backend.interpreter;
import cd.backend.ExitCode;
import cd.util.FileUtil;
/** Thrown in cases that are not ruled out by static analysis: */
@SuppressWarnings("serial")
public class DynamicError extends RuntimeException {
private ExitCode code;
public DynamicError(String message, ExitCode code) {
super(message);
this.code = code;
}
public DynamicError(Throwable thr, ExitCode code) {
super(thr);
this.code = code;
}
public ExitCode getExitCode() {
return this.code;
}
/**
* Returns a string exactly like the one that
* {@link FileUtil#runCommand(java.io.File, String[], String[], String, boolean)}
* returns when a command results in an error. */
public String format() {
return "Error: " + code.value + "\n";
}
}

View file

@ -0,0 +1,585 @@
package cd.backend.interpreter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Scanner;
import cd.backend.ExitCode;
import cd.backend.interpreter.Interpreter.MethodInterp.EarlyReturnException;
import cd.ir.Ast;
import cd.ir.Ast.Assign;
import cd.ir.Ast.BinaryOp;
import cd.ir.Ast.BooleanConst;
import cd.ir.Ast.BuiltInRead;
import cd.ir.Ast.BuiltInWrite;
import cd.ir.Ast.BuiltInWriteln;
import cd.ir.Ast.Cast;
import cd.ir.Ast.ClassDecl;
import cd.ir.Ast.Expr;
import cd.ir.Ast.Field;
import cd.ir.Ast.IfElse;
import cd.ir.Ast.Index;
import cd.ir.Ast.IntConst;
import cd.ir.Ast.MethodCall;
import cd.ir.Ast.MethodCallExpr;
import cd.ir.Ast.MethodDecl;
import cd.ir.Ast.NewArray;
import cd.ir.Ast.NewObject;
import cd.ir.Ast.NullConst;
import cd.ir.Ast.ReturnStmt;
import cd.ir.Ast.Stmt;
import cd.ir.Ast.ThisRef;
import cd.ir.Ast.UnaryOp;
import cd.ir.Ast.Var;
import cd.ir.Ast.WhileLoop;
import cd.ir.AstVisitor;
import cd.ir.BasicBlock;
import cd.ir.ControlFlowGraph;
import cd.ir.Symbol.ArrayTypeSymbol;
import cd.ir.Symbol.ClassSymbol;
import cd.ir.Symbol.TypeSymbol;
import cd.ir.Symbol.VariableSymbol;
/**
* An interpreter for the Javali IR. It requires that the IR be fully
* semantically analyzed -- in particular, that symbols be assigned to Var and
* Field nodes.
*
* It can interpret either the AST used in CD1 or the CFG from CD2. It detects
* infinite loops and also tracks how many operations of each kind were
* performed.
*/
public class Interpreter {
private static final long MAX_STEPS = 100000000;
private long steps = 0;
private final JlNull nullPointer = new JlNull();
private final List<ClassDecl> classDecls;
private final Writer output;
private final Scanner input;
public Interpreter(List<ClassDecl> classDecls, Reader in, Writer out) {
this.classDecls = classDecls;
this.input = new Scanner(in);
this.output = out;
}
public void execute() {
ClassSymbol mainType = findMainClass();
invokeMethod(mainType, "main", new JlObject(mainType),
Collections.<JlValue> emptyList());
}
// Optimization detection:
//
// We count the number of binary and unary operations that
// occurred during execution and compare this to a fully-optimized version.
// The key to this hashtable is either a BinaryOp.BOp or UnaryOp.UOp.
private final Map<Object, Integer> opCounts = new HashMap<Object, Integer>();
private void increment(Object operator) {
Integer current = opCounts.get(operator);
if (current == null)
opCounts.put(operator, 1);
else
opCounts.put(operator, current + 1);
}
public String operationSummary() {
List<String> operationSummaries = new ArrayList<String>();
for (Object operation : opCounts.keySet()) {
operationSummaries.add(String.format("%s: %s\n", operation,
opCounts.get(operation)));
}
Collections.sort(operationSummaries);
StringBuilder sb = new StringBuilder();
for (String summary : operationSummaries) {
sb.append(summary);
}
return sb.toString();
}
public void step() {
// Stop after taking too many evaluation steps!
if (++steps > MAX_STEPS) {
throw new DynamicError("Infinite Loop!",
ExitCode.INFINITE_LOOP);
}
}
// The interpreter proper:
class ExprInterp extends AstVisitor<JlValue, StackFrame> {
private JlValue v(int value) {
return new JlInt(value);
}
private JlValue v(boolean b) {
return new JlBoolean(b);
}
@Override
public JlValue visit(Ast ast, StackFrame arg) {
step();
return super.visit(ast, arg);
}
@Override
public JlValue binaryOp(BinaryOp ast, StackFrame arg) {
try {
final JlValue left = visit(ast.left(), arg);
final JlValue right = visit(ast.right(), arg);
// TODO Only increment this operator for integers
increment(ast.operator);
switch (ast.operator) {
case B_TIMES :
return left.times(right);
case B_DIV :
return left.div(right);
case B_MOD :
return left.mod(right);
case B_PLUS :
return left.add(right);
case B_MINUS :
return left.subtract(right);
case B_AND :
return left.and(right);
case B_OR :
return left.or(right);
case B_EQUAL :
return v(left.equals(right));
case B_NOT_EQUAL :
return v(!left.equals(right));
case B_LESS_THAN :
return left.less(right);
case B_LESS_OR_EQUAL :
return left.lessOrEqual(right);
case B_GREATER_THAN :
return left.greater(right);
case B_GREATER_OR_EQUAL :
return left.greaterOrEqual(right);
}
throw new DynamicError("Unhandled binary operator",
ExitCode.INTERNAL_ERROR);
} catch (ArithmeticException e) {
throw new DynamicError("Division by zero",
ExitCode.DIVISION_BY_ZERO);
}
}
@Override
public JlValue booleanConst(BooleanConst ast, StackFrame arg) {
return v(ast.value);
}
@Override
public JlValue builtInRead(BuiltInRead ast, StackFrame arg) {
try {
return v(input.nextInt());
} catch (InputMismatchException e) {
throw new DynamicError("Your .javali.in file is malformed.",
ExitCode.INTERNAL_ERROR);
} catch (NoSuchElementException e) {
throw new DynamicError("Your .javali.in does not contain enough numbers"
+ " or may not exist at all.\nMake sure that test cases that contain "
+ "read() expressions provide a [testcasename].javali.in file.",
ExitCode.INTERNAL_ERROR);
}
}
@Override
public JlValue cast(Cast ast, StackFrame arg) {
JlReference ref = visit(ast.arg(), arg).asRef();
if (ref.canBeCastTo(ast.typeName)) {
return ref;
}
throw new DynamicError("Cast failure: cannot cast " + ref.typeSym
+ " to " + ast.typeName, ExitCode.INVALID_DOWNCAST);
}
@Override
public JlValue field(Field ast, StackFrame arg) {
JlValue lhs = visit(ast.arg(), arg);
return lhs.asRef().field(ast.sym);
}
@Override
public JlValue index(Index ast, StackFrame arg) {
JlValue lhs = visit(ast.left(), arg);
JlValue idx = visit(ast.right(), arg);
return lhs.asRef().deref(idx.asInt());
}
@Override
public JlValue intConst(IntConst ast, StackFrame arg) {
return v(ast.value);
}
@Override
public JlValue newArray(NewArray ast, StackFrame arg) {
JlValue size = visit(ast.arg(), arg);
return new JlArray((ArrayTypeSymbol) ast.type, size.asInt());
}
@Override
public JlValue newObject(NewObject ast, StackFrame arg) {
return new JlObject((ClassSymbol) ast.type);
}
@Override
public JlValue nullConst(NullConst ast, StackFrame arg) {
return nullPointer;
}
@Override
public JlValue thisRef(ThisRef ast, StackFrame arg) {
return arg.getThisPointer();
}
@Override
public JlValue methodCall(MethodCallExpr ast, StackFrame frame) {
JlObject rcvr = expr(ast.receiver(), frame).asObject();
List<JlValue> arguments = new ArrayList<JlValue>();
for (Ast arg : ast.argumentsWithoutReceiver()) {
arguments.add(expr(arg, frame));
}
return invokeMethod((ClassSymbol) rcvr.typeSym, ast.methodName,
rcvr, arguments);
}
@Override
public JlValue unaryOp(UnaryOp ast, StackFrame arg) {
JlValue val = visit(ast.arg(), arg);
// TODO Increment this only when is an int
increment(ast.operator);
switch (ast.operator) {
case U_PLUS :
return val.plus();
case U_MINUS :
return val.minus();
case U_BOOL_NOT :
return val.not();
}
throw new DynamicError("Unhandled unary operator " + ast.operator,
ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue var(Var ast, StackFrame arg) {
if (ast.sym == null) {
throw new DynamicError("Var node with null symbol",
ExitCode.INTERNAL_ERROR);
}
switch (ast.sym.kind) {
case LOCAL :
case PARAM :
return arg.var(ast.sym);
case FIELD :
return arg.getThisPointer().field(ast.sym);
}
throw new DynamicError("Unhandled VariableSymbol kind: "
+ ast.sym.kind, ExitCode.INTERNAL_ERROR);
}
}
public JlValue expr(Ast ast, StackFrame frame) {
return new ExprInterp().visit(ast, frame);
}
private ClassSymbol findMainClass() {
for (ClassDecl classDecl : classDecls) {
if (classDecl.name.equals("Main"))
return classDecl.sym;
}
throw new StaticError("No Main class found");
}
public ClassDecl findClassDecl(TypeSymbol typeSym) {
for (ClassDecl cd : classDecls) {
if (cd.sym == typeSym)
return cd;
}
throw new StaticError("No such type " + typeSym.name);
}
class MethodInterp extends cd.ir.AstVisitor<JlValue, StackFrame> {
public boolean earlyReturn = false;
@SuppressWarnings("serial")
class EarlyReturnException extends RuntimeException {
public JlValue value;
public EarlyReturnException(final JlValue value) {
this.value = value;
}
}
@Override
public JlValue assign(Assign ast, final StackFrame frame) {
new AstVisitor<Void, Expr>() {
@Override
public Void field(Field ast, Expr right) {
JlValue obj = expr(ast.arg(), frame);
assert obj != null && obj.asRef() != null;
final JlValue val = expr(right, frame);
assert val != null;
obj.asRef().setField(ast.sym, val);
return null;
}
@Override
public Void index(Index ast, Expr right) {
JlValue obj = expr(ast.left(), frame);
JlValue idx = expr(ast.right(), frame);
final JlValue val = expr(right, frame);
assert val != null;
obj.asRef().setDeref(idx.asInt(), val);
return null;
}
@Override
public Void var(Var ast, Expr right) {
final JlValue val = expr(right, frame);
assert val != null;
frame.setVar(ast.sym, val);
return null;
}
@Override
protected Void dflt(Ast ast, Expr arg) {
throw new StaticError("Malformed l-value in AST");
}
}.visit(ast.left(), ast.right());
return null;
}
@Override
public JlValue builtInWrite(BuiltInWrite ast, StackFrame frame) {
JlValue val = expr(ast.arg(), frame);
try {
output.write(Integer.toString(val.asInt()));
} catch (IOException e) {
throw new DynamicError(e, ExitCode.INTERNAL_ERROR);
}
return null;
}
@Override
public JlValue builtInWriteln(BuiltInWriteln ast, StackFrame arg) {
try {
output.write("\n");
} catch (IOException e) {
throw new DynamicError(e, ExitCode.INTERNAL_ERROR);
}
return null;
}
@Override
public JlValue ifElse(IfElse ast, StackFrame frame) {
JlValue cond = expr(ast.condition(), frame);
if (cond.asBoolean()) {
return visit(ast.then(), frame);
} else {
return visit(ast.otherwise(), frame);
}
}
@Override
public JlValue methodCall(MethodCall ast, final StackFrame frame) {
return expr(ast.getMethodCallExpr(), frame);
}
@Override
public JlValue whileLoop(WhileLoop ast, StackFrame frame) {
while (true) {
JlValue cond = expr(ast.condition(), frame);
if (!cond.asBoolean()) {
return null;
}
visit(ast.body(), frame);
}
}
@Override
public JlValue returnStmt(ReturnStmt ast, StackFrame frame) {
JlValue ret = null;
if (ast.arg() != null) {
ret = expr(ast.arg(), frame);
} else {
ret = new JlNull();
}
if (!earlyReturn) {
return ret;
} else {
throw new EarlyReturnException(ret);
}
}
}
public MethodDecl findMethodDecl(ClassSymbol typeSym,
final String methodName) {
ClassSymbol currSym = typeSym;
while (currSym != ClassSymbol.objectType) {
ClassDecl cd = findClassDecl(currSym);
final List<MethodDecl> result = new ArrayList<MethodDecl>();
for (Ast mem : cd.members()) {
AstVisitor<Void, Void> vis = new AstVisitor<Void, Void>() {
@Override
public Void methodDecl(MethodDecl ast, Void arg) {
if (!ast.name.equals(methodName)) {
return null;
}
result.add(ast);
return null;
}
};
vis.visit(mem, null);
}
if (result.size() == 1) {
return result.get(0);
}
if (result.size() > 1) {
throw new StaticError(result.size()
+ " implementations of method " + methodName
+ " found in type " + currSym.name);
}
currSym = currSym.superClass;
}
throw new StaticError("No method " + methodName + " in type " + typeSym);
}
// Note: does not interpret phis!
public JlValue interpretCfg(ControlFlowGraph cfg, final StackFrame frame) {
BasicBlock current = cfg.start;
MethodInterp minterp = new MethodInterp();
JlValue res = null;
while (true) {
step();
for(Stmt stmt : current.stmts) {
res = minterp.visit(stmt, frame);
if(stmt instanceof ReturnStmt)
return res;
}
if (current == cfg.end) {
return res;
} else if (current.condition == null) {
current = current.successors.get(0);
} else {
JlValue cond = expr(current.condition, frame);
if (cond.asBoolean()) {
current = current.trueSuccessor();
} else {
current = current.falseSuccessor();
}
}
}
}
public JlValue invokeMethod(final ClassSymbol typeSym,
final String methodName, final JlObject rcvr,
final List<JlValue> arguments) {
MethodDecl mdecl = findMethodDecl(typeSym, methodName);
StackFrame newFrame = new StackFrame(rcvr);
int idx = 0;
for (VariableSymbol sym : mdecl.sym.parameters) {
newFrame.setVar(sym, arguments.get(idx++));
}
if (mdecl.cfg != null) {
return interpretCfg(mdecl.cfg, newFrame);
} else {
final MethodInterp mthInterp = new MethodInterp();
mthInterp.earlyReturn = true;
try {
return mthInterp.visit(mdecl.body(), newFrame);
} catch (final EarlyReturnException ex) {
return ex.value;
}
}
}
}

View file

@ -0,0 +1,544 @@
package cd.backend.interpreter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import cd.backend.ExitCode;
import cd.ir.Symbol.ArrayTypeSymbol;
import cd.ir.Symbol.ClassSymbol;
import cd.ir.Symbol.PrimitiveTypeSymbol;
import cd.ir.Symbol.TypeSymbol;
import cd.ir.Symbol.VariableSymbol;
// Values:
abstract class JlValue {
public final TypeSymbol typeSym;
static public JlValue getDefault(TypeSymbol type) {
JlValue result = null;
if (type.isReferenceType())
result = new JlNull();
else if (type == PrimitiveTypeSymbol.booleanType)
result = new JlBoolean(false);
else if (type == PrimitiveTypeSymbol.intType)
result = new JlInt(0);
assert result != null;
return result;
}
public JlValue(TypeSymbol s) {
typeSym = s;
}
protected void defaultConversion() {
throw new StaticError("Type conversion between incompatible types.");
}
public boolean asBoolean() {
defaultConversion();
return false;
}
public int asInt() {
defaultConversion();
return 0;
}
public JlReference asRef() {
defaultConversion();
return null;
}
public JlObject asObject() {
defaultConversion();
return null;
}
// Binary Operations
// Arithmetic
protected JlValue defaultOperation() {
throw new StaticError("Operation not supported on " + this.getClass());
}
public JlValue times(JlValue value) {
return defaultOperation();
}
public JlValue div(JlValue value) {
return defaultOperation();
}
public JlValue add(JlValue value) {
return defaultOperation();
}
public JlValue subtract(JlValue value) {
return defaultOperation();
}
public JlValue mod(JlValue value) {
return defaultOperation();
}
// Boolean
public JlValue or(JlValue value) {
return defaultOperation();
}
public JlValue and(JlValue value) {
return defaultOperation();
}
// Comparison
public JlValue less(JlValue value) {
return defaultOperation();
}
public JlValue lessOrEqual(JlValue value) {
return defaultOperation();
}
public JlValue greater(JlValue value) {
return defaultOperation();
}
public JlValue greaterOrEqual(JlValue value) {
return defaultOperation();
}
// Unary Operation
public JlValue plus() {
return defaultOperation();
}
public JlValue minus() {
return defaultOperation();
}
public JlValue not() {
return defaultOperation();
}
}
abstract class JlReference extends JlValue {
public JlReference(TypeSymbol s) {
super(s);
}
@Override
public JlReference asRef() {
return this;
}
public abstract JlValue field(VariableSymbol name);
public abstract void setField(VariableSymbol name, JlValue val);
public abstract JlValue deref(int index);
public abstract void setDeref(int index, JlValue val);
public abstract boolean canBeCastTo(String typeName);
@Override
public String toString() {
return String.format("%s(%x)", typeSym, System.identityHashCode(this));
}
}
class JlObject extends JlReference {
protected Map<VariableSymbol, JlValue> fields = new HashMap<VariableSymbol, JlValue>();
public JlObject(ClassSymbol s) {
super(s);
}
@Override
public JlObject asObject() {
return this;
}
@Override
public JlValue field(VariableSymbol name) {
if (fields.containsKey(name)) {
return fields.get(name);
}
JlValue dflt = JlValue.getDefault(name.type);
setField(name, dflt);
return dflt;
}
@Override
public void setField(VariableSymbol name, JlValue val) {
fields.put(name, val);
}
@Override
public JlValue deref(int index) {
throw new StaticError("Not an array");
}
@Override
public void setDeref(int index, JlValue val) {
throw new StaticError("Not an array");
}
@Override
public boolean canBeCastTo(String typeName) {
// Can always cast to Object:
if (typeName.equals("Object"))
return true;
// Make up a set of acceptable types. Check for circular loops!
Set<String> superTypes = new HashSet<String>();
ClassSymbol currentType = (ClassSymbol)typeSym;
while (!currentType.name.equals("Object")) {
if (superTypes.contains(currentType.name)) {
throw new StaticError("Circular inheritance: " + currentType.name);
}
superTypes.add(currentType.name);
currentType = currentType.superClass;
}
return superTypes.contains(typeName);
}
}
class JlArray extends JlReference {
private JlValue contents[];
public JlArray(ArrayTypeSymbol s, int size) {
super(s);
if (size < 0) {
throw new DynamicError("Invalid array size: " + size,
ExitCode.INVALID_ARRAY_SIZE);
}
this.contents = new JlValue[size];
for (int i = 0; i < size; i++) {
this.contents[i] = JlValue.getDefault(s.elementType);
}
}
@Override
public JlReference asRef() {
return this;
}
public JlArray asArray() {
return this;
}
@Override
public JlValue deref(int idx) {
try {
return contents[idx];
} catch (final ArrayIndexOutOfBoundsException ex) {
throw new DynamicError("Array index out of bounds " + idx,
ExitCode.INVALID_ARRAY_BOUNDS);
}
}
@Override
public void setDeref(int idx, JlValue value) {
try {
contents[idx] = value;
} catch (final ArrayIndexOutOfBoundsException ex) {
throw new DynamicError("Array index out of bounds " + idx,
ExitCode.INVALID_ARRAY_BOUNDS);
}
}
@Override
public JlValue field(VariableSymbol name) {
throw new StaticError("Not an object");
}
@Override
public void setField(VariableSymbol name, JlValue value) {
throw new StaticError("Not an object");
}
@Override
public boolean canBeCastTo(String typeName) {
return this.typeSym.name.equals(typeName) || typeName.equals("Object");
}
}
class JlNull extends JlReference {
public JlNull() {
super(ClassSymbol.nullType);
}
@Override
public boolean equals(Object o) {
if (o instanceof JlNull) {
return true;
}
return false;
}
@Override
public JlReference asRef() {
return this;
}
@Override
public JlObject asObject() {
throw new DynamicError("Null pointer dereferenced",
ExitCode.NULL_POINTER);
}
@Override
public JlValue field(VariableSymbol name) {
throw new DynamicError("Null pointer dereferenced",
ExitCode.NULL_POINTER);
}
@Override
public void setField(VariableSymbol name, JlValue value) {
throw new DynamicError("Null pointer dereferenced",
ExitCode.NULL_POINTER);
}
@Override
public JlValue deref(int idx) {
throw new DynamicError("Null pointer dereferenced",
ExitCode.NULL_POINTER);
}
@Override
public void setDeref(int idx, JlValue value) {
throw new DynamicError("Null pointer dereferenced",
ExitCode.NULL_POINTER);
}
@Override
public boolean canBeCastTo(String typeName) {
return true;
}
@Override
public String toString() {
return "null";
}
}
class JlInt extends JlValue {
private final int value;
JlInt(int value) {
super(PrimitiveTypeSymbol.intType);
this.value = value;
}
@Override
public boolean equals(Object o) {
if (o instanceof JlInt) {
return value == ((JlInt) o).value;
}
return false;
}
@Override
public JlValue times(JlValue obj) {
if (obj instanceof JlInt) {
return new JlInt(this.value * ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue div(JlValue obj) {
if (obj instanceof JlInt) {
return new JlInt(this.value / ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue mod(JlValue obj) {
if (obj instanceof JlInt) {
return new JlInt(this.value % ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue add(JlValue obj) {
if (obj instanceof JlInt) {
return new JlInt(this.value + ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue subtract(JlValue obj) {
if (obj instanceof JlInt) {
return new JlInt(this.value - ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue less(JlValue obj) {
if (obj instanceof JlInt) {
return new JlBoolean(this.value < ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue lessOrEqual(JlValue obj) {
if (obj instanceof JlInt) {
return new JlBoolean(this.value <= ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue greater(JlValue obj) {
if (obj instanceof JlInt) {
return new JlBoolean(this.value > ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue greaterOrEqual(JlValue obj) {
if (obj instanceof JlInt) {
return new JlBoolean(this.value >= ((JlInt) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue plus() {
return new JlInt(value);
}
@Override
public JlValue minus() {
return new JlInt(-value);
}
@Override
public int asInt() {
return value;
}
@Override
public String toString() {
return Integer.toString(value);
}
}
class JlBoolean extends JlValue {
private final boolean value;
JlBoolean(boolean value) {
super(PrimitiveTypeSymbol.booleanType);
this.value = value;
}
@Override
public boolean equals(Object o) {
if (o instanceof JlBoolean) {
return value == ((JlBoolean) o).value;
}
return false;
}
@Override
public JlValue not() {
return new JlBoolean(!value);
};
@Override
public JlValue or(JlValue obj) {
if (obj instanceof JlBoolean) {
return new JlBoolean(this.value || ((JlBoolean) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public JlValue and(JlValue obj) {
if (obj instanceof JlBoolean) {
return new JlBoolean(this.value && ((JlBoolean) obj).value);
}
throw new DynamicError("Invalid type!", ExitCode.INTERNAL_ERROR);
}
@Override
public boolean asBoolean() {
return value;
}
@Override
public String toString() {
return Boolean.toString(value);
}
}

View file

@ -0,0 +1,41 @@
package cd.backend.interpreter;
import java.util.HashMap;
import java.util.Map;
import cd.ir.Symbol.VariableSymbol;
// The stack:
class StackFrame {
private final JlObject thisPointer;
private final Map<VariableSymbol, JlValue> variables;
public StackFrame(JlObject thisPointer) {
this.thisPointer = thisPointer;
this.variables = new HashMap<VariableSymbol, JlValue>();
}
public JlValue var(VariableSymbol name) {
if (variables.containsKey(name)) {
return variables.get(name);
}
JlValue dflt = JlValue.getDefault(name.type);
setVar(name, dflt);
return dflt;
}
public void setVar(VariableSymbol name, JlValue val) {
variables.put(name, val);
}
public String toString() {
return String.format("StackFrame(%s) {%s}", System.identityHashCode(this), variables.toString());
}
public JlObject getThisPointer() {
return thisPointer;
}
}

View file

@ -0,0 +1,10 @@
package cd.backend.interpreter;
/** Thrown in cases that should be ruled out by static analysis: */
@SuppressWarnings("serial")
public
class StaticError extends RuntimeException {
public StaticError(String message) {
super(message);
}
}