Skip to content

Commit 4545a55

Browse files
authored
Add support for arrays on ports and state variables (#158)
* Add support for C arrays on ports and state variables * Formatter * Refactor * Typo
1 parent 1231bbd commit 4545a55

File tree

8 files changed

+142
-7
lines changed

8 files changed

+142
-7
lines changed

include/reactor-uc/macros.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
_port->set(_port, &__val); \
1212
} while (0)
1313

14+
// Sets an output port, copies data and triggers all downstream reactions.
15+
#define lf_set_array(port, array) \
16+
do { \
17+
Port *_port = (Port *)(port); \
18+
_port->set(_port, array); \
19+
} while (0)
20+
1421
/**
1522
* @brief Retreive the value of a trigger and cast it to the expected type
1623
*/
@@ -214,6 +221,13 @@
214221
BufferType value; \
215222
} ReactorName##_##PortName;
216223

224+
#define LF_DEFINE_OUTPUT_ARRAY_STRUCT(ReactorName, PortName, SourceSize, BufferType, ArrayLen) \
225+
typedef struct { \
226+
Port super; \
227+
Reaction *sources[(SourceSize)]; \
228+
BufferType value[(ArrayLen)]; \
229+
} ReactorName##_##PortName;
230+
217231
#define LF_DEFINE_OUTPUT_CTOR(ReactorName, PortName, SourceSize) \
218232
void ReactorName##_##PortName##_ctor(ReactorName##_##PortName *self, Reactor *parent, \
219233
OutputExternalCtorArgs external) { \
@@ -249,6 +263,16 @@
249263
Connection *conns_out[(NumConnsOut)]; \
250264
} ReactorName##_##PortName;
251265

