From be1632c6c4e933a117cf2286a0c6c6acb70f51ac Mon Sep 17 00:00:00 2001 From: dgelessus <dgelessus@users.noreply.github.com> Date: Fri, 6 Oct 2023 11:29:10 +0200 Subject: [PATCH] Update to Rodin 3.3 sources --- META-INF/MANIFEST.MF | 2 +- build.gradle | 2 +- .../eventb/core/ast/ExtendedPredicate.java | 17 +- src/org/eventb/core/ast/Formula.java | 10 +- src/org/eventb/core/ast/FreeIdentifier.java | 21 +- src/org/eventb/core/ast/ISpecialization.java | 179 ++++- src/org/eventb/core/ast/ITypeEnvironment.java | 8 +- src/org/eventb/core/ast/Type.java | 7 +- .../core/ast/extension/ExtensionFactory.java | 25 +- .../core/ast/extension/IPriorityMediator.java | 15 +- .../core/ast/BindingSubstitution.java | 4 +- .../core/ast/BoundIdentDeclRemover.java | 8 +- .../core/ast/DefaultTypeCheckingRewriter.java | 69 +- .../internal/core/ast/SimpleSubstitution.java | 8 +- .../internal/core/ast/Specialization.java | 691 ++++++++++++++---- .../eventb/internal/core/ast/Substitute.java | 127 ++-- .../internal/core/ast/Substitution.java | 6 +- .../internal/core/ast/TypeRewriter.java | 8 +- .../internal/core/ast/datatype/Datatype.java | 43 +- .../core/ast/datatype/DatatypeRewriter.java | 79 +- .../ast/datatype/DatatypeTranslation.java | 8 +- .../ast/extension/ExtensionSignature.java | 145 ++-- .../ast/extension/ExtensionTranslation.java | 108 ++- .../ast/extension/ExtensionTranslator.java | 147 +++- .../ast/extension/FunctionalTypeBuilder.java | 91 +++ .../ast/extension/TranslatorRegistry.java | 40 +- .../internal/core/parser/SubParsers.java | 55 +- 27 files changed, 1445 insertions(+), 478 deletions(-) create mode 100644 src/org/eventb/internal/core/ast/extension/FunctionalTypeBuilder.java diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index 50e84de..91b52c6 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eventb.core.ast;singleton:=true -Bundle-Version: 3.2.0.qualifier +Bundle-Version: 3.3.0.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: org.eventb.core.ast, diff --git a/build.gradle b/build.gradle index ec7a6e3..c9f019f 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } project.group = 'de.hhu.stups' -project.version = "3.2.1" +project.version = "3.3.0-SNAPSHOT" final isSnapshot = project.version.endsWith("-SNAPSHOT") sourceSets { diff --git a/src/org/eventb/core/ast/ExtendedPredicate.java b/src/org/eventb/core/ast/ExtendedPredicate.java index 2ae4f52..32c5d9c 100644 --- a/src/org/eventb/core/ast/ExtendedPredicate.java +++ b/src/org/eventb/core/ast/ExtendedPredicate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2013 Systerel and others. + * Copyright (c) 2010, 2016 Systerel and others. * 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 @@ -13,9 +13,12 @@ package org.eventb.core.ast; import static org.eventb.core.ast.AssociativeHelper.getSyntaxTreeHelper; import static org.eventb.core.ast.ExtensionHelper.makeParserPrinter; import static org.eventb.core.ast.extension.IOperatorProperties.FormulaType.PREDICATE; +import static org.eventb.core.ast.extension.IOperatorProperties.Notation.INFIX; import static org.eventb.core.ast.extension.IOperatorProperties.Notation.PREFIX; import static org.eventb.internal.core.ast.extension.ArityCoverage.ANY; import static org.eventb.internal.core.ast.extension.ArityCoverage.ONE_OR_MORE; +import static org.eventb.internal.core.ast.extension.ArityCoverage.TWO; +import static org.eventb.internal.core.ast.extension.ArityCoverage.NONE; import java.util.ArrayList; import java.util.Arrays; @@ -66,6 +69,16 @@ public class ExtendedPredicate extends Predicate implements IExtendedFormula { return new SubParsers.ExtendedPredParen(kind, tag); } + }, + + EXTENDED_RELATIONAL_PREDICATE(INFIX, PREDICATE, TWO, NONE, TWO, false) { + + @Override + protected IParserPrinter<ExtendedPredicate> makeParser(int kind, + int tag) { + return new SubParsers.ExtendedRelationalPredicateParser(kind, tag); + } + }, ; @@ -98,7 +111,7 @@ public class ExtendedPredicate extends Predicate implements IExtendedFormula { @Override public boolean isSpaced() { - return false; + return ExtendedPredicateParsers.this.getOperatorCoverage().getNotation() == INFIX; } @Override diff --git a/src/org/eventb/core/ast/Formula.java b/src/org/eventb/core/ast/Formula.java index 3d76447..39fbe60 100644 --- a/src/org/eventb/core/ast/Formula.java +++ b/src/org/eventb/core/ast/Formula.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2014 ETH Zurich and others. + * Copyright (c) 2005, 2017 ETH Zurich and others. * 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 @@ -2393,13 +2393,19 @@ public abstract class Formula<T extends Formula<T>> { * if this formula is an assignment * @throws IllegalStateException * if this formula is not type-checked. + * @throws IllegalArgumentException + * if the given specialization is not compatible with this + * formula, that is the specialization contains a substitution + * for an identifier with the same name as an identifier in this + * formula, but with a different type * * @since 2.6 */ public T specialize(ISpecialization specialization) { ensureTypeChecked(); final Specialization spec = (Specialization) specialization; - return rewrite(spec); + spec.prepare(this); + return rewrite(spec.getFormulaRewriter()); } /** diff --git a/src/org/eventb/core/ast/FreeIdentifier.java b/src/org/eventb/core/ast/FreeIdentifier.java index 37978b9..81a0241 100644 --- a/src/org/eventb/core/ast/FreeIdentifier.java +++ b/src/org/eventb/core/ast/FreeIdentifier.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2013 ETH Zurich and others. + * Copyright (c) 2005, 2017 ETH Zurich and others. * 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 @@ -297,10 +297,25 @@ public class FreeIdentifier extends Identifier { return false; } + /** + * Returns the given type corresponding to this type-checked identifier. + * <p> + * The returned type is <em>not</em> the type of this identifier. + * </p> + * + * @return the given type represented by this identifier + * @throws IllegalStateException + * when this identifier is not a given type or is not + * type-checked + * @see Type#toExpression() + * @see #isATypeExpression() + * @since 3.3 change return type to GivenType + */ @Override - public Type toType() { + public GivenType toType() { if (!isATypeExpression()) { - return super.toType(); + throw new IllegalStateException( + "Identifier does not denote a type: " + toString()); } return getFactory().makeGivenType(this); } diff --git a/src/org/eventb/core/ast/ISpecialization.java b/src/org/eventb/core/ast/ISpecialization.java index ae2524f..b89d27f 100644 --- a/src/org/eventb/core/ast/ISpecialization.java +++ b/src/org/eventb/core/ast/ISpecialization.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2014 Systerel and others. + * Copyright (c) 2012, 2017 Systerel and others. * 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 @@ -7,18 +7,21 @@ * * Contributors: * Systerel - initial API and implementation + * University of Southampton - added support for predicate variables *******************************************************************************/ package org.eventb.core.ast; /** - * Common protocol for describing a specialization, which groups together a type - * substitution and a free identifier substitution in one object. It allows to - * specialize a formula by applying both substitutions at once. + * Common protocol for describing a specialization, which groups together type + * substitutions, free-identifier substitutions, and predicate-variable + * substitutions in one object. It allows to specialize a formula by applying + * all these substitutions at once. * <p> - * Instances of this class can be created only through a formula factory. Type - * and free identifier substitutions are then added one by one using - * <code>put()</code> methods. Finally, the instance is passed as argument to a - * <code>specialize()</code> method on a type, type environment or formula. + * Instances of this class can be created only through a formula factory. Type, + * free-identifier and predicate-variable substitutions are then added one by + * one using <code>put()</code> methods. Finally, the instance is passed as + * argument to a <code>specialize()</code> method on a type, type environment or + * formula. * </p> * <p> * The substitutions can also change the formula factory. Consequently, all @@ -26,9 +29,9 @@ package org.eventb.core.ast; * specialization. * </p> * <p> - * Both substitutions must be compatible, that is the expression to be + * These substitutions must be compatible, that is the expression to be * substituted for an identifier must bear a type which is the result of - * applying the type substitution to the type of the identifier. + * applying the type substitutions to the type of the identifier. * </p> * <p> * This condition must hold after every method call. This implies that a type @@ -52,19 +55,35 @@ package org.eventb.core.ast; * <code>T</code> for <code>x</code> of type <code>S</code>. * </p> * <p> - * This side-effect is made on purpose to ensure that successive applications of - * a specialization to several type environments or formulas are all compatible. + * When defining substitutions, a specialization also maintains a destination + * type environment. It contains all the identifiers that have been used in the + * right-hand sides of substitutions, as well as all identifiers that have + * occurred in a formula passed to <code>specialize()</code> methods and that + * have not been substituted. + * </p> + * <p> + * The purpose of this destination type environment, together with the automatic + * completion of substitutions ensures that successive applications of a + * specialization to several type environments or formulas are all compatible. * In particular, if a formula type-checks with respect to some type * environment, then the specialized formula also type-checks with the * specialized type environment, under the condition that both specialization * are performed with the same instance of this class. * </p> * <p> - * In the rare cases where this side-effect is not wanted, one can always clone + * Similarly, when specializing a formula, an instance of this class can change + * by side-effect in the following manner: For each predicate variable, not + * already part of the predicate variable substitution and which occurs in the + * formula, a new predicate variable substitution is added to this + * specialization. It maps that predicate variable to itself. + * </p> + * <p> + * In the rare cases where the side-effects are not wanted, one can always clone * a specialization object and use the clone to apply a specialization. * </p> * * @author Laurent Voisin + * @author htson - added support for predicate variables. * * @see FormulaFactory#makeSpecialization() * @see Type#specialize(ISpecialization) @@ -100,6 +119,11 @@ public interface ISpecialization { * substitution must be compatible with already registered substitutions * (for both given types and free identifiers). The value must have been * created by the same formula factory as this instance. + * </p> + * <p> + * This method can have side-effects, as described in + * {@link ISpecialization}. + * </p> * * @param type * given type to specialize @@ -110,6 +134,7 @@ public interface ISpecialization { * registered substitutions or the value has been created by * another formula factory * @see Type#getFactory() + * @see #canPut(GivenType, Type) */ void put(GivenType type, Type value); @@ -118,7 +143,7 @@ public interface ISpecialization { * * @param type * some given type - * @return the type to be substituted for the given given type of + * @return the type to be substituted for the given given type or * <code>null</code> if no substitution has been defined for the * given given type * @since 3.1 @@ -135,6 +160,10 @@ public interface ISpecialization { * bound identifiers, it is up to the caller to manage that they do not * escape their scope. The given expression must have been created by the * same formula factory as this instance. + * <p> + * This method can have side-effects, as described in + * {@link ISpecialization}. + * </p> * * @param ident * a typed identifier to substitute @@ -147,6 +176,7 @@ public interface ISpecialization { * created by another formula factory * @see Formula#isTypeChecked() * @see Formula#getFactory() + * @see #canPut(FreeIdentifier, Expression) */ void put(FreeIdentifier ident, Expression value); @@ -155,11 +185,130 @@ public interface ISpecialization { * * @param ident * a typed identifier - * @return the expression to be substituted for the given identifier of + * @return the expression to be substituted for the given identifier or * <code>null</code> if no substitution has been defined for the * given identifier * @since 3.1 */ Expression get(FreeIdentifier ident); + /** + * Checks whether the proposed type substitution is compatible with already + * registered substitutions (for given types, free identifiers, and + * predicate variables), i.e., if the precondition for + * {@link #put(GivenType, Type)} is satisfied. The value must have been + * created by the same formula factory as this instance. This method does + * <em>not</em> modify the specialization instance. + * + * @param type + * given type to specialize + * @param value + * replacement for the given type + * @return <code>true</code> if the proposed type substitution is compatible + * with already registered substitutions, <code>false</code> + * otherwise. + * @throws IllegalArgumentException + * if the value has been created by another formula factory + * @author htson + * @since 3.3 + */ + boolean canPut(GivenType type, Type value); + + /** + * Checks whether the proposed free-identifier substitution is compatible + * with already registered substitutions (for given types, free identifiers, + * and predicate variables), i.e., if the precondition of + * {@link #put(FreeIdentifier, Expression)} is satisfied. Both the type and + * the value must be type-checked. The value expression must have been + * created by the same formula factory as this instance. This method does + * <em>not</em> modify the specialization instance. + * + * @param ident + * a typed identifier to substitute + * @param value + * a typed expression to substitute for the given identifier + * @return <code>true</code> if the proposed free identifier substitution is + * compatible with already registered substitutions. Return + * <code>false</code> otherwise. + * @throws IllegalArgumentException + * if either parameter is not typed, or the value has been + * created by another formula factory + * @author htson + * @since 3.3 + */ + boolean canPut(FreeIdentifier ident, Expression value); + + /** + * Adds a new predicate variable substitution to this specialization. All + * substitutions will be applied in parallel when specializing a formula. + * The given predicate value must be typed, but needs not be well-formed. In + * case the predicate value contains bound identifiers, it is up to the + * caller to manage that they do not escape their scope. The given predicate + * value must have been created by the same formula factory as this + * instance. + * <p> + * This method can have side-effects, as described in + * {@link ISpecialization}. + * </p> + * + * @param predVar + * a predicate variable to substitute + * @param value + * a typed predicate to substitute for the given predicate + * variable. + * @return <code>true</code> if the proposed predicate variable substitution + * is compatible with already registered substitutions, and this + * specialization instance has been changed accordingly. Return + * <code>false</code> otherwise and this specialization instance is + * unchanged. + * @throws IllegalArgumentException + * if the value is not typed or has been created by another + * formula factory + * @see Formula#isTypeChecked() + * @see Formula#getFactory() + * @author htson + * @since 3.3 + */ + boolean put(PredicateVariable predVar, Predicate value); + + /** + * Returns the predicate to be substituted for the given predicate variable. + * + * @param predVar + * a predicate variable. + * @return the predicate to be substituted for the given predicate variable + * or <code>null</code> if no substitution has been defined for the + * given predicate variable + * @author htson + * @since 3.3 + */ + Predicate get(PredicateVariable predVar); + + /** + * Returns the set of given types to be substituted. + * + * @return the set of given types to be substituted + * @author htson + * @since 3.3 + */ + GivenType[] getTypes(); + + /** + * Returns the set of free identifiers to be substituted. + * + * @return the set of free identifiers to be substituted + * @author htson + * @since 3.3 + */ + FreeIdentifier[] getFreeIdentifiers(); + + /** + * Returns the set of predicate variables to be substituted. + * + * @return the set of predicate variables to be substituted + * @author htson + * @since 3.3 + */ + PredicateVariable[] getPredicateVariables(); + } diff --git a/src/org/eventb/core/ast/ITypeEnvironment.java b/src/org/eventb/core/ast/ITypeEnvironment.java index f9dc087..8c72b45 100644 --- a/src/org/eventb/core/ast/ITypeEnvironment.java +++ b/src/org/eventb/core/ast/ITypeEnvironment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2014 ETH Zurich and others. + * Copyright (c) 2005, 2017 ETH Zurich and others. * 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 @@ -271,6 +271,12 @@ public interface ITypeEnvironment { * the specialization to apply * @return the type environment obtained by applying the given * specialization to this type environment + * @throws IllegalArgumentException + * if the given specialization is not compatible with this type + * environment, that is the specialization contains a + * substitution for an identifier with the same name as an + * identifier in this type environment, but with a different + * type * @since 3.0 */ ITypeEnvironmentBuilder specialize(ISpecialization specialization); diff --git a/src/org/eventb/core/ast/Type.java b/src/org/eventb/core/ast/Type.java index fd6a72f..2bc492f 100644 --- a/src/org/eventb/core/ast/Type.java +++ b/src/org/eventb/core/ast/Type.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2014 ETH Zurich and others. + * Copyright (c) 2005, 2017 ETH Zurich and others. * 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 @@ -296,6 +296,11 @@ public abstract class Type { * @param specialization * the specialization to apply * @return a specialization of this type or <code>this</code> if unchanged + * @throws IllegalArgumentException + * if the given specialization is not compatible with this type, + * that is the specialization contains a substitution for an + * identifier with the same name as a given type in this type, + * but with a different type * @since 2.6 */ public final Type specialize(ISpecialization specialization) { diff --git a/src/org/eventb/core/ast/extension/ExtensionFactory.java b/src/org/eventb/core/ast/extension/ExtensionFactory.java index f97f779..91c3a19 100644 --- a/src/org/eventb/core/ast/extension/ExtensionFactory.java +++ b/src/org/eventb/core/ast/extension/ExtensionFactory.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Systerel and others. + * Copyright (c) 2010, 2016 Systerel and others. * 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 @@ -15,13 +15,14 @@ import static org.eventb.core.ast.extension.IOperatorProperties.MULTARY_2; import static org.eventb.core.ast.extension.IOperatorProperties.UNARY; import static org.eventb.core.ast.extension.IOperatorProperties.FormulaType.EXPRESSION; import static org.eventb.core.ast.extension.IOperatorProperties.FormulaType.PREDICATE; +import static org.eventb.core.ast.extension.IOperatorProperties.Notation.INFIX; import static org.eventb.core.ast.extension.IOperatorProperties.Notation.PREFIX; import org.eventb.core.ast.extension.IOperatorProperties.FormulaType; import org.eventb.internal.core.ast.extension.Arity; -import org.eventb.internal.core.ast.extension.TypeDistribs.MixedTypes; -import org.eventb.internal.core.ast.extension.TypeDistribs.AllSameType; import org.eventb.internal.core.ast.extension.ExtensionKind; +import org.eventb.internal.core.ast.extension.TypeDistribs.AllSameType; +import org.eventb.internal.core.ast.extension.TypeDistribs.MixedTypes; /** * @author Nicolas Beauger @@ -84,6 +85,24 @@ public class ExtensionFactory { return new ExtensionKind(PREFIX, formulaType, childTypes, false); } + /** + * Make an infix extension kind. + * + * @param formulaType + * type of the resulting formula + * @param childTypes + * type distribution of child formulae + * @param isAssociative + * <code>true</code> for associative kind, <code>false</code> + * otherwise + * @return a new extension kind + * @since 3.3 + */ + public static IExtensionKind makeInfixKind(FormulaType formulaType, + ITypeDistribution childTypes, boolean isAssociative) { + return new ExtensionKind(INFIX, formulaType, childTypes, isAssociative); + } + public static IArity makeArity(int min, int max) { return new Arity(min, max); } diff --git a/src/org/eventb/core/ast/extension/IPriorityMediator.java b/src/org/eventb/core/ast/extension/IPriorityMediator.java index 26563ad..a4d0804 100644 --- a/src/org/eventb/core/ast/extension/IPriorityMediator.java +++ b/src/org/eventb/core/ast/extension/IPriorityMediator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010 Systerel and others. + * Copyright (c) 2010, 2016 Systerel and others. * 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 @@ -18,7 +18,10 @@ package org.eventb.core.ast.extension; public interface IPriorityMediator { /** - * Adds a priority between operators of given ids. + * Adds a priority between the two operators with the given ids. + * <p> + * Both operators must belong to the same operator group. + * </p> * <p> * lowOpId operator gets a lower priority than highOpId operator. * </p> @@ -37,6 +40,9 @@ public interface IPriorityMediator { * an operator id * @throws CycleError * if adding the given priority introduces a cycle + * @throws IllegalArgumentException + * if the operators do not belong to the same operator group, or + * if one of the given operator ids has not been declared */ void addPriority(String lowOpId, String highOpId) throws CycleError; @@ -56,7 +62,8 @@ public interface IPriorityMediator { * a group id * @throws CycleError * if adding the given priority introduces a cycle + * @throws IllegalArgumentException + * if one of the given group ids has not been declared */ - void addGroupPriority(String lowGroupId, String highGroupId) - throws CycleError; + void addGroupPriority(String lowGroupId, String highGroupId) throws CycleError; } diff --git a/src/org/eventb/internal/core/ast/BindingSubstitution.java b/src/org/eventb/internal/core/ast/BindingSubstitution.java index 73208b9..7aa2ec7 100644 --- a/src/org/eventb/internal/core/ast/BindingSubstitution.java +++ b/src/org/eventb/internal/core/ast/BindingSubstitution.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2013 ETH Zurich and others. + * Copyright (c) 2005, 2016 ETH Zurich and others. * 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 @@ -41,7 +41,7 @@ public class BindingSubstitution extends SimpleSubstitution { super(ff); this.offset = identsToBind.size(); - map = new HashMap<FreeIdentifier, Substitute>(offset * 4 / 3 + 1); + map = new HashMap<FreeIdentifier, Substitute<Expression>>(offset * 4 / 3 + 1); int index = offset - 1; for (FreeIdentifier ident : identsToBind) { diff --git a/src/org/eventb/internal/core/ast/BoundIdentDeclRemover.java b/src/org/eventb/internal/core/ast/BoundIdentDeclRemover.java index 298239b..7065c26 100644 --- a/src/org/eventb/internal/core/ast/BoundIdentDeclRemover.java +++ b/src/org/eventb/internal/core/ast/BoundIdentDeclRemover.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2013 ETH Zurich and others. + * Copyright (c) 2005, 2016 ETH Zurich and others. * 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 @@ -33,7 +33,7 @@ public class BoundIdentDeclRemover extends Substitution { protected final List<BoundIdentDecl> newDecls; // Reversed array of substitutes - protected final Substitute[] substitutes; + protected final Substitute<Expression>[] substitutes; /** * Creates a new substitution for removing some bound identifier @@ -60,7 +60,9 @@ public class BoundIdentDeclRemover extends Substitution { assert decls.length == keep.length; final int lastIndex = decls.length - 1; - substitutes = new Substitute[keep.length]; + @SuppressWarnings("unchecked") + final Substitute<Expression>[] temp = new Substitute[keep.length]; + substitutes = temp; newDecls = new ArrayList<BoundIdentDecl>(decls.length); int newIndex = 0; // We need to traverse both arrays backward to compute the new indexes diff --git a/src/org/eventb/internal/core/ast/DefaultTypeCheckingRewriter.java b/src/org/eventb/internal/core/ast/DefaultTypeCheckingRewriter.java index fb73dd9..40fecde 100644 --- a/src/org/eventb/internal/core/ast/DefaultTypeCheckingRewriter.java +++ b/src/org/eventb/internal/core/ast/DefaultTypeCheckingRewriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Systerel and others. + * Copyright (c) 2012, 2016 Systerel and others. * 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 @@ -39,12 +39,20 @@ import org.eventb.core.ast.UnaryPredicate; /** * Default implementation of a type-checking rewriter that does not perform any - * rewrite. In this class, we do not use the <code>checkReplacement()</code> - * methods because the result bears the same type by construction. However, - * these methods must be used by sub-classes that actually perform a rewrite - * when it cannot be proven that the rewrite is always type-checked. + * rewrite by default. In this class, we do not use the + * <code>checkReplacement()</code> methods because the result bears the expected + * type by construction. However, these methods must be used by sub-classes that + * actually perform a rewrite when it cannot be proven that the rewrite is + * always type-checked. Note that these methods cannot be used in the case where + * types are also rewritten (it checks that the types did not change). * * <p> + * If a type rewriter is given to the constructor, then this class will + * implement type rewriting for all nodes. It is then expected to be sub-classed + * so that free identifiers (among others) are also rewritten to conform to the + * new type. + * </p> + * <p> * This implementation guarantees that a leaf node is rebuilt with the rewriter * factory if the factory of the node is different as required by * {@link ITypeCheckingRewriter}. Consequently, when extending this class, @@ -94,6 +102,13 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { this.typeRewriter = new TypeRewriter(ff); } + // Version with a type rewriter provided by the caller and which therefore + // allows to also modify the types at the same time. + public DefaultTypeCheckingRewriter(TypeRewriter typeRewriter) { + this.ff = typeRewriter.getFactory(); + this.typeRewriter = typeRewriter; + } + @Override public boolean autoFlatteningMode() { return false; @@ -126,11 +141,13 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public BoundIdentDecl rewrite(BoundIdentDecl src) { - if (ff == src.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && ff == src.getFactory()) { return src; } return ff.makeBoundIdentDecl(src.getName(), src.getSourceLocation(), - typeRewriter.rewrite(src.getType())); + trgType); } @Override @@ -146,11 +163,13 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public Expression rewrite(AtomicExpression src) { - if (ff == src.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && ff == src.getFactory()) { return src; } return ff.makeAtomicExpression(src.getTag(), src.getSourceLocation(), - typeRewriter.rewrite(src.getType())); + trgType); } @Override @@ -170,22 +189,26 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public Expression rewrite(BoundIdentifier src) { - if (ff == src.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && ff == src.getFactory()) { return src; } return ff.makeBoundIdentifier(src.getBoundIndex(), - src.getSourceLocation(), typeRewriter.rewrite(src.getType())); + src.getSourceLocation(), trgType); } @Override public Expression rewrite(ExtendedExpression src, boolean changed, Expression[] newChildExprs, Predicate[] newChildPreds) { - if (!changed && ff == src.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && !changed && ff == src.getFactory()) { return src; } return ff.makeExtendedExpression(src.getExtension(), newChildExprs, newChildPreds, src.getSourceLocation(), - typeRewriter.rewrite(src.getType())); + trgType); } @Override @@ -200,11 +223,13 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public Expression rewrite(FreeIdentifier src) { - if (ff == src.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && ff == src.getFactory()) { return src; } return ff.makeFreeIdentifier(src.getName(), src.getSourceLocation(), - typeRewriter.rewrite(src.getType())); + trgType); } @Override @@ -254,15 +279,15 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public Expression rewrite(SetExtension src, SetExtension expr) { - if (ff == expr.getFactory()) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && ff == expr.getFactory()) { return expr; } if (expr.getMembers().length == 0) { - return ff.makeEmptySetExtension( - typeRewriter.rewrite(expr.getType()), - expr.getSourceLocation()); + return ff.makeEmptySetExtension(trgType, src.getSourceLocation()); } - return ff.makeSetExtension(expr.getMembers(), expr.getSourceLocation()); + return ff.makeSetExtension(expr.getMembers(), src.getSourceLocation()); } @Override @@ -279,7 +304,9 @@ public class DefaultTypeCheckingRewriter implements ITypeCheckingRewriter { @Override public Expression rewrite(UnaryExpression src, boolean changed, Expression newChild) { - if (!changed) { + final Type srcType = src.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + if (trgType == srcType && !changed) { assert ff == src.getFactory(); return src; } diff --git a/src/org/eventb/internal/core/ast/SimpleSubstitution.java b/src/org/eventb/internal/core/ast/SimpleSubstitution.java index f9bf041..dbcc54b 100644 --- a/src/org/eventb/internal/core/ast/SimpleSubstitution.java +++ b/src/org/eventb/internal/core/ast/SimpleSubstitution.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2013 ETH Zurich and others. + * Copyright (c) 2006, 2016 ETH Zurich and others. * 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 @@ -26,7 +26,7 @@ import org.eventb.core.ast.FreeIdentifier; */ public class SimpleSubstitution extends Substitution { - protected Map<FreeIdentifier, Substitute> map; + protected Map<FreeIdentifier, Substitute<Expression>> map; // Constructor for sub-classes that build directly the map. protected SimpleSubstitution(FormulaFactory ff) { @@ -43,7 +43,7 @@ public class SimpleSubstitution extends Substitution { */ public SimpleSubstitution(Map<FreeIdentifier, Expression> map, FormulaFactory ff) { super(ff); - this.map = new HashMap<FreeIdentifier, Substitute>(map.size() * 4/3 + 1); + this.map = new HashMap<FreeIdentifier, Substitute<Expression>>(map.size() * 4/3 + 1); for (Map.Entry<FreeIdentifier, Expression> entry : map.entrySet()) { FreeIdentifier ident = entry.getKey(); Expression expr = entry.getValue(); @@ -59,7 +59,7 @@ public class SimpleSubstitution extends Substitution { @Override public Expression rewrite(FreeIdentifier ident) { - Substitute repl = map.get(ident); + Substitute<Expression> repl = map.get(ident); if (repl == null) { return super.rewrite(ident); } diff --git a/src/org/eventb/internal/core/ast/Specialization.java b/src/org/eventb/internal/core/ast/Specialization.java index ce09c67..43cef43 100644 --- a/src/org/eventb/internal/core/ast/Specialization.java +++ b/src/org/eventb/internal/core/ast/Specialization.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2014 Systerel and others. + * Copyright (c) 2010, 2017 Systerel and others. * 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 @@ -7,6 +7,7 @@ * * Contributors: * Systerel - initial API and implementation + * University of Southamtpon - added support for predicate varialbes. *******************************************************************************/ package org.eventb.internal.core.ast; @@ -15,23 +16,20 @@ import static org.eventb.internal.core.ast.Substitute.makeSubstitute; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; -import org.eventb.core.ast.AtomicExpression; -import org.eventb.core.ast.BoundIdentDecl; -import org.eventb.core.ast.BoundIdentifier; import org.eventb.core.ast.Expression; -import org.eventb.core.ast.ExtendedExpression; +import org.eventb.core.ast.Formula; import org.eventb.core.ast.FormulaFactory; import org.eventb.core.ast.FreeIdentifier; import org.eventb.core.ast.GivenType; import org.eventb.core.ast.ISpecialization; +import org.eventb.core.ast.ITypeEnvironment; import org.eventb.core.ast.ITypeEnvironment.IIterator; import org.eventb.core.ast.ITypeEnvironmentBuilder; import org.eventb.core.ast.Predicate; -import org.eventb.core.ast.SetExtension; -import org.eventb.core.ast.SourceLocation; +import org.eventb.core.ast.PredicateVariable; import org.eventb.core.ast.Type; -import org.eventb.core.ast.extension.IExpressionExtension; import org.eventb.internal.core.typecheck.TypeEnvironment; /** @@ -42,41 +40,255 @@ import org.eventb.internal.core.typecheck.TypeEnvironment; * doubled as an identifier substitution. * * @author Laurent Voisin + * @author htson - added support for predicate variables. */ -public class Specialization extends Substitution implements ISpecialization { +public class Specialization implements ISpecialization { - // Type substitutions - private final Map<GivenType, Type> typeSubst; + private static class SpecializationTypeRewriter extends TypeRewriter { - // Identifier substitutions - private final Map<FreeIdentifier, Substitute> identSubst; + // Type substitutions + private final Map<GivenType, Type> typeSubst; + + public SpecializationTypeRewriter(FormulaFactory ff) { + super(ff); + typeSubst = new HashMap<GivenType, Type>(); + } + + public SpecializationTypeRewriter(SpecializationTypeRewriter other) { + super(other.ff); + typeSubst = new HashMap<GivenType, Type>(other.typeSubst); + } + + public Type get(GivenType key) { + return typeSubst.get(key); + } + + public Type getWithDefault(GivenType key) { + Type value = typeSubst.get(key); + if (value == null) { + value = key.translate(ff); + } + return value; + } + + public GivenType[] getTypes() { + final Set<GivenType> keySet = typeSubst.keySet(); + return keySet.toArray(new GivenType[keySet.size()]); + } + + public void put(GivenType type, Type value) { + final Type oldValue = typeSubst.put(type, value); + if (oldValue != null && !oldValue.equals(value)) { + typeSubst.put(type, oldValue); // repair + throw new IllegalArgumentException("Type substitution for " + + type + " already registered"); + } + } + + @Override + public void visit(GivenType type) { + final Type rewritten = getWithDefault(type); + // If the given type is not rewritten, use the super algorithm + // (this implements factory translation) + if (type.equals(rewritten)) { + super.visit(type); + } else { + result = rewritten; + } + } + + // For debugging purpose + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + toString(sb); + return sb.toString(); + } + + public void toString(StringBuilder sb) { + sb.append("{"); + String sep = ""; + for (Entry<GivenType, Type> entry : typeSubst.entrySet()) { + sb.append(sep); + sep = " || "; + sb.append(entry.getKey()); + sb.append("="); + sb.append(entry.getValue()); + } + sb.append("}"); + } + } + + private static class SpecializationFormulaRewriter extends Substitution { + + // Identifier substitutions + private final Map<FreeIdentifier, Substitute<Expression>> identSubst; + + // Predicate variable substitutions + private final Map<PredicateVariable, Substitute<Predicate>> predSubst; + + public SpecializationFormulaRewriter(SpecializationTypeRewriter typeRewriter) { + super(typeRewriter); + identSubst = new HashMap<FreeIdentifier, Substitute<Expression>>(); + predSubst = new HashMap<PredicateVariable, Substitute<Predicate>>(); + } + + public SpecializationFormulaRewriter( + SpecializationFormulaRewriter other, + SpecializationTypeRewriter otherTypeRewriter) { + super(otherTypeRewriter); + identSubst = new HashMap<FreeIdentifier, Substitute<Expression>>( + other.identSubst); + predSubst = new HashMap<PredicateVariable, Substitute<Predicate>>( + other.predSubst); + } + + public Expression get(FreeIdentifier ident) { + final Substitute<Expression> subst = identSubst.get(ident); + return subst == null ? null : subst.getSubstitute(ident, 0); + } + + public Predicate get(PredicateVariable predVar) { + final Substitute<Predicate> subst = predSubst.get(predVar); + return subst == null ? null : subst.getSubstitute(predVar, 0); + } + + public Expression getWithDefault(FreeIdentifier ident) { + final Substitute<Expression> subst = identSubst.get(ident); + if (subst != null) { + return subst.getSubstitute(ident, getBindingDepth()); + } + final Type type = ident.getType(); + final Type newType = typeRewriter.rewrite(type); + if (newType == type) { + return super.rewrite(ident); + } + return ff.makeFreeIdentifier(ident.getName(), + ident.getSourceLocation(), newType); + } + + public Predicate getWithDefault(PredicateVariable predVar) { + Substitute<Predicate> subst = predSubst.get(predVar); + if (subst != null) { + return subst.getSubstitute(predVar, getBindingDepth()); + } + return super.rewrite(predVar); + } + + public FreeIdentifier[] getFreeIdentifiers() { + final Set<FreeIdentifier> keySet = identSubst.keySet(); + return keySet.toArray(new FreeIdentifier[keySet.size()]); + } + + public PredicateVariable[] getPredicateVariables() { + final Set<PredicateVariable> keySet = predSubst.keySet(); + return keySet.toArray(new PredicateVariable[keySet.size()]); + } + + public void put(FreeIdentifier ident, Expression value) { + final Substitute<Expression> subst = makeSubstitute(value); + final Substitute<Expression> oldSubst = identSubst.put(ident, + subst); + if (oldSubst != null && !oldSubst.equals(subst)) { + identSubst.put(ident, oldSubst); // repair + throw new IllegalArgumentException( + "Identifier substitution for " + ident + + " already registered"); + } + } + + public boolean put(PredicateVariable predVar, Predicate value) { + final Substitute<Predicate> subst = makeSubstitute(value); + final Substitute<Predicate> oldSubst = predSubst.put(predVar, + subst); + if (oldSubst != null && !oldSubst.equals(subst)) { + predSubst.put(predVar, oldSubst); + return false; + } + return true; + } + + @Override + public Expression rewrite(FreeIdentifier identifier) { + final Expression newIdent = getWithDefault(identifier); + if (newIdent.equals(identifier)) { + return super.rewrite(identifier); + } + return newIdent; + } + + @Override + public Predicate rewrite(PredicateVariable predVar) { + final Predicate newPred = getWithDefault(predVar); + if (newPred.equals(predVar)) { + return super.rewrite(predVar); + } + return newPred; + } + + // For debugging purpose + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + toString(sb); + return sb.toString(); + } + + public void toString(StringBuilder sb) { + sb.append("{"); + String sep = ""; + for (Entry<FreeIdentifier, Substitute<Expression>> entry : identSubst + .entrySet()) { + sb.append(sep); + sep = " || "; + sb.append(entry.getKey()); + sb.append("="); + sb.append(entry.getValue()); + } + sb.append("} + {"); + sep = ""; + for (Entry<PredicateVariable, Substitute<Predicate>> entry : predSubst + .entrySet()) { + sb.append(sep); + sep = " || "; + sb.append(entry.getKey()); + sb.append("="); + sb.append(entry.getValue()); + } + sb.append("}"); + } + } + + // The type environment of the source language (quasi-final field to be + // set once at the first use and never changed after). + private ITypeEnvironmentBuilder srcTypenv; + + // The type environment of the destination language. + private ITypeEnvironmentBuilder dstTypenv; - private final TypeRewriter speTypeRewriter; + // The language of the right-hand sides of substitutions + private final FormulaFactory ff; + + private final SpecializationTypeRewriter speTypeRewriter; + + private final SpecializationFormulaRewriter formRewriter; public Specialization(FormulaFactory ff) { - super(ff); - typeSubst = new HashMap<GivenType, Type>(); - identSubst = new HashMap<FreeIdentifier, Substitute>(); - speTypeRewriter = new TypeRewriter(ff) { - @Override - public void visit(GivenType type) { - final Type rewritten = getOrSetDefault(type); - // If the given type is not rewritten, use the super algorithm - // (this implements factory translation) - if (type.equals(rewritten)) { - super.visit(type); - } else { - result = rewritten; - } - } - }; + this.srcTypenv = null; + this.dstTypenv = ff.makeTypeEnvironment(); + this.ff = ff; + speTypeRewriter = new SpecializationTypeRewriter(ff); + formRewriter = new SpecializationFormulaRewriter(speTypeRewriter); } public Specialization(Specialization other) { - super(other.ff); - typeSubst = new HashMap<GivenType, Type>(other.typeSubst); - identSubst = new HashMap<FreeIdentifier, Substitute>(other.identSubst); - speTypeRewriter = other.speTypeRewriter; + this.srcTypenv = other.srcTypenv == null ? null + : other.srcTypenv.makeBuilder(); + this.dstTypenv = other.dstTypenv.makeBuilder(); + this.ff = other.ff; + speTypeRewriter = new SpecializationTypeRewriter(other.speTypeRewriter); + formRewriter = new SpecializationFormulaRewriter(other.formRewriter, + speTypeRewriter); } @Override @@ -84,8 +296,40 @@ public class Specialization extends Substitution implements ISpecialization { return new Specialization(this); } + // For testing purpose, do not publish. + public ITypeEnvironmentBuilder getSourceTypenv() { + return srcTypenv; + } + + @Override + public FormulaFactory getFactory() { + return ff; + } + + // For testing purpose + public ITypeEnvironmentBuilder getDestinationTypenv() { + return dstTypenv; + } + + public ITypeCheckingRewriter getFormulaRewriter() { + return formRewriter; + } + + @Override + public boolean canPut(GivenType type, Type value) { + return canPutInternal(type, value) == null; + } + @Override public void put(GivenType type, Type value) { + final String errorMessage = canPutInternal(type, value); + if (errorMessage != null) { + throw new IllegalArgumentException(errorMessage); + } + addTypeSubstitution(type, value); + } + + private String canPutInternal(GivenType type, Type value) { if (type == null) throw new NullPointerException("Null given type"); if (value == null) @@ -94,71 +338,148 @@ public class Specialization extends Substitution implements ISpecialization { throw new IllegalArgumentException("Wrong factory for value: " + value.getFactory() + ", should be " + ff); } - final Type oldValue = typeSubst.put(type, value); + if (!verifySrcTypenv(type.toExpression())) { + return "Identifier " + type + + " already entered with a different type"; + } + final String error = isCompatibleFormula(dstTypenv, + value.toExpression()); + if (error != null) { + return error; + } + final Type oldValue = speTypeRewriter.get(type); if (oldValue != null && !oldValue.equals(value)) { - typeSubst.put(type, oldValue); // repair - throw new IllegalArgumentException("Type substitution for " + type - + " already registered"); + return "Type substitution for " + type + " already registered"; + } + return null; + } + + private void addTypeSubstitution(GivenType type, Type value) { + final FreeIdentifier ident = type.toExpression(); + srcTypenv.add(ident); + speTypeRewriter.put(type, value); + formRewriter.put(ident, value.toExpression()); + for (final GivenType given : value.getGivenTypes()) { + dstTypenv.addGivenSet(given.getName()); } - final Substitute subst = makeSubstitute(value.toExpression()); - identSubst.put(type.toExpression(), subst); } + private void maybeAddTypeIdentitySubstitution(GivenType type) { + if (!srcTypenv.contains(type.getName())) { + addTypeSubstitution(type, type.translate(ff)); + } + } + @Override public Type get(GivenType key) { - return typeSubst.get(key); + return speTypeRewriter.get(key); } - public Type getOrSetDefault(GivenType key) { - Type value = get(key); - if (value == null) { - value = key.translate(ff); - put(key, value); - } - return value; + @Override + public boolean canPut(FreeIdentifier ident, Expression value) { + return canPutInternal(ident, value) == null; } @Override public void put(FreeIdentifier ident, Expression value) { + final String errorMessage = canPutInternal(ident, value); + if (errorMessage != null) { + throw new IllegalArgumentException(errorMessage); + } + addIdentSubstitution(ident, value); + } + + private String canPutInternal(FreeIdentifier ident, Expression value) { if (ident == null) throw new NullPointerException("Null identifier"); if (!ident.isTypeChecked()) throw new IllegalArgumentException("Untyped identifier"); if (value == null) throw new NullPointerException("Null value"); + if (!value.isTypeChecked()) + throw new IllegalArgumentException("Untyped value"); if (ff != value.getFactory()) { throw new IllegalArgumentException("Wrong factory for value: " + value.getFactory() + ", should be " + ff); } - if (!value.isTypeChecked()) - throw new IllegalArgumentException("Untyped value"); - verify(ident, value); - final Substitute subst = makeSubstitute(value); - final Substitute oldSubst = identSubst.put(ident, subst); - if (oldSubst != null && !oldSubst.equals(subst)) { - identSubst.put(ident, oldSubst); // repair - throw new IllegalArgumentException("Identifier substitution for " - + ident + " already registered"); + if (!verifySrcTypenv(ident)) { + return "Incompatible types for " + ident; } + if (!verify(ident, value)) { + return "Incompatible types for " + ident; + } + final String error = isCompatibleFormula(dstTypenv, value); + if (error != null) { + return error; + } + final Expression oldValue = formRewriter.get(ident); + if (oldValue != null && !oldValue.equals(value)) { + return "Identifier substitution for " + ident + + " already registered"; + } + return null; } /* - * Checks that a new substitution is compatible. We also save the given sets - * that are now frozen and must not change afterwards. + * Tells whether the new substitution is compatible with existing ones. If + * commit is true, we also save the given sets that are now frozen and must + * not change afterwards. */ - private void verify(FreeIdentifier ident, Expression value) { + private boolean verify(FreeIdentifier ident, Expression value) { final Type identType = ident.getType(); - final Type newType = identType.specialize(this); - if (!value.getType().equals(newType)) { - throw new IllegalArgumentException("Incompatible types for " - + ident); + final Type newType = speTypeRewriter.rewrite(identType); + return value.getType().equals(newType); + } + + private void addIdentSubstitution(FreeIdentifier ident, Expression value) { + for (final GivenType given : ident.getGivenTypes()) { + maybeAddTypeIdentitySubstitution(given); } + srcTypenv.add(ident); + formRewriter.put(ident, value); + dstTypenv.addAll(value.getFreeIdentifiers()); } + private void maybeAddIdentIdentitySubstitution(FreeIdentifier ident) { + if (!srcTypenv.contains(ident.getName())) { + addIdentSubstitution(ident, formRewriter.rewrite(ident)); + } + } + public Type specialize(Type type) { + prepare(type); return speTypeRewriter.rewrite(type); } + /* + * Prepares the specialization of a type. + * + * We check here that the specialization will not encounter a typing error + * and perform the side-effects for types not yet registered with this + * specialization. + */ + public void prepare(Type type) { + final Set<GivenType> givens = type.getGivenTypes(); + + // Ensure that type environments are compatible + for (final GivenType given : givens) { + if (!verifySrcTypenv(given.toExpression())) { + throw new IllegalArgumentException("Type " + given + + " already entered with a different type"); + } + if (speTypeRewriter.get(given) == null + && !isCompatible(dstTypenv, given)) { + throw new IllegalArgumentException("Destination name " + given + + " already used with a different type"); + } + } + + // Then insert the identity substitutions not already there + for (final GivenType given : givens) { + maybeAddTypeIdentitySubstitution(given); + } + } + /* * Specializing a type environment consists in, starting from an empty type * environment, adding all given sets and free identifiers that occur in the @@ -166,12 +487,13 @@ public class Specialization extends Substitution implements ISpecialization { * environment. */ public ITypeEnvironmentBuilder specialize(TypeEnvironment typenv) { + prepare(typenv); final ITypeEnvironmentBuilder result = ff.makeTypeEnvironment(); final IIterator iter = typenv.getIterator(); while (iter.hasNext()) { iter.advance(); final FreeIdentifier ident = iter.asFreeIdentifier(); - final Expression expr = this.getOrSetDefault(ident); + final Expression expr = formRewriter.rewrite(ident); for (final FreeIdentifier free : expr.getFreeIdentifiers()) { result.add(free); } @@ -179,124 +501,177 @@ public class Specialization extends Substitution implements ISpecialization { return result; } - @Override - public Expression get(FreeIdentifier ident) { - final Substitute subst = identSubst.get(ident); - return subst == null ? null : subst.getSubstitute(ident, 0); - } - - private Expression getOrSetDefault(FreeIdentifier ident) { - final Substitute subst = identSubst.get(ident); - if (subst != null) { - return subst.getSubstitute(ident, getBindingDepth()); - } - final Type type = ident.getType(); - final Type newType = type.specialize(this); - final Expression result; - if (newType == type) { - result = super.rewrite(ident); - } else { - result = ff.makeFreeIdentifier(ident.getName(), - ident.getSourceLocation(), newType); + /* + * Prepares the specialization of a type environment. + * + * We check here that the specialization will not encounter a typing error + * and perform the side-effects for identifiers not yet registered with this + * specialization. + */ + public void prepare(TypeEnvironment typenv) { + // Ensure that type environments are compatible + final IIterator iter = typenv.getIterator(); + while (iter.hasNext()) { + iter.advance(); + final FreeIdentifier ident = iter.asFreeIdentifier(); + if (!verifySrcTypenv(ident)) { + throw new IllegalArgumentException("Identifier " + ident + + " already entered with a different type"); + } + verifyDstTypenv(ident); } - identSubst.put(ident, makeSubstitute(result)); - return result; - } - @Override - public Expression rewrite(FreeIdentifier identifier) { - final Expression newIdent = getOrSetDefault(identifier); - if (newIdent.equals(identifier)) { - return super.rewrite(identifier); + // Then insert the identity substitutions not yet there + final IIterator iter2 = typenv.getIterator(); + while (iter2.hasNext()) { + iter2.advance(); + final FreeIdentifier ident = iter2.asFreeIdentifier(); + maybeAddIdentIdentitySubstitution(ident); } - return newIdent; } - @Override - public BoundIdentDecl rewrite(BoundIdentDecl decl) { - final Type type = decl.getType(); - final Type newType = type.specialize(this); - if (newType == type) { - return super.rewrite(decl); + /* + * Prepares the specialization of an arbitrary formula. The specialization + * itself cannot be performed here, as it must use the non-API rewrite + * method of class Formula. + * + * We check here that the specialization will not encounter a typing error + * and perform the side-effects for identifiers and predicate variables not + * yet registered with this specialization. + */ + public <T extends Formula<T>> void prepare(Formula<T> formula) { + final FreeIdentifier[] localEnv = formula.getFreeIdentifiers(); + + // Ensure that type environments are compatible + for (final FreeIdentifier ident : localEnv) { + if (!verifySrcTypenv(ident)) { + throw new IllegalArgumentException("Identifier " + ident + + " already entered with a different type"); + } + verifyDstTypenv(ident); + } + + // Then protect the identity substitutions not already there + for (final FreeIdentifier ident : localEnv) { + maybeAddIdentIdentitySubstitution(ident); + } + + // Also add identity substitutions for the predicate variables that do + // not have a substitution yet. + final PredicateVariable[] predVars = formula.getPredicateVariables(); + for (final PredicateVariable predVar : predVars) { + if (formRewriter.get(predVar) == null) { + formRewriter.put(predVar, predVar.translate(ff)); + } } - final String name = decl.getName(); - final SourceLocation sloc = decl.getSourceLocation(); - return ff.makeBoundIdentDecl(name, sloc, newType); } - @Override - public Expression rewrite(BoundIdentifier identifier) { - final Type type = identifier.getType(); - final Type newType = type.specialize(this); - if (newType == type) { - return super.rewrite(identifier); + /* + * Ensures that the specialization of srcIdent will be compatible with the + * destination environment. + */ + private void verifyDstTypenv(FreeIdentifier srcIdent) { + if (formRewriter.get(srcIdent) != null) { + return; + } + final Expression dstExpr = formRewriter.rewrite(srcIdent); + final FreeIdentifier dstIdent = (FreeIdentifier) dstExpr; + if (!isCompatible(dstTypenv, dstIdent)) { + throw new IllegalArgumentException("Destination name " + dstIdent + + " already used with a different type"); } - return ff.makeBoundIdentifier(identifier.getBoundIndex(), - identifier.getSourceLocation(), newType); } @Override - public Expression rewrite(AtomicExpression expression) { - final Type type = expression.getType(); - final Type newType = type.specialize(this); - if (newType == type) { - return super.rewrite(expression); - } - final SourceLocation loc = expression.getSourceLocation(); - return ff.makeAtomicExpression(expression.getTag(), loc, newType); + public Expression get(FreeIdentifier ident) { + return formRewriter.get(ident); } + // For debugging purposes @Override - public Expression rewrite(ExtendedExpression expr, boolean changed, - Expression[] newChildExprs, Predicate[] newChildPreds) { - final Type type = expr.getType(); - final Type newType = type.specialize(this); - if (!changed && newType == type) { - return super.rewrite(expr, changed, newChildExprs, newChildPreds); - } - final IExpressionExtension extension = expr.getExtension(); - final SourceLocation loc = expr.getSourceLocation(); - return ff.makeExtendedExpression(extension, newChildExprs, - newChildPreds, loc, newType); + public String toString() { + final StringBuilder sb = new StringBuilder(); + speTypeRewriter.toString(sb); + sb.append(" + "); + formRewriter.toString(sb); + return sb.toString(); } /* - * For a set extension, the only special case is that of an empty extension, - * where we have to specialize the type. + * Tells whether the given identifier is compatible with the source type + * environment. */ - @Override - public Expression rewrite(SetExtension src, SetExtension expr) { - if (expr.getChildCount() != 0) { - return expr; + private boolean verifySrcTypenv(FreeIdentifier ident) { + if (srcTypenv == null) { + srcTypenv = ident.getFactory().makeTypeEnvironment(); } - final Type type = expr.getType(); - final Type newType = type.specialize(this); - if (newType == type) { - return super.rewrite(src, expr); + return isCompatible(srcTypenv, ident); + } + + private <T extends Formula<T>> String isCompatibleFormula( + ITypeEnvironment typenv, T value) { + for (final FreeIdentifier ident : value.getFreeIdentifiers()) { + if (!isCompatible(typenv, ident)) { + return "Destination name " + ident + + " already used with a different type"; + } } - return ff.makeEmptySetExtension(newType, expr.getSourceLocation()); + return null; + } + + private boolean isCompatible(ITypeEnvironment typenv, + FreeIdentifier ident) { + final Type knownType = typenv.getType(ident.getName()); + return knownType == null || knownType.equals(ident.getType()); + } + + private boolean isCompatible(ITypeEnvironment typenv, GivenType type) { + final Type knownType = typenv.getType(type.getName()); + return knownType == null || type.equals(knownType.getBaseType()); } - // For debugging purposes @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - String sep = ""; - for (Entry<GivenType, Type> entry : typeSubst.entrySet()) { - sb.append(sep); - sep = " || "; - sb.append(entry.getKey()); - sb.append("="); - sb.append(entry.getValue()); - } - for (Entry<FreeIdentifier, Substitute> entry : identSubst.entrySet()) { - sb.append(sep); - sep = " || "; - sb.append(entry.getKey()); - sb.append("="); - sb.append(entry.getValue()); + public boolean put(PredicateVariable predVar, Predicate value) { + if (predVar == null) + throw new NullPointerException("Null predicate variable"); + if (value == null) + throw new NullPointerException("Null value"); + if (!value.isTypeChecked()) + throw new IllegalArgumentException("Untyped value"); + if (ff != value.getFactory()) { + throw new IllegalArgumentException("Wrong factory for value: " + + value.getFactory() + ", should be " + ff); } - return sb.toString(); + + if (isCompatibleFormula(dstTypenv, value) != null) { + return false; + } + + final boolean result = formRewriter.put(predVar, value); + if (result) { + dstTypenv.addAll(value.getFreeIdentifiers()); + } + return result; + } + + @Override + public Predicate get(PredicateVariable predVar) { + return formRewriter.get(predVar); + } + + @Override + public GivenType[] getTypes() { + return speTypeRewriter.getTypes(); + } + + @Override + public FreeIdentifier[] getFreeIdentifiers() { + return formRewriter.getFreeIdentifiers(); + } + + @Override + public PredicateVariable[] getPredicateVariables() { + return formRewriter.getPredicateVariables(); } } diff --git a/src/org/eventb/internal/core/ast/Substitute.java b/src/org/eventb/internal/core/ast/Substitute.java index f8cd659..ddc8cdf 100644 --- a/src/org/eventb/internal/core/ast/Substitute.java +++ b/src/org/eventb/internal/core/ast/Substitute.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2014 ETH Zurich and others. + * Copyright (c) 2006, 2016 ETH Zurich and others. * 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 @@ -7,41 +7,44 @@ * * Contributors: * ETH Zurich - initial API and implementation + * Systerel - Make this class generic *******************************************************************************/ package org.eventb.internal.core.ast; import org.eventb.core.ast.Expression; +import org.eventb.core.ast.Formula; /** - * Common abstraction for a substitute expression used in a substitution. + * Common abstraction for a substitute formula used in a substitution. * <p> * This class is not public API. Don't use it. * </p> * * @author Laurent Voisin */ -public abstract class Substitute { +public abstract class Substitute<T extends Formula<T>> { /** - * Simple substitute where the expression doesn't contain any externally + * Simple substitute where the formula doesn't contain any externally * bound identifier. */ - private static class SimpleSubstitute extends Substitute { + private static class SimpleSubstitute<T extends Formula<T>> + extends Substitute<T> { - Expression expr; + T formula; - public SimpleSubstitute(Expression expr) { - this.expr = expr; + public SimpleSubstitute(T formula) { + this.formula = formula; } @Override - public Expression getSubstitute(Expression original, int nbOfInternallyBound) { - return expr; + public T getSubstitute(T original, int nbOfInternallyBound) { + return formula; } @Override public int hashCode() { - return expr.hashCode(); + return formula.hashCode(); } @Override @@ -52,27 +55,29 @@ public abstract class Substitute { if (obj == null || this.getClass() != obj.getClass()) { return false; } - final SimpleSubstitute other = (SimpleSubstitute) obj; - return expr.equals(other.expr); + @SuppressWarnings("unchecked") + final SimpleSubstitute<T> other = (SimpleSubstitute<T>) obj; + return formula.equals(other.formula); } @Override public String toString() { - return expr.toString(); + return formula.toString(); } } /** - * Susbtitute where the expression consists of a bound identifier. + * Susbtitute where the formula consists of a bound identifier. * <p> * This means that we must renumber the index of this identifier, taking * into account the offset. * </p> * This class corresponds to an optimized simple version of - * {@link ComplexSubstitute}. + * {@link org.eventb.internal.core.ast.Substitute.ComplexSubstitute + * ComplexSubstitute}. */ - private static class BoundIdentSubstitute extends Substitute { + private static class BoundIdentSubstitute extends Substitute<Expression> { /** * Index of the bound variable, before correction. @@ -115,7 +120,7 @@ public abstract class Substitute { } /** - * Complex substitute where the expression does contain some externally + * Complex substitute where the formula does contain some externally * bound identifiers. * <p> * This means that we must renumber the index of these identifiers, taking @@ -123,26 +128,27 @@ public abstract class Substitute { * small cache. * </p> */ - private static class ComplexSubstitute extends Substitute { + private static class ComplexSubstitute<T extends Formula<T>> + extends Substitute<T> { /** - * Cache of substitute expressions, indexed by the offset applied to + * Cache of substitute formulas, indexed by the offset applied to * them. For instance, the first element of the list contains the - * original expression untouched. + * original formula untouched. */ - private Cache<Expression> cache; + private Cache<T> cache; - public ComplexSubstitute(Expression expr) { - this.cache = new Cache<Expression>(); - this.cache.set(0, expr); + public ComplexSubstitute(T formula) { + this.cache = new Cache<T>(); + this.cache.set(0, formula); } @Override - public Expression getSubstitute(Expression original, int nbOfInternallyBound) { - Expression result = cache.get(nbOfInternallyBound); + public T getSubstitute(T original, int nbOfInternallyBound) { + T result = cache.get(nbOfInternallyBound); if (result == null) { - Expression expr = cache.get(0); - result = expr.shiftBoundIdentifiers(nbOfInternallyBound); + T formula = cache.get(0); + result = formula.shiftBoundIdentifiers(nbOfInternallyBound); cache.set(nbOfInternallyBound, result); } return result; @@ -161,11 +167,13 @@ public abstract class Substitute { if (obj == null || this.getClass() != obj.getClass()) { return false; } - return equalExpressions((ComplexSubstitute) obj); + @SuppressWarnings("unchecked") + final ComplexSubstitute<T> other = (ComplexSubstitute<T>) obj; + return equalFormulas(other); } // Test extracted to a method for subclass comparison - protected boolean equalExpressions(ComplexSubstitute other) { + protected boolean equalFormulas(ComplexSubstitute<T> other) { return cache.get(0).equals(other.cache.get(0)); } @@ -177,20 +185,21 @@ public abstract class Substitute { } /** - * Complex substitute where the expression does contain some externally + * Complex substitute where the formula does contain some externally * bound identifiers, and where an additional offset needs to be applied. */ - private static class ComplexSubstituteWithOffset extends ComplexSubstitute { + private static class ComplexSubstituteWithOffset<T extends Formula<T>> + extends ComplexSubstitute<T> { private final int offset; - public ComplexSubstituteWithOffset(Expression expr, int offset) { - super(expr); + public ComplexSubstituteWithOffset(T formula, int offset) { + super(formula); this.offset = offset; } @Override - public Expression getSubstitute(Expression original, int nbOfInternallyBound) { + public T getSubstitute(T original, int nbOfInternallyBound) { return super.getSubstitute(original, nbOfInternallyBound + offset); } @@ -207,8 +216,9 @@ public abstract class Substitute { if (obj == null || this.getClass() != obj.getClass()) { return false; } - final ComplexSubstituteWithOffset other = (ComplexSubstituteWithOffset) obj; - return equalExpressions(other) && offset == other.offset; + @SuppressWarnings("unchecked") + final ComplexSubstituteWithOffset<T> other = (ComplexSubstituteWithOffset<T>) obj; + return equalFormulas(other) && offset == other.offset; } @Override @@ -219,31 +229,32 @@ public abstract class Substitute { } /** - * Factory method to create a substitute with an arbitrary expression. + * Factory method to create a substitute with an arbitrary formula. * - * @param expr - * initial substitute expression - * @return the substitute object for that expression + * @param formula + * initial substitute formula + * @return the substitute object for that formula */ - public static Substitute makeSubstitute(Expression expr) { - if (expr.isWellFormed()) { - return new SimpleSubstitute(expr); + public static <T extends Formula<T>> Substitute<T> makeSubstitute(T formula) { + if (formula.isWellFormed()) { + return new SimpleSubstitute<T>(formula); } - return new ComplexSubstitute(expr); + return new ComplexSubstitute<T>(formula); } /** - * Factory method to create a substitute with an arbitrary expression and + * Factory method to create a substitute with an arbitrary formula and * applying a constant offset to its bound identifiers. * - * @param expr - * initial substitute expression + * @param formula + * initial substitute formula * @param offset * offset to systematically apply - * @return the substitute object for that expression + * @return the substitute object for that formula */ - public static Substitute makeSubstitute(Expression expr, int offset) { - return new ComplexSubstituteWithOffset(expr, offset); + public static <T extends Formula<T>> Substitute<T> makeSubstitute(T formula, + int offset) { + return new ComplexSubstituteWithOffset<T>(formula, offset); } /** @@ -253,23 +264,23 @@ public abstract class Substitute { * initial index of the bound identifier * @return the substitute object for that identifier */ - public static Substitute makeSubstitute(int index) { + public static Substitute<Expression> makeSubstitute(int index) { return new BoundIdentSubstitute(index); } /** - * Returns the substitute expression where bound identifier occurrences have + * Returns the substitute formula where bound identifier occurrences have * been renumbered using the given offset. * * @param original - * original expression that gets substituted + * original formula that gets substituted * @param nbOfInternallyBound * offset to use, that is the number of identifiers bound between - * the point where the substitute expression was given and the + * the point where the substitute formula was given and the * place where it is used * - * @return the actual substitute expression to use + * @return the actual substitute formula to use */ - public abstract Expression getSubstitute(Expression original, int nbOfInternallyBound); + public abstract T getSubstitute(T original, int nbOfInternallyBound); } diff --git a/src/org/eventb/internal/core/ast/Substitution.java b/src/org/eventb/internal/core/ast/Substitution.java index 5a67f97..3af6df0 100644 --- a/src/org/eventb/internal/core/ast/Substitution.java +++ b/src/org/eventb/internal/core/ast/Substitution.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2012 ETH Zurich and others. + * Copyright (c) 2006, 2016 ETH Zurich and others. * 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 @@ -23,4 +23,8 @@ public abstract class Substitution extends DefaultTypeCheckingRewriter { super(ff); } + public Substitution(TypeRewriter typeRewriter) { + super(typeRewriter); + } + } diff --git a/src/org/eventb/internal/core/ast/TypeRewriter.java b/src/org/eventb/internal/core/ast/TypeRewriter.java index b08b07b..59e7ef6 100644 --- a/src/org/eventb/internal/core/ast/TypeRewriter.java +++ b/src/org/eventb/internal/core/ast/TypeRewriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2012, 2013 Systerel and others. + * Copyright (c) 2012, 2016 Systerel and others. * 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 @@ -38,7 +38,7 @@ import org.eventb.core.ast.extension.IExpressionExtension; public class TypeRewriter implements ITypeVisitor { // Formula factory to use for building the rewritten types - private final FormulaFactory ff; + protected final FormulaFactory ff; // Result of the last call to visit() protected Type result; @@ -47,6 +47,10 @@ public class TypeRewriter implements ITypeVisitor { this.ff = ff; } + public FormulaFactory getFactory() { + return ff; + } + public Type rewrite(Type type) { if (type == null) { return null; diff --git a/src/org/eventb/internal/core/ast/datatype/Datatype.java b/src/org/eventb/internal/core/ast/datatype/Datatype.java index 26572ed..8d742b2 100644 --- a/src/org/eventb/internal/core/ast/datatype/Datatype.java +++ b/src/org/eventb/internal/core/ast/datatype/Datatype.java @@ -79,7 +79,7 @@ public class Datatype implements IDatatype { // Cache of the extensions provided by this datatype private final Set<IFormulaExtension> extensions; - + private final Object origin; private Datatype(DatatypeBuilder dtBuilder) { @@ -87,7 +87,7 @@ public class Datatype implements IDatatype { origin = dtBuilder.getOrigin(); typeCons = new TypeConstructorExtension(this, dtBuilder); constructors = new LinkedHashMap<String, ConstructorExtension>(); - destructors = new HashMap<String, DestructorExtension>(); + destructors = new HashMap<String, DestructorExtension>(); final List<ConstructorBuilder> dtConstrs = dtBuilder.getConstructors(); for (final ConstructorBuilder dtCons : dtConstrs) { final ConstructorExtension constructor = dtCons.makeExtension(this); @@ -161,17 +161,24 @@ public class Datatype implements IDatatype { return unmodifiableSet(extensions); } + /** + * The hash code is computed from the datatype's type constructors, + * constructor extensions, and the origin. + */ @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + typeCons.hashCode(); + result = prime * result + typeCons.hashCode(); result = prime * result + constructors.hashCode(); - result = prime * result + ((origin == null) ? 0 : origin.hashCode()); + result = prime * result + (origin == null ? 0 : origin.hashCode()); return result; } - + /** + * The datatypes are the same if they have the same name and "similar" type + * constructors, constructor extensions, and origins. + */ @Override public boolean equals(Object obj) { if (this == obj) { @@ -183,15 +190,23 @@ public class Datatype implements IDatatype { final Datatype other = (Datatype) obj; return this.typeCons.isSimilarTo(other.typeCons) && areSimilarConstructors(this.constructors.values(), - other.constructors.values()) - && areEqualOrigins(this.origin, other.origin); - } - - private static boolean areEqualOrigins(Object origin1, Object origin2) { - if (origin1 == null) { - return origin2 == null; - } - return origin1.equals(origin2); + other.constructors.values()) && + areSimilarOrigins(this.getOrigin(), other.getOrigin()); + } + + /** + * Utility method to compare the datatype origin. + * + * @param mine + * mine origin + * @param other + * the other's origin + * @return <code>true</code> if the two origin are equal. + */ + private boolean areSimilarOrigins(Object mine, Object other) { + if (mine == null) + return (other == null); + return mine.equals(other); } private static boolean areSimilarConstructors( diff --git a/src/org/eventb/internal/core/ast/datatype/DatatypeRewriter.java b/src/org/eventb/internal/core/ast/datatype/DatatypeRewriter.java index bfd8e8d..58ed267 100644 --- a/src/org/eventb/internal/core/ast/datatype/DatatypeRewriter.java +++ b/src/org/eventb/internal/core/ast/datatype/DatatypeRewriter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 Systerel and others. + * Copyright (c) 2013, 2016 Systerel and others. * 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 @@ -10,16 +10,9 @@ *******************************************************************************/ package org.eventb.internal.core.ast.datatype; -import org.eventb.core.ast.AtomicExpression; -import org.eventb.core.ast.BoundIdentDecl; -import org.eventb.core.ast.BoundIdentifier; import org.eventb.core.ast.Expression; import org.eventb.core.ast.ExtendedExpression; -import org.eventb.core.ast.FreeIdentifier; import org.eventb.core.ast.Predicate; -import org.eventb.core.ast.SetExtension; -import org.eventb.core.ast.SourceLocation; -import org.eventb.core.ast.Type; import org.eventb.core.ast.datatype.IDatatype; import org.eventb.core.ast.extension.IExpressionExtension; import org.eventb.internal.core.ast.DefaultTypeCheckingRewriter; @@ -40,71 +33,10 @@ public class DatatypeRewriter extends DefaultTypeCheckingRewriter { private final DatatypeTranslation translation; public DatatypeRewriter(DatatypeTranslation translation) { - super(translation.getTargetFormulaFactory()); + super(translation.getTypeRewriter()); this.translation = translation; } - @Override - public BoundIdentDecl rewrite(BoundIdentDecl decl) { - final Type type = decl.getType(); - final Type newType = translation.translate(type); - if (newType == type) { - return super.rewrite(decl); - } - final String name = decl.getName(); - final SourceLocation sLoc = decl.getSourceLocation(); - return ff.makeBoundIdentDecl(name, sLoc, newType); - } - - @Override - public Expression rewrite(AtomicExpression expression) { - final Type type = expression.getType(); - final Type newType = translation.translate(type); - if (newType == type) { - return super.rewrite(expression); - } - final SourceLocation sLoc = expression.getSourceLocation(); - return ff.makeAtomicExpression(expression.getTag(), sLoc, newType); - } - - @Override - public Expression rewrite(BoundIdentifier identifier) { - final Type type = identifier.getType(); - final Type newType = translation.translate(type); - if (newType == type) { - return super.rewrite(identifier); - } - final SourceLocation sLoc = identifier.getSourceLocation(); - final int index = identifier.getBoundIndex(); - return ff.makeBoundIdentifier(index, sLoc, newType); - } - - @Override - public Expression rewrite(FreeIdentifier ident) { - final Type type = ident.getType(); - final Type newType = translation.translate(type); - if (newType == type) { - return super.rewrite(ident); - } - final SourceLocation sLoc = ident.getSourceLocation(); - final String name = ident.getName(); - return ff.makeFreeIdentifier(name, sLoc, newType); - } - - @Override - public Expression rewrite(SetExtension src, SetExtension expr) { - if (expr.getChildCount() != 0) { - return expr; - } - final Type type = expr.getType(); - final Type newType = translation.translate(type); - if (newType == type) { - return expr; - } - final SourceLocation sLoc = expr.getSourceLocation(); - return ff.makeEmptySetExtension(newType, sLoc); - } - @Override public Expression rewrite(ExtendedExpression src, boolean changed, Expression[] newChildExprs, Predicate[] newChildPreds) { @@ -116,11 +48,8 @@ public class DatatypeRewriter extends DefaultTypeCheckingRewriter { return translation.translate(src, newChildExprs); } else { // Not a datatype operator, just translate the type - final SourceLocation sLoc = src.getSourceLocation(); - final Type type = translation.translate(src.getType()); - return ff.makeExtendedExpression(extension, newChildExprs, - newChildPreds, sLoc, type); + return super.rewrite(src, changed, newChildExprs, newChildPreds); } } -} \ No newline at end of file +} diff --git a/src/org/eventb/internal/core/ast/datatype/DatatypeTranslation.java b/src/org/eventb/internal/core/ast/datatype/DatatypeTranslation.java index 889fa88..55f015f 100644 --- a/src/org/eventb/internal/core/ast/datatype/DatatypeTranslation.java +++ b/src/org/eventb/internal/core/ast/datatype/DatatypeTranslation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013, 2014 Systerel and others. + * Copyright (c) 2013, 2016 Systerel and others. * 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 @@ -117,6 +117,10 @@ public class DatatypeTranslation extends AbstractTranslation implements return formulaRewriter; } + public TypeRewriter getTypeRewriter() { + return typeRewriter; + } + public final GivenType solveGivenType(String typeSymbol) { final String solvedTypeName = nameSolver.solveAndAdd(typeSymbol); return targetFactory.makeGivenType(solvedTypeName); @@ -172,4 +176,4 @@ public class DatatypeTranslation extends AbstractTranslation implements return "Datatype Translation for factory: " + sourceFactory + " in type environment: " + srcTypenv; } -} \ No newline at end of file +} diff --git a/src/org/eventb/internal/core/ast/extension/ExtensionSignature.java b/src/org/eventb/internal/core/ast/extension/ExtensionSignature.java index 172179f..a62e88f 100644 --- a/src/org/eventb/internal/core/ast/extension/ExtensionSignature.java +++ b/src/org/eventb/internal/core/ast/extension/ExtensionSignature.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Systerel and others. + * Copyright (c) 2014, 2016 Systerel and others. * 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 @@ -17,7 +17,9 @@ import org.eventb.core.ast.ExtendedExpression; import org.eventb.core.ast.ExtendedPredicate; import org.eventb.core.ast.Formula; import org.eventb.core.ast.FormulaFactory; +import org.eventb.core.ast.ParametricType; import org.eventb.core.ast.Type; +import org.eventb.core.ast.extension.IExpressionExtension; import org.eventb.core.ast.extension.IExtendedFormula; import org.eventb.core.ast.extension.IFormulaExtension; @@ -30,6 +32,17 @@ import org.eventb.core.ast.extension.IFormulaExtension; */ public abstract class ExtensionSignature { + /** + * Returns the signature of a parametric type occurrence. + * + * @param src + * some parametric type + * @return the signature of the parametric type + */ + public static ExpressionExtSignature getSignature(ParametricType src) { + return new ExpressionExtSignature(src); + } + /** * Returns the signature of an expression extension occurrence. * @@ -62,13 +75,26 @@ public abstract class ExtensionSignature { return childTypes; } + private static Type[] makePowerSetTypes(Type[] src) { + if (src.length == 0) { + return src; + } + final FormulaFactory fac = src[0].getFactory(); + final Type[] result = new Type[src.length]; + for (int i = 0; i < src.length; i++) { + result[i] = fac.makePowerSetType(src[i]); + } + return result; + } + private static final int PRIME = 31; - // The formula factory for this signature + // The formula factory for this signature, i.e., the factory containing the + // extension. protected final FormulaFactory factory; // The extension definition corresponding to this signature - private final IFormulaExtension extension; + protected final IFormulaExtension extension; // Number of child predicates private final int numberOfPredicates; @@ -83,6 +109,13 @@ public abstract class ExtensionSignature { this.childTypes = getChildTypes(src); } + protected ExtensionSignature(ParametricType src) { + this.factory = src.getFactory(); + this.extension = src.getExprExtension(); + this.numberOfPredicates = 0; + this.childTypes = makePowerSetTypes(src.getTypeParameters()); + } + // For testing purposes protected ExtensionSignature(FormulaFactory factory, IFormulaExtension extension, int numberOfPredicates, @@ -94,12 +127,30 @@ public abstract class ExtensionSignature { } /** - * Returns the formula extension definition associated to this signature + * Returns the symbol associated to this signature. This symbol might not be + * a valid identifier. * - * @return the IFormulaExtension associated to this signature + * @return the symbol associated to this signature */ - public IFormulaExtension getExtension() { - return extension; + public String getSymbol() { + return extension.getSyntaxSymbol(); + } + + /** + * Returns whether the extension with this signature is a type constructor. + * + * @return whether this signature corresponds to a type constructor + */ + public abstract boolean isATypeConstructor(); + + /** + * Returns whether this signature is atomic, that is denotes an operator + * that does not have any child. + * + * @return whether this signature is atomic + */ + public boolean isAtomic() { + return numberOfPredicates == 0 && childTypes.length == 0; } /** @@ -108,7 +159,25 @@ public abstract class ExtensionSignature { * * @return the type of a replacement function */ - public abstract Type getFunctionalType(); + public Type getFunctionalType(FunctionalTypeBuilder builder) { + return builder.makeFunctionalType(childTypes, numberOfPredicates, + getReturnType()); + } + + /** + * Returns the type of a relation that could be used to replace an + * occurrence of the extension with this signature. To be used in the + * special case of type constructors. + * + * @return the type of a replacement relation + */ + public Type getRelationalType(FunctionalTypeBuilder builder) { + assert isATypeConstructor(); + return builder.makeRelationalType(childTypes, getReturnType()); + } + + // What is the range type of the operator ? + protected abstract Type getReturnType(); @Override public int hashCode() { @@ -133,37 +202,6 @@ public abstract class ExtensionSignature { && Arrays.equals(this.childTypes, other.childTypes); } - protected Type makeDomainType() { - Type result = null; - for (Type childType : childTypes) { - result = join(result, childType); - } - final Type boolType = makeBooleanType(); - for (int i = 0; i < numberOfPredicates; i++) { - result = join(result, boolType); - } - return result; - } - - private Type join(Type left, Type right) { - if (left == null) { - return right; - } - return factory.makeProductType(left, right); - } - - protected Type makeBooleanType() { - return factory.makeBooleanType(); - } - - protected Type makeRelationalType(Type left, Type right) { - if (left == null) { - // Atomic operator - return right; - } - return factory.makeRelationalType(left, right); - } - public static class PredicateExtSignature extends ExtensionSignature { public PredicateExtSignature(ExtendedPredicate src) { @@ -178,8 +216,13 @@ public abstract class ExtensionSignature { } @Override - public Type getFunctionalType() { - return makeRelationalType(makeDomainType(), makeBooleanType()); + protected Type getReturnType() { + return factory.makeBooleanType(); + } + + @Override + public boolean isATypeConstructor() { + return false; } } @@ -191,20 +234,31 @@ public abstract class ExtensionSignature { public ExpressionExtSignature(ExtendedExpression src) { super(src); + if (src.getType() == null) { + throw new NullPointerException(); + } this.returnType = src.getType(); } + public ExpressionExtSignature(ParametricType src) { + super(src); + this.returnType = factory.makePowerSetType(src); + } + // For testing purposes public ExpressionExtSignature(FormulaFactory factory, IFormulaExtension extension, Type returnType, int numberOfPredicates, Type[] childTypes) { super(factory, extension, numberOfPredicates, childTypes); + if (returnType == null) { + throw new NullPointerException(); + } this.returnType = returnType; } @Override - public Type getFunctionalType() { - return makeRelationalType(makeDomainType(), returnType); + protected Type getReturnType() { + return returnType; } @Override @@ -223,6 +277,11 @@ public abstract class ExtensionSignature { return result; } + @Override + public boolean isATypeConstructor() { + return ((IExpressionExtension) extension).isATypeConstructor(); + } + } } diff --git a/src/org/eventb/internal/core/ast/extension/ExtensionTranslation.java b/src/org/eventb/internal/core/ast/extension/ExtensionTranslation.java index e7ec66b..f7d5e7c 100644 --- a/src/org/eventb/internal/core/ast/extension/ExtensionTranslation.java +++ b/src/org/eventb/internal/core/ast/extension/ExtensionTranslation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Systerel and others. + * Copyright (c) 2014, 2016 Systerel and others. * 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 @@ -12,6 +12,7 @@ package org.eventb.internal.core.ast.extension; import static org.eventb.internal.core.ast.extension.ExtensionSignature.getSignature; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; @@ -20,9 +21,12 @@ import org.eventb.core.ast.ExtendedExpression; import org.eventb.core.ast.ExtendedPredicate; import org.eventb.core.ast.FormulaFactory; import org.eventb.core.ast.FreeIdentifier; +import org.eventb.core.ast.GivenType; import org.eventb.core.ast.IExtensionTranslation; import org.eventb.core.ast.ISealedTypeEnvironment; +import org.eventb.core.ast.ITypeEnvironment.IIterator; import org.eventb.core.ast.ITypeEnvironmentBuilder; +import org.eventb.core.ast.ParametricType; import org.eventb.core.ast.Predicate; import org.eventb.core.ast.Type; import org.eventb.core.ast.datatype.IDatatype; @@ -31,13 +35,17 @@ import org.eventb.internal.core.ast.AbstractTranslation; import org.eventb.internal.core.ast.DefaultTypeCheckingRewriter; import org.eventb.internal.core.ast.FreshNameSolver; import org.eventb.internal.core.ast.ITypeCheckingRewriter; +import org.eventb.internal.core.ast.TypeRewriter; import org.eventb.internal.core.ast.datatype.DatatypeTranslation; import org.eventb.internal.core.ast.extension.ExtensionSignature.ExpressionExtSignature; import org.eventb.internal.core.ast.extension.ExtensionSignature.PredicateExtSignature; import org.eventb.internal.core.ast.extension.ExtensionTranslator.ExpressionExtTranslator; import org.eventb.internal.core.ast.extension.ExtensionTranslator.PredicateExtTranslator; +import org.eventb.internal.core.ast.extension.ExtensionTranslator.TypeExtTranslator; import org.eventb.internal.core.ast.extension.TranslatorRegistry.ExprTranslatorRegistry; import org.eventb.internal.core.ast.extension.TranslatorRegistry.PredTranslatorRegistry; +import org.eventb.internal.core.ast.extension.TranslatorRegistry.TypeTranslatorRegistry; +import org.eventb.internal.core.typecheck.TypeEnvironmentBuilder; /** * Translation of operator extensions to function applications. We do not @@ -57,19 +65,29 @@ public class ExtensionTranslation extends AbstractTranslation implements private final ITypeEnvironmentBuilder trgTypenv; private final FreshNameSolver nameSolver; + private final TypeTranslatorRegistry typeTranslators // + = new TypeTranslatorRegistry(this); private final ExprTranslatorRegistry exprTranslators // = new ExprTranslatorRegistry(this); private final PredTranslatorRegistry predTranslators // = new PredTranslatorRegistry(this); - private ITypeCheckingRewriter rewriter; + private final FunctionalTypeBuilder typeBuilder; + + private final ITypeCheckingRewriter rewriter; public ExtensionTranslation(ISealedTypeEnvironment srcTypenv) { super(srcTypenv); this.trgFactory = computeTargetFactory(srcTypenv.getFormulaFactory()); - this.trgTypenv = srcTypenv.translate(trgFactory).makeBuilder(); - this.nameSolver = new FreshNameSolver(trgTypenv); - this.rewriter = new ExtensionRewriter(trgFactory, this); + final Set<String> usedNames = new HashSet<String>(srcTypenv.getNames()); + this.nameSolver = new FreshNameSolver(usedNames, trgFactory); + + final TypeRewriter typeRewriter; + typeRewriter = new ExtensionTypeRewriter(trgFactory, this); + this.typeBuilder = new FunctionalTypeBuilder(typeRewriter); + this.rewriter = new ExtensionRewriter(typeRewriter, this); + this.trgTypenv = new TypeEnvironmentBuilder(trgFactory); + populateTargetTypenv(typeRewriter); } private static FormulaFactory computeTargetFactory(FormulaFactory fac) { @@ -89,6 +107,17 @@ public class ExtensionTranslation extends AbstractTranslation implements return FormulaFactory.getInstance(keptExtensions); } + private void populateTargetTypenv(TypeRewriter typeRewriter) { + final IIterator iter = srcTypenv.getIterator(); + while (iter.hasNext()) { + iter.advance(); + final String name = iter.getName(); + final Type srcType = iter.getType(); + final Type trgType = typeRewriter.rewrite(srcType); + trgTypenv.addName(name, trgType); + } + } + public FormulaFactory getTargetFactory() { return trgFactory; } @@ -98,6 +127,12 @@ public class ExtensionTranslation extends AbstractTranslation implements return trgTypenv.makeSnapshot(); } + public Type translate(ParametricType src) { + final ExpressionExtSignature signature = getSignature(src); + final TypeExtTranslator translator = typeTranslators.get(signature); + return translator.translate(); + } + public Expression translate(ExtendedExpression src, Expression[] newChildExprs, Predicate[] newChildPreds) { final ExpressionExtSignature signature = getSignature(src); @@ -114,12 +149,34 @@ public class ExtensionTranslation extends AbstractTranslation implements return translator.translate(newChildExprs, newChildPreds); } - public FreeIdentifier makeFunction(ExtensionSignature signature) { + public GivenType makeType(ExtensionSignature signature) { + assert signature.isATypeConstructor(); final String baseName = makeBaseName(signature); - final String name = nameSolver.solve(baseName); - final Type type = signature.getFunctionalType().translate(trgFactory); + final String name = nameSolver.solveAndAdd(baseName); + final GivenType trgType = trgFactory.makeGivenType(name); + trgTypenv.add(trgType.toExpression()); + return trgType; + } + + public FreeIdentifier makeFunction(ExtensionSignature signature) { + String baseName = makeBaseName(signature); + + final Type type; + if (signature.isATypeConstructor()) { + type = signature.getRelationalType(typeBuilder); + if (signature.isAtomic()) { + final GivenType givenType = (GivenType) type.getBaseType(); + return givenType.toExpression(); + } + baseName += "_constr"; + } else { + type = signature.getFunctionalType(typeBuilder); + } + + final String name = nameSolver.solveAndAdd(baseName); final FreeIdentifier ident = trgFactory.makeFreeIdentifier(name, null, type); + trgTypenv.add(ident); return ident; } @@ -130,10 +187,9 @@ public class ExtensionTranslation extends AbstractTranslation implements * fresh name solver will loop forever. */ private String makeBaseName(ExtensionSignature signature) { - final IFormulaExtension extension = signature.getExtension(); - final String id = extension.getId(); - if (trgFactory.isValidIdentifierName(id)) { - return id; + final String symbol = signature.getSymbol(); + if (trgFactory.isValidIdentifierName(symbol)) { + return symbol; } // Use some arbitrary name which can be used for identifiers return "ext"; @@ -150,17 +206,39 @@ public class ExtensionTranslation extends AbstractTranslation implements + srcTypenv.getFormulaFactory() + " in type environment: " + srcTypenv; } - - private static class ExtensionRewriter extends DefaultTypeCheckingRewriter { + + private static class ExtensionTypeRewriter extends TypeRewriter { private ExtensionTranslation translation; - public ExtensionRewriter(FormulaFactory targetFactory, + public ExtensionTypeRewriter(FormulaFactory targetFactory, ExtensionTranslation translation) { super(targetFactory); this.translation = translation; } + @Override + public void visit(ParametricType type) { + if (type.getExprExtension().getOrigin() instanceof IDatatype) { + super.visit(type); + return; + } + + result = translation.translate(type); + } + + } + + private static class ExtensionRewriter extends DefaultTypeCheckingRewriter { + + private ExtensionTranslation translation; + + public ExtensionRewriter(TypeRewriter typeRewriter, + ExtensionTranslation translation) { + super(typeRewriter); + this.translation = translation; + } + @Override public Expression rewrite(ExtendedExpression src, boolean changed, Expression[] newChildExprs, Predicate[] newChildPreds) { diff --git a/src/org/eventb/internal/core/ast/extension/ExtensionTranslator.java b/src/org/eventb/internal/core/ast/extension/ExtensionTranslator.java index 67c63b8..6ead336 100644 --- a/src/org/eventb/internal/core/ast/extension/ExtensionTranslator.java +++ b/src/org/eventb/internal/core/ast/extension/ExtensionTranslator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Systerel and others. + * Copyright (c) 2014, 2016 Systerel and others. * 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 @@ -10,17 +10,21 @@ *******************************************************************************/ package org.eventb.internal.core.ast.extension; +import static org.eventb.core.ast.Formula.CPROD; import static org.eventb.core.ast.Formula.EQUAL; import static org.eventb.core.ast.Formula.FUNIMAGE; import static org.eventb.core.ast.Formula.MAPSTO; +import static org.eventb.core.ast.Formula.RELIMAGE; import static org.eventb.core.ast.Formula.TRUE; import org.eventb.core.ast.Expression; import org.eventb.core.ast.Formula; import org.eventb.core.ast.FormulaFactory; import org.eventb.core.ast.FreeIdentifier; +import org.eventb.core.ast.GivenType; import org.eventb.core.ast.Predicate; import org.eventb.core.ast.RelationalPredicate; +import org.eventb.core.ast.Type; /** * Common implementation of a translator for an extension instance. Instances @@ -30,53 +34,57 @@ import org.eventb.core.ast.RelationalPredicate; */ public abstract class ExtensionTranslator { - protected final FreeIdentifier function; - protected final FormulaFactory factory; + public static class IdentExtTranslator extends ExtensionTranslator { - public ExtensionTranslator(FreeIdentifier function) { - this.function = function; - this.factory = function.getFactory(); - } + protected final FreeIdentifier function; + protected final FormulaFactory factory; - protected Expression makeFunApp(Expression[] newChildExprs, - Predicate[] newChildPreds) { - Expression param = null; - for (final Expression expr : newChildExprs) { - param = join(param, expr); - } - for (final Predicate pred : newChildPreds) { - param = join(param, makeExprOfPred(pred)); - } - if (param == null) { - // Atomic extension - return function; + public IdentExtTranslator(FreeIdentifier function) { + this.function = function; + this.factory = function.getFactory(); } - return factory.makeBinaryExpression(FUNIMAGE, function, param, null); - } + protected Expression makeFunApp(Expression[] newChildExprs, + Predicate[] newChildPreds) { + Expression param = null; + for (final Expression expr : newChildExprs) { + param = join(param, expr); + } + for (final Predicate pred : newChildPreds) { + param = join(param, makeExprOfPred(pred)); + } + if (param == null) { + // Atomic extension + return function; + } + return factory.makeBinaryExpression(FUNIMAGE, function, param, + null); - private Expression makeExprOfPred(Predicate pred) { - if (pred.getTag() == Formula.EQUAL) { - final RelationalPredicate relPred = (RelationalPredicate) pred; - if (relPred.getRight().getTag() == Formula.TRUE) { - return relPred.getLeft(); + } + + private Expression makeExprOfPred(Predicate pred) { + if (pred.getTag() == Formula.EQUAL) { + final RelationalPredicate relPred = (RelationalPredicate) pred; + if (relPred.getRight().getTag() == Formula.TRUE) { + return relPred.getLeft(); + } } + return factory.makeBoolExpression(pred, null); } - return factory.makeBoolExpression(pred, null); - } - /* - * Joins the given expressions with a maplet, unless the first is null. - */ - private Expression join(Expression left, Expression right) { - if (left == null) { - return right; + /* + * Joins the given expressions with a maplet, unless the first is null. + */ + private Expression join(Expression left, Expression right) { + if (left == null) { + return right; + } + return factory.makeBinaryExpression(MAPSTO, left, right, null); } - return factory.makeBinaryExpression(MAPSTO, left, right, null); + } - public static class PredicateExtTranslator extends - ExtensionTranslator { + public static class PredicateExtTranslator extends IdentExtTranslator { private final Expression btrue; @@ -96,8 +104,7 @@ public abstract class ExtensionTranslator { } - public static class ExpressionExtTranslator extends - ExtensionTranslator { + public static class ExpressionExtTranslator extends IdentExtTranslator { public ExpressionExtTranslator(FreeIdentifier function) { super(function); @@ -110,4 +117,66 @@ public abstract class ExtensionTranslator { } + public static class TypeConstructorTranslator extends ExpressionExtTranslator { + + public TypeConstructorTranslator(FreeIdentifier relation) { + super(relation); + } + + @Override + public Expression translate(Expression[] newChildExprs, + Predicate[] newChildPreds) { + return makeRelApp(newChildExprs, newChildPreds); + } + + private Expression makeRelApp(Expression[] newChildExprs, + Predicate[] newChildPreds) { + Expression param = null; + for (final Expression expr : newChildExprs) { + param = joinProd(param, expr); + } + assert newChildPreds.length == 0; + if (param == null) { + // Atomic extension + return function; + } + if (param.isATypeExpression()) { + return function.getType().getTarget().toExpression(); + } + return factory.makeBinaryExpression(RELIMAGE, function, param, + null); + } + + /* + * Joins the given expressions with a Cartesian product, unless the + * first is null. + */ + private Expression joinProd(Expression left, Expression right) { + if (left == null) { + return right; + } + return factory.makeBinaryExpression(CPROD, left, right, null); + } + + } + + /** + * Translator for a parametric type. The translation class has allocated a + * given type that corresponds to the parametric type instance and we just + * return this given type (there are no type polymorphism in plain Event-B). + */ + public static class TypeExtTranslator extends ExtensionTranslator { + + private final Type type; + + public TypeExtTranslator(GivenType type) { + this.type = type; + } + + public Type translate() { + return type; + } + + } + } diff --git a/src/org/eventb/internal/core/ast/extension/FunctionalTypeBuilder.java b/src/org/eventb/internal/core/ast/extension/FunctionalTypeBuilder.java new file mode 100644 index 0000000..6620f63 --- /dev/null +++ b/src/org/eventb/internal/core/ast/extension/FunctionalTypeBuilder.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2014, 2016 Systerel and others. + * 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: + * Systerel - initial API and implementation + *******************************************************************************/ +package org.eventb.internal.core.ast.extension; + +import org.eventb.core.ast.FormulaFactory; +import org.eventb.core.ast.Type; +import org.eventb.internal.core.ast.TypeRewriter; + +/** + * A class which allows to build the type of a function or constant that + * replaces a mathematical extension. + * + * @author Thomas Muller + * @author Laurent Voisin + */ +public class FunctionalTypeBuilder { + + // How to rewrite the types coming from the source language. + private final TypeRewriter rewriter; + + // The formula factory of the target language + private final FormulaFactory factory; + + public FunctionalTypeBuilder(TypeRewriter rewriter) { + this.rewriter = rewriter; + this.factory = rewriter.getFactory(); + } + + public Type makeFunctionalType(Type[] children, int numberOfPredicates, + Type range) { + final Type trgDomain = makeDomainType(children, numberOfPredicates); + final Type trgRange = rewriter.rewrite(range); + if (trgDomain == null) { + // Atomic operator + return trgRange; + } + return factory.makeRelationalType(trgDomain, trgRange); + } + + public Type makeRelationalType(Type[] children, Type range) { + final Type trgDomain = makeRelDomainType(children); + final Type trgRange = rewriter.rewrite(range); + if (trgDomain == null) { + // Atomic operator + return trgRange; + } + final Type trgBase = trgRange.getBaseType(); + assert trgBase != null; + return factory.makeRelationalType(trgDomain, trgBase); + } + + private Type makeDomainType(Type[] children, int numberOfPredicates) { + Type result = null; + for (Type child : children) { + final Type trgChild = rewriter.rewrite(child); + result = join(result, trgChild); + } + final Type boolType = factory.makeBooleanType(); + for (int i = 0; i < numberOfPredicates; i++) { + result = join(result, boolType); + } + return result; + } + + private Type makeRelDomainType(Type[] children) { + Type result = null; + for (final Type child : children) { + final Type base = child.getBaseType(); + assert base != null; + final Type trgChild = rewriter.rewrite(base); + result = join(result, trgChild); + } + return result; + } + + private Type join(Type left, Type right) { + if (left == null) { + return right; + } + return factory.makeProductType(left, right); + } + +} \ No newline at end of file diff --git a/src/org/eventb/internal/core/ast/extension/TranslatorRegistry.java b/src/org/eventb/internal/core/ast/extension/TranslatorRegistry.java index 3164013..371d01a 100644 --- a/src/org/eventb/internal/core/ast/extension/TranslatorRegistry.java +++ b/src/org/eventb/internal/core/ast/extension/TranslatorRegistry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2014 Systerel and others. + * Copyright (c) 2014, 2016 Systerel and others. * 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 @@ -14,10 +14,13 @@ import java.util.HashMap; import java.util.Map; import org.eventb.core.ast.FreeIdentifier; +import org.eventb.core.ast.GivenType; import org.eventb.internal.core.ast.extension.ExtensionSignature.ExpressionExtSignature; import org.eventb.internal.core.ast.extension.ExtensionSignature.PredicateExtSignature; import org.eventb.internal.core.ast.extension.ExtensionTranslator.ExpressionExtTranslator; import org.eventb.internal.core.ast.extension.ExtensionTranslator.PredicateExtTranslator; +import org.eventb.internal.core.ast.extension.ExtensionTranslator.TypeConstructorTranslator; +import org.eventb.internal.core.ast.extension.ExtensionTranslator.TypeExtTranslator; /** * Maintains a map between extension signatures and extension translations. Two @@ -28,7 +31,7 @@ import org.eventb.internal.core.ast.extension.ExtensionTranslator.PredicateExtTr */ public abstract class TranslatorRegistry<S extends ExtensionSignature, T extends ExtensionTranslator> { - private final ExtensionTranslation translation; + protected final ExtensionTranslation translation; private final Map<S, T> translators = new HashMap<S, T>(); @@ -39,14 +42,13 @@ public abstract class TranslatorRegistry<S extends ExtensionSignature, T extends public T get(S signature) { T result = translators.get(signature); if (result == null) { - final FreeIdentifier function = translation.makeFunction(signature); - result = newTranslator(function); + result = newTranslator(signature); translators.put(signature, result); } return result; } - protected abstract T newTranslator(FreeIdentifier function); + protected abstract T newTranslator(S signature); public static class PredTranslatorRegistry extends TranslatorRegistry<PredicateExtSignature, PredicateExtTranslator> { @@ -56,7 +58,9 @@ public abstract class TranslatorRegistry<S extends ExtensionSignature, T extends } @Override - protected PredicateExtTranslator newTranslator(FreeIdentifier function) { + protected PredicateExtTranslator newTranslator( + PredicateExtSignature signature) { + final FreeIdentifier function = translation.makeFunction(signature); return new PredicateExtTranslator(function); } @@ -70,10 +74,32 @@ public abstract class TranslatorRegistry<S extends ExtensionSignature, T extends } @Override - protected ExpressionExtTranslator newTranslator(FreeIdentifier function) { + protected ExpressionExtTranslator newTranslator( + ExpressionExtSignature signature) { + final FreeIdentifier function = translation.makeFunction(signature); + if (signature.isATypeConstructor()) { + return new TypeConstructorTranslator(function); + } return new ExpressionExtTranslator(function); } } + public static class TypeTranslatorRegistry extends + TranslatorRegistry<ExpressionExtSignature, TypeExtTranslator> { + + public TypeTranslatorRegistry(ExtensionTranslation translation) { + super(translation); + } + + @Override + protected TypeExtTranslator newTranslator( + ExpressionExtSignature signature) { + assert (signature.isATypeConstructor()); + final GivenType type = translation.makeType(signature); + return new TypeExtTranslator(type); + } + + } + } diff --git a/src/org/eventb/internal/core/parser/SubParsers.java b/src/org/eventb/internal/core/parser/SubParsers.java index d15bedc..2ea5a18 100644 --- a/src/org/eventb/internal/core/parser/SubParsers.java +++ b/src/org/eventb/internal/core/parser/SubParsers.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010, 2014 Systerel and others. + * Copyright (c) 2010, 2016 Systerel and others. * 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 @@ -958,6 +958,36 @@ public class SubParsers { } } + public static class ExtendedRelationalPredicateParser extends BinaryLedExprParser<ExtendedPredicate> { + + public ExtendedRelationalPredicateParser(int kind, int tag) { + super(kind, tag); + } + + @Override + protected void checkValue(ParserContext pc, + Expression left, Expression right) + throws SyntaxError { + EXTENDED_PRED.check(pc, tag, asList(left, right)); + } + + @Override + protected ExtendedPredicate makeValue(FormulaFactory factory, + Expression left, Expression right, SourceLocation loc) throws SyntaxError { + return EXTENDED_PRED.make(factory, tag, asList(left, right), loc); + } + + @Override + protected Expression getLeft(ExtendedPredicate parent) { + return parent.getChildExpressions()[0]; + } + + @Override + protected Expression getRight(ExtendedPredicate parent) { + return parent.getChildExpressions()[1]; + } + } + public static abstract class LedImage extends BinaryLedExprParser<BinaryExpression> { public LedImage(int kind, int tag) { @@ -1065,6 +1095,29 @@ public class SubParsers { } } + public static class ExtendedBinaryPredicateParser extends BinaryLedPredParser<ExtendedPredicate> { + + public ExtendedBinaryPredicateParser(int kind, int tag) { + super(kind, tag); + } + + @Override + protected ExtendedPredicate makeValue(FormulaFactory factory, Predicate left, + Predicate right, SourceLocation loc) throws SyntaxError { + return EXTENDED_PRED.make(factory, tag, asList(left, right), loc); + } + + @Override + protected Predicate getLeft(ExtendedPredicate parent) { + return parent.getChildPredicates()[0]; + } + + @Override + protected Predicate getRight(ExtendedPredicate parent) { + return parent.getChildPredicates()[1]; + } + } + public static class QuantifiedPredicateParser extends QuantifiedParser<QuantifiedPredicate> { public QuantifiedPredicateParser(int kind, int tag) { -- GitLab