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