266+
#define LF_DEFINE_INPUT_ARRAY_STRUCT(ReactorName, PortName, EffectSize, ObserversSize, BufferType, ArrayLen, \
267+
NumConnsOut) \
268+
typedef struct { \
269+
Port super; \
270+
Reaction *effects[(EffectSize)]; \
271+
Reaction *observers[(ObserversSize)]; \
272+
BufferType value[(ArrayLen)]; \
273+
Connection *conns_out[(NumConnsOut)]; \
274+
} ReactorName##_##PortName;
275+
252276
#define LF_DEFINE_INPUT_CTOR(ReactorName, PortName, EffectSize, ObserverSize, BufferType, NumConnsOut) \
253277
void ReactorName##_##PortName##_ctor(ReactorName##_##PortName *self, Reactor *parent, \
254278
InputExternalCtorArgs external) { \

lfc/core/src/main/java/org/lflang/generator/TargetTypes.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ default String getTargetExpr(Expression expr, InferredType type) {
184184
return ASTUtils.addZeroToLeadingDot(((Literal) expr).getLiteral()); // here we don't escape
185185
} else if (expr instanceof CodeExpr) {
186186
return ASTUtils.toText(((CodeExpr) expr).getCode());
187-
// } else if (expr instanceof BracedListExpression) {
188-
// return getTargetBracedListExpr((BracedListExpression) expr, type);
187+
} else if (expr instanceof BracedListExpression) {
188+
return getTargetBracedListExpr((BracedListExpression) expr, type);
189189
// } else if (expr instanceof BracketListExpression) {
190190
// return getTargetBracketListExpr((BracketListExpression) expr, type);
191191
// } else if (expr instanceof ParenthesisListExpression) {

lfc/core/src/main/java/org/lflang/target/Target.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public boolean mandatesEqualsInitializers() {
468468

469469
/** Allow expressions of the form {@code {a, b, c}}. */
470470
public boolean allowsBracedListExpressions() {
471-
return false;
471+
return true;
472472
}
473473

474474
/** Allow expressions of the form {@code [a, b, c]}. */

lfc/core/src/main/kotlin/org/lflang/generator/uc/UcPortGenerator.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,33 @@ import org.lflang.lf.*
3636
class UcPortGenerator(private val reactor: Reactor, private val connections: UcConnectionGenerator) {
3737
val Port.external_args
3838
get(): String = "_${name}_external"
39+
3940
companion object {
4041
val Port.width
4142
get(): Int = widthSpec?.getWidth()?:1
43+
val Type.isArray
44+
get(): Boolean = cStyleArraySpec != null
45+
val Type.arrayLength
46+
get(): Int = cStyleArraySpec.length
47+
4248
}
4349

44-
private fun generateSelfStruct(input: Input) = "LF_DEFINE_INPUT_STRUCT(${reactor.codeType}, ${input.name}, ${reactor.getEffects(input).size}, ${reactor.getObservers(input).size}, ${input.type.toText()}, ${connections.getNumConnectionsFromPort(null, input as Port)});"
50+
private fun generateSelfStruct(input: Input): String {
51+
if (input.type.isArray) {
52+
return "LF_DEFINE_INPUT_ARRAY_STRUCT(${reactor.codeType}, ${input.name}, ${reactor.getEffects(input).size}, ${reactor.getObservers(input).size}, ${input.type.id}, ${input.type.arrayLength}, ${connections.getNumConnectionsFromPort(null, input as Port)});"
53+
} else {
54+
return "LF_DEFINE_INPUT_STRUCT(${reactor.codeType}, ${input.name}, ${reactor.getEffects(input).size}, ${reactor.getObservers(input).size}, ${input.type.toText()}, ${connections.getNumConnectionsFromPort(null, input as Port)});"
55+
}
56+
}
4557
private fun generateInputCtor(input: Input) = "LF_DEFINE_INPUT_CTOR(${reactor.codeType}, ${input.name}, ${reactor.getEffects(input).size}, ${reactor.getObservers(input).size}, ${input.type.toText()}, ${connections.getNumConnectionsFromPort(null, input as Port)});"
46-
private fun generateSelfStruct(output: Output) = "LF_DEFINE_OUTPUT_STRUCT(${reactor.codeType}, ${output.name}, ${reactor.getSources(output).size}, ${output.type.toText()});"
58+
private fun generateSelfStruct(output: Output): String {
59+
if (output.type.isArray) {
60+
return "LF_DEFINE_OUTPUT_ARRAY_STRUCT(${reactor.codeType}, ${output.name}, ${reactor.getSources(output).size}, ${output.type.id}, ${output.type.arrayLength});"
61+
} else {
62+
return "LF_DEFINE_OUTPUT_STRUCT(${reactor.codeType}, ${output.name}, ${reactor.getSources(output).size}, ${output.type.toText()});"
63+
}
64+
}
65+
4766
private fun generateOutputCtor(output: Output) = "LF_DEFINE_OUTPUT_CTOR(${reactor.codeType}, ${output.name}, ${reactor.getSources(output).size});"
4867

4968
fun generateSelfStructs() = reactor.allInputs.plus(reactor.allOutputs).joinToString(prefix = "// Port structs\n", separator = "\n", postfix = "\n") {
Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,31 @@
11
package org.lflang.generator.uc
22

33
import org.lflang.allStateVars
4+
import org.lflang.generator.uc.UcPortGenerator.Companion.arrayLength
5+
import org.lflang.generator.uc.UcPortGenerator.Companion.isArray
46
import org.lflang.isInitialized
57
import org.lflang.lf.Reactor
8+
import org.lflang.lf.StateVar
69
import org.lflang.toText
710

811
class UcStateGenerator(private val reactor: Reactor) {
912
fun generateReactorStructFields() =
10-
reactor.allStateVars.joinToString(prefix = "// State variables \n", separator = "\n") { "${it.type.toText()} ${it.name};" }
13+
reactor.allStateVars.joinToString(prefix = "// State variables \n", separator = "\n") {
14+
if (it.type.isArray) {
15+
"${it.type.id} ${it.name}[${it.type.arrayLength}];"
16+
} else {
17+
"${it.type.toText()} ${it.name};"
18+
}
19+
}
1120

1221
fun generateInitializeStateVars() =
13-
reactor.allStateVars.filter{it.isInitialized}.joinToString(prefix = "// Initialize State variables \n", separator = "\n") { "self->${it.name} = ${it.init.expr.toCCode()};" }
22+
reactor.allStateVars.filter{it.isInitialized}.joinToString(prefix = "// Initialize State variables \n", separator = "\n") {
23+
if (it.type.isArray) {
24+
"""|${it.type.id} _${it.name}_init[${it.type.arrayLength}] = ${it.init.expr.toCCode()};
25+
|memcpy(&self->${it.name}, &_${it.name}_init, sizeof(_${it.name}_init));
26+
""".trimMargin()
27+
} else {
28+
"self->${it.name} = ${it.init.expr.toCCode()};"
29+
}
30+
}
1431
}

test/lf/src/ArrayPorts.lf

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
target uC {
2+
platform: Native
3+
}
4+
5+
6+
reactor Src {
7+
output out: int[4]
8+
9+
reaction(startup) -> out {=
10+
int arr[] = {1, 2, 3, 4};
11+
lf_set_array(out, arr);
12+
=}
13+
}
14+
15+
reactor Sink {
16+
input in: int[4]
17+
18+
reaction(in) {=
19+
for (int i = 0; i < 4; i++) {
20+
printf("%d\n", in->value[i]);
21+
validate(in->value[i] == i+1);
22+
}
23+
=}
24+
}
25+
26+
main reactor {
27+
src = new Src()
28+
sink = new Sink()
29+
src.out -> sink.in
30+
}

test/lf/src/ArrayState.lf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
target uC {
2+
platform: Native
3+
}
4+
5+
main reactor {
6+
state s: int[4] = {1, 2, 3, 4}
7+
8+
reaction(startup) {=
9+
for (int i = 0; i < 4; i++) {
10+
printf("%d\n", self->s[i]);
11+
validate(self->s[i] == i+1);
12+
}
13+
=}
14+
}

test/lf/src/StringPorts.lf

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
target uC {
2+
platform: Native
3+
}
4+
5+
6+
reactor Src {
7+
output out: char[12]
8+
9+
reaction(startup) -> out {=
10+
lf_set_array(out, "Hello World");
11+
=}
12+
}
13+
14+
reactor Sink {
15+
input in: char[12]
16+
17+
reaction(in) {=
18+
const char *expected = "Hello World";
19+
for (int i = 0; i < 12; i++) {
20+
printf("%c", in->value[i]);
21+
validate(in->value[i] == expected[i]);
22+
}
23+
printf("\n");
24+
=}
25+
}
26+
27+
main reactor {
28+
src = new Src()
29+
sink = new Sink()
30+
src.out -> sink.in
31+
}

0 commit comments

Comments
 (0)