package de.unisiegen.tpml.core.expressions ; import java.util.ArrayList ; import de.unisiegen.tpml.core.Messages ; import de.unisiegen.tpml.core.exceptions.LanguageParserMultiException ; import de.unisiegen.tpml.core.exceptions.NotOnlyFreeVariableException ; import de.unisiegen.tpml.core.interfaces.DefaultExpressions ; import de.unisiegen.tpml.core.interfaces.DefaultTypes ; import de.unisiegen.tpml.core.interfaces.ExpressionOrType ; import de.unisiegen.tpml.core.interfaces.SortedChildren ; import de.unisiegen.tpml.core.latex.DefaultLatexCommand ; import de.unisiegen.tpml.core.latex.LatexCommandList ; import de.unisiegen.tpml.core.latex.LatexStringBuilder ; import de.unisiegen.tpml.core.latex.LatexStringBuilderFactory ; import de.unisiegen.tpml.core.prettyprinter.PrettyStringBuilder ; import de.unisiegen.tpml.core.prettyprinter.PrettyStringBuilderFactory ; import de.unisiegen.tpml.core.typechecker.TypeSubstitution ; import de.unisiegen.tpml.core.types.MonoType ; import de.unisiegen.tpml.core.types.Type ; import de.unisiegen.tpml.core.types.TypeVariable ; /** * Represents the <b>(COERCION)</b> expression in the expression hierarchy. * * @author Christian Fehler * @version $Rev:1092 $ * @see Expression */ public final class Coercion extends Expression implements DefaultTypes , DefaultExpressions , SortedChildren { /** * Indeces of the child {@link Expression}s. */ private static final int [ ] INDICES_E = new int [ ] { - 1 } ; /** * Indeces of the child {@link Type}s. */ private static final int [ ] INDICES_TYPE = new int [ ] { 1 , 2 } ; /** * String for the case that the expression is null. */ private static final String EXPRESSION_NULL = "expression is null" ; //$NON-NLS-1$ /** * String for the case that tau1 is null. */ private static final String TAU1_NULL = "tau1 is null" ; //$NON-NLS-1$ /** * String for the case that tau2 is null. */ private static final String TAU2_NULL = "tau2 is null" ; //$NON-NLS-1$ /** * The caption of this {@link Expression}. */ private static final String CAPTION = Expression.getCaption ( Coercion.class ) ; /** * Returns a set of needed latex commands for this latex printable object. * * @return A set of needed latex commands for this latex printable object. */ public static LatexCommandList getLatexCommandsStatic ( ) { LatexCommandList commands = new LatexCommandList ( ) ; commands.add ( new DefaultLatexCommand ( LATEX_COERCION , 3 , "\\color{" //$NON-NLS-1$ + LATEX_COLOR_EXPRESSION + "}(#1\\colon\\ #2\\ <\\colon\\ #3)" , "e" , //$NON-NLS-1$//$NON-NLS-2$ "tau1" , "tau2" ) ) ; //$NON-NLS-1$//$NON-NLS-2$ return commands ; } /** * The types. * * @see #getTypes() */ private MonoType [ ] types ; /** * The expression. */ private Expression [ ] expressions ; /** * Allocates a new coercion. * * @param pExpression The body. * @param pTau1 The first type. * @param pTau2 The second type. * @throws NullPointerException If something is null. */ public Coercion ( Expression pExpression , MonoType pTau1 , MonoType pTau2 ) { if ( pExpression == null ) { throw new NullPointerException ( EXPRESSION_NULL ) ; } if ( pTau1 == null ) { throw new NullPointerException ( TAU1_NULL ) ; } if ( pTau2 == null ) { throw new NullPointerException ( TAU2_NULL ) ; } // Expression this.expressions = new Expression [ ] { pExpression } ; this.expressions [ 0 ].setParent ( this ) ; // Type this.types = new MonoType [ ] { pTau1 , pTau2 } ; this.types [ 0 ].setParent ( this ) ; this.types [ 1 ].setParent ( this ) ; checkTypeVariables ( ) ; } /** * Allocates a new coercion. * * @param pExpression The body. * @param pTau1 The first type. * @param pTau2 The second type. * @param pParserStartOffset The start offset of this {@link Expression} in * the source code. * @param pParserEndOffset The end offset of this {@link Expression} in the * source code. * @throws NullPointerException If something is null. */ public Coercion ( Expression pExpression , MonoType pTau1 , MonoType pTau2 , int pParserStartOffset , int pParserEndOffset ) { this ( pExpression , pTau1 , pTau2 ) ; this.parserStartOffset = pParserStartOffset ; this.parserEndOffset = pParserEndOffset ; } /** * Checks if a child type contains {@link TypeVariable}s. */ public void checkTypeVariables ( ) { ArrayList < TypeVariable > list = new ArrayList < TypeVariable > ( ) ; list.addAll ( this.types [ 0 ].getTypeVariablesFree ( ) ) ; list.addAll ( this.types [ 1 ].getTypeVariablesFree ( ) ) ; if ( list.size ( ) > 0 ) { String [ ] message = new String [ list.size ( ) ] ; int [ ] startOffset = new int [ list.size ( ) ] ; int [ ] endOffset = new int [ list.size ( ) ] ; for ( int i = 0 ; i < list.size ( ) ; i ++ ) { message [ i ] = Messages.getString ( "Parser.18" ) ; //$NON-NLS-1$ startOffset [ i ] = list.get ( i ).getParserStartOffset ( ) ; endOffset [ i ] = list.get ( i ).getParserEndOffset ( ) ; } throw new LanguageParserMultiException ( message , startOffset , endOffset ) ; } } /** * {@inheritDoc} * * @see Expression#clone() */ @ Override public Coercion clone ( ) { return new Coercion ( this.expressions [ 0 ].clone ( ) , this.types [ 0 ] .clone ( ) , this.types [ 1 ].clone ( ) ) ; } /** * {@inheritDoc} * * @see Expression#equals(Object) */ @ Override public boolean equals ( Object pObject ) { if ( pObject instanceof Coercion ) { Coercion other = ( Coercion ) pObject ; return ( ( this.expressions [ 0 ].equals ( other.expressions [ 0 ] ) ) && ( this.types [ 0 ].equals ( other.types [ 0 ] ) ) && ( this.types [ 1 ] .equals ( other.types [ 1 ] ) ) ) ; } return false ; } /** * {@inheritDoc} */ @ Override public String getCaption ( ) { return CAPTION ; } /** * Returns the body of the lambda expression. * * @return the bodyof the lambda expression. */ public Expression getE ( ) { return this.expressions [ 0 ] ; } /** * Returns the sub expressions. * * @return the sub expressions. */ public Expression [ ] getExpressions ( ) { return this.expressions ; } /** * Returns the indices of the child {@link Expression}s. * * @return The indices of the child {@link Expression}s. */ public int [ ] getExpressionsIndex ( ) { return Coercion.INDICES_E ; } /** * Returns a set of needed latex commands for this latex printable object. * * @return A set of needed latex commands for this latex printable object. */ @ Override public LatexCommandList getLatexCommands ( ) { LatexCommandList commands = super.getLatexCommands ( ) ; commands.add ( getLatexCommandsStatic ( ) ) ; return commands ; } /** * Returns the {@link Expression} and the {@link Type}s in the right sorting. * * @return The {@link Expression} and the {@link Type}s in the right sorting. * @see SortedChildren#getSortedChildren() */ public ExpressionOrType [ ] getSortedChildren ( ) { return new ExpressionOrType [ ] { this.expressions [ 0 ] , this.types [ 0 ] , this.types [ 1 ] } ; } /** * Returns the first type.. * * @return The first type. */ public MonoType getTau1 ( ) { return this.types [ 0 ] ; } /** * Returns the second type.. * * @return The second type. */ public MonoType getTau2 ( ) { return this.types [ 1 ] ; } /** * Returns the types. * * @return The types. */ public MonoType [ ] getTypes ( ) { return this.types ; } /** * Returns the indices of the child {@link Type}s. * * @return The indices of the child {@link Type}s. */ public int [ ] getTypesIndex ( ) { return Coercion.INDICES_TYPE ; } /** * {@inheritDoc} * * @see Expression#hashCode() */ @ Override public int hashCode ( ) { return this.expressions [ 0 ].hashCode ( ) + this.types [ 0 ].hashCode ( ) + this.types [ 1 ].hashCode ( ) ; } /** * {@inheritDoc} * * @see Expression#substitute(Identifier, Expression) */ @ Override public Coercion substitute ( Identifier pId , Expression pExpression ) { if ( pExpression.getIdentifierFreeNotOnlyVariable ( ) ) { throw new NotOnlyFreeVariableException ( ) ; } Expression newE = this.expressions [ 0 ].substitute ( pId , pExpression ) ; return new Coercion ( newE , this.types [ 0 ] , this.types [ 1 ] ) ; } /** * {@inheritDoc} * * @see Expression#substitute(TypeSubstitution) */ @ Override public Coercion substitute ( TypeSubstitution pTypeSubstitution ) { Expression newE = this.expressions [ 0 ].substitute ( pTypeSubstitution ) ; MonoType newTau1 = this.types [ 0 ].substitute ( pTypeSubstitution ) ; MonoType newTau2 = this.types [ 1 ].substitute ( pTypeSubstitution ) ; return new Coercion ( newE , newTau1 , newTau2 ) ; } /** * {@inheritDoc} * * @see Expression#toLatexStringBuilder(LatexStringBuilderFactory,int) */ @ Override public LatexStringBuilder toLatexStringBuilder ( LatexStringBuilderFactory pLatexStringBuilderFactory , int pIndent ) { LatexStringBuilder builder = pLatexStringBuilderFactory.newBuilder ( PRIO_COERCION , LATEX_COERCION , pIndent , this.toPrettyString ( ) .toString ( ) , this.expressions [ 0 ].toPrettyString ( ) .toString ( ) , this.types [ 0 ].toPrettyString ( ).toString ( ) , this.types [ 1 ].toPrettyString ( ).toString ( ) ) ; builder .addBuilder ( this.expressions [ 0 ].toLatexStringBuilder ( pLatexStringBuilderFactory , pIndent + LATEX_INDENT ) , PRIO_COERCION_E ) ; builder.addBreak ( ) ; builder.addBuilder ( this.types [ 0 ].toLatexStringBuilder ( pLatexStringBuilderFactory , pIndent + LATEX_INDENT ) , PRIO_COERCION_TAU1 ) ; builder.addBreak ( ) ; builder.addBuilder ( this.types [ 1 ].toLatexStringBuilder ( pLatexStringBuilderFactory , pIndent + LATEX_INDENT ) , PRIO_COERCION_TAU2 ) ; return builder ; } /** * {@inheritDoc} * * @see Expression#toPrettyStringBuilder(PrettyStringBuilderFactory) */ @ Override public PrettyStringBuilder toPrettyStringBuilder ( PrettyStringBuilderFactory pPrettyStringBuilderFactory ) { if ( this.prettyStringBuilder == null ) { this.prettyStringBuilder = pPrettyStringBuilderFactory.newBuilder ( this , PRIO_COERCION ) ; this.prettyStringBuilder.addText ( PRETTY_LPAREN ) ; this.prettyStringBuilder.addBuilder ( this.expressions [ 0 ] .toPrettyStringBuilder ( pPrettyStringBuilderFactory ) , PRIO_COERCION_E ) ; this.prettyStringBuilder.addText ( PRETTY_COLON ) ; this.prettyStringBuilder.addText ( PRETTY_SPACE ) ; this.prettyStringBuilder.addBreak ( ) ; this.prettyStringBuilder.addBuilder ( this.types [ 0 ] .toPrettyStringBuilder ( pPrettyStringBuilderFactory ) , PRIO_COERCION_TAU1 ) ; this.prettyStringBuilder.addText ( PRETTY_SPACE ) ; this.prettyStringBuilder.addText ( PRETTY_SUBTYPE ) ; this.prettyStringBuilder.addText ( PRETTY_SPACE ) ; this.prettyStringBuilder.addBreak ( ) ; this.prettyStringBuilder.addBuilder ( this.types [ 1 ] .toPrettyStringBuilder ( pPrettyStringBuilderFactory ) , PRIO_COERCION_TAU2 ) ; this.prettyStringBuilder.addText ( PRETTY_RPAREN ) ; } return this.prettyStringBuilder ; } }