/** * <copyright> * * This program and the accompanying materials are made available under the * terms of the BSD 3-clause license which accompanies this distribution. * * </copyright> */ package siple; import java.io.FileReader; import java.io.IOException; import java.io.StringReader; import beaver.Parser.Exception; /** * Instances of this class represent <i>SiPLE</i> types. Constraints:<br> * 1) Iff {@link Type#domain} <tt>==</tt> {@link Domains#Procedure} or * {@link Domains#Pointer}, {@link #rtype} must not be <tt>null</tt>, * otherwise {@link #rtype} must be <tt>null</tt>.<br> * 2) Iff {@link Type#domain} <tt>==</tt> {@link Domains#Pointer}, * {@link #rtype} must not be {@link #Undefined}. * @author C. Bürger */ public class Type { /** * Enumeration of SiPLE's basic type domains. * @author C. Bürger */ public static enum Domains { Boolean, Integer, Real, Pointer, Procedure, Undefined, ERROR_TYPE } /** * The type's base type restricting its domain. */ public Domains domain = null; /** * The parameter types, iff the {@link #domain base type} is * {@link Domains#Procedure}. */ public Type[] paras = {}; /** * The return type, iff the {@link #domain base type} is * {@link Domains#Procedure} or {@link Domains#Pointer}. */ public Type rtype = null; private Type(Domains domain) {this.domain = domain;} /** Prototype representing a boolean type. */ public static final Type Boolean = new Type(Domains.Boolean); /** Prototype representing an integer type. */ public static final Type Integer = new Type(Domains.Integer); /** Prototype representing a real type. */ public static final Type Real = new Type(Domains.Real); /** Prototype representing an undefined type. */ public static final Type Undefined = new Type(Domains.Undefined); /** Prototype representing an error type. */ public static final Type ERROR_TYPE = new Type(Domains.ERROR_TYPE); /** * Parses a given value string to a concrete instance of this class. It is called by the * basic EMF EFactory to create instances through the EDataType Binding. * * @param value String representation of an instance of Type. * @return A corresponding instance. */ public static Type valueOf(String value){ if("Integer".equals(value)){ return Integer; } else if("Boolean".equals(value)){ return Boolean; } else if("Real".equals(value)){ return Real; } else if(value.startsWith("Pointer") || value.startsWith("Procedure")){ Lexer scanner = new Lexer(new StringReader(value)); Parser parser = new Parser(); try { Type type = (Type)parser.parse(scanner, Parser.AltGoals.Type); return type; } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } //consider pointers and procedure types too! return Undefined; } /** * Construct a pointer for the given type. * @param rtype Type the resulting pointer points to. * @return Pointer of type "pointer to <tt>rtype</tt>". */ public static Type newPointer(Type rtype) { Type type = new Type(Domains.Pointer); type.rtype = rtype; return type; } /** * Construct a procedure for the given parameter and return types. * @param paras Array of parameter types. * @param rtype Return type. * @return Procedure of type "procedure with parameters <tt>paras</tt> * and return type <tt>rtype</tt>". */ public static Type newProcedure(Type[] paras, Type rtype) { Type type = new Type(Domains.Procedure); type.paras = paras; type.rtype = rtype; return type; } /** * Return, if this type represents a boolean. * @return <tt>true</tt>, iff this type represents a boolean. */ public boolean isBoolean() {return this.domain == Domains.Boolean;} /** Similar to {@link #isBoolean()}. */ public boolean isInteger() {return this.domain == Domains.Integer;} /** Similar to {@link #isBoolean()}. */ public boolean isReal() {return this.domain == Domains.Real;} /** Similar to {@link #isBoolean()}. */ public boolean isPointer() {return this.domain == Domains.Pointer;} /** Similar to {@link #isBoolean()}. */ public boolean isProcedure() {return this.domain == Domains.Procedure;} /** Similar to {@link #isBoolean()}. */ public boolean isUndefined() {return this.domain == Domains.Undefined;} /** Similar to {@link #isBoolean()}. */ public boolean isError() {return this.domain == Domains.ERROR_TYPE;} /** * Compare two types for equality; For a variant returning a truth value * see {@link #bequals(Type, Type)}. * @param t1 The first type to compare. * @param t2 The second type to compare. * @return t1, iff both types are equal, {@link Domains#ERROR_TYPE} otherwise. */ public static Type equals(Type t1, Type t2) { if (t1 == null || t2 == null) if (t1 != t2) return ERROR_TYPE; else return null; if (t1.domain == t2.domain) { if (!bequals(t1.rtype, t2.rtype)) return ERROR_TYPE; if (t1.paras.length != t2.paras.length) return ERROR_TYPE; for (int i = 0; i < t1.paras.length; i++) if (!bequals(t1.paras[i], t2.paras[i])) return ERROR_TYPE; return t1; } return ERROR_TYPE; } /** * For details see {@link #equals(Type, Type)}. * @return <tt>true</tt>, iff <tt>t1</tt> and <tt>t2</tt> represent the * same type. */ public static boolean bequals(Type t1, Type t2) { return equals(t1, t2) != ERROR_TYPE; } /** * Pretty print the represented type as written in SiPLE. * @return SiPLE code for this type. */ public String toString() { StringBuilder result = new StringBuilder(); result.append(domain); switch (domain) { case Procedure: result.append(" ("); for (Type para:paras) result.append(para.toString()); result.append(")"); if (rtype != null) { result.append(":"); result.append(rtype.toString()); } break; case Pointer: result.append("("); result.append(rtype.toString()); result.append(")"); } return result.toString(); } }