All Downloads are FREE. Search and download functionalities are using the official Maven repository.

wyil.lang.WyilFile Maven / Gradle / Ivy

// Copyright 2011 The Whiley Project Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package wyil.lang;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

import wycc.util.ArrayUtils;
import wycc.util.Trie;
import wycc.util.AbstractCompilationUnit.Identifier;
import wycc.lang.Syntactic;
import wycc.lang.Syntactic.Schema;
import wycc.util.AbstractItem;
import wycc.util.SectionedSchema;
import wycc.util.AbstractCompilationUnit;
import wycc.util.SectionedSchema.Section;
import wyc.lang.WhileyFile;
import wyc.util.ErrorMessages;
import wyil.util.AbstractConsumer;

/**
 * 

* Provides the in-memory representation of a Whiley source file (a.k.a. an * "Abstract Syntax Tree"). This is implemented as a "heap" of syntactic items. * For example, consider the following simple Whiley source file: *

* *
 * function id(int x) -> (int y):
 *     return x
 * 
* *

* This is represented internally using a heap of syntactic items which might * look something like this: *

* *
 * [00] DECL_function(#0,#2,#6,#8)
 * [01] ITEM_utf8("id")
 * [02] ITEM_tuple(#3)
 * [03] DECL_variable(#4,#5)
 * [04] ITEM_utf8("x")
 * [05] TYPE_int
 * [06] ITEM_tuple(#7)
 * [07] DECL_variable(#8,#9)
 * [08] ITEM_utf8("y")
 * [09] TYPE_int
 * [10] STMT_block(#11)
 * [11] STMT_return(#12)
 * [12] EXPR_variable(#03)
 * 
* *

* Each of these syntactic items will additionally be associated with one or * more attributes (e.g. encoding line number information, etc). *

* * @author David J. Pearce * */ public class WyilFile extends AbstractCompilationUnit { // ========================================================================= // Schema // ========================================================================= public static final int ITEM_null = 0; // public static final int ITEM_bool = 1; // public static final int ITEM_int = 2; // public static final int ITEM_utf8 = 3; // public static final int ITEM_pair = 4; // public static final int ITEM_tuple = 5; // public static final int ITEM_array = 6; // public static final int ITEM_ident = 7; // public static final int ITEM_name = 8; // public static final int ITEM_decimal = 9; // public static final int ITEM_ref = 10; // public static final int ITEM_dictionary = 11; // public static final int ATTR_span = 14; // public static final int ITEM_byte = 15; // public static final int DECL_unknown = 16; // public static final int DECL_module = 17; // public static final int DECL_unit = 18; // public static final int DECL_import = 19; // public static final int DECL_importfrom = 20; // public static final int DECL_importwith = 21; // public static final int DECL_staticvar = 22; // public static final int DECL_type = 23; // public static final int DECL_rectype = 24; // public static final int DECL_function = 25; // public static final int DECL_method = 26; // public static final int DECL_property = 27; // public static final int DECL_lambda = 28; // public static final int DECL_variable = 29; // public static final int DECL_link = 30; // public static final int DECL_binding = 31; // public static final int DECL_variant = 32; // public static final int MOD_native = 48; // public static final int MOD_export = 49; // public static final int MOD_final = 50; // public static final int MOD_private = 52; // public static final int MOD_public = 53; // public static final int MOD_unsafe = 54; // public static final int TEMPLATE_type = 56; // public static final int ATTR_error = 65; // public static final int ATTR_stackframe = 68; // public static final int ATTR_counterexample = 69; // public static final int TYPE_unknown = 80; // public static final int TYPE_void = 81; // public static final int TYPE_any = 82; // public static final int TYPE_null = 83; // public static final int TYPE_bool = 84; // public static final int TYPE_int = 85; // public static final int TYPE_nominal = 86; // public static final int TYPE_reference = 87; // public static final int TYPE_array = 88; // public static final int TYPE_tuple = 89; // public static final int TYPE_record = 90; // public static final int TYPE_field = 91; // public static final int TYPE_function = 92; // public static final int TYPE_method = 93; // public static final int TYPE_property = 94; // public static final int TYPE_union = 95; // public static final int TYPE_byte = 96; // public static final int TYPE_recursive = 105; // public static final int TYPE_universal = 106; // public static final int TYPE_existential = 107; // public static final int STMT_block = 144; // public static final int STMT_namedblock = 145; // public static final int STMT_caseblock = 146; // public static final int STMT_assert = 147; // public static final int STMT_assign = 148; // public static final int STMT_assume = 149; // public static final int STMT_debug = 150; // public static final int STMT_skip = 151; // public static final int STMT_break = 152; // public static final int STMT_continue = 153; // public static final int STMT_dowhile = 154; // public static final int STMT_fail = 155; // public static final int STMT_for = 156; // public static final int STMT_if = 158; // public static final int STMT_ifelse = 159; // public static final int STMT_initialiser = 160; // public static final int STMT_initialiservoid = 161; // public static final int STMT_return = 162; // public static final int STMT_returnvoid = 163; // public static final int STMT_switch = 164; // public static final int STMT_while = 165; // public static final int EXPR_variablecopy = 176; // public static final int EXPR_variablemove = 177; // public static final int EXPR_staticvariable = 179; // public static final int EXPR_constant = 180; // public static final int EXPR_cast = 181; // public static final int EXPR_invoke = 182; // public static final int EXPR_indirectinvoke = 183; // public static final int EXPR_logicalnot = 184; // public static final int EXPR_logicaland = 185; // public static final int EXPR_logicalor = 186; // public static final int EXPR_logicalimplication = 187; // public static final int EXPR_logicaliff = 188; // public static final int EXPR_logicalexistential = 189; // public static final int EXPR_logicaluniversal = 190; // public static final int EXPR_equal = 191; // public static final int EXPR_notequal = 192; // public static final int EXPR_integerlessthan = 193; // public static final int EXPR_integerlessequal = 194; // public static final int EXPR_integergreaterthan = 195; // public static final int EXPR_integergreaterequal = 196; // public static final int EXPR_is = 197; // public static final int EXPR_old = 198; // public static final int EXPR_integernegation = 199; // public static final int EXPR_integeraddition = 200; // public static final int EXPR_integersubtraction = 201; // public static final int EXPR_integermultiplication = 202; // public static final int EXPR_integerdivision = 203; // public static final int EXPR_integerremainder = 204; // public static final int EXPR_integerexponent = 205; // public static final int EXPR_bitwisenot = 207; // public static final int EXPR_bitwiseand = 208; // public static final int EXPR_bitwiseor = 209; // public static final int EXPR_bitwisexor = 210; // public static final int EXPR_bitwiseshl = 211; // public static final int EXPR_bitwiseshr = 212; // public static final int EXPR_dereference = 215; // public static final int EXPR_new = 216; // public static final int EXPR_lambdaaccess = 217; // public static final int EXPR_fielddereference = 218; // public static final int EXPR_recordaccess = 222; // public static final int EXPR_recordborrow = 223; // public static final int EXPR_recordupdate = 224; // public static final int EXPR_recordinitialiser = 225; // public static final int EXPR_tupleinitialiser = 226; // public static final int EXPR_arrayaccess = 230; // public static final int EXPR_arrayborrow = 231; // public static final int EXPR_arrayupdate = 232; // public static final int EXPR_arraylength = 233; // public static final int EXPR_arraygenerator = 234; // public static final int EXPR_arrayinitialiser = 235; // public static final int EXPR_arrayrange = 236; // /** * Cached copy of the current schema */ private static Schema SCHEMA; public static Schema getSchema() { // FIXME: doing something? if(SCHEMA == null) { // Generate the latest schema SCHEMA = createSchema(); } return SCHEMA; } // ========================================================================= // Constructors // ========================================================================= private final List sourceFiles; private final int majorVersion; private final int minorVersion; public WyilFile(List sourceFiles) { super(); Schema schema = WyilFile.getSchema(); this.sourceFiles = new ArrayList<>(sourceFiles); this.majorVersion = schema.getMajorVersion(); this.minorVersion = schema.getMinorVersion(); } /** * Copy constructor which creates an identical WyilFile. * * @param wf */ public WyilFile(WyilFile wf) { this.majorVersion = wf.majorVersion; this.minorVersion = wf.minorVersion; // Create initial copies for (int i = 0; i != wf.size(); ++i) { Syntactic.Item item = wf.getSyntacticItem(i); // Construct unlinked item item = SCHEMA.getDescriptor(item.getOpcode()).construct(item.getOpcode(), new Syntactic.Item[item.size()], item.getData()); syntacticItems.add(item); item.allocate(this, i); } // Link operands up for (int i = 0; i != wf.size(); ++i) { Syntactic.Item item = wf.getSyntacticItem(i); Syntactic.Item nItem = syntacticItems.get(i); for(int j=0;j!=item.size();++j) { int operand = item.get(j).getIndex(); nItem.setOperand(j, syntacticItems.get(operand)); } } // Set the distinguished root item setRootItem(getSyntacticItem(root)); // this.sourceFiles = new ArrayList<>(wf.sourceFiles); } public WyilFile(int root, Syntactic.Item[] items, int major, int minor) { this.majorVersion = major; this.minorVersion = minor; // Allocate every item into this heap for (int i = 0; i != items.length; ++i) { syntacticItems.add(items[i]); items[i].allocate(this, i); } // Set the distinguished root item setRootItem(getSyntacticItem(root)); this.sourceFiles = new ArrayList<>(); } // ========================================================================= // Accessors // ========================================================================= // public List getSourceArtifacts() { // return sourceFiles; // } public boolean isValid() { return findAll(Syntactic.Marker.class).size() == 0; } public int getMajorVersion() { return majorVersion; } public int getMinorVersion() { return minorVersion; } public Decl.Module getModule() { return (Decl.Module) getRootItem(); } public Decl.Unit getUnit() { // The first node is always the declaration root. List modules = getSyntacticItems(Decl.Unit.class); if (modules.size() != 1) { throw new RuntimeException("expecting one module, found " + modules.size()); } return modules.get(0); } public S getDeclaration(Identifier name, Type signature, Class kind) { List matches = super.getSyntacticItems(kind); for (int i = 0; i != matches.size(); ++i) { S match = matches.get(i); if (match.getName().equals(name)) { if (signature != null && signature.equals(match.getType())) { return match; } else if (signature == null) { return match; } } } throw new IllegalArgumentException("unknown declarataion (" + name + "," + signature + ")"); } @Override public void replace(T from, T to) { BitSet matches = findReachable(from, new BitSet()); Decl.Module module = getModule(); // Carefully remove all markers for items within that being replaced. Tuple markers = module.getAttributes(); ArrayList items = new ArrayList<>(); // for(int i=0;i!=markers.size();++i) { Syntactic.Item marker = markers.get(i); for(int j=0;j!=marker.size();++j) { if(matches.get(marker.get(j).getIndex())) { // Found a match items.add(marker); break; } } } // Remove all existing markers module.setAttributes(markers.removeAll(items)); // Done super.replace(from, to); } /** * A qualified name represents a fully-qualified name within a * compilation unit. That is, a full-qualified unit identifier and corresponding * name. * * @author David J. Pearce * */ public static class QualifiedName { private final Name unit; private final Identifier name; public QualifiedName(Tuple path, Identifier name) { this(path.toArray(Identifier.class), name); } public QualifiedName(Identifier[] path, Identifier name) { this(new Name(path), name); } public QualifiedName(Name unit, Identifier name) { this.unit = unit; this.name = name; } @Override public boolean equals(Object o) { if (o instanceof QualifiedName) { QualifiedName n = (QualifiedName) o; return unit.equals(n.unit) && name.equals(n.name); } return false; } @Override public int hashCode() { return unit.hashCode() ^ name.hashCode(); } public Name getUnit() { return unit; } public Identifier getName() { return name; } /** * Provide a simple conversion from a qualified name to a generic name * * @return */ public Name toName() { return new Name(ArrayUtils.append(unit.getAll(), name)); } @Override public String toString() { return unit + "::" + name; } public static QualifiedName fromString(String arg) { String[] split = arg.split("::"); int n = split.length - 1; Trie path = Trie.fromStrings(Arrays.copyOf(split, n)); Identifier method = new Identifier(split[n]); return new QualifiedName(new Name(path), method); } } // ============================================================ // Declarations // ============================================================ /** *

* Represents a declaration within a Whiley source file. This includes import * declarations, function or method declarations, type * declarations, variable declarations and more. *

*

* In general, a declaration is often a top-level entity within a module. * However, this is not always the case. For example, variable declarations are * used to represent local variables, function or method parameters, etc. *

* * @author David J. Pearce * */ public static interface Decl extends Syntactic.Item { public static class Unknown extends AbstractItem implements Decl { public Unknown() { super(DECL_unknown); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Unknown(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "DECL_unknown") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Unknown(); } }; } /** * A WyilFile contains exactly one active module which represents the root of * all items in the module. * * @author David J. Pearce * */ public static class Module extends AbstractItem { public Module(Name name, Tuple modules, Tuple externs, Tuple attributes) { super(DECL_module, name, modules, externs, attributes); } public Name getName() { return (Name) get(0); } public Tuple getUnits() { return (Tuple) get(1); } public Tuple getExterns() { return (Tuple) get(2); } public Tuple getAttributes() { return (Tuple) get(3); } public Decl.Unit putUnit(Decl.Unit unit) { Tuple units = getUnits(); // Check whether replacing unit or adding new for (int i = 0; i != units.size(); ++i) { Decl.Unit ith = units.get(i); if (ith.getName().equals(unit.getName())) { // We're replacing an existing unit units.setOperand(i, unit); // return ith; } } // We're adding a new unit setOperand(1, getHeap().allocate(units.append(unit))); // Nothing was replaced return null; } public Decl.Unit putExtern(Decl.Unit unit) { Tuple externs = getExterns(); // Check whether replacing unit or adding new for (int i = 0; i != externs.size(); ++i) { Decl.Unit ith = externs.get(i); if (ith.getName().equals(unit.getName())) { // We're replacing an existing unit externs.setOperand(i, unit); return ith; } } // We're adding a new unit setOperand(2, getHeap().allocate(externs.append(unit))); // Nothing was replaced return null; } public void addAttribute(Syntactic.Marker attribute) { setOperand(3, getHeap().allocate(getAttributes().append(attribute))); } public void setAttributes(Tuple attributes) { setOperand(3, getHeap().allocate(attributes)); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Module((Name) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Tuple) operands[3]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "DECL_module") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Module((Name) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Tuple) operands[3]); } }; } /** * Represents the top-level entity in a Whiley source file. All other * declartions are contained within this. * * @author David J. Pearce * */ public static class Unit extends AbstractItem implements Decl { public Unit(Name name, Tuple declarations) { super(DECL_unit, name, declarations); } public Name getName() { return (Name) get(0); } @SuppressWarnings("unchecked") public Tuple getDeclarations() { return (Tuple) get(1); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Unit((Name) operands[0], (Tuple) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "DECL_unit") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Unit((Name) operands[0], (Tuple) operands[1]); } }; } /** *

* Represents an import declaration in a Whiley source file. For example, the * following illustrates a simple import statement: *

* *
		 * import println from std::io
		 * 
* *

* Here, the module is std::io and the symbol imported is * println. *

* * @author David J. Pearce * */ public static class Import extends AbstractItem implements Decl { public Import(Tuple path) { super(DECL_import, path); } public Import(Tuple path, boolean inclusive, Tuple names) { super(inclusive ? DECL_importwith : DECL_importfrom, path, names); } /** * Get the filter path associated with this import declaration. This is * std::math in import max from std::math. * * @return */ @SuppressWarnings("unchecked") public Tuple getPath() { return (Tuple) super.get(0); } /** * Check whether from name is associated with this import declaration. This * would max in import max from std::math, but is not * present in import std::math. * * @return */ public boolean hasFrom() { return opcode == DECL_importfrom; } /** * Check whether from name is associated with this import declaration. This * would max in import max from std::math, but is not * present in import std::math. * * @return */ public boolean hasWith() { return opcode == DECL_importwith; } /** * Get the with name(s) associated with this import declaration. This is * max in import std::math with max. * * @return */ public Tuple getNames() { return (Tuple) super.get(1); } @SuppressWarnings("unchecked") @Override public Import clone(Syntactic.Item[] operands) { switch(opcode) { case DECL_import: return new Import((Tuple) operands[0]); case DECL_importfrom: return new Import((Tuple) operands[0], false, (Tuple) operands[1]); default: case DECL_importwith: return new Import((Tuple) operands[0], true, (Tuple) operands[1]); } } @Override public String toString() { String r = "import "; if (hasFrom()) { r += WyilFile.toString(getNames()); r += " from "; } Tuple path = getPath(); for (int i = 0; i != path.size(); ++i) { if (i != 0) { r += "."; } Identifier component = path.get(i); if (component == null) { r += "*"; } else { r += component.get(); } } if (hasWith()) { r += " with "; r += WyilFile.toString(getNames()); } return r; } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.ONE, Data.ZERO, "DECL_import") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Import((Tuple) operands[0]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.TWO, Data.ZERO, "DECL_importfrom") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Import((Tuple) operands[0], false, (Tuple) operands[1]); } }; public static final Descriptor DESCRIPTOR_0c = new Descriptor(Operands.TWO, Data.ZERO, "DECL_importwith") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Import((Tuple) operands[0], true, (Tuple) operands[1]); } }; } /** * A named declaration has an additional symbol name associated with it * * @author David J. Pearce * */ public static abstract class Named extends AbstractItem implements Decl { public Named(int opcode, Tuple modifiers, Identifier name, Syntactic.Item... rest) { super(opcode, ArrayUtils.append(new Syntactic.Item[] { modifiers, name }, rest)); } @SuppressWarnings("unchecked") public Tuple getModifiers() { return (Tuple) super.get(0); } public Identifier getName() { return (Identifier) super.get(1); } public QualifiedName getQualifiedName() { // FIXME: this is completely broken. Unit module = getAncestor(Decl.Unit.class); return new QualifiedName(module.getName(), getName()); } public Tuple getTemplate() { throw new UnsupportedOperationException(); } public abstract T getType(); } /** * Represents a function, method or property declaration in * a Whiley source file. */ public static abstract class Callable extends Named { public Callable(int opcode, Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Syntactic.Item... rest) { super(opcode, modifiers, name, ArrayUtils.append(new Syntactic.Item[] { template, parameters, returns }, rest)); } @Override @SuppressWarnings("unchecked") public Tuple getTemplate() { return (Tuple) get(2); } @SuppressWarnings("unchecked") public Tuple getParameters() { return (Tuple) get(3); } @SuppressWarnings("unchecked") public Tuple getReturns() { return (Tuple) get(4); } public static WyilFile.Type project(Tuple decls) { switch(decls.size()) { case 0: return WyilFile.Type.Void; case 1: return decls.get(0).getType(); default: WyilFile.Type[] types = new WyilFile.Type[decls.size()]; for(int i=0;i!=types.length;++i) { types[i] = decls.get(i).getType(); } return new WyilFile.Type.Tuple(types); } } /** * Get the body associated with this callable declaration which is either a * statement block (for functions and methods) or an expression (for properties * and lambdas). * * @return */ public abstract Stmt getBody(); @Override public abstract WyilFile.Type.Callable getType(); } /** *

* Represents a function, method or property declaration in * a Whiley source file. The following function declaration provides a small * example to illustrate: *

* *
		 * function max(int[] xs) -> (int z)
		 * // array xs cannot be empty
		 * requires |xs| > 0
		 * // return must be greater than all elements in xs
		 * ensures all { i in 0..|xs| | xs[i] <= z }
		 * // return must equal one of the elements in xs
		 * ensures some { i in 0..|xs| | xs[i] == z }
		 *     ...
		 * 
* *

* Here, we see the specification for the well-known max() function * which returns the largest value of an array. This employs both * requires and ensures clauses: *

    *
  • Requires clause. This defines a constraint on the permissible * values of the parameters on entry to the function or method, and is often * referred to as the "precondition". This expression may refer to any variables * declared within the parameter type pattern. Multiple clauses may be given, * and these are taken together as a conjunction. Furthermore, the convention is * to specify the requires clause(s) before any ensure(s) clauses.
  • *
  • Ensures clause. This defines a constraint on the permissible * values of the the function or method's return value, and is often referred to * as the "postcondition". This expression may refer to any variables declared * within either the parameter or return type pattern. Multiple clauses may be * given, and these are taken together as a conjunction. Furthermore, the * convention is to specify the requires clause(s) after the others.
  • *
*

* * @see Callable */ public static abstract class FunctionOrMethod extends Callable { public FunctionOrMethod(int opcode, Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Tuple requires, Tuple ensures, Stmt.Block body, Syntactic.Item... rest) { super(opcode, modifiers, name, template, parameters, returns, ArrayUtils.append(new Syntactic.Item[] { requires, ensures, body }, rest)); } @SuppressWarnings("unchecked") public Tuple getRequires() { return (Tuple) get(5); } @SuppressWarnings("unchecked") public Tuple getEnsures() { return (Tuple) get(6); } @Override public Stmt.Block getBody() { return (Stmt.Block) get(7); } } /** *

* Represents a function declaration in a Whiley source file. For example: *

* *
		 * function f(int x) -> (int y)
		 * // Parameter must be positive
		 * requires x > 0
		 * // Return must be negative
		 * ensures y < 0:
		 *    // body
		 *    return -x
		 * 
* *

* Here, a function f is defined which accepts only positive * integers and returns only negative integers. The variable y is * used to refer to the return value. Functions in Whiley may not have * side-effects (i.e. they are pure functions). *

* *

* Function declarations may also have modifiers, such as public * and private. *

* * @see FunctionOrMethod * * @author David J. Pearce * */ public static class Function extends FunctionOrMethod { public Function(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Tuple requires, Tuple ensures, Stmt.Block body) { super(DECL_function, modifiers, name, template, parameters, returns, requires, ensures, body); } @Override public WyilFile.Type.Function getType() { return new WyilFile.Type.Function(project(getParameters()),project(getReturns())); } @Override @SuppressWarnings("unchecked") public Function clone(Syntactic.Item[] operands) { return new Function((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Tuple) operands[6], (Stmt.Block) operands[7]); } @Override public String toString() { return "function " + getName() + " : " + getType(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.EIGHT, Data.ZERO, "DECL_function") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Function((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Tuple) operands[6], (Stmt.Block) operands[7]); } }; } /** *

* Represents a method declaration in a Whiley source file. For example: *

* *
		 * method m(int x) -> (int y)
		 * // Parameter must be positive
		 * requires x > 0
		 * // Return must be negative
		 * ensures $ < 0:
		 *    // body
		 *    return -x
		 * 
* *

* Here, a method m is defined which accepts only positive integers * and returns only negative integers. The variable y is used to * refer to the return value. Unlike functions, methods in Whiley may have * side-effects. *

* *

* Method declarations may also have modifiers, such as public and * private. *

* * @see FunctionOrMethod * * @author David J. Pearce * */ public static class Method extends FunctionOrMethod { public Method(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Tuple requires, Tuple ensures, Stmt.Block body) { super(DECL_method, modifiers, name, template, parameters, returns, requires, ensures, body); } @Override public WyilFile.Type.Method getType() { // FIXME: This just feels wrong as we are throwing away other template // variables. The issue is that callable types do not declare template variables // as they are compiled away. return new WyilFile.Type.Method(project(getParameters()), project(getReturns())); } @SuppressWarnings("unchecked") @Override public Method clone(Syntactic.Item[] operands) { return new Method((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Tuple) operands[6], (Stmt.Block) operands[7]); } @Override public String toString() { return "method " + getName() + " : " + getType(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.EIGHT, Data.ZERO, "DECL_method") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Method((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Tuple) operands[6], (Stmt.Block) operands[7]); } }; } /** *

* Represents a property declaration in a Whiley source file. For example: *

* *
		 * property contains(int[] xs, int x)
		 * where some { i in 0..|xs| | xs[i] == x}
		 * 
* *

* Here, a property contains is defined which captures the concept * of an element being contained in an array. *

* *

* Property declarations may also have modifiers, such as public * and private. *

* * @See FunctionOrMethod * * @author David J. Pearce * */ public static class Property extends Callable { public Property(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Tuple requires, Stmt.Block body) { super(DECL_property, modifiers, name, template, parameters, returns,requires, body); } @Override public WyilFile.Type.Property getType() { return new WyilFile.Type.Property(project(getParameters()), project(getReturns())); } @SuppressWarnings("unchecked") public Tuple getRequires() { return (Tuple) get(5); } @Override @SuppressWarnings("unchecked") public Stmt.Block getBody() { return (Stmt.Block) get(6); } @SuppressWarnings("unchecked") @Override public Property clone(Syntactic.Item[] operands) { return new Property((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Stmt.Block) operands[6]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.SIX, Data.ZERO, "DECL_property") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { Tuple es = (Tuple) operands[5]; Stmt.Block block = new Stmt.Block(new Stmt.Return(new Expr.LogicalAnd(es))); return new Property((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], new Tuple(), block); } }; public static final Descriptor DESCRIPTOR_1 = new Descriptor(Operands.SEVEN, Data.ZERO, "DECL_property") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Property((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5], (Stmt.Block) operands[5]); } }; } /** * A variant is a two state property. * * @author David J. Pearce * */ public static class Variant extends Callable { public Variant(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple invariant) { super(DECL_variant, modifiers, name, template, parameters, new Tuple(), invariant); } public Variant(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Tuple invariant) { super(DECL_variant, modifiers, name, template, parameters, returns, invariant); } @Override public WyilFile.Type.Property getType() { return new WyilFile.Type.Property(project(getParameters())); } @SuppressWarnings("unchecked") public Tuple getInvariant() { return (Tuple) get(5); } @Override public Stmt getBody() { // FIXME: this doesn't make sense for properties. Realistically, this should be // resolved when properties are changed from their current form into something // more useful. throw new UnsupportedOperationException(); } @SuppressWarnings("unchecked") @Override public Variant clone(Syntactic.Item[] operands) { return new Variant((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.SIX, Data.ZERO, "DECL_property") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Variant((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Tuple) operands[5]); } }; } /** *

* Represents a lambda declaration within a Whiley source file. Sometimes also * known as closures, these are anonymous function or method declarations * declared within an expression. The following illustrates: *

* *
		 * type func is function(int)->int
		*
		* function g() -> func:
		*    return &(int x -> x + 1)
		 * 
*

* This defines a lambda which accepts one parameter x and returns * its increment. *

* * @author David J. Pearce * */ public static class Lambda extends Callable implements Expr { public Lambda(Tuple modifiers, Identifier name, Tuple parameters, Expr body, WyilFile.Type.Callable signature) { this(modifiers, name, new Tuple<>(), parameters, new Tuple(), body, signature); } public Lambda(Tuple modifiers, Identifier name, Tuple template, Tuple parameters, Tuple returns, Expr body, WyilFile.Type.Callable signature) { super(DECL_lambda, modifiers, name, template, parameters, returns, body, signature); } public Set getCapturedVariables() { UsedVariableExtractor usedVariableExtractor = new UsedVariableExtractor(); HashSet captured = new HashSet<>(); usedVariableExtractor.visitExpression(getBody(), captured); Tuple parameters = getParameters(); for (int i = 0; i != parameters.size(); ++i) { captured.remove(parameters.get(i)); } return captured; } @Override public Expr getBody() { return (Expr) get(5); } @Override public WyilFile.Type.Callable getType() { return (WyilFile.Type.Callable) super.get(6); } @Override public void setType(WyilFile.Type type) { // FIXME: this is a hack which should be removed. type = type.as(WyilFile.Type.Callable.class); Syntactic.Heap heap = getHeap(); // if (type instanceof WyilFile.Type.Callable) { // Set the type operands[6] = heap.allocate(type); } else { throw new IllegalArgumentException(); } } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Lambda((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Expr) operands[5], (WyilFile.Type.Callable) operands[6]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.SEVEN, Data.ZERO, "DECL_lambda") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Lambda((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Tuple) operands[3], (Tuple) operands[4], (Expr) operands[5], (WyilFile.Type.Callable) operands[6]); } }; } /** *

* Represents a type declaration in a Whiley source file. A simple example to * illustrate is: *

* *
		 * type nat is (int x) where x >= 0
		 * 
* *

* This defines a constrained type called nat which * represents the set of natural numbers (i.e the non-negative integers). The * "where" clause is optional and is often referred to as the type's * "constraint". *

* *

* Type declarations may also have modifiers, such as public and * private. *

* * @author David J. Pearce * */ public static class Type extends Named { public Type(Tuple modifiers, Identifier name, Tuple template, Decl.Variable vardecl, Tuple invariant) { super(DECL_type, modifiers, name, template, vardecl, invariant); } @Override public Tuple getTemplate() { return (Tuple) get(2); } public Decl.Variable getVariableDeclaration() { return (Decl.Variable) get(3); } @SuppressWarnings("unchecked") public Tuple getInvariant() { return (Tuple) get(4); } @Override public WyilFile.Type getType() { return getVariableDeclaration().getType(); } @SuppressWarnings("unchecked") @Override public Decl.Type clone(Syntactic.Item[] operands) { return new Type((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Decl.Variable) operands[3], (Tuple) operands[4]); } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.FIVE, Data.ZERO, "DECL_type") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Type((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Decl.Variable) operands[3], (Tuple) operands[4]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.FIVE, Data.ZERO, "DECL_rectype") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { Decl.Type r = new Type((Tuple) operands[0], (Identifier) operands[1], (Tuple) operands[2], (Decl.Variable) operands[3], (Tuple) operands[4]); //r.setRecursive(); return r; } }; } // ============================================================ // Variable Declaration // ============================================================ /** *

* Represents a variable declaration which has an optional expression assignment * referred to as an initialiser. If an initialiser is given, then this * will be evaluated and assigned to the variable when the declaration is * executed. Some example declarations: *

* *
		 * int x
		 * int y = 1
		 * int z = x + y
		 * 
* * @author David J. Pearce * */ public static class Variable extends Named { public Variable(Tuple modifiers, Identifier name, WyilFile.Type type) { super(DECL_variable, modifiers, name, type); } protected Variable(int opcode, Tuple modifiers, Identifier name, WyilFile.Type type, WyilFile.Expr initialiser) { super(opcode, modifiers, name, type, initialiser); } @Override public WyilFile.Type getType() { return (WyilFile.Type) get(2); } @SuppressWarnings("unchecked") @Override public Decl.Variable clone(Syntactic.Item[] operands) { return new Variable((Tuple) operands[0], (Identifier) operands[1], (WyilFile.Type) operands[2]); } @Override public String toString() { return getType().toString() + " " + getName(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "DECL_variable") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Variable((Tuple) operands[0], (Identifier) operands[1], (WyilFile.Type) operands[2]); } }; } /** * Represents a constant declaration in a Whiley source file, which has the * form: * *
		 * ConstantDeclaration ::= "constant" Identifier "is" Expression
		 * 
* * A simple example to illustrate is: * *
		 * constant PI is 3.141592654
		 * 
* * Here, we are defining a constant called PI which represents the * decimal value "3.141592654". Constant declarations may also have modifiers, * such as public and private. * * @author David J. Pearce * */ public class StaticVariable extends Variable { public StaticVariable(Tuple modifiers, Identifier name, WyilFile.Type type, Expr initialiser) { super(DECL_staticvar, modifiers, name, type, initialiser); } @Override public WyilFile.Type getType() { return (WyilFile.Type) get(2); } public Expr getInitialiser() { return (Expr) get(3); } @SuppressWarnings("unchecked") @Override public StaticVariable clone(Syntactic.Item[] operands) { return new StaticVariable((Tuple) operands[0], (Identifier) operands[1], (WyilFile.Type) operands[2], (Expr) operands[3]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "DECL_staticvar") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new StaticVariable((Tuple) operands[0], (Identifier) operands[1], (WyilFile.Type) operands[2], (Expr) operands[3]); } }; } /** * Represents a link to a given syntactic item which is "resolvable". That is, * it is given as a name which is subsequently resolved during some compilation * stage. * * @author David J. Pearce * * @param */ public static class Link> extends AbstractItem { public Link(Name name) { super(DECL_link,name); } private Link(int opcode, Syntactic.Item... operands) { super(opcode, operands); } public boolean isResolved() { return operands.length == 2; } public boolean isPartiallyResolved() { return operands.length >= 2; } public Name getName() { return (Name) operands[0]; } public T getTarget() { if(isResolved()) { return ((Ref) operands[1]).get(); } else { throw new IllegalArgumentException("link unresolved"); } } public List getCandidates() { ArrayList candidates = new ArrayList<>(); for (int i = 1; i != operands.length; ++i) { Ref candidate = (Ref) operands[i]; candidates.add(candidate.get()); } return candidates; } public T lookup(WyilFile.Type type) { for (int i = 1; i != operands.length; ++i) { Ref candidate = (Ref) operands[i]; Decl.Named n = candidate.get(); if(n.getType().equals(type)) { return (T) n; } } throw new IllegalArgumentException("unable to find candidate declaration"); } @SuppressWarnings("unchecked") public void resolve(T... items) { Syntactic.Heap heap = getHeap(); Syntactic.Item first = operands[0]; this.operands = Arrays.copyOf(operands, items.length + 1); this.operands[0] = first; for(int i=1;i!=operands.length;++i) { operands[i] = heap.allocate(new Ref<>(items[i - 1])); } } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Link(DECL_link, operands); } @Override public String toString() { return ""; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.MANY, Data.ZERO, "DECL_link") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Link(DECL_link, operands); } }; } /** * Represents a binding between a Linkable item and the corresponding * declaration. * * @author David J. Pearce * * @param */ public static class Binding> extends AbstractItem { private S concreteType; public Binding(Link link, Tuple arguments) { super(DECL_binding, link, arguments); } @SuppressWarnings("unchecked") public Link getLink() { return (Link) get(0); } public S getConcreteType() { if(concreteType == null) { T decl = getLink().getTarget(); S type = decl.getType(); // // Substitute type parameters if(type instanceof WyilFile.Type.Callable) { concreteType = (S) WyilFile.substituteTypeCallable((WyilFile.Type.Callable) type, decl.getTemplate(), getArguments()); } else { concreteType = (S) type.substitute(bindingFunction(decl.getTemplate(), getArguments())); } } return concreteType; } public T getDeclaration() { return getLink().getTarget(); } /** * Get the provided template arguments. * * @return */ public Tuple getArguments() { return (Tuple) get(1); } public void setArguments(Tuple arguments) { operands[1] = getHeap().allocate(arguments); concreteType = null; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Binding((Link) operands[0], (Tuple) operands[1]); } @Override public String toString() { Identifier name = getDeclaration().getName(); String arguments = getArguments().toBareString(); return name + "<" + arguments + ">"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "DECL_binding") { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Binding((Decl.Link) operands[0], (Tuple) operands[1]); } }; } } // ============================================================ // Template // ============================================================ public interface Template { public enum Variance { UNKNOWN, INVARIANT, COVARIANT, CONTRAVARIANT } public static abstract class Variable extends AbstractItem { public Variable(int opcode, Identifier name, Variance variance) { super(opcode, new byte[] { (byte) variance.ordinal() }, name); } public Identifier getName() { return (Identifier) get(0); } public Variance getVariance() { return getVariance(data[0]); } public void setVariance(Variance v) { data[0] = (byte) v.ordinal(); } protected static Variance getVariance(byte b) { switch (b) { case 0: return Variance.UNKNOWN; case 1: return Variance.INVARIANT; case 2: return Variance.COVARIANT; case 3: return Variance.CONTRAVARIANT; default: throw new IllegalArgumentException("Invalid variance modifier"); } } } public static class Type extends Variable { public Type(Identifier name, Variance variance) { super(TEMPLATE_type, name, variance); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Type((Identifier) operands[0], getVariance()); } @Override public String toString() { return getName().get(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ONE, "TEMPLATE_type") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Template.Type((Identifier) operands[0], getVariance(data[0])); } }; } } // ============================================================ // Stmt // ============================================================ /** * Provides classes for representing statements in Whiley's source language. * Examples include assignments, for-loops, conditions, * etc. Each class is an instance of Syntactic.Item and, hence, can * be adorned with certain information (such as source location, etc). * * @author David J. Pearce * */ public interface Stmt extends Syntactic.Item { public interface Loop extends Stmt { //Expr getCondition(); Tuple getInvariant(); Tuple getModified(); Stmt getBody(); } /** *

* A statement block represents a sequence of zero or more consecutive * statements at the same indentation level. The following illustrates: *

* *
		 * function abs(int x) -> (int r):
		 * // ---------------------------+
		 *    if x > 0:               // |
		 *       // ----------------+    |
		 *       return x        // |    |
		 *       // ----------------+    |
		 *    else:                   // |
		 *       // ----------------+    |
		 *       return -x       // |    |
		 *       // ----------------+    |
		 * // ---------------------------+
		 * 
*

* This example contains three statement blocks. The outermost block defines the * body of the function and contains exactly one statement (i.e. the * if statement). Two inner blocks are used to represent the true * and false branches of the conditional. *

* * @author David J. Pearce * */ public static class Block extends AbstractItem implements Stmt { public Block(Stmt... stmts) { super(STMT_block, stmts); } @Override public Stmt get(int i) { return (Stmt) super.get(i); } @Override public Block clone(Syntactic.Item[] operands) { return new Block(ArrayUtils.toArray(Stmt.class, operands)); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.MANY, Data.ZERO, "STMT_block") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Block(ArrayUtils.toArray(Stmt.class, operands)); } }; } /** * Represents a named block, which has the form: * *
		 * NamedBlcok ::= LifetimeIdentifier ':' NewLine Block
		 * 
* * As an example: * *
		 * function sum():
		 *   &this:int x = new:this x
		 *   myblock:
		 *     &myblock:int y = new:myblock y
		 * 
*/ public static class NamedBlock extends AbstractItem implements Stmt { public NamedBlock(Identifier name, Stmt.Block block) { super(STMT_namedblock, name, block); } public Identifier getName() { return (Identifier) super.get(0); } public Block getBlock() { return (Block) super.get(1); } @Override public NamedBlock clone(Syntactic.Item[] operands) { return new NamedBlock((Identifier) operands[0], (Block) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "STMT_namedblock") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new NamedBlock((Identifier) operands[0], (Stmt.Block) operands[1]); } }; } /** *

* Represents a assert statement of the form "assert e", where * e is a boolean expression. The following illustrates: *

* *
		 * function abs(int x) -> int:
		 *     if x < 0:
		 *         x = -x
		 *     assert x >= 0
		 *     return x
		 * 
* *

* Assertions are either statically checked by the verifier, or turned into * runtime checks. *

* * @author David J. Pearce * */ public static class Assert extends AbstractItem implements Stmt { public Assert(Expr condition) { super(STMT_assert, condition); } public Expr getCondition() { return (Expr) super.get(0); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Assert((Expr) operands[0]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "STMT_assert") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Assert((Expr) operands[0]); } }; } /** *

* Represents an assignment statement of the form "lhs = rhs". * Here, the rhs is any expression, whilst the lhs * must be an LVal --- that is, an expression permitted on the * left-side of an assignment. The following illustrates different possible * assignment statements: *

* *
		 * x = y       // variable assignment
		 * x.f = y     // field assignment
		 * x[i] = y    // list assignment
		 * x[i].f = y  // compound assignment
		 * 
* *

* The last assignment here illustrates that the left-hand side of an assignment * can be arbitrarily complex, involving nested assignments into lists and * records. *

* * @author David J. Pearce * */ public static class Assign extends AbstractItem implements Stmt { public Assign(Tuple lvals, Tuple rvals) { super(STMT_assign, lvals, rvals); } @SuppressWarnings("unchecked") public Tuple getLeftHandSide() { return (Tuple) super.get(0); } @SuppressWarnings("unchecked") public Tuple getRightHandSide() { return (Tuple) super.get(1); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Assign((Tuple) operands[0], (Tuple) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "STMT_assign") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Assign((Tuple) operands[0], (Tuple) operands[1]); } }; } /** *

* Represents an assume statement of the form "assume e", where * e is a boolean expression. The following illustrates: *

* *
		 * function abs(int x) -> int:
		 *     if x < 0:
		 *         x = -x
		 *     assume x >= 0
		 *     return x
		 * 
* *

* Assumptions are assumed by the verifier and, since this may be unsound, * always turned into runtime checks. *

* * @author David J. Pearce * */ public static class Assume extends AbstractItem implements Stmt { public Assume(Expr condition) { super(STMT_assume, condition); } public Expr getCondition() { return (Expr) super.get(0); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Assume((Expr) operands[0]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "STMT_assume") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Assume((Expr) operands[0]); } }; } /** * Represents a debug statement of the form "debug e" where * e is a string expression. Debug statements are effectively print * statements in debug mode, and no-operations otherwise. * * @author David J. Pearce * */ public static class Debug extends AbstractItem implements Stmt { public Debug(Expr condition) { super(STMT_debug, condition); } public Expr getOperand() { return (Expr) super.get(0); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Debug((Expr) operands[0]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "STMT_debug") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Debug((Expr) operands[0]); } }; } /** * Represents a classical skip statement of the form "skip". A skip * statement is simply a no-operation. * * @author David J. Pearce * */ public static class Skip extends AbstractItem implements Stmt { public Skip() { super(STMT_skip); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Skip(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "STMT_skip") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Skip(); } }; } /** * Represents a classical break statement of the form "break" which * can be used to force the termination of a loop or switch statement. * * @author David J. Pearce * */ public static class Break extends AbstractItem implements Stmt { public Break() { super(STMT_break); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Break(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "STMT_break") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Break(); } }; } /** * Represents a classical continue statement of the form "continue" * which can be used to proceed to the next iteration of a loop or the next case * of a switch statement. * * @author David J. Pearce * */ public static class Continue extends AbstractItem implements Stmt { public Continue() { super(STMT_continue); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Continue(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "STMT_continue") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Continue(); } }; } /** *

* Represents a do-while statement whose body is made up from a block of * statements separated by indentation. As an example: *

* *
		 * function sum([int] xs) -> int
		 * requires |xs| > 0:
		 *   int r = 0
		 *   int i = 0
		 *   do:
		 *     r = r + xs[i]
		 *     i = i + 1
		 *   while i < |xs| where i >= 0
		 *   return r
		 * 
* *

* The where clause is optional, and commonly referred to as the * loop invariant. When multiple clauses are given, these are combined * using a conjunction. The combined invariant defines a condition which must be * true on every iteration of the loop. *

* * @author David J. Pearce * */ public static class DoWhile extends AbstractItem implements Loop { public DoWhile(Expr condition, Tuple invariant, Tuple modified, Stmt.Block body) { super(STMT_dowhile, condition, invariant, modified, body); } public Expr getCondition() { return (Expr) super.get(0); } @Override @SuppressWarnings("unchecked") public Tuple getInvariant() { return (Tuple) super.get(1); } @Override @SuppressWarnings("unchecked") public Tuple getModified() { return (Tuple) super.get(2); } public void setModified(Tuple modified) { operands[2] = modified; } @Override public Stmt.Block getBody() { return (Stmt.Block) super.get(3); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new DoWhile((Expr) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[3]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "STMT_dowhile") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new DoWhile((Expr) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[3]); } }; } /** * Represents a fail statement for the form "fail". This causes an * abrupt termination of the program and should represent dead-code if present. */ public static class Fail extends AbstractItem implements Stmt { public Fail() { super(STMT_fail); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Fail(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "STMT_fail") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Fail(); } }; } /** *

* Represents a for statement made up of variable initialisers and a block of statements * referred to as the body. The following illustrates: *

* *
		 * function sum(int[] xs) -> int:
		 *   int r = 0
		 *   for i in 0..|xs|:
		 *     r = r + xs[i]
		 *   return r
		 * 
* * @author David J. Pearce * */ public static class For extends AbstractItem implements Loop { public For(Decl.StaticVariable var, Tuple invariant, Tuple modified, Stmt.Block trueBranch) { super(STMT_for, var, invariant, modified, trueBranch); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new For((Decl.StaticVariable) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[2]); } public Decl.StaticVariable getVariable() { return (Decl.StaticVariable) operands[0]; } @Override public Tuple getInvariant() { return (Tuple) operands[1]; } @Override public Tuple getModified() { return (Tuple)operands[2]; } public void setModified(Tuple modified) { operands[2] = modified; } @Override public Stmt.Block getBody() { return (Stmt.Block) operands[3]; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "STMT_for") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new For((Decl.StaticVariable) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[2]); } }; } /** *

* Represents a classical if-else statement consisting of a condition, a * true branch and an optional false branch. The following * illustrates: *

* *
		 * function max(int x, int y) -> int:
		 *   if(x > y):
		 *     return x
		 *   else if(x == y):
		 *   	return 0
		 *   else:
		 *     return y
		 * 
* * @author David J. Pearce * */ public static class IfElse extends AbstractItem implements Stmt { public IfElse(Expr condition, Stmt.Block trueBranch) { super(STMT_if, condition, trueBranch); } public IfElse(Expr condition, Stmt.Block trueBranch, Stmt.Block falseBranch) { super(STMT_ifelse, condition, trueBranch, falseBranch); } public boolean hasFalseBranch() { return getOpcode() == STMT_ifelse; } public Expr getCondition() { return (Expr) super.get(0); } public Stmt.Block getTrueBranch() { return (Stmt.Block) super.get(1); } public Stmt.Block getFalseBranch() { return (Stmt.Block) super.get(2); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { if (operands.length == 2) { return new IfElse((Expr) operands[0], (Stmt.Block) operands[1]); } else { return new IfElse((Expr) operands[0], (Stmt.Block) operands[1], (Stmt.Block) operands[2]); } } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.TWO, Data.ZERO, "STMT_if") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IfElse((Expr) operands[0], (Stmt.Block) operands[1]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.THREE, Data.ZERO, "STMT_ifelse") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IfElse((Expr) operands[0], (Stmt.Block) operands[1], (Stmt.Block) operands[2]); } }; } /** *

* Represents a variable initialiser statement which declares one or more * variables with an optional initialiser. The following illustrates: *

*
		 * int x, int y = swap(1,2)
		 * 
* * @author David J. Pearce * */ public static class Initialiser extends AbstractItem implements Stmt { public Initialiser(Tuple variables) { super(STMT_initialiservoid, variables); } public Initialiser(Tuple variables, Expr initialiser) { super(STMT_initialiser, variables, initialiser); } public boolean hasInitialiser() { return opcode == STMT_initialiser; } public Tuple getVariables() { return (Tuple) get(0); } public Expr getInitialiser() { return (Expr) get(1); } public Type getType() { return Type.Tuple.create(getVariables().map(v -> v.getType())); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { if(hasInitialiser()) { return new Initialiser((Tuple) operands[0], (Expr) operands[1]); } else { return new Initialiser((Tuple) operands[0]); } } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.TWO, Data.ZERO, "STMT_initialiser") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Initialiser((Tuple) operands[0], (Expr) operands[1]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.ONE, Data.ZERO, "STMT_initialiservoid") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Initialiser((Tuple) operands[0]); } }; } /** *

* Represents a return statement which has one or more optional return * expressions referred to simply as the "returns". Note that, the returned * expression (if there is one) must begin on the same line as the return * statement itself. The following illustrates: *

* *
		 * function f(int x) -> int:
		 * 	  return x + 1
		 * 
* *

* Here, we see a simple return statement which returns an * int value. *

* * @author David J. Pearce * */ public static class Return extends AbstractItem implements Stmt { public Return() { super(STMT_returnvoid); } public Return(Expr operand) { super(STMT_return, operand); } public boolean hasReturn() { return opcode == STMT_return; } @SuppressWarnings("unchecked") public Expr getReturn() { return (Expr) super.get(0); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { if(hasReturn()) { return new Return((Expr) operands[0]); } else { return new Return(); } } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.ONE, Data.ZERO, "STMT_return") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Return((Expr) operands[0]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.ZERO, Data.ZERO, "STMT_returnvoid") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Return(); } }; } /** *

* Represents a classical switch statement made of up a condition and one or * more case blocks. Each case consists of zero or more constant expressions. * The following illustrates: *

* *
		 * switch x:
		 *   case 1:
		 *     y = -1
		 *   case 2:
		 *     y = -2
		 *   default:
		 *     y = 0
		 * 
* * @author David J. Pearce * */ public static class Switch extends AbstractItem implements Stmt { public Switch(Expr condition, Tuple cases) { super(STMT_switch, condition, cases); } public Expr getCondition() { return (Expr) get(0); } @SuppressWarnings("unchecked") public Tuple getCases() { return (Tuple) get(1); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Switch((Expr) operands[0], (Tuple) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "STMT_switch") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Switch((Expr) operands[0], (Tuple) operands[1]); } }; } public static class Case extends AbstractItem { public Case(Tuple conditions, Stmt.Block block) { super(STMT_caseblock, conditions, block); } public boolean isDefault() { return getConditions().size() == 0; } @SuppressWarnings("unchecked") public Tuple getConditions() { return (Tuple) get(0); } public Stmt.Block getBlock() { return (Stmt.Block) get(1); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Case((Tuple) operands[0], (Stmt.Block) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "STMT_caseblock") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Case((Tuple) operands[0], (Stmt.Block) operands[1]); } }; } /** *

* Represents a while statement made up a condition and a block of statements * referred to as the body. The following illustrates: *

* *
		 * function sum([int] xs) -> int:
		 *   int r = 0
		 *   int i = 0
		 *   while i < |xs| where i >= 0:
		 *     r = r + xs[i]
		 *     i = i + 1
		 *   return r
		 * 
* *

* The optional where clause(s) are commonly referred to as the * "loop invariant". When multiple clauses are given, these are combined using a * conjunction. The combined invariant defines a condition which must be true on * every iteration of the loop. *

* * @author David J. Pearce * */ public static class While extends AbstractItem implements Loop { public While(Expr condition, Tuple invariant, Tuple modified, Stmt.Block body) { super(STMT_while, condition, invariant, modified, body); } public Expr getCondition() { return (Expr) super.get(0); } @Override @SuppressWarnings("unchecked") public Tuple getInvariant() { return (Tuple) super.get(1); } @Override @SuppressWarnings("unchecked") public Tuple getModified() { return (Tuple) super.get(2); } public void setModified(Tuple modified) { operands[2] = modified; } @Override public Stmt.Block getBody() { return (Stmt.Block) super.get(3); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new While((Expr) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[3]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "STMT_while") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new While((Expr) operands[0], (Tuple) operands[1], (Tuple) operands[2], (Stmt.Block) operands[3]); } }; } } /** *

* Represents an arbitrary expression permissible on the left-hand side of an * assignment statement. For example, consider the following method: *

* *
	 * method f(int[] xs, int x, int y):
	 *   x = y + 1
	 *   xs[i] = x
	 * 
*

* This contains two assignment statements with the lval's x and * xs[i] respectively. The set of lvals is a subset of the set of * all expressions, since not every expression can be assigned. For example, an * assignment "f() = x" does not make sense. *

* * @author David J. Pearce * */ public interface LVal extends Expr { } /** * Represents an arbitrary expression within a Whiley source file. Every * expression has a known type and zero or more expression operands alongside * other syntactic information. * * @author David J. Pearce * */ public interface Expr extends Stmt { /** * Get the type to which this expression is guaranteed to evaluate. That is, the * result type of this expression. * * @return */ public Type getType(); /** * Set the inferred return type for this expression. Observe that some * expressions do not support this operation. * * @param type */ public void setType(Type type); // ========================================================================= // General Expressions // ========================================================================= /** * Represents an abstract operator expression over exactly one operand * expression. For example, !x is a unary operator expression. * * @author David J. Pearce * */ public interface UnaryOperator extends Expr { public Expr getOperand(); } /** * Represents an abstract operator expression over exactly two operand * expressions. For example, x << 1 is a binary operator * expression. * * @author David J. Pearce * */ public interface BinaryOperator extends Expr { public Expr getFirstOperand(); public Expr getSecondOperand(); } /** * Represents an abstract operator expression over exactly three operand * expressions. For example, xs[i:=1] is a ternary operator * expression. * * @author David J. Pearce * */ public interface TernaryOperator extends Expr { public Expr getFirstOperand(); public Expr getSecondOperand(); public Expr getThirdOperand(); } /** * Represents an abstract operator expression over one or more operand * expressions. For example. in arr[i+1] the expression * i+1 would be an nary operator expression. * * @author David J. Pearce * */ public interface NaryOperator extends Expr { public Tuple getOperands(); } public abstract static class AbstractExpr extends AbstractItem implements Expr { public AbstractExpr(int opcode, Type type, Syntactic.Item... items) { super(opcode, ArrayUtils.append(type, items)); } @Override public Type getType() { return (Type) super.get(0); } @Override public void setType(Type type) { operands[0] = type; } } /** * Represents a cast expression of the form "(T) e" where * T is the cast type and e the casted * expression. * * @author David J. Pearce * */ public static class Cast extends AbstractExpr implements Expr, UnaryOperator { public Cast(Type type, Expr rhs) { super(EXPR_cast, type, rhs); } @Override public Expr getOperand() { return (Expr) super.get(1); } @Override public Cast clone(Syntactic.Item[] operands) { return new Cast((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "(" + getType() + ") " + getOperand(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_cast") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Cast((Type) operands[0], (Expr) operands[1]); } }; } /** * Represents the use of a constant within some expression. For example, in * x + 1 the expression 1 is a constant expression. * * @author David J. Pearce * */ public static class Constant extends AbstractExpr implements Expr { public Constant(Type type, Value value) { super(EXPR_constant, type, value); } public Value getValue() { return (Value) get(1); } @Override public Constant clone(Syntactic.Item[] operands) { return new Constant((Type) operands[0], (Value) operands[1]); } @Override public String toString() { return getValue().toString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_constant") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Constant((Type) operands[0], (Value) operands[1]); } }; } /** * Represents the use of a static variable within an expression. A static * variable is effectively a global variable which may or may not be defined * within the enclosing module. * * @author David J. Pearce * */ public static class StaticVariableAccess extends AbstractExpr implements LVal, Expr, Linkable { public StaticVariableAccess(Type type, Decl.Link name) { super(EXPR_staticvariable, type, name); } @Override public Decl.Link getLink() { return (Decl.Link) get(1); } @Override public StaticVariableAccess clone(Syntactic.Item[] operands) { return new StaticVariableAccess((Type) operands[0], (Decl.Link) operands[1]); } @Override public String toString() { return getLink().toString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_staticvariable") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new StaticVariableAccess((Type) operands[0], (Decl.Link) operands[1]); } }; } /** * Represents a type test expression of the form "e is T" * where e is the test expression and T is the * test type. * * @author David J. Pearce * */ public static class Is extends AbstractItem implements Expr, UnaryOperator { public Is(Expr lhs, Type rhs) { super(EXPR_is, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getOperand() { return (Expr) get(0); } public Type getTestType() { return (Type) get(1); } @Override public Is clone(Syntactic.Item[] operands) { return new Is((Expr) operands[0], (Type) operands[1]); } @Override public String toString() { return getOperand() + " is " + getTestType(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_is") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Is((Expr) operands[0], (Type) operands[1]); } }; } /** * Represents an invocation of the form "x.y.f(e1,..en)". Here, * x.y.f constitute a partially- or fully-qualified * name and e1 ... en are the argument * expressions. * * @author David J. Pearce * */ public static class Invoke extends AbstractItem implements Expr, NaryOperator, Bindable { public Invoke(Decl.Binding binding, Tuple arguments) { super(EXPR_invoke, binding, arguments); } @Override public Type getType() { return getBinding().getConcreteType().getReturn(); } @Override public void setType(Type type) { throw new UnsupportedOperationException(); } @Override public Decl.Link getLink() { return getBinding().getLink(); } @Override public Decl.Binding getBinding() { return (Decl.Binding) get(0); } @Override @SuppressWarnings("unchecked") public Tuple getOperands() { return (Tuple) get(1); } @SuppressWarnings("unchecked") @Override public Invoke clone(Syntactic.Item[] operands) { return new Invoke((Decl.Binding) operands[0], (Tuple) operands[1]); } @Override public String toString() { return getBinding().toString() + getOperands(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_invoke") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Invoke((Decl.Binding) operands[0], (Tuple) operands[1]); } }; } /** * Represents an indirect invocation of the form "x.y(e1,..en)". * Here, x.y returns a function value and e1 ... * en are the argument expressions. * * @author David J. Pearce * */ public static class IndirectInvoke extends AbstractItem implements Expr { public IndirectInvoke(Type type, Expr source, Tuple arguments) { super(EXPR_indirectinvoke, type, source, arguments); } @Override public Type getType() { return (Type) operands[0]; } @Override public void setType(Type type) { operands[0] = type; } public Expr getSource() { return (Expr) get(1); } @SuppressWarnings("unchecked") public Tuple getArguments() { return (Tuple) get(2); } @SuppressWarnings("unchecked") @Override public IndirectInvoke clone(Syntactic.Item[] operands) { return new IndirectInvoke((Type) operands[0], (Expr) operands[1], (Tuple) operands[2]); } @Override public String toString() { String r = getSource().toString(); r += getArguments(); return r; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_indirectinvoke") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IndirectInvoke((Type) operands[0], (Expr) operands[1], (Tuple) operands[2]); } }; } /** * Represents an old expression of the form "old(e)". This * can only appear in specification elements (i.e. it is a ghost expression), * and signals that the given expression should be evaluated in the heap as it * was on entry to the function or method. * * @author David J. Pearce * */ public static class Old extends AbstractExpr implements Expr, UnaryOperator { public Old(Type type, Expr expr) { super(EXPR_old, type, expr); } @Override public Type getType() { return (Type) operands[0]; } @Override public void setType(Type type) { operands[0] = type; } @Override public Expr getOperand() { return (Expr) get(1); } @Override public Old clone(Syntactic.Item[] operands) { return new Old((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "old(" + getOperand() + ")"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_old") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Old((Type) operands[0], (Expr) operands[1]); } }; } /** * Represents an abstract quantified expression of the form * "forall(T v1, ... T vn).e" or * "exists(T v1, ... T vn).e" where T1 v1 ... * Tn vn are the quantified variable declarations and * e is the body. * * @author David J. Pearce * */ public abstract static class Quantifier extends AbstractItem implements Expr, UnaryOperator { public Quantifier(int opcode, Decl.StaticVariable[] parameters, Expr body) { super(opcode, new Tuple<>(parameters), body); } public Quantifier(int opcode, Tuple parameters, Expr body) { super(opcode, parameters, body); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @SuppressWarnings("unchecked") public Tuple getParameters() { return (Tuple) get(0); } @Override public Expr getOperand() { return (Expr) get(1); } @Override public abstract Expr clone(Syntactic.Item[] operands); } /** * Represents an unbounded universally quantified expression of the form * "forall(T v1, ... T vn).e" where T1 v1 ... * Tn vn are the quantified variable declarations and * e is the body. * * @author David J. Pearce * */ public static class UniversalQuantifier extends Quantifier { public UniversalQuantifier(Decl.StaticVariable[] parameters, Expr body) { super(EXPR_logicaluniversal, new Tuple<>(parameters), body); } public UniversalQuantifier(Tuple parameters, Expr body) { super(EXPR_logicaluniversal, parameters, body); } @SuppressWarnings("unchecked") @Override public Expr clone(Syntactic.Item[] operands) { return new UniversalQuantifier((Tuple) operands[0], (Expr) operands[1]); } @Override public String toString() { String r = "forall"; r += getParameters(); r += "."; r += getOperand(); return r; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_logicaluniversal") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new UniversalQuantifier((Tuple) operands[0], (Expr) operands[1]); } }; } /** * Represents an unbounded existentially quantified expression of the form * "some(T v1, ... T vn).e" where T1 v1 ... * Tn vn are the quantified variable declarations and * e is the body. * * @author David J. Pearce * */ public static class ExistentialQuantifier extends Quantifier { public ExistentialQuantifier(Decl.StaticVariable[] parameters, Expr body) { super(EXPR_logicalexistential, new Tuple<>(parameters), body); } public ExistentialQuantifier(Tuple parameters, Expr body) { super(EXPR_logicalexistential, parameters, body); } @SuppressWarnings("unchecked") @Override public Expr clone(Syntactic.Item[] operands) { return new ExistentialQuantifier((Tuple) operands[0], (Expr) operands[1]); } @Override public String toString() { String r = "exists"; r += getParameters(); r += "."; r += getOperand(); return r; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_logicalexistential") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ExistentialQuantifier((Tuple) operands[0], (Expr) operands[1]); } }; } /** * Represents the use of some variable within an expression. For example, in * x + 1 the expression x is a variable access * expression. Every variable access is associated with a variable * declaration that unique identifies which variable is being accessed. * * @author David J. Pearce * */ public static class VariableAccess extends AbstractExpr implements LVal { public VariableAccess(Type type, Decl.Variable decl) { super(EXPR_variablecopy, type, decl); } public Decl.Variable getVariableDeclaration() { return (Decl.Variable) get(1); } /** * Mark this variable access as a move or borrow */ public void setMove() { this.opcode = EXPR_variablemove; } public boolean isMove() { return this.opcode == EXPR_variablemove; } @Override public VariableAccess clone(Syntactic.Item[] operands) { return new VariableAccess((Type) operands[0], (Decl.Variable) operands[1]); } @Override public String toString() { return getVariableDeclaration().getName().toString(); } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_variablecopy") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new VariableAccess((Type) operands[0], (Decl.Variable) operands[1]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_variablemove") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { Expr.VariableAccess v = new VariableAccess((Type) operands[0], (Decl.Variable) operands[1]); v.setMove(); return v; } }; } // ========================================================================= // Logical Expressions // ========================================================================= /** * Represents a logical conjunction of the form * "e1 && .. && en" where e1 ... en are * the operand expressions. * * @author David J. Pearce * */ public static class LogicalAnd extends AbstractItem implements NaryOperator { public LogicalAnd(Tuple operands) { super(EXPR_logicaland, operands); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Tuple getOperands() { return (Tuple) super.get(0); } @Override public Expr clone(Syntactic.Item[] operands) { return new LogicalAnd((Tuple) operands[0]); } @Override public String toString() { return " && "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "EXPR_logicaland") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LogicalAnd((Tuple) operands[0]); } }; } /** * Represents a logical disjunction of the form * "e1 || .. || en" where e1 ... en are * the operand expressions. * * @author David J. Pearce * */ public static class LogicalOr extends AbstractItem implements NaryOperator { public LogicalOr(Tuple operands) { super(EXPR_logicalor, operands); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Tuple getOperands() { return (Tuple) super.get(0); } @Override public Expr clone(Syntactic.Item[] operands) { return new LogicalOr((Tuple) operands[0]); } @Override public String toString() { return " || "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "EXPR_logicalor") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LogicalOr((Tuple) operands[0]); } }; } /** * Represents a logical implication of the form "e1 ==> e2" * where e1 and e2 are the operand expressions. * * @author David J. Pearce * */ public static class LogicalImplication extends AbstractItem implements BinaryOperator { public LogicalImplication(Expr lhs, Expr rhs) { super(EXPR_logicalimplication, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new LogicalImplication((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " ==> "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_logicalimplication") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LogicalImplication((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a logical biconditional of the form * "e1 <==> e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class LogicalIff extends AbstractItem implements BinaryOperator { public LogicalIff(Expr lhs, Expr rhs) { super(EXPR_logicaliff, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new LogicalIff((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " <==> "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_logicaliff") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LogicalIff((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a logical negation of the form "!e" where * e is the operand expression. * * @author David J. Pearce * */ public static class LogicalNot extends AbstractItem implements UnaryOperator { public LogicalNot(Expr operand) { super(EXPR_logicalnot, operand); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getOperand() { return (Expr) get(0); } @Override public Expr clone(Syntactic.Item[] operands) { return new LogicalNot((Expr) operands[0]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "EXPR_logicalnot") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LogicalNot((Expr) operands[0]); } }; } // ========================================================================= // Comparator Expressions // ========================================================================= /** * Represents an equality expression of the form "e1 == e2" where * e1 and e2 are the operand expressions. * * @author David J. Pearce * */ public static class Equal extends AbstractItem implements BinaryOperator { public Equal(Expr lhs, Expr rhs) { super(EXPR_equal, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new Equal((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " == "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_equal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Equal((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents an unequality expression of the form "e1 != e2" where * e1 and e2 are the operand expressions. * * @author David J. Pearce * */ public static class NotEqual extends AbstractItem implements BinaryOperator { public NotEqual(Expr lhs, Expr rhs) { super(EXPR_notequal, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new NotEqual((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " != "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_notequal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new NotEqual((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a strict inequality expression of the form * "e1 < e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerLessThan extends AbstractItem implements BinaryOperator { public IntegerLessThan(Expr lhs, Expr rhs) { super(EXPR_integerlessthan, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerLessThan((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " < "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_integerlessthan") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerLessThan((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a non-strict inequality expression of the form * "e1 <= e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerLessThanOrEqual extends AbstractItem implements BinaryOperator { public IntegerLessThanOrEqual(Expr lhs, Expr rhs) { super(EXPR_integerlessequal, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerLessThanOrEqual((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " <= "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_integerlessequal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerLessThanOrEqual((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a strict inequality expression of the form * "e1 > e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerGreaterThan extends AbstractItem implements BinaryOperator { public IntegerGreaterThan(Expr lhs, Expr rhs) { super(EXPR_integergreaterthan, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerGreaterThan((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " > "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_integergreaterthan") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerGreaterThan((Expr) operands[0], (Expr) operands[1]); } }; } /** * Represents a non-strict inequality expression of the form * "e1 >= e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerGreaterThanOrEqual extends AbstractItem implements BinaryOperator { public IntegerGreaterThanOrEqual(Expr lhs, Expr rhs) { super(EXPR_integergreaterequal, lhs, rhs); } @Override public Type getType() { return Type.Bool; } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Expr getFirstOperand() { return (Expr) super.get(0); } @Override public Expr getSecondOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerGreaterThanOrEqual((Expr) operands[0], (Expr) operands[1]); } @Override public String toString() { return " >= "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_integergreaterequal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerGreaterThanOrEqual((Expr) operands[0], (Expr) operands[1]); } }; } // ========================================================================= // Integer Expressions // ========================================================================= /** * Represents an integer addition expression of the form * "e1 + e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerAddition extends AbstractExpr implements BinaryOperator { public IntegerAddition(Type type, Expr lhs, Expr rhs) { super(EXPR_integeraddition, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerAddition((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " + "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integeraddition") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerAddition((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer subtraction expression of the form * "e1 - e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerSubtraction extends AbstractExpr implements BinaryOperator { public IntegerSubtraction(Type type, Expr lhs, Expr rhs) { super(EXPR_integersubtraction, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerSubtraction((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " - "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integersubtraction") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerSubtraction((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer multiplication expression of the form * "e1 * e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerMultiplication extends AbstractExpr implements BinaryOperator { public IntegerMultiplication(Type type, Expr lhs, Expr rhs) { super(EXPR_integermultiplication, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerMultiplication((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " * "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integermultiplication") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerMultiplication((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer division expression of the form * "e1 / e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerDivision extends AbstractExpr implements BinaryOperator { public IntegerDivision(Type type, Expr lhs, Expr rhs) { super(EXPR_integerdivision, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerDivision((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " / "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integerdivision") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerDivision((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer remainder expression of the form * "e1 % e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerRemainder extends AbstractExpr implements BinaryOperator { public IntegerRemainder(Type type, Expr lhs, Expr rhs) { super(EXPR_integerremainder, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerRemainder((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " % "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integerremainder") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerRemainder((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer exponent expression of the form * "e1 ** e2" where e1 and e2 are the * operand expressions. * * @author David J. Pearce * */ public static class IntegerExponent extends AbstractExpr implements BinaryOperator { public IntegerExponent(Type type, Expr lhs, Expr rhs) { super(EXPR_integerexponent, type, lhs, rhs); } @Override public Expr getFirstOperand() { return (Expr) super.get(1); } @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerExponent((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " ** "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_integermultiplication") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerExponent((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an integer negation expression of the form * "-e" where e is the operand expression. * * @author David J. Pearce * */ public static class IntegerNegation extends AbstractExpr implements UnaryOperator { public IntegerNegation(Type type, Expr operand) { super(EXPR_integernegation, type, operand); } @Override public Expr getOperand() { return (Expr) get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new IntegerNegation((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "-" + getOperand(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_integernegation") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new IntegerNegation((Type) operands[0], (Expr) operands[1]); } }; } // ========================================================================= // Bitwise Expressions // ========================================================================= /** * Represents a bitwise shift left of the form "e << i" * where e is the expression being shifted and i the * amount it is shifted by. * * @author David J. Pearce * */ public static class BitwiseShiftLeft extends AbstractExpr implements BinaryOperator { public BitwiseShiftLeft(Type type, Expr lhs, Expr rhs) { super(EXPR_bitwiseshl, type, lhs, rhs); } /** * Get the value operand to be shifted. That is x in * x << i. */ @Override public Expr getFirstOperand() { return (Expr) super.get(1); } /** * Get the operand indicating the amount to shift. That is i in * x << i. */ @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseShiftLeft((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " << "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_bitwiseshl") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseShiftLeft((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents a bitwise shift right of the form "e >> i" * where e is the expression being shifted and i the * amount it is shifted by. * * @author David J. Pearce * */ public static class BitwiseShiftRight extends AbstractExpr implements BinaryOperator { public BitwiseShiftRight(Type type, Expr lhs, Expr rhs) { super(EXPR_bitwiseshr, type, lhs, rhs); } /** * Get the value operand to be shifted. That is x in * x >> i. */ @Override public Expr getFirstOperand() { return (Expr) super.get(1); } /** * Get the operand indicating the amount to shift. That is i in * x >> i. */ @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseShiftRight((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return " >> "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_bitwiseshr") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseShiftRight((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents a bitwise and of the form "e1 & .. & en" where * e1 ... en are the operand expressions. * * @author David J. Pearce * */ public static class BitwiseAnd extends AbstractExpr implements NaryOperator { public BitwiseAnd(Type type, Tuple operands) { super(EXPR_bitwiseand, type, operands); } @Override public Tuple getOperands() { return (Tuple) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseAnd((Type) operands[0], (Tuple) operands[1]); } @Override public String toString() { return " & "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_bitwiseand") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseAnd((Type) operands[0], (Tuple) operands[1]); } }; } /** * Represents a bitwise or of the form "e1 | .. | en" where * e1 ... en are the operand expressions. * * @author David J. Pearce * */ public static class BitwiseOr extends AbstractExpr implements NaryOperator { public BitwiseOr(Type type, Tuple operands) { super(EXPR_bitwiseor, type, operands); } @Override public Tuple getOperands() { return (Tuple) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseOr((Type) operands[0], (Tuple) operands[1]); } @Override public String toString() { return " | "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_bitwiseor") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseOr((Type) operands[0], (Tuple) operands[1]); } }; } /** * Represents a bitwise xor of the form "e1 ^ .. ^ en" where * e1 ... en are the operand expressions. * * @author David J. Pearce * */ public static class BitwiseXor extends AbstractExpr implements NaryOperator { public BitwiseXor(Type type, Tuple operands) { super(EXPR_bitwisexor, type, operands); } @Override public Tuple getOperands() { return (Tuple) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseXor((Type) operands[0], (Tuple) operands[1]); } @Override public String toString() { return " ^ "; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_bitwisexor") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseXor((Type) operands[0], (Tuple) operands[1]); } }; } /** * Represents a bitwise complement of the form "~e" where * e is the operand expression. * * @author David J. Pearce * */ public static class BitwiseComplement extends AbstractExpr implements UnaryOperator { public BitwiseComplement(Type type, Expr operand) { super(EXPR_bitwisenot, type, operand); } /** * Get the operand to be complimented. That is, * e in !e. */ @Override public Expr getOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new BitwiseComplement((Type) operands[0], (Expr) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_bitwisenot") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new BitwiseComplement((Type) operands[0], (Expr) operands[1]); } }; } // ========================================================================= // Reference Expressions // ========================================================================= /** * Represents an object dereference expression of the form "*e" * where e is the operand expression. * * @author David J. Pearce * */ public static class Dereference extends AbstractExpr implements LVal, UnaryOperator { public Dereference(Type type, Expr operand) { super(EXPR_dereference, type, operand); } /** * Get the operand to be dereferenced. That is, * e in *e. */ @Override public Expr getOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new Dereference((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "*" + getOperand(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_dereference") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Dereference((Type) operands[0], (Expr) operands[1]); } }; } /** * Represents an object dereference expression of the form "e->f" * where e is the operand expression and f the * target field. * * @author David J. Pearce * */ public static class FieldDereference extends AbstractExpr implements LVal, UnaryOperator { public FieldDereference(Type type, Expr operand, Identifier field) { super(EXPR_fielddereference, type, operand, field); } /** * Get the operand to be dereferenced. That is, * e in *e. */ @Override public Expr getOperand() { return (Expr) super.get(1); } public Identifier getField() { return (Identifier) super.get(2); } @Override public Expr clone(Syntactic.Item[] operands) { return new FieldDereference((Type) operands[0], (Expr) operands[1], (Identifier) operands[2]); } @Override public String toString() { return getOperand() + "->" + getField(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_fielddereference") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new FieldDereference((Type) operands[0], (Expr) operands[1], (Identifier) operands[2]); } }; } /** * Represents an object allocation expression of the form * new e or new e where e is the * operand expression. * * @author David J. Pearce * */ public static class New extends AbstractExpr implements LVal, UnaryOperator { public New(Type type, Expr operand) { super(EXPR_new, type, operand); } /** * Get the operand to be evaluated and stored in the heap. That is, * e in new e. */ @Override public Expr getOperand() { return (Expr) super.get(1); } @Override public Expr clone(Syntactic.Item[] operands) { return new New((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "new " + getOperand(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_new") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new New((Type) operands[0], (Expr) operands[1]); } }; } public static class LambdaAccess extends AbstractItem implements Expr, Bindable { public LambdaAccess(Decl.Binding name, Type parameters) { super(EXPR_lambdaaccess, name, parameters); } @Override public Type getType() { return getLink().getTarget().getType(); } @Override public void setType(Type type) { if(!type.equals(Type.Bool)) { throw new IllegalArgumentException(); } } @Override public Decl.Link getLink() { return getBinding().getLink(); } @Override public Decl.Binding getBinding() { return (Decl.Binding) get(0); } @SuppressWarnings("unchecked") public Type getParameterTypes() { return (Type) get(1); } @SuppressWarnings("unchecked") @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new LambdaAccess((Decl.Binding) operands[0], (Type.Tuple) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_lambdaaccess") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new LambdaAccess((Decl.Binding) operands[0], (Type) operands[1]); } }; } // ========================================================================= // Array Expressions // ========================================================================= /** * Represents an array access expression of the form * "arr[e]" where arr is the source array and * e the subscript expression. This returns the value held * in the element determined by e. * * @author David J. Pearce * */ public static class ArrayAccess extends AbstractExpr implements LVal, BinaryOperator { public ArrayAccess(Type type, Expr src, Expr index) { super(EXPR_arrayaccess, type, src, index); } /** * Get the source array operand for this access. That is xs in * xs[i]. */ @Override public Expr getFirstOperand() { return (Expr) get(1); } /** * Get the index operand for this access. That is i in * xs[i]. */ @Override public Expr getSecondOperand() { return (Expr) get(2); } public void setMove() { this.opcode = EXPR_arrayborrow; } public boolean isMove() { return opcode == EXPR_arrayborrow; } @Override public ArrayAccess clone(Syntactic.Item[] operands) { return new ArrayAccess((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } @Override public String toString() { return getFirstOperand() + "[" + getSecondOperand() + "]"; } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_arrayaccess") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayAccess((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_arrayborrow") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { Expr.ArrayAccess r = new ArrayAccess((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); r.setMove(); return r; } }; } /** * Represents an array update expression of the form * "arr[e1:=e2]" where arr is the source array, * e1 the subscript expression and e2 is the * value expression. This returns a new array which is equivalent to * arr but where the element determined by e1 has the * value resulting from e2. * * @author David J. Pearce * */ public static class ArrayUpdate extends AbstractExpr implements Expr, TernaryOperator { public ArrayUpdate(Type type, Expr src, Expr index, Expr value) { super(EXPR_arrayupdate, type, src, index, value); } /** * Get the source array operand for this update. That is xs in * xs[i:=v]. */ @Override public Expr getFirstOperand() { return (Expr) get(1); } /** * Get the index operand for this update. That is i in * xs[i:=v]. */ @Override public Expr getSecondOperand() { return (Expr) get(2); } /** * Get the value operand of this update. That is v in * xs[i:=v]. */ @Override public Expr getThirdOperand() { return (Expr) get(3); } @Override public ArrayUpdate clone(Syntactic.Item[] operands) { return new ArrayUpdate((Type) operands[0], (Expr) operands[1], (Expr) operands[2], (Expr) operands[3]); } @Override public String toString() { return getFirstOperand() + "[" + getSecondOperand() + ":=" + getThirdOperand() + "]"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "EXPR_arrayupdate") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayUpdate((Type) operands[0], (Expr) operands[1], (Expr) operands[2], (Expr) operands[3]); } }; } /** * Represents an array initialiser expression of the form * "[e1,...,en]" where e1 ... en are the * initialiser expressions. Thus returns a new array made up from those * values resulting from the initialiser expressions. * * @author David J. Pearce * */ public static class ArrayInitialiser extends AbstractExpr implements NaryOperator { public ArrayInitialiser(Type type, Tuple elements) { super(EXPR_arrayinitialiser, type, elements); } @Override public Tuple getOperands() { return (Tuple) super.get(1); } @Override public ArrayInitialiser clone(Syntactic.Item[] operands) { return new ArrayInitialiser((Type) operands[0], (Tuple) operands[1]); } @Override public String toString() { return Arrays.toString(toArray(Syntactic.Item.class)); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_arrayinitialiser") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayInitialiser((Type) operands[0], (Tuple) operands[1]); } }; } /** * Represents an array generator expression of the form * "[e1;e2]" where e1 is the element expression * and e2 is the length expression. This returns a new array * whose length is determined by e2 and where every element has * contains the value determined by e1. * * @author David J. Pearce * */ public static class ArrayGenerator extends AbstractExpr implements BinaryOperator { public ArrayGenerator(Type type, Expr value, Expr length) { super(EXPR_arraygenerator, type, value, length); } /** * Get the value operand for this generator. That is e in * [e; n]. */ @Override public Expr getFirstOperand() { return (Expr) get(1); } /** * Get the length operand for this generator. That is n in * [e; n]. */ @Override public Expr getSecondOperand() { return (Expr) get(2); } @Override public ArrayGenerator clone(Syntactic.Item[] operands) { return new ArrayGenerator((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_arraygenerator") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayGenerator((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an array range expression of the form * "e1 .. e2" where e1 is the start of the range and * e2 the end. Thus returns a new array made up from those values * between start and end (but not including the end). * * @author David J. Pearce * */ public static class ArrayRange extends AbstractExpr implements BinaryOperator { public ArrayRange(Type type, Expr start, Expr end) { super(EXPR_arrayrange, type, start, end); } /** * Get the starting operand for this range. That is s in * s..e. This determines the first element of the resulting range. */ @Override public Expr getFirstOperand() { return (Expr) super.get(1); } /** * Get the ending operand for this range. That is e in * s..e. The range extends up to (but not including) this value. */ @Override public Expr getSecondOperand() { return (Expr) super.get(2); } @Override public ArrayRange clone(Syntactic.Item[] operands) { return new ArrayRange((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_arrayrange") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayRange((Type) operands[0], (Expr) operands[1], (Expr) operands[2]); } }; } /** * Represents an array length expression of the form "|arr|" * where arr is the source array. This simply returns the * length of array arr. e. * * @author David J. Pearce * */ public static class ArrayLength extends AbstractExpr implements Expr.UnaryOperator { public ArrayLength(Type type, Expr src) { super(EXPR_arraylength, type, src); } @Override public Expr getOperand() { return (Expr) super.get(1); } @Override public ArrayLength clone(Syntactic.Item[] operands) { return new ArrayLength((Type) operands[0], (Expr) operands[1]); } @Override public String toString() { return "|" + getOperand() + "|"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_arraylength") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new ArrayLength((Type) operands[0], (Expr) operands[1]); } }; } // ========================================================================= // Record Expressions // ========================================================================= /** * Represents a record access expression of the form "rec.f" * where rec is the source record and f is the * field. * * @author David J. Pearce * */ public static class RecordAccess extends AbstractExpr implements LVal, UnaryOperator { public RecordAccess(Type type, Expr lhs, Identifier rhs) { super(EXPR_recordaccess, type, lhs, rhs); } /** * Get the source operand for this access. That is e in * e.f/code>. */ @Override public Expr getOperand() { return (Expr) get(1); } /** * Get the field name for this access. That is f in * e.f/code>. */ public Identifier getField() { return (Identifier) get(2); } public void setMove() { this.opcode = EXPR_recordborrow; } public boolean isMove() { return opcode == EXPR_recordborrow; } @Override public RecordAccess clone(Syntactic.Item[] operands) { return new RecordAccess((Type) operands[0], (Expr) operands[1], (Identifier) operands[2]); } @Override public String toString() { return getOperand() + "." + getField(); } public static final Descriptor DESCRIPTOR_0a = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_recordaccess") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new RecordAccess((Type) operands[0], (Expr) operands[1], (Identifier) operands[2]); } }; public static final Descriptor DESCRIPTOR_0b = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_recordborrow") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { Expr.RecordAccess r = new RecordAccess((Type) operands[0], (Expr) operands[1], (Identifier) operands[2]); r.setMove(); return r; } }; } /** * Represents a tuple initialiser expression of the form * "(e1,..,en)". This returns a new tuple where each element holds * the value resulting from its corresponding expression. * * @author David J. Pearce * */ public static class TupleInitialiser extends AbstractExpr implements Expr, LVal, NaryOperator { public TupleInitialiser(Type type, Tuple operands) { super(EXPR_tupleinitialiser, type, operands); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new TupleInitialiser((Type) operands[0], (Tuple) operands[1]); } @Override public Tuple getOperands() { return (Tuple) operands[1]; } @Override public String toString() { String r = ""; // for (int i = 0; i != size(); ++i) { if (i != 0) { r += ","; } r += get(i).toString(); } // return "(" + r + ")"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "EXPR_tupleinitialiser") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new TupleInitialiser((Type) operands[0], (Tuple) operands[1]); } }; } /** * Represents a record initialiser expression of the form * "{ f1:e1, ..., fn:en }" where f1:e1 ... * fn:en are field initialisers. This returns a new record * where each field holds the value resulting from its corresponding expression. * * @author David J. Pearce * */ public static class RecordInitialiser extends AbstractExpr implements Expr, NaryOperator { public RecordInitialiser(Type type, Tuple fields, Tuple operands) { // FIXME: it would be nice for the constructor to require a record type; // however, the parser constructs multiple initialisers during parsing (even // when only one is present). This causes subsequent problems down the track. super(EXPR_recordinitialiser, type, fields, operands); } public Tuple getFields() { return (Tuple) super.get(1); } @Override public Tuple getOperands() { return (Tuple) super.get(2); } @SuppressWarnings("unchecked") @Override public RecordInitialiser clone(Syntactic.Item[] operands) { return new RecordInitialiser((Type) operands[0], (Tuple) operands[1], (Tuple) operands[2]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.THREE, Data.ZERO, "EXPR_recordinitialiser") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new RecordInitialiser((Type) operands[0], (Tuple) operands[1], (Tuple) operands[2]); } }; } /** * Represents a record update expression of the form * "e[f:=v]" where e is the source operand, * f is the field and v is the value * operand. This returns a new record which is equivalent to e * but where the element in field f has the value resulting from * v. * * @author David J. Pearce * */ public static class RecordUpdate extends AbstractExpr implements Expr, BinaryOperator { public RecordUpdate(Type type, Expr lhs, Identifier mhs, Expr rhs) { super(EXPR_recordupdate, type, lhs, mhs, rhs); } /** * Get the source operand for this update. That is e in * e[f:=v]/code>. */ @Override public Expr getFirstOperand() { return (Expr) get(1); } /** * Get the field name for this update. That is f in * e[f:=v]/code>. */ public Identifier getField() { return (Identifier) get(2); } /** * Get the value operand for this update. That is v in * e[f:=v]/code>. */ @Override public Expr getSecondOperand() { return (Expr) get(3); } @Override public RecordUpdate clone(Syntactic.Item[] operands) { return new RecordUpdate((Type) operands[0], (Expr) operands[1], (Identifier) operands[2], (Expr) operands[3]); } @Override public String toString() { return getFirstOperand() + "{" + getField() + ":=" + getSecondOperand() + "}"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.FOUR, Data.ZERO, "EXPR_recordupdate") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new RecordUpdate((Type) operands[0], (Expr) operands[1], (Identifier) operands[2], (Expr) operands[3]); } }; } } // ========================================================================= // Syntactic Type // ========================================================================= public static interface Type extends Syntactic.Item { public static final Any Any = new Any(); public static final Void Void = new Void(); public static final Bool Bool = new Bool(); public static final Byte Byte = new Byte(); public static final Int Int = new Int(); public static final Array VoidArray = new Array(Void); public static final Array IntArray = new Array(Int); public static final Array AnyArray = new Array(Any); public static final Null Null = new Null(); /** * Get the "shape" of this type. That is, the number of dimensions it has. * * @return */ public int shape(); /** * Get the nth dimension of this type. * * @param nth * @return */ public Type dimension(int nth); /** * Determine whether or not this type can be written. This is equivalent to * asking whether or not it has a known static size. * * @return */ public boolean isWriteable(); /** * Determine whether or not this type can be read. Types with an "unknown" * component cannot be read. * * @return */ public boolean isReadable(); /** * Substitute for type parameters * * @param binding A function which returns * @return */ public Type substitute(java.util.function.Function binding); /** * Expose the underlying type of this type. For example, consider this: * *
		 *  type
		 * Point is {int x, int y}
		 *
		 * function getX(Point p) -> (int r): return p.x
		 * 
* * At the point of the record access `p.x` we may want to know the underlying * record type for `p` (e.g. perhaps to calculate the offset of field `x`). * However, the `getType()` method only returns an instance of `Type` which, in * fact, is an instance of `Type.Nominal`. We need to further expand this to get * at the underlying record type. That is what this function does. * * @param kind * @return */ public T as(Class kind); /** * Filter a type according to a given kind whilst descending through unions. For * example, consider the following: * *
		 * {int f}|null xs = {f:0}
		 * 
* * In this case, at the point of the record initialiser, we need to extract the * target type {int f} from the type of xs. This is * what the filter method does. The following illustrates another example: * *
		 * {int f}|{bool f}|null xs = {f:0}
		 * 
* * In this case, the filter will return two instances of * Type.Record one for {int f} and one for * {bool f}. * * @param * @param kind * @param type * @return */ public List filter(Class kind); /** * Return a canonical string which embodies this type. * * @return */ public String toCanonicalString(); public interface Atom extends Type { } public interface Primitive extends Atom { } static abstract class AbstractType extends AbstractItem implements Type { AbstractType(int opcode) { super(opcode); } AbstractType(int opcode, Syntactic.Item operand) { super(opcode, operand); } AbstractType(int opcode, Syntactic.Item... operands) { super(opcode, operands); } AbstractType(int opcode, byte[] bytes) { super(opcode, bytes); } @Override public int shape() { return 1; } @Override public Type dimension(int nth) { if(nth != 0) { throw new IllegalArgumentException("invalid dimension"); } else { return this; } } @Override public boolean isWriteable() { return true; } @Override public boolean isReadable() { return true; } @Override public T as(Class kind) { if (kind.isInstance(this)) { return (T) this; } else { return null; } } @Override public List filter(Class kind) { if (kind.isInstance(this)) { ArrayList results = new ArrayList<>(); results.add((T) this); return results; } else { return Collections.EMPTY_LIST; } } } /** * Represents the set of all functions, methods and properties. These are values * which can be called using an indirect invoke expression. Each function or * method accepts zero or more parameters and will produce zero or more returns. * * @author David J. Pearce * */ public static interface Callable extends Atom { public Type getParameter(); public Type getReturn(); @Override public Type.Callable substitute(java.util.function.Function binding); } /** * A void type represents the type whose variables cannot exist! That is, they * cannot hold any possible value. Void is used to represent the return type of * a function which does not return anything. However, it is also used to * represent the element type of an empty list of set. NOTE: the void * type is a subtype of everything; that is, it is bottom in the type lattice. * * @author David J. Pearce * */ public static class Void extends AbstractType implements Primitive { public Void() { super(TYPE_void); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Void clone(Syntactic.Item[] operands) { return new Void(); } @Override public int shape() { return 0; } @Override public Type dimension(int nth) { throw new IllegalArgumentException(); } @Override public String toString() { return "void"; } @Override public String toCanonicalString() { return "void"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_void") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Void(); } }; } /** * An any type represents the type of all possible values. This type is not * currently permited in the syntax of Whiley, but is used internally within the * subtyping algorithm. NOTE: the any type is a supertype of everything; * that is, it is top in the type lattice. * * @author David J. Pearce * */ public static class Any extends AbstractType implements Primitive { public Any() { super(TYPE_any); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Any clone(Syntactic.Item[] operands) { return new Any(); } @Override public int shape() { return 1; } @Override public Type dimension(int nth) { return this; } @Override public String toString() { return "any"; } @Override public String toCanonicalString() { return "any"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_any") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Any(); } }; } /** * The null type is a special type which should be used to show the absence of * something. It is distinct from void, since variables can hold the special * null value (where as there is no special "void" value). With all * of the problems surrounding null and * NullPointerExceptions in languages like Java and C, it may seem * that this type should be avoided. However, it remains a very useful * abstraction to have around and, in Whiley, it is treated in a completely safe * manner (unlike e.g. Java). * * @author David J. Pearce * */ public static class Null extends AbstractType implements Primitive { public Null() { super(TYPE_null); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Null clone(Syntactic.Item[] operands) { return new Null(); } @Override public String toString() { return "null"; } @Override public String toCanonicalString() { return "null"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_null") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Null(); } }; } /** * Represents the set of boolean values (i.e. true and false) * * @author David J. Pearce * */ public static class Bool extends AbstractType implements Primitive { public Bool() { super(TYPE_bool); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Bool clone(Syntactic.Item[] operands) { return new Bool(); } @Override public String toString() { return "bool"; } @Override public String toCanonicalString() { return "bool"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_bool") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Bool(); } }; } /** * Represents a sequence of 8 bits. Note that, unlike many languages, there is * no representation associated with a byte. For example, to extract an integer * value from a byte, it must be explicitly decoded according to some * representation (e.g. two's compliment) using an auxillary function (e.g. * Byte.toInt()). * * @author David J. Pearce * */ public static class Byte extends AbstractType implements Primitive { public Byte() { super(TYPE_byte); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Byte clone(Syntactic.Item[] operands) { return new Byte(); } @Override public String toString() { return "byte"; } @Override public String toCanonicalString() { return "byte"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_byte") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Byte(); } }; } /** * Represents the set of (unbound) integer values. Since integer types in Whiley * are unbounded, there is no equivalent to Java's MIN_VALUE and * MAX_VALUE for int types. * * @author David J. Pearce * */ public static class Int extends AbstractType implements Primitive { public Int() { super(TYPE_int); } @Override public Type substitute(java.util.function.Function binding) { return this; } @Override public Int clone(Syntactic.Item[] operands) { return new Int(); } @Override public String toString() { return "int"; } @Override public String toCanonicalString() { return "int"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_int") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Int(); } }; } /** * Represents an array type, which is of the form: * *
		 * ArrayType ::= Type '[' ']'
		 * 
* * An array type describes array values whose elements are subtypes of the * element type. For example, [1,2,3] is an instance of array type * int[]; however, [false] is not. * * @return */ public static class Array extends AbstractType implements Atom { public Array(Type element) { super(TYPE_array, element); } public Type getElement() { return (Type) get(0); } @Override public boolean isWriteable() { return false; } @Override public Type.Array substitute(java.util.function.Function binding) { Type before = getElement(); Type after = before.substitute(binding); if (before == after) { return this; } else if (after == null) { return null; } else { return new Array(after); } } @Override public Type.Array clone(Syntactic.Item[] operands) { return new Array((Type) operands[0]); } @Override public String toString() { return getElement().toString() + "[]"; } @Override public String toCanonicalString() { return canonicalBraceAsNecessary(getElement()) + "[]"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "TYPE_array") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Array((Type) operands[0]); } }; } /** * Parse a reference type, which is of the form: * *
		 * ReferenceType ::= '&' Type
		 * 
* * Represents a reference to an object in Whiley. For example, * &this:int is the type of a reference to a location allocated in * the enclosing scope which holds an integer value. * * @return */ public static class Reference extends AbstractType implements Atom { public Reference(Type element) { super(TYPE_reference, element); } public Type getElement() { return (Type) get(0); } public Identifier getLifetime() { return (Identifier) get(1); } @Override public Type.Reference substitute(java.util.function.Function binding) { Type elementBefore = getElement(); Type elementAfter = elementBefore.substitute(binding); if(elementBefore != elementAfter) { if(elementAfter == null) { return null; } else { return new Reference(elementAfter); } } return this; } @Override public Type.Reference clone(Syntactic.Item[] operands) { return new Reference((Type) operands[0]); } @Override public String toString() { return "&" + braceAsNecessary(getElement()); } @Override public String toCanonicalString() { return "&" + canonicalBraceAsNecessary(getElement()); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "TYPE_reference") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Reference((Type) operands[0]); } }; } /** * Represents record type, which is of the form: * *
		 * RecordType ::= '{' Type Identifier (',' Type Identifier)* [ ',' "..." ] '}'
		 * 
* * A record is made up of a number of fields, each of which has a unique name. * Each field has a corresponding type. One can think of a record as a special * kind of "fixed" map (i.e. where we know exactly which entries we have). * * @return */ public static class Record extends AbstractType implements Atom { public Record(boolean isOpen, WyilFile.Tuple fields) { this(new Value.Bool(isOpen), fields); } public Record(boolean isOpen, WyilFile.Tuple fields, WyilFile.Tuple types) { this(new Value.Bool(isOpen), zip(fields,types)); } public Record(boolean isOpen, Identifier field, Type type) { this(new Value.Bool(isOpen), new WyilFile.Tuple<>(new Type.Field(field, type))); } public Record(Value.Bool isOpen, WyilFile.Tuple fields) { super(TYPE_record, isOpen, fields); } @Override public boolean isWriteable() { if(isOpen()) { return false; } else { WyilFile.Tuple fields = getFields(); for (int i = 0; i != fields.size(); ++i) { Field vd = fields.get(i); if(!vd.getType().isWriteable()) { return false; } } return true; } } @Override public boolean isReadable() { if(isOpen()) { return false; } else { WyilFile.Tuple fields = getFields(); for (int i = 0; i != fields.size(); ++i) { Field vd = fields.get(i); if(!vd.getType().isReadable()) { return false; } } return true; } } public boolean isOpen() { Value.Bool flag = (Value.Bool) get(0); return flag.get(); } public Type getField(Identifier fieldName) { WyilFile.Tuple fields = getFields(); for (int i = 0; i != fields.size(); ++i) { Field vd = fields.get(i); Identifier declaredFieldName = vd.getName(); if (declaredFieldName.equals(fieldName)) { return vd.getType(); } } return null; } @SuppressWarnings("unchecked") public WyilFile.Tuple getFields() { return (WyilFile.Tuple) get(1); } @Override public Type.Record substitute(java.util.function.Function binding) { WyilFile.Tuple before = getFields(); WyilFile.Tuple after = substitute(before, binding); if (before == after) { return this; } else if(after == null) { return null; } else { return new Record(isOpen(), after); } } @Override public Type.Record clone(Syntactic.Item[] operands) { return new Record((Value.Bool) operands[0], (WyilFile.Tuple) operands[1]); } /** * Substitute through fields whilst minimising memory allocations * * @param fields * @param binding * @return */ private static WyilFile.Tuple substitute(WyilFile.Tuple fields, java.util.function.Function binding) { // for (int i = 0; i != fields.size(); ++i) { Type.Field field = fields.get(i); Type before = field.getType(); Type after = before.substitute(binding); if(after == null) { return null; } else if (before != after) { // Now committed to a change Type.Field[] nFields = fields.toArray(Type.Field.class); nFields[i] = new Field(field.getName(), after); for (int j = i + 1; j < fields.size(); ++j) { field = fields.get(j); before = field.getType(); after = before.substitute(binding); if(after == null) { return null; } else if (before != after) { nFields[j] = new Field(field.getName(), after); } } return new WyilFile.Tuple<>(nFields); } } // return fields; } @Override public String toString() { WyilFile.Tuple fields = getFields(); String r = ""; // for (int i = 0; i != fields.size(); ++i) { Type.Field field = fields.get(i); if (i != 0) { r += ","; } r += field.toString(); } // if(isOpen()) { if(fields.size() > 0) { r += ", ..."; } else { r += "..."; } } // return "{" + r + "}"; } @Override public String toCanonicalString() { WyilFile.Tuple fields = getFields(); String r = ""; // for (int i = 0; i != fields.size(); ++i) { Type.Field field = fields.get(i); if (i != 0) { r += ","; } r += field.toCanonicalString(); } // if(isOpen()) { if(fields.size() > 0) { r += ", ..."; } else { r += "..."; } } // return "{" + r + "}"; } private static WyilFile.Tuple zip(WyilFile.Tuple fields, WyilFile.Tuple types) { Type.Field[] fs = new Type.Field[fields.size()]; for(int i=0;i!=fs.length;++i) { fs[i] = new Type.Field(fields.get(i),types.get(i)); } return new WyilFile.Tuple<>(fs); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_record") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Record((Value.Bool) operands[0], (WyilFile.Tuple) operands[1]); } }; } public static class Field extends AbstractItem { public Field(Identifier name, Type type) { super(TYPE_field, name, type); } public Identifier getName() { return (Identifier) get(0); } public Type getType() { return (Type) get(1); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Field((Identifier) operands[0], (Type) operands[1]); } @Override public String toString() { Type type = getType(); if(type != null) { return type.toString() + " " + getName(); } else { return "??? " + getName(); } } public String toCanonicalString() { return getType().toString() + " " + getName(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_field") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Field((Identifier) operands[0], (Type) operands[1]); } }; } /** * Represents tuple type, which is of the form: * *
		 * RecordType ::= '(' Type (',' Type )* ')'
		 * 
* * A tuple is simply a finite sequence of types. * * @return */ public static class Tuple extends AbstractType implements Atom { /** * Create a sequence of zero or more types. * * @param types * @return */ public static Type create(List types) { switch(types.size()) { case 0: return Type.Void; case 1: return types.get(0); default: return new Type.Tuple(types); } } /** * Create a sequence of zero or more types. * * @param types * @return */ public static Type create(Type... types) { switch(types.length) { case 0: return Type.Void; case 1: return types[0]; default: // Sanity check return new Type.Tuple(types); } } /** * Create a sequence of zero or more types. * * @param types * @return */ public static Type create(WyilFile.Tuple types) { switch(types.size()) { case 0: return Type.Void; case 1: return types.get(0); default: // Sanity check for(int i=0;i!=types.size();++i) { if(types.get(i) instanceof Type.Void) { return Type.Void; } } return new Type.Tuple(types.toArray(Type.class)); } } private Tuple(Type... types) { super(TYPE_tuple, types); if(types.length <= 1) { throw new IllegalArgumentException("invalid tuple created"); } } private Tuple(List types) { super(TYPE_tuple, types.toArray(new Type[types.size()])); if(types.size() <= 1) { throw new IllegalArgumentException("invalid tuple created"); } } @Override public int shape() { return size(); } @Override public Type dimension(int nth) { return get(nth); } @Override public boolean isWriteable() { for(int i=0;i!=size();++i) { if(!get(i).isWriteable()) { return false; } } return true; } @Override public boolean isReadable() { for(int i=0;i!=size();++i) { if(!get(i).isReadable()) { return false; } } return true; } @Override public Type get(int ith) { return (Type) super.get(ith); } @Override public Type[] getAll() { return (Type[]) super.getAll(); } @Override public Type.Tuple substitute(java.util.function.Function binding) { for(int i=0;i!=size();++i) { Type before = get(i); Type after = before.substitute(binding); if(after == null) { return null; } else if(before != after) { // Committed to change Type[] types = new Type[size()]; for(int j=0;j!=types.length;++j) { types[j] = get(j).substitute(binding); } return new Tuple(types); } } return this; } @Override public Type.Tuple clone(Syntactic.Item[] operands) { return new Tuple(ArrayUtils.toArray(Type.class, operands)); } @Override public String toString() { String r = ""; // for (int i = 0; i != size(); ++i) { if (i != 0) { r += ","; } r += get(i).toString(); } // return "(" + r + ")"; } @Override public String toCanonicalString() { String r = ""; // for (int i = 0; i != size(); ++i) { if (i != 0) { r += ","; } r += get(i).toCanonicalString(); } // return "(" + r + ")"; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.MANY, Data.ZERO, "TYPE_tuple") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Tuple(ArrayUtils.toArray(Type.class, operands)); } }; } /** * Represents a nominal type, which is of the form: * *
		 * NominalType ::= Identifier ('.' Identifier)*
		 * 
* * A nominal type specifies the name of a type defined elsewhere. In some cases, * this type can be expanded (or "inlined"). However, visibility modifiers can * prevent this and, thus, give rise to true nominal types. * * @return */ public static class Nominal extends AbstractItem implements Type, Linkable { public Nominal(Decl.Link name, WyilFile.Tuple parameters) { super(TYPE_nominal, name, parameters); if(parameters != null) { for(Type t : parameters) { if(t == null) { throw new IllegalArgumentException("invalid parameter types"); } } } } @Override public int shape() { // NOTE: Don't believe we need to use the concrete type here as shape is not // affected by substitution. return getLink().getTarget().getType().shape(); } @Override public Type dimension(int nth) { if(shape() == 1) { // In the special case we have unit shape, then return ourself. This gives // better error messages by retaining the nominal name. return this; } else { // NOTE: Don't believe we need to use the concrete type here as shape is not // affected by substitution. return getLink().getTarget().getType().dimension(nth); } } public boolean isAlias() { return getLink().getTarget().getInvariant().size() == 0; } @Override public boolean isWriteable() { return getConcreteType().isWriteable(); } @Override public boolean isReadable() { return getConcreteType().isReadable(); } @Override public Decl.Link getLink() { return (Decl.Link) get(0); } public WyilFile.Tuple getParameters() { return (WyilFile.Tuple) get(1); } @Override public T as(Class kind) { if(kind.isInstance(this)) { return (T) this; } else { return getConcreteType().as(kind); } } @Override public List filter(Class kind) { if(kind.isInstance(this)) { ArrayList result = new ArrayList<>(); result.add((T) this); return result; } else { return getConcreteType().filter(kind); } } public Type getConcreteType() { Decl.Type decl = getLink().getTarget(); WyilFile.Tuple template = decl.getTemplate(); WyilFile.Tuple arguments = getParameters(); Type type = decl.getType(); // if (template.size() > 0) { type = type.substitute(bindingFunction(template,arguments)); } // return type; } @Override public Type.Nominal substitute(java.util.function.Function binding) { WyilFile.Tuple o_parameters = getParameters(); WyilFile.Tuple n_parameters = WyilFile.substitute(o_parameters, binding); if(n_parameters == null) { return null; } else if (o_parameters == n_parameters) { return this; } else { return new Nominal(getLink(), n_parameters); } } @Override public Nominal clone(Syntactic.Item[] operands) { return new Nominal((Decl.Link) operands[0], ((WyilFile.Tuple) operands[1])); } @Override public String toString() { String s = getLink().getName().toString(); WyilFile.Tuple parameters = getParameters(); if (parameters.size() == 0) { return s; } else { return s + "<" + WyilFile.toString(parameters) + ">"; } } @Override public String toCanonicalString() { return getLink().getTarget().getQualifiedName().toString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_nominal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Nominal((Decl.Link) operands[0], (WyilFile.Tuple) operands[1]); } }; } /** * Represents a union type, which is of the form: * *
		 * UnionType ::= IntersectionType ('|' IntersectionType)*
		 * 
* * Union types are used to compose types together. For example, the type * int|null represents the type which is either an int * or null. * * Represents the union of one or more types together. For example, the union of * int and null is int|null. Any variable * of this type may hold any integer or the null value. Furthermore, the types * int and null are collectively referred to as the * "bounds" of this type. * * @return */ public static class Union extends AbstractType implements Type { public static Type create(WyilFile.Tuple types) { return create(types.toArray(Type.class)); } /** * Create a sequence of zero or more types. * * @param types * @return */ public static Type create(Type... _types) { Type[] types = _types; for (int i = 0; i != types.length; ++i) { Type ith = types[i]; if (ith instanceof Type.Union) { Type.Union u = (Type.Union) ith; Type[] nTypes = new Type[types.length + u.size() - 1]; System.arraycopy(types, 0, nTypes, 0, i); System.arraycopy(u.getAll(), 0, nTypes, i, u.size()); System.arraycopy(types, i + 1, nTypes, i + u.size(), (types.length - i - 1)); return create(nTypes); } else if(ith instanceof Type.Void) { if(types == _types) { types = Arrays.copyOf(_types, _types.length); } types[i] = null; } } // types = ArrayUtils.removeAll(types, null); types = ArrayUtils.removeDuplicates(types); // switch (types.length) { case 0: return Type.Void; case 1: return types[0]; default: return new Type.Union(types); } } public Union(Type... types) { super(TYPE_union, types); } @Override public boolean isWriteable() { for(int i=0;i!=size();++i) { if(!get(i).isWriteable()) { return false; } } return true; } @Override public boolean isReadable() { for(int i=0;i!=size();++i) { if(!get(i).isReadable()) { return false; } } return true; } @Override public Type get(int i) { return (Type) super.get(i); } @Override public Type[] getAll() { return (Type[]) super.getAll(); } @Override public Type substitute(java.util.function.Function binding) { Type[] before = getAll(); Type[] after = WyilFile.substitute(before, binding); if(after == null) { return null; } else if (before == after) { return this; } else { return create(after); } } @Override public Type.Union clone(Syntactic.Item[] operands) { return new Union(ArrayUtils.toArray(Type.class, operands)); } @Override public List filter(Class kind) { ArrayList result = new ArrayList<>(); if (kind.isInstance(this)) { result.add((T) this); } else { for (int i = 0; i != size(); ++i) { result.addAll(get(i).filter(kind)); } } return result; } @Override public String toString() { String r = ""; for (int i = 0; i != size(); ++i) { if (i != 0) { r += "|"; } r += braceAsNecessary(get(i)); } return r; } @Override public String toCanonicalString() { String r = ""; for (int i = 0; i != size(); ++i) { if (i != 0) { r += "|"; } r += "(" + get(i).toCanonicalString() + ")"; } return r; } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.MANY, Data.ZERO, "TYPE_union") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Union(ArrayUtils.toArray(Type.class, operands)); } }; } /** * Represents the set of all function values. These are pure functions, * sometimes also called "mathematical" functions. A function cannot have any * side-effects and must always return the same values given the same inputs. A * function cannot have zero returns, since this would make it a no-operation. * * @author David J. Pearce * */ public static class Function extends AbstractType implements Type.Callable { public Function(Type parameters, Type returns) { super(TYPE_function, parameters, returns); } @Override @SuppressWarnings("unchecked") public Type getParameter() { return (Type) get(0); } @Override @SuppressWarnings("unchecked") public Type getReturn() { return (Type) get(1); } @Override public Type.Function substitute(java.util.function.Function binding) { Type parameterBefore = getParameter(); Type parameterAfter = parameterBefore.substitute(binding); Type returnBefore = getReturn(); Type returnAfter = returnBefore.substitute(binding); if(parameterAfter == null || returnAfter == null) { return null; } else if (parameterBefore == parameterAfter && returnBefore == returnAfter) { return this; } else { return new Function(parameterAfter, returnAfter); } } @SuppressWarnings("unchecked") @Override public Function clone(Syntactic.Item[] operands) { return new Function((Type.Tuple) operands[0], (Type.Tuple) operands[1]); } @Override public String toString() { return "function" + brace(getParameter()) + "->" + brace(getReturn()); } @Override public String toCanonicalString() { Type ret = getReturn(); return "function" + getParameter().toCanonicalString() + "->" + getReturn().toCanonicalString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_function") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Function((Type) operands[0], (Type) operands[1]); } }; } /** * Represents the set of all method values. These are impure and may have * side-effects (e.g. performing I/O, updating non-local state, etc). A method * may have zero returns and, in such case, the effect of a method comes through * other side-effects. Methods may also have captured lifetime arguments, and * may themselves declare lifetime arguments. * * @author David J. Pearce * */ public static class Method extends AbstractType implements Type.Callable { public Method(Type parameters, Type returns) { super(TYPE_method, new Syntactic.Item[] { parameters, returns }); } @Override @SuppressWarnings("unchecked") public Type getParameter() { return (Type) get(0); } @Override @SuppressWarnings("unchecked") public Type getReturn() { return (Type) get(1); } @Override public Type.Method substitute(java.util.function.Function binding) { // Proceed with the potentially updated binding Type parametersBefore = getParameter(); Type parametersAfter = parametersBefore.substitute(binding); Type returnBefore = getReturn(); Type returnAfter = returnBefore.substitute(binding); if (parametersBefore == parametersAfter && returnBefore == returnAfter) { return this; } else { return new Method(parametersAfter, returnAfter); } } @Override public String toString() { return "method" + brace(getParameter()) + "->" + brace(getReturn()); } @Override public String toCanonicalString() { return "method" + getParameter().toCanonicalString() + "->" + getReturn().toCanonicalString(); } @SuppressWarnings("unchecked") @Override public Method clone(Syntactic.Item[] operands) { return new Method((Type.Tuple) operands[0], (Type.Tuple) operands[1]); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_method") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Method((Type) operands[0], (Type) operands[1]); } }; } /** * Represents the set of all proeprty values. These are pure predicates, * sometimes also called "mathematical" functions. A property cannot have any * side-effects and always returns the boolean true. * * @author David J. Pearce * */ public static class Property extends AbstractType implements Type.Callable { public Property(Type parameter) { super(TYPE_property, parameter, Type.Bool); } public Property(Type parameter, Type ret) { super(TYPE_property, parameter, ret); } @Override @SuppressWarnings("unchecked") public Type getParameter() { return (Type) get(0); } @Override @SuppressWarnings("unchecked") public Type getReturn() { return (Type) get(1); } @Override public Type.Property substitute(java.util.function.Function binding) { Type parametersBefore = getParameter(); Type parametersAfter = parametersBefore.substitute(binding); Type returnBefore = getReturn(); Type returnAfter = returnBefore.substitute(binding); if (parametersBefore == parametersAfter && returnBefore == returnAfter) { return this; } else { return new Property(parametersAfter, returnAfter); } } @SuppressWarnings("unchecked") @Override public Property clone(Syntactic.Item[] operands) { return new Property((Type.Tuple) operands[0], (Type.Tuple) operands[1]); } @Override public String toString() { return "property" + brace(getParameter()) + "->" + brace(getReturn()); } @Override public String toCanonicalString() { return "property" + getParameter().toCanonicalString() + "->" + getReturn().toCanonicalString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "TYPE_property") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Property((Type.Tuple) operands[0], (Type.Tuple) operands[1]); } }; } public static class Unknown extends AbstractType implements Callable { public Unknown() { super(TYPE_unknown); } @Override public Type.Tuple getParameter() { throw new UnsupportedOperationException(); } @Override public Type.Tuple getReturn() { throw new UnsupportedOperationException(); } @Override public Type.Unknown substitute(java.util.function.Function binding) { throw new UnsupportedOperationException(); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Unknown(); } @Override public String toString() { return "(???)->(???)"; } @Override public String toCanonicalString() { throw new UnsupportedOperationException(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "TYPE_unknown") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Unknown(); } }; } public static class Existential extends AbstractType implements Atom { public Existential(int index) { super(TYPE_existential, BigInteger.valueOf(index).toByteArray()); if(index < 0) { throw new IllegalArgumentException("invalid existential type index"); } } @Override public boolean isWriteable() { // It never makes sense to ask this question of a type variable, since we cannot // possible known the answer. throw new UnsupportedOperationException(); } @Override public boolean isReadable() { // It never makes sense to ask this question of a type variable, since we cannot // possible known the answer. throw new UnsupportedOperationException(); } public int get() { return new BigInteger(data).intValue(); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Existential(new BigInteger(data).intValue()); } @Override public Type substitute(java.util.function.Function binding) { Syntactic.Item i = binding.apply(get()); if(i instanceof Type) { return (Type) i; } else { return this; } } @Override public String toCanonicalString() { return toString(); } @Override public String toString() { return "?" + Integer.toString(get()); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.MANY, "TYPE_existential") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Existential(new BigInteger(data).intValue()); } }; } public static class Universal extends AbstractType implements Atom { public Universal(Identifier name) { super(TYPE_universal, name); } @Override public boolean isWriteable() { return false; } @Override public boolean isReadable() { // It never makes sense to ask this question of a type variable, since we cannot // possible known the answer. throw new UnsupportedOperationException(); } public Identifier getOperand() { return (Identifier) get(0); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Universal((Identifier) operands[0]); } @Override public Type substitute(java.util.function.Function binding) { Syntactic.Item expanded = binding.apply(getOperand()); if (expanded instanceof Type) { return (Type) expanded; } else { return this; } } @Override public String toCanonicalString() { return toString(); } @Override public String toString() { return getOperand().toString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "TYPE_universal") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Universal((Identifier) operands[0]); } }; } /** * Represents a recursive link. That is a backlink into the type itself. * * @return */ public static class Recursive extends AbstractType implements Type { public Recursive(Ref reference) { super(TYPE_recursive, reference); } @Override public boolean isWriteable() { return false; } @Override public boolean isReadable() { return false; } public Type getHead() { Ref r = (Ref) get(0); return r.get(); } public void setHead(Ref ref) { operands[0] = ref; } @Override public Recursive substitute(java.util.function.Function binding) { return this; } @Override public Recursive clone(Syntactic.Item[] operands) { return new Recursive((Ref) operands[0]); } @Override public String toString() { Type head = getHead(); if (head instanceof Type.Atom || head instanceof Type.Nominal) { return "?" + head; } else if (head.getHeap() != null) { return "?" + head.getIndex(); } else { return "?"; } } @Override public String toCanonicalString() { throw new UnsupportedOperationException(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "TYPE_recursive") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Recursive((Ref) operands[0]); } }; } /** * A type selector provides a form of refinement for a give type. More * specifically, it determines which type tags are active for a given type. * * @author David J. Pearce * */ public static class Selector { /** * Indicates that the given element is not selected. */ public static final Selector BOTTOM = new Selector() { @Override public String toString(Type t) { return "..."; } @Override public String toString() { return "_"; } @Override public Type apply(Type source) { return Type.Void; } }; /** * Indicates that the given element is selected entirely. */ public static final Selector TOP = new Selector() { @Override public String toString(Type t) { return t.toString(); } @Override public Type apply(Type source) { return source; } @Override public String toString() { return "*"; } }; private final Selector[] children; public Selector(Selector... nodes) { this.children = nodes; } public int size() { return children.length; } public Selector get(int ith) { return children[ith]; } @Override public String toString() { String r = ""; for(int i=0;i!=children.length;++i) { if(i != 0) { r += ","; } r += children[i].toString(); } return "(" + r + ")"; } /** * Generate a "partial" view of a given type according to this selector. For * example, null|{int f} with selector (_|*) would * produce the string ...|{int f}. * * @param t * @return */ public String toString(Type type) { switch (type.getOpcode()) { case TYPE_any: case TYPE_void: case TYPE_null: case TYPE_bool: case TYPE_byte: case TYPE_int: case TYPE_reference: case TYPE_method: case TYPE_function: case TYPE_property: return type.toString(); case TYPE_array: { Type.Array t = (Type.Array) type; return children[0].toString(t.getElement()) + "[]"; } case TYPE_nominal: { Type.Nominal t = (Type.Nominal) type; return toString(t.getConcreteType()); } case TYPE_record: { Type.Record t = (Type.Record) type; WyilFile.Tuple fields = t.getFields(); String r = ""; boolean ignored = false; for (int i = 0; i != fields.size(); ++i) { Type.Field f = fields.get(i); Selector s = children[i]; if(!ignored || s != BOTTOM) { if(i != 0) { r = r + ", "; } if(s == BOTTOM) { r = r + s.toString(f.getType()); } else { r = r + s.toString(f.getType()) + " " + f.getName(); } } ignored = (s == BOTTOM); } return "{" + r + "}"; } default: { Type.Union t = (Type.Union) type; String r = ""; boolean ignored = false; for(int i=0;i!=t.size();++i) { Selector s = children[i]; if(!ignored || s != BOTTOM) { if(i != 0) { r = r + "|"; } r += s.toString(t.get(i)); } ignored = (s == BOTTOM); } return r; } } } /** * Apply this selector to a given type, producing a potentially updated type. * For example, applying int|null to the selector _|* * yields null. * * @param source * @return */ public Type apply(Type type) { // FIXME: need to support infinite selectors switch (type.getOpcode()) { case TYPE_any: case TYPE_void: case TYPE_null: case TYPE_bool: case TYPE_byte: case TYPE_int: case TYPE_reference: case TYPE_method: case TYPE_function: case TYPE_property: return type; case TYPE_array: { Type.Array t = (Type.Array) type; return new Type.Array(children[0].apply(t.getElement())); } case TYPE_nominal: { Type.Nominal t = (Type.Nominal) type; return apply(t.getConcreteType()); } case TYPE_record: { Type.Record t = (Type.Record) type; WyilFile.Tuple fields = t.getFields(); Type.Field[] items = new Type.Field[fields.size()]; for (int i = 0; i != fields.size(); ++i) { Type.Field f = fields.get(i); Type ft = children[i].apply(f.getType()); items[i] = new Type.Field(f.getName(), ft); } return new Type.Record(t.isOpen(), new WyilFile.Tuple<>(items)); } default: return apply((Type.Union) type); } } private Type apply(Type.Union type) { Type[] items = new Type[type.size()]; for(int i=0;i!=type.size();++i) { items[i] = children[i].apply(type.get(i)); } // Strip out unselected items items = ArrayUtils.removeAll(items, Type.Void); // switch(items.length) { case 0: return Type.Void; case 1: return items[0]; default: return new Type.Union(items); } } } } private static Tuple substitute(Tuple types, java.util.function.Function binding) { for (int i = 0; i != types.size(); ++i) { Type before = types.get(i); Type after = before.substitute(binding); if (before != after) { // Committed to change Type[] nTypes = new Type[types.size()]; for (int j = 0; j != nTypes.length; ++j) { after = types.get(j).substitute(binding); if(after == null) { return null; } nTypes[j] = after; } return new Tuple<>(nTypes); } } // return types; } private static Type[] substitute(Type[] types, java.util.function.Function binding) { Type[] nTypes = types; for (int i = 0; i != nTypes.length; ++i) { Type before = types[i]; Type after = before.substitute(binding); if(after == null) { return null; } else if (before != after) { if (nTypes == types) { nTypes = Arrays.copyOf(types, types.length); } nTypes[i] = after; } } // return nTypes; } /** * Apply an explicit binding to a given function, method or property declaration * via substitution. Observe we cannot just use the existing Type.substitute * method as this accounts for lifetime captures. Therefore, we first build the * binding and then apply it to each of the parameters and returns. * * @param fmp * @param templateArguments * @return */ public static Type.Callable substituteTypeCallable(Type.Callable fmp, Tuple templateParameters, Tuple templateArguments) { Function binding = WyilFile.bindingFunction(templateParameters,templateArguments); // Proceed with the potentially updated binding Type parameters = fmp.getParameter().substitute(binding); Type ret = fmp.getReturn().substitute(binding); // if(fmp instanceof Type.Method) { return new Type.Method(parameters, ret); } else if(fmp instanceof Type.Function) { return new Type.Function(parameters, ret); } else { return new Type.Property(parameters, ret); } } private static String brace(Type t) { if(t.shape() < 2) { return "(" + t + ")"; } else { return t.toString(); } } public static String toString(Tuple items) { String r = ""; for (int i = 0; i != items.size(); ++i) { Syntactic.Item ith = items.get(i); if (i != 0) { r += ","; } r += ith == null ? "?" : ith; } return r; } // ============================================================ // Modifiers // ============================================================ /** *

* Represents an arbitrary modifier on a declaration. For example, all * declarations (e.g. functions, types, etc) can be marked as * public or private. The following illustrates: *

* *
	 * public function square(int x, int y) -> int:
	 *    return x * y
	 * 
*

* The public modifier used above indicates that the function * square can be accessed from outside its enclosing module. *

*

* The modifiers native and export are used to enable * inter-operation with other languages. By declaring a function or method as * native you are signaling that its implementation is provided * elsewhere (e.g. it's implemented in Java code directly). By marking a * function or method with export, you are declaring that external * code may call it. For example, you have some Java code that needs to call it. * The modifier is required because, by default, all the names of all methods * and functions are mangled to include type information and enable * overloading. Therefore, a method/function marked with export * will generate a function without name mangling. *

* * @author David J. Pearce * */ public interface Modifier extends Syntactic.Item { public static final class Public extends AbstractItem implements Modifier { public Public() { super(MOD_public); } @Override public String toString() { return "public"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Public(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_public") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Public(); } }; } public static final class Private extends AbstractItem implements Modifier { public Private() { super(MOD_private); } @Override public String toString() { return "private"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Private(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_private") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Private(); } }; } public static final class Native extends AbstractItem implements Modifier { public Native() { super(MOD_native); } @Override public String toString() { return "native"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Native(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_native") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Native(); } }; } public static final class Export extends AbstractItem implements Modifier { public Export() { super(MOD_export); } @Override public String toString() { return "export"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Export(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_export") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Export(); } }; } public static final class Final extends AbstractItem implements Modifier { public Final() { super(MOD_final); } @Override public String toString() { return "final"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Final(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_final") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Final(); } }; } public static final class Unsafe extends AbstractItem implements Modifier { public Unsafe() { super(MOD_unsafe); } @Override public String toString() { return "unsafe"; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new Unsafe(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ZERO, Data.ZERO, "MOD_unsafe") { @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new Modifier.Unsafe(); } }; } } public interface Linkable { /** * Get the link associated with this linkable expression. * @return */ Decl.Link getLink(); } public interface Bindable extends Linkable, Syntactic.Item { /** * Get the binding associated with this bindable expression. * * @return */ Decl.Binding getBinding(); } /** * Create a simple binding function from two tuples representing the key set and * value set respectively. * * @param variables * @param arguments * @return */ public static java.util.function.Function bindingFunction( Tuple variables, Tuple arguments) { // return (Object var) -> { int n = Math.min(variables.size(),arguments.size()); for (int i = 0; i != n; ++i) { if (var.equals(variables.get(i).getName())) { return arguments.get(i); } } return null; }; } /** * Create a simple binding function from two tuples representing the key set and * value set respectively. * * @param variables * @param arguments * @return */ public static java.util.function.Function bindingFunction( Tuple variables, Type.Tuple arguments) { // return (Object var) -> { int n = Math.min(variables.size(),arguments.size()); for (int i = 0; i != n; ++i) { if (var.equals(variables.get(i).getName())) { return arguments.get(i); } } return null; }; } /** * Construct a binding function from another binding where a given set of * variables are removed. This is necessary in situations where the given * variables are captured. * * @param binding * @param variables * @return */ public static java.util.function.Function removeFromBinding( java.util.function.Function binding, Tuple variables) { return (Object var) -> { // Sanity check whether this is a variable which is being removed for (int i = 0; i != variables.size(); ++i) { if (var.equals(variables.get(i))) { return null; } } // Not being removed, reuse existing binding return binding.apply(var); }; } // ============================================================ // Attributes // ============================================================ public interface Attr { public static class SyntaxError extends AbstractItem implements Syntactic.Marker { public SyntaxError(int errcode, Syntactic.Item target) { super(ATTR_error, BigInteger.valueOf(errcode).toByteArray(), target, new Tuple<>()); } public SyntaxError(int errcode, Syntactic.Item target, Tuple context) { super(ATTR_error, BigInteger.valueOf(errcode).toByteArray(), target, context); } @Override public Syntactic.Item getTarget() { return operands[0]; } public Tuple getContext() { return (Tuple) operands[1]; } /** * Get the error code associated with this message * * @return */ public int getErrorCode() { return new BigInteger(getData()).intValue(); } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new SyntaxError(getErrorCode(), operands[0], (Tuple) operands[1]); } @Override public String getMessage() { // Done return ErrorMessages.getErrorMessage(getErrorCode(), getContext()); } @Override public Trie getSource() { WyilFile bin = (WyilFile) getTarget().getHeap(); Decl.Unit unit = getTarget().getAncestor(Decl.Unit.class); String nameStr = unit.getName().toString().replace("::", "/"); return Trie.fromString(nameStr); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.MANY, Data.TWO, "ATTR_error") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { int errcode = new BigInteger(data).intValue(); return new SyntaxError(errcode, operands[0], (Tuple) operands[1]); } }; } public static class StackFrame extends AbstractItem { public StackFrame(Decl.Named context, Tuple arguments) { super(ATTR_stackframe,context,arguments); } public Decl.Named getContext() { return (Decl.Named) operands[0]; } public Tuple getArguments() { return (Tuple) operands[1]; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new StackFrame((Decl.Callable) operands[0], (Tuple) operands[1]); } @Override public String toString() { return getContext().getQualifiedName().toString() + getArguments(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.TWO, Data.ZERO, "ATTR_stackframe") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new StackFrame((Decl.Named) operands[0], (Tuple) operands[1]); } }; } public static class CounterExample extends AbstractItem { public CounterExample(Value.Dictionary mapping) { super(ATTR_counterexample,mapping); } public Value.Dictionary getMapping() { return (Value.Dictionary) operands[0]; } @Override public Syntactic.Item clone(Syntactic.Item[] operands) { return new CounterExample((Value.Dictionary) operands[0]); } @Override public String toString() { return getMapping().toString(); } public static final Descriptor DESCRIPTOR_0 = new Descriptor(Operands.ONE, Data.ZERO, "ATTR_counterexample") { @SuppressWarnings("unchecked") @Override public Syntactic.Item construct(int opcode, Syntactic.Item[] operands, byte[] data) { return new CounterExample((Value.Dictionary) operands[0]); } }; } } // Generic public static final int INTERNAL_FAILURE = 0; // Parsing public static final int EXPECTING_TOKEN = 300; // "expecting \"" + kind + "\" here" public static final int EXPECTED_LIFETIME = 301;// "expecting lifetime identifier" public static final int UNEXPECTED_EOF = 302; // "unexpected end-of-file" public static final int UNEXPECTED_BLOCK_END = 303; // "unexpected end-of-block" public static final int UNKNOWN_LIFETIME = 304; // "use of undeclared lifetime" public static final int UNKNOWN_TYPE = 305; // "unknown type encountered" public static final int UNKNOWN_LVAL = 306; // "unexpected lval" public static final int UNKNOWN_TERM = 307; // "unrecognised term" public static final int INVALID_UNICODE_LITERAL = 308; // "invalid unicode string" public static final int INVALID_BINARY_LITERAL = 309; // "invalid binary literal" public static final int INVALID_HEX_LITERAL = 310; // "invalid hex literal (invalid characters)" public static final int DUPLICATE_VISIBILITY_MODIFIER = 311; // "visibility modifier already given" public static final int DUPLICATE_TEMPLATE_VARIABLE = 312; // "duplicate template variable" public static final int DUPLICATE_CASE_LABEL = 313; // "duplicate case label" public static final int DUPLICATE_DEFAULT_LABEL = 314; // "duplicate default label" public static final int DUPLICATE_FIELD = 315; // "duplicate record key" public static final int DUPLICATE_DECLARATION = 316; // "name already declared" public static final int MISSING_TYPE_VARIABLE = 317; // "missing type variable(s)" public static final int BREAK_OUTSIDE_SWITCH_OR_LOOP = 318; // "break outside switch or loop" public static final int CONTINUE_OUTSIDE_LOOP = 319; // "continue outside loop" public static final int OLD_REQUIRES_TWOSTATES = 320; // "old requires context with pre- and post-states" public static final int BRACES_REQUIRED_TO_DISAMBIGUATE = 321; // "braces required to disambiguate expression" // Types public static final int SUBTYPE_ERROR = 400; public static final int EMPTY_TYPE = 401; public static final int EXPECTED_ARRAY = 402; public static final int EXPECTED_RECORD = 403; public static final int EXPECTED_REFERENCE = 404; public static final int EXPECTED_LAMBDA = 405; public static final int INVALID_FIELD = 406; public static final int RESOLUTION_ERROR = 407; public static final int AMBIGUOUS_COERCION = 408; public static final int MISSING_TEMPLATE_PARAMETERS = 409; public static final int TOOMANY_TEMPLATE_PARAMETERS = 410; public static final int EXPOSING_HIDDEN_DECLARATION = 411; public static final int INTERNAL_RESOLUTION_ERROR = 412; // Statements public static final int MISSING_RETURN_STATEMENT = 500; public static final int UNREACHABLE_CODE = 504; public static final int BRANCH_ALWAYS_TAKEN = 506; public static final int TOO_MANY_RETURNS = 507; public static final int INSUFFICIENT_RETURNS = 508; public static final int CYCLIC_STATIC_INITIALISER = 509; // Expressions public static final int VARIABLE_POSSIBLY_UNITIALISED = 601; public static final int INCOMPARABLE_OPERANDS = 602; public static final int INSUFFICIENT_ARGUMENTS = 603; public static final int AMBIGUOUS_CALLABLE = 604; public static final int PARAMETER_REASSIGNED = 605; public static final int FINAL_VARIABLE_REASSIGNED = 606; public static final int ALLOCATION_NOT_PERMITTED = 607; public static final int METHODCALL_NOT_PERMITTED = 608; public static final int REFERENCE_ACCESS_NOT_PERMITTED = 609; public static final int INVALID_LVAL_EXPRESSION = 610; public static final int DEREFERENCED_DYNAMICALLY_SIZED = 611; public static final int DEREFERENCED_UNKNOWN_TYPE = 612; public static final int UNSAFECALL_NOT_PERMITTED = 613; public static final int VARIANTCALL_NOT_PERMITTED = 614; public static final int STATIC_ACCESS_NOT_PERMITTED = 615; // Runtime Failure Subset public static final int RUNTIME_PRECONDITION_FAILURE = 700; public static final int RUNTIME_POSTCONDITION_FAILURE = 701; public static final int RUNTIME_TYPEINVARIANT_FAILURE = 702; public static final int RUNTIME_LOOPINVARIANT_ESTABLISH_FAILURE = 703; public static final int RUNTIME_LOOPINVARIANT_RESTORED_FAILURE = 704; public static final int RUNTIME_ASSERTION_FAILURE = 705; public static final int RUNTIME_ASSUMPTION_FAILURE = 706; public static final int RUNTIME_BELOWBOUNDS_INDEX_FAILURE = 707; public static final int RUNTIME_ABOVEBOUNDS_INDEX_FAILURE = 708; public static final int RUNTIME_NEGATIVE_LENGTH_FAILURE = 709; public static final int RUNTIME_NEGATIVE_RANGE_FAILURE = 710; public static final int RUNTIME_DIVIDEBYZERO_FAILURE = 711; public static final int RUNTIME_FAULT = 712; public static final int RUNTIME_NEGATIVE_EXPONENT_FAILURE = 713; // Verification Subset public static final int STATIC_PRECONDITION_FAILURE = 716; public static final int STATIC_POSTCONDITION_FAILURE = 717; public static final int STATIC_TYPEINVARIANT_FAILURE = 718; public static final int STATIC_ESTABLISH_LOOPINVARIANT_FAILURE = 719; public static final int STATIC_ENTER_LOOPINVARIANT_FAILURE = 720; public static final int STATIC_RESTORE_LOOPINVARIANT_FAILURE = 721; public static final int STATIC_ASSERTION_FAILURE = 722; public static final int STATIC_ASSUMPTION_FAILURE = 723; public static final int STATIC_BELOWBOUNDS_INDEX_FAILURE = 724; public static final int STATIC_ABOVEBOUNDS_INDEX_FAILURE = 725; public static final int STATIC_NEGATIVE_LENGTH_FAILURE = 726; public static final int STATIC_NEGATIVE_RANGE_FAILURE = 727; public static final int STATIC_DIVIDEBYZERO_FAILURE = 728; public static final int STATIC_FAULT = 729; public static final int STATIC_NEGATIVE_EXPONENT_FAILURE = 730; // ============================================================================== // // ============================================================================== private static String canonicalBraceAsNecessary(Type type) { String str = type.toCanonicalString(); if (needsBraces(type)) { return "(" + str + ")"; } else { return str; } } private static String braceAsNecessary(Type type) { String str = type.toString(); if (needsBraces(type)) { return "(" + str + ")"; } else { return str; } } private static boolean needsBraces(Type type) { if (type instanceof Type.Atom || type instanceof Type.Nominal) { return false; } else { return true; } } private static class UsedVariableExtractor extends AbstractConsumer> { @Override public void visitVariableAccess(WyilFile.Expr.VariableAccess expr, HashSet used) { used.add(expr.getVariableDeclaration()); } @Override public void visitUniversalQuantifier(WyilFile.Expr.UniversalQuantifier expr, HashSet used) { for(Decl.StaticVariable v : expr.getParameters()) { visitVariable(v,used); } visitExpression(expr.getOperand(), used); removeAllDeclared(expr.getParameters(), used); } @Override public void visitExistentialQuantifier(WyilFile.Expr.ExistentialQuantifier expr, HashSet used) { for(Decl.StaticVariable v : expr.getParameters()) { visitVariable(v,used); } visitExpression(expr.getOperand(), used); removeAllDeclared(expr.getParameters(), used); } @Override public void visitType(WyilFile.Type type, HashSet used) { // No need to visit types } private void removeAllDeclared(Tuple parameters, HashSet used) { for (int i = 0; i != parameters.size(); ++i) { used.remove(parameters.get(i)); } } }; // ========================================================================= // Schema Generator // ========================================================================= /** * This method constructs a chain of versioned schemas which should represent an * immutable record of the various file formats used for representing WyilFiles. * * @return */ private static Schema createSchema() { return createSchema_2_2(); } private static SectionedSchema createSchema_2_2() { SectionedSchema schema = createSchema_2_1(); SectionedSchema.Builder builder = schema.extend(); builder.replace("DECL", "property", Decl.Property.DESCRIPTOR_1); return builder.done(); } /** * The first recorded schema for WyIL files. There were many many versions prior * to this, but their differences are now lost in time. * * @return */ private static SectionedSchema createSchema_2_1() { SectionedSchema ROOT = new SectionedSchema(null, 2, 1, new Section[0]); SectionedSchema.Builder builder = ROOT.extend(); // Register the necessary sections builder.register("ITEM", 16); builder.register("DECL", 32); builder.register("MOD", 8); builder.register("TEMPLATE", 8); builder.register("ATTR", 16); builder.register("TYPE", 64); builder.register("STMT", 32); builder.register("EXPR", 64); // Items from AbstractCompilationUnit builder.add("ITEM", "null", AbstractCompilationUnit.Value.Null.DESCRIPTOR_0); builder.add("ITEM", "bool", AbstractCompilationUnit.Value.Bool.DESCRIPTOR_0); builder.add("ITEM", "int", AbstractCompilationUnit.Value.Int.DESCRIPTOR_0); builder.add("ITEM", "utf8", AbstractCompilationUnit.Value.UTF8.DESCRIPTOR_0); builder.add("ITEM", "pair", AbstractCompilationUnit.Pair.DESCRIPTOR_0); builder.add("ITEM", "tuple", AbstractCompilationUnit.Tuple.DESCRIPTOR_0); builder.add("ITEM", "array", AbstractCompilationUnit.Value.Array.DESCRIPTOR_0); builder.add("ITEM", "ident", AbstractCompilationUnit.Identifier.DESCRIPTOR_0); builder.add("ITEM", "name", AbstractCompilationUnit.Name.DESCRIPTOR_0); builder.add("ITEM", "decimal", AbstractCompilationUnit.Value.Decimal.DESCRIPTOR_0); builder.add("ITEM", "ref", AbstractCompilationUnit.Ref.DESCRIPTOR_0); builder.add("ITEM", "dictionary", AbstractCompilationUnit.Value.Dictionary.DESCRIPTOR_0); builder.add("ITEM", null, null); builder.add("ITEM", null, null); builder.add("ITEM", "span", AbstractCompilationUnit.Attribute.Span.DESCRIPTOR_0); builder.add("ITEM", "byte", AbstractCompilationUnit.Value.Byte.DESCRIPTOR_0); // Declarations builder.add("DECL", "unknown", Decl.Unknown.DESCRIPTOR_0); builder.add("DECL", "module", Decl.Module.DESCRIPTOR_0); builder.add("DECL", "unit", Decl.Unit.DESCRIPTOR_0); builder.add("DECL", "import", Decl.Import.DESCRIPTOR_0a); builder.add("DECL", "importfrom", Decl.Import.DESCRIPTOR_0b); builder.add("DECL", "importwith", Decl.Import.DESCRIPTOR_0c); builder.add("DECL", "staticvar", Decl.StaticVariable.DESCRIPTOR_0); builder.add("DECL", "type", Decl.Type.DESCRIPTOR_0a); builder.add("DECL", "rectype", Decl.Type.DESCRIPTOR_0b); builder.add("DECL", "function", Decl.Function.DESCRIPTOR_0); builder.add("DECL", "method", Decl.Method.DESCRIPTOR_0); builder.add("DECL", "property", Decl.Property.DESCRIPTOR_0); builder.add("DECL", "lambda", Decl.Lambda.DESCRIPTOR_0); builder.add("DECL", "variable", Decl.Variable.DESCRIPTOR_0); builder.add("DECL", "link", Decl.Link.DESCRIPTOR_0); builder.add("DECL", "binding", Decl.Binding.DESCRIPTOR_0); builder.add("DECL", "variant", Decl.Variant.DESCRIPTOR_0); // Modifiers builder.add("MOD", "native", Modifier.Native.DESCRIPTOR_0); builder.add("MOD", "export", Modifier.Export.DESCRIPTOR_0); builder.add("MOD", "final", Modifier.Final.DESCRIPTOR_0); builder.add("MOD", "protected", null); builder.add("MOD", "private", Modifier.Private.DESCRIPTOR_0); builder.add("MOD", "public", Modifier.Public.DESCRIPTOR_0); builder.add("MOD", "unsafe", Modifier.Unsafe.DESCRIPTOR_0); // Templates builder.add("TEMPLATE", "type", Template.Type.DESCRIPTOR_0); // Attributes builder.add("ATTR", "warning", null); builder.add("ATTR", "error", Attr.SyntaxError.DESCRIPTOR_0); builder.add("ATTR", "verificationcondition", null); builder.add("ATTR", null, null); builder.add("ATTR", "stackframe", Attr.StackFrame.DESCRIPTOR_0); builder.add("ATTR", "counterexample", Attr.CounterExample.DESCRIPTOR_0); // Types builder.add("TYPE", "unknown", Type.Unknown.DESCRIPTOR_0); builder.add("TYPE", "void", Type.Void.DESCRIPTOR_0); builder.add("TYPE", "any", Type.Any.DESCRIPTOR_0); builder.add("TYPE", "null", Type.Null.DESCRIPTOR_0); builder.add("TYPE", "bool", Type.Bool.DESCRIPTOR_0); builder.add("TYPE", "int", Type.Int.DESCRIPTOR_0); builder.add("TYPE", "nominal", Type.Nominal.DESCRIPTOR_0); builder.add("TYPE", "reference", Type.Reference.DESCRIPTOR_0); builder.add("TYPE", "array", Type.Array.DESCRIPTOR_0); builder.add("TYPE", "tuple", Type.Tuple.DESCRIPTOR_0); builder.add("TYPE", "record", Type.Record.DESCRIPTOR_0); builder.add("TYPE", "field", Type.Field.DESCRIPTOR_0); builder.add("TYPE", "function", Type.Function.DESCRIPTOR_0); builder.add("TYPE", "method", Type.Method.DESCRIPTOR_0); builder.add("TYPE", "property", Type.Property.DESCRIPTOR_0); builder.add("TYPE", "union", Type.Union.DESCRIPTOR_0); builder.add("TYPE", "byte", Type.Byte.DESCRIPTOR_0); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", null, null); builder.add("TYPE", "recursive", Type.Recursive.DESCRIPTOR_0); builder.add("TYPE", "universal", Type.Universal.DESCRIPTOR_0); builder.add("TYPE", "existential", Type.Existential.DESCRIPTOR_0); // Statements builder.add("STMT", "block", Stmt.Block.DESCRIPTOR_0); builder.add("STMT", "namedblock", Stmt.NamedBlock.DESCRIPTOR_0); builder.add("STMT", "caseblock", Stmt.Case.DESCRIPTOR_0); builder.add("STMT", "assert", Stmt.Assert.DESCRIPTOR_0); builder.add("STMT", "assign", Stmt.Assign.DESCRIPTOR_0); builder.add("STMT", "assume", Stmt.Assume.DESCRIPTOR_0); builder.add("STMT", "debug", Stmt.Debug.DESCRIPTOR_0); builder.add("STMT", "skip", Stmt.Skip.DESCRIPTOR_0); builder.add("STMT", "break", Stmt.Break.DESCRIPTOR_0); builder.add("STMT", "continue", Stmt.Continue.DESCRIPTOR_0); builder.add("STMT", "dowhile", Stmt.DoWhile.DESCRIPTOR_0); builder.add("STMT", "fail", Stmt.Fail.DESCRIPTOR_0); builder.add("STMT", "for", Stmt.For.DESCRIPTOR_0); builder.add("STMT", "foreach", null); builder.add("STMT", "if", Stmt.IfElse.DESCRIPTOR_0a); builder.add("STMT", "ifelse", Stmt.IfElse.DESCRIPTOR_0b); builder.add("STMT", "initialiser", Stmt.Initialiser.DESCRIPTOR_0a); builder.add("STMT", "initialiservoid", Stmt.Initialiser.DESCRIPTOR_0b); builder.add("STMT", "return", Stmt.Return.DESCRIPTOR_0a); builder.add("STMT", "returnvoid", Stmt.Return.DESCRIPTOR_0b); builder.add("STMT", "switch", Stmt.Switch.DESCRIPTOR_0); builder.add("STMT", "while", Stmt.While.DESCRIPTOR_0); // General Expressions builder.add("EXPR", "variablecopy", Expr.VariableAccess.DESCRIPTOR_0a); builder.add("EXPR", "variablemove", Expr.VariableAccess.DESCRIPTOR_0b); builder.add("EXPR", null, null); builder.add("EXPR", "staticvariable", Expr.StaticVariableAccess.DESCRIPTOR_0); // builder.add("EXPR", "constant", Expr.Constant.DESCRIPTOR_0); builder.add("EXPR", "cast", Expr.Cast.DESCRIPTOR_0); builder.add("EXPR", "invoke", Expr.Invoke.DESCRIPTOR_0); builder.add("EXPR", "indirectinvoke", Expr.IndirectInvoke.DESCRIPTOR_0); // Logical Expressions builder.add("EXPR", "logicalnot", Expr.LogicalNot.DESCRIPTOR_0); builder.add("EXPR", "logicaland", Expr.LogicalAnd.DESCRIPTOR_0); builder.add("EXPR", "logicalor", Expr.LogicalOr.DESCRIPTOR_0); builder.add("EXPR", "logicalimplication", Expr.LogicalImplication.DESCRIPTOR_0); // builder.add("EXPR", "logicaliff", Expr.LogicalIff.DESCRIPTOR_0); builder.add("EXPR", "logicalexistential", Expr.ExistentialQuantifier.DESCRIPTOR_0); builder.add("EXPR", "logicaluniversal", Expr.UniversalQuantifier.DESCRIPTOR_0); // Comparator Expressions builder.add("EXPR", "equal", Expr.Equal.DESCRIPTOR_0); builder.add("EXPR", "notequal", Expr.NotEqual.DESCRIPTOR_0); builder.add("EXPR", "integerlessthan", Expr.IntegerLessThan.DESCRIPTOR_0); builder.add("EXPR", "integerlessequal", Expr.IntegerLessThanOrEqual.DESCRIPTOR_0); builder.add("EXPR", "integergreaterthan", Expr.IntegerGreaterThan.DESCRIPTOR_0); builder.add("EXPR", "integergreaterequal", Expr.IntegerGreaterThanOrEqual.DESCRIPTOR_0); builder.add("EXPR", "is", Expr.Is.DESCRIPTOR_0); builder.add("EXPR", "old", Expr.Old.DESCRIPTOR_0); // Arithmetic Expressions builder.add("EXPR", "integernegation", Expr.IntegerNegation.DESCRIPTOR_0); builder.add("EXPR", "integeraddition", Expr.IntegerAddition.DESCRIPTOR_0); builder.add("EXPR", "integersubtraction", Expr.IntegerSubtraction.DESCRIPTOR_0); builder.add("EXPR", "integermultiplication", Expr.IntegerMultiplication.DESCRIPTOR_0); // builder.add("EXPR", "integerdivision", Expr.IntegerDivision.DESCRIPTOR_0); builder.add("EXPR", "integerremainder", Expr.IntegerRemainder.DESCRIPTOR_0); builder.add("EXPR", "integerexponent", Expr.IntegerExponent.DESCRIPTOR_0); builder.add("EXPR", null, null); // Bitwise Expressions builder.add("EXPR", "bitwisenot", Expr.BitwiseComplement.DESCRIPTOR_0); builder.add("EXPR", "bitwiseand", Expr.BitwiseAnd.DESCRIPTOR_0); builder.add("EXPR", "bitwiseor", Expr.BitwiseOr.DESCRIPTOR_0); builder.add("EXPR", "bitwisexor", Expr.BitwiseXor.DESCRIPTOR_0); // builder.add("EXPR", "bitwiseshl", Expr.BitwiseShiftLeft.DESCRIPTOR_0); builder.add("EXPR", "bitwiseshr", Expr.BitwiseShiftRight.DESCRIPTOR_0); builder.add("EXPR", null, null); builder.add("EXPR", null, null); // Reference Expressions builder.add("EXPR", "dereference", Expr.Dereference.DESCRIPTOR_0); builder.add("EXPR", "new", Expr.New.DESCRIPTOR_0); builder.add("EXPR", "lambdaaccess", Expr.LambdaAccess.DESCRIPTOR_0); // builder.add("EXPR", "fielddereference", Expr.FieldDereference.DESCRIPTOR_0); builder.add("EXPR", null, null); builder.add("EXPR", null, null); builder.add("EXPR", null, null); // Record Expressions builder.add("EXPR", "recordaccess", Expr.RecordAccess.DESCRIPTOR_0a); builder.add("EXPR", "recordborrow", Expr.RecordAccess.DESCRIPTOR_0b); builder.add("EXPR", "recordupdate", Expr.RecordUpdate.DESCRIPTOR_0); builder.add("EXPR", "recordinitialiser", Expr.RecordInitialiser.DESCRIPTOR_0); // Tuple Expressions builder.add("EXPR", "tupleinitialiser", Expr.TupleInitialiser.DESCRIPTOR_0); builder.add("EXPR", null, null); builder.add("EXPR", null, null); builder.add("EXPR", null, null); // Array Expressions builder.add("EXPR", "arrayaccess", Expr.ArrayAccess.DESCRIPTOR_0a); builder.add("EXPR", "arrayborrow", Expr.ArrayAccess.DESCRIPTOR_0b); builder.add("EXPR", "arrayupdate", Expr.ArrayUpdate.DESCRIPTOR_0); builder.add("EXPR", "arraylength", Expr.ArrayLength.DESCRIPTOR_0); // builder.add("EXPR", "arraygenerator", Expr.ArrayGenerator.DESCRIPTOR_0); builder.add("EXPR", "arrayinitialiser", Expr.ArrayInitialiser.DESCRIPTOR_0); builder.add("EXPR", "arrayrange", Expr.ArrayRange.DESCRIPTOR_0); builder.add("EXPR", null, null); // Done SectionedSchema v0_1 = builder.done(); return v0_1; } public static void main(String[] args) { Schema current = createSchema(); for (int i = 0; i <= 255; ++i) { Syntactic.Item.Descriptor desc = current.getDescriptor(i); if (desc != null) { System.out.println("public static final int " + desc.getMnemonic() + " = " + i + "; // " + desc); } } System.out.println("VERSION: " + current.getMajorVersion() + "." + current.getMinorVersion()); } }