Commit 04755f71 authored by Dennis Hendriks's avatar Dennis Hendriks
Browse files

Merge branch 'develop' into 'master'

#264 master to develop for v0.5-RC1

See merge request !287
parents dcc21995 8239cb07
Pipeline #2706 passed with stage
in 0 seconds
......@@ -11,8 +11,8 @@
-->
<extensions>
<extension>
<groupId>org.eclipse.tycho.extras</groupId>
<artifactId>tycho-pomless</artifactId>
<version>2.5.0</version>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-build</artifactId>
<version>2.7.0</version>
</extension>
</extensions>
This diff is collapsed.
......@@ -30,6 +30,7 @@ TBD
Improvements and fixes:
* Some small changes to the documentation (issue #271).
* The release notes for each version now contain the release date, with the exception of milestone releases and release candidates (issue #314).
=== Version 0.4 (2021-12-17)
......
......@@ -197,13 +197,15 @@ An example:
int i = 5;
real r = 3.14;
write("%4d/%8.2f", i, r)
write("Result:\n");
write("%4d/%8.2f", i, r);
----
This fragment has the effect that the values of `i` and `r` are written to the screen as follows:
[source, console]
----
Result:
5/ 3.14
----
......@@ -277,13 +279,16 @@ An example is:
----
int i = 5, j = 10;
real r = 3.14;
write("%6d\t%d\n\t%.2f\n", i, j, r)
write("Result:\n");
write("%6d\t%d\n\t%.2f\n", i, j, r);
----
The result looks like:
[source, console]
----
Result:
5 10
3.14
----
......
......@@ -23,7 +23,10 @@ import java.util.List;
import java.util.Map;
import org.eclipse.escet.cif.cif2cif.AddDefaultInitialValues;
import org.eclipse.escet.cif.cif2cif.AnonymizeNames;
import org.eclipse.escet.cif.cif2cif.CifToCifTransformation;
import org.eclipse.escet.cif.cif2cif.ConvertEventsControllability.ConvertCntrlEventsToUncntrl;
import org.eclipse.escet.cif.cif2cif.ConvertEventsControllability.ConvertUncntrlEventsToCntrl;
import org.eclipse.escet.cif.cif2cif.ElimAlgVariables;
import org.eclipse.escet.cif.cif2cif.ElimAutCasts;
import org.eclipse.escet.cif.cif2cif.ElimComponentDefInst;
......@@ -50,6 +53,7 @@ import org.eclipse.escet.cif.cif2cif.RemoveIoDecls;
import org.eclipse.escet.cif.cif2cif.RemovePositionInfo;
import org.eclipse.escet.cif.cif2cif.RemovePrintDecls;
import org.eclipse.escet.cif.cif2cif.RemoveRequirements;
import org.eclipse.escet.cif.cif2cif.RemoveUnusedAlgVariables;
import org.eclipse.escet.cif.cif2cif.SimplifyOthers;
import org.eclipse.escet.cif.cif2cif.SimplifyValues;
import org.eclipse.escet.cif.cif2cif.SimplifyValuesNoRefs;
......@@ -94,6 +98,9 @@ public class CifToCifTransOption extends Option<String> {
TRANSFORMATIONS = map();
TRANSFORMATIONS.put("add-default-init-values", AddDefaultInitialValues.class);
TRANSFORMATIONS.put("anonymize-names", AnonymizeNames.class);
TRANSFORMATIONS.put("convert-uncntrl-events-to-cntrl", ConvertUncntrlEventsToCntrl.class);
TRANSFORMATIONS.put("convert-cntrl-events-to-uncntrl", ConvertCntrlEventsToUncntrl.class);
TRANSFORMATIONS.put("elim-alg-vars", ElimAlgVariables.class);
TRANSFORMATIONS.put("elim-aut-casts", ElimAutCasts.class);
TRANSFORMATIONS.put("elim-comp-def-inst", ElimComponentDefInst.class);
......@@ -121,6 +128,7 @@ public class CifToCifTransOption extends Option<String> {
TRANSFORMATIONS.put("remove-print-decls", RemovePrintDecls.class);
TRANSFORMATIONS.put("remove-pos-info", RemovePositionInfo.class);
TRANSFORMATIONS.put("remove-reqs", RemoveRequirements.class);
TRANSFORMATIONS.put("remove-unused-alg-vars", RemoveUnusedAlgVariables.class);
TRANSFORMATIONS.put("simplify-others", SimplifyOthers.class);
TRANSFORMATIONS.put("simplify-values", SimplifyValues.class);
TRANSFORMATIONS.put("simplify-values-optimized", SimplifyValuesOptimized.class);
......
//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2022 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available
// under the terms of the MIT License which is available at
// https://opensource.org/licenses/MIT
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
package org.eclipse.escet.cif.cif2cif;
import static org.eclipse.escet.common.java.Lists.list;
import static org.eclipse.escet.common.java.Maps.map;
import java.util.List;
import java.util.Map;
import org.eclipse.escet.cif.common.CifCollectUtils;
import org.eclipse.escet.cif.common.CifEnumUtils;
import org.eclipse.escet.cif.common.CifTypeUtils;
import org.eclipse.escet.cif.metamodel.cif.AlgParameter;
import org.eclipse.escet.cif.metamodel.cif.ComponentDef;
import org.eclipse.escet.cif.metamodel.cif.ComponentInst;
import org.eclipse.escet.cif.metamodel.cif.ComponentParameter;
import org.eclipse.escet.cif.metamodel.cif.EventParameter;
import org.eclipse.escet.cif.metamodel.cif.Group;
import org.eclipse.escet.cif.metamodel.cif.LocationParameter;
import org.eclipse.escet.cif.metamodel.cif.Specification;
import org.eclipse.escet.cif.metamodel.cif.automata.Automaton;
import org.eclipse.escet.cif.metamodel.cif.automata.Location;
import org.eclipse.escet.cif.metamodel.cif.declarations.AlgVariable;
import org.eclipse.escet.cif.metamodel.cif.declarations.Constant;
import org.eclipse.escet.cif.metamodel.cif.declarations.ContVariable;
import org.eclipse.escet.cif.metamodel.cif.declarations.DiscVariable;
import org.eclipse.escet.cif.metamodel.cif.declarations.EnumDecl;
import org.eclipse.escet.cif.metamodel.cif.declarations.EnumLiteral;
import org.eclipse.escet.cif.metamodel.cif.declarations.Event;
import org.eclipse.escet.cif.metamodel.cif.declarations.InputVariable;
import org.eclipse.escet.cif.metamodel.cif.declarations.TypeDecl;
import org.eclipse.escet.cif.metamodel.cif.expressions.CastExpression;
import org.eclipse.escet.cif.metamodel.cif.functions.Function;
import org.eclipse.escet.cif.metamodel.cif.functions.FunctionParameter;
import org.eclipse.escet.cif.metamodel.cif.types.CifType;
import org.eclipse.escet.cif.metamodel.cif.types.Field;
import org.eclipse.escet.cif.metamodel.cif.types.StringType;
import org.eclipse.escet.cif.metamodel.cif.types.TupleType;
import org.eclipse.escet.cif.metamodel.java.CifWalker;
import org.eclipse.escet.common.java.Assert;
/**
* In-place transformation that anonymizes the names of all named objects.
*
* <p>
* Precondition: Specifications with automaton to string casts are not supported.
* </p>
*/
public class AnonymizeNames extends CifWalker implements CifToCifTransformation {
/**
* Mapping from name prefixes to the next free number for that prefix. Mapping starts empty, and entries are added
* as needed.
*/
private Map<String, Integer> nextFreeNumbers;
/** Mapping from enumeration declarations to their representatives. */
private Map<EnumDecl, EnumDecl> enumRepresentatives;
/** Mapping of enumeration literals of representative enumerations to their new names. */
private Map<EnumLiteral, String> enumLitRepresentativesNewNames;
@Override
public void transform(Specification spec) {
// Clear next free number administration.
nextFreeNumbers = map();
// Get enumeration representatives.
List<EnumDecl> enumDecls = list();
CifCollectUtils.collectEnumDecls(spec, enumDecls);
enumRepresentatives = CifEnumUtils.getEnumDeclReprs(enumDecls);
// Assign new names to enumeration literals of enumeration representatives.
enumLitRepresentativesNewNames = map();
for (EnumDecl enumDecl: enumRepresentatives.values()) {
for (EnumLiteral lit: enumDecl.getLiterals()) {
enumLitRepresentativesNewNames.put(lit, getName("lit"));
}
}
// Perform the transformation by walking over the specification.
walkSpecification(spec);
}
@Override
protected void preprocessCastExpression(CastExpression castExpr) {
// Automaton to string casts are not supported, to prevent the resulting specification from becoming invalid.
// For instance, the renamed locations of the automaton could be compared to string literals.
CifType childType = CifTypeUtils.normalizeType(castExpr.getChild().getType());
CifType resultType = CifTypeUtils.normalizeType(castExpr.getType());
if (CifTypeUtils.hasComponentLikeType(childType) && resultType instanceof StringType) {
throw new CifToCifPreconditionException("Anonymizing names for a CIF specification with automaton to "
+ "string casts is currently not supported.");
}
}
/**
* Returns a new name for an object to anonymize.
*
* @param prefix The prefix for the name.
* @return The new name.
*/
private String getName(String prefix) {
Integer nextNr = nextFreeNumbers.get(prefix);
if (nextNr == null) {
nextNr = 1;
}
nextFreeNumbers.put(prefix, nextNr + 1);
return prefix + nextNr;
}
@Override
protected void preprocessAutomaton(Automaton automaton) {
if (automaton.eContainer() instanceof ComponentDef) {
// Body of an automaton definition.
automaton.setName(getName("autdef"));
} else {
// Automaton.
automaton.setName(getName("aut"));
}
}
@Override
protected void preprocessGroup(Group group) {
if (group instanceof Specification) {
// Specifications must have 'specification' as their name.
Assert.check("specification".equals(group.getName()));
} else if (group.eContainer() instanceof ComponentDef) {
// Body of a group definition.
group.setName(getName("grpdef"));
} else {
// Group.
group.setName(getName("grp"));
}
}
@Override
protected void preprocessComponentInst(ComponentInst componentInst) {
componentInst.setName(getName("inst"));
}
@Override
protected void preprocessAlgVariable(AlgVariable algVar) {
if (algVar.eContainer() instanceof AlgParameter) {
// Algebraic parameter.
algVar.setName(getName("aparam"));
} else {
// Algebraic variable.
algVar.setName(getName("alg"));
}
}
@Override
protected void preprocessConstant(Constant constant) {
constant.setName(getName("const"));
}
@Override
protected void preprocessContVariable(ContVariable contVar) {
contVar.setName(getName("cont"));
}
@Override
protected void preprocessDiscVariable(DiscVariable discVar) {
if (discVar.eContainer() instanceof FunctionParameter) {
// Function parameter.
discVar.setName(getName("fparam"));
} else {
// Discrete variable.
discVar.setName(getName("disc"));
}
}
@Override
protected void preprocessEnumDecl(EnumDecl enumDecl) {
enumDecl.setName(getName("enum"));
}
@Override
protected void preprocessEvent(Event event) {
// Give name based on being a parameter or an event.
if (event.eContainer() instanceof EventParameter) {
// Event parameter.
event.setName(getName("eparam"));
} else {
// Event.
event.setName(getName("evt"));
}
// Prefix event name based on its supervisory kind. Don't prefix events without a supervisory kind, to prevent
// introducing such prefixes for specifications without (un)controllable events.
if (event.getControllable() != null) {
String prefix = event.getControllable() ? "c_" : "u_";
event.setName(prefix + event.getName());
}
}
@Override
protected void preprocessFunction(Function function) {
function.setName(getName("func"));
}
@Override
protected void preprocessInputVariable(InputVariable inputVar) {
inputVar.setName(getName("input"));
}
@Override
protected void preprocessTypeDecl(TypeDecl typeDecl) {
typeDecl.setName(getName("type"));
}
@Override
protected void preprocessLocation(Location location) {
if (location.eContainer() instanceof LocationParameter) {
// Location parameter.
Assert.notNull(location.getName());
location.setName(getName("lparam"));
} else {
// Location.
if (location.getName() != null) {
location.setName(getName("loc"));
}
}
}
@Override
protected void preprocessComponentParameter(ComponentParameter compParam) {
compParam.setName(getName("cparam"));
}
@Override
protected void preprocessEnumLiteral(EnumLiteral enumLit) {
// Compatible enumerations will need to remain compatible.
// We use the new names obtained previously for the literals of enumeration representatives.
// Get enumeration representative.
EnumDecl enumDecl = (EnumDecl)enumLit.eContainer();
EnumDecl enumRepresentative = enumRepresentatives.get(enumDecl);
// Get literal representative.
int index = enumDecl.getLiterals().indexOf(enumLit);
EnumLiteral litRepresentative = enumRepresentative.getLiterals().get(index);
// Assign new name.
enumLit.setName(enumLitRepresentativesNewNames.get(litRepresentative));
}
@Override
protected void preprocessField(Field field) {
// Tuple type compatibility is based on field types, not field names.
// But a tuple-typed variable and a projection on that variable with a field name, must use matching names.
// Given that each tuple type has unique 'Field' class instances, we can't use global numbering.
// Hence, rather than global numbering, we number based on field indices.
if (field.getName() != null) {
TupleType tupleType = (TupleType)field.eContainer();
int index = tupleType.getFields().indexOf(field);
field.setName("field" + Integer.toString(index + 1));
}
}
}
//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available
// under the terms of the MIT License which is available at
// https://opensource.org/licenses/MIT
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
package org.eclipse.escet.cif.cif2cif;
import static java.util.Collections.emptySet;
import static org.eclipse.escet.cif.common.CifCollectUtils.collectEvents;
import static org.eclipse.escet.cif.common.CifScopeUtils.getScope;
import static org.eclipse.escet.cif.common.CifScopeUtils.getSymbolNamesForScope;
import static org.eclipse.escet.cif.common.CifScopeUtils.getUniqueName;
import static org.eclipse.escet.cif.common.CifScopeUtils.hasCompDefInst;
import static org.eclipse.escet.common.java.Lists.list;
import static org.eclipse.escet.common.java.Strings.fmt;
import java.util.List;
import java.util.Set;
import org.eclipse.escet.cif.common.ScopeCache;
import org.eclipse.escet.cif.metamodel.cif.Specification;
import org.eclipse.escet.cif.metamodel.cif.declarations.Event;
/**
* Basic class to convert events with a controllability status.
*
* <p>
* It also contains an inner class to convert all uncontrollable events to controllable events and an inner
* class to convert all controllable events to uncontrollable events.
* </p>
*
* <p>
* Precondition: Specifications with component definitions/instantiations are currently not supported.
* </p>
*/
public final class ConvertEventsControllability {
@SuppressWarnings("javadoc")
private ConvertEventsControllability() {
// Static class.
}
/**
* Converts events with a controllability status in the given specification to the desired controllability status.
*
* <p>
* Event names of modified events are changed if they use the specific prefix "c_" or "u_".
* </p>
*
* @param spec The specification to adapt.
* @param toControllable Set to {@code true} to convert uncontrollable events to controllable events or
* {@code false} to convert controllable events to uncontrollable events.
*/
public static void convert(Specification spec, boolean toControllable) {
// Check no component definition/instantiation precondition.
if (hasCompDefInst(spec)) {
String eventSource = toControllable ? "uncontrollable" : "controllable";
String eventDestination = toControllable ? "controllable" : "uncontrollable";
String msg = fmt("Converting %s events to %s events", eventSource, eventDestination);
throw new CifToCifPreconditionException(
msg + " in a CIF specification with component definitions is currently not supported.");
}
// Collect the events of the specification.
List<Event> events = list();
collectEvents(spec, events);
// Change the events.
String prefixToReplace = toControllable ? "u_" : "c_";
String prefixReplacement = toControllable ? "c_" : "u_";
ScopeCache scopeCache = new ScopeCache();
for (Event event: events) {
if (event.getControllable() != null && event.getControllable() != toControllable) {
event.setControllable(toControllable);
// Change the name if necessary.
String name = event.getName();
Set<String> localNames = getSymbolNamesForScope(getScope(event), scopeCache);
if (name.startsWith(prefixToReplace)) {
String newName = prefixReplacement + name.substring(prefixToReplace.length());
// If the new name also exists, find a better name.
if (localNames.contains(newName)) {
newName = getUniqueName(newName, localNames, emptySet());
}
event.setName(newName);
localNames.remove(name);
localNames.add(newName);
}
// Else name was not modified, no need to rename.
}
}
}
/**
* In-place transformation that converts all uncontrollable events to controllable events.
*
* <p>
* Precondition: Specifications with component definitions/instantiations are currently not supported.
* </p>
*/
public static class ConvertUncntrlEventsToCntrl implements CifToCifTransformation {
@Override
public void transform(Specification spec) {
convert(spec, true);
}
}
/**
* In-place transformation that converts all controllable events to uncontrollable events.
*
* <p>
* Precondition: Specifications with component definitions/instantiations are currently not supported.
* </p>
*/
public static class ConvertCntrlEventsToUncntrl implements CifToCifTransformation {
@Override
public void transform(Specification spec) {
convert(spec, false);
}
}
}
//////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available
// under the terms of the MIT License which is available at
// https://opensource.org/licenses/MIT
//
// SPDX-License-Identifier: MIT
//////////////////////////////////////////////////////////////////////////////
package org.eclipse.escet.cif.cif2cif;
import static org.eclipse.escet.common.java.Lists.filter;
import static org.eclipse.escet.common.java.Lists.list;
import static org.eclipse.escet.common.java.Maps.map;
import static org.eclipse.escet.common.java.Sets.difference;
import static org.eclipse.escet.common.java.Sets.set;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.escet.cif.common.CifScopeUtils;
import org.eclipse.escet.cif.metamodel.cif.ComplexComponent;
import org.eclipse.escet.cif.metamodel.cif.Equation;
import org.eclipse.escet.cif.metamodel.cif.Specification;
import org.eclipse.escet.cif.metamodel.cif.declarations.AlgVariable;
import org.eclipse.escet.cif.metamodel.cif.expressions.AlgVariableExpression;
import org.eclipse.escet.cif.metamodel.java.CifWalker;
import org.eclipse.escet.common.emf.EMFHelper;
/**
* In-place transformation that removes unused algebraic variables and their equations.
*
* <p>
* Precondition: Specifications with component definitions/instantiations are currently not supported.
* </p>
*/
public class RemoveUnusedAlgVariables extends CifWalker implements CifToCifTransformation {
/** All algebraic variables encountered so far. */
private Set<AlgVariable> allAlgVars = set();
/** All algebraic variables used in expressions outside value expressions of other algebraic variables. */
private Set<AlgVariable> allUsedAlgVars = set();
/** Map of algebraic variables to the collection of algebraic variables used in its defining expressions. */
private Map<AlgVariable, Set<AlgVariable>> algVarsReferredByAlgVar = map();
/**
* If not {@code null}, the algebraic variable owning the value expression or equation that is currently being
* analyzed.
*/
private AlgVariable analyzingAlgVar = null;
/** Equations defining values for algebraic variables. */
private final List<Equation> algEquations = list();
@Override
public void transform(Specification spec) {
// Check no component definition/instantiation precondition.
if (CifScopeUtils.hasCompDefInst(spec)) {
String msg = "Eliminating unused algebraic variables from a CIF specification with component "
+ "definitions is currently not supported.";
throw new CifToCifPreconditionException(msg);
}