Skip to content

Commit

Permalink
Merge pull request #2003 from oowekyala/clem.bracket-list-expr
Browse files Browse the repository at this point in the history
Bracket list expression for initialization without escaping
  • Loading branch information
lhstrh authored Sep 24, 2023
2 parents ba00299 + 9edab37 commit c623210
Show file tree
Hide file tree
Showing 14 changed files with 120 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ jobs:
uses: lf-lang/epoch/.github/workflows/build.yml@main
with:
lingua-franca-ref: ${{ github.head_ref || github.ref_name }}
lingua-franca-repo: ${{ github.event.pull_request.head.repo.full_name }}
upload-artifacts: false
8 changes: 8 additions & 0 deletions core/src/main/java/org/lflang/LinguaFranca.xtext
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ Expression:
| ParameterReference
| {CodeExpr} code=Code
| BracedListExpression
| BracketListExpression
;

// A list of expressions within braces.
Expand All @@ -328,6 +329,13 @@ BracedListExpression:
'{' {BracedListExpression} (items+=Expression (',' items+=Expression)*)? ','? '}'
;

// A list of expressions within square brackets.
// In Python and TS, this is a list literal. In Rust this could be an array but Rust
// array expressions are relatively rare so probably not worth supporting.
BracketListExpression:
'[' {BracketListExpression} (items+=Expression (',' items+=Expression)*)? ','? ']'
;

ParameterReference:
parameter=[Parameter]
;
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/lflang/Target.java
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,11 @@ public boolean allowsBracedListExpressions() {
return this == C || this == CCPP || this == CPP;
}

/** Allow expressions of the form {@code [a, b, c]}. */
public boolean allowsBracketListExpressions() {
return this == Python || this == TS || this == Rust;
}

/** Return a string that demarcates the beginning of a single-line comment. */
public String getSingleLineCommentPrefix() {
return this.equals(Target.Python) ? "#" : "//";
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/lflang/ast/IsEqual.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.lflang.lf.AttrParm;
import org.lflang.lf.Attribute;
import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.BuiltinTriggerRef;
import org.lflang.lf.Code;
import org.lflang.lf.CodeExpr;
Expand Down Expand Up @@ -465,6 +466,13 @@ public Boolean caseBracedListExpression(BracedListExpression object) {
.conclusion;
}

@Override
public Boolean caseBracketListExpression(BracketListExpression object) {
return new ComparisonMachine<>(object, BracketListExpression.class)
.listsEquivalent(BracketListExpression::getItems)
.conclusion;
}

@Override
public Boolean caseParameterReference(ParameterReference object) {
return new ComparisonMachine<>(object, ParameterReference.class)
Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/lflang/ast/ToLf.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.lflang.lf.AttrParm;
import org.lflang.lf.Attribute;
import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.BuiltinTriggerRef;
import org.lflang.lf.Code;
import org.lflang.lf.CodeExpr;
Expand Down Expand Up @@ -873,6 +874,14 @@ public MalleableString caseBracedListExpression(BracedListExpression object) {
return bracedListExpression(object.getItems());
}

@Override
public MalleableString caseBracketListExpression(BracketListExpression object) {
if (object.getItems().isEmpty()) {
return MalleableString.anyOf("[]");
}
return list(", ", "[", "]", false, false, true, object.getItems());
}

/**
* Represent a braced list expression. Do not invoke on expressions that may have comments
* attached.
Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/org/lflang/ast/ToText.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.lflang.lf.ArraySpec;
import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.Code;
import org.lflang.lf.CodeExpr;
import org.lflang.lf.Host;
Expand Down Expand Up @@ -80,6 +81,11 @@ public String caseBracedListExpression(BracedListExpression object) {
return new ToLf().caseBracedListExpression(object).toString();
}

@Override
public String caseBracketListExpression(BracketListExpression object) {
return new ToLf().caseBracketListExpression(object).toString();
}

@Override
public String caseHost(Host host) {
return new ToLf().caseHost(host).toString();
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/org/lflang/generator/LfExpressionVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package org.lflang.generator;

import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.Code;
import org.lflang.lf.CodeExpr;
import org.lflang.lf.Expression;
Expand All @@ -44,6 +45,8 @@ public interface LfExpressionVisitor<P, R> {

R visitBracedListExpr(BracedListExpression expr, P param);

R visitBracketListExpr(BracketListExpression expr, P param);

R visitTimeLiteral(Time expr, P param);

R visitCodeExpr(CodeExpr expr, P param);
Expand All @@ -66,6 +69,8 @@ static <P, R> R dispatch(
return visitor.visitLiteral((Literal) e, arg);
} else if (e instanceof BracedListExpression) {
return visitor.visitBracedListExpr((BracedListExpression) e, arg);
} else if (e instanceof BracketListExpression) {
return visitor.visitBracketListExpr((BracketListExpression) e, arg);
} else if (e instanceof Time) {
return visitor.visitTimeLiteral((Time) e, arg);
} else if (e instanceof CodeExpr) {
Expand Down Expand Up @@ -106,6 +111,11 @@ public R visitCodeExpr(CodeExpr expr, P param) {
public R visitParameterRef(ParameterReference expr, P param) {
return visitExpression(expr, param);
}

@Override
public R visitBracketListExpr(BracketListExpression expr, P param) {
return visitExpression(expr, param);
}
}

/**
Expand Down Expand Up @@ -147,6 +157,15 @@ public Expression visitParameterRef(ParameterReference expr, P param) {
return clone;
}

@Override
public Expression visitBracketListExpr(BracketListExpression expr, P param) {
BracketListExpression clone = LfFactory.eINSTANCE.createBracketListExpression();
for (Expression item : expr.getItems()) {
clone.getItems().add(dispatch(item, param, this));
}
return clone;
}

@Override
public Expression visitCodeExpr(CodeExpr expr, P param) {
CodeExpr codeExpr = LfFactory.eINSTANCE.createCodeExpr();
Expand Down
11 changes: 11 additions & 0 deletions core/src/main/java/org/lflang/generator/TargetTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.lflang.ast.ASTUtils;
import org.lflang.lf.Action;
import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.CodeExpr;
import org.lflang.lf.Expression;
import org.lflang.lf.Initializer;
Expand Down Expand Up @@ -60,6 +61,14 @@ default String getTargetBracedListExpr(BracedListExpression expr, InferredType t
.collect(Collectors.joining(",", "{", "}"));
}

/** Translate the bracket list expression into target language syntax. */
default String getTargetBracketListExpr(BracketListExpression expr, InferredType typeOrNull) {
InferredType t = typeOrNull == null ? InferredType.undefined() : typeOrNull;
return expr.getItems().stream()
.map(e -> getTargetExpr(e, t))
.collect(Collectors.joining(", ", "[", "]"));
}

/** Return an "unknown" type which is used as a default when a type cannot be inferred. */
String getTargetUndefinedType();

Expand Down Expand Up @@ -224,6 +233,8 @@ default String getTargetExpr(Expression expr, InferredType type) {
return ASTUtils.toText(((CodeExpr) expr).getCode());
} else if (expr instanceof BracedListExpression) {
return getTargetBracedListExpr((BracedListExpression) expr, type);
} else if (expr instanceof BracketListExpression) {
return getTargetBracketListExpr((BracketListExpression) expr, type);
} else {
throw new IllegalStateException("Invalid value " + expr);
}
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/java/org/lflang/validation/LFValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.lflang.lf.Assignment;
import org.lflang.lf.Attribute;
import org.lflang.lf.BracedListExpression;
import org.lflang.lf.BracketListExpression;
import org.lflang.lf.BuiltinTrigger;
import org.lflang.lf.BuiltinTriggerRef;
import org.lflang.lf.Connection;
Expand Down Expand Up @@ -193,6 +194,15 @@ public void checkBracedExpression(BracedListExpression expr) {
}
}

@Check(CheckType.FAST)
public void checkBracketExpression(BracketListExpression expr) {
if (!target.allowsBracketListExpressions()) {
var message =
"Bracketed expression lists are not a valid expression for the " + target + " target.";
error(message, Literals.BRACKET_LIST_EXPRESSION.eContainmentFeature());
}
}

@Check(CheckType.FAST)
public void checkAssignment(Assignment assignment) {

Expand Down
4 changes: 2 additions & 2 deletions test/Python/src/ArrayAsParameter.lf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Source has an array as a parameter, the elements of which it passes to Print.
target Python

reactor Source(sequence(0, 1, 2)) {
reactor Source(sequence = [0, 1, 2]) {
output out
state count = 0
logical action next
Expand Down Expand Up @@ -36,7 +36,7 @@ reactor Print {
}

main reactor ArrayAsParameter {
s = new Source(sequence(1, 2, 3, 4))
s = new Source(sequence = [1, 2, 3, 4])
p = new Print()
s.out -> p._in
}
4 changes: 2 additions & 2 deletions test/Python/src/modal_models/util/TraceTesting.lf
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/** Utility reactor to record and test execution traces. */
target Python

reactor TraceTesting(events_size=0, trace = {= [] =}, training=False) {
reactor TraceTesting(events_size=0, trace=[], training=False) {
input[events_size] events

state last_reaction_time = 0
state trace_idx = 0
state recorded_events = {= [] =}
state recorded_events = []
state recorded_events_next = 0

reaction(startup) {=
Expand Down
36 changes: 36 additions & 0 deletions test/Rust/src/ArrayAsParameter.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Source has an array as a parameter, the elements of which it passes to Print.
target Rust

reactor Source(sequence: {= [i32; 3] =} = [0, 1, 2]) {
output out: i32
state count: usize = 0
state seq = sequence
logical action next

reaction(startup, next) -> out, next {=
ctx.set(out, self.seq[self.count]);
self.count += 1;
if self.count < self.seq.len() {
ctx.schedule(next, Asap);
}
=}
}

reactor Print {
input x: i32
state count: usize = 0

reaction(x) {=
let expected = [2, 3, 4];
let x = ctx.get(x).unwrap();
println!("Received: {}.", x);
assert_eq!(x, expected[self.count]);
self.count += 1;
=}
}

main reactor ArrayAsParameter {
s = new Source(sequence = [2, 3, 4])
p = new Print()
s.out -> p.x
}
4 changes: 2 additions & 2 deletions test/TypeScript/src/ArrayAsParameter.lf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Source has an array as a parameter, the elements of which it passes to Print.
target TypeScript

reactor Source(sequence: {= Array<number> =} = {= [0, 1, 2] =}) {
reactor Source(sequence: Array<number> = [0, 1, 2]) {
output out: number
state count: number = 0
logical action next
Expand Down Expand Up @@ -29,7 +29,7 @@ reactor Print {
}

main reactor ArrayAsParameter {
s = new Source(sequence = {= [1, 2, 3, 4] =})
s = new Source(sequence = [1, 2, 3, 4])
p = new Print()
s.out -> p.x
}
2 changes: 1 addition & 1 deletion test/TypeScript/src/MovingAverage.lf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ reactor Source {
}

reactor MovingAverageImpl {
state delay_line: {= Array<number> =} = {= [0.0, 0.0, 0.0] =}
state delay_line: Array<number> = [0.0, 0.0, 0.0]
state index: number = 0
input x: number
output out: number
Expand Down

0 comments on commit c623210

Please sign in to comment.