Package wyil.lang

Source Code of wyil.lang.Codes$UnaryOperator

package wyil.lang;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import wycc.lang.NameID;
import wycc.util.Pair;
import wyil.lang.Code.*;
import static wyil.lang.Code.*;
import static wyil.lang.CodeUtils.*;

public abstract class Codes {

  /**
   * Provided to aid readability of client code.
   */
  public final static int NULL_REG = -1;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_0 = 0;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_1 = 1;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_2 = 2;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_3 = 3;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_4 = 4;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_5 = 5;
  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_6 = 6;

  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_7 = 7;

  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_8 = 8;

  /**
   * Provided to aid readability of client code.
   */
  public final static int REG_9 = 9;

  // ===============================================================
  // Bytecode Constructors
  // ===============================================================

  /**
   * Construct an <code>assert</code> bytecode which represents a user-defined
   * assertion check.
   *
   * @param message
   *            --- message to report upon failure.
   * @return
   */
  public static Assert Assert(String target) {
    return Codes.get(new Assert(target));
  }

  /**
   * Construct an <code>assume</code> bytecode which represents a user-defined
   * assumption.
   *
   * @param message
   *            --- message to report upon failure.
   * @return
   */
  public static Assume Assume(String target) {
    return Codes.get(new Assume(target));
  }

  public static BinaryOperator BinaryOperator(Type type, int target, int leftOperand,
      int rightOperand, BinaryOperatorKind op) {
    return Codes.get(new BinaryOperator(type, target, leftOperand,
        rightOperand, op));
  }

  /**
   * Construct a <code>const</code> bytecode which loads a given constant onto
   * the stack.
   *
   * @param afterType
   *            --- record type.
   * @param field
   *            --- field to write.
   * @return
   */
  public static Const Const(int target, Constant constant) {
    return Codes.get(new Const(target, constant));
  }

  /**
   * Construct a <code>copy</code> bytecode which copies the value from a
   * given operand register into a given target register.
   *
   * @param type
   *            --- record type.
   * @param reg
   *            --- reg to load.
   * @return
   */
  public static Assign Assign(Type type, int target, int operand) {
    return Codes.get(new Assign(type, target, operand));
  }

  public static Convert Convert(Type from, int target, int operand, Type to) {
    return Codes.get(new Convert(from, target, operand, to));
  }

  public static final Debug Debug(int operand) {
    return Codes.get(new Debug(operand));
  }

  public static LoopEnd LoopEnd(String label) {
    return Codes.get(new LoopEnd(label));
  }

  /**
   * Construct a <code>fail</code> bytecode which halts execution by raising a
   * fault.
   *
   * @param string
   *            --- Message to give on error.
   * @return
   */
  public static Fail Fail(String message) {
    return Codes.get(new Fail(message));
  }

  /**
   * Construct a <code>fieldload</code> bytecode which reads a given field
   * from a record of a given type.
   *
   * @param type
   *            --- record type.
   * @param field
   *            --- field to load.
   * @return
   */
  public static FieldLoad FieldLoad(Type.EffectiveRecord type, int target,
      int operand, String field) {
    return Codes.get(new FieldLoad(type, target, operand, field));
  }

  /**
   * Construct a <code>goto</code> bytecode which branches unconditionally to
   * a given label.
   *
   * @param label
   *            --- destination label.
   * @return
   */
  public static Goto Goto(String label) {
    return Codes.get(new Goto(label));
  }

  public static Invoke Invoke(Type.FunctionOrMethod fun, int target,
      Collection<Integer> operands, NameID name) {
    return Codes.get(new Invoke(fun, target, CodeUtils.toIntArray(operands), name));
  }

  public static Invoke Invoke(Type.FunctionOrMethod fun, int target,
      int[] operands, NameID name) {
    return Codes.get(new Invoke(fun, target, operands, name));
  }

  public static Lambda Lambda(Type.FunctionOrMethod fun, int target,
      Collection<Integer> operands, NameID name) {
    return Codes.get(new Lambda(fun, target, CodeUtils.toIntArray(operands), name));
  }

  public static Lambda Lambda(Type.FunctionOrMethod fun, int target,
      int[] operands, NameID name) {
    return Codes.get(new Lambda(fun, target, operands, name));
  }

  public static Not Not(int target, int operand) {
    return Codes.get(new Not(target, operand));
  }

  public static LengthOf LengthOf(Type.EffectiveCollection type, int target,
      int operand) {
    return Codes.get(new LengthOf(type, target, operand));
  }

  public static Move Move(Type type, int target, int operand) {
    return Codes.get(new Move(type, target, operand));
  }

  public static SubList SubList(Type.EffectiveList type, int target,
      int sourceOperand, int leftOperand, int rightOperand) {
    int[] operands = new int[] { sourceOperand, leftOperand, rightOperand };
    return Codes.get(new SubList(type, target, operands));
  }

  public static SubList SubList(Type.EffectiveList type, int target,
      int[] operands) {
    return Codes.get(new SubList(type, target, operands));
  }

  public static ListOperator ListOperator(Type.EffectiveList type, int target,
      int leftOperand, int rightOperand, ListOperatorKind dir) {
    return Codes.get(new ListOperator(type, target, leftOperand, rightOperand,
        dir));
  }

  /**
   * Construct a <code>listload</code> bytecode which reads a value from a
   * given index in a given list.
   *
   * @param type
   *            --- list type.
   * @return
   */
  public static IndexOf IndexOf(Type.EffectiveIndexible type, int target,
      int leftOperand, int rightOperand) {
    return Codes.get(new IndexOf(type, target, leftOperand, rightOperand));
  }

  public static Loop Loop(String label, Collection<Integer> operands) {
    return Codes.get(new Loop(label, CodeUtils.toIntArray(operands)));
  }

  public static Loop Loop(String label, int[] modifies) {
    return Codes.get(new Loop(label, modifies));
  }

  public static ForAll ForAll(Type.EffectiveCollection type,
      int sourceOperand, int indexOperand,
      Collection<Integer> modifiedOperands, String label) {
    return Codes.get(new ForAll(type, sourceOperand, indexOperand,
        CodeUtils.toIntArray(modifiedOperands), label));
  }

  public static ForAll ForAll(Type.EffectiveCollection type,
      int sourceOperand, int indexOperand, int[] modifiedOperands,
      String label) {
    return Codes.get(new ForAll(type, sourceOperand, indexOperand,
        modifiedOperands, label));
  }

  /**
   * Construct a <code>newdict</code> bytecode which constructs a new map and
   * puts it on the stack.
   *
   * @param type
   * @return
   */
  public static NewMap NewMap(Type.Map type, int target,
      Collection<Integer> operands) {
    return Codes.get(new NewMap(type, target, CodeUtils.toIntArray(operands)));
  }

  public static NewMap NewMap(Type.Map type, int target, int[] operands) {
    return Codes.get(new NewMap(type, target, operands));
  }

  /**
   * Construct a <code>newset</code> bytecode which constructs a new set and
   * puts it on the stack.
   *
   * @param type
   * @return
   */
  public static NewSet NewSet(Type.Set type, int target,
      Collection<Integer> operands) {
    return Codes.get(new NewSet(type, target, CodeUtils.toIntArray(operands)));
  }

  public static NewSet NewSet(Type.Set type, int target, int[] operands) {
    return Codes.get(new NewSet(type, target, operands));
  }

  /**
   * Construct a <code>newlist</code> bytecode which constructs a new list and
   * puts it on the stack.
   *
   * @param type
   * @return
   */
  public static NewList NewList(Type.List type, int target,
      Collection<Integer> operands) {
    return Codes.get(new NewList(type, target, CodeUtils.toIntArray(operands)));
  }

  public static NewList NewList(Type.List type, int target, int[] operands) {
    return Codes.get(new NewList(type, target, operands));
  }

  /**
   * Construct a <code>newtuple</code> bytecode which constructs a new tuple
   * and puts it on the stack.
   *
   * @param type
   * @return
   */
  public static NewTuple NewTuple(Type.Tuple type, int target,
      Collection<Integer> operands) {
    return Codes.get(new NewTuple(type, target, CodeUtils.toIntArray(operands)));
  }

  public static NewTuple NewTuple(Type.Tuple type, int target, int[] operands) {
    return Codes.get(new NewTuple(type, target, operands));
  }

  /**
   * Construct a <code>newrecord</code> bytecode which constructs a new record
   * and puts it on the stack.
   *
   * @param type
   * @return
   */
  public static NewRecord NewRecord(Type.Record type, int target,
      Collection<Integer> operands) {
    return Codes.get(new NewRecord(type, target, CodeUtils.toIntArray(operands)));
  }

  public static NewRecord NewRecord(Type.Record type, int target,
      int[] operands) {
    return Codes.get(new NewRecord(type, target, operands));
  }

  /**
   * Construct a return bytecode which does return a value and, hence, its
   * type automatically defaults to void.
   *
   * @return
   */
  public static Return Return() {
    return Codes.get(new Return(Type.T_VOID, Codes.NULL_REG));
  }

  /**
   * Construct a return bytecode which reads a value from the operand register
   * and returns it.
   *
   * @param type
   *            --- type of the value to be returned (cannot be void).
   * @param operand
   *            --- register to read return value from.
   * @return
   */
  public static Return Return(Type type, int operand) {
    return Codes.get(new Return(type, operand));
  }

  public static If If(Type type, int leftOperand, int rightOperand,
      Comparator cop, String label) {
    return Codes.get(new If(type, leftOperand, rightOperand, cop, label));
  }

  public static IfIs IfIs(Type type, int leftOperand, Type rightOperand,
      String label) {
    return Codes.get(new IfIs(type, leftOperand, rightOperand, label));
  }

  public static IndirectInvoke IndirectInvoke(Type.FunctionOrMethod fun,
      int target, int operand, Collection<Integer> operands) {
    return Codes.get(new IndirectInvoke(fun, target, operand, CodeUtils
        .toIntArray(operands)));
  }

  public static IndirectInvoke IndirectInvoke(Type.FunctionOrMethod fun,
      int target, int operand, int[] operands) {
    return Codes.get(new IndirectInvoke(fun, target, operand, operands));
  }

  public static Invert Invert(Type type, int target, int operand) {
    return Codes.get(new Invert(type, target, operand));
  }

  public static Label Label(String label) {
    return Codes.get(new Label(label));
  }

  public static final Nop Nop = new Nop();

  public static SetOperator SetOperator(Type.EffectiveSet type, int target,
      int leftOperand, int rightOperand, SetOperatorKind operation) {
    return Codes.get(new SetOperator(type, target, leftOperand, rightOperand,
        operation));
  }

  public static StringOperator StringOperator(int target, int leftOperand,
      int rightOperand, StringOperatorKind operation) {
    return Codes.get(new StringOperator(target, leftOperand, rightOperand,
        operation));
  }

  public static SubString SubString(int target, int sourceOperand,
      int leftOperand, int rightOperand) {
    int[] operands = new int[] { sourceOperand, leftOperand, rightOperand };
    return Codes.get(new SubString(target, operands));
  }

  private static SubString SubString(int target, int[] operands) {
    return Codes.get(new SubString(target, operands));
  }

  /**
   * Construct a <code>switch</code> bytecode which pops a value off the
   * stack, and switches to a given label based on it.
   *
   * @param type
   *            --- value type to switch on.
   * @param defaultLabel
   *            --- target for the default case.
   * @param cases
   *            --- map from values to destination labels.
   * @return
   */
  public static Switch Switch(Type type, int operand, String defaultLabel,
      Collection<Pair<Constant, String>> cases) {
    return Codes.get(new Switch(type, operand, defaultLabel, cases));
  }

  /**
   * Construct a <code>throw</code> bytecode which pops a value off the stack
   * and throws it.
   *
   * @param afterType
   *            --- value type to throw
   * @return
   */
  public static Throw Throw(Type type, int operand) {
    return Codes.get(new Throw(type, operand));
  }

  /**
   * Construct a <code>trycatch</code> bytecode which defines a region of
   * bytecodes which are covered by one or more catch handles.
   *
   * @param target
   *            --- identifies end-of-block label.
   * @param catches
   *            --- map from types to destination labels.
   * @return
   */
  public static TryCatch TryCatch(int operand, String target,
      Collection<Pair<Type, String>> catches) {
    return Codes.get(new TryCatch(operand, target, catches));
  }

  public static TryEnd TryEnd(String label) {
    return Codes.get(new TryEnd(label));
  }

  public static TupleLoad TupleLoad(Type.EffectiveTuple type, int target,
      int operand, int index) {
    return Codes.get(new TupleLoad(type, target, operand, index));
  }

  public static NewObject NewObject(Type.Reference type, int target,
      int operand) {
    return Codes.get(new NewObject(type, target, operand));
  }

  public static Dereference Dereference(Type.Reference type, int target,
      int operand) {
    return Codes.get(new Dereference(type, target, operand));
  }

  public static Update Update(Type beforeType, int target,
      Collection<Integer> operands, int operand, Type afterType,
      Collection<String> fields) {
    return Codes.get(new Update(beforeType, target,
        CodeUtils.toIntArray(operands), operand, afterType, fields));
  }

  public static Update Update(Type beforeType, int target, int[] operands,
      int operand, Type afterType, Collection<String> fields) {
    return Codes.get(new Update(beforeType, target, operands, operand,
        afterType, fields));
  }

  public static UnaryOperator UnaryOperator(Type type, int target, int operand,
      UnaryOperatorKind uop) {
    return Codes.get(new UnaryOperator(type, target, operand, uop));
  }

  public static Void Void(Type type, int[] operands) {
    return Codes.get(new Void(type, operands));
  }

  // ===============================================================
  // Bytecode Implementations
  // ===============================================================

  /**
   * Represents a binary operator (e.g. '+','-',etc) that is provided to a
   * <code>BinOp</code> bytecode.
   *
   * @author David J. Pearce
   *
   */
  public enum BinaryOperatorKind {
    ADD(0) {
      public String toString() {
        return "add";
      }
    },
    SUB(1) {
      public String toString() {
        return "sub";
      }
    },
    MUL(2) {
      public String toString() {
        return "mul";
      }
    },
    DIV(3) {
      public String toString() {
        return "div";
      }
    },
    REM(4) {
      public String toString() {
        return "rem";
      }
    },
    RANGE(5) {
      public String toString() {
        return "range";
      }
    },
    BITWISEOR(6) {
      public String toString() {
        return "or";
      }
    },
    BITWISEXOR(7) {
      public String toString() {
        return "xor";
      }
    },
    BITWISEAND(8) {
      public String toString() {
        return "and";
      }
    },
    LEFTSHIFT(9) {
      public String toString() {
        return "shl";
      }
    },
    RIGHTSHIFT(10) {
      public String toString() {
        return "shr";
      }
    };
    public int offset;

    private BinaryOperatorKind(int offset) {
      this.offset = offset;
    }
  };

  /**
   * <p>
   * A binary operation which reads two numeric values from the operand
   * registers, performs an operation on them and writes the result to the
   * target register. The binary operators are:
   * </p>
   * <ul>
   * <li><i>add, subtract, multiply, divide, remainder</i>. Both operands must
   * be either integers or reals (but not one or the other). A value of the
   * same type is produced.</li>
   * <li><i>range</i></li>
   * <li><i>bitwiseor, bitwisexor, bitwiseand</i></li>
   * <li><i>leftshift,rightshift</i></li>
   * </ul>
   * For example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y) => int:
   *     return ((x * y) + 1) / 2
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y) => int:
   * body:
   *     mul %2 = %0, %1   : int
   *     const %3 = 1      : int
   *     add %2 = %2, %3   : int
   *     const %3 = 2      : int
   *     const %4 = 0      : int
   *     assertne %3, %4 "division by zero" : int
   *     div %2 = %2, %3   : int
   *     return %2         : int
   * </pre>
   *
   * Here, the <code>assertne</code> bytecode has been included to check
   * against division-by-zero. In this particular case the assertion is known
   * true at compile time and, in practice, would be compiled away.
   *
   * @author David J. Pearce
   *
   */
  public static final class BinaryOperator extends AbstractBinaryAssignable<Type> {
    public final BinaryOperatorKind kind;

    private BinaryOperator(Type type, int target, int lhs, int rhs,
        BinaryOperatorKind bop) {
      super(type, target, lhs, rhs);
      if (bop == null) {
        throw new IllegalArgumentException(
            "BinOp bop argument cannot be null");
      }
      this.kind = bop;
    }

    @Override
    public int opcode() {
      return OPCODE_add + kind.offset;
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return BinaryOperator(type(), nTarget, nOperands[0], nOperands[1],
          kind);
    }

    public int hashCode() {
      return kind.hashCode() + super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof BinaryOperator) {
        BinaryOperator bo = (BinaryOperator) o;
        return kind.equals(bo.kind) && super.equals(bo);
      }
      return false;
    }

    public String toString() {
      return kind + " %" + target() + " = %" + operand(0) + ", %"
          + operand(1) + " : " + type();
    }
  }

  /**
   * Reads a value from the operand register, converts it to a given type and
   * writes the result to the target register. This bytecode is the only way
   * to change the type of a value. It's purpose is to simplify
   * implementations which have different representations of data types. A
   * convert bytecode must be inserted whenever the type of a register
   * changes. This includes at control-flow meet points, when the value is
   * passed as a parameter, assigned to a field, etc. For example, the
   * following Whiley code:
   *
   * <pre>
   * function f(int x) => real:
   *     return x + 1
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => real:
   * body:
   *     const %2 = 1           : int
   *     add %1 = %0, %2        : int
   *     convert %1 = %1 real   : int
   *     return %1              : real
   * </pre>
   * <p>
   * Here, we see that the <code>int</code> value in register <code>%1</code>
   * must be explicitly converted into a <code>real</code> value before it can
   * be returned from this function.
   * </p>
   * <p>
   * <b>NOTE:</b> In many cases, this bytecode may correspond to a nop on the
   * hardware. Consider converting from <code>[any]</code> to <code>any</code>
   * . On the JVM, <code>any</code> translates to <code>Object</code>, whilst
   * <code>[any]</code> translates to <code>List</code> (which is an instance
   * of <code>Object</code>). Thus, no conversion is necessary since
   * <code>List</code> can safely flow into <code>Object</code>.
   * </p>
   *
   */
  public static final class Convert extends AbstractUnaryAssignable<Type> {
    public final Type result;

    private Convert(Type from, int target, int operand, Type result) {
      super(from, target, operand);
      if (result == null) {
        throw new IllegalArgumentException(
            "Convert to argument cannot be null");
      }
      this.result = result;
    }

    public Code.Unit clone(int nTarget, int[] nOperands) {
      return Convert(type(), nTarget, nOperands[0], result);
    }

    public int opcode() {
      return OPCODE_convert;
    }

    public int hashCode() {
      return result.hashCode() + super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof Convert) {
        Convert c = (Convert) o;
        return super.equals(c) && result.equals(c.result);
      }
      return false;
    }

    public String toString() {
      return "convert %" + target() + " = %" + operand(0) + " " + result
          + " : " + type();
    }
  }

  /**
   * Writes a constant value to a target register. This includes
   * <i>integers</i>, <i>rationals</i>, <i>lists</i>, <i>sets</i>,
   * <i>maps</i>, etc. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x) => int:
   *     xs = {1,2.12}
   *     return |xs| + 1
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => int:
   * body:
   *     var xs
   *     const %2 = 1               : int
   *     convert %2 = % 2 int|real  : int
   *     const %3 = 2.12            : real
   *     convert %3 = % 3 int|real  : real
   *     newset %1 = (%2, %3)       : {int|real}
   *     assign %3 = %1             : {int|real}
   *     lengthof %3 = % 3          : {int|real}
   *     const %4 = 1               : int
   *     add %2 = % 3, %4           : int
   *     return %2                  : int
   * </pre>
   *
   * Here, we see two kinds of constants values being used: integers (i.e.
   * <code>const %2 = 1</code>) and rationals (i.e.
   * <code>const %3 = 2.12</code>).
   *
   * @author David J. Pearce
   *
   */
  public static final class Const extends AbstractAssignable {
    public final Constant constant;

    private Const(int target, Constant constant) {
      super(target);
      this.constant = constant;
    }

    public int opcode() {
      return OPCODE_const;
    }

    @Override
    public void registers(java.util.Set<Integer> registers) {
      registers.add(target());
    }

    @Override
    public Code.Unit remap(Map<Integer, Integer> binding) {
      Integer nTarget = binding.get(target());
      if (nTarget != null) {
        return Const(nTarget, constant);
      }
      return this;
    }

    public Type assignedType() {
      return (Type) constant.type();
    }

    public int hashCode() {
      return constant.hashCode() + target();
    }

    public boolean equals(Object o) {
      if (o instanceof Const) {
        Const c = (Const) o;
        return constant.equals(c.constant) && target() == c.target();
      }
      return false;
    }

    public String toString() {
      return "const %" + target() + " = " + constant + " : "
          + constant.type();
    }
  }

  /**
   * Copy the contents from a given operand register into a given target
   * register. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x) => int:
   *     x = x + 1
   *     return x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => int:
   * body:
   *     assign %1 = %0      : int
   *     const %2 = 1        : int
   *     add %0 = %1, %2     : int
   *     return %0           : int
   * </pre>
   *
   * Here we see that an initial assignment is made from register
   * <code>%0</code> to register <code>%1</code>. In fact, this assignment is
   * unecessary but is useful to illustrate the <code>assign</code> bytecode.
   *
   * <p>
   * <b>NOTE:</b> on many architectures this operation may not actually clone
   * the data in question. Rather, it may copy the <i>reference</i> to the
   * data and then increment its <i>reference count</i>. This is to ensure
   * efficient treatment of large compound structures (e.g. lists, sets, maps
   * and records).
   * </p>
   *
   * @author David J. Pearce
   *
   */
  public static final class Assign extends AbstractUnaryAssignable<Type> {

    private Assign(Type type, int target, int operand) {
      super(type, target, operand);
    }

    public int opcode() {
      return OPCODE_assign;
    }

    public Code.Unit clone(int nTarget, int[] nOperands) {
      return Assign(type(), nTarget, nOperands[0]);
    }

    public boolean equals(Object o) {
      if (o instanceof Assign) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "assign %" + target() + " = %" + operand(0) + " " + " : " + type();
    }
  }

  /**
   * Read a string from the operand register and prints it to the debug
   * console. For example, the following Whiley code:
   *
   * <pre>
   * method f(int x):
   *     debug "X = " + x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * method f(int x):
   * body:
   *     const %2 = "X = "       : string
   *     convert %0 = %0 any     : int
   *     invoke %0 (%0) whiley/lang/Any:toString : string(any)
   *     strappend %1 = %2, %0   : string
   *     debug %1                : string
   *     return
   * </pre>
   *
   * <b>NOTE</b> This bytecode is not intended to form part of the program's
   * operation. Rather, it is to facilitate debugging within functions (since
   * they cannot have side-effects). Furthermore, if debugging is disabled,
   * this bytecode is a nop.
   *
   * @author David J. Pearce
   *
   */
  public static final class Debug extends AbstractUnaryOp<Type.Strung> {

    private Debug(int operand) {
      super(Type.T_STRING, operand);
    }

    public int opcode() {
      return OPCODE_debug;
    }

    @Override
    public Code.Unit clone(int nOperand) {
      return Debug(nOperand);
    }

    public boolean equals(Object o) {
      return o instanceof Debug && super.equals(o);
    }

    public String toString() {
      return "debug %" + operand + " " + " : " + type;
    }
  }

  /**
   * Marks the end of a loop block.
   *
   * @author David J. Pearce
   *
   */
  public static final class LoopEnd extends Label {
    LoopEnd(String label) {
      super(label);
    }

    public LoopEnd relabel(Map<String, String> labels) {
      String nlabel = labels.get(label);
      if (nlabel == null) {
        return this;
      } else {
        return LoopEnd(nlabel);
      }
    }

    public int hashCode() {
      return label.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof LoopEnd) {
        LoopEnd e = (LoopEnd) o;
        return e.label.equals(label);
      }
      return false;
    }

    public String toString() {
      return "end " + label;
    }
  }

  /**
   * An abstract class representing either an <code>assert</code> or
   * <code>assume</code> bytecode block.
   *
   * @author David J. Pearce
   *
   */
  public static abstract class AssertOrAssume extends Code.Unit {
    public final String target;


    private AssertOrAssume(String target) {
      this.target = target;
    }
  }
  /**
   * Represents a block of bytecode instructions representing an assertion.
   *
   * @author David J. Pearce
   *
   */
  public static final class Assert extends AssertOrAssume {

    private Assert(String target) {
      super(target);
    }

    public int opcode() {
      return OPCODE_assertblock;
    }

    public String toString() {
      return "assert " + target;
    }
  }

  /**
   * Represents a block of bytecode instructions representing an assumption.
   *
   * @author David J. Pearce
   *
   */
  public static final class Assume extends AssertOrAssume {

    private Assume(String target) {
      super(target);
    }

    public int opcode() {
      return OPCODE_assumeblock;
    }

    public String toString() {
      return "assume " + target;
    }
  }

  /**
   * A bytecode that halts execution by raising a runtime fault. This bytecode
   * signals that some has gone wrong, and is typically used to signal an
   * assertion failure.
   *
   * @author David J. Pearce
   *
   */
  public static final class Fail extends Code.Unit {
    public final Constant.Strung message;

    private Fail(String message) {
      this.message = Constant.V_STRING(message);
    }

    @Override
    public int opcode() {
      return OPCODE_fail;
    }

    public String toString() {
      if(message == null) {
        return "fail";
      } else {
        return "fail \"" + message + "\"";
      }
    }
  }

  /**
   * Reads a record value from an operand register, extracts the value of a
   * given field and writes this to the target register. For example, the
   * following Whiley code:
   *
   * <pre>
   * type Point is {int x, int y}
   *
   * function f(Point p) => int:
   *     return p.x + p.y
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f({int x,int y} p) => int:
   * body:
   *     fieldload %2 = %0 x    : {int x,int y}
   *     fieldload %3 = %0 y    : {int x,int y}
   *     add %1 = %2, %3        : int
   *     return %1              : int
   * </pre>
   *
   * @author David J. Pearce
   *
   */
  public static final class FieldLoad extends
      AbstractUnaryAssignable<Type.EffectiveRecord> {
    public final String field;

    private FieldLoad(Type.EffectiveRecord type, int target, int operand,
        String field) {
      super(type, target, operand);
      if (field == null) {
        throw new IllegalArgumentException(
            "FieldLoad field argument cannot be null");
      }
      this.field = field;
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return FieldLoad(type(), nTarget, nOperands[0], field);
    }

    public int opcode() {
      return OPCODE_fieldload;
    }

    public int hashCode() {
      return super.hashCode() + field.hashCode();
    }

    public Type fieldType() {
      return type().fields().get(field);
    }

    public Type assignedType() {
      return type().fields().get(field);
    }

    public boolean equals(Object o) {
      if (o instanceof FieldLoad) {
        FieldLoad i = (FieldLoad) o;
        return super.equals(i) && field.equals(i.field);
      }
      return false;
    }

    public String toString() {
      return "fieldload %" + target() + " = %" + operand(0) + " " + field
          + " : " + type();
    }
  }

  /**
   * Branches unconditionally to the given label. This is typically used for
   * if/else statements. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x) => int:
   *     if x >= 0:
   *         x = 1
   *     else:
   *         x = -1
   *     return x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => int:
   * body:
   *     const %1 = 0             : int
   *     iflt %0, %1 goto blklab0 : int
   *     const %0 = 1             : int
   *     goto blklab1
   * .blklab0
   *     const %0 = 1             : int
   *     neg %0 = % 0             : int
   * .blklab1
   *     return %0                : int
   * </pre>
   *
   * Here, we see the <code>goto</code> bytecode being used to jump from the
   * end of the true branch over the false branch.
   *
   * <p>
   * <b>Note:</b> in WyIL bytecode, <i>such branches may only go forward</i>.
   * Thus, a <code>goto</code> bytecode cannot be used to implement the
   * back-edge of a loop. Rather, a loop block must be used for this purpose.
   * </p>
   *
   * @author David J. Pearce
   *
   */
  public static final class Goto extends Code.Unit {
    public final String target;

    private Goto(String target) {
      this.target = target;
    }

    public int opcode() {
      return OPCODE_goto;
    }

    public Goto relabel(Map<String, String> labels) {
      String nlabel = labels.get(target);
      if (nlabel == null) {
        return this;
      } else {
        return Goto(nlabel);
      }
    }

    public int hashCode() {
      return target.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof Goto) {
        return target.equals(((Goto) o).target);
      }
      return false;
    }

    public String toString() {
      return "goto " + target;
    }
  }

  /**
   * <p>
   * Branches conditionally to the given label by reading the values from two
   * operand registers and comparing them. The possible comparators are:
   * </p>
   * <ul>
   * <li><i>equals (eq) and not-equals (ne)</i>. Both operands must have the
   * given type.</li>
   * <li><i>less-than (lt), less-than-or-equals (le), greater-than (gt) and
   * great-than-or-equals (ge).</i> Both operands must have the given type,
   * which additionally must by either <code>char</code>, <code>int</code> or
   * <code>real</code>.</li>
   * <li><i>element of (in).</i> The second operand must be a set whose
   * element type is that of the first.</li>
   * <li><i>subset (ss) and subset-equals (sse)</i>. Both operands must have
   * the given type, which additionally must be a set.</li>
   * </ul>
   * For example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y) => int:
   *     if x < y:
   *         return -1
   *     else if x > y:
   *         return 1
   *     else:
   *         return 0
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y) => int:
   * body:
   *     ifge %0, %1 goto blklab0 : int
   *     const %2 = -1 : int
   *     return %2 : int
   * .blklab0
   *     ifle %0, %1 goto blklab2 : int
   *     const %2 = 1 : int
   *     return %2 : int
   * .blklab2
   *     const %2 = 0 : int
   *     return %2 : int
   * </pre>
   *
   * <b>Note:</b> in WyIL bytecode, <i>such branches may only go forward</i>.
   * Thus, an <code>ifgoto</code> bytecode cannot be used to implement the
   * back-edge of a loop. Rather, a loop block must be used for this purpose.
   *
   * @author David J. Pearce
   *
   */
  public static final class If extends AbstractBinaryOp<Type> {
    public final String target;
    public final Comparator op;

    private If(Type type, int leftOperand, int rightOperand, Comparator op,
        String target) {
      super(type, leftOperand, rightOperand);
      if (op == null) {
        throw new IllegalArgumentException(
            "IfGoto op argument cannot be null");
      }
      if (target == null) {
        throw new IllegalArgumentException(
            "IfGoto target argument cannot be null");
      }
      this.op = op;
      this.target = target;
    }

    public If relabel(Map<String, String> labels) {
      String nlabel = labels.get(target);
      if (nlabel == null) {
        return this;
      } else {
        return If(type, leftOperand, rightOperand, op, nlabel);
      }
    }

    public int opcode() {
      return OPCODE_ifeq + op.offset;
    }

    @Override
    public Code.Unit clone(int nLeftOperand, int nRightOperand) {
      return If(type, nLeftOperand, nRightOperand, op, target);
    }

    public int hashCode() {
      return super.hashCode() + op.hashCode() + target.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof If) {
        If ig = (If) o;
        return op == ig.op && target.equals(ig.target)
            && super.equals(ig);
      }
      return false;
    }

    public String codeString() {
      return null;
    }

    public String toString() {
      return "if" + op + " %" + leftOperand + ", %" + rightOperand
          + " goto " + target + " : " + type;
    }
  }

  /**
   * Represents a comparison operator (e.g. '==','!=',etc) that is provided to
   * a <code>IfGoto</code> bytecode.
   *
   * @author David J. Pearce
   *
   */
  public enum Comparator {
    EQ(0) {
      public String toString() {
        return "eq";
      }
    },
    NEQ(1) {
      public String toString() {
        return "ne";
      }
    },
    LT(2) {
      public String toString() {
        return "lt";
      }
    },
    LTEQ(3) {
      public String toString() {
        return "le";
      }
    },
    GT(4) {
      public String toString() {
        return "gt";
      }
    },
    GTEQ(5) {
      public String toString() {
        return "ge";
      }
    },
    IN(6) {
      public String toString() {
        return "in";
      }
    },
    SUBSET(7) {
      public String toString() {
        return "sb";
      }
    },
    SUBSETEQ(8) {
      public String toString() {
        return "sbe";
      }
    };
    public int offset;

    private Comparator(int offset) {
      this.offset = offset;
    }
  };

  /**
   * Branches conditionally to the given label based on the result of a
   * runtime type test against a value from the operand register. More
   * specifically, it checks whether the value is a subtype of the type test.
   * The operand register is automatically <i>retyped</i> as a result of the
   * type test. On the true branch, its type is intersected with type test. On
   * the false branch, its type is intersected with the <i>negation</i> of the
   * type test. For example, the following Whiley code:
   *
   * <pre>
   * function f(int|[int] x) => int:
   *     if x is [int]:
   *         return |x|
   *     else:
   *         return x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int|[int] x) => int:
   * body:
   *     ifis %0, [int] goto lab    : int|[int]
   *     return %0                  : int
   * .lab
   *     lengthof %0 = %0           : [int]
   *     return %0                  : int
   * </pre>
   *
   * Here, we see that, on the false branch, register <code>%0</code> is
   * automatically given type <code>int</code>, whilst on the true branch it
   * is automatically given type <code>[int]</code>.
   *
   * <p>
   * <b>Note:</b> in WyIL bytecode, <i>such branches may only go forward</i>.
   * Thus, an <code>ifis</code> bytecode cannot be used to implement the
   * back-edge of a loop. Rather, a loop block must be used for this purpose.
   * </p>
   *
   * @author David J. Pearce
   *
   */
  public static final class IfIs extends AbstractUnaryOp<Type> {
    public final String target;
    public final Type rightOperand;

    private IfIs(Type type, int leftOperand, Type rightOperand,
        String target) {
      super(type, leftOperand);
      if (rightOperand == null) {
        throw new IllegalArgumentException(
            "IfIs test argument cannot be null");
      }
      if (target == null) {
        throw new IllegalArgumentException(
            "IfIs target argument cannot be null");
      }
      this.target = target;
      this.rightOperand = rightOperand;
    }

    public int opcode() {
      return OPCODE_ifis;
    }

    public IfIs relabel(Map<String, String> labels) {
      String nlabel = labels.get(target);
      if (nlabel == null) {
        return this;
      } else {
        return IfIs(type, operand, rightOperand, nlabel);
      }
    }

    @Override
    public Code.Unit clone(int nOperand) {
      return IfIs(type, nOperand, rightOperand, target);
    }

    public int hashCode() {
      return type.hashCode() + +target.hashCode() + super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof IfIs) {
        IfIs ig = (IfIs) o;
        return super.equals(o) && rightOperand.equals(ig.rightOperand)
            && target.equals(ig.target);
      }
      return false;
    }

    public String toString() {
      return "ifis" + " %" + operand + ", " + rightOperand + " goto "
          + target + " : " + type;
    }

  }

  /**
   * Represents an indirect function call. For example, consider the
   * following:
   *
   * <pre>
   * function fun(function (int)=>int f, int x) => int:
   *    return f(x)
   * </pre>
   *
   * Here, the function call <code>f(x)</code> is indirect as the called
   * function is determined by the variable <code>f</code>.
   *
   * @author David J. Pearce
   *
   */
  public static final class IndirectInvoke extends
      AbstractNaryAssignable<Type.FunctionOrMethod> {

    /**
     * Construct an indirect invocation bytecode which assigns to an
     * optional target register the result from indirectly invoking a
     * function in a given operand with a given set of parameter operands.
     *
     * @param type
     * @param target Register (optional) to which result of invocation is assigned.
     * @param operand Register holding function point through which indirect invocation is made.
     * @param operands Registers holding parameters for the invoked function
     */
    private IndirectInvoke(Type.FunctionOrMethod type, int target,
        int operand, int[] operands) {
      super(type, target, append(operand,operands));
    }

    /**
     * Return register holding the indirect function/method reference.
     *
     * @return
     */
    public int reference() {
      return operands()[0];
    }

    /**
     * Return register holding the ith parameter for the invoked function.
     *
     * @param i
     * @return
     */
    public int parameter(int i) {
      return operands()[i + 1];
    }

    /**
     * Return registers holding parameters for the invoked function.
     *
     * @param i
     * @return
     */
    public int[] parameters() {
      return Arrays.copyOfRange(operands(),1,operands().length);
    }

    public int opcode() {
      if (type() instanceof Type.Function) {
        if (target() != Codes.NULL_REG) {
          return OPCODE_indirectinvokefn;
        } else {
          return OPCODE_indirectinvokefnv;
        }
      } else {
        if (target() != Codes.NULL_REG) {
          return OPCODE_indirectinvokemd;
        } else {
          return OPCODE_indirectinvokemdv;
        }
      }
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return IndirectInvoke(type(), nTarget, nOperands[0],
          Arrays.copyOfRange(nOperands, 1, nOperands.length));
    }

    public boolean equals(Object o) {
      return o instanceof IndirectInvoke && super.equals(o);
    }

    public Type assignedType() {
      return type().ret();
    }

    public String toString() {
      if (target() != Codes.NULL_REG) {
        return "indirectinvoke " + target() + " = " + reference() + " "
            + arrayToString(parameters()) + " : " + type();
      } else {
        return "indirectinvoke %" + reference() + " "
            + arrayToString(parameters()) + " : " + type();
      }
    }
  }

  /**
   * Read a boolean value from the operand register, inverts it and writes the
   * result to the target register. For example, the following Whiley code:
   *
   * <pre>
   * function f(bool x) => bool:
   *     return !x
   * </pre>
   *
   * can be translated into the following WyIL:
   *
   * <pre>
   * function f(bool x) => bool:
   * body:
   *     not %0 = %0     : int
   *     return %0       : int
   * </pre>
   *
   * This simply reads the parameter <code>x</code> stored in register
   * <code>%0</code>, inverts it and then returns the inverted value.
   *
   * @author David J. Pearce
   *
   */
  public static final class Not extends AbstractUnaryAssignable<Type.Bool> {

    private Not(int target, int operand) {
      super(Type.T_BOOL, target, operand);
    }

    public int opcode() {
      return OPCODE_not;
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return Not(nTarget, nOperands[0]);
    }

    public int hashCode() {
      return super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof Not) {
        Not n = (Not) o;
        return super.equals(n);
      }
      return false;
    }

    public String toString() {
      return "not %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * Corresponds to a function or method call whose parameters are read from
   * zero or more operand registers. If a return value is required, this is
   * written to a target register afterwards. For example, the following
   * Whiley code:
   *
   * <pre>
   * function g(int x, int y, int z) => int:
   *     return x * y * z
   *
   * function f(int x, int y) => int:
   *     r = g(x,y,3)
   *     return r + 1
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function g(int x, int y, int z) => int:
   * body:
   *     mul %3 = %0, %1   : int
   *     mul %3 = %3, %2   : int
   *     return %3         : int
   *
   * function f(int x, int y) => int:
   * body:
   *     const %2 = 3                    : int
   *     invoke %2 = (%0, %1, %2) test:g   : int(int,int,int)
   *     const %3 = 1                    : int
   *     add %2 = (%2, %3)                : int
   *     return %2                       : int
   * </pre>
   *
   * Here, we see that arguments to the <code>invoke</code> bytecode are
   * supplied in the order they are given in the function or method's
   * declaration.
   *
   * @author David J. Pearce
   *
   */
  public static final class Invoke extends
      AbstractNaryAssignable<Type.FunctionOrMethod> {
    public final NameID name;

    private Invoke(Type.FunctionOrMethod type, int target, int[] operands,
        NameID name) {
      super(type, target, operands);
      this.name = name;
    }

    public int opcode() {
      if (type() instanceof Type.Function) {
        if (target() != Codes.NULL_REG) {
          return OPCODE_invokefn;
        } else {
          return OPCODE_invokefnv;
        }
      } else {
        if (target() != Codes.NULL_REG) {
          return OPCODE_invokemd;
        } else {
          return OPCODE_invokemdv;
        }
      }
    }

    public Type assignedType() {
      return type().ret();
    }

    public int hashCode() {
      return name.hashCode() + super.hashCode();
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return Invoke(type(), nTarget, nOperands, name);
    }

    public boolean equals(Object o) {
      if (o instanceof Invoke) {
        Invoke i = (Invoke) o;
        return name.equals(i.name) && super.equals(i);
      }
      return false;
    }

    public String toString() {
      if (target() != Codes.NULL_REG) {
        return "invoke %" + target() + " = " + arrayToString(operands())
            + " " + name + " : " + type();
      } else {
        return "invoke %" + arrayToString(operands()) + " " + name
            + " : " + type();
      }
    }
  }

  public static final class Lambda extends
      AbstractNaryAssignable<Type.FunctionOrMethod> {
    public final NameID name;

    private Lambda(Type.FunctionOrMethod type, int target, int[] operands,
        NameID name) {
      super(type, target, operands);
      this.name = name;
    }

    public int opcode() {
      if (type() instanceof Type.Function) {
        return OPCODE_lambdafn;
      } else {
        return OPCODE_lambdamd;
      }
    }

    public Type assignedType() {
      return type().ret();
    }

    public int hashCode() {
      return name.hashCode() + super.hashCode();
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return Lambda(type(), nTarget, nOperands, name);
    }

    public boolean equals(Object o) {
      if (o instanceof Lambda) {
        Lambda i = (Lambda) o;
        return name.equals(i.name) && super.equals(i);
      }
      return false;
    }

    public String toString() {
      return "lambda %" + target() + " = " + arrayToString(operands()) + " "
          + name + " : " + type();
    }
  }

  /**
   * Represents the labelled destination of a branch or loop statement.
   *
   * @author David J. Pearce
   *
   */
  public static class Label extends Code.Unit {
    public final String label;

    private Label(String label) {
      this.label = label;
    }

    public int opcode() {
      return -1;
    }

    public Label relabel(Map<String, String> labels) {
      String nlabel = labels.get(label);
      if (nlabel == null) {
        return this;
      } else {
        return Label(nlabel);
      }
    }

    public int hashCode() {
      return label.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof Label) {
        return label.equals(((Label) o).label);
      }
      return false;
    }

    public String toString() {
      return "." + label;
    }
  }

  public enum ListOperatorKind {
    APPEND(0) {
      public String toString() {
        return "append";
      }
    },
    LEFT_APPEND(1) {
      public String toString() {
        return "appendl";
      }
    },
    RIGHT_APPEND(2) {
      public String toString() {
        return "appendr";
      }
    };
    public final int offset;

    private ListOperatorKind(int offset) {
      this.offset = offset;
    }
  }

  /**
   * Reads the (effective) list values from two operand registers, performs an
   * operation (e.g. append) on them and writes the result back to a target
   * register. For example, the following Whiley code:
   *
   * <pre>
   * function f([int] xs, [int] ys) => [int]:
   *    return xs ++ ys
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f([int] xs, [int] ys) => [int]:
   * body:
   *    append %2 = %0, %1   : [int]
   *    return %2            : [int]
   * </pre>
   *
   * This appends two the parameter lists together writting the new list into
   * register <code>%2</code>.
   *
   * @author David J. Pearce
   *
   */
  public static final class ListOperator extends
      AbstractBinaryAssignable<Type.EffectiveList> {
    public final ListOperatorKind kind;

    private ListOperator(Type.EffectiveList type, int target, int leftOperand,
        int rightOperand, ListOperatorKind operation) {
      super(type, target, leftOperand, rightOperand);
      if (operation == null) {
        throw new IllegalArgumentException(
            "ListAppend direction cannot be null");
      }
      this.kind = operation;
    }

    public int opcode() {
      return OPCODE_append + kind.offset;
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return ListOperator(type(), nTarget, nOperands[0], nOperands[1],
          kind);
    }

    public int hashCode() {
      return super.hashCode() + kind.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof ListOperator) {
        ListOperator setop = (ListOperator) o;
        return super.equals(setop) && kind.equals(setop.kind);
      }
      return false;
    }

    public String toString() {
      return kind + " %" + target() + " = %" + operand(0) + ", %"
          + operand(1) + " : " + type();
    }
  }

  /**
   * Reads an (effective) collection (i.e. a set, list or map) from the
   * operand register, and writes its length into the target register. For
   * example, the following Whiley code:
   *
   * <pre>
   * function f([int] ls) => int:
   *     return |ls|
   * </pre>
   *
   * translates to the following WyIL code:
   *
   * <pre>
   * function f([int] ls) => int:
   * body:
   *     lengthof %0 = %0   : [int]
   *     return %0          : int
   * </pre>
   *
   * @author David J. Pearce
   *
   */
  public static final class LengthOf extends
      AbstractUnaryAssignable<Type.EffectiveCollection> {
    private LengthOf(Type.EffectiveCollection type, int target, int operand) {
      super(type, target, operand);
    }

    public int opcode() {
      return OPCODE_lengthof;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return LengthOf(type(), nTarget, nOperands[0]);
    }

    public Type assignedType() {
      return Type.T_INT;
    }

    public boolean equals(Object o) {
      if (o instanceof LengthOf) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "lengthof %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * Reads the (effective) list value from a source operand register, and the
   * integer values from two index operand registers, computes the sublist and
   * writes the result back to a target register.
   *
   * @author David J. Pearce
   *
   */
  public static final class SubList extends
      AbstractNaryAssignable<Type.EffectiveList> {

    private SubList(Type.EffectiveList type, int target, int[] operands) {
      super(type, target, operands);
    }

    public int opcode() {
      return OPCODE_sublist;
    }

    @Override
    public final Code.Unit clone(int nTarget, int[] nOperands) {
      return SubList(type(), nTarget, nOperands);
    }

    public boolean equals(Object o) {
      return o instanceof SubList && super.equals(o);
    }

    public String toString() {
      return "sublist %" + target() + " = %" + operands()[0] + ", %"
          + operands()[1] + ", %" + operands()[2] + " : " + type();
    }
  }

  /**
   * Reads an effective list or map from the source (left) operand register,
   * and a key value from the key (right) operand register and returns the
   * value associated with that key. If the key does not exist, then a fault
   * is raised. For example, the following Whiley code:
   *
   * <pre>
   * function f({int=>string} map, int key) => string:
   *     return map[key]
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f({int->string} map, int key) => string:
   * body:
   *     assertky %1, %0 "invalid key"       : {int->string}
   *     indexof %2 = %0, %1                 : {int->string}
   *     return %2                          : string
   * </pre>
   *
   * Here, we see the <code>assertky</code> bytecode is used to first check
   * that the given key exists in <code>map</code>, otherwise a fault is
   * raised.
   *
   * @author David J. Pearce
   *
   */
  public static final class IndexOf extends
      AbstractBinaryAssignable<Type.EffectiveIndexible> {
    private IndexOf(Type.EffectiveIndexible type, int target,
        int sourceOperand, int keyOperand) {
      super(type, target, sourceOperand, keyOperand);
    }

    public int opcode() {
      return OPCODE_indexof;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return IndexOf(type(), nTarget, nOperands[0], nOperands[1]);
    }

    public Type assignedType() {
      return type().value();
    }

    public boolean equals(Object o) {
      if (o instanceof IndexOf) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "indexof %" + target() + " = %" + operand(0) + ", %"
          + operand(1) + " : " + type();
    }
  }

  /**
   * Moves the contents of a given operand register into a given target
   * register. This is similar to an <code>assign</code> bytecode, except that
   * the register's contents are <i>voided</i> afterwards. This guarantees
   * that the register is no longer live, which is useful for determining the
   * live ranges of registers in a function or method. For example, the
   * following Whiley code:
   *
   * <pre>
   * function f(int x, int y) => int:
   *     x = x + 1
   *     return x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y) => int:
   * body:
   *     ifge %0, %1 goto blklab0  : int
   *     move %0 = %1              : int
   * .blklab0
   *     return %0                 : int
   * </pre>
   *
   * Here we see that when <code>x < y</code> the value of <code>y</code>
   * (held in register <code>%1</code>) is <i>moved</i> into variable
   * <code>x</code> (held in register <code>%0</code>). This is safe because
   * register <code>%1</code> is no longer live at that point.
   *
   * @author David J. Pearce
   *
   */
  public static final class Move extends AbstractUnaryAssignable<Type> {

    private Move(Type type, int target, int operand) {
      super(type, target, operand);
    }

    public int opcode() {
      return OPCODE_move;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return Move(type(), nTarget, nOperands[0]);
    }

    public boolean equals(Object o) {
      if (o instanceof Move) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "move %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * Represents a block of code which loops continuously until e.g. a
   * conditional branch is taken out of the block. For example:
   *
   * <pre>
   * function f() => int:
   *     r = 0
   *     while r < 10:
   *         r = r + 1
   *     return r
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f() => int:
   * body:
   *     const %0 = 0             : int
   *     loop (%0)
   *         const %1 = 10        : int
   *         ifge %0, %1 goto blklab0 : int
   *         const %1 = 1         : int
   *         add %0 = %0, %1      : int
   * .blklab0
   *     return %0                : int
   * </pre>
   *
   * <p>
   * Here, we see a loop which increments an accumulator register
   * <code>%0</code> until it reaches <code>10</code>, and then exits the loop
   * block.
   * </p>
   * <p>
   * The <i>modified operands</i> of a loop bytecode (shown in brackets
   * alongside the bytecode) indicate those operands which are modified at
   * some point within the loop.
   * </p>
   *
   * @author David J. Pearce
   *
   */
  public static class Loop extends Code.Unit {
    public final String target;
    public final int[] modifiedOperands;

    private Loop(String target, int[] modifies) {
      this.target = target;
      this.modifiedOperands = modifies;
    }

    public int opcode() {
      return OPCODE_loop;
    }

    public Loop relabel(Map<String, String> labels) {
      String nlabel = labels.get(target);
      if (nlabel == null) {
        return this;
      } else {
        return Loop(nlabel, modifiedOperands);
      }
    }

    @Override
    public void registers(java.util.Set<Integer> registers) {
      for (int operand : modifiedOperands) {
        registers.add(operand);
      }
    }

    @Override
    public Code.Unit remap(Map<Integer, Integer> binding) {
      int[] nOperands = remapOperands(binding, modifiedOperands);
      if (nOperands != modifiedOperands) {
        return Loop(target, nOperands);
      } else {
        return this;
      }
    }

    public int hashCode() {
      return target.hashCode() + Arrays.hashCode(modifiedOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof Loop) {
        Loop f = (Loop) o;
        return target.equals(f.target)
            && Arrays.equals(modifiedOperands, f.modifiedOperands);
      }
      return false;
    }

    public String toString() {
      return "loop " + arrayToString(modifiedOperands);
    }
  }

  /**
   * Pops a set, list or map from the stack and iterates over every element it
   * contains. A register is identified to hold the current value being
   * iterated over.
   *
   * @author David J. Pearce
   *
   */
  public static final class ForAll extends Loop {
    public final int sourceOperand;
    public final int indexOperand;
    public final Type.EffectiveCollection type;

    private ForAll(Type.EffectiveCollection type, int sourceOperand,
        int indexOperand, int[] modifies, String target) {
      super(target, modifies);
      this.type = type;
      this.sourceOperand = sourceOperand;
      this.indexOperand = indexOperand;
    }

    public int opcode() {
      return OPCODE_forall;
    }

    public ForAll relabel(Map<String, String> labels) {
      String nlabel = labels.get(target);
      if (nlabel == null) {
        return this;
      } else {
        return ForAll(type, sourceOperand, indexOperand,
            modifiedOperands, nlabel);
      }
    }

    @Override
    public void registers(java.util.Set<Integer> registers) {
      registers.add(indexOperand);
      registers.add(sourceOperand);
      super.registers(registers);
    }

    @Override
    public Code.Unit remap(Map<Integer, Integer> binding) {
      int[] nModifiedOperands = remapOperands(binding, modifiedOperands);
      Integer nIndexOperand = binding.get(indexOperand);
      Integer nSourceOperand = binding.get(sourceOperand);
      if (nSourceOperand != null || nIndexOperand != null
          || nModifiedOperands != modifiedOperands) {
        nSourceOperand = nSourceOperand != null ? nSourceOperand
            : sourceOperand;
        nIndexOperand = nIndexOperand != null ? nIndexOperand
            : indexOperand;

        return ForAll(type, nSourceOperand, nIndexOperand,
            nModifiedOperands, target);
      } else {
        return this;
      }
    }

    public int hashCode() {
      return super.hashCode() + sourceOperand + indexOperand
          + Arrays.hashCode(modifiedOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof ForAll) {
        ForAll f = (ForAll) o;
        return target.equals(f.target) && type.equals(f.type)
            && sourceOperand == f.sourceOperand
            && indexOperand == f.indexOperand
            && Arrays.equals(modifiedOperands, f.modifiedOperands);
      }
      return false;
    }

    public String toString() {
      return "forall %" + indexOperand + " in %" + sourceOperand + " "
          + arrayToString(modifiedOperands) + " : " + type;
    }
  }

  /**
   * Represents a type which may appear on the left of an assignment
   * expression. Lists, Dictionaries, Strings, Records and References are the
   * only valid types for an lval.
   *
   * @author David J. Pearce
   *
   */
  public static abstract class LVal<T> {
    protected T type;

    public LVal(T t) {
      this.type = t;
    }

    public T rawType() {
      return type;
    }
  }

  /**
   * An LVal with map type.
   *
   * @author David J. Pearce
   *
   */
  public static final class MapLVal extends LVal<Type.EffectiveMap> {
    public final int keyOperand;

    public MapLVal(Type.EffectiveMap t, int keyOperand) {
      super(t);
      this.keyOperand = keyOperand;
    }
  }

  /**
   * An LVal with list type.
   *
   * @author David J. Pearce
   *
   */
  public static final class ListLVal extends LVal<Type.EffectiveList> {
    public final int indexOperand;

    public ListLVal(Type.EffectiveList t, int indexOperand) {
      super(t);
      this.indexOperand = indexOperand;
    }
  }

  /**
   * An LVal with list type.
   *
   * @author David J. Pearce
   *
   */
  public static final class ReferenceLVal extends LVal<Type.Reference> {
    public ReferenceLVal(Type.Reference t) {
      super(t);
    }
  }

  /**
   * An LVal with string type.
   *
   * @author David J. Pearce
   *
   */
  public static final class StringLVal extends LVal<Type.EffectiveIndexible> {
    public final int indexOperand;

    public StringLVal(int indexOperand) {
      super(Type.T_STRING);
      this.indexOperand = indexOperand;
    }
  }

  /**
   * An LVal with record type.
   *
   * @author David J. Pearce
   *
   */
  public static final class RecordLVal extends LVal<Type.EffectiveRecord> {
    public final String field;

    public RecordLVal(Type.EffectiveRecord t, String field) {
      super(t);
      this.field = field;
      if (!t.fields().containsKey(field)) {
        throw new IllegalArgumentException("invalid Record Type");
      }
    }
  }

  private static final class UpdateIterator implements Iterator<LVal> {
    private final ArrayList<String> fields;
    private final int[] operands;
    private Type iter;
    private int fieldIndex;
    private int operandIndex;
    private int index;

    public UpdateIterator(Type type, int level, int[] operands,
        ArrayList<String> fields) {
      this.fields = fields;
      this.iter = type;
      this.index = level;
      this.operands = operands;
    }

    public LVal next() {
      Type raw = iter;
      index--;
      if (Type.isSubtype(Type.T_STRING, iter)) {
        iter = Type.T_CHAR;
        return new StringLVal(operands[operandIndex++]);
      } else if (Type.isSubtype(Type.Reference(Type.T_ANY), iter)) {
        Type.Reference proc = Type.effectiveReference(iter);
        iter = proc.element();
        return new ReferenceLVal(proc);
      } else if (iter instanceof Type.EffectiveList) {
        Type.EffectiveList list = (Type.EffectiveList) iter;
        iter = list.element();
        return new ListLVal(list, operands[operandIndex++]);
      } else if (iter instanceof Type.EffectiveMap) {
        Type.EffectiveMap dict = (Type.EffectiveMap) iter;
        iter = dict.value();
        return new MapLVal(dict, operands[operandIndex++]);
      } else if (iter instanceof Type.EffectiveRecord) {
        Type.EffectiveRecord rec = (Type.EffectiveRecord) iter;
        String field = fields.get(fieldIndex++);
        iter = rec.fields().get(field);
        return new RecordLVal(rec, field);
      } else {
        throw new IllegalArgumentException(
            "Invalid type for Update");
      }
    }

    public boolean hasNext() {
      return index > 0;
    }

    public void remove() {
      throw new UnsupportedOperationException(
          "UpdateIterator is unmodifiable");
    }
  }

  /**
   * <p>
   * Pops a compound structure, zero or more indices and a value from the
   * stack and updates the compound structure with the given value. Valid
   * compound structures are lists, dictionaries, strings, records and
   * references.
   * </p>
   * <p>
   * Ideally, this operation is done in-place, meaning the operation is
   * constant time. However, to support Whiley's value semantics this bytecode
   * may require (in some cases) a clone of the underlying data-structure.
   * Thus, the worst-case runtime of this operation is linear in the size of
   * the compound structure.
   * </p>
   *
   * @author David J. Pearce
   *
   */
  public static final class Update extends AbstractNaryAssignable<Type>
      implements Iterable<LVal> {
    public final Type afterType;
    public final ArrayList<String> fields;

    /**
     * Construct an Update bytecode which assigns to a given operand to a
     * set of target registers. For indirect map/list updates, an additional
     * set of operands is used to generate the appropriate keys. For field
     * assignments, a set of fields is provided.
     *
     * @param beforeType
     * @param target
     *            Register being assigned
     * @param operands
     *            Registers used for keys on left-hand side in map/list
     *            updates
     * @param operand
     *            Register on right-hand side whose value is assigned
     * @param afterType
     * @param fields
     *            Fields for record updates
     */
    private Update(Type beforeType, int target, int[] operands,
        int operand, Type afterType, Collection<String> fields) {
      super(beforeType, target, append(operands,operand));
      if (fields == null) {
        throw new IllegalArgumentException(
            "FieldStore fields argument cannot be null");
      }
      this.afterType = afterType;
      this.fields = new ArrayList<String>(fields);
    }

    // Helper used for clone()
    private Update(Type beforeType, int target, int[] operands,
        Type afterType, Collection<String> fields) {
      super(beforeType, target, operands);
      if (fields == null) {
        throw new IllegalArgumentException(
            "FieldStore fields argument cannot be null");
      }
      this.afterType = afterType;
      this.fields = new ArrayList<String>(fields);
    }

    public int opcode() {
      return OPCODE_update;
    }

    /**
     * Returns register from which assigned value is read. This is also
     * known as the "right-hand side".
     *
     * @return
     */
    public int result() {
      return operands()[operands().length-1];
    }

    /**
     * Get the given key register (in order of appearance from the left)
     * used in a map or list update.
     *
     * @param index
     * @return
     */
    public int key(int index) {
      return operands()[index];
    }

    /**
     * Return the registers used to hold key values for map or list updates.
     *
     * @return
     */
    public int[] keys() {
      return Arrays.copyOf(operands(),operands().length-1);
    }

    public int level() {
      int base = -1; // because last operand is rhs
      if (type() instanceof Type.Reference) {
        base++;
      }
      return base + fields.size() + operands().length;
    }

    public Iterator<LVal> iterator() {
      return new UpdateIterator(afterType, level(), keys(), fields);
    }

    public Type assignedType() {
      return afterType;
    }

    /**
     * Extract the type for the right-hand side of this assignment.
     *
     * @return
     */
    public Type rhs() {
      Type iter = afterType;

      int fieldIndex = 0;
      for (int i = 0; i != level(); ++i) {
        if (Type.isSubtype(Type.T_STRING, iter)) {
          iter = Type.T_CHAR;
        } else if (Type.isSubtype(Type.Reference(Type.T_ANY), iter)) {
          Type.Reference proc = Type.effectiveReference(iter);
          iter = proc.element();
        } else if (iter instanceof Type.EffectiveList) {
          Type.EffectiveList list = (Type.EffectiveList) iter;
          iter = list.element();
        } else if (iter instanceof Type.EffectiveMap) {
          Type.EffectiveMap dict = (Type.EffectiveMap) iter;
          iter = dict.value();
        } else if (iter instanceof Type.EffectiveRecord) {
          Type.EffectiveRecord rec = (Type.EffectiveRecord) iter;
          String field = fields.get(fieldIndex++);
          iter = rec.fields().get(field);
        } else {
          throw new IllegalArgumentException(
              "Invalid type for Update");
        }
      }
      return iter;
    }

    @Override
    public final Code.Unit clone(int nTarget, int[] nOperands) {
      return Update(type(), nTarget,
          Arrays.copyOf(nOperands, nOperands.length - 1),
          nOperands[nOperands.length - 1], afterType, fields);
    }

    public boolean equals(Object o) {
      if (o instanceof Update) {
        Update i = (Update) o;
        return super.equals(o) && afterType.equals(i.afterType)
            && fields.equals(i.fields);
      }
      return false;
    }

    public String toString() {
      String r = "%" + target();
      for (LVal lv : this) {
        if (lv instanceof ListLVal) {
          ListLVal l = (ListLVal) lv;
          r = r + "[%" + l.indexOperand + "]";
        } else if (lv instanceof StringLVal) {
          StringLVal l = (StringLVal) lv;
          r = r + "[%" + l.indexOperand + "]";
        } else if (lv instanceof MapLVal) {
          MapLVal l = (MapLVal) lv;
          r = r + "[%" + l.keyOperand + "]";
        } else if (lv instanceof RecordLVal) {
          RecordLVal l = (RecordLVal) lv;
          r = r + "." + l.field;
        } else {
          ReferenceLVal l = (ReferenceLVal) lv;
          r = "(*" + r + ")";
        }
      }
      return "update " + r + " = %" + result() + " : " + type() + " -> "
          + afterType;
    }
  }

  /**
   * Constructs a map value from zero or more key-value pairs on the stack.
   * For each pair, the key must occur directly before the value on the stack.
   * For example, consider the following Whiley function <code>f()</code>:
   *
   * <pre>
   * function f() => {int=>string}:
   *     return {1=>"Hello",2=>"World"}
   * </pre>
   *
   * This could be compiled into the following WyIL code using this bytecode:
   *
   * <pre>
   * function f() => {int->string}:
   * body:
   *   const %1 = 1                   : int
   *   const %2 = "Hello"             : string
   *   const %3 = 2                   : int
   *   const %4 = "World"             : string
   *   newmap %0 = (%1, %2, %3, %4)   : {int=>string}
   *   return %0                      : {int=>string}
   * </pre>
   *
   *
   * @author David J. Pearce
   *
   */
  public static final class NewMap extends AbstractNaryAssignable<Type.Map> {

    private NewMap(Type.Map type, int target, int[] operands) {
      super(type, target, operands);
    }

    public int opcode() {
      return OPCODE_newmap;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewMap(type(), nTarget, nOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof NewMap) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "newmap %" + target() + " = " + arrayToString(operands())
          + " : " + type();
    }
  }

  /**
   * Constructs a new record value from the values of zero or more operand
   * register, each of which is associated with a field name. The new record
   * value is then written into the target register. For example, the
   * following Whiley code:
   *
   * <pre>
   * type Point is {real x, real y}
   *
   * function f(real x, real y) => Point:
   *     return {x: x, y: x}
   * </pre>
   *
   * can be translated into the following WyIL:
   *
   * <pre>
   * function f(real x, real y) => Point:
   * body:
   *     assign %3 = %0         : real
   *     assign %4 = %0         : real
   *     newrecord %2 (%3, %4)  : {real x,real y}
   *     return %2              : {real x,real y}
   * </pre>
   *
   * @author David J. Pearce
   *
   */
  public static final class NewRecord extends
      AbstractNaryAssignable<Type.Record> {
    private NewRecord(Type.Record type, int target, int[] operands) {
      super(type, target, operands);
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewRecord(type(), nTarget, nOperands);
    }

    public int opcode() {
      return OPCODE_newrecord;
    }

    public boolean equals(Object o) {
      if (o instanceof NewRecord) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "newrecord %" + target() + " = " + arrayToString(operands())
          + " : " + type();
    }
  }

  /**
   * Constructs a new tuple value from the values given by zero or more
   * operand registers. The new tuple is then written into the target
   * register. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y) => (int,int):
   *     return x,y
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y) => (int,int):
   * body:
   *     assign %3 = %0          : int
   *     assign %4 = %1          : int
   *     newtuple %2 = (%3, %4)  : (int,int)
   *     return %2               : (int,int)
   * </pre>
   *
   * This writes the tuple value generated from <code>(x,y)</code> into
   * register <code>%2</code> and returns it.
   *
   * @author David J. Pearce
   *
   */
  public static final class NewTuple extends
      AbstractNaryAssignable<Type.Tuple> {

    private NewTuple(Type.Tuple type, int target, int[] operands) {
      super(type, target, operands);
    }

    public int opcode() {
      return OPCODE_newtuple;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewTuple(type(), nTarget, nOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof NewTuple) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "newtuple %" + target() + " = " + arrayToString(operands())
          + " : " + type();
    }
  }

  /**
   * Constructs a new set value from the values given by zero or more operand
   * registers. The new set is then written into the target register. For
   * example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y, int z) => {int}:
   *     return {x,y,z}
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y, int z) => {int}:
   * body:
   *    assign %4 = %0             : int
   *    assign %5 = %1             : int
   *    assign %6 = %2             : int
   *    newset %3 = (%4, %5, %6)   : [int]
   *    return %3                  : [int]
   * </pre>
   *
   * Writes the set value given by <code>{x,y,z}</code> into register
   * <code>%3</code> and returns it.
   *
   * @author David J. Pearce
   *
   */
  public static final class NewSet extends AbstractNaryAssignable<Type.Set> {

    private NewSet(Type.Set type, int target, int[] operands) {
      super(type, target, operands);
    }

    public int opcode() {
      return OPCODE_newset;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewSet(type(), nTarget, nOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof NewSet) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "newset %" + target() + " = " + arrayToString(operands())
          + " : " + type();
    }
  }

  /**
   * Constructs a new list value from the values given by zero or more operand
   * registers. The new list is then written into the target register. For
   * example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y, int z) => [int]:
   *     return [x,y,z]
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x, int y, int z) => [int]:
   * body:
   *    assign %4 = %0             : int
   *    assign %5 = %1             : int
   *    assign %6 = %2             : int
   *    newlist %3 = (%4, %5, %6)  : [int]
   *    return %3                  : [int]
   * </pre>
   *
   * Writes the list value given by <code>[x,y,z]</code> into register
   * <code>%3</code> and returns it.
   *
   * @author David J. Pearce
   *
   */
  public static final class NewList extends AbstractNaryAssignable<Type.List> {

    private NewList(Type.List type, int target, int[] operands) {
      super(type, target, operands);
    }

    public int opcode() {
      return OPCODE_newlist;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewList(type(), nTarget, nOperands);
    }

    public boolean equals(Object o) {
      if (o instanceof NewList) {
        return super.equals(operands());
      }
      return false;
    }

    public String toString() {
      return "newlist %" + target() + " = " + arrayToString(operands())
          + " : " + type();
    }
  }

  /**
   * Represents a no-operation bytecode which, as the name suggests, does
   * nothing.
   *
   * @author David J. Pearce
   *
   */
  public static final class Nop extends Code.Unit {
    private Nop() {
    }

    @Override
    public int opcode() {
      return OPCODE_nop;
    }

    public String toString() {
      return "nop";
    }
  }

  /**
   * Returns from the enclosing function or method, possibly returning a
   * value. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x, int y) => int:
   *     return x + y
   * </pre>
   *
   * can be translated into the following WyIL:
   *
   * <pre>
   * function f(int x, int y) => int:
   * body:
   *     assign %3 = %0    : int
   *     assign %4 = %1    : int
   *     add %2 = % 3, %4  : int
   *     return %2         : int
   * </pre>
   *
   * Here, the
   * <code>return<code> bytecode returns the value of its operand register.
   *
   * @author David J. Pearce
   *
   */
  public static final class Return extends AbstractUnaryOp<Type> {

    private Return(Type type, int operand) {
      super(type, operand);
      if (type == Type.T_VOID && operand != Codes.NULL_REG) {
        throw new IllegalArgumentException(
            "Return with void type cannot have target register.");
      } else if (type != Type.T_VOID && operand == Codes.NULL_REG) {
        throw new IllegalArgumentException(
            "Return with non-void type must have target register.");
      }
    }

    @Override
    public int opcode() {
      if (type == Type.T_VOID) {
        return OPCODE_returnv;
      } else {
        return OPCODE_return;
      }
    }

    public Code.Unit clone(int nOperand) {
      return new Return(type, nOperand);
    }

    public boolean equals(Object o) {
      if (o instanceof Return) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      if (operand != Codes.NULL_REG) {
        return "return %" + operand + " : " + type;
      } else {
        return "return";
      }
    }
  }

  public enum SetOperatorKind {
    UNION(0) {
      public String toString() {
        return "union";
      }
    },
    LEFT_UNION(1) {
      public String toString() {
        return "unionl";
      }
    },
    RIGHT_UNION(2) {
      public String toString() {
        return "unionl";
      }
    },
    INTERSECTION(3) {
      public String toString() {
        return "intersect";
      }
    },
    LEFT_INTERSECTION(4) {
      public String toString() {
        return "intersectl";
      }
    },
    RIGHT_INTERSECTION(5) {
      public String toString() {
        return "intersectr";
      }
    },
    DIFFERENCE(6) {
      public String toString() {
        return "diff";
      }
    },
    LEFT_DIFFERENCE(7) {
      public String toString() {
        return "diffl";
      }
    };
    public final int offset;

    private SetOperatorKind(int offset) {
      this.offset = offset;
    }
  }

  /**
   * <p>
   * A binary operation which reads two set values from the operand registers,
   * performs an operation on them and writes the result to the target
   * register. The binary set operators are:
   * </p>
   * <ul>
   * <li><i>union, intersection, difference</i>. Both operands must be have
   * the given (effective) set type. same type is produced.</li>
   * <li><i>left union, left intersection, left difference</i>. The left
   * operand must have the given (effective) set type, whilst the right
   * operand has the given (effective) set element type.</li>
   * <li><i>right union, right intersection</i>. The right operand must have
   * the given (effective) set type, whilst the left operand has the given
   * (effective) set element type.</li>
   * </ul>
   * For example, the following Whiley code:
   *
   * <pre>
   * function f({int} xs, {int} ys) => {int}:
   *     return xs + ys // set union
   *
   * function g(int x, {int} ys) => {int}:
   *     return {x} & ys // set intersection
   *
   * function h({int} xs, int y) => {int}:
   *     return xs - {y} // set difference
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f({int} xs, {int} ys) => {int}:
   * body:
   *     union %2 = %0, %1  : {int}
   *     return %2          : {int}
   *
   * function g({int} xs, {int} ys) => {int}:
   * body:
   *     rintersect %2 = %0, %1  : {int}
   *     return %2               : {int}
   *
   * function h({int} xs, {int} ys) => {int}:
   * body:
   *     ldiff %2 = %0, %1    : {int}
   *     return %2            : {int}
   * </pre>
   *
   * Here, we see that the purpose of the <i>left-</i> and <i>right-</i>
   * operations is to avoid creating a temporary set in the common case of a
   * single element set on one side. This is largely an optimisation and it is
   * expected that the front-end of the compiler will spots such situations
   * and compile them down appropriately.
   *
   * @author David J. Pearce
   */
  public static final class SetOperator extends
      AbstractBinaryAssignable<Type.EffectiveSet> {
    public final SetOperatorKind kind;

    private SetOperator(Type.EffectiveSet type, int target, int leftOperand,
        int rightOperand, SetOperatorKind operation) {
      super(type, target, leftOperand, rightOperand);
      if (operation == null) {
        throw new IllegalArgumentException(
            "SetOp operation cannot be null");
      }
      this.kind = operation;
    }

    @Override
    public int opcode() {
      return OPCODE_union + kind.offset;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return SetOperator(type(), nTarget, nOperands[0], nOperands[1],
          kind);
    }

    public int hashCode() {
      return kind.hashCode() + super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof SetOperator) {
        SetOperator setop = (SetOperator) o;
        return kind.equals(setop.kind) && super.equals(o);
      }
      return false;
    }

    public String toString() {
      return kind + " %" + target() + " = %" + operand(0) + ", %"
          + operand(1) + " : " + type();
    }
  }

  public enum StringOperatorKind {
    APPEND(0) {
      public String toString() {
        return "sappend";
      }
    },
    LEFT_APPEND(1) {
      public String toString() {
        return "sappendl";
      }
    },
    RIGHT_APPEND(2) {
      public String toString() {
        return "sappendr";
      }
    };
    public final int offset;

    private StringOperatorKind(int offset) {
      this.offset = offset;
    }
  }

  /**
   * <p>
   * A binary operation which reads two string values from the operand
   * registers, performs an operation (append) on them and writes the result
   * to the target register. The binary set operators are:
   * </p>
   * <ul>
   * <li><i>append</i>. Both operands must be have string type.</li>
   * <li><i>left append</i>. The left operand must have string type, whilst
   * the right operand has char type.</li>
   * <li><i>right append</i>. The right operand must have string type, whilst
   * the left operand has char type.</li>
   * </ul>
   * For example, the following Whiley code:
   *
   * <pre>
   * function f(string xs, string ys) => string:
   *     return xs ++ ys
   *
   * function g(string xs, char y) => string:
   *     return xs ++ y
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(string xs, string ys) => string:
   * body:
   *     strappend %2 = %0, %2    : string
   *     return %2                : string
   *
   * function g(string xs, char y) => string:
   * body:
   *     strappend_l %2 = %0, %1  : string
   *     return %2                : string
   * </pre>
   *
   * Here, we see that the purpose of the <i>left-</i> and <i>right-</i>
   * operations is to avoid creating a temporary string in the common case of
   * a single char being appended.
   *
   * @author David J. Pearce
   */
  public static final class StringOperator extends
      AbstractBinaryAssignable<Type.Strung> {
    public final StringOperatorKind kind;

    private StringOperator(int target, int leftOperand, int rightOperand,
        StringOperatorKind operation) {
      super(Type.T_STRING, target, leftOperand, rightOperand);
      if (operation == null) {
        throw new IllegalArgumentException(
            "StringBinOp operation cannot be null");
      }
      this.kind = operation;
    }

    @Override
    public int opcode() {
      return OPCODE_sappend + kind.offset;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return StringOperator(nTarget, nOperands[0], nOperands[1], kind);
    }

    public boolean equals(Object o) {
      if (o instanceof StringOperator) {
        StringOperator setop = (StringOperator) o;
        return kind.equals(setop.kind) && super.equals(o);
      }
      return false;
    }

    public String toString() {
      return kind + " %" + target() + " = %" + operand(0) + ", %"
          + operand(1) + " : " + type();
    }
  }

  /**
   * Reads the string value from a source operand register, and the integer
   * values from two index operand registers, computes the substring and
   * writes the result back to a target register.
   *
   * @author David J. Pearce
   *
   */
  public static final class SubString extends AbstractNaryAssignable {

    private SubString(int target, int[] operands) {
      super(Type.T_STRING, target, operands);
    }

    @Override
    public int opcode() {
      return OPCODE_substring;
    }

    @Override
    public final Code.Unit clone(int nTarget, int[] nOperands) {
      return SubString(nTarget, nOperands);
    }

    public boolean equals(Object o) {
      return o instanceof SubString && super.equals(o);
    }

    public String toString() {
      return "substr %" + target() + " = %" + operands()[0] + ", %"
          + operands()[1] + ", %" + operands()[2] + " : " + type();
    }
  }

  /**
   * Performs a multi-way branch based on the value contained in the operand
   * register. A <i>dispatch table</i> is provided which maps individual
   * matched values to their destination labels. For example, the following
   * Whiley code:
   *
   * <pre>
   * function f(int x) => string:
   *     switch x:
   *         case 1:
   *             return "ONE"
   *         case 2:
   *             return "TWO"
   *         default:
   *             return "OTHER"
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => string:
   * body:
   *     switch %0 1->blklab1, 2->blklab2, *->blklab3
   * .blklab1
   *     const %1 = "ONE" : string
   *     return %1 : string
   * .blklab2
   *     const %1 = "TWO" : string
   *     return %1 : string
   * .blklab3
   *     const %1 = "OTHER" : string
   *     return %1 : string
   * </pre>
   *
   * Here, we see how e.g. value <code>1</code> is mapped to the label
   * <code>blklab1</code>. Thus, if the operand register <code>%0</code>
   * contains value <code>1</code>, then control will be transferred to that
   * label. The final mapping <code>*->blklab3</code> covers the default case
   * where the value in the operand is not otherwise matched.
   *
   * @author David J. Pearce
   *
   */
  public static final class Switch extends AbstractUnaryOp<Type> {
    public final ArrayList<Pair<Constant, String>> branches;
    public final String defaultTarget;

    Switch(Type type, int operand, String defaultTarget,
        Collection<Pair<Constant, String>> branches) {
      super(type, operand);
      this.branches = new ArrayList<Pair<Constant, String>>(branches);
      this.defaultTarget = defaultTarget;
    }

    @Override
    public int opcode() {
      return OPCODE_switch;
    }

    public Switch relabel(Map<String, String> labels) {
      ArrayList<Pair<Constant, String>> nbranches = new ArrayList();
      for (Pair<Constant, String> p : branches) {
        String nlabel = labels.get(p.second());
        if (nlabel == null) {
          nbranches.add(p);
        } else {
          nbranches.add(new Pair(p.first(), nlabel));
        }
      }

      String nlabel = labels.get(defaultTarget);
      if (nlabel == null) {
        return Switch(type, operand, defaultTarget, nbranches);
      } else {
        return Switch(type, operand, nlabel, nbranches);
      }
    }

    public int hashCode() {
      return type.hashCode() + operand + defaultTarget.hashCode()
          + branches.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof Switch) {
        Switch ig = (Switch) o;
        return operand == ig.operand
            && defaultTarget.equals(ig.defaultTarget)
            && branches.equals(ig.branches) && type.equals(ig.type);
      }
      return false;
    }

    public String toString() {
      String table = "";
      boolean firstTime = true;
      for (Pair<Constant, String> p : branches) {
        if (!firstTime) {
          table += ", ";
        }
        firstTime = false;
        table += p.first() + "->" + p.second();
      }
      table += ", *->" + defaultTarget;
      return "switch %" + operand + " " + table;
    }

    @Override
    public Code.Unit clone(int nOperand) {
      return new Switch(type, nOperand, defaultTarget, branches);
    }

  }

  /**
   * Throws an exception containing the value in the given operand register.
   * For example, the following Whiley Code:
   *
   * <pre>
   * function f(int x) => int
   * throws string:
   *     if x < 0:
   *         throw "ERROR"
   *     else:
   *         return 1
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => int
   * throws:
   *      string
   * body:
   *     const %1 = 0 : int
   *     ifge %0, %1 goto blklab0 : int
   *     const %1 = "ERROR" : string
   *     throw %1 : string
   * .blklab0
   *     const %1 = 1 : int
   *     return %1 : int
   * </pre>
   *
   * Here, we see an exception containing a <code>string</code> value will be
   * thrown when the parameter <code>x</code> is negative.
   *
   * @author David J. Pearce
   *
   */
  public static final class Throw extends AbstractUnaryOp<Type> {
    private Throw(Type type, int operand) {
      super(type, operand);
    }

    @Override
    public int opcode() {
      return OPCODE_throw;
    }

    @Override
    public Code.Unit clone(int nOperand) {
      return Throw(type, nOperand);
    }

    public boolean equals(Object o) {
      if (o instanceof Throw) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "throw %" + operand + " : " + type;
    }
  }

  /**
   * Represents a try-catch block within which specified exceptions will
   * caught and processed within a handler. For example, the following Whiley
   * code:
   *
   * <pre>
   * function f(int x) => int
   * throws Error:
   *     ...
   *
   * function g(int x) => int:
   *     try:
   *         x = f(x)
   *     catch(Error e):
   *         return 0
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int x) => int:
   * throws:
   *     Error
   * body:
   *     ...
   *
   * function g(int x) => int:
   * body:
   *     trycatch Error -> lab2
   *        assign %3 = %0           : int
   *        invoke %0 = (%3) test:f  : int(int) throws {string msg}
   *     return
   * .lab2
   *     const %3 = 0                : int
   *     return %3                   : int
   * </pre>
   *
   * Here, we see that within the try-catch block control is transferred to
   * <code>lab2</code> if an exception of type <code>Error</code> is thrown.
   *
   * @author David J. Pearce
   *
   */
  public static final class TryCatch extends Code.Unit {
    public final int operand;
    public final String target;
    public final ArrayList<Pair<Type, String>> catches;

    TryCatch(int operand, String label,
        Collection<Pair<Type, String>> catches) {
      this.operand = operand;
      this.catches = new ArrayList<Pair<Type, String>>(catches);
      this.target = label;
    }

    @Override
    public int opcode() {
      return OPCODE_trycatch;
    }

    @Override
    public void registers(java.util.Set<Integer> registers) {
      registers.add(operand);
    }

    @Override
    public Code.Unit remap(Map<Integer, Integer> binding) {
      Integer nOperand = binding.get(operand);
      if (nOperand != null) {
        return TryCatch(nOperand, target, catches);
      }
      return this;
    }

    public TryCatch relabel(Map<String, String> labels) {
      ArrayList<Pair<Type, String>> nbranches = new ArrayList();
      for (Pair<Type, String> p : catches) {
        String nlabel = labels.get(p.second());
        if (nlabel == null) {
          nbranches.add(p);
        } else {
          nbranches.add(new Pair(p.first(), nlabel));
        }
      }

      String ntarget = labels.get(target);
      if (ntarget != null) {
        return TryCatch(operand, ntarget, nbranches);
      } else {
        return TryCatch(operand, target, nbranches);
      }
    }

    public int hashCode() {
      return operand + target.hashCode() + catches.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof TryCatch) {
        TryCatch ig = (TryCatch) o;
        return operand == ig.operand && target.equals(ig.target)
            && catches.equals(ig.catches);
      }
      return false;
    }

    public String toString() {
      String table = "";
      boolean firstTime = true;
      for (Pair<Type, String> p : catches) {
        if (!firstTime) {
          table += ", ";
        }
        firstTime = false;
        table += p.first() + "->" + p.second();
      }
      return "trycatch " + table;
    }
  }

  /**
   * Marks the end of a try-catch block.
   *
   * @author David J. Pearce
   *
   */
  public static final class TryEnd extends Label {
    TryEnd(String label) {
      super(label);
    }

    public TryEnd relabel(Map<String, String> labels) {
      String nlabel = labels.get(label);
      if (nlabel == null) {
        return this;
      } else {
        return TryEnd(nlabel);
      }
    }

    public int hashCode() {
      return label.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof TryEnd) {
        TryEnd e = (TryEnd) o;
        return e.label.equals(label);
      }
      return false;
    }

    public String toString() {
      return "tryend " + label;
    }
  }

  /**
   * Corresponds to a bitwise inversion operation, which reads a byte value
   * from the operand register, inverts it and writes the result to the target
   * resgister. For example, the following Whiley code:
   *
   * <pre>
   * function f(byte x) => byte:
   *    return ~x
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(byte x) => byte:
   * body:
   *     invert %0 = %0   : byte
   *     return %0        : byte
   * </pre>
   *
   * Here, the expression <code>~x</code> generates an <code>invert</code>
   * bytecode.
   *
   * @author David J. Pearce
   *
   */
  public static final class Invert extends AbstractUnaryAssignable<Type> {

    private Invert(Type type, int target, int operand) {
      super(type, target, operand);
    }

    @Override
    public int opcode() {
      return OPCODE_invert;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return Invert(type(), nTarget, nOperands[0]);
    }

    public boolean equals(Object o) {
      if (o instanceof Invert) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "invert %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * Instantiate a new object from the value in a given operand register, and
   * write the result (a reference to that object) to a given target register.
   * For example, the following Whiley code:
   *
   * <pre>
   * type PointObj as &{real x, real y}
   *
   * method f(real x, real y) => PointObj:
   *     return new {x: x, y: y}
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * method f(int x, int y) => &{real x,real y}:
   * body:
   *     newrecord %2 = (%0, %1)  : {real x,real y}
   *     newobject %2 = %2        : ref {real x,real y}
   *     return %2                : ref {real x,real y}
   * </pre>
   *
   * <b>NOTE:</b> objects are unlike other data types in WyIL, in that they
   * represent mutable state allocated on a heap. Thus, changes to an object
   * within a method are visible to those outside of the method.
   *
   * @author David J. Pearce
   *
   */
  public static final class NewObject extends
      AbstractUnaryAssignable<Type.Reference> {

    private NewObject(Type.Reference type, int target, int operand) {
      super(type, target, operand);
    }

    @Override
    public int opcode() {
      return OPCODE_newobject;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return NewObject(type(), nTarget, nOperands[0]);
    }

    public boolean equals(Object o) {
      if (o instanceof NewObject) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "newobject %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * Read a tuple value from the operand register, extract the value it
   * contains at a given index and write that to the target register. For
   * example, the following Whiley code:
   *
   * <pre>
   * function f(int,int tup) => int:
   *     return tup[0]
   * </pre>
   *
   * can be translated into the following WyIL code:
   *
   * <pre>
   * function f(int,int tup) => int:
   * body:
   *     tupleload %0 = %0 0  : int,int
   *     return %0            : int
   * </pre>
   *
   * This simply reads the parameter <code>x</code> stored in register
   * <code>%0</code>, and returns the value stored at index <code>0</code>.
   *
   * @author David J. Pearce
   *
   */
  public static final class TupleLoad extends
      AbstractUnaryAssignable<Type.EffectiveTuple> {
    public final int index;

    private TupleLoad(Type.EffectiveTuple type, int target, int operand,
        int index) {
      super(type, target, operand);
      this.index = index;
    }

    @Override
    public int opcode() {
      return OPCODE_tupleload;
    }

    public Type assignedType() {
      return type().element(index);
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return TupleLoad(type(), nTarget, nOperands[0], index);
    }

    public boolean equals(Object o) {
      if (o instanceof TupleLoad) {
        TupleLoad i = (TupleLoad) o;
        return index == i.index && super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "tupleload %" + target() + " = %" + operand(0) + " " + index
          + " : " + type();
    }
  }

  /**
   * Reads a reference value from the operand register, dereferences it (i.e.
   * extracts the value it refers to) and writes this to the target register.
   *
   * @author David J. Pearce
   *
   */
  public static final class Dereference extends
      AbstractUnaryAssignable<Type.Reference> {

    private Dereference(Type.Reference type, int target, int operand) {
      super(type, target, operand);
    }

    @Override
    public int opcode() {
      return OPCODE_dereference;
    }

    public Type assignedType() {
      return type().element();
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return Dereference(type(), nTarget, nOperands[0]);
    }

    public boolean equals(Object o) {
      if (o instanceof Dereference) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "deref %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  public enum UnaryOperatorKind {
    NEG(0) {
      public String toString() {
        return "neg";
      }
    },

    NUMERATOR(1) {
      public String toString() {
        return "num";
      }
    },

    DENOMINATOR(2) {
      public String toString() {
        return "den";
      }
    };
    public final int offset;

    private UnaryOperatorKind(int offset) {
      this.offset = offset;
    }
  };

  /**
   * Read a number (int or real) from the operand register, perform a unary
   * arithmetic operation on it (e.g. negation) and writes the result to the
   * target register. For example, the following Whiley code:
   *
   * <pre>
   * function f(int x) => int:
   *     return -x
   * </pre>
   *
   * can be translated into the following WyIL:
   *
   * <pre>
   * function f(int x) => int:
   * body:
   *     neg %0 = %0     : int
   *     return %0       : int
   * </pre>
   *
   * This simply reads the parameter <code>x</code> stored in register
   * <code>%0</code>, negates it and then returns the negated value.
   *
   * @author David J. Pearce
   *
   */
  public static final class UnaryOperator extends AbstractUnaryAssignable<Type> {
    public final UnaryOperatorKind kind;

    private UnaryOperator(Type type, int target, int operand, UnaryOperatorKind uop) {
      super(type, target, operand);
      if (uop == null) {
        throw new IllegalArgumentException(
            "UnaryArithOp bop argument cannot be null");
      }
      this.kind = uop;
    }

    @Override
    public int opcode() {
      return OPCODE_neg + kind.offset;
    }

    @Override
    public Code.Unit clone(int nTarget, int[] nOperands) {
      return UnaryOperator(type(), nTarget, nOperands[0], kind);
    }

    public int hashCode() {
      return kind.hashCode() + super.hashCode();
    }

    public boolean equals(Object o) {
      if (o instanceof UnaryOperator) {
        UnaryOperator bo = (UnaryOperator) o;
        return kind.equals(bo.kind) && super.equals(bo);
      }
      return false;
    }

    public String toString() {
      return kind + " %" + target() + " = %" + operand(0) + " : " + type();
    }
  }

  /**
   * The void bytecode is used to indicate that the given register(s) are no
   * longer live. This is useful for communicating information to the memory
   * management system about which values could in principle be collected.
   *
   * @author David J. Pearce
   *
   */
  public static class Void extends AbstractNaryAssignable<Type> {

    private Void(Type type, int[] operands) {
      super(type, Codes.NULL_REG, operands);
    }

    @Override
    public int opcode() {
      return OPCODE_void;
    }

    protected Code.Unit clone(int nTarget, int[] nOperands) {
      return Void(type(), nOperands);
    }

    public Type assignedType() {
      return Type.T_VOID;
    }

    public boolean equals(Object o) {
      if (o instanceof Void) {
        return super.equals(o);
      }
      return false;
    }

    public String toString() {
      return "void " + arrayToString(operands());
    }
  }

  // =============================================================
  // Helpers
  // =============================================================
  private static int[] append(int[] operands, int operand) {
    int[] noperands = Arrays.copyOf(operands, operands.length+1);
    noperands[operands.length] = operand;
    return noperands;
  }

  private static int[] append(int operand, int[] operands) {
    int[] noperands = new int[operands.length+1];
    System.arraycopy(operands,0,noperands,1,operands.length);
    noperands[0] = operand;
    return noperands;
  }

  private static final ArrayList<Code> values = new ArrayList<Code>();
  private static final HashMap<Code, Integer> cache = new HashMap<Code, Integer>();

  private static <T extends Code> T get(T type) {
    Integer idx = cache.get(type);
    if (idx != null) {
      return (T) values.get(idx);
    } else {
      cache.put(type, values.size());
      values.add(type);
      return type;
    }
  }
}
TOP

Related Classes of wyil.lang.Codes$UnaryOperator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.