-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #962 from lf-lang/inheritance-cleanups
Inheritance cleanups
- Loading branch information
Showing
3 changed files
with
154 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,14 +27,15 @@ | |
|
||
package org.lflang; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.ArrayList; | ||
import java.util.LinkedHashMap; | ||
import java.util.LinkedHashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import com.google.common.collect.Iterables; | ||
import com.google.common.collect.Iterators; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
import java.util.stream.Collectors; | ||
|
||
import org.eclipse.emf.ecore.EObject; | ||
import org.eclipse.emf.ecore.resource.Resource; | ||
|
@@ -47,12 +48,11 @@ | |
import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; | ||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils; | ||
import org.eclipse.xtext.resource.XtextResource; | ||
import org.eclipse.xtext.xbase.lib.CollectionExtensions; | ||
import org.eclipse.xtext.xbase.lib.IterableExtensions; | ||
import org.eclipse.xtext.xbase.lib.IteratorExtensions; | ||
import org.eclipse.xtext.xbase.lib.StringExtensions; | ||
import org.lflang.generator.GeneratorBase; | ||
import org.lflang.generator.CodeMap; | ||
import org.lflang.generator.GeneratorBase; | ||
import org.lflang.generator.InvalidSourceException; | ||
import org.lflang.lf.Action; | ||
import org.lflang.lf.ActionOrigin; | ||
|
@@ -84,6 +84,9 @@ | |
import org.lflang.lf.WidthSpec; | ||
import org.lflang.lf.WidthTerm; | ||
|
||
import com.google.common.collect.Iterables; | ||
import com.google.common.collect.Iterators; | ||
|
||
/** | ||
* A helper class for modifying and analyzing the AST. | ||
* @author{Marten Lohstroh <[email protected]>} | ||
|
@@ -447,13 +450,7 @@ public static String getUniqueIdentifier(Reactor reactor, String name) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Action> allActions(Reactor definition) { | ||
List<Action> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allActions(toDefinition(base))); | ||
} | ||
result.addAll(definition.getActions()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getActions()); | ||
} | ||
|
||
/** | ||
|
@@ -462,28 +459,19 @@ public static List<Action> allActions(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Connection> allConnections(Reactor definition) { | ||
List<Connection> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allConnections(toDefinition(base))); | ||
} | ||
result.addAll(definition.getConnections()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getConnections()); | ||
} | ||
|
||
/** | ||
* Given a reactor class, return a list of all its inputs, | ||
* which includes inputs of base classes that it extends. | ||
* If the base classes include a cycle, where X extends Y and Y extends X, | ||
* then return only the input defined in the base class. | ||
* The returned list may be empty. | ||
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Input> allInputs(Reactor definition) { | ||
List<Input> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allInputs(toDefinition(base))); | ||
} | ||
result.addAll(definition.getInputs()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getInputs()); | ||
} | ||
|
||
/** | ||
|
@@ -492,13 +480,7 @@ public static List<Input> allInputs(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Instantiation> allInstantiations(Reactor definition) { | ||
List<Instantiation> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allInstantiations(toDefinition(base))); | ||
} | ||
result.addAll(definition.getInstantiations()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getInstantiations()); | ||
} | ||
|
||
/** | ||
|
@@ -507,13 +489,7 @@ public static List<Instantiation> allInstantiations(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Output> allOutputs(Reactor definition) { | ||
List<Output> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allOutputs(toDefinition(base))); | ||
} | ||
result.addAll(definition.getOutputs()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getOutputs()); | ||
} | ||
|
||
/** | ||
|
@@ -522,13 +498,7 @@ public static List<Output> allOutputs(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Parameter> allParameters(Reactor definition) { | ||
List<Parameter> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allParameters(toDefinition(base))); | ||
} | ||
result.addAll(definition.getParameters()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getParameters()); | ||
} | ||
|
||
/** | ||
|
@@ -537,13 +507,7 @@ public static List<Parameter> allParameters(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Reaction> allReactions(Reactor definition) { | ||
List<Reaction> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allReactions(toDefinition(base))); | ||
} | ||
result.addAll(definition.getReactions()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getReactions()); | ||
} | ||
|
||
/** | ||
|
@@ -552,13 +516,7 @@ public static List<Reaction> allReactions(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<StateVar> allStateVars(Reactor definition) { | ||
List<StateVar> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allStateVars(toDefinition(base))); | ||
} | ||
result.addAll(definition.getStateVars()); | ||
return result; | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getStateVars()); | ||
} | ||
|
||
/** | ||
|
@@ -567,12 +525,43 @@ public static List<StateVar> allStateVars(Reactor definition) { | |
* @param definition Reactor class definition. | ||
*/ | ||
public static List<Timer> allTimers(Reactor definition) { | ||
List<Timer> result = new ArrayList<>(); | ||
List<ReactorDecl> superClasses = convertToEmptyListIfNull(definition.getSuperClasses()); | ||
for (ReactorDecl base : superClasses) { | ||
result.addAll(allTimers(toDefinition(base))); | ||
return ASTUtils.collectElements(definition, (Reactor r) -> r.getTimers()); | ||
} | ||
|
||
/** | ||
* Return all the superclasses of the specified reactor | ||
* in deepest-first order. For example, if A extends B and C, and | ||
* B and C both extend D, this will return the list [D, B, C, A]. | ||
* Duplicates are removed. If the specified reactor does not extend | ||
* any other reactor, then return an empty list. | ||
* If a cycle is found, where X extends Y and Y extends X, or if | ||
* a superclass is declared that is not found, then return null. | ||
* @param reactor The specified reactor. | ||
*/ | ||
public static LinkedHashSet<Reactor> superClasses(Reactor reactor) { | ||
return superClasses(reactor, new LinkedHashSet<Reactor>()); | ||
} | ||
|
||
/** | ||
* Collect elements of type T from the class hierarchy defined by | ||
* a given reactor definition. | ||
* @param definition The reactor definition. | ||
* @param elements A function that maps a reactor definition to a list of | ||
* elements of type T. | ||
* @param <T> The type of elements to collect (e.g., Port, Timer, etc.) | ||
* @return | ||
*/ | ||
public static <T> List<T> collectElements(Reactor definition, Function<Reactor,List<T>> elements) { | ||
List<T> result = new ArrayList<T>(); | ||
// Add elements of elements defined in superclasses. | ||
LinkedHashSet<Reactor> s = superClasses(definition); | ||
if (s != null) { | ||
for (Reactor superClass : s) { | ||
result.addAll(elements.apply(superClass)); | ||
} | ||
} | ||
result.addAll(definition.getTimers()); | ||
// Add elements of the current reactor. | ||
result.addAll(elements.apply(definition)); | ||
return result; | ||
} | ||
|
||
|
@@ -894,7 +883,7 @@ public static String baseType(Type type) { | |
|
||
/** | ||
* Report whether the given literal is zero or not. | ||
* @param literalOrCode AST node to inspect. | ||
* @param literal AST node to inspect. | ||
* @return True if the given literal denotes the constant `0`, false | ||
* otherwise. | ||
*/ | ||
|
@@ -997,7 +986,7 @@ public static boolean isValidTime(Value value) { | |
|
||
/** | ||
* Report whether the given time denotes a valid time or not. | ||
* @param value AST node to inspect. | ||
* @param t AST node to inspect. | ||
* @return True if the argument denotes a valid time, false otherwise. | ||
*/ | ||
public static boolean isValidTime(Time t) { | ||
|
@@ -1010,7 +999,7 @@ public static boolean isValidTime(Time t) { | |
/** | ||
* Report whether the given parameter denotes time list, meaning it is a list | ||
* of which all elements are valid times. | ||
* @param value AST node to inspect. | ||
* @param p AST node to inspect. | ||
* @return True if the argument denotes a valid time list, false otherwise. | ||
*/ | ||
// TODO: why does this function always return true ??? | ||
|
@@ -1094,7 +1083,7 @@ public static boolean isValidTimeList(Parameter p) { | |
* ``` | ||
* | ||
* @param parameter The parameter. | ||
* @param instantiation The (optional) instantiation. | ||
* @param instantiations The (optional) list of instantiations. | ||
* | ||
* @return The value of the parameter. | ||
* | ||
|
@@ -1161,7 +1150,7 @@ public static List<Value> initialValue(Parameter parameter, List<Instantiation> | |
* belongs to the specified instantiation, meaning that it is defined in | ||
* the reactor class being instantiated or one of its base classes. | ||
* @param eobject The object. | ||
* @param instnatiation The instantiation. | ||
* @param instantiation The instantiation. | ||
*/ | ||
public static boolean belongsTo(EObject eobject, Instantiation instantiation) { | ||
Reactor reactor = toDefinition(instantiation.getReactorClass()); | ||
|
@@ -1173,7 +1162,7 @@ public static boolean belongsTo(EObject eobject, Instantiation instantiation) { | |
* belongs to the specified reactor, meaning that it is defined in | ||
* reactor class or one of its base classes. | ||
* @param eobject The object. | ||
* @param instnatiation The instantiation. | ||
* @param reactor The reactor. | ||
*/ | ||
public static boolean belongsTo(EObject eobject, Reactor reactor) { | ||
if (eobject.eContainer() == reactor) return true; | ||
|
@@ -1190,7 +1179,7 @@ public static boolean belongsTo(EObject eobject, Reactor reactor) { | |
* if it does not have an integer value. | ||
* If the value of the parameter is a list of integers, | ||
* return the sum of value in the list. | ||
* The instantiations parameter is as in | ||
* The instantiations parameter is as in | ||
* {@link initialValue(Parameter, List<Instantiation>)}. | ||
* | ||
* @param parameter The parameter. | ||
|
@@ -1490,7 +1479,7 @@ public static boolean isGeneric(Reactor r) { | |
* return the imported reactor class definition. Otherwise, | ||
* just return the argument. | ||
* @param r A Reactor or an ImportedReactor. | ||
* @return The Reactor class definition. | ||
* @return The Reactor class definition or null if no definition is found. | ||
*/ | ||
public static Reactor toDefinition(ReactorDecl r) { | ||
if (r == null) | ||
|
@@ -1640,11 +1629,43 @@ public static TargetDecl targetDecl(Model model) { | |
public static TargetDecl targetDecl(Resource model) { | ||
return IteratorExtensions.head(Iterators.filter(model.getAllContents(), TargetDecl.class)); | ||
} | ||
|
||
|
||
///////////////////////////////////////////////////////// | ||
//// Private methods | ||
|
||
/** | ||
* Returns the list if it is not null. Otherwise return an empty list. | ||
*/ | ||
private static <T> List<T> convertToEmptyListIfNull(List<T> list) { | ||
return list != null ? list : new ArrayList<>(); | ||
} | ||
|
||
/** | ||
* Return all the superclasses of the specified reactor | ||
* in deepest-first order. For example, if A extends B and C, and | ||
* B and C both extend D, this will return the list [D, B, C, A]. | ||
* Duplicates are removed. If the specified reactor does not extend | ||
* any other reactor, then return an empty list. | ||
* If a cycle is found, where X extends Y and Y extends X, or if | ||
* a superclass is declared that is not found, then return null. | ||
* @param reactor The specified reactor. | ||
* @param extensions A set of reactors extending the specified reactor | ||
* (used to detect circular extensions). | ||
*/ | ||
private static LinkedHashSet<Reactor> superClasses(Reactor reactor, Set<Reactor> extensions) { | ||
LinkedHashSet<Reactor> result = new LinkedHashSet<Reactor>(); | ||
for (ReactorDecl superDecl : convertToEmptyListIfNull(reactor.getSuperClasses())) { | ||
Reactor r = toDefinition(superDecl); | ||
if (r == reactor || r == null) return null; | ||
// If r is in the extensions, then we have a circular inheritance structure. | ||
if (extensions.contains(r)) return null; | ||
extensions.add(r); | ||
LinkedHashSet<Reactor> baseExtends = superClasses(r, extensions); | ||
extensions.remove(r); | ||
if (baseExtends == null) return null; | ||
result.addAll(baseExtends); | ||
result.add(r); | ||
} | ||
return result; | ||
} | ||
} |
Oops, something went wrong.