Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic params allowed as generic arguments in C target #1804

Merged
merged 10 commits into from
Jun 2, 2023
Merged
16 changes: 0 additions & 16 deletions org.lflang/src/org/lflang/ast/ASTUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@
import org.lflang.generator.CodeMap;
import org.lflang.generator.InvalidSourceException;
import org.lflang.generator.ReactorInstance;
import org.lflang.generator.c.CUtil;
import org.lflang.generator.c.TypeParameterizedReactor;
import org.lflang.lf.Action;
import org.lflang.lf.Assignment;
import org.lflang.lf.Code;
Expand Down Expand Up @@ -409,20 +407,6 @@ public static List<Instantiation> allInstantiations(Reactor definition) {
return ASTUtils.collectElements(definition, featurePackage.getReactor_Instantiations());
}

/**
* Given a reactor Class, return a set of include names for interacting reactors which includes
* all instantiations of base class that it extends.
*
* @param r Reactor Class
*/
public static HashSet<String> allIncludes(Reactor r) {
var set = new HashSet<String>();
for (var i : allInstantiations(r)) {
set.add(CUtil.getName(new TypeParameterizedReactor(i)));
}
return set;
}

/*
* Given a reactor class, return a stream of reactor classes that it instantiates.
* @param definition Reactor class definition.
Expand Down
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/generator/ReactorInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ public ReactorInstance(
this.reporter = reporter;
this.reactorDeclaration = definition.getReactorClass();
this.reactorDefinition = ASTUtils.toDefinition(reactorDeclaration);
this.tpr = new TypeParameterizedReactor(definition);
this.tpr = new TypeParameterizedReactor(definition, parent == null ? null : parent.tpr);

// check for recursive instantiation
var currentParent = parent;
Expand Down
45 changes: 3 additions & 42 deletions org.lflang/src/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -89,7 +87,6 @@
import org.lflang.lf.Reactor;
import org.lflang.lf.ReactorDecl;
import org.lflang.lf.StateVar;
import org.lflang.lf.Type;
import org.lflang.lf.Variable;
import org.lflang.util.ArduinoUtil;
import org.lflang.util.FileUtil;
Expand Down Expand Up @@ -850,46 +847,12 @@ protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) {
private void generateReactorDefinitions() throws IOException {
var generatedReactors = new LinkedHashSet<TypeParameterizedReactor>();
if (this.main != null) {
resolveTemplatedTypes(this.main, this.main.tpr);
generateReactorChildren(this.main, generatedReactors);
generateReactorClass(this.main.getTypeParameterizedReactor());
}
// do not generate code for reactors that are not instantiated
}

/**
* Recursively Resolve all Templated Types of child Reactors to their respective concrete types
*
* @param reactorInstance The Reactor Class
* @param parentTpr {@link TypeParameterizedReactor} of Parent
*/
private void resolveTemplatedTypes(
ReactorInstance reactorInstance, TypeParameterizedReactor parentTpr) {
for (var child : reactorInstance.children) {
if (parentTpr.typeArgs() != null) {
Map<String, Type> copy = new HashMap<>();
child
.tpr
.typeArgs()
.forEach(
(literal, typename) -> {
var type = typename.getId();
if (parentTpr.typeArgs().containsKey(type)) {
var basicType = parentTpr.typeArgs().get(type);
copy.put(literal, basicType);
} else {
// Typename is not inherited from Parent Reactor. Keep As Is!
copy.put(literal, typename);
}
});
if (!copy.isEmpty()) { // If we found some templated-types update the tpr with new map
child.tpr = new TypeParameterizedReactor(child.tpr.reactor(), copy);
}
resolveTemplatedTypes(child, child.tpr);
}
}
}

private record TypeParameterizedReactorWithDecl(TypeParameterizedReactor tpr, ReactorDecl decl) {}

/** Generate user-visible header files for all reactors instantiated. */
Expand All @@ -910,7 +873,7 @@ private void generateHeaders() throws IOException {
.map(
it ->
new TypeParameterizedReactorWithDecl(
new TypeParameterizedReactor(it), it.getReactorClass()))
new TypeParameterizedReactor(it, rr), it.getReactorClass()))
.collect(Collectors.toSet())
.forEach(
it -> {
Expand Down Expand Up @@ -1069,9 +1032,7 @@ protected void generateReactorClassHeaders(
src.pr("#include \"include/" + CReactorHeaderFileGenerator.outputPath(tpr) + "\"");
src.pr("#include \"" + headerName + "\"");
tpr.doDefines(src);
ASTUtils.allIncludes(tpr.reactor()).stream()
.map(name -> "#include \"" + name + ".h\"")
.forEach(header::pr);
CUtil.allIncludes(tpr).stream().map(name -> "#include \"" + name + ".h\"").forEach(header::pr);
}

private void generateReactorClassBody(
Expand Down Expand Up @@ -1245,7 +1206,7 @@ private void generateInteractingContainedReactors(
var contained = new InteractingContainedReactors(tpr.reactor());
// Next generate the relevant code.
for (Instantiation containedReactor : contained.containedReactors()) {
var containedTpr = new TypeParameterizedReactor(containedReactor);
var containedTpr = new TypeParameterizedReactor(containedReactor, tpr);
// First define an _width variable in case it is a bank.
var array = "";
var width = -2;
Expand Down
13 changes: 8 additions & 5 deletions org.lflang/src/org/lflang/generator/c/CReactionGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ public static String generateInitializationForReaction(
reactionInitialization,
fieldsForStructsForContainedReactors,
effect.getContainer(),
(Input) variable);
(Input) variable,
tpr);
} else if (variable instanceof Watchdog) {
reactionInitialization.pr(generateWatchdogVariablesInReaction(effect));
} else {
Expand Down Expand Up @@ -363,14 +364,16 @@ private static void generateVariablesForSendingToContainedReactors(
CodeBuilder builder,
Map<Instantiation, CodeBuilder> structs,
Instantiation definition,
Input input) {
Input input,
TypeParameterizedReactor container) {
CodeBuilder structBuilder = structs.get(definition);
if (structBuilder == null) {
structBuilder = new CodeBuilder();
structs.put(definition, structBuilder);
}
String inputStructType =
CGenerator.variableStructType(input, new TypeParameterizedReactor(definition), false);
CGenerator.variableStructType(
input, new TypeParameterizedReactor(definition, container), false);
String defName = definition.getName();
String defWidth = generateWidthVariable(defName);
String inputName = input.getName();
Expand Down Expand Up @@ -461,7 +464,7 @@ private static void generatePortVariablesInReaction(
Output output = (Output) port.getVariable();
String portStructType =
CGenerator.variableStructType(
output, new TypeParameterizedReactor(port.getContainer()), false);
output, new TypeParameterizedReactor(port.getContainer(), tpr), false);

CodeBuilder structBuilder = structs.get(port.getContainer());
if (structBuilder == null) {
Expand Down Expand Up @@ -773,7 +776,7 @@ public static String generateOutputVariablesInReaction(
(effect.getContainer() == null)
? CGenerator.variableStructType(output, tpr, false)
: CGenerator.variableStructType(
output, new TypeParameterizedReactor(effect.getContainer()), false);
output, new TypeParameterizedReactor(effect.getContainer(), tpr), false);
if (!ASTUtils.isMultiport(output)) {
// Output port is not a multiport.
return outputStructType + "* " + outputName + " = &self->_lf_" + outputName + ";";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public static String nonInlineInitialization(Reaction r, TypeParameterizedReacto
reactor.reactor().getInstantiations().stream()
.filter(
instantiation ->
new TypeParameterizedReactor(instantiation)
new TypeParameterizedReactor(instantiation, reactor)
.equals(it.r))
.findAny()
.orElseThrow(),
Expand Down Expand Up @@ -184,7 +184,7 @@ private static Stream<PortVariable> portVariableStream(
? new PortVariable(
tv,
it.getContainer() != null
? new TypeParameterizedReactor(it.getContainer())
? new TypeParameterizedReactor(it.getContainer(), reactorOfReaction)
: reactorOfReaction,
it.getContainer())
: null)
Expand Down
20 changes: 17 additions & 3 deletions org.lflang/src/org/lflang/generator/c/CUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
Expand All @@ -36,6 +37,7 @@
import org.lflang.FileConfig;
import org.lflang.InferredType;
import org.lflang.TargetConfig;
import org.lflang.ast.ASTUtils;
import org.lflang.generator.ActionInstance;
import org.lflang.generator.GeneratorCommandFactory;
import org.lflang.generator.LFGeneratorContext;
Expand Down Expand Up @@ -135,7 +137,7 @@ public static String channelIndexName(PortInstance port) {
* (to allow for instantiations that have the same name as the main reactor or the .lf file).
*/
public static String getName(TypeParameterizedReactor reactor) {
String name = reactor.reactor().getName().toLowerCase() + reactor.hashCode();
String name = reactor.uniqueName();
petervdonovan marked this conversation as resolved.
Show resolved Hide resolved
if (reactor.reactor().isMain()) {
return name + "_main";
}
Expand Down Expand Up @@ -496,9 +498,9 @@ public static String runtimeIndex(ReactorInstance reactor) {
*/
public static String selfType(TypeParameterizedReactor reactor) {
if (reactor.reactor().isMain()) {
return "_" + CUtil.getName(reactor) + "_main_self_t";
return CUtil.getName(reactor) + "_main_self_t";
}
return "_" + CUtil.getName(reactor) + "_self_t";
return CUtil.getName(reactor) + "_self_t";
}

/** Construct a unique type for the "self" struct of the class of the given reactor. */
Expand Down Expand Up @@ -554,6 +556,18 @@ public static String triggerRefNested(PortInstance port, String runtimeIndex, St
+ "_trigger";
}

/**
* Given a reactor Class, return a set of include names for interacting reactors which includes
* all instantiations of base class that it extends.
*/
public static HashSet<String> allIncludes(TypeParameterizedReactor tpr) {
var set = new HashSet<String>();
for (var i : ASTUtils.allInstantiations(tpr.reactor())) {
set.add(getName(new TypeParameterizedReactor(i, tpr)));
}
return set;
}

//////////////////////////////////////////////////////
//// FIXME: Not clear what the strategy is with the following inner interface.
// The {@code ReportCommandErrors} interface allows the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,31 @@
*/
public record TypeParameterizedReactor(Reactor reactor, Map<String, Type> typeArgs) {

public TypeParameterizedReactor(Instantiation i) {
private static final Map<TypeParameterizedReactor, String> uniqueNames = new HashMap<>();
private static final Map<String, Integer> nameCounts = new HashMap<>();

/**
* Construct the TPR corresponding to the given instantiation which syntactically appears within
* the definition corresponding to {@code parent}.
*
* @param i An instantiation of the TPR to be constructed.
* @param parent The reactor in which {@code i} appears, or {@code null} if type variables are
* permitted instead of types in this TPR.
*/
public TypeParameterizedReactor(Instantiation i, TypeParameterizedReactor parent) {
this(
ASTUtils.toDefinition(i.getReactorClass()),
addTypeArgs(i, ASTUtils.toDefinition(i.getReactorClass())));
addTypeArgs(i, ASTUtils.toDefinition(i.getReactorClass()), parent));
}

private static Map<String, Type> addTypeArgs(Instantiation instantiation, Reactor r) {
private static Map<String, Type> addTypeArgs(
Instantiation instantiation, Reactor r, TypeParameterizedReactor parent) {
HashMap<String, Type> ret = new HashMap<>();
if (instantiation.getTypeArgs() != null) {
for (int i = 0; i < r.getTypeParms().size(); i++) {
ret.put(r.getTypeParms().get(i).getLiteral(), instantiation.getTypeArgs().get(i));
var arg = instantiation.getTypeArgs().get(i);
ret.put(
r.getTypeParms().get(i).getLiteral(), parent == null ? arg : parent.resolveType(arg));
}
}
return ret;
Expand Down Expand Up @@ -76,9 +90,27 @@ public InferredType resolveType(InferredType t) {
return InferredType.fromAST(resolveType(t.astType));
}

/**
* Return a name that is unique to this TypeParameterizedReactor (up to structural equality) and
* that is prefixed with exactly one underscore and that does not contain any upper-case letters.
*/
public String uniqueName() {
petervdonovan marked this conversation as resolved.
Show resolved Hide resolved
String name = reactor.getName().toLowerCase();
if (uniqueNames.containsKey(this)) return uniqueNames.get(this);
if (nameCounts.containsKey(name)) {
int currentCount = nameCounts.get(name);
nameCounts.put(name, currentCount + 1);
lhstrh marked this conversation as resolved.
Show resolved Hide resolved
uniqueNames.put(this, "_" + name + currentCount);
return uniqueName();
}
nameCounts.put(name, 1);
uniqueNames.put(this, "_" + name);
return uniqueName();
}

@Override
public int hashCode() {
return Math.abs(reactor.hashCode() * 31 + typeArgs.hashCode());
return reactor.hashCode() * 31 + typeArgs.hashCode();
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion org.lflang/src/org/lflang/validation/LFValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private Type portTypeIfResolvable(VarRef port) {
var portType = ((Port) port.getVariable()).getType();
return port.getContainer() == null
? portType
: new TypeParameterizedReactor(port.getContainer()).resolveType(portType);
: new TypeParameterizedReactor(port.getContainer(), null).resolveType(portType);
}

@Check(CheckType.FAST)
Expand Down
27 changes: 27 additions & 0 deletions test/C/src/generics/ParameterAsArgument.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
target C

reactor Child<T1, In, Out> {
state k: T1
input in: In
output out: Out

reaction(in) {=
int a = in->value;
printf("Got %d\n", a);
=}
}

reactor Super<T1, T2, T3, In, Out> {
input in: In
output out: Out
state t1: T1
c = new Child<T3, In, Out>()
in -> c.in
c.out -> out
}

main reactor {
cc = new Super<long, double, char, int, float>()

reaction(startup) -> cc.in {= lf_set(cc.in, 42); =}
}