// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.
package wyil.util.interpreter;
import wyil.lang.Bytecode;
import wyil.lang.Bytecode.Expr;
import wyil.lang.Bytecode.Operator;
import wyil.lang.Constant;
import wyil.lang.SyntaxTree;
import wyil.lang.SyntaxTree.Location;
import wyil.lang.Type;
import wyil.util.interpreter.Interpreter.ConstantObject;
import wyil.util.interpreter.Interpreter.InternalFunction;
import static wyil.util.interpreter.Interpreter.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import wybs.util.ResolveError;
public class StandardFunctions {
/**
* The standard functions for use with the interpreter.
*/
public static final InternalFunction[] standardFunctions = new InternalFunction[255];
static {
standardFunctions[Bytecode.OPCODE_neg] = new Negate();
standardFunctions[Bytecode.OPCODE_add ] = new Add();
standardFunctions[Bytecode.OPCODE_sub ] = new Subtract();
standardFunctions[Bytecode.OPCODE_mul ] = new Multiply();
standardFunctions[Bytecode.OPCODE_div ] = new Divide();
standardFunctions[Bytecode.OPCODE_rem ] = new Remainder();
standardFunctions[Bytecode.OPCODE_eq ] = new Equal();
standardFunctions[Bytecode.OPCODE_ne ] = new NotEqual();
standardFunctions[Bytecode.OPCODE_lt ] = new LessThan();
standardFunctions[Bytecode.OPCODE_le ] = new LessThanEqual();
standardFunctions[Bytecode.OPCODE_gt ] = new GreaterThan();
standardFunctions[Bytecode.OPCODE_ge ] = new GreaterThanEqual();
standardFunctions[Bytecode.OPCODE_logicalnot] = new LogicalNot();
standardFunctions[Bytecode.OPCODE_bitwiseinvert] = new BitwiseInvert();
standardFunctions[Bytecode.OPCODE_bitwiseor] = new BitwiseOr();
standardFunctions[Bytecode.OPCODE_bitwisexor] = new BitwiseXor();
standardFunctions[Bytecode.OPCODE_bitwiseand] = new BitwiseAnd();
standardFunctions[Bytecode.OPCODE_shl] = new LeftShift();
standardFunctions[Bytecode.OPCODE_shr] = new RightShift();
standardFunctions[Bytecode.OPCODE_arrayindex] = new ArrayIndex();
standardFunctions[Bytecode.OPCODE_arraygen] = new ArrayGenerator();
standardFunctions[Bytecode.OPCODE_arraylength] = new ArrayLength();
standardFunctions[Bytecode.OPCODE_array] = new ArrayConstructor();
standardFunctions[Bytecode.OPCODE_record] = new RecordConstructor();
standardFunctions[Bytecode.OPCODE_newobject] = new ObjectConstructor();
standardFunctions[Bytecode.OPCODE_dereference] = new Dereference();
standardFunctions[Bytecode.OPCODE_is] = new Is();
};
// ====================================================================================
// References
// ====================================================================================
private static final class Dereference implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
ConstantObject ref = checkType(operands[0], context, ConstantObject.class);
return ref.read();
}
}
private static final class ObjectConstructor implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return new ConstantObject(operands[0]);
}
}
// ====================================================================================
// Logical
// ====================================================================================
private static final class LogicalNot implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Bool i = checkType(operands[0], context, Constant.Bool.class);
return Constant.Bool(!i.value());
}
}
// ====================================================================================
// Arithmetic
// ====================================================================================
private static final class Negate implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer i = checkType(operands[0], context, Constant.Integer.class);
return new Constant.Integer(i.value().negate());
}
}
private static final class Add implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer lhs = checkType(operands[0], context, Constant.Integer.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
return new Constant.Integer(lhs.value().add(rhs.value()));
}
}
private static final class Subtract implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer lhs = checkType(operands[0], context, Constant.Integer.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
return new Constant.Integer(lhs.value().subtract(rhs.value()));
}
}
private static final class Multiply implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer lhs = checkType(operands[0], context, Constant.Integer.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
return new Constant.Integer(lhs.value().multiply(rhs.value()));
}
}
private static final class Divide implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer lhs = checkType(operands[0], context, Constant.Integer.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
return new Constant.Integer(lhs.value().divide(rhs.value()));
}
}
private static final class Remainder implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Integer lhs = checkType(operands[0], context, Constant.Integer.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
return new Constant.Integer(lhs.value().remainder(rhs.value()));
}
}
private static final class Equal implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return Constant.Bool(operands[0].equals(operands[1]));
}
}
private static final class NotEqual implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return Constant.Bool(!operands[0].equals(operands[1]));
}
}
private static final class LessThan implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return lessThan(operands[0],operands[1],true,context);
}
}
private static final class LessThanEqual implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return lessThan(operands[0],operands[1],false,context);
}
}
private static final class GreaterThan implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return lessThan(operands[1],operands[0],true,context);
}
}
private static final class GreaterThanEqual implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
return lessThan(operands[1],operands[0],false,context);
}
}
// ====================================================================================
// Bytes
// ====================================================================================
private static final class BitwiseInvert implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte b = checkType(operands[0], context, Constant.Byte.class);
return new Constant.Byte((byte) ~b.value());
}
}
private static final class BitwiseOr implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte lhs = checkType(operands[0], context, Constant.Byte.class);
Constant.Byte rhs = checkType(operands[1], context, Constant.Byte.class);
int result = lhs.value() | rhs.value();
return new Constant.Byte((byte) result);
}
}
private static final class BitwiseXor implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte lhs = checkType(operands[0], context, Constant.Byte.class);
Constant.Byte rhs = checkType(operands[1], context, Constant.Byte.class);
int result = lhs.value() ^ rhs.value();
return new Constant.Byte((byte) result);
}
}
private static final class BitwiseAnd implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte lhs = checkType(operands[0], context, Constant.Byte.class);
Constant.Byte rhs = checkType(operands[1], context, Constant.Byte.class);
int result = lhs.value() & rhs.value();
return new Constant.Byte((byte) result);
}
}
private static final class LeftShift implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte lhs = checkType(operands[0], context, Constant.Byte.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
int result = lhs.value() << rhs.value().intValue();
return new Constant.Byte((byte) result);
}
}
private static final class RightShift implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Byte lhs = checkType(operands[0], context, Constant.Byte.class);
Constant.Integer rhs = checkType(operands[1], context, Constant.Integer.class);
int result = lhs.value() >> rhs.value().intValue();
return new Constant.Byte((byte) result);
}
}
// ====================================================================================
// Arrays
// ====================================================================================
private static final class ArrayLength implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Array array = checkType(operands[0], context, Constant.Array.class);
BigInteger length = BigInteger.valueOf(array.values().size());
return new Constant.Integer(length);
}
}
private static final class ArrayIndex implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant.Array src = checkType(operands[0], context, Constant.Array.class);
Constant.Integer index = checkType(operands[1], context, Constant.Integer.class);
int i = index.value().intValue();
if (i < 0 || i >= src.values().size()) {
error("index-out-of-bounds", context);
}
// Ok, get the element at that index
return src.values().get(index.value().intValue());
}
}
private static final class ArrayGenerator implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
Constant element = operands[0];
Constant.Integer count = checkType(operands[1], context, Constant.Integer.class);
// Check that we have a integer count
int n = count.value().intValue();
ArrayList<Constant> values = new ArrayList<>();
for (int i = 0; i != n; ++i) {
values.add(element);
}
return new Constant.Array(values);
}
}
private static final class ArrayConstructor implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) {
ArrayList<Constant> values = new ArrayList<>();
for (Constant c : operands) {
values.add(c);
}
return new Constant.Array(values);
}
}
// ====================================================================================
// Records
// ====================================================================================
private static final class RecordConstructor implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) throws ResolveError {
Type.EffectiveRecord type = enclosing.getTypeSystem().expandAsEffectiveRecord(context.getType());
HashMap<String, Constant> values = new HashMap<>();
String[] fields = type.getFieldNames();
for (int i = 0; i != operands.length; ++i) {
values.put(fields[i], operands[i]);
}
return new Constant.Record(values);
}
}
// ====================================================================================
// Other
// ====================================================================================
private static final class Is implements InternalFunction {
@Override
public Constant apply(Constant[] operands, Interpreter enclosing, Location<Operator> context) throws ResolveError {
Constant.Type ct = checkType(operands[1], context, Constant.Type.class);
boolean r = enclosing.isMemberOfType(operands[0], ct.value(), context);
return Constant.Bool(r);
}
}
// ====================================================================================
// Helpers
// ====================================================================================
private static Constant.Bool lessThan(Constant lhs, Constant rhs, boolean isStrict, Location<Operator> context) {
checkType(lhs, context, Constant.Integer.class);
checkType(rhs, context, Constant.Integer.class);
Constant.Integer lhs_i = (Constant.Integer) lhs;
Constant.Integer rhs_i = (Constant.Integer) rhs;
int result = lhs_i.compareTo(rhs_i);
// In the strict case, the lhs must be strictly below the rhs. In the
// non-strict case, they can be equal.
if (isStrict) {
return Constant.Bool(result < 0);
} else {
return Constant.Bool(result <= 0);
}
}
}