/******************************************************************************* * Copyright (c) 2009-2016 CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.interpreter.types; import java.util.Random; import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; import org.rascalmpl.value.IConstructor; import org.rascalmpl.value.ISet; import org.rascalmpl.value.ISetWriter; import org.rascalmpl.value.IValueFactory; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory.TypeReifier; import org.rascalmpl.value.type.TypeStore; import org.rascalmpl.values.ValueFactoryFactory; /** * A failure type is external to the type hierarchy. It is not even a sub-type of `value`. * It is used to continue after a partially succesfull type check and provide user feedback. */ public class FailureType extends RascalType { private final ISet messages; public FailureType(ISet messages) { this.messages = messages; } public ISet getMessages() { return messages; } public static class Reifier implements TypeReifier { @Override public Type getSymbolConstructorType() { return symbols().typeSymbolConstructor("failure", tf().setType(tf().abstractDataType(new TypeStore(), "Message")), "messages"); } @Override public Type fromSymbol(IConstructor symbol, TypeStore store, Function<IConstructor, Set<IConstructor>> grammar) { return RTF.failureType((ISet) symbol.get("messages")); } @Override public IConstructor toSymbol(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set<IConstructor> done) { return vf.constructor(getSymbolConstructorType(), ((FailureType) type).getMessages()); } @Override public void asProductions(Type type, IValueFactory vf, TypeStore store, ISetWriter grammar, Set<IConstructor> done) { return; } @Override public boolean isRecursive() { return false; } @Override public Type randomInstance(Supplier<Type> next, TypeStore store, Random rnd) { return RascalTypeFactory.getInstance().failureType(ValueFactoryFactory.getValueFactory().set()); } } @Override public TypeReifier getTypeReifier() { return new Reifier(); } @Override public Type asAbstractDataType() { return getTypeReifier().symbols().symbolADT(); } @Override public boolean isFailure() { return true; } @Override public String getName() { return "failure"; } @Override public <T, E extends Throwable> T accept(IRascalTypeVisitor<T, E> visitor) throws E { return visitor.visitFailureType(this); } @Override protected boolean isSupertypeOf(RascalType type) { return type.isSubtypeOfFailure(this); } @Override protected Type lubWithValue(Type type) { return this; } @Override protected Type lubWithVoid(Type type) { return this; } @Override protected Type glbWithVoid(Type type) { return this; } @Override protected Type glbWithValue(Type type) { return this; } @Override protected Type lub(RascalType type) { return type.lubWithFailure(this); } @Override protected Type glb(RascalType type) { return type.glbWithFailure(this); } @Override protected boolean isSubtypeOfValue(Type type) { // failures never fit anywhere, not even for values! return false; } @Override public boolean isSubtypeOfFailure(RascalType type) { // failures never fit anywhere, not even with themselves. return false; } @Override protected Type lubWithFailure(RascalType type) { // let's just collect error messages here return RascalTypeFactory.getInstance().failureType(messages.union(((FailureType) type).getMessages())); } @Override protected Type glbWithFailure(RascalType type) { // let's just collect error messages here return RascalTypeFactory.getInstance().failureType(messages.union(((FailureType) type).getMessages())); } @Override public String toString() { return "failure[" + getMessages() + "]"; } @Override public boolean equals(Object obj) { if(obj == null) return false; if (obj.getClass() == getClass()) { return messages.equals(((FailureType) obj).messages); } return false; } @Override public int hashCode() { return 93 + messages.hashCode(); } }