// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz) // All rights reserved. // // This software may be modified and distributed under the terms // of the BSD license. See the LICENSE file for details. package wyc.lang; import java.util.*; import wybs.lang.Attribute; import wybs.lang.SyntacticElement; import wyc.lang.SyntacticType.NonUnion; import wyil.lang.Type; /** * <p> * Provides classes for representing types in Whiley's source language. These * are referred to as <i>unresolved types</i> as they include nominal types * whose full NameID remains unknown. Unresolved types are <i>resolved</i> * during the name resolution> stage of the compiler. * </p> * * <p> * Each class is an instance of <code>SyntacticElement</code> and, hence, can be * adorned with certain information (such as source location, etc). * </p> * * @author David J. Pearce * */ public interface SyntacticType extends SyntacticElement { /** * A non-union type represents a type which is not an instance of * <code>Union</code>. * * @author David J. Pearce * */ public interface NonUnion extends SyntacticType { // FIXME: this interface should not exist! } public interface Primitive extends SyntacticType { } /** * The type <code>any</code> represents the type whose variables may hold * any possible value. <b>NOTE:</b> the any type is top in the type lattice. * * @author David J. Pearce * */ public static final class Any extends SyntacticElement.Impl implements NonUnion,Primitive { public Any(Attribute... attributes) { super(attributes); } } /** * 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. <b>NOTE:</b> * the void type is a subtype of everything; that is, it is bottom in the * type lattice. * * @author David J. Pearce * */ public static final class Void extends SyntacticElement.Impl implements NonUnion,Primitive { public Void(Attribute... attributes) { super(attributes); } } /** * 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 <code>null</code> value (where as there is no special "void" * value). With all of the problems surrounding <code>null</code> and * <code>NullPointerException</code>s 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 final class Null extends SyntacticElement.Impl implements NonUnion,Primitive { public Null(Attribute... attributes) { super(attributes); } } /** * Represents the set of boolean values (i.e. true and false) * @author David J. Pearce * */ public static final class Bool extends SyntacticElement.Impl implements NonUnion,Primitive { public Bool(Attribute... attributes) { super(attributes); } } /** * 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. <code>Byte.toInt()</code>). * * @author David J. Pearce * */ public static final class Byte extends SyntacticElement.Impl implements NonUnion,Primitive { public Byte(Attribute... attributes) { super(attributes); } } /** * Represents the set of (unbound) integer values. Since integer types in * Whiley are unbounded, there is no equivalent to Java's * <code>MIN_VALUE</code> and <code>MAX_VALUE</code> for <code>int</code> * types. * * @author David J. Pearce * */ public static final class Int extends SyntacticElement.Impl implements NonUnion,Primitive { public Int(Attribute... attributes) { super(attributes); } } /** * Represents a nominal type, which is of the form: * * <pre> * NominalType ::= Identifier ('.' Identifier)* * </pre> * * 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 final class Nominal extends SyntacticElement.Impl implements NonUnion { public final ArrayList<String> names; public Nominal(Collection<String> names, Attribute... attributes) { super(attributes); this.names = new ArrayList<>(names); } } /** * Represents a list type, which is of the form: * * <pre> * ArrayType ::= Type '[' ']' * </pre> * * @return */ public static final class Array extends SyntacticElement.Impl implements NonUnion { public final SyntacticType element; public Array(SyntacticType element, Attribute... attributes) { super(attributes); this.element = element; } } /** * Parse a negation type, which is of the form: * * <pre> * ReferenceType ::= '!' Type * </pre> * * @return */ public static final class Negation extends SyntacticElement.Impl implements NonUnion { public final SyntacticType element; public Negation(SyntacticType element, Attribute... attributes) { this.element = element; } } /** * Represents a union type, which is of the form: * * <pre> * UnionType ::= IntersectionType ('|' IntersectionType)* * </pre> * * Union types are used to compose types together. For example, the type * <code>int|null</code> represents the type which is either an * <code>int</code> or <code>null</code>. * * @return */ public static final class Union extends SyntacticElement.Impl implements SyntacticType { public final ArrayList<NonUnion> bounds; public Union(Collection<NonUnion> bounds, Attribute... attributes) { super(attributes); if (bounds.size() < 2) { new IllegalArgumentException( "Cannot construct a type union with fewer than two bounds"); } this.bounds = new ArrayList<>(bounds); } public Union(ArrayList<NonUnion> bounds, java.util.Collection<Attribute> attributes) { super(attributes); if (bounds.size() < 2) { new IllegalArgumentException( "Cannot construct a type union with fewer than two bounds"); } this.bounds = new ArrayList<>(bounds); } } /** * Represents an intersection type, which is of the form: * * <pre> * IntersectionType ::= BaseType ('&' BaseType)* * </pre> * * Intersection types are used to unify types together. For example, the * type <code>{int x, int y}&MyType</code> represents the type which is both * an instanceof of <code>{int x, int y}</code> and an instance of * <code>MyType</code>. * * @return */ public static final class Intersection extends SyntacticElement.Impl implements SyntacticType { public final ArrayList<SyntacticType> bounds; public Intersection(Collection<SyntacticType> bounds, Attribute... attributes) { super(attributes); if (bounds.size() < 2) { new IllegalArgumentException( "Cannot construct a type intersection with fewer than two bounds"); } this.bounds = new ArrayList<>(bounds); } public Intersection(ArrayList<SyntacticType> bounds, Collection<Attribute> attributes) { super(attributes); if (bounds.size() < 2) { new IllegalArgumentException( "Cannot construct a type intersection with fewer than two bounds"); } this.bounds = new ArrayList<>(bounds); } } /** * Parse a reference type, which is of the form: * * <pre> * ReferenceType ::= '&' Type * </pre> * * @return */ public static final class Reference extends SyntacticElement.Impl implements NonUnion { public final SyntacticType element; public final String lifetime; public final boolean lifetimeWasExplicit; public Reference(SyntacticType element, String lifetime, boolean lifetimeWasExplicit, Attribute... attributes) { this.element = element; this.lifetime = lifetime; this.lifetimeWasExplicit = lifetimeWasExplicit; } } /** * Represents record type, which is of the form: * * <pre> * RecordType ::= '{' Type Identifier (',' Type Identifier)* [ ',' "..." ] '}' * </pre> * * @return */ public static final class Record extends SyntacticElement.Impl implements NonUnion { public final HashMap<String,SyntacticType> types; public final boolean isOpen; public Record(boolean isOpen, java.util.Map<String, SyntacticType> types, Attribute... attributes) { super(attributes); if(types.size() == 0) { throw new IllegalArgumentException( "Cannot create type tuple with no fields"); } this.isOpen = isOpen; this.types = new HashMap<>(types); } public Record(boolean isOpen, java.util.Map<String, SyntacticType> types, java.util.List<Attribute> attributes) { super(attributes); if(types.size() == 0) { throw new IllegalArgumentException( "Cannot create type tuple with no fields"); } this.isOpen = isOpen; this.types = new HashMap<>(types); } } public abstract static class FunctionOrMethod extends SyntacticElement.Impl implements NonUnion { public final ArrayList<SyntacticType> returnTypes; public final ArrayList<SyntacticType> paramTypes; public final ArrayList<String> contextLifetimes; public final ArrayList<String> lifetimeParameters; public FunctionOrMethod(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Collection<String> contextLifetimes, Collection<String> lifetimeParameters, Attribute... attributes) { super(attributes); this.returnTypes = new ArrayList<>(returnTypes); this.paramTypes = new ArrayList<>(paramTypes); this.contextLifetimes = new ArrayList<>(contextLifetimes); this.lifetimeParameters = new ArrayList<>(lifetimeParameters); for(SyntacticType t : paramTypes) { if(t == null) { throw new IllegalArgumentException("parameter cannot be null"); } } for(SyntacticType t : returnTypes) { if(t == null) { throw new IllegalArgumentException("return cannot be null"); } } for(String s : lifetimeParameters) { if(s == null) { throw new IllegalArgumentException("lifetime cannot be null"); } } } public FunctionOrMethod(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Collection<String> contextLifetimes, Collection<String> lifetimeParameters, Collection<Attribute> attributes) { super(attributes); this.returnTypes = new ArrayList<>(returnTypes); this.paramTypes = new ArrayList<>(paramTypes); this.contextLifetimes = new ArrayList<>(contextLifetimes); this.lifetimeParameters = new ArrayList<>(lifetimeParameters); for(SyntacticType t : paramTypes) { if(t == null) { throw new IllegalArgumentException("parameter cannot be null"); } } for(SyntacticType t : returnTypes) { if(t == null) { throw new IllegalArgumentException("return cannot be null"); } } for(String s : lifetimeParameters) { if(s == null) { throw new IllegalArgumentException("lifetime cannot be null"); } } } } public static class Function extends FunctionOrMethod implements NonUnion { public Function(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Attribute... attributes) { super(returnTypes,paramTypes,Collections.<String>emptySet(),Collections.<String>emptyList(),attributes); } public Function(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Collection<Attribute> attributes) { super(returnTypes,paramTypes,Collections.<String>emptySet(),Collections.<String>emptyList(),attributes); } } public static class Property extends FunctionOrMethod implements NonUnion { public Property(Collection<SyntacticType> paramTypes, Attribute... attributes) { super(Collections.EMPTY_LIST, paramTypes, Collections.<String>emptySet(), Collections.<String>emptyList(), attributes); } public Property(Collection<SyntacticType> paramTypes, Collection<Attribute> attributes) { super(Collections.EMPTY_LIST, paramTypes, Collections.<String>emptySet(), Collections.<String>emptyList(), attributes); } } public static class Method extends FunctionOrMethod implements NonUnion { public Method(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Collection<String> contextLifetimes, Collection<String> lifetimeParameters, Attribute... attributes) { super(returnTypes,paramTypes,contextLifetimes,lifetimeParameters,attributes); } public Method(Collection<SyntacticType> returnTypes, Collection<SyntacticType> paramTypes, Collection<String> contextLifetimes, Collection<String> lifetimeParameters, Collection<Attribute> attributes) { super(returnTypes,paramTypes,contextLifetimes,lifetimeParameters,attributes); } } }