diff --git a/core/src/main/java/org/lflang/federated/extensions/CExtension.java b/core/src/main/java/org/lflang/federated/extensions/CExtension.java index edf5bc8d19..12edb2e693 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -520,6 +520,7 @@ public String generatePreamble( includes.pr("#include \"core/federated/federate.h\""); includes.pr("#include \"core/federated/network/net_common.h\""); includes.pr("#include \"core/federated/network/net_util.h\""); + includes.pr("#include \"core/federated/network/socket_common.h\""); includes.pr("#include \"core/federated/clock-sync.h\""); includes.pr("#include \"core/threaded/reactor_threaded.h\""); includes.pr("#include \"core/utils/util.h\""); @@ -542,6 +543,7 @@ protected String makePreamble( code.pr("#include \"core/federated/federate.h\""); code.pr("#include \"core/federated/network/net_common.h\""); code.pr("#include \"core/federated/network/net_util.h\""); + code.pr("#include \"core/federated/network/socket_common.h\""); code.pr("#include \"core/federated/clock-sync.h\""); code.pr("#include \"core/threaded/reactor_threaded.h\""); code.pr("#include \"core/utils/util.h\""); diff --git a/core/src/main/java/org/lflang/generator/c/CParameterGenerator.java b/core/src/main/java/org/lflang/generator/c/CParameterGenerator.java index 273f058d57..bcf03ea33a 100644 --- a/core/src/main/java/org/lflang/generator/c/CParameterGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CParameterGenerator.java @@ -1,5 +1,6 @@ package org.lflang.generator.c; +import java.util.HashSet; import org.lflang.ast.ASTUtils; import org.lflang.generator.CodeBuilder; import org.lflang.generator.ParameterInstance; @@ -41,7 +42,14 @@ public static String getInitializer(ParameterInstance p) { public static String generateDeclarations( TypeParameterizedReactor reactor, CTypes types, boolean suppressLineDirectives) { CodeBuilder code = new CodeBuilder(); + // Allow derived classes to override base class parameter definitions. + // Assume that the validator has checked that types match. + var declared = new HashSet(); for (Parameter parameter : ASTUtils.allParameters(reactor.reactor())) { + // If the parameter name has been seen already, assume it is an override of the default value + // in a derived class. The validator should check. + if (declared.contains(parameter.getName())) continue; + declared.add(parameter.getName()); code.prSourceLineNumber(parameter, suppressLineDirectives); code.pr( types.getTargetType(reactor.resolveType(ASTUtils.getInferredType(parameter))) diff --git a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java index ebef8e5933..5ff6a65200 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -1087,6 +1087,60 @@ private static String deferredAllocationForEffectsOnInputs(ReactorInstance react return code.toString(); } + /** + * Set the parent pointer and reactor name. If the reactor is in a bank, the name will be the + * instance name with [index] appended. + * + * @param reactor The reactor instance. + */ + private static String deferredSetParentAndName(ReactorInstance reactor) { + var code = new CodeBuilder(); + if (reactor.isBank()) { + // First, generate code to determine the size of the memory needed for the name. + code.pr("char* format = \"%s[%d]\";"); + code.pr( + "int length = snprintf(NULL, 0, format, \"" + + reactor.getName() + + "\", " + + CUtil.bankIndexName(reactor) + + ");\n"); + code.pr( + CUtil.reactorRef(reactor) + + "->base.name = (char*)lf_allocate(length + 1, sizeof(char)," + + " (allocation_record_t**)&((self_base_t*)" + + CUtil.reactorRef(reactor) + + ")->allocations);"); + code.pr( + "if(" + + CUtil.reactorRef(reactor) + + "->base.name != NULL) {"); // Will be NULL if lf_allocate fails. + code.indent(); + code.pr( + "snprintf(" + + CUtil.reactorRef(reactor) + + "->base.name, length + 1, format, \"" + + reactor.getName() + + "\", " + + CUtil.bankIndexName(reactor) + + ");"); + code.unindent(); + code.pr("}"); + } else { + code.pr(CUtil.reactorRef(reactor) + "->base.name = \"" + reactor.getName() + "\";"); + } + ReactorInstance parent = reactor.getParent(); + if (parent == null) { + code.pr(CUtil.reactorRef(reactor) + "->base.parent = (self_base_t*)NULL;"); + } else { + code.pr( + CUtil.reactorRef(reactor) + + "->base.parent = (self_base_t*)" + + CUtil.reactorRef(parent) + + ";"); + } + return code.toString(); + } + /** * Perform initialization functions that must be performed after all reactor runtime instances * have been created. This function creates nested loops over nested banks. @@ -1104,6 +1158,9 @@ private static String deferredInitialize( // over bank members for the reactor's parent. code.startScopedBlock(reactor); + // Set the parent pointer and name for the reactor. + code.pr(deferredSetParentAndName(reactor)); + // If the child has a multiport that is an effect of some reaction in its container, // then we have to generate code to allocate memory for arrays pointing to // its data. If the child is a bank, then memory is allocated for the entire diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 2f839ac3cf..25a32c9210 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 2f839ac3cf4a34c8a3cec61a194380b50c4441f3 +Subproject commit 25a32c9210e95752619db5ddae445dffd34c1b03 diff --git a/test/C/src/ParameterOverride.lf b/test/C/src/ParameterOverride.lf new file mode 100644 index 0000000000..b586281dee --- /dev/null +++ b/test/C/src/ParameterOverride.lf @@ -0,0 +1,16 @@ +target C + +reactor A(x: int = 0) { + reaction(startup) {= + if (self->x != 1) { + lf_print_error_and_exit("x is %d. Should be 1.", self->x); + } + =} +} + +reactor B(x: int = 1) extends A { +} + +main reactor { + b = new B() +} diff --git a/test/C/src/ReactorName.lf b/test/C/src/ReactorName.lf new file mode 100644 index 0000000000..0fa130168f --- /dev/null +++ b/test/C/src/ReactorName.lf @@ -0,0 +1,58 @@ +target C { + build-type: debug +} + +preamble {= + #include +=} + +reactor A(parent_bank_index: size_t = 0) { + reaction(startup) {= + const char* name = lf_reactor_full_name(self); + lf_print("name: %s", name); + char buffer[20]; + snprintf(buffer, 20, "ReactorName.b[%zu].a", self->parent_bank_index); + if (strcmp(buffer, name) != 0) { + lf_print_error_and_exit("full name does not match"); + } + name = lf_reactor_name(self); + if (strcmp("a", name) != 0) { + lf_print_error_and_exit("name does not match"); + } + =} +} + +reactor B(bank_index: size_t = 0) { + a = new A(parent_bank_index=bank_index) + + reaction(startup) {= + const char* name = lf_reactor_full_name(self); + lf_print("name: %s", name); + char buffer[20]; + snprintf(buffer, 20, "ReactorName.b[%zu]", self->bank_index); + if (strcmp(buffer, name) != 0) { + lf_print_error_and_exit("full name does not match"); + } + name = lf_reactor_name(self); + snprintf(buffer, 20, "b[%zu]", self->bank_index); + if (strcmp(buffer, name) != 0) { + lf_print_error_and_exit("name does not match"); + } + =} +} + +main reactor { + b = new[3] B() + + reaction(startup) {= + const char* name = lf_reactor_full_name(self); + lf_print("name: %s", name); + if (strcmp("ReactorName", name) != 0) { + lf_print_error_and_exit("full name does not match"); + } + name = lf_reactor_name(self); + if (strcmp("ReactorName", name) != 0) { + lf_print_error_and_exit("name does not match"); + } + =} +}