From 8dea1492c6fcb23892c1da61c55ebb1d7358d151 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 8 Jun 2022 11:01:13 -0700 Subject: [PATCH 001/130] [fed] Add empty overrides of toText functions. --- org.lflang/src/org/lflang/ast/ToText.java | 228 ++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 3f862a240e..07a2811f01 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -7,15 +7,53 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; +import org.lflang.lf.Action; +import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; +import org.lflang.lf.Assignment; import org.lflang.lf.Code; +import org.lflang.lf.Connection; +import org.lflang.lf.Deadline; +import org.lflang.lf.Element; +import org.lflang.lf.Expression; import org.lflang.lf.Host; +import org.lflang.lf.IPV4Host; +import org.lflang.lf.IPV6Host; +import org.lflang.lf.Import; +import org.lflang.lf.ImportedReactor; +import org.lflang.lf.Input; +import org.lflang.lf.Instantiation; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; import org.lflang.lf.Literal; +import org.lflang.lf.Method; +import org.lflang.lf.MethodArgument; +import org.lflang.lf.Mode; +import org.lflang.lf.Model; +import org.lflang.lf.Mutation; +import org.lflang.lf.NamedHost; +import org.lflang.lf.Output; +import org.lflang.lf.Parameter; import org.lflang.lf.ParameterReference; +import org.lflang.lf.Port; +import org.lflang.lf.Preamble; +import org.lflang.lf.Reaction; +import org.lflang.lf.Reactor; +import org.lflang.lf.ReactorDecl; +import org.lflang.lf.STP; +import org.lflang.lf.Serializer; +import org.lflang.lf.StateVar; +import org.lflang.lf.TargetDecl; import org.lflang.lf.Time; +import org.lflang.lf.Timer; +import org.lflang.lf.TriggerRef; import org.lflang.lf.Type; import org.lflang.lf.TypeParm; +import org.lflang.lf.TypedVariable; import org.lflang.lf.VarRef; +import org.lflang.lf.Variable; +import org.lflang.lf.WidthSpec; +import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; import org.lflang.util.StringUtil; @@ -121,6 +159,196 @@ public String caseVarRef(VarRef v) { } } + @Override + public String caseModel(Model object) { + return super.caseModel(object); + } + + @Override + public String caseImport(Import object) { + return super.caseImport(object); + } + + @Override + public String caseReactorDecl(ReactorDecl object) { + return super.caseReactorDecl(object); + } + + @Override + public String caseImportedReactor(ImportedReactor object) { + return super.caseImportedReactor(object); + } + + @Override + public String caseReactor(Reactor object) { + return super.caseReactor(object); + } + + @Override + public String caseTargetDecl(TargetDecl object) { + return super.caseTargetDecl(object); + } + + @Override + public String caseStateVar(StateVar object) { + return super.caseStateVar(object); + } + + @Override + public String caseMethod(Method object) { + return super.caseMethod(object); + } + + @Override + public String caseMethodArgument(MethodArgument object) { + return super.caseMethodArgument(object); + } + + @Override + public String caseInput(Input object) { + return super.caseInput(object); + } + + @Override + public String caseOutput(Output object) { + return super.caseOutput(object); + } + + @Override + public String caseTimer(Timer object) { + return super.caseTimer(object); + } + + @Override + public String caseMode(Mode object) { + return super.caseMode(object); + } + + @Override + public String caseAction(Action object) { + return super.caseAction(object); + } + + @Override + public String caseReaction(Reaction object) { + return super.caseReaction(object); + } + + @Override + public String caseTriggerRef(TriggerRef object) { + return super.caseTriggerRef(object); + } + + @Override + public String caseDeadline(Deadline object) { + return super.caseDeadline(object); + } + + @Override + public String caseSTP(STP object) { + return super.caseSTP(object); + } + + @Override + public String caseMutation(Mutation object) { + return super.caseMutation(object); + } + + @Override + public String casePreamble(Preamble object) { + return super.casePreamble(object); + } + + @Override + public String caseInstantiation(Instantiation object) { + return super.caseInstantiation(object); + } + + @Override + public String caseConnection(Connection object) { + return super.caseConnection(object); + } + + @Override + public String caseSerializer(Serializer object) { + return super.caseSerializer(object); + } + + @Override + public String caseKeyValuePairs(KeyValuePairs object) { + return super.caseKeyValuePairs(object); + } + + @Override + public String caseKeyValuePair(KeyValuePair object) { + return super.caseKeyValuePair(object); + } + + @Override + public String caseArray(Array object) { + return super.caseArray(object); + } + + @Override + public String caseElement(Element object) { + return super.caseElement(object); + } + + @Override + public String caseTypedVariable(TypedVariable object) { + return super.caseTypedVariable(object); + } + + @Override + public String caseVariable(Variable object) { + return super.caseVariable(object); + } + + @Override + public String caseAssignment(Assignment object) { + return super.caseAssignment(object); + } + + @Override + public String caseParameter(Parameter object) { + return super.caseParameter(object); + } + + @Override + public String caseExpression(Expression object) { + return super.caseExpression(object); + } + + @Override + public String casePort(Port object) { + return super.casePort(object); + } + + @Override + public String caseWidthSpec(WidthSpec object) { + return super.caseWidthSpec(object); + } + + @Override + public String caseWidthTerm(WidthTerm object) { + return super.caseWidthTerm(object); + } + + @Override + public String caseIPV4Host(IPV4Host object) { + return super.caseIPV4Host(object); + } + + @Override + public String caseIPV6Host(IPV6Host object) { + return super.caseIPV6Host(object); + } + + @Override + public String caseNamedHost(NamedHost object) { + return super.caseNamedHost(object); + } + @Override public String defaultCase(EObject object) { throw new UnsupportedOperationException("ToText has no case for " + object.getClass().getName()); From fd5ee165e0eedfacf5b46cb4acdb231af9358153 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Wed, 8 Jun 2022 12:03:09 -0700 Subject: [PATCH 002/130] Handle ToText of Model and TargetDecl --- org.lflang/src/org/lflang/ast/ToText.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 07a2811f01..5864610b0f 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -161,7 +161,15 @@ public String caseVarRef(VarRef v) { @Override public String caseModel(Model object) { - return super.caseModel(object); + StringBuilder sb = new StringBuilder(); + + sb.append(caseTargetDecl(object.getTarget())); + object.getImports().forEach(i -> sb.append(caseImport(i))); + object.getPreambles().forEach(p -> sb.append(casePreamble(p))); + object.getReactors().forEach(r -> sb.append(caseReactor(r))); + + return sb.toString(); + } @Override @@ -186,7 +194,7 @@ public String caseReactor(Reactor object) { @Override public String caseTargetDecl(TargetDecl object) { - return super.caseTargetDecl(object); + return String.format("target %s", object); } @Override From 07b44154c82da508c89619dc730e38e595772557 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 8 Jun 2022 21:53:07 -0700 Subject: [PATCH 003/130] [fed] Start implementing the new toText cases. --- org.lflang/src/org/lflang/LinguaFranca.xtext | 4 +- org.lflang/src/org/lflang/ast/ToText.java | 138 ++++++++++++++++--- 2 files changed, 122 insertions(+), 20 deletions(-) diff --git a/org.lflang/src/org/lflang/LinguaFranca.xtext b/org.lflang/src/org/lflang/LinguaFranca.xtext index e5ece03e62..9d1965cea8 100644 --- a/org.lflang/src/org/lflang/LinguaFranca.xtext +++ b/org.lflang/src/org/lflang/LinguaFranca.xtext @@ -327,8 +327,8 @@ WidthSpec: ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; WidthTerm: - width=INT - | parameter=[Parameter] + width=INT + | parameter=[Parameter] | 'widthof(' port=VarRef ')' | code=Code; diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 5864610b0f..8f3549fc16 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -1,5 +1,8 @@ package org.lflang.ast; +import java.util.Objects; +import java.util.stream.Collectors; + import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; @@ -269,92 +272,191 @@ public String casePreamble(Preamble object) { @Override public String caseInstantiation(Instantiation object) { - return super.caseInstantiation(object); + // name=ID '=' 'new' (widthSpec=WidthSpec)? + // reactorClass=[ReactorDecl] ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? '(' + // (parameters+=Assignment (',' parameters+=Assignment)*)? + // ')' ('at' host=Host)? ';'?; + StringBuilder sb = new StringBuilder(); + sb.append(object.getName()).append(" = new"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(doSwitch(object.getReactorClass())); + if (!object.getTypeParms().isEmpty()) { + sb.append(object.getTypeParms().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "<", ">")) + ); + } + sb.append(object.getParameters().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "(", ")")) + ); + // TODO: Delete the following case when the corresponding feature is removed + if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); + return sb.toString(); } @Override public String caseConnection(Connection object) { - return super.caseConnection(object); + // ((leftPorts += VarRef (',' leftPorts += VarRef)*) + // | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?)) + // ('->' | physical?='~>') + // rightPorts += VarRef (',' rightPorts += VarRef)* + // ('after' delay=Expression)? + // (serializer=Serializer)? + // ';'? + StringBuilder sb = new StringBuilder(); + if (object.isIterated()) sb.append("("); + sb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + if (object.isIterated()) sb.append(")+"); + sb.append(object.isPhysical() ? " ~> " : " -> "); + sb.append(object.getRightPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + if (object.getDelay() != null) sb.append(" after ").append(doSwitch(object.getDelay())); + if (object.getSerializer() != null) sb.append(" ").append(doSwitch(object.getSerializer())); + return sb.toString(); } @Override public String caseSerializer(Serializer object) { - return super.caseSerializer(object); + // 'serializer' type=STRING + return "serializer " + object.getType(); } @Override public String caseKeyValuePairs(KeyValuePairs object) { - return super.caseKeyValuePairs(object); + return object.getPairs().stream().map(this::doSwitch).collect( + Collectors.joining(",\n ", "{\n ", "\n}") + ); } @Override public String caseKeyValuePair(KeyValuePair object) { - return super.caseKeyValuePair(object); + return object.getName() + ": " + object.getValue(); } @Override public String caseArray(Array object) { - return super.caseArray(object); + // '[' elements+=Element (',' (elements+=Element))* ','? ']' + return object.getElements().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "[", "]") + ); } @Override public String caseElement(Element object) { - return super.caseElement(object); + // keyvalue=KeyValuePairs + // | array=Array + // | literal=Literal + // | (time=INT unit=TimeUnit) + // | id=Path + return defaultCase(object); } @Override public String caseTypedVariable(TypedVariable object) { - return super.caseTypedVariable(object); + // Port | Action + return defaultCase(object); } @Override public String caseVariable(Variable object) { - return super.caseVariable(object); + // TypedVariable | Timer | Mode + return defaultCase(object); } @Override public String caseAssignment(Assignment object) { - return super.caseAssignment(object); + // (lhs=[Parameter] ( + // (equals='=' rhs+=Expression) + // | ((equals='=')? ( + // parens+='(' (rhs+=Expression (',' rhs+=Expression)*)? parens+=')' + // | braces+='{' (rhs+=Expression (',' rhs+=Expression)*)? braces+='}')) + // )); + StringBuilder sb = new StringBuilder(); + sb.append(doSwitch(object.getLhs())); + if (object.getEquals() != null) sb.append(" = "); + if (!object.getParens().isEmpty()) sb.append("("); + if (!object.getBraces().isEmpty()) sb.append("{"); + sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + if (!object.getParens().isEmpty()) sb.append(")"); + if (!object.getBraces().isEmpty()) sb.append("}"); + return sb.toString(); } @Override public String caseParameter(Parameter object) { - return super.caseParameter(object); + // name=ID (':' (type=Type))? + // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') + // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') + // )? + StringBuilder sb = new StringBuilder(); + sb.append(object.getName()); + if (object.getType() != null) sb.append(":").append(doSwitch(object.getType())); + if (object.getInit().isEmpty()) { + sb.append(object.getInit().stream().map(this::doSwitch).collect(Collectors.joining( + ", ", + object.getBraces().isEmpty() ? "(" : "{", + object.getBraces().isEmpty() ? ")" : "}" + ))); + } + return sb.toString(); } @Override public String caseExpression(Expression object) { - return super.caseExpression(object); + // {Literal} literal = Literal + // | Time + // | ParameterReference + // | Code + return defaultCase(object); } @Override public String casePort(Port object) { - return super.casePort(object); + // Input | Output + return defaultCase(object); } @Override public String caseWidthSpec(WidthSpec object) { - return super.caseWidthSpec(object); + // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; + if (object.isOfVariableLength()) return "[]"; + return object.getTerms().stream().map(this::doSwitch).collect( + Collectors.joining("+ ", "[", "]") + ); } @Override public String caseWidthTerm(WidthTerm object) { - return super.caseWidthTerm(object); + // width=INT + // | parameter=[Parameter] + // | 'widthof(' port=VarRef ')' + // | code=Code; + if (object.getWidth() != 0) { + return Objects.toString(object.getWidth()); + } else if (object.getParameter() != null) { + return doSwitch(object.getParameter()); + } else if (object.getPort() != null) { + return String.format("widthof(%s)", object.getPort()); + } else if (object.getCode() != null) { + return doSwitch(object.getCode()); + } + throw new IllegalArgumentException(); } @Override public String caseIPV4Host(IPV4Host object) { - return super.caseIPV4Host(object); + // (user=Kebab '@')? addr=IPV4Addr (':' port=INT)? + return caseHost(object); } @Override public String caseIPV6Host(IPV6Host object) { - return super.caseIPV6Host(object); + // ('[' (user=Kebab '@')? addr=IPV6Addr ']' (':' port=INT)?) + return caseHost(object); } @Override public String caseNamedHost(NamedHost object) { - return super.caseNamedHost(object); + // (user=Kebab '@')? addr=HostName (':' port=INT)? + return caseHost(object); } @Override From 48cd0fe1104e441ec40e4a05ba2614d2cf85cc06 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 9 Jun 2022 13:55:58 -0700 Subject: [PATCH 004/130] [fed] Implement more toText cases. --- org.lflang/src/org/lflang/ast/ToText.java | 97 +++++++++++++++++++---- 1 file changed, 80 insertions(+), 17 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 8f3549fc16..246783bee0 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -1,8 +1,11 @@ package org.lflang.ast; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; @@ -96,6 +99,7 @@ public String caseCode(Code code) { // which the validator uses. return str; } + // FIXME: Exclusion of {= =} violates the spec given by the docstring of this class. str = str.substring(start + 2, end); if (str.split("\n").length > 1) { // multi line code @@ -237,37 +241,81 @@ public String caseMode(Mode object) { @Override public String caseAction(Action object) { - return super.caseAction(object); + // (origin=ActionOrigin)? 'action' name=ID + // ('(' minDelay=Expression (',' minSpacing=Expression (',' policy=STRING)? )? ')')? + // (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + if (object.getOrigin() == null) sb.append(object.getOrigin().getLiteral()).append(" "); + sb.append("action"); + if (object.getMinDelay() != null) { + sb.append(doSwitch(object.getMinDelay())); + if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); + if (object.getPolicy() != null) sb.append(", ").append(object.getPolicy()); + } + if (object.getType() != null) sb.append(": ").append(doSwitch(object.getType())); + return sb.toString(); } @Override public String caseReaction(Reaction object) { - return super.caseReaction(object); + // ('reaction') + // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? + // (sources+=VarRef (',' sources+=VarRef)*)? + // ('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)? + // code=Code + // (stp=STP)? + // (deadline=Deadline)? + StringBuilder sb = new StringBuilder(); + sb.append("reaction"); + if (!object.getTriggers().isEmpty()) { + sb.append(object.getTriggers().stream().map(this::doSwitch).collect(Collectors.joining(", ", "(", ")"))); + } } @Override public String caseTriggerRef(TriggerRef object) { - return super.caseTriggerRef(object); + if (object.isStartup()) return "startup"; + if (object.isShutdown()) return "shutdown"; + throw new IllegalArgumentException("The given TriggerRef object appears to be a VarRef."); } @Override public String caseDeadline(Deadline object) { - return super.caseDeadline(object); + // 'deadline' '(' delay=Expression ')' code=Code + return String.format("deadline(%s) %s", doSwitch(object.getDelay()), doSwitch(object.getCode())); } @Override public String caseSTP(STP object) { - return super.caseSTP(object); + // 'STP' '(' value=Expression ')' code=Code + return String.format("STP(%s) %s", doSwitch(object.getValue()), doSwitch(object.getCode())); } @Override public String caseMutation(Mutation object) { + // ('mutation') + // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? + // (sources+=VarRef (',' sources+=VarRef)*)? + // ('->' effects+=[VarRef] (',' effects+=[VarRef])*)? + // code=Code + StringBuilder sb = new StringBuilder(); + sb.append("mutation"); + if (!object.getTriggers().isEmpty()) { + sb.append(object.getTriggers().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "(", ")")) + ); + } return super.caseMutation(object); } @Override public String casePreamble(Preamble object) { - return super.casePreamble(object); + // (visibility=Visibility)? 'preamble' code=Code + return String.format( + "%s preamble %s", + object.getVisibility() != null ? object.getVisibility().getLiteral() : "", + doSwitch(object.getCode()) + ); } @Override @@ -374,7 +422,7 @@ public String caseAssignment(Assignment object) { if (object.getEquals() != null) sb.append(" = "); if (!object.getParens().isEmpty()) sb.append("("); if (!object.getBraces().isEmpty()) sb.append("{"); - sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", ", "", ""))); if (!object.getParens().isEmpty()) sb.append(")"); if (!object.getBraces().isEmpty()) sb.append("}"); return sb.toString(); @@ -389,13 +437,13 @@ public String caseParameter(Parameter object) { StringBuilder sb = new StringBuilder(); sb.append(object.getName()); if (object.getType() != null) sb.append(":").append(doSwitch(object.getType())); - if (object.getInit().isEmpty()) { - sb.append(object.getInit().stream().map(this::doSwitch).collect(Collectors.joining( - ", ", - object.getBraces().isEmpty() ? "(" : "{", - object.getBraces().isEmpty() ? ")" : "}" - ))); - } + sb.append( + list(object.getInit(), + ", ", + object.getBraces().isEmpty() ? "(" : "{", + object.getBraces().isEmpty() ? ")" : "}", + true + )); return sb.toString(); } @@ -418,9 +466,7 @@ public String casePort(Port object) { public String caseWidthSpec(WidthSpec object) { // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; if (object.isOfVariableLength()) return "[]"; - return object.getTerms().stream().map(this::doSwitch).collect( - Collectors.joining("+ ", "[", "]") - ); + return list(object.getTerms(), " + ", "[", "]", false); } @Override @@ -463,4 +509,21 @@ public String caseNamedHost(NamedHost object) { public String defaultCase(EObject object) { throw new UnsupportedOperationException("ToText has no case for " + object.getClass().getName()); } + + /** + * Represent the given EList as a string. + * @param delimiter The delimiter separating elements of the list. + * @param prefix The token marking the start of the list. + * @param suffix The token marking the end of the list. + * @param nothingIfEmpty Whether the result should be simplified to the + * empty string as opposed to just the prefix and suffix. + */ + private String list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { + if (nothingIfEmpty && items.isEmpty()) return ""; + return items.stream().map(this::doSwitch).collect(Collectors.joining(delimiter, prefix, suffix)); + } + + private String list(EList items) { + return list(items, ", ", "(", ")", true); + } } From 234189a3935f3af9542fc7287edd04f0e8d16906 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 9 Jun 2022 15:55:55 -0700 Subject: [PATCH 005/130] [fed] All toText cases have (untested) implementations. --- org.lflang/src/org/lflang/ast/ToText.java | 177 +++++++++++++++++++--- 1 file changed, 152 insertions(+), 25 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 246783bee0..e0a59237a8 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -1,6 +1,5 @@ package org.lflang.ast; -import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -70,6 +69,9 @@ */ public class ToText extends LfSwitch { + // FIXME: This class needs to respect comments, which lost at the EObject level of abstraction and must be obtained + // using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 + /// public instance initialized when loading the class public static final ToText instance = new ToText(); @@ -181,62 +183,174 @@ public String caseModel(Model object) { @Override public String caseImport(Import object) { - return super.caseImport(object); + // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? + return String.format( + "import %s from %s\n", + list(object.getReactorClasses(), ", ", "", "", false), + object.getImportURI() + ); } @Override public String caseReactorDecl(ReactorDecl object) { - return super.caseReactorDecl(object); + // Reactor | ImportedReactor + return defaultCase(object); } @Override public String caseImportedReactor(ImportedReactor object) { - return super.caseImportedReactor(object); + // reactorClass=[Reactor] ('as' name=ID)? + return String.format("%s as %s", object.getReactorClass(), object.getName()); } @Override public String caseReactor(Reactor object) { - return super.caseReactor(object); + // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) 'reactor' (name=ID)? + // ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? + // ('(' parameters+=Parameter (',' parameters+=Parameter)* ')')? + // ('at' host=Host)? + // ('extends' (superClasses+=[ReactorDecl] (',' superClasses+=[ReactorDecl])*))? + // '{' + // ( (preambles+=Preamble) + // | (stateVars+=StateVar) + // | (methods+=Method) + // | (inputs+=Input) + // | (outputs+=Output) + // | (timers+=Timer) + // | (actions+=Action) + // | (instantiations+=Instantiation) + // | (connections+=Connection) + // | (reactions+=Reaction) + // | (modes+=Mode) + // | (mutations+=Mutation) + // )* '}' + StringBuilder sb = new StringBuilder(); + if (object.isFederated()) sb.append("federated "); + if (object.isMain()) sb.append("main "); + if (object.isRealtime()) sb.append("realtime "); + sb.append("reactor "); + if (object.getName() != null) sb.append(object.getName()); + sb.append(list(object.getTypeParms(), ", ", "<", ">", true)); + sb.append(list(object.getParameters())); + if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); + if (object.getSuperClasses() != null) { + sb.append(" extends ").append(list(object.getSuperClasses(), ", ", "", "", true)); + } + sb.append(" {\n"); + sb.append(indentedStatements(List.of( + object.getPreambles(), + object.getStateVars(), + object.getMethods(), + object.getInputs(), + object.getOutputs(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections(), + object.getReactions(), + object.getModes(), + object.getMutations() + ))); + sb.append("}\n"); + return sb.toString(); } @Override public String caseTargetDecl(TargetDecl object) { - return String.format("target %s", object); + return String.format("target %s", object); } @Override public String caseStateVar(StateVar object) { - return super.caseStateVar(object); + // 'state' name=ID ( + // (':' (type=Type))? + // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') + // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') + // )? + // ) ';'? + return "state " + object.getName() + typeAnnotationFor(object.getType()); } @Override public String caseMethod(Method object) { - return super.caseMethod(object); + // const?='const'? 'method' name=ID + // '(' (arguments+=MethodArgument (',' arguments+=MethodArgument)*)? ')' + // (':' return=Type)? + // code=Code + // ';'? + StringBuilder sb = new StringBuilder(); + if (object.isConst()) sb.append("const "); + sb.append("method"); + return sb.toString(); } @Override public String caseMethodArgument(MethodArgument object) { - return super.caseMethodArgument(object); + return object.getName() + typeAnnotationFor(object.getType()); } @Override public String caseInput(Input object) { - return super.caseInput(object); + // mutable?='mutable'? 'input' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + if (object.isMutable()) sb.append("mutable "); + sb.append("input"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(" ").append(object.getName()).append(typeAnnotationFor(object.getType())); + return sb.toString(); } @Override public String caseOutput(Output object) { - return super.caseOutput(object); + // 'output' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + sb.append("output"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(" ").append(object.getName()); + if (object.getType() != null) sb.append(doSwitch(object.getType())); + return sb.toString(); } @Override public String caseTimer(Timer object) { - return super.caseTimer(object); + // 'timer' name=ID ('(' offset=Expression (',' period=Expression)? ')')? ';'? + StringBuilder sb = new StringBuilder(); + sb.append("timer ").append(object.getName()); + if (object.getOffset() != null) { + sb.append("("); + sb.append(doSwitch(object.getOffset())); + if (object.getPeriod() != null) sb.append(", ").append(doSwitch(object.getPeriod())); + sb.append(")"); + } + return sb.toString(); } @Override public String caseMode(Mode object) { - return super.caseMode(object); + // {Mode} (initial?='initial')? 'mode' (name=ID)? + // '{' ( + // (stateVars+=StateVar) | + // (timers+=Timer) | + // (actions+=Action) | + // (instantiations+=Instantiation) | + // (connections+=Connection) | + // (reactions+=Reaction) + // )* '}' + StringBuilder sb = new StringBuilder(); + if (object.isInitial()) sb.append("initial "); + sb.append("mode "); + if (object.getName() != null) sb.append(object.getName()).append(" "); + sb.append("{\n"); + sb.append(indentedStatements(List.of( + object.getStateVars(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections(), + object.getReactions() + ))); + sb.append("}\n"); + return sb.toString(); } @Override @@ -252,7 +366,7 @@ public String caseAction(Action object) { if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); if (object.getPolicy() != null) sb.append(", ").append(object.getPolicy()); } - if (object.getType() != null) sb.append(": ").append(doSwitch(object.getType())); + sb.append(typeAnnotationFor(object.getType())); return sb.toString(); } @@ -267,9 +381,13 @@ public String caseReaction(Reaction object) { // (deadline=Deadline)? StringBuilder sb = new StringBuilder(); sb.append("reaction"); - if (!object.getTriggers().isEmpty()) { - sb.append(object.getTriggers().stream().map(this::doSwitch).collect(Collectors.joining(", ", "(", ")"))); - } + sb.append(list(object.getTriggers())); + sb.append(list(object.getSources(), ", ", " ", "", true)); + sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + sb.append(doSwitch(object.getCode())); + if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); + if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); + return sb.toString(); } @Override @@ -305,7 +423,7 @@ public String caseMutation(Mutation object) { Collectors.joining(", ", "(", ")")) ); } - return super.caseMutation(object); + return sb.toString(); } @Override @@ -434,17 +552,13 @@ public String caseParameter(Parameter object) { // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') // )? - StringBuilder sb = new StringBuilder(); - sb.append(object.getName()); - if (object.getType() != null) sb.append(":").append(doSwitch(object.getType())); - sb.append( - list(object.getInit(), + return object.getName() + typeAnnotationFor(object.getType()) + list( + object.getInit(), ", ", object.getBraces().isEmpty() ? "(" : "{", object.getBraces().isEmpty() ? ")" : "}", true - )); - return sb.toString(); + ); } @Override @@ -526,4 +640,17 @@ private String list(List items, String delimiter, String private String list(EList items) { return list(items, ", ", "(", ")", true); } + + private String typeAnnotationFor(Type type) { + if (type == null) return ""; + return String.format(": %s", doSwitch(type)); + } + + private String indentedStatements(List> statementListList) { + StringBuilder sb = new StringBuilder(); + for (EList statementList : statementListList) { + sb.append(list(statementList, "\n ", " ", "\n\n", true)); + } + return sb.toString(); + } } From afd82f502dc33bc6795b8f55cbfcf1ab3cabf289 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 9 Jun 2022 17:09:23 -0700 Subject: [PATCH 006/130] [fed] toText: Add some fixes. --- org.lflang/src/org/lflang/ast/ToText.java | 45 ++++++++++++++++------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index e0a59237a8..0ad528a10c 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -57,6 +57,7 @@ import org.lflang.lf.TypedVariable; import org.lflang.lf.VarRef; import org.lflang.lf.Variable; +import org.lflang.lf.Visibility; import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; @@ -149,6 +150,9 @@ public String caseTime(Time t) { @Override public String caseType(Type type) { + // time?='time' (arraySpec=ArraySpec)? + // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? + // | code=Code String base = ASTUtils.baseType(type); String arr = (type.getArraySpec() != null) ? doSwitch(type.getArraySpec()) : ""; return base + arr; @@ -156,11 +160,14 @@ public String caseType(Type type) { @Override public String caseTypeParm(TypeParm t) { + // literal=TypeExpr | code=Code return !StringExtensions.isNullOrEmpty(t.getLiteral()) ? t.getLiteral() : doSwitch(t.getCode()); } @Override public String caseVarRef(VarRef v) { + // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] + // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' if (v.getContainer() != null) { return String.format("%s.%s", v.getContainer().getName(), v.getVariable().getName()); } else { @@ -170,22 +177,25 @@ public String caseVarRef(VarRef v) { @Override public String caseModel(Model object) { + // target=TargetDecl + // (imports+=Import)* + // (preambles+=Preamble)* + // (reactors+=Reactor)+ StringBuilder sb = new StringBuilder(); - sb.append(caseTargetDecl(object.getTarget())); + sb.append(caseTargetDecl(object.getTarget())).append("\n\n"); object.getImports().forEach(i -> sb.append(caseImport(i))); object.getPreambles().forEach(p -> sb.append(casePreamble(p))); object.getReactors().forEach(r -> sb.append(caseReactor(r))); return sb.toString(); - } @Override public String caseImport(Import object) { // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? return String.format( - "import %s from %s\n", + "import %s from %s", list(object.getReactorClasses(), ", ", "", "", false), object.getImportURI() ); @@ -251,13 +261,17 @@ public String caseReactor(Reactor object) { object.getModes(), object.getMutations() ))); - sb.append("}\n"); + sb.append("}"); return sb.toString(); } @Override public String caseTargetDecl(TargetDecl object) { - return String.format("target %s", object); + // target=TargetDecl + // (imports+=Import)* + // (preambles+=Preamble)* + // (reactors+=Reactor)+ + return String.format("target %s %s", object.getName(), doSwitch(object.getConfig())); } @Override @@ -286,6 +300,7 @@ public String caseMethod(Method object) { @Override public String caseMethodArgument(MethodArgument object) { + // name=ID (':' type=Type)? return object.getName() + typeAnnotationFor(object.getType()); } @@ -349,7 +364,7 @@ public String caseMode(Mode object) { object.getConnections(), object.getReactions() ))); - sb.append("}\n"); + sb.append("}"); return sb.toString(); } @@ -383,7 +398,9 @@ public String caseReaction(Reaction object) { sb.append("reaction"); sb.append(list(object.getTriggers())); sb.append(list(object.getSources(), ", ", " ", "", true)); - sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + if (!object.getEffects().isEmpty()) { + sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + } sb.append(doSwitch(object.getCode())); if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); @@ -392,6 +409,7 @@ public String caseReaction(Reaction object) { @Override public String caseTriggerRef(TriggerRef object) { + // VarRef | startup?='startup' | shutdown?='shutdown' if (object.isStartup()) return "startup"; if (object.isShutdown()) return "shutdown"; throw new IllegalArgumentException("The given TriggerRef object appears to be a VarRef."); @@ -431,7 +449,8 @@ public String casePreamble(Preamble object) { // (visibility=Visibility)? 'preamble' code=Code return String.format( "%s preamble %s", - object.getVisibility() != null ? object.getVisibility().getLiteral() : "", + object.getVisibility() != null && object.getVisibility() != Visibility.NONE + ? object.getVisibility().getLiteral() : "", doSwitch(object.getCode()) ); } @@ -494,7 +513,7 @@ public String caseKeyValuePairs(KeyValuePairs object) { @Override public String caseKeyValuePair(KeyValuePair object) { - return object.getName() + ": " + object.getValue(); + return object.getName() + ": " + doSwitch(object.getValue()); } @Override @@ -647,10 +666,8 @@ private String typeAnnotationFor(Type type) { } private String indentedStatements(List> statementListList) { - StringBuilder sb = new StringBuilder(); - for (EList statementList : statementListList) { - sb.append(list(statementList, "\n ", " ", "\n\n", true)); - } - return sb.toString(); + return statementListList.stream().map( + statementList -> list(statementList, "\n ", " ", "\n\n", true) + ).collect(Collectors.joining("\n\n", "", "")); } } From a987311da200f2da9e06eed3f4f8eacf12fa51db Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 9 Jun 2022 17:11:28 -0700 Subject: [PATCH 007/130] [tests] First draft test for toText functions. --- .../src/org/lflang/tests/TestRegistry.java | 4 -- .../compiler/LinguaFrancaParsingTest.java | 24 ++----- .../lflang/tests/compiler/RoundTripTests.java | 66 +++++++++++++++++++ 3 files changed, 73 insertions(+), 21 deletions(-) create mode 100644 org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java diff --git a/org.lflang.tests/src/org/lflang/tests/TestRegistry.java b/org.lflang.tests/src/org/lflang/tests/TestRegistry.java index 4c24699e3c..078cf8af85 100644 --- a/org.lflang.tests/src/org/lflang/tests/TestRegistry.java +++ b/org.lflang.tests/src/org/lflang/tests/TestRegistry.java @@ -2,8 +2,6 @@ import static java.nio.file.FileVisitResult.CONTINUE; import static java.nio.file.FileVisitResult.SKIP_SUBTREE; -import static org.eclipse.xtext.xbase.lib.IteratorExtensions.exists; -import static org.eclipse.xtext.xbase.lib.IteratorExtensions.filter; import java.io.File; import java.io.IOException; @@ -17,7 +15,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.Stack; import java.util.TreeSet; @@ -33,7 +30,6 @@ import org.lflang.LFStandaloneSetup; import org.lflang.Target; import org.lflang.lf.Reactor; -import org.lflang.lf.TargetDecl; import org.lflang.tests.LFTest.Result; /** diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaParsingTest.java b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaParsingTest.java index f898b76c08..23ba302fe1 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaParsingTest.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/LinguaFrancaParsingTest.java @@ -1,5 +1,3 @@ -/* Parsing unit tests. */ - /************* Copyright (c) 2019, The University of California at Berkeley. @@ -36,31 +34,23 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.lflang.tests.LFInjectorProvider; -@ExtendWith(InjectionExtension.class) -@InjectWith(LFInjectorProvider.class) - /** * Test harness for ensuring that grammar captures * all corner cases. */ +@ExtendWith(InjectionExtension.class) +@InjectWith(LFInjectorProvider.class) class LinguaFrancaParsingTest { @Inject ParseHelper parser; @Test public void checkForTarget() throws Exception { -// Java 17: -// String testCase = """ -// targett C; -// reactor Foo { -// } -// """ -// Java 11: - String testCase = String.join(System.getProperty("line.separator"), - "targett C;", - "reactor Foo {", - "}" - ); + String testCase = """ + targett C; + reactor Foo { + } + """; Model result = parser.parse(testCase); Assertions.assertNotNull(result); Assertions.assertFalse(result.eResource().getErrors().isEmpty(), "Failed to catch misspelled target keyword."); diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java new file mode 100644 index 0000000000..c63419be92 --- /dev/null +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -0,0 +1,66 @@ +package org.lflang.tests.compiler; + +import java.nio.file.Files; +import java.util.function.Function; + +import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.testing.InjectWith; +import org.eclipse.xtext.testing.extensions.InjectionExtension; +import org.eclipse.xtext.testing.util.ParseHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.lflang.Target; +import org.lflang.ast.ToText; +import org.lflang.lf.Model; +import org.lflang.tests.LFInjectorProvider; +import org.lflang.tests.LFTest; +import org.lflang.tests.TestRegistry; +import org.lflang.tests.TestRegistry.TestCategory; + +import com.google.inject.Inject; + +@ExtendWith(InjectionExtension.class) +@InjectWith(LFInjectorProvider.class) +public class RoundTripTests { + @Inject + ParseHelper parser; + + @Test + public void roundTripTest() throws Exception { + for (Target target : Target.values()) { + for (TestCategory category : TestCategory.values()) { + for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { + run(test); + } + } + } + } + + private void run(LFTest test) throws Exception { + String testCase = Files.readString(test.srcFile); + Model originalModel = parser.parse(testCase); + Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); + String reformattedTestCase = ToText.instance.doSwitch(originalModel); + Model resultingModel = parser.parse(reformattedTestCase); + Assertions.assertNotNull(resultingModel); + if (!resultingModel.eResource().getErrors().isEmpty()) System.err.println(reformattedTestCase); + Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); + checkSemanticallyEquivalent(originalModel, resultingModel); + } + + private void checkSemanticallyEquivalent(Model originalModel, Model resultingModel) { + // FIXME: This is a toy implementation. It is no good. + Function, Integer> getSize = contents -> { + int count = 0; + for (; contents.hasNext(); contents.next()) count++; + return count; + }; + Assertions.assertEquals( + getSize.apply(originalModel.eAllContents()), + getSize.apply(resultingModel.eAllContents()) + ); + } +} From 4dfda7a2f28425222a86f110716af43c6a313b53 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 10 Jun 2022 10:28:15 -0700 Subject: [PATCH 008/130] [validator] Address runtime error for an incorrect program. --- org.lflang/src/org/lflang/ModelInfo.java | 3 +++ org.lflang/src/org/lflang/generator/DeadlineInstance.java | 2 -- org.lflang/src/org/lflang/generator/ReactorInstance.java | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/ModelInfo.java b/org.lflang/src/org/lflang/ModelInfo.java index 84de93d598..1ce6155818 100644 --- a/org.lflang/src/org/lflang/ModelInfo.java +++ b/org.lflang/src/org/lflang/ModelInfo.java @@ -195,6 +195,8 @@ private boolean isTooLarge(TimeValue time) { * Given a parameter that is used in a deadline specification, recursively * track down its definition and check whether it is overflowing. Also * detect and report overrides that are overflowing. + * @return true if there exists a parameter corresponding to a value that + * does not fit in the available bits. */ private boolean detectOverflow(Set visited, Parameter current) { var overflow = false; @@ -215,6 +217,7 @@ private boolean detectOverflow(Set visited, Parameter current) { // Find assignments that override the current parameter. for (var assignment : instantiation.getParameters()) { if (assignment.getLhs().equals(current)) { + if (assignment.getRhs().isEmpty()) continue; // This error should be caught elsewhere. Expression expr = assignment.getRhs().get(0); if (expr instanceof ParameterReference) { // Check for overflow in the referenced parameter. diff --git a/org.lflang/src/org/lflang/generator/DeadlineInstance.java b/org.lflang/src/org/lflang/generator/DeadlineInstance.java index 395e823d1a..ca70584d05 100644 --- a/org.lflang/src/org/lflang/generator/DeadlineInstance.java +++ b/org.lflang/src/org/lflang/generator/DeadlineInstance.java @@ -27,10 +27,8 @@ package org.lflang.generator; -import org.lflang.ASTUtils; import org.lflang.TimeValue; import org.lflang.lf.Deadline; -import org.lflang.lf.Parameter; /** * Instance of a deadline. Upon creation the actual delay is converted into diff --git a/org.lflang/src/org/lflang/generator/ReactorInstance.java b/org.lflang/src/org/lflang/generator/ReactorInstance.java index c7d169ab23..7653d5eee7 100644 --- a/org.lflang/src/org/lflang/generator/ReactorInstance.java +++ b/org.lflang/src/org/lflang/generator/ReactorInstance.java @@ -651,6 +651,8 @@ public String toString() { public TimeValue getTimeValue(Expression expr) { if (expr instanceof ParameterReference) { final var param = ((ParameterReference)expr).getParameter(); + // Avoid a runtime error in validator for invalid programs. + if (lookupParameterInstance(param).getInitialValue().isEmpty()) return null; return ASTUtils.getLiteralTimeValue(lookupParameterInstance(param).getInitialValue().get(0)); } else { return ASTUtils.getLiteralTimeValue(expr); From 8939ee6863a2039b14ead6b236884591e5c21875 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 10 Jun 2022 15:22:29 -0700 Subject: [PATCH 009/130] [fed] More fixes for pretty-printer. Still does not compile. --- org.lflang/src/org/lflang/ASTUtils.java | 35 +++++++ org.lflang/src/org/lflang/ast/ToText.java | 117 +++++++++++----------- 2 files changed, 91 insertions(+), 61 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index 0f39e701a5..45144b942e 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -45,6 +45,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.ILeafNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.impl.CompositeNode; import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; @@ -794,8 +795,42 @@ public static String toText(EObject node) { */ public static String toOriginalText(EObject node) { if (node == null) return ""; + if (node instanceof Code code) return getCode(code); return ToText.instance.doSwitch(node); } + + private static String getCode(Code code) { + ICompositeNode node = NodeModelUtils.getNode(code); + if (node != null) { + StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); + for (ILeafNode leaf : node.getLeafNodes()) { + builder.append(leaf.getText()); + } + String str = builder.toString().trim(); + // Remove the code delimiters (and any surrounding comments). + // This assumes any comment before {= does not include {=. + int start = str.indexOf("{="); + int end = str.indexOf("=}", start); + if (start == -1 || end == -1) { + // Silent failure is needed here because toText is needed to create the intermediate representation, + // which the validator uses. + return str; + } + // FIXME: Exclusion of {= =} violates the spec given by the docstring of this class. + str = str.substring(start + 2, end); + if (str.split("\n").length > 1) { + // multi line code + return StringUtil.trimCodeBlock(str); + } else { + // single line code + return str.trim(); + } + } else if (code.getBody() != null) { + // Code must have been added as a simple string. + return code.getBody(); + } + return ""; + } /** * Return an integer representation of the given element. diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 0ad528a10c..df7d6db09d 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -2,13 +2,11 @@ import java.util.List; import java.util.Objects; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.nodemodel.ICompositeNode; -import org.eclipse.xtext.nodemodel.ILeafNode; -import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; @@ -61,7 +59,6 @@ import org.lflang.lf.WidthSpec; import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; -import org.lflang.util.StringUtil; /** @@ -86,36 +83,9 @@ public String caseArraySpec(ArraySpec spec) { @Override public String caseCode(Code code) { - ICompositeNode node = NodeModelUtils.getNode(code); - if (node != null) { - StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); - for (ILeafNode leaf : node.getLeafNodes()) { - builder.append(leaf.getText()); - } - String str = builder.toString().trim(); - // Remove the code delimiters (and any surrounding comments). - // This assumes any comment before {= does not include {=. - int start = str.indexOf("{="); - int end = str.indexOf("=}", start); - if (start == -1 || end == -1) { - // Silent failure is needed here because toText is needed to create the intermediate representation, - // which the validator uses. - return str; - } - // FIXME: Exclusion of {= =} violates the spec given by the docstring of this class. - str = str.substring(start + 2, end); - if (str.split("\n").length > 1) { - // multi line code - return StringUtil.trimCodeBlock(str); - } else { - // single line code - return str.trim(); - } - } else if (code.getBody() != null) { - // Code must have been added as a simple string. - return code.getBody(); - } - return ""; + String content = ASTUtils.toOriginalText(code); + if (content.lines().count() > 1) return String.format("{=\n%s=}", content); + return String.format("{= %s =}", content); } @Override @@ -168,6 +138,8 @@ public String caseTypeParm(TypeParm t) { public String caseVarRef(VarRef v) { // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' + // FIXME: This, like the original caseCode implementation, also appears to violate the spec given by the + // docstring. if (v.getContainer() != null) { return String.format("%s.%s", v.getContainer().getName(), v.getVariable().getName()); } else { @@ -184,9 +156,11 @@ public String caseModel(Model object) { StringBuilder sb = new StringBuilder(); sb.append(caseTargetDecl(object.getTarget())).append("\n\n"); - object.getImports().forEach(i -> sb.append(caseImport(i))); - object.getPreambles().forEach(p -> sb.append(casePreamble(p))); - object.getReactors().forEach(r -> sb.append(caseReactor(r))); + object.getImports().forEach(i -> sb.append(caseImport(i)).append("\n")); + if (!object.getImports().isEmpty()) sb.append("\n"); + object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append("\n\n")); + if (!object.getPreambles().isEmpty()) sb.append("\n"); + object.getReactors().forEach(r -> sb.append(caseReactor(r)).append("\n\n")); return sb.toString(); } @@ -195,7 +169,7 @@ public String caseModel(Model object) { public String caseImport(Import object) { // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? return String.format( - "import %s from %s", + "import %s from \"%s\"", list(object.getReactorClasses(), ", ", "", "", false), object.getImportURI() ); @@ -210,7 +184,10 @@ public String caseReactorDecl(ReactorDecl object) { @Override public String caseImportedReactor(ImportedReactor object) { // reactorClass=[Reactor] ('as' name=ID)? - return String.format("%s as %s", object.getReactorClass(), object.getName()); + if (object.getName() != null) { + return String.format("%s as %s", object.getReactorClass().getName(), object.getName()); + } + return object.getReactorClass().getName(); } @Override @@ -238,13 +215,15 @@ public String caseReactor(Reactor object) { if (object.isFederated()) sb.append("federated "); if (object.isMain()) sb.append("main "); if (object.isRealtime()) sb.append("realtime "); - sb.append("reactor "); - if (object.getName() != null) sb.append(object.getName()); + sb.append("reactor"); + if (object.getName() != null) sb.append(" ").append(object.getName()); sb.append(list(object.getTypeParms(), ", ", "<", ">", true)); sb.append(list(object.getParameters())); if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); - if (object.getSuperClasses() != null) { - sb.append(" extends ").append(list(object.getSuperClasses(), ", ", "", "", true)); + if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { + sb.append(" extends ").append( + object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) + ); } sb.append(" {\n"); sb.append(indentedStatements(List.of( @@ -261,7 +240,7 @@ public String caseReactor(Reactor object) { object.getModes(), object.getMutations() ))); - sb.append("}"); + sb.append("\n}"); return sb.toString(); } @@ -271,7 +250,10 @@ public String caseTargetDecl(TargetDecl object) { // (imports+=Import)* // (preambles+=Preamble)* // (reactors+=Reactor)+ - return String.format("target %s %s", object.getName(), doSwitch(object.getConfig())); + StringBuilder sb = new StringBuilder(); + sb.append("target ").append(object.getName()); + if (object.getConfig() != null) sb.append(" ").append(doSwitch(object.getConfig())); + return sb.toString(); } @Override @@ -282,7 +264,12 @@ public String caseStateVar(StateVar object) { // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') // )? // ) ';'? - return "state " + object.getName() + typeAnnotationFor(object.getType()); + StringBuilder sb = new StringBuilder(); + sb.append("state ").append(object.getName()); + sb.append(typeAnnotationFor(object.getType())); + if (!object.getParens().isEmpty()) sb.append(list(object.getInit())); + if (!object.getBraces().isEmpty()) sb.append(list(object.getInit(), ", ", "{", "}", true)); + return sb.toString(); } @Override @@ -322,7 +309,7 @@ public String caseOutput(Output object) { sb.append("output"); if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); sb.append(" ").append(object.getName()); - if (object.getType() != null) sb.append(doSwitch(object.getType())); + sb.append(typeAnnotationFor(object.getType())); return sb.toString(); } @@ -374,12 +361,14 @@ public String caseAction(Action object) { // ('(' minDelay=Expression (',' minSpacing=Expression (',' policy=STRING)? )? ')')? // (':' type=Type)? ';'? StringBuilder sb = new StringBuilder(); - if (object.getOrigin() == null) sb.append(object.getOrigin().getLiteral()).append(" "); - sb.append("action"); + if (object.getOrigin() != null) sb.append(object.getOrigin().getLiteral()).append(" "); + sb.append("action "); + sb.append(object.getName()); if (object.getMinDelay() != null) { - sb.append(doSwitch(object.getMinDelay())); + sb.append("(").append(doSwitch(object.getMinDelay())); if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); - if (object.getPolicy() != null) sb.append(", ").append(object.getPolicy()); + if (object.getPolicy() != null) sb.append(", \"").append(object.getPolicy()).append("\""); + sb.append(")"); } sb.append(typeAnnotationFor(object.getType())); return sb.toString(); @@ -401,7 +390,7 @@ public String caseReaction(Reaction object) { if (!object.getEffects().isEmpty()) { sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); } - sb.append(doSwitch(object.getCode())); + sb.append(" ").append(doSwitch(object.getCode())); if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); return sb.toString(); @@ -448,9 +437,9 @@ public String caseMutation(Mutation object) { public String casePreamble(Preamble object) { // (visibility=Visibility)? 'preamble' code=Code return String.format( - "%s preamble %s", + "%spreamble %s", object.getVisibility() != null && object.getVisibility() != Visibility.NONE - ? object.getVisibility().getLiteral() : "", + ? object.getVisibility().getLiteral() + " " : "", doSwitch(object.getCode()) ); } @@ -464,7 +453,7 @@ public String caseInstantiation(Instantiation object) { StringBuilder sb = new StringBuilder(); sb.append(object.getName()).append(" = new"); if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(doSwitch(object.getReactorClass())); + sb.append(" ").append(object.getReactorClass().getName()); if (!object.getTypeParms().isEmpty()) { sb.append(object.getTypeParms().stream().map(this::doSwitch).collect( Collectors.joining(", ", "<", ">")) @@ -501,11 +490,12 @@ public String caseConnection(Connection object) { @Override public String caseSerializer(Serializer object) { // 'serializer' type=STRING - return "serializer " + object.getType(); + return String.format("serializer \"%s\"", object.getType()); } @Override public String caseKeyValuePairs(KeyValuePairs object) { + // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' return object.getPairs().stream().map(this::doSwitch).collect( Collectors.joining(",\n ", "{\n ", "\n}") ); @@ -513,6 +503,7 @@ public String caseKeyValuePairs(KeyValuePairs object) { @Override public String caseKeyValuePair(KeyValuePair object) { + // name=Kebab ':' value=Element return object.getName() + ": " + doSwitch(object.getValue()); } @@ -531,7 +522,11 @@ public String caseElement(Element object) { // | literal=Literal // | (time=INT unit=TimeUnit) // | id=Path - return defaultCase(object); + if (object.getKeyvalue() != null) return doSwitch(object.getKeyvalue()); + if (object.getArray() != null) return doSwitch(object.getArray()); + if (object.getLiteral() != null) return object.getLiteral(); + if (object.getTime() != 0) return String.format("%d %s", object.getTime(), object.getUnit()); + return object.getId(); } @Override @@ -555,7 +550,7 @@ public String caseAssignment(Assignment object) { // | braces+='{' (rhs+=Expression (',' rhs+=Expression)*)? braces+='}')) // )); StringBuilder sb = new StringBuilder(); - sb.append(doSwitch(object.getLhs())); + sb.append(object.getLhs().getName()); if (object.getEquals() != null) sb.append(" = "); if (!object.getParens().isEmpty()) sb.append("("); if (!object.getBraces().isEmpty()) sb.append("{"); @@ -611,7 +606,7 @@ public String caseWidthTerm(WidthTerm object) { if (object.getWidth() != 0) { return Objects.toString(object.getWidth()); } else if (object.getParameter() != null) { - return doSwitch(object.getParameter()); + return object.getParameter().getName(); } else if (object.getPort() != null) { return String.format("widthof(%s)", object.getPort()); } else if (object.getCode() != null) { @@ -666,8 +661,8 @@ private String typeAnnotationFor(Type type) { } private String indentedStatements(List> statementListList) { - return statementListList.stream().map( - statementList -> list(statementList, "\n ", " ", "\n\n", true) + return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( + statementList -> list(statementList, "\n ", " ", "", true) ).collect(Collectors.joining("\n\n", "", "")); } } From b67bf88880f7e83c4d657056c9a929495a4fab09 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 10 Jun 2022 18:22:19 -0700 Subject: [PATCH 010/130] [tests] Attempt linking. --- .../lflang/tests/compiler/RoundTripTests.java | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index c63419be92..9218fa07fb 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -1,13 +1,21 @@ package org.lflang.tests.compiler; import java.nio.file.Files; +import java.nio.file.Path; import java.util.function.Function; import org.eclipse.emf.common.util.TreeIterator; +import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.xtext.EcoreUtil2; import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.eclipse.xtext.testing.util.ParseHelper; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.validation.CheckMode; +import org.eclipse.xtext.validation.IResourceValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -21,33 +29,56 @@ import org.lflang.tests.TestRegistry.TestCategory; import com.google.inject.Inject; +import com.google.inject.Provider; @ExtendWith(InjectionExtension.class) @InjectWith(LFInjectorProvider.class) public class RoundTripTests { + @Inject + IResourceValidator validator; + + @Inject + Provider resourceSetProvider; + @Inject ParseHelper parser; @Test public void roundTripTest() throws Exception { + int nonFailures = 0; for (Target target : Target.values()) { for (TestCategory category : TestCategory.values()) { for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { - run(test); + run(test.srcFile); + System.out.printf("%s non-failures%n", ++nonFailures); } } } } - private void run(LFTest test) throws Exception { - String testCase = Files.readString(test.srcFile); - Model originalModel = parser.parse(testCase); + private void run(Path file) throws Exception { + String testCase = Files.readString(file); + Resource resource = resourceSetProvider.get().getResource( + URI.createFileURI(file.toFile().getAbsolutePath()), + true + ); + var issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); + Assertions.assertTrue(issues.isEmpty()); +// EcoreUtil2.resolveAll(resource); + EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl); + ResourceSet resourceSet = resource.getResourceSet(); +// EcoreUtil2.resolveAll(resourceSet); + Model originalModel = parser.parse(testCase, resourceSet); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); String reformattedTestCase = ToText.instance.doSwitch(originalModel); - Model resultingModel = parser.parse(reformattedTestCase); + System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); + Model resultingModel = parser.parse(reformattedTestCase, resourceSet); Assertions.assertNotNull(resultingModel); - if (!resultingModel.eResource().getErrors().isEmpty()) System.err.println(reformattedTestCase); - Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); + if (!resultingModel.eResource().getErrors().isEmpty()) { + System.err.println(reformattedTestCase); + resultingModel.eResource().getErrors().forEach(System.err::println); + Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); + } checkSemanticallyEquivalent(originalModel, resultingModel); } From b722f6d9c3c26bb30032a8160e858eaef03da576 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 11 Jun 2022 11:22:00 -0700 Subject: [PATCH 011/130] [tests] Linking works. --- .../lflang/tests/compiler/RoundTripTests.java | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 9218fa07fb..0bf014b0df 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -1,6 +1,5 @@ package org.lflang.tests.compiler; -import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Function; @@ -8,18 +7,16 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.xtext.EcoreUtil2; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.eclipse.xtext.testing.util.ParseHelper; -import org.eclipse.xtext.util.CancelIndicator; -import org.eclipse.xtext.validation.CheckMode; -import org.eclipse.xtext.validation.IResourceValidator; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.lflang.LFStandaloneSetup; import org.lflang.Target; import org.lflang.ast.ToText; import org.lflang.lf.Model; @@ -29,16 +26,13 @@ import org.lflang.tests.TestRegistry.TestCategory; import com.google.inject.Inject; -import com.google.inject.Provider; +import com.google.inject.Injector; @ExtendWith(InjectionExtension.class) @InjectWith(LFInjectorProvider.class) public class RoundTripTests { @Inject - IResourceValidator validator; - - @Inject - Provider resourceSetProvider; + XtextResourceSet resourceSet; @Inject ParseHelper parser; @@ -57,31 +51,28 @@ public void roundTripTest() throws Exception { } private void run(Path file) throws Exception { - String testCase = Files.readString(file); - Resource resource = resourceSetProvider.get().getResource( - URI.createFileURI(file.toFile().getAbsolutePath()), - true - ); - var issues = validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); - Assertions.assertTrue(issues.isEmpty()); -// EcoreUtil2.resolveAll(resource); - EcoreUtil2.resolveLazyCrossReferences(resource, CancelIndicator.NullImpl); - ResourceSet resourceSet = resource.getResourceSet(); -// EcoreUtil2.resolveAll(resourceSet); - Model originalModel = parser.parse(testCase, resourceSet); + Model originalModel = parse(file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); String reformattedTestCase = ToText.instance.doSwitch(originalModel); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = parser.parse(reformattedTestCase, resourceSet); Assertions.assertNotNull(resultingModel); if (!resultingModel.eResource().getErrors().isEmpty()) { - System.err.println(reformattedTestCase); resultingModel.eResource().getErrors().forEach(System.err::println); Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); } checkSemanticallyEquivalent(originalModel, resultingModel); } + private Model parse(Path file) { + // Source: https://wiki.eclipse.org/Xtext/FAQ#How_do_I_load_my_model_in_a_standalone_Java_application_.3F + Injector injector = new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); + XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class); + resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); + Resource resource = resourceSet.getResource(URI.createFileURI(file.toFile().getAbsolutePath()), true); + return (Model) resource.getContents().get(0); + } + private void checkSemanticallyEquivalent(Model originalModel, Model resultingModel) { // FIXME: This is a toy implementation. It is no good. Function, Integer> getSize = contents -> { From 9568c3dc6f88d3a8c28e0bbe0e91871dcd94497f Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 11 Jun 2022 11:54:59 -0700 Subject: [PATCH 012/130] [fed] More fixes for pretty-printer. --- org.lflang/src/org/lflang/ast/ToText.java | 51 +++++++++++++---------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index df7d6db09d..0e83c4c043 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -67,8 +67,8 @@ */ public class ToText extends LfSwitch { - // FIXME: This class needs to respect comments, which lost at the EObject level of abstraction and must be obtained - // using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 + // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be + // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 /// public instance initialized when loading the class public static final ToText instance = new ToText(); @@ -84,8 +84,14 @@ public String caseArraySpec(ArraySpec spec) { @Override public String caseCode(Code code) { String content = ASTUtils.toOriginalText(code); - if (content.lines().count() > 1) return String.format("{=\n%s=}", content); - return String.format("{= %s =}", content); + if (content.lines().count() > 1) { + return String.format( + "{=%n%s=}", + content.endsWith("\n") || content.endsWith("\r") ? content : content + System.lineSeparator() + ); + } + if (content.contains("#") || content.contains("//")) return String.format("{=%n%s%n=}", content.strip()); + return String.format("{= %s =}", content.strip()); } @Override @@ -154,14 +160,12 @@ public String caseModel(Model object) { // (preambles+=Preamble)* // (reactors+=Reactor)+ StringBuilder sb = new StringBuilder(); - - sb.append(caseTargetDecl(object.getTarget())).append("\n\n"); - object.getImports().forEach(i -> sb.append(caseImport(i)).append("\n")); - if (!object.getImports().isEmpty()) sb.append("\n"); - object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append("\n\n")); - if (!object.getPreambles().isEmpty()) sb.append("\n"); - object.getReactors().forEach(r -> sb.append(caseReactor(r)).append("\n\n")); - + sb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); + object.getImports().forEach(i -> sb.append(caseImport(i)).append(System.lineSeparator())); + if (!object.getImports().isEmpty()) sb.append(System.lineSeparator()); + object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2))); + if (!object.getPreambles().isEmpty()) sb.append(System.lineSeparator()); + object.getReactors().forEach(r -> sb.append(caseReactor(r)).append(System.lineSeparator().repeat(2))); return sb.toString(); } @@ -225,7 +229,7 @@ public String caseReactor(Reactor object) { object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) ); } - sb.append(" {\n"); + sb.append(String.format(" {%n")); sb.append(indentedStatements(List.of( object.getPreambles(), object.getStateVars(), @@ -240,7 +244,7 @@ public String caseReactor(Reactor object) { object.getModes(), object.getMutations() ))); - sb.append("\n}"); + sb.append(String.format("%n}")); return sb.toString(); } @@ -342,7 +346,7 @@ public String caseMode(Mode object) { if (object.isInitial()) sb.append("initial "); sb.append("mode "); if (object.getName() != null) sb.append(object.getName()).append(" "); - sb.append("{\n"); + sb.append(String.format("{%n")); sb.append(indentedStatements(List.of( object.getStateVars(), object.getTimers(), @@ -497,7 +501,7 @@ public String caseSerializer(Serializer object) { public String caseKeyValuePairs(KeyValuePairs object) { // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' return object.getPairs().stream().map(this::doSwitch).collect( - Collectors.joining(",\n ", "{\n ", "\n}") + Collectors.joining(String.format(",%n "), String.format("{%n "), String.format("%n}")) ); } @@ -525,8 +529,9 @@ public String caseElement(Element object) { if (object.getKeyvalue() != null) return doSwitch(object.getKeyvalue()); if (object.getArray() != null) return doSwitch(object.getArray()); if (object.getLiteral() != null) return object.getLiteral(); - if (object.getTime() != 0) return String.format("%d %s", object.getTime(), object.getUnit()); - return object.getId(); + if (object.getId() != null) return object.getId(); + if (object.getUnit() != null) return String.format("%d %s", object.getTime(), object.getUnit()); + return String.valueOf(object.getTime()); } @Override @@ -635,7 +640,11 @@ public String caseNamedHost(NamedHost object) { @Override public String defaultCase(EObject object) { - throw new UnsupportedOperationException("ToText has no case for " + object.getClass().getName()); + throw new UnsupportedOperationException(String.format( + "ToText has no case for %s or any of its supertypes, or it does have such a case, but " + + "the return value of that case was null.", + object.getClass().getName() + )); } /** @@ -662,7 +671,7 @@ private String typeAnnotationFor(Type type) { private String indentedStatements(List> statementListList) { return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( - statementList -> list(statementList, "\n ", " ", "", true) - ).collect(Collectors.joining("\n\n", "", "")); + statementList -> list(statementList, String.format("%n "), " ", "", true) + ).collect(Collectors.joining(System.lineSeparator().repeat(2), "", "")); } } From d5c1f40ff13f3568520ba5cb3c414ecc2600d5e9 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 11 Jun 2022 12:17:50 -0700 Subject: [PATCH 013/130] [ast] Separate concerns: ToLf != toText. --- .../lflang/tests/compiler/RoundTripTests.java | 4 +- org.lflang/src/org/lflang/ASTUtils.java | 35 - org.lflang/src/org/lflang/ast/ToLf.java | 671 ++++++++++++++++++ org.lflang/src/org/lflang/ast/ToText.java | 641 ++--------------- 4 files changed, 714 insertions(+), 637 deletions(-) create mode 100644 org.lflang/src/org/lflang/ast/ToLf.java diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 0bf014b0df..44c035e38d 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -18,7 +18,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.Target; -import org.lflang.ast.ToText; +import org.lflang.ast.ToLf; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; @@ -53,7 +53,7 @@ public void roundTripTest() throws Exception { private void run(Path file) throws Exception { Model originalModel = parse(file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); - String reformattedTestCase = ToText.instance.doSwitch(originalModel); + String reformattedTestCase = ToLf.instance.doSwitch(originalModel); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = parser.parse(reformattedTestCase, resourceSet); Assertions.assertNotNull(resultingModel); diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index 45144b942e..0f39e701a5 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -45,7 +45,6 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; -import org.eclipse.xtext.nodemodel.ILeafNode; import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.impl.CompositeNode; import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; @@ -795,42 +794,8 @@ public static String toText(EObject node) { */ public static String toOriginalText(EObject node) { if (node == null) return ""; - if (node instanceof Code code) return getCode(code); return ToText.instance.doSwitch(node); } - - private static String getCode(Code code) { - ICompositeNode node = NodeModelUtils.getNode(code); - if (node != null) { - StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); - for (ILeafNode leaf : node.getLeafNodes()) { - builder.append(leaf.getText()); - } - String str = builder.toString().trim(); - // Remove the code delimiters (and any surrounding comments). - // This assumes any comment before {= does not include {=. - int start = str.indexOf("{="); - int end = str.indexOf("=}", start); - if (start == -1 || end == -1) { - // Silent failure is needed here because toText is needed to create the intermediate representation, - // which the validator uses. - return str; - } - // FIXME: Exclusion of {= =} violates the spec given by the docstring of this class. - str = str.substring(start + 2, end); - if (str.split("\n").length > 1) { - // multi line code - return StringUtil.trimCodeBlock(str); - } else { - // single line code - return str.trim(); - } - } else if (code.getBody() != null) { - // Code must have been added as a simple string. - return code.getBody(); - } - return ""; - } /** * Return an integer representation of the given element. diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java new file mode 100644 index 0000000000..2fe23257d7 --- /dev/null +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -0,0 +1,671 @@ +package org.lflang.ast; + +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.xbase.lib.StringExtensions; + +import org.lflang.ASTUtils; +import org.lflang.lf.Action; +import org.lflang.lf.Array; +import org.lflang.lf.ArraySpec; +import org.lflang.lf.Assignment; +import org.lflang.lf.Code; +import org.lflang.lf.Connection; +import org.lflang.lf.Deadline; +import org.lflang.lf.Element; +import org.lflang.lf.Expression; +import org.lflang.lf.Host; +import org.lflang.lf.IPV4Host; +import org.lflang.lf.IPV6Host; +import org.lflang.lf.Import; +import org.lflang.lf.ImportedReactor; +import org.lflang.lf.Input; +import org.lflang.lf.Instantiation; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.Literal; +import org.lflang.lf.Method; +import org.lflang.lf.MethodArgument; +import org.lflang.lf.Mode; +import org.lflang.lf.Model; +import org.lflang.lf.Mutation; +import org.lflang.lf.NamedHost; +import org.lflang.lf.Output; +import org.lflang.lf.Parameter; +import org.lflang.lf.ParameterReference; +import org.lflang.lf.Port; +import org.lflang.lf.Preamble; +import org.lflang.lf.Reaction; +import org.lflang.lf.Reactor; +import org.lflang.lf.ReactorDecl; +import org.lflang.lf.STP; +import org.lflang.lf.Serializer; +import org.lflang.lf.StateVar; +import org.lflang.lf.TargetDecl; +import org.lflang.lf.Time; +import org.lflang.lf.Timer; +import org.lflang.lf.TriggerRef; +import org.lflang.lf.Type; +import org.lflang.lf.TypeParm; +import org.lflang.lf.TypedVariable; +import org.lflang.lf.VarRef; +import org.lflang.lf.Variable; +import org.lflang.lf.Visibility; +import org.lflang.lf.WidthSpec; +import org.lflang.lf.WidthTerm; +import org.lflang.lf.util.LfSwitch; + +/** + * Switch class for converting AST nodes to their textual representation as + * it would appear in LF code. + */ +public class ToLf extends LfSwitch { + + // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be + // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 + + /// public instance initialized when loading the class + public static final ToLf instance = new ToLf(); + + // private constructor + private ToLf() { super(); } + + @Override + public String caseArraySpec(ArraySpec spec) { + return (spec.isOfVariableLength()) ? "[]" : "[" + spec.getLength() + "]"; + } + + @Override + public String caseCode(Code code) { + String content = ToText.instance.doSwitch(code); + if (content.lines().count() > 1) { + return String.format( + "{=%n%s=}", + content.endsWith("\n") || content.endsWith("\r") ? content : content + System.lineSeparator() + ); + } + if (content.contains("#") || content.contains("//")) return String.format("{=%n%s%n=}", content.strip()); + return String.format("{= %s =}", content.strip()); + } + + @Override + public String caseHost(Host host) { + StringBuilder sb = new StringBuilder(); + if (!StringExtensions.isNullOrEmpty(host.getUser())) { + sb.append(host.getUser()).append("@"); + } + if (!StringExtensions.isNullOrEmpty(host.getAddr())) { + sb.append(host.getAddr()); + } + if (host.getPort() != 0) { + sb.append(":").append(host.getPort()); + } + return sb.toString(); + } + + @Override + public String caseLiteral(Literal l) { + return l.getLiteral(); + } + + @Override + public String caseParameterReference(ParameterReference p) { + return p.getParameter().getName(); + } + + @Override + public String caseTime(Time t) { + return ASTUtils.toTimeValue(t).toString(); + } + + @Override + public String caseType(Type type) { + // time?='time' (arraySpec=ArraySpec)? + // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? + // | code=Code + String base = ASTUtils.baseType(type); + String arr = (type.getArraySpec() != null) ? doSwitch(type.getArraySpec()) : ""; + return base + arr; + } + + @Override + public String caseTypeParm(TypeParm t) { + // literal=TypeExpr | code=Code + return !StringExtensions.isNullOrEmpty(t.getLiteral()) ? t.getLiteral() : doSwitch(t.getCode()); + } + + @Override + public String caseVarRef(VarRef v) { + // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] + // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' + if (!v.isInterleaved()) return ToText.instance.doSwitch(v); + return String.format("interleaved (%s)", ToText.instance.doSwitch(v)); + } + + @Override + public String caseModel(Model object) { + // target=TargetDecl + // (imports+=Import)* + // (preambles+=Preamble)* + // (reactors+=Reactor)+ + StringBuilder sb = new StringBuilder(); + sb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); + object.getImports().forEach(i -> sb.append(caseImport(i)).append(System.lineSeparator())); + if (!object.getImports().isEmpty()) sb.append(System.lineSeparator()); + object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2))); + if (!object.getPreambles().isEmpty()) sb.append(System.lineSeparator()); + object.getReactors().forEach(r -> sb.append(caseReactor(r)).append(System.lineSeparator().repeat(2))); + return sb.toString(); + } + + @Override + public String caseImport(Import object) { + // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? + return String.format( + "import %s from \"%s\"", + list(object.getReactorClasses(), ", ", "", "", false), + object.getImportURI() + ); + } + + @Override + public String caseReactorDecl(ReactorDecl object) { + // Reactor | ImportedReactor + return defaultCase(object); + } + + @Override + public String caseImportedReactor(ImportedReactor object) { + // reactorClass=[Reactor] ('as' name=ID)? + if (object.getName() != null) { + return String.format("%s as %s", object.getReactorClass().getName(), object.getName()); + } + return object.getReactorClass().getName(); + } + + @Override + public String caseReactor(Reactor object) { + // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) 'reactor' (name=ID)? + // ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? + // ('(' parameters+=Parameter (',' parameters+=Parameter)* ')')? + // ('at' host=Host)? + // ('extends' (superClasses+=[ReactorDecl] (',' superClasses+=[ReactorDecl])*))? + // '{' + // ( (preambles+=Preamble) + // | (stateVars+=StateVar) + // | (methods+=Method) + // | (inputs+=Input) + // | (outputs+=Output) + // | (timers+=Timer) + // | (actions+=Action) + // | (instantiations+=Instantiation) + // | (connections+=Connection) + // | (reactions+=Reaction) + // | (modes+=Mode) + // | (mutations+=Mutation) + // )* '}' + StringBuilder sb = new StringBuilder(); + if (object.isFederated()) sb.append("federated "); + if (object.isMain()) sb.append("main "); + if (object.isRealtime()) sb.append("realtime "); + sb.append("reactor"); + if (object.getName() != null) sb.append(" ").append(object.getName()); + sb.append(list(object.getTypeParms(), ", ", "<", ">", true)); + sb.append(list(object.getParameters())); + if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); + if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { + sb.append(" extends ").append( + object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) + ); + } + sb.append(String.format(" {%n")); + sb.append(indentedStatements(List.of( + object.getPreambles(), + object.getStateVars(), + object.getMethods(), + object.getInputs(), + object.getOutputs(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections(), + object.getReactions(), + object.getModes(), + object.getMutations() + ))); + sb.append(String.format("%n}")); + return sb.toString(); + } + + @Override + public String caseTargetDecl(TargetDecl object) { + // target=TargetDecl + // (imports+=Import)* + // (preambles+=Preamble)* + // (reactors+=Reactor)+ + StringBuilder sb = new StringBuilder(); + sb.append("target ").append(object.getName()); + if (object.getConfig() != null) sb.append(" ").append(doSwitch(object.getConfig())); + return sb.toString(); + } + + @Override + public String caseStateVar(StateVar object) { + // 'state' name=ID ( + // (':' (type=Type))? + // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') + // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') + // )? + // ) ';'? + StringBuilder sb = new StringBuilder(); + sb.append("state ").append(object.getName()); + sb.append(typeAnnotationFor(object.getType())); + if (!object.getParens().isEmpty()) sb.append(list(object.getInit())); + if (!object.getBraces().isEmpty()) sb.append(list(object.getInit(), ", ", "{", "}", true)); + return sb.toString(); + } + + @Override + public String caseMethod(Method object) { + // const?='const'? 'method' name=ID + // '(' (arguments+=MethodArgument (',' arguments+=MethodArgument)*)? ')' + // (':' return=Type)? + // code=Code + // ';'? + StringBuilder sb = new StringBuilder(); + if (object.isConst()) sb.append("const "); + sb.append("method"); + return sb.toString(); + } + + @Override + public String caseMethodArgument(MethodArgument object) { + // name=ID (':' type=Type)? + return object.getName() + typeAnnotationFor(object.getType()); + } + + @Override + public String caseInput(Input object) { + // mutable?='mutable'? 'input' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + if (object.isMutable()) sb.append("mutable "); + sb.append("input"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(" ").append(object.getName()).append(typeAnnotationFor(object.getType())); + return sb.toString(); + } + + @Override + public String caseOutput(Output object) { + // 'output' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + sb.append("output"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(" ").append(object.getName()); + sb.append(typeAnnotationFor(object.getType())); + return sb.toString(); + } + + @Override + public String caseTimer(Timer object) { + // 'timer' name=ID ('(' offset=Expression (',' period=Expression)? ')')? ';'? + StringBuilder sb = new StringBuilder(); + sb.append("timer ").append(object.getName()); + if (object.getOffset() != null) { + sb.append("("); + sb.append(doSwitch(object.getOffset())); + if (object.getPeriod() != null) sb.append(", ").append(doSwitch(object.getPeriod())); + sb.append(")"); + } + return sb.toString(); + } + + @Override + public String caseMode(Mode object) { + // {Mode} (initial?='initial')? 'mode' (name=ID)? + // '{' ( + // (stateVars+=StateVar) | + // (timers+=Timer) | + // (actions+=Action) | + // (instantiations+=Instantiation) | + // (connections+=Connection) | + // (reactions+=Reaction) + // )* '}' + StringBuilder sb = new StringBuilder(); + if (object.isInitial()) sb.append("initial "); + sb.append("mode "); + if (object.getName() != null) sb.append(object.getName()).append(" "); + sb.append(String.format("{%n")); + sb.append(indentedStatements(List.of( + object.getStateVars(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections(), + object.getReactions() + ))); + sb.append("}"); + return sb.toString(); + } + + @Override + public String caseAction(Action object) { + // (origin=ActionOrigin)? 'action' name=ID + // ('(' minDelay=Expression (',' minSpacing=Expression (',' policy=STRING)? )? ')')? + // (':' type=Type)? ';'? + StringBuilder sb = new StringBuilder(); + if (object.getOrigin() != null) sb.append(object.getOrigin().getLiteral()).append(" "); + sb.append("action "); + sb.append(object.getName()); + if (object.getMinDelay() != null) { + sb.append("(").append(doSwitch(object.getMinDelay())); + if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); + if (object.getPolicy() != null) sb.append(", \"").append(object.getPolicy()).append("\""); + sb.append(")"); + } + sb.append(typeAnnotationFor(object.getType())); + return sb.toString(); + } + + @Override + public String caseReaction(Reaction object) { + // ('reaction') + // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? + // (sources+=VarRef (',' sources+=VarRef)*)? + // ('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)? + // code=Code + // (stp=STP)? + // (deadline=Deadline)? + StringBuilder sb = new StringBuilder(); + sb.append("reaction"); + sb.append(list(object.getTriggers())); + sb.append(list(object.getSources(), ", ", " ", "", true)); + if (!object.getEffects().isEmpty()) { + sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + } + sb.append(" ").append(doSwitch(object.getCode())); + if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); + if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); + return sb.toString(); + } + + @Override + public String caseTriggerRef(TriggerRef object) { + // VarRef | startup?='startup' | shutdown?='shutdown' + if (object.isStartup()) return "startup"; + if (object.isShutdown()) return "shutdown"; + throw new IllegalArgumentException("The given TriggerRef object appears to be a VarRef."); + } + + @Override + public String caseDeadline(Deadline object) { + // 'deadline' '(' delay=Expression ')' code=Code + return String.format("deadline(%s) %s", doSwitch(object.getDelay()), doSwitch(object.getCode())); + } + + @Override + public String caseSTP(STP object) { + // 'STP' '(' value=Expression ')' code=Code + return String.format("STP(%s) %s", doSwitch(object.getValue()), doSwitch(object.getCode())); + } + + @Override + public String caseMutation(Mutation object) { + // ('mutation') + // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? + // (sources+=VarRef (',' sources+=VarRef)*)? + // ('->' effects+=[VarRef] (',' effects+=[VarRef])*)? + // code=Code + StringBuilder sb = new StringBuilder(); + sb.append("mutation"); + if (!object.getTriggers().isEmpty()) { + sb.append(object.getTriggers().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "(", ")")) + ); + } + return sb.toString(); + } + + @Override + public String casePreamble(Preamble object) { + // (visibility=Visibility)? 'preamble' code=Code + return String.format( + "%spreamble %s", + object.getVisibility() != null && object.getVisibility() != Visibility.NONE + ? object.getVisibility().getLiteral() + " " : "", + doSwitch(object.getCode()) + ); + } + + @Override + public String caseInstantiation(Instantiation object) { + // name=ID '=' 'new' (widthSpec=WidthSpec)? + // reactorClass=[ReactorDecl] ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? '(' + // (parameters+=Assignment (',' parameters+=Assignment)*)? + // ')' ('at' host=Host)? ';'?; + StringBuilder sb = new StringBuilder(); + sb.append(object.getName()).append(" = new"); + if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); + sb.append(" ").append(object.getReactorClass().getName()); + if (!object.getTypeParms().isEmpty()) { + sb.append(object.getTypeParms().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "<", ">")) + ); + } + sb.append(object.getParameters().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "(", ")")) + ); + // TODO: Delete the following case when the corresponding feature is removed + if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); + return sb.toString(); + } + + @Override + public String caseConnection(Connection object) { + // ((leftPorts += VarRef (',' leftPorts += VarRef)*) + // | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?)) + // ('->' | physical?='~>') + // rightPorts += VarRef (',' rightPorts += VarRef)* + // ('after' delay=Expression)? + // (serializer=Serializer)? + // ';'? + StringBuilder sb = new StringBuilder(); + if (object.isIterated()) sb.append("("); + sb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + if (object.isIterated()) sb.append(")+"); + sb.append(object.isPhysical() ? " ~> " : " -> "); + sb.append(object.getRightPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); + if (object.getDelay() != null) sb.append(" after ").append(doSwitch(object.getDelay())); + if (object.getSerializer() != null) sb.append(" ").append(doSwitch(object.getSerializer())); + return sb.toString(); + } + + @Override + public String caseSerializer(Serializer object) { + // 'serializer' type=STRING + return String.format("serializer \"%s\"", object.getType()); + } + + @Override + public String caseKeyValuePairs(KeyValuePairs object) { + // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' + return object.getPairs().stream().map(this::doSwitch).collect( + Collectors.joining(String.format(",%n "), String.format("{%n "), String.format("%n}")) + ); + } + + @Override + public String caseKeyValuePair(KeyValuePair object) { + // name=Kebab ':' value=Element + return object.getName() + ": " + doSwitch(object.getValue()); + } + + @Override + public String caseArray(Array object) { + // '[' elements+=Element (',' (elements+=Element))* ','? ']' + return object.getElements().stream().map(this::doSwitch).collect( + Collectors.joining(", ", "[", "]") + ); + } + + @Override + public String caseElement(Element object) { + // keyvalue=KeyValuePairs + // | array=Array + // | literal=Literal + // | (time=INT unit=TimeUnit) + // | id=Path + if (object.getKeyvalue() != null) return doSwitch(object.getKeyvalue()); + if (object.getArray() != null) return doSwitch(object.getArray()); + if (object.getLiteral() != null) return object.getLiteral(); + if (object.getId() != null) return object.getId(); + if (object.getUnit() != null) return String.format("%d %s", object.getTime(), object.getUnit()); + return String.valueOf(object.getTime()); + } + + @Override + public String caseTypedVariable(TypedVariable object) { + // Port | Action + return defaultCase(object); + } + + @Override + public String caseVariable(Variable object) { + // TypedVariable | Timer | Mode + return defaultCase(object); + } + + @Override + public String caseAssignment(Assignment object) { + // (lhs=[Parameter] ( + // (equals='=' rhs+=Expression) + // | ((equals='=')? ( + // parens+='(' (rhs+=Expression (',' rhs+=Expression)*)? parens+=')' + // | braces+='{' (rhs+=Expression (',' rhs+=Expression)*)? braces+='}')) + // )); + StringBuilder sb = new StringBuilder(); + sb.append(object.getLhs().getName()); + if (object.getEquals() != null) sb.append(" = "); + if (!object.getParens().isEmpty()) sb.append("("); + if (!object.getBraces().isEmpty()) sb.append("{"); + sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", ", "", ""))); + if (!object.getParens().isEmpty()) sb.append(")"); + if (!object.getBraces().isEmpty()) sb.append("}"); + return sb.toString(); + } + + @Override + public String caseParameter(Parameter object) { + // name=ID (':' (type=Type))? + // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') + // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') + // )? + return object.getName() + typeAnnotationFor(object.getType()) + list( + object.getInit(), + ", ", + object.getBraces().isEmpty() ? "(" : "{", + object.getBraces().isEmpty() ? ")" : "}", + true + ); + } + + @Override + public String caseExpression(Expression object) { + // {Literal} literal = Literal + // | Time + // | ParameterReference + // | Code + return defaultCase(object); + } + + @Override + public String casePort(Port object) { + // Input | Output + return defaultCase(object); + } + + @Override + public String caseWidthSpec(WidthSpec object) { + // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; + if (object.isOfVariableLength()) return "[]"; + return list(object.getTerms(), " + ", "[", "]", false); + } + + @Override + public String caseWidthTerm(WidthTerm object) { + // width=INT + // | parameter=[Parameter] + // | 'widthof(' port=VarRef ')' + // | code=Code; + if (object.getWidth() != 0) { + return Objects.toString(object.getWidth()); + } else if (object.getParameter() != null) { + return object.getParameter().getName(); + } else if (object.getPort() != null) { + return String.format("widthof(%s)", object.getPort()); + } else if (object.getCode() != null) { + return doSwitch(object.getCode()); + } + throw new IllegalArgumentException(); + } + + @Override + public String caseIPV4Host(IPV4Host object) { + // (user=Kebab '@')? addr=IPV4Addr (':' port=INT)? + return caseHost(object); + } + + @Override + public String caseIPV6Host(IPV6Host object) { + // ('[' (user=Kebab '@')? addr=IPV6Addr ']' (':' port=INT)?) + return caseHost(object); + } + + @Override + public String caseNamedHost(NamedHost object) { + // (user=Kebab '@')? addr=HostName (':' port=INT)? + return caseHost(object); + } + + @Override + public String defaultCase(EObject object) { + throw new UnsupportedOperationException(String.format( + "ToText has no case for %s or any of its supertypes, or it does have such a case, but " + + "the return value of that case was null.", + object.getClass().getName() + )); + } + + /** + * Represent the given EList as a string. + * @param delimiter The delimiter separating elements of the list. + * @param prefix The token marking the start of the list. + * @param suffix The token marking the end of the list. + * @param nothingIfEmpty Whether the result should be simplified to the + * empty string as opposed to just the prefix and suffix. + */ + private String list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { + if (nothingIfEmpty && items.isEmpty()) return ""; + return items.stream().map(this::doSwitch).collect(Collectors.joining(delimiter, prefix, suffix)); + } + + private String list(EList items) { + return list(items, ", ", "(", ")", true); + } + + private String typeAnnotationFor(Type type) { + if (type == null) return ""; + return String.format(": %s", doSwitch(type)); + } + + private String indentedStatements(List> statementListList) { + return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( + statementList -> list(statementList, String.format("%n "), " ", "", true) + ).collect(Collectors.joining(System.lineSeparator().repeat(2), "", "")); + } +} diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 0e83c4c043..d25a5253a6 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -1,75 +1,31 @@ package org.lflang.ast; -import java.util.List; -import java.util.Objects; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.ILeafNode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; -import org.lflang.lf.Action; -import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; -import org.lflang.lf.Assignment; import org.lflang.lf.Code; -import org.lflang.lf.Connection; -import org.lflang.lf.Deadline; -import org.lflang.lf.Element; -import org.lflang.lf.Expression; import org.lflang.lf.Host; -import org.lflang.lf.IPV4Host; -import org.lflang.lf.IPV6Host; -import org.lflang.lf.Import; -import org.lflang.lf.ImportedReactor; -import org.lflang.lf.Input; -import org.lflang.lf.Instantiation; -import org.lflang.lf.KeyValuePair; -import org.lflang.lf.KeyValuePairs; import org.lflang.lf.Literal; -import org.lflang.lf.Method; -import org.lflang.lf.MethodArgument; -import org.lflang.lf.Mode; -import org.lflang.lf.Model; -import org.lflang.lf.Mutation; -import org.lflang.lf.NamedHost; -import org.lflang.lf.Output; -import org.lflang.lf.Parameter; import org.lflang.lf.ParameterReference; -import org.lflang.lf.Port; -import org.lflang.lf.Preamble; -import org.lflang.lf.Reaction; -import org.lflang.lf.Reactor; -import org.lflang.lf.ReactorDecl; -import org.lflang.lf.STP; -import org.lflang.lf.Serializer; -import org.lflang.lf.StateVar; -import org.lflang.lf.TargetDecl; import org.lflang.lf.Time; -import org.lflang.lf.Timer; -import org.lflang.lf.TriggerRef; import org.lflang.lf.Type; import org.lflang.lf.TypeParm; -import org.lflang.lf.TypedVariable; import org.lflang.lf.VarRef; -import org.lflang.lf.Variable; -import org.lflang.lf.Visibility; -import org.lflang.lf.WidthSpec; -import org.lflang.lf.WidthTerm; import org.lflang.lf.util.LfSwitch; +import org.lflang.util.StringUtil; /** - * Switch class for converting AST nodes to their textual representation as - * it would appear in LF code. + * Switch class for converting AST nodes to some textual representation that seems likely + * to be useful for as many code generators as possible. */ public class ToText extends LfSwitch { - // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be - // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 - /// public instance initialized when loading the class public static final ToText instance = new ToText(); @@ -78,57 +34,64 @@ public class ToText extends LfSwitch { @Override public String caseArraySpec(ArraySpec spec) { - return (spec.isOfVariableLength()) ? "[]" : "[" + spec.getLength() + "]"; + return ToLf.instance.doSwitch(spec); } @Override public String caseCode(Code code) { - String content = ASTUtils.toOriginalText(code); - if (content.lines().count() > 1) { - return String.format( - "{=%n%s=}", - content.endsWith("\n") || content.endsWith("\r") ? content : content + System.lineSeparator() - ); + ICompositeNode node = NodeModelUtils.getNode(code); + if (node != null) { + StringBuilder builder = new StringBuilder(Math.max(node.getTotalLength(), 1)); + for (ILeafNode leaf : node.getLeafNodes()) { + builder.append(leaf.getText()); + } + String str = builder.toString().trim(); + // Remove the code delimiters (and any surrounding comments). + // This assumes any comment before {= does not include {=. + int start = str.indexOf("{="); + int end = str.indexOf("=}", start); + if (start == -1 || end == -1) { + // Silent failure is needed here because toText is needed to create the intermediate representation, + // which the validator uses. + return str; + } + str = str.substring(start + 2, end); + if (str.split("\n").length > 1) { + // multi line code + return StringUtil.trimCodeBlock(str); + } else { + // single line code + return str.trim(); + } + } else if (code.getBody() != null) { + // Code must have been added as a simple string. + return code.getBody(); } - if (content.contains("#") || content.contains("//")) return String.format("{=%n%s%n=}", content.strip()); - return String.format("{= %s =}", content.strip()); + return ""; } @Override public String caseHost(Host host) { - StringBuilder sb = new StringBuilder(); - if (!StringExtensions.isNullOrEmpty(host.getUser())) { - sb.append(host.getUser()).append("@"); - } - if (!StringExtensions.isNullOrEmpty(host.getAddr())) { - sb.append(host.getAddr()); - } - if (host.getPort() != 0) { - sb.append(":").append(host.getPort()); - } - return sb.toString(); + return ToLf.instance.caseHost(host); } @Override public String caseLiteral(Literal l) { - return l.getLiteral(); + return ToLf.instance.caseLiteral(l); } @Override public String caseParameterReference(ParameterReference p) { - return p.getParameter().getName(); + return ToLf.instance.caseParameterReference(p); } @Override public String caseTime(Time t) { - return ASTUtils.toTimeValue(t).toString(); + return ToLf.instance.caseTime(t); } @Override public String caseType(Type type) { - // time?='time' (arraySpec=ArraySpec)? - // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? - // | code=Code String base = ASTUtils.baseType(type); String arr = (type.getArraySpec() != null) ? doSwitch(type.getArraySpec()) : ""; return base + arr; @@ -136,16 +99,11 @@ public String caseType(Type type) { @Override public String caseTypeParm(TypeParm t) { - // literal=TypeExpr | code=Code - return !StringExtensions.isNullOrEmpty(t.getLiteral()) ? t.getLiteral() : doSwitch(t.getCode()); + return ToLf.instance.caseTypeParm(t); } @Override public String caseVarRef(VarRef v) { - // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] - // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' - // FIXME: This, like the original caseCode implementation, also appears to violate the spec given by the - // docstring. if (v.getContainer() != null) { return String.format("%s.%s", v.getContainer().getName(), v.getVariable().getName()); } else { @@ -153,525 +111,8 @@ public String caseVarRef(VarRef v) { } } - @Override - public String caseModel(Model object) { - // target=TargetDecl - // (imports+=Import)* - // (preambles+=Preamble)* - // (reactors+=Reactor)+ - StringBuilder sb = new StringBuilder(); - sb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); - object.getImports().forEach(i -> sb.append(caseImport(i)).append(System.lineSeparator())); - if (!object.getImports().isEmpty()) sb.append(System.lineSeparator()); - object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2))); - if (!object.getPreambles().isEmpty()) sb.append(System.lineSeparator()); - object.getReactors().forEach(r -> sb.append(caseReactor(r)).append(System.lineSeparator().repeat(2))); - return sb.toString(); - } - - @Override - public String caseImport(Import object) { - // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? - return String.format( - "import %s from \"%s\"", - list(object.getReactorClasses(), ", ", "", "", false), - object.getImportURI() - ); - } - - @Override - public String caseReactorDecl(ReactorDecl object) { - // Reactor | ImportedReactor - return defaultCase(object); - } - - @Override - public String caseImportedReactor(ImportedReactor object) { - // reactorClass=[Reactor] ('as' name=ID)? - if (object.getName() != null) { - return String.format("%s as %s", object.getReactorClass().getName(), object.getName()); - } - return object.getReactorClass().getName(); - } - - @Override - public String caseReactor(Reactor object) { - // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) 'reactor' (name=ID)? - // ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? - // ('(' parameters+=Parameter (',' parameters+=Parameter)* ')')? - // ('at' host=Host)? - // ('extends' (superClasses+=[ReactorDecl] (',' superClasses+=[ReactorDecl])*))? - // '{' - // ( (preambles+=Preamble) - // | (stateVars+=StateVar) - // | (methods+=Method) - // | (inputs+=Input) - // | (outputs+=Output) - // | (timers+=Timer) - // | (actions+=Action) - // | (instantiations+=Instantiation) - // | (connections+=Connection) - // | (reactions+=Reaction) - // | (modes+=Mode) - // | (mutations+=Mutation) - // )* '}' - StringBuilder sb = new StringBuilder(); - if (object.isFederated()) sb.append("federated "); - if (object.isMain()) sb.append("main "); - if (object.isRealtime()) sb.append("realtime "); - sb.append("reactor"); - if (object.getName() != null) sb.append(" ").append(object.getName()); - sb.append(list(object.getTypeParms(), ", ", "<", ">", true)); - sb.append(list(object.getParameters())); - if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); - if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { - sb.append(" extends ").append( - object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) - ); - } - sb.append(String.format(" {%n")); - sb.append(indentedStatements(List.of( - object.getPreambles(), - object.getStateVars(), - object.getMethods(), - object.getInputs(), - object.getOutputs(), - object.getTimers(), - object.getActions(), - object.getInstantiations(), - object.getConnections(), - object.getReactions(), - object.getModes(), - object.getMutations() - ))); - sb.append(String.format("%n}")); - return sb.toString(); - } - - @Override - public String caseTargetDecl(TargetDecl object) { - // target=TargetDecl - // (imports+=Import)* - // (preambles+=Preamble)* - // (reactors+=Reactor)+ - StringBuilder sb = new StringBuilder(); - sb.append("target ").append(object.getName()); - if (object.getConfig() != null) sb.append(" ").append(doSwitch(object.getConfig())); - return sb.toString(); - } - - @Override - public String caseStateVar(StateVar object) { - // 'state' name=ID ( - // (':' (type=Type))? - // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') - // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') - // )? - // ) ';'? - StringBuilder sb = new StringBuilder(); - sb.append("state ").append(object.getName()); - sb.append(typeAnnotationFor(object.getType())); - if (!object.getParens().isEmpty()) sb.append(list(object.getInit())); - if (!object.getBraces().isEmpty()) sb.append(list(object.getInit(), ", ", "{", "}", true)); - return sb.toString(); - } - - @Override - public String caseMethod(Method object) { - // const?='const'? 'method' name=ID - // '(' (arguments+=MethodArgument (',' arguments+=MethodArgument)*)? ')' - // (':' return=Type)? - // code=Code - // ';'? - StringBuilder sb = new StringBuilder(); - if (object.isConst()) sb.append("const "); - sb.append("method"); - return sb.toString(); - } - - @Override - public String caseMethodArgument(MethodArgument object) { - // name=ID (':' type=Type)? - return object.getName() + typeAnnotationFor(object.getType()); - } - - @Override - public String caseInput(Input object) { - // mutable?='mutable'? 'input' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - if (object.isMutable()) sb.append("mutable "); - sb.append("input"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getName()).append(typeAnnotationFor(object.getType())); - return sb.toString(); - } - - @Override - public String caseOutput(Output object) { - // 'output' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - sb.append("output"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getName()); - sb.append(typeAnnotationFor(object.getType())); - return sb.toString(); - } - - @Override - public String caseTimer(Timer object) { - // 'timer' name=ID ('(' offset=Expression (',' period=Expression)? ')')? ';'? - StringBuilder sb = new StringBuilder(); - sb.append("timer ").append(object.getName()); - if (object.getOffset() != null) { - sb.append("("); - sb.append(doSwitch(object.getOffset())); - if (object.getPeriod() != null) sb.append(", ").append(doSwitch(object.getPeriod())); - sb.append(")"); - } - return sb.toString(); - } - - @Override - public String caseMode(Mode object) { - // {Mode} (initial?='initial')? 'mode' (name=ID)? - // '{' ( - // (stateVars+=StateVar) | - // (timers+=Timer) | - // (actions+=Action) | - // (instantiations+=Instantiation) | - // (connections+=Connection) | - // (reactions+=Reaction) - // )* '}' - StringBuilder sb = new StringBuilder(); - if (object.isInitial()) sb.append("initial "); - sb.append("mode "); - if (object.getName() != null) sb.append(object.getName()).append(" "); - sb.append(String.format("{%n")); - sb.append(indentedStatements(List.of( - object.getStateVars(), - object.getTimers(), - object.getActions(), - object.getInstantiations(), - object.getConnections(), - object.getReactions() - ))); - sb.append("}"); - return sb.toString(); - } - - @Override - public String caseAction(Action object) { - // (origin=ActionOrigin)? 'action' name=ID - // ('(' minDelay=Expression (',' minSpacing=Expression (',' policy=STRING)? )? ')')? - // (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - if (object.getOrigin() != null) sb.append(object.getOrigin().getLiteral()).append(" "); - sb.append("action "); - sb.append(object.getName()); - if (object.getMinDelay() != null) { - sb.append("(").append(doSwitch(object.getMinDelay())); - if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); - if (object.getPolicy() != null) sb.append(", \"").append(object.getPolicy()).append("\""); - sb.append(")"); - } - sb.append(typeAnnotationFor(object.getType())); - return sb.toString(); - } - - @Override - public String caseReaction(Reaction object) { - // ('reaction') - // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? - // (sources+=VarRef (',' sources+=VarRef)*)? - // ('->' effects+=VarRefOrModeTransition (',' effects+=VarRefOrModeTransition)*)? - // code=Code - // (stp=STP)? - // (deadline=Deadline)? - StringBuilder sb = new StringBuilder(); - sb.append("reaction"); - sb.append(list(object.getTriggers())); - sb.append(list(object.getSources(), ", ", " ", "", true)); - if (!object.getEffects().isEmpty()) { - sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); - } - sb.append(" ").append(doSwitch(object.getCode())); - if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); - if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); - return sb.toString(); - } - - @Override - public String caseTriggerRef(TriggerRef object) { - // VarRef | startup?='startup' | shutdown?='shutdown' - if (object.isStartup()) return "startup"; - if (object.isShutdown()) return "shutdown"; - throw new IllegalArgumentException("The given TriggerRef object appears to be a VarRef."); - } - - @Override - public String caseDeadline(Deadline object) { - // 'deadline' '(' delay=Expression ')' code=Code - return String.format("deadline(%s) %s", doSwitch(object.getDelay()), doSwitch(object.getCode())); - } - - @Override - public String caseSTP(STP object) { - // 'STP' '(' value=Expression ')' code=Code - return String.format("STP(%s) %s", doSwitch(object.getValue()), doSwitch(object.getCode())); - } - - @Override - public String caseMutation(Mutation object) { - // ('mutation') - // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? - // (sources+=VarRef (',' sources+=VarRef)*)? - // ('->' effects+=[VarRef] (',' effects+=[VarRef])*)? - // code=Code - StringBuilder sb = new StringBuilder(); - sb.append("mutation"); - if (!object.getTriggers().isEmpty()) { - sb.append(object.getTriggers().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "(", ")")) - ); - } - return sb.toString(); - } - - @Override - public String casePreamble(Preamble object) { - // (visibility=Visibility)? 'preamble' code=Code - return String.format( - "%spreamble %s", - object.getVisibility() != null && object.getVisibility() != Visibility.NONE - ? object.getVisibility().getLiteral() + " " : "", - doSwitch(object.getCode()) - ); - } - - @Override - public String caseInstantiation(Instantiation object) { - // name=ID '=' 'new' (widthSpec=WidthSpec)? - // reactorClass=[ReactorDecl] ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? '(' - // (parameters+=Assignment (',' parameters+=Assignment)*)? - // ')' ('at' host=Host)? ';'?; - StringBuilder sb = new StringBuilder(); - sb.append(object.getName()).append(" = new"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getReactorClass().getName()); - if (!object.getTypeParms().isEmpty()) { - sb.append(object.getTypeParms().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "<", ">")) - ); - } - sb.append(object.getParameters().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "(", ")")) - ); - // TODO: Delete the following case when the corresponding feature is removed - if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); - return sb.toString(); - } - - @Override - public String caseConnection(Connection object) { - // ((leftPorts += VarRef (',' leftPorts += VarRef)*) - // | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?)) - // ('->' | physical?='~>') - // rightPorts += VarRef (',' rightPorts += VarRef)* - // ('after' delay=Expression)? - // (serializer=Serializer)? - // ';'? - StringBuilder sb = new StringBuilder(); - if (object.isIterated()) sb.append("("); - sb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); - if (object.isIterated()) sb.append(")+"); - sb.append(object.isPhysical() ? " ~> " : " -> "); - sb.append(object.getRightPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); - if (object.getDelay() != null) sb.append(" after ").append(doSwitch(object.getDelay())); - if (object.getSerializer() != null) sb.append(" ").append(doSwitch(object.getSerializer())); - return sb.toString(); - } - - @Override - public String caseSerializer(Serializer object) { - // 'serializer' type=STRING - return String.format("serializer \"%s\"", object.getType()); - } - - @Override - public String caseKeyValuePairs(KeyValuePairs object) { - // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' - return object.getPairs().stream().map(this::doSwitch).collect( - Collectors.joining(String.format(",%n "), String.format("{%n "), String.format("%n}")) - ); - } - - @Override - public String caseKeyValuePair(KeyValuePair object) { - // name=Kebab ':' value=Element - return object.getName() + ": " + doSwitch(object.getValue()); - } - - @Override - public String caseArray(Array object) { - // '[' elements+=Element (',' (elements+=Element))* ','? ']' - return object.getElements().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "[", "]") - ); - } - - @Override - public String caseElement(Element object) { - // keyvalue=KeyValuePairs - // | array=Array - // | literal=Literal - // | (time=INT unit=TimeUnit) - // | id=Path - if (object.getKeyvalue() != null) return doSwitch(object.getKeyvalue()); - if (object.getArray() != null) return doSwitch(object.getArray()); - if (object.getLiteral() != null) return object.getLiteral(); - if (object.getId() != null) return object.getId(); - if (object.getUnit() != null) return String.format("%d %s", object.getTime(), object.getUnit()); - return String.valueOf(object.getTime()); - } - - @Override - public String caseTypedVariable(TypedVariable object) { - // Port | Action - return defaultCase(object); - } - - @Override - public String caseVariable(Variable object) { - // TypedVariable | Timer | Mode - return defaultCase(object); - } - - @Override - public String caseAssignment(Assignment object) { - // (lhs=[Parameter] ( - // (equals='=' rhs+=Expression) - // | ((equals='=')? ( - // parens+='(' (rhs+=Expression (',' rhs+=Expression)*)? parens+=')' - // | braces+='{' (rhs+=Expression (',' rhs+=Expression)*)? braces+='}')) - // )); - StringBuilder sb = new StringBuilder(); - sb.append(object.getLhs().getName()); - if (object.getEquals() != null) sb.append(" = "); - if (!object.getParens().isEmpty()) sb.append("("); - if (!object.getBraces().isEmpty()) sb.append("{"); - sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", ", "", ""))); - if (!object.getParens().isEmpty()) sb.append(")"); - if (!object.getBraces().isEmpty()) sb.append("}"); - return sb.toString(); - } - - @Override - public String caseParameter(Parameter object) { - // name=ID (':' (type=Type))? - // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') - // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') - // )? - return object.getName() + typeAnnotationFor(object.getType()) + list( - object.getInit(), - ", ", - object.getBraces().isEmpty() ? "(" : "{", - object.getBraces().isEmpty() ? ")" : "}", - true - ); - } - - @Override - public String caseExpression(Expression object) { - // {Literal} literal = Literal - // | Time - // | ParameterReference - // | Code - return defaultCase(object); - } - - @Override - public String casePort(Port object) { - // Input | Output - return defaultCase(object); - } - - @Override - public String caseWidthSpec(WidthSpec object) { - // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; - if (object.isOfVariableLength()) return "[]"; - return list(object.getTerms(), " + ", "[", "]", false); - } - - @Override - public String caseWidthTerm(WidthTerm object) { - // width=INT - // | parameter=[Parameter] - // | 'widthof(' port=VarRef ')' - // | code=Code; - if (object.getWidth() != 0) { - return Objects.toString(object.getWidth()); - } else if (object.getParameter() != null) { - return object.getParameter().getName(); - } else if (object.getPort() != null) { - return String.format("widthof(%s)", object.getPort()); - } else if (object.getCode() != null) { - return doSwitch(object.getCode()); - } - throw new IllegalArgumentException(); - } - - @Override - public String caseIPV4Host(IPV4Host object) { - // (user=Kebab '@')? addr=IPV4Addr (':' port=INT)? - return caseHost(object); - } - - @Override - public String caseIPV6Host(IPV6Host object) { - // ('[' (user=Kebab '@')? addr=IPV6Addr ']' (':' port=INT)?) - return caseHost(object); - } - - @Override - public String caseNamedHost(NamedHost object) { - // (user=Kebab '@')? addr=HostName (':' port=INT)? - return caseHost(object); - } - @Override public String defaultCase(EObject object) { - throw new UnsupportedOperationException(String.format( - "ToText has no case for %s or any of its supertypes, or it does have such a case, but " - + "the return value of that case was null.", - object.getClass().getName() - )); - } - - /** - * Represent the given EList as a string. - * @param delimiter The delimiter separating elements of the list. - * @param prefix The token marking the start of the list. - * @param suffix The token marking the end of the list. - * @param nothingIfEmpty Whether the result should be simplified to the - * empty string as opposed to just the prefix and suffix. - */ - private String list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { - if (nothingIfEmpty && items.isEmpty()) return ""; - return items.stream().map(this::doSwitch).collect(Collectors.joining(delimiter, prefix, suffix)); - } - - private String list(EList items) { - return list(items, ", ", "(", ")", true); - } - - private String typeAnnotationFor(Type type) { - if (type == null) return ""; - return String.format(": %s", doSwitch(type)); - } - - private String indentedStatements(List> statementListList) { - return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( - statementList -> list(statementList, String.format("%n "), " ", "", true) - ).collect(Collectors.joining(System.lineSeparator().repeat(2), "", "")); + throw new UnsupportedOperationException("ToText has no case for " + object.getClass().getName()); } } From fa0de9d557a53cfa70baee082cfb40505522f7ea Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 11 Jun 2022 16:33:13 -0700 Subject: [PATCH 014/130] [fed] Pretty-printer passes sanity checks. All tests compile after being parsed and regurgitated. --- org.lflang/src/org/lflang/ast/ToLf.java | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 2fe23257d7..f2b734b332 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -128,9 +128,19 @@ public String caseType(Type type) { // time?='time' (arraySpec=ArraySpec)? // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? // | code=Code - String base = ASTUtils.baseType(type); - String arr = (type.getArraySpec() != null) ? doSwitch(type.getArraySpec()) : ""; - return base + arr; + if (type.getCode() != null) return doSwitch(type.getCode()); + StringBuilder sb = new StringBuilder(); + if (type.isTime()) { + sb.append("time"); + } else if (type.getId() != null) { + sb.append(type.getId()); + if (type.getTypeParms() != null) { + sb.append(list(type.getTypeParms(), ", ", "<", ">", true)); + } + sb.append("*".repeat(type.getStars().size())); + } + if (type.getArraySpec() != null) sb.append(doSwitch(type.getArraySpec())); + return sb.toString(); } @Override @@ -279,7 +289,9 @@ public String caseMethod(Method object) { // ';'? StringBuilder sb = new StringBuilder(); if (object.isConst()) sb.append("const "); - sb.append("method"); + sb.append("method ").append(object.getName()); + sb.append(list(object.getArguments(), ", ", "(", ")", false)); + sb.append(typeAnnotationFor(object.getReturn())).append(" ").append(doSwitch(object.getCode())); return sb.toString(); } From c3a0237f1842997e6f12cf89d272c34f3f716cb9 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 11 Jun 2022 17:38:37 -0700 Subject: [PATCH 015/130] [fed] Pretty-printer: cosmetic changes. Horizontal whitespace, vertical whitespace, removal of empty target config. --- org.lflang/src/org/lflang/ast/ToLf.java | 119 +++++++++++++++++------- 1 file changed, 83 insertions(+), 36 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index f2b734b332..e2b1acb31b 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -66,6 +66,9 @@ */ public class ToLf extends LfSwitch { + /** The number of spaces to prepend to a line per indentation level. */ + private static final int INDENTATION = 4; + // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 @@ -83,13 +86,9 @@ public String caseArraySpec(ArraySpec spec) { @Override public String caseCode(Code code) { String content = ToText.instance.doSwitch(code); - if (content.lines().count() > 1) { - return String.format( - "{=%n%s=}", - content.endsWith("\n") || content.endsWith("\r") ? content : content + System.lineSeparator() - ); + if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { + return String.format("{=%n%s=}", content.strip().indent(INDENTATION)); } - if (content.contains("#") || content.contains("//")) return String.format("{=%n%s%n=}", content.strip()); return String.format("{= %s =}", content.strip()); } @@ -167,9 +166,14 @@ public String caseModel(Model object) { sb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); object.getImports().forEach(i -> sb.append(caseImport(i)).append(System.lineSeparator())); if (!object.getImports().isEmpty()) sb.append(System.lineSeparator()); - object.getPreambles().forEach(p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2))); + object.getPreambles().forEach( + p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2)) + ); if (!object.getPreambles().isEmpty()) sb.append(System.lineSeparator()); - object.getReactors().forEach(r -> sb.append(caseReactor(r)).append(System.lineSeparator().repeat(2))); + sb.append( + object.getReactors().stream().map(this::doSwitch) + .collect(Collectors.joining(System.lineSeparator().repeat(2))) + ).append(System.lineSeparator()); return sb.toString(); } @@ -219,6 +223,39 @@ public String caseReactor(Reactor object) { // | (modes+=Mode) // | (mutations+=Mutation) // )* '}' + StringBuilder sb = new StringBuilder(); + sb.append(reactorHeader(object)); + String smallFeatures = indentedStatements( + List.of( + object.getPreambles(), + object.getInputs(), + object.getOutputs(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections(), + object.getStateVars() + ), + 0 + ); + String bigFeatures = indentedStatements( + List.of( + object.getReactions(), + object.getMethods(), + object.getMutations(), + object.getModes() + ), + 1 + ); + sb.append(smallFeatures); + if (!smallFeatures.isBlank() && !bigFeatures.isBlank()) sb.append(System.lineSeparator()); + sb.append(bigFeatures); + sb.append("}"); + return sb.toString(); + } + + /** Return the signature of the given reactor. */ + private String reactorHeader(Reactor object) { StringBuilder sb = new StringBuilder(); if (object.isFederated()) sb.append("federated "); if (object.isMain()) sb.append("main "); @@ -234,21 +271,6 @@ public String caseReactor(Reactor object) { ); } sb.append(String.format(" {%n")); - sb.append(indentedStatements(List.of( - object.getPreambles(), - object.getStateVars(), - object.getMethods(), - object.getInputs(), - object.getOutputs(), - object.getTimers(), - object.getActions(), - object.getInstantiations(), - object.getConnections(), - object.getReactions(), - object.getModes(), - object.getMutations() - ))); - sb.append(String.format("%n}")); return sb.toString(); } @@ -353,14 +375,20 @@ public String caseMode(Mode object) { sb.append("mode "); if (object.getName() != null) sb.append(object.getName()).append(" "); sb.append(String.format("{%n")); - sb.append(indentedStatements(List.of( - object.getStateVars(), - object.getTimers(), - object.getActions(), - object.getInstantiations(), - object.getConnections(), - object.getReactions() - ))); + sb.append(indentedStatements( + List.of( + object.getStateVars(), + object.getTimers(), + object.getActions(), + object.getInstantiations(), + object.getConnections() + ), + 0 + )); + sb.append(indentedStatements( + List.of(object.getReactions()), + 1 + )); sb.append("}"); return sb.toString(); } @@ -506,8 +534,12 @@ public String caseSerializer(Serializer object) { @Override public String caseKeyValuePairs(KeyValuePairs object) { // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' - return object.getPairs().stream().map(this::doSwitch).collect( - Collectors.joining(String.format(",%n "), String.format("{%n "), String.format("%n}")) + return list( + object.getPairs(), + String.format(",%n "), + String.format("{%n "), + String.format("%n}"), + true ); } @@ -675,9 +707,24 @@ private String typeAnnotationFor(Type type) { return String.format(": %s", doSwitch(type)); } - private String indentedStatements(List> statementListList) { + /** + * Represent a list of groups of statements. + * @param statementListList A list of groups of statements. + * @param extraSeparation Additional vertical separation beyond the bare + * minimum, to be inserted between everything. + * @return A string representation of {@code statementListList}. + */ + private String indentedStatements(List> statementListList, int extraSeparation) { return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( - statementList -> list(statementList, String.format("%n "), " ", "", true) - ).collect(Collectors.joining(System.lineSeparator().repeat(2), "", "")); + statementList -> list( + statementList, + System.lineSeparator().repeat(1 + extraSeparation), + "", + "", + true + ) + ).collect( + Collectors.joining(System.lineSeparator().repeat(2 + extraSeparation), "", "") + ).indent(INDENTATION); } } From 527463c368d69695a4cbad4e2808607af2995b07 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 12 Jun 2022 00:55:05 -0700 Subject: [PATCH 016/130] [tests] Partially implement IsEqual for versions of the AST. --- org.lflang/src/org/lflang/ast/IsEqual.java | 480 +++++++++++++++++++++ org.lflang/src/org/lflang/ast/ToLf.java | 5 +- org.lflang/src/org/lflang/ast/ToText.java | 1 - 3 files changed, 481 insertions(+), 5 deletions(-) create mode 100644 org.lflang/src/org/lflang/ast/IsEqual.java diff --git a/org.lflang/src/org/lflang/ast/IsEqual.java b/org.lflang/src/org/lflang/ast/IsEqual.java new file mode 100644 index 0000000000..76ce2cf482 --- /dev/null +++ b/org.lflang/src/org/lflang/ast/IsEqual.java @@ -0,0 +1,480 @@ +package org.lflang.ast; + +import java.util.Objects; +import java.util.function.Function; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EObject; + +import org.lflang.lf.Action; +import org.lflang.lf.Array; +import org.lflang.lf.ArraySpec; +import org.lflang.lf.Assignment; +import org.lflang.lf.Code; +import org.lflang.lf.Connection; +import org.lflang.lf.Deadline; +import org.lflang.lf.Element; +import org.lflang.lf.Expression; +import org.lflang.lf.Host; +import org.lflang.lf.IPV4Host; +import org.lflang.lf.IPV6Host; +import org.lflang.lf.Import; +import org.lflang.lf.ImportedReactor; +import org.lflang.lf.Input; +import org.lflang.lf.Instantiation; +import org.lflang.lf.KeyValuePair; +import org.lflang.lf.KeyValuePairs; +import org.lflang.lf.Literal; +import org.lflang.lf.Method; +import org.lflang.lf.MethodArgument; +import org.lflang.lf.Mode; +import org.lflang.lf.Model; +import org.lflang.lf.Mutation; +import org.lflang.lf.NamedHost; +import org.lflang.lf.Output; +import org.lflang.lf.Parameter; +import org.lflang.lf.ParameterReference; +import org.lflang.lf.Port; +import org.lflang.lf.Preamble; +import org.lflang.lf.Reaction; +import org.lflang.lf.Reactor; +import org.lflang.lf.ReactorDecl; +import org.lflang.lf.STP; +import org.lflang.lf.Serializer; +import org.lflang.lf.StateVar; +import org.lflang.lf.TargetDecl; +import org.lflang.lf.Time; +import org.lflang.lf.Timer; +import org.lflang.lf.TriggerRef; +import org.lflang.lf.Type; +import org.lflang.lf.TypeParm; +import org.lflang.lf.TypedVariable; +import org.lflang.lf.VarRef; +import org.lflang.lf.Variable; +import org.lflang.lf.WidthSpec; +import org.lflang.lf.WidthTerm; +import org.lflang.lf.util.LfSwitch; + +/** + * Switch class that checks if subtrees of the AST are semantically equivalent + * to each other. Return {@code false} if they are not equivalent; return + * {@code true} or {@code false} (but preferably {@code true}) if they are + * equivalent. + */ +public class IsEqual extends LfSwitch { + + private final EObject otherObject; + + public IsEqual(EObject other) { + this.otherObject = other; + } + + @Override + protected Boolean doSwitch(int classifierID, EObject theEObject) { + if (otherObject == theEObject) return true; + return super.doSwitch(classifierID, theEObject); + } + + @Override + public Boolean caseModel(Model object) { + return otherObject instanceof Model other + && new ComparisonMachine<>(object, other) + .equivalent(Model::getTarget) + .listsEqual(Model::getImports) + .listsEqual(Model::getPreambles) + .listsEqual(Model::getReactors).conclusion; + } + + @Override + public Boolean caseImport(Import object) { + return otherObject instanceof Import other + && new ComparisonMachine<>(object, other) + .equalAsObjects(Import::getImportURI) + .listsEqual(Import::getReactorClasses).conclusion; + } + + @Override + public Boolean caseReactorDecl(ReactorDecl object) { + return otherObject instanceof ReactorDecl other + && object.getName().equals(other.getName()); + } + + @Override + public Boolean caseImportedReactor(ImportedReactor object) { + return otherObject instanceof ImportedReactor other + && object.getName().equals(other.getName()) + && new IsEqual(object.getReactorClass()).doSwitch(other.getReactorClass()); + } + + @Override + public Boolean caseReactor(Reactor object) { + return otherObject instanceof Reactor other + && new ComparisonMachine<>(object, other) + .identical(Reactor::isFederated) + .identical(Reactor::isRealtime) + .identical(Reactor::isMain) + .equalAsObjects(Reactor::getName) + .listsEqual(Reactor::getTypeParms) + .listsEqual(Reactor::getParameters) + .equivalent(Reactor::getHost) + .listsEqual(Reactor::getSuperClasses) + .listsEqual(Reactor::getPreambles) + .listsEqual(Reactor::getInputs) + .listsEqual(Reactor::getOutputs) + .listsEqual(Reactor::getTimers) + .listsEqual(Reactor::getActions) + .listsEqual(Reactor::getInstantiations) + .listsEqual(Reactor::getConnections) + .listsEqual(Reactor::getStateVars) + .listsEqual(Reactor::getReactions) + .listsEqual(Reactor::getMethods) + .listsEqual(Reactor::getMutations) + .listsEqual(Reactor::getModes) + .conclusion; + } + + @Override + public Boolean caseTypeParm(TypeParm object) { + return otherObject instanceof TypeParm other + && new ComparisonMachine<>(object, other) + .equalAsObjects(TypeParm::getLiteral) + .equivalent(TypeParm::getCode) + .conclusion; + } + + @Override + public Boolean caseTargetDecl(TargetDecl object) { + return otherObject instanceof TargetDecl other + && new ComparisonMachine<>(object, other) + .equalAsObjects(TargetDecl::getName) + .equivalent(TargetDecl::getConfig) + .conclusion; + } + + @Override + public Boolean caseStateVar(StateVar object) { + return otherObject instanceof StateVar other + && other.getBraces().size() == object.getBraces().size() + && other.getParens().size() == object.getParens().size() + && new ComparisonMachine<>(object, other) + .equalAsObjects(StateVar::getName) + .equalAsObjects(StateVar::getType) + .listsEqual(StateVar::getInit) + .conclusion; + } + + @Override + public Boolean caseMethod(Method object) { + return otherObject instanceof Method other + && new ComparisonMachine<>(object, other) + .identical(Method::isConst) + .equalAsObjects(Method::getName) + .listsEqual(Method::getArguments) + .equivalent(Method::getReturn) + .equivalent(Method::getCode) + .conclusion; + } + + @Override + public Boolean caseMethodArgument(MethodArgument object) { + return otherObject instanceof MethodArgument other + && new ComparisonMachine<>(object, other) + .equalAsObjects(MethodArgument::getName) + .equivalent(MethodArgument::getType) + .conclusion; + } + + @Override + public Boolean caseInput(Input object) { + return otherObject instanceof Input other + && new ComparisonMachine<>(object, other) + .identical(Input::isMutable) + .equivalent(Input::getWidthSpec) + .equivalent(Input::getType) + .conclusion; + } + + @Override + public Boolean caseOutput(Output object) { + return otherObject instanceof Output other + && new ComparisonMachine<>(object, other) + .equivalent(Output::getWidthSpec) + .equalAsObjects(Output::getName) + .equivalent(Output::getType) + .conclusion; + } + + @Override + public Boolean caseTimer(Timer object) { + return otherObject instanceof Timer other + && new ComparisonMachine<>(object, other) + .equalAsObjects(Timer::getName) + .equivalent(Timer::getOffset) + .equivalent(Timer::getPeriod) + .conclusion; + } + + @Override + public Boolean caseMode(Mode object) { + return otherObject instanceof Mode other + && new ComparisonMachine<>(object, other) + .identical(Mode::isInitial) + .equalAsObjects(Mode::getName) + .listsEqual(Mode::getStateVars) + .listsEqual(Mode::getTimers) + .listsEqual(Mode::getActions) + .listsEqual(Mode::getInstantiations) + .listsEqual(Mode::getConnections) + .listsEqual(Mode::getReactions) + .conclusion; + } + + @Override + public Boolean caseAction(Action object) { + return otherObject instanceof Action other + && new ComparisonMachine<>(object, other) + .identical(Action::getOrigin) // This is an enum + .equalAsObjects(Action::getName) + .equivalent(Action::getMinDelay) + .equivalent(Action::getMinSpacing) + .equalAsObjects(Action::getPolicy) + .equivalent(Action::getType) + .conclusion; + } + + @Override + public Boolean caseReaction(Reaction object) { + return otherObject instanceof Reaction other + && new ComparisonMachine<>(object, other) + .listsEqual(Reaction::getTriggers) + .listsEqual(Reaction::getSources) + .listsEqual(Reaction::getEffects) + .equivalent(Reaction::getCode) + .equivalent(Reaction::getStp) + .equivalent(Reaction::getDeadline) + .conclusion; + } + + @Override + public Boolean caseTriggerRef(TriggerRef object) { + if (object instanceof VarRef) { + throw new IllegalArgumentException("caseVarRef should be invoked on" + + " TriggerRefs that are actually VarRefs."); + } + return otherObject instanceof TriggerRef other + && new ComparisonMachine<>(object, other) + .identical(TriggerRef::isStartup) + .identical(TriggerRef::isShutdown) + .conclusion; + } + + @Override + public Boolean caseDeadline(Deadline object) { + return super.caseDeadline(object); + } + + @Override + public Boolean caseSTP(STP object) { + return super.caseSTP(object); + } + + @Override + public Boolean caseMutation(Mutation object) { + return super.caseMutation(object); + } + + @Override + public Boolean casePreamble(Preamble object) { + return super.casePreamble(object); + } + + @Override + public Boolean caseInstantiation(Instantiation object) { + return super.caseInstantiation(object); + } + + @Override + public Boolean caseConnection(Connection object) { + return super.caseConnection(object); + } + + @Override + public Boolean caseSerializer(Serializer object) { + return super.caseSerializer(object); + } + + @Override + public Boolean caseKeyValuePairs(KeyValuePairs object) { + return super.caseKeyValuePairs(object); + } + + @Override + public Boolean caseKeyValuePair(KeyValuePair object) { + return super.caseKeyValuePair(object); + } + + @Override + public Boolean caseArray(Array object) { + return super.caseArray(object); + } + + @Override + public Boolean caseElement(Element object) { + return super.caseElement(object); + } + + @Override + public Boolean caseTypedVariable(TypedVariable object) { + return super.caseTypedVariable(object); + } + + @Override + public Boolean caseVariable(Variable object) { + return super.caseVariable(object); + } + + @Override + public Boolean caseVarRef(VarRef object) { + return super.caseVarRef(object); + } + + @Override + public Boolean caseAssignment(Assignment object) { + return super.caseAssignment(object); + } + + @Override + public Boolean caseParameter(Parameter object) { + return super.caseParameter(object); + } + + @Override + public Boolean caseExpression(Expression object) { + return super.caseExpression(object); + } + + @Override + public Boolean caseParameterReference(ParameterReference object) { + return super.caseParameterReference(object); + } + + @Override + public Boolean caseTime(Time object) { + return super.caseTime(object); + } + + @Override + public Boolean casePort(Port object) { + return super.casePort(object); + } + + @Override + public Boolean caseType(Type object) { + return super.caseType(object); + } + + @Override + public Boolean caseArraySpec(ArraySpec object) { + return super.caseArraySpec(object); + } + + @Override + public Boolean caseWidthSpec(WidthSpec object) { + return super.caseWidthSpec(object); + } + + @Override + public Boolean caseWidthTerm(WidthTerm object) { + return super.caseWidthTerm(object); + } + + @Override + public Boolean caseIPV4Host(IPV4Host object) { + return super.caseIPV4Host(object); + } + + @Override + public Boolean caseIPV6Host(IPV6Host object) { + return super.caseIPV6Host(object); + } + + @Override + public Boolean caseNamedHost(NamedHost object) { + return super.caseNamedHost(object); + } + + @Override + public Boolean caseHost(Host object) { + return super.caseHost(object); + } + + @Override + public Boolean caseCode(Code object) { + return super.caseCode(object); + } + + @Override + public Boolean caseLiteral(Literal object) { + return super.caseLiteral(object); + } + + @Override + public Boolean defaultCase(EObject object) { + return super.defaultCase(object); + } + + /** Fluently compare a pair of parse tree nodes for equivalence. */ + private static class ComparisonMachine { + private final E object; + private final E other; + private boolean conclusion = true; + + ComparisonMachine(E object, E other) { + this.object = object; + this.other = other; + } + + /** Conclude false if the two given ELists are different. Order matters. */ + ComparisonMachine listsEqual(Function> listGetter) { + if (!conclusion) return this; + var list0 = listGetter.apply(object); + var list1 = listGetter.apply(other); + if (list0.size() != list1.size()) { + conclusion = false; + return this; + } + for (int i = 0; i < list0.size(); i++) { + if (!new IsEqual(list0.get(i)).doSwitch(list1.get(i))) { + conclusion = false; + return this; + } + } + return this; + } + + /** + * Conclude false if the two properties are not equal as pointers or + * as primitives. + */ + ComparisonMachine identical(Function propertyGetter) { + if (conclusion) conclusion = propertyGetter.apply(object) == propertyGetter.apply(other); + return this; + } + + /** Conclude false if the two properties are not equal as objects. */ + ComparisonMachine equalAsObjects(Function propertyGetter) { + if (conclusion) conclusion = Objects.equals(propertyGetter.apply(object), propertyGetter.apply(other)); + return this; + } + + /** + * Conclude false if the two properties are not semantically equivalent + * parse nodes. + */ + ComparisonMachine equivalent(Function propertyGetter) { + if (conclusion) conclusion = new IsEqual(propertyGetter.apply(object)) + .doSwitch(propertyGetter.apply(other)); + return this; + } + } +} diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index e2b1acb31b..0b289ae264 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -276,10 +276,7 @@ private String reactorHeader(Reactor object) { @Override public String caseTargetDecl(TargetDecl object) { - // target=TargetDecl - // (imports+=Import)* - // (preambles+=Preamble)* - // (reactors+=Reactor)+ + // 'target' name=ID (config=KeyValuePairs)? ';'? StringBuilder sb = new StringBuilder(); sb.append("target ").append(object.getName()); if (object.getConfig() != null) sb.append(" ").append(doSwitch(object.getConfig())); diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index d25a5253a6..996d463258 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -4,7 +4,6 @@ import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; -import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; import org.lflang.lf.ArraySpec; From 68b4dde12f1c29624d2c658976d067700d454f0c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 12 Jun 2022 16:04:06 -0700 Subject: [PATCH 017/130] [formatting] Bring up to date with master. --- .../lflang/tests/compiler/RoundTripTests.java | 2 +- org.lflang/src/org/lflang/ast/IsEqual.java | 17 ++++++++++------- org.lflang/src/org/lflang/ast/ToLf.java | 15 +++++++++++---- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 44c035e38d..e4ebfd6eac 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -61,7 +61,7 @@ private void run(Path file) throws Exception { resultingModel.eResource().getErrors().forEach(System.err::println); Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); } - checkSemanticallyEquivalent(originalModel, resultingModel); + // checkSemanticallyEquivalent(originalModel, resultingModel); } private Model parse(Path file) { diff --git a/org.lflang/src/org/lflang/ast/IsEqual.java b/org.lflang/src/org/lflang/ast/IsEqual.java index 76ce2cf482..2cb46aac08 100644 --- a/org.lflang/src/org/lflang/ast/IsEqual.java +++ b/org.lflang/src/org/lflang/ast/IsEqual.java @@ -10,6 +10,7 @@ import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; import org.lflang.lf.Assignment; +import org.lflang.lf.BuiltinTriggerRef; import org.lflang.lf.Code; import org.lflang.lf.Connection; import org.lflang.lf.Deadline; @@ -257,14 +258,16 @@ public Boolean caseReaction(Reaction object) { @Override public Boolean caseTriggerRef(TriggerRef object) { - if (object instanceof VarRef) { - throw new IllegalArgumentException("caseVarRef should be invoked on" - + " TriggerRefs that are actually VarRefs."); - } - return otherObject instanceof TriggerRef other + throw new UnsupportedOperationException( + "TriggerRefs are BuiltinTriggerRefs or VarRefs, so the methods " + + "corresponding to those types should be invoked instead."); + } + + @Override + public Boolean caseBuiltinTriggerRef(BuiltinTriggerRef object) { + return otherObject instanceof BuiltinTriggerRef other && new ComparisonMachine<>(object, other) - .identical(TriggerRef::isStartup) - .identical(TriggerRef::isShutdown) + .identical(BuiltinTriggerRef::getType) // This is an enum .conclusion; } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 0b289ae264..986f53c41b 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -14,6 +14,7 @@ import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; import org.lflang.lf.Assignment; +import org.lflang.lf.BuiltinTriggerRef; import org.lflang.lf.Code; import org.lflang.lf.Connection; import org.lflang.lf.Deadline; @@ -433,10 +434,16 @@ public String caseReaction(Reaction object) { @Override public String caseTriggerRef(TriggerRef object) { - // VarRef | startup?='startup' | shutdown?='shutdown' - if (object.isStartup()) return "startup"; - if (object.isShutdown()) return "shutdown"; - throw new IllegalArgumentException("The given TriggerRef object appears to be a VarRef."); + // BuiltinTriggerRef | VarRef + throw new UnsupportedOperationException( + "TriggerRefs are BuiltinTriggerRefs or VarRefs, so the methods " + + "corresponding to those types should be invoked instead."); + } + + @Override + public String caseBuiltinTriggerRef(BuiltinTriggerRef object) { + // type = BuiltinTrigger + return object.getType().getLiteral(); } @Override From ce689349e2d09e5744d993fa6e5590ff58a1d885 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 12 Jun 2022 16:51:04 -0700 Subject: [PATCH 018/130] [formatting] Address Rust test failure. --- org.lflang/src/org/lflang/ast/ToText.java | 1 + 1 file changed, 1 insertion(+) diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 996d463258..2b13e7aea9 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -98,6 +98,7 @@ public String caseType(Type type) { @Override public String caseTypeParm(TypeParm t) { + if (t.getCode() != null) return doSwitch(t); return ToLf.instance.caseTypeParm(t); } From 44f039ded5c73300bc87214d9a50148a3dcd2cc1 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 12 Jun 2022 18:40:33 -0700 Subject: [PATCH 019/130] [formatting] Finish first draft of IsEqual. --- org.lflang/src/org/lflang/ast/IsEqual.java | 361 ++++++++++++++------- org.lflang/src/org/lflang/ast/ToLf.java | 3 + 2 files changed, 248 insertions(+), 116 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/IsEqual.java b/org.lflang/src/org/lflang/ast/IsEqual.java index 2cb46aac08..f70dae8198 100644 --- a/org.lflang/src/org/lflang/ast/IsEqual.java +++ b/org.lflang/src/org/lflang/ast/IsEqual.java @@ -1,7 +1,11 @@ package org.lflang.ast; +import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.function.BiPredicate; import java.util.function.Function; +import java.util.stream.Collectors; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; @@ -78,66 +82,64 @@ protected Boolean doSwitch(int classifierID, EObject theEObject) { @Override public Boolean caseModel(Model object) { - return otherObject instanceof Model other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Model.class) .equivalent(Model::getTarget) - .listsEqual(Model::getImports) - .listsEqual(Model::getPreambles) - .listsEqual(Model::getReactors).conclusion; + .listsEquivalent(Model::getImports) + .listsEquivalent(Model::getPreambles) + .listsEquivalent(Model::getReactors).conclusion; } @Override public Boolean caseImport(Import object) { - return otherObject instanceof Import other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Import.class) .equalAsObjects(Import::getImportURI) - .listsEqual(Import::getReactorClasses).conclusion; + .listsEquivalent(Import::getReactorClasses).conclusion; } @Override public Boolean caseReactorDecl(ReactorDecl object) { - return otherObject instanceof ReactorDecl other - && object.getName().equals(other.getName()); + return new ComparisonMachine<>(object, ReactorDecl.class) + .equalAsObjects(ReactorDecl::getName) + .conclusion; } @Override public Boolean caseImportedReactor(ImportedReactor object) { - return otherObject instanceof ImportedReactor other - && object.getName().equals(other.getName()) - && new IsEqual(object.getReactorClass()).doSwitch(other.getReactorClass()); + return new ComparisonMachine<>(object, ImportedReactor.class) + .equalAsObjects(ImportedReactor::getName) + .equivalent(ImportedReactor::getReactorClass) + .conclusion; } @Override public Boolean caseReactor(Reactor object) { - return otherObject instanceof Reactor other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Reactor.class) .identical(Reactor::isFederated) .identical(Reactor::isRealtime) .identical(Reactor::isMain) .equalAsObjects(Reactor::getName) - .listsEqual(Reactor::getTypeParms) - .listsEqual(Reactor::getParameters) + .listsEquivalent(Reactor::getTypeParms) + .listsEquivalent(Reactor::getParameters) .equivalent(Reactor::getHost) - .listsEqual(Reactor::getSuperClasses) - .listsEqual(Reactor::getPreambles) - .listsEqual(Reactor::getInputs) - .listsEqual(Reactor::getOutputs) - .listsEqual(Reactor::getTimers) - .listsEqual(Reactor::getActions) - .listsEqual(Reactor::getInstantiations) - .listsEqual(Reactor::getConnections) - .listsEqual(Reactor::getStateVars) - .listsEqual(Reactor::getReactions) - .listsEqual(Reactor::getMethods) - .listsEqual(Reactor::getMutations) - .listsEqual(Reactor::getModes) + .listsEquivalent(Reactor::getSuperClasses) + .listsEquivalent(Reactor::getPreambles) + .listsEquivalent(Reactor::getInputs) + .listsEquivalent(Reactor::getOutputs) + .listsEquivalent(Reactor::getTimers) + .listsEquivalent(Reactor::getActions) + .listsEquivalent(Reactor::getInstantiations) + .listsEquivalent(Reactor::getConnections) + .listsEquivalent(Reactor::getStateVars) + .listsEquivalent(Reactor::getReactions) + .listsEquivalent(Reactor::getMethods) + .listsEquivalent(Reactor::getMutations) + .listsEquivalent(Reactor::getModes) .conclusion; } @Override public Boolean caseTypeParm(TypeParm object) { - return otherObject instanceof TypeParm other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, TypeParm.class) .equalAsObjects(TypeParm::getLiteral) .equivalent(TypeParm::getCode) .conclusion; @@ -145,8 +147,7 @@ public Boolean caseTypeParm(TypeParm object) { @Override public Boolean caseTargetDecl(TargetDecl object) { - return otherObject instanceof TargetDecl other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, TargetDecl.class) .equalAsObjects(TargetDecl::getName) .equivalent(TargetDecl::getConfig) .conclusion; @@ -154,23 +155,21 @@ public Boolean caseTargetDecl(TargetDecl object) { @Override public Boolean caseStateVar(StateVar object) { - return otherObject instanceof StateVar other - && other.getBraces().size() == object.getBraces().size() - && other.getParens().size() == object.getParens().size() - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, StateVar.class) + .listsEqualAsObjects(StateVar::getBraces) + .listsEqualAsObjects(StateVar::getParens) .equalAsObjects(StateVar::getName) .equalAsObjects(StateVar::getType) - .listsEqual(StateVar::getInit) + .listsEquivalent(StateVar::getInit) .conclusion; } @Override public Boolean caseMethod(Method object) { - return otherObject instanceof Method other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Method.class) .identical(Method::isConst) .equalAsObjects(Method::getName) - .listsEqual(Method::getArguments) + .listsEquivalent(Method::getArguments) .equivalent(Method::getReturn) .equivalent(Method::getCode) .conclusion; @@ -178,8 +177,7 @@ public Boolean caseMethod(Method object) { @Override public Boolean caseMethodArgument(MethodArgument object) { - return otherObject instanceof MethodArgument other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, MethodArgument.class) .equalAsObjects(MethodArgument::getName) .equivalent(MethodArgument::getType) .conclusion; @@ -187,8 +185,7 @@ public Boolean caseMethodArgument(MethodArgument object) { @Override public Boolean caseInput(Input object) { - return otherObject instanceof Input other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Input.class) .identical(Input::isMutable) .equivalent(Input::getWidthSpec) .equivalent(Input::getType) @@ -197,8 +194,7 @@ public Boolean caseInput(Input object) { @Override public Boolean caseOutput(Output object) { - return otherObject instanceof Output other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Output.class) .equivalent(Output::getWidthSpec) .equalAsObjects(Output::getName) .equivalent(Output::getType) @@ -207,8 +203,7 @@ public Boolean caseOutput(Output object) { @Override public Boolean caseTimer(Timer object) { - return otherObject instanceof Timer other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Timer.class) .equalAsObjects(Timer::getName) .equivalent(Timer::getOffset) .equivalent(Timer::getPeriod) @@ -217,23 +212,21 @@ public Boolean caseTimer(Timer object) { @Override public Boolean caseMode(Mode object) { - return otherObject instanceof Mode other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Mode.class) .identical(Mode::isInitial) .equalAsObjects(Mode::getName) - .listsEqual(Mode::getStateVars) - .listsEqual(Mode::getTimers) - .listsEqual(Mode::getActions) - .listsEqual(Mode::getInstantiations) - .listsEqual(Mode::getConnections) - .listsEqual(Mode::getReactions) + .listsEquivalent(Mode::getStateVars) + .listsEquivalent(Mode::getTimers) + .listsEquivalent(Mode::getActions) + .listsEquivalent(Mode::getInstantiations) + .listsEquivalent(Mode::getConnections) + .listsEquivalent(Mode::getReactions) .conclusion; } @Override public Boolean caseAction(Action object) { - return otherObject instanceof Action other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, Action.class) .identical(Action::getOrigin) // This is an enum .equalAsObjects(Action::getName) .equivalent(Action::getMinDelay) @@ -245,11 +238,10 @@ public Boolean caseAction(Action object) { @Override public Boolean caseReaction(Reaction object) { - return otherObject instanceof Reaction other - && new ComparisonMachine<>(object, other) - .listsEqual(Reaction::getTriggers) - .listsEqual(Reaction::getSources) - .listsEqual(Reaction::getEffects) + return new ComparisonMachine<>(object, Reaction.class) + .listsEquivalent(Reaction::getTriggers) + .listsEquivalent(Reaction::getSources) + .listsEquivalent(Reaction::getEffects) .equivalent(Reaction::getCode) .equivalent(Reaction::getStp) .equivalent(Reaction::getDeadline) @@ -258,167 +250,265 @@ public Boolean caseReaction(Reaction object) { @Override public Boolean caseTriggerRef(TriggerRef object) { - throw new UnsupportedOperationException( - "TriggerRefs are BuiltinTriggerRefs or VarRefs, so the methods " - + "corresponding to those types should be invoked instead."); + throw thereIsAMoreSpecificCase(TriggerRef.class, BuiltinTriggerRef.class, VarRef.class); } @Override public Boolean caseBuiltinTriggerRef(BuiltinTriggerRef object) { - return otherObject instanceof BuiltinTriggerRef other - && new ComparisonMachine<>(object, other) + return new ComparisonMachine<>(object, BuiltinTriggerRef.class) .identical(BuiltinTriggerRef::getType) // This is an enum .conclusion; } @Override public Boolean caseDeadline(Deadline object) { - return super.caseDeadline(object); + return new ComparisonMachine<>(object, Deadline.class) + .equivalent(Deadline::getDelay) + .equivalent(Deadline::getCode) + .conclusion; } @Override public Boolean caseSTP(STP object) { - return super.caseSTP(object); + return new ComparisonMachine<>(object, STP.class) + .equivalent(STP::getValue) + .equivalent(STP::getCode) + .conclusion; } @Override public Boolean caseMutation(Mutation object) { - return super.caseMutation(object); + return new ComparisonMachine<>(object, Mutation.class) + .listsEquivalent(Mutation::getTriggers) + .listsEquivalent(Mutation::getSources) + .listsEquivalent(Mutation::getEffects) + .equivalent(Mutation::getCode) + .conclusion; } @Override public Boolean casePreamble(Preamble object) { - return super.casePreamble(object); + return new ComparisonMachine<>(object, Preamble.class) + .identical(Preamble::getVisibility) // This is an enum + .equivalent(Preamble::getCode) + .conclusion; } @Override public Boolean caseInstantiation(Instantiation object) { - return super.caseInstantiation(object); + return new ComparisonMachine<>(object, Instantiation.class) + .equalAsObjects(Instantiation::getName) + .equivalent(Instantiation::getWidthSpec) + .equivalent(Instantiation::getReactorClass) + .listsEquivalent(Instantiation::getTypeParms) + .listsEquivalent(Instantiation::getParameters) + .equivalent(Instantiation::getHost) + .conclusion; } @Override public Boolean caseConnection(Connection object) { - return super.caseConnection(object); + return new ComparisonMachine<>(object, Connection.class) + .listsEquivalent(Connection::getLeftPorts) + .identical(Connection::isIterated) + .identical(Connection::isPhysical) + .listsEquivalent(Connection::getRightPorts) + .equivalent(Connection::getDelay) + .equivalent(Connection::getSerializer) + .conclusion; } @Override public Boolean caseSerializer(Serializer object) { - return super.caseSerializer(object); + return new ComparisonMachine<>(object, Serializer.class) + .equalAsObjects(Serializer::getType) + .conclusion; } @Override public Boolean caseKeyValuePairs(KeyValuePairs object) { - return super.caseKeyValuePairs(object); + return new ComparisonMachine<>(object, KeyValuePairs.class) + .listsEquivalent(KeyValuePairs::getPairs) + .conclusion; } @Override public Boolean caseKeyValuePair(KeyValuePair object) { - return super.caseKeyValuePair(object); + return new ComparisonMachine<>(object, KeyValuePair.class) + .equalAsObjects(KeyValuePair::getName) + .equivalent(KeyValuePair::getValue) + .conclusion; } @Override public Boolean caseArray(Array object) { - return super.caseArray(object); + return new ComparisonMachine<>(object, Array.class) + .listsEquivalent(Array::getElements) + .conclusion; } @Override public Boolean caseElement(Element object) { - return super.caseElement(object); + return new ComparisonMachine<>(object, Element.class) + .equivalent(Element::getKeyvalue) + .equivalent(Element::getArray) + .equalAsObjects(Element::getLiteral) + .equalAsObjects(Element::getId) + .equalAsObjects(Element::getUnit) + .conclusion; } @Override public Boolean caseTypedVariable(TypedVariable object) { - return super.caseTypedVariable(object); + throw thereIsAMoreSpecificCase(TypedVariable.class, Port.class, Action.class); } @Override public Boolean caseVariable(Variable object) { - return super.caseVariable(object); + throw thereIsAMoreSpecificCase(Variable.class, TypedVariable.class, Timer.class, Mode.class); } @Override public Boolean caseVarRef(VarRef object) { - return super.caseVarRef(object); + return new ComparisonMachine<>(object, VarRef.class) + .equivalent(VarRef::getVariable) + .equivalent(VarRef::getContainer) + .identical(VarRef::isInterleaved) + .conclusion; } @Override public Boolean caseAssignment(Assignment object) { - return super.caseAssignment(object); + return new ComparisonMachine<>(object, Assignment.class) + .equivalent(Assignment::getLhs) + .equalAsObjects(Assignment::getEquals) + .listsEqualAsObjects(Assignment::getBraces) + .listsEqualAsObjects(Assignment::getParens) + .listsEquivalent(Assignment::getRhs) + .conclusion; } @Override public Boolean caseParameter(Parameter object) { - return super.caseParameter(object); + return new ComparisonMachine<>(object, Parameter.class) + .equalAsObjects(Parameter::getName) + .equivalent(Parameter::getType) + .listsEqualAsObjects(Parameter::getParens) + .listsEqualAsObjects(Parameter::getBraces) + .listsEquivalent(Parameter::getInit) + .conclusion; } @Override public Boolean caseExpression(Expression object) { - return super.caseExpression(object); + throw thereIsAMoreSpecificCase( + Expression.class, + Literal.class, + Time.class, + ParameterReference.class, + Code.class + ); } @Override public Boolean caseParameterReference(ParameterReference object) { - return super.caseParameterReference(object); + return new ComparisonMachine<>(object, ParameterReference.class) + .equivalent(ParameterReference::getParameter) + .conclusion; } @Override public Boolean caseTime(Time object) { - return super.caseTime(object); + return new ComparisonMachine<>(object, Time.class) + .identical(Time::getInterval) + .equalAsObjects(Time::getUnit) + .conclusion; } @Override public Boolean casePort(Port object) { - return super.casePort(object); + throw thereIsAMoreSpecificCase(Port.class, Input.class, Output.class); } @Override public Boolean caseType(Type object) { - return super.caseType(object); + return new ComparisonMachine<>(object, Type.class) + .equivalent(Type::getCode) + .identical(Type::isTime) + .equivalent(Type::getArraySpec) + .equalAsObjects(Type::getId) + .listsEquivalent(Type::getTypeParms) + .listsEqualAsObjects(Type::getStars) + .equivalent(Type::getArraySpec) + .equivalent(Type::getCode) + .conclusion; } @Override public Boolean caseArraySpec(ArraySpec object) { - return super.caseArraySpec(object); + return new ComparisonMachine<>(object, ArraySpec.class) + .identical(ArraySpec::isOfVariableLength) + .identical(ArraySpec::getLength) + .conclusion; } @Override public Boolean caseWidthSpec(WidthSpec object) { - return super.caseWidthSpec(object); + return new ComparisonMachine<>(object, WidthSpec.class) + .identical(WidthSpec::isOfVariableLength) + .listsEquivalent(WidthSpec::getTerms) + .conclusion; } @Override public Boolean caseWidthTerm(WidthTerm object) { - return super.caseWidthTerm(object); + return new ComparisonMachine<>(object, WidthTerm.class) + .identical(WidthTerm::getWidth) + .equivalent(WidthTerm::getParameter) + .equivalent(WidthTerm::getPort) + .equivalent(WidthTerm::getCode) + .conclusion; } @Override public Boolean caseIPV4Host(IPV4Host object) { - return super.caseIPV4Host(object); + return caseHost(object); } @Override public Boolean caseIPV6Host(IPV6Host object) { - return super.caseIPV6Host(object); + return caseHost(object); } @Override public Boolean caseNamedHost(NamedHost object) { - return super.caseNamedHost(object); + return caseHost(object); } @Override public Boolean caseHost(Host object) { - return super.caseHost(object); + return new ComparisonMachine<>(object, Host.class) + .equalAsObjects(Host::getUser) + .equalAsObjects(Host::getAddr) + .identical(Host::getPort) + .conclusion; } @Override public Boolean caseCode(Code object) { - return super.caseCode(object); + return new ComparisonMachine<>(object, Code.class) + .equalAsObjectsModulo( + Code::getBody, + ((Function) String::strip).compose(String::stripIndent) + ) + .conclusion; } @Override public Boolean caseLiteral(Literal object) { - return super.caseLiteral(object); + return new ComparisonMachine<>(object, Literal.class) + .equalAsObjects(Literal::getLiteral) + .conclusion; } @Override @@ -426,33 +516,58 @@ public Boolean defaultCase(EObject object) { return super.defaultCase(object); } + @SafeVarargs + private UnsupportedOperationException thereIsAMoreSpecificCase( + Class thisCase, + Class... moreSpecificCases + ) { + return new UnsupportedOperationException(String.format( + "%ss are %s, so the methods " + + "corresponding to those types should be invoked instead.", + thisCase.getName(), + Arrays.stream(moreSpecificCases) + .map(Class::getName) + .map(it -> it + (it.endsWith("s") ? "es" : "s")) + .collect(Collectors.joining(" or ")) + )); + } + /** Fluently compare a pair of parse tree nodes for equivalence. */ - private static class ComparisonMachine { + private class ComparisonMachine { private final E object; private final E other; - private boolean conclusion = true; + private boolean conclusion; - ComparisonMachine(E object, E other) { + ComparisonMachine(E object, Class clz) { this.object = object; - this.other = other; + this.conclusion = clz.isInstance(otherObject); + this.other = conclusion ? clz.cast(otherObject) : null; } /** Conclude false if the two given ELists are different. Order matters. */ - ComparisonMachine listsEqual(Function> listGetter) { - if (!conclusion) return this; - var list0 = listGetter.apply(object); - var list1 = listGetter.apply(other); - if (list0.size() != list1.size()) { - conclusion = false; - return this; - } + ComparisonMachine listsEquivalent(Function> listGetter) { + if (conclusion) conclusion = listsEqualish(listGetter, (T a, T b) -> new IsEqual(a).doSwitch(b)); + return this; + } + + /** Conclude false if the two given Lists are different. Order matters. */ + ComparisonMachine listsEqualAsObjects(Function> listGetter) { + if (conclusion) conclusion = listsEqualish(listGetter, Objects::equals); + return this; + } + + boolean listsEqualish(Function> listGetter, BiPredicate equalish) { + if (!conclusion) return false; + List list0 = listGetter.apply(object); + List list1 = listGetter.apply(other); + if (list0 == list1) return true; // e.g., they are both null + if (list0.size() != list1.size()) return false; for (int i = 0; i < list0.size(); i++) { - if (!new IsEqual(list0.get(i)).doSwitch(list1.get(i))) { - conclusion = false; - return this; + if (!equalish.test(list0.get(i), list1.get(i))) { + return false; } } - return this; + return true; } /** @@ -466,6 +581,20 @@ ComparisonMachine identical(Function propertyGetter) { /** Conclude false if the two properties are not equal as objects. */ ComparisonMachine equalAsObjects(Function propertyGetter) { + return equalAsObjectsModulo(propertyGetter, Function.identity()); + } + + /** Conclude false if the two properties are not equal as objects. */ + ComparisonMachine equalAsObjectsModulo( + Function propertyGetter, + Function projectionToClassRepresentatives + ) { + if (propertyGetter.apply(object) instanceof EObject) { + throw new IllegalArgumentException( + "EObjects should be compared for semantic equivalence, not object equality." + ); + } + propertyGetter = projectionToClassRepresentatives.compose(propertyGetter); if (conclusion) conclusion = Objects.equals(propertyGetter.apply(object), propertyGetter.apply(other)); return this; } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 986f53c41b..7731691ed2 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -110,16 +110,19 @@ public String caseHost(Host host) { @Override public String caseLiteral(Literal l) { + // STRING | CHAR_LIT | SignedFloat | SignedInt | Boolean return l.getLiteral(); } @Override public String caseParameterReference(ParameterReference p) { + // parameter=[Parameter] return p.getParameter().getName(); } @Override public String caseTime(Time t) { + // (interval=INT unit=TimeUnit) return ASTUtils.toTimeValue(t).toString(); } From afe2332b5a59f023e337b1f6ca8c544b7a9f2e80 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 13 Jun 2022 01:24:44 -0700 Subject: [PATCH 020/130] [formatting] IsEqual works. Test passes. --- .../lflang/tests/compiler/RoundTripTests.java | 39 +++---- org.lflang/src/org/lflang/ast/IsEqual.java | 102 +++++++++++------- 2 files changed, 83 insertions(+), 58 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index e4ebfd6eac..56e2b64bfc 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -1,11 +1,12 @@ package org.lflang.tests.compiler; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; import java.nio.file.Path; -import java.util.function.Function; +import java.util.Locale; -import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.resource.XtextResourceSet; @@ -18,6 +19,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.Target; +import org.lflang.ast.IsEqual; import org.lflang.ast.ToLf; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; @@ -37,6 +39,8 @@ public class RoundTripTests { @Inject ParseHelper parser; + private static final String REFORMATTED_FILE_PREFIX = "reformatted_"; + @Test public void roundTripTest() throws Exception { int nonFailures = 0; @@ -52,16 +56,28 @@ public void roundTripTest() throws Exception { private void run(Path file) throws Exception { Model originalModel = parse(file); + System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); String reformattedTestCase = ToLf.instance.doSwitch(originalModel); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); - Model resultingModel = parser.parse(reformattedTestCase, resourceSet); + Model resultingModel = getResultingModel(file, reformattedTestCase); Assertions.assertNotNull(resultingModel); if (!resultingModel.eResource().getErrors().isEmpty()) { resultingModel.eResource().getErrors().forEach(System.err::println); Assertions.assertTrue(resultingModel.eResource().getErrors().isEmpty()); } - // checkSemanticallyEquivalent(originalModel, resultingModel); + Assertions.assertTrue(new IsEqual(originalModel).doSwitch(resultingModel)); + } + + private Model getResultingModel(Path file, String reformattedTestCase) throws FileNotFoundException { + File swap = file.getParent().resolve(file.getFileName().toString() + ".swp").toFile(); + file.toFile().renameTo(swap); // FIXME: renameTo may fail. + try (PrintWriter out = new PrintWriter(file.toFile())) { + out.println(reformattedTestCase); + } + Model resultingModel = parse(file); + swap.renameTo(file.toFile()); + return resultingModel; } private Model parse(Path file) { @@ -72,17 +88,4 @@ private Model parse(Path file) { Resource resource = resourceSet.getResource(URI.createFileURI(file.toFile().getAbsolutePath()), true); return (Model) resource.getContents().get(0); } - - private void checkSemanticallyEquivalent(Model originalModel, Model resultingModel) { - // FIXME: This is a toy implementation. It is no good. - Function, Integer> getSize = contents -> { - int count = 0; - for (; contents.hasNext(); contents.next()) count++; - return count; - }; - Assertions.assertEquals( - getSize.apply(originalModel.eAllContents()), - getSize.apply(resultingModel.eAllContents()) - ); - } } diff --git a/org.lflang/src/org/lflang/ast/IsEqual.java b/org.lflang/src/org/lflang/ast/IsEqual.java index f70dae8198..2c82ca416d 100644 --- a/org.lflang/src/org/lflang/ast/IsEqual.java +++ b/org.lflang/src/org/lflang/ast/IsEqual.java @@ -10,6 +10,7 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import org.lflang.TimeUnit; import org.lflang.lf.Action; import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; @@ -75,9 +76,10 @@ public IsEqual(EObject other) { } @Override - protected Boolean doSwitch(int classifierID, EObject theEObject) { - if (otherObject == theEObject) return true; - return super.doSwitch(classifierID, theEObject); + public Boolean doSwitch(EObject eObject) { + if (otherObject == eObject) return true; + if (eObject == null) return false; + return super.doSwitch(eObject); } @Override @@ -114,9 +116,9 @@ public Boolean caseImportedReactor(ImportedReactor object) { @Override public Boolean caseReactor(Reactor object) { return new ComparisonMachine<>(object, Reactor.class) - .identical(Reactor::isFederated) - .identical(Reactor::isRealtime) - .identical(Reactor::isMain) + .equalAsObjects(Reactor::isFederated) + .equalAsObjects(Reactor::isRealtime) + .equalAsObjects(Reactor::isMain) .equalAsObjects(Reactor::getName) .listsEquivalent(Reactor::getTypeParms) .listsEquivalent(Reactor::getParameters) @@ -149,25 +151,29 @@ public Boolean caseTypeParm(TypeParm object) { public Boolean caseTargetDecl(TargetDecl object) { return new ComparisonMachine<>(object, TargetDecl.class) .equalAsObjects(TargetDecl::getName) - .equivalent(TargetDecl::getConfig) + .equivalentModulo( + TargetDecl::getConfig, + (KeyValuePairs it) -> it != null && it.getPairs().isEmpty() ? null : it + ) .conclusion; } @Override public Boolean caseStateVar(StateVar object) { return new ComparisonMachine<>(object, StateVar.class) - .listsEqualAsObjects(StateVar::getBraces) - .listsEqualAsObjects(StateVar::getParens) .equalAsObjects(StateVar::getName) - .equalAsObjects(StateVar::getType) + .equivalent(StateVar::getType) .listsEquivalent(StateVar::getInit) + // Empty braces or parentheses are semantically equivalent to no init at all. + .listsEqualAsObjects(stateVar -> stateVar.getInit().isEmpty() ? null : stateVar.getBraces()) + .listsEqualAsObjects(stateVar -> stateVar.getInit().isEmpty() ? null : stateVar.getParens()) .conclusion; } @Override public Boolean caseMethod(Method object) { return new ComparisonMachine<>(object, Method.class) - .identical(Method::isConst) + .equalAsObjects(Method::isConst) .equalAsObjects(Method::getName) .listsEquivalent(Method::getArguments) .equivalent(Method::getReturn) @@ -186,7 +192,7 @@ public Boolean caseMethodArgument(MethodArgument object) { @Override public Boolean caseInput(Input object) { return new ComparisonMachine<>(object, Input.class) - .identical(Input::isMutable) + .equalAsObjects(Input::isMutable) .equivalent(Input::getWidthSpec) .equivalent(Input::getType) .conclusion; @@ -213,7 +219,7 @@ public Boolean caseTimer(Timer object) { @Override public Boolean caseMode(Mode object) { return new ComparisonMachine<>(object, Mode.class) - .identical(Mode::isInitial) + .equalAsObjects(Mode::isInitial) .equalAsObjects(Mode::getName) .listsEquivalent(Mode::getStateVars) .listsEquivalent(Mode::getTimers) @@ -227,7 +233,7 @@ public Boolean caseMode(Mode object) { @Override public Boolean caseAction(Action object) { return new ComparisonMachine<>(object, Action.class) - .identical(Action::getOrigin) // This is an enum + .equalAsObjects(Action::getOrigin) // This is an enum .equalAsObjects(Action::getName) .equivalent(Action::getMinDelay) .equivalent(Action::getMinSpacing) @@ -256,7 +262,7 @@ public Boolean caseTriggerRef(TriggerRef object) { @Override public Boolean caseBuiltinTriggerRef(BuiltinTriggerRef object) { return new ComparisonMachine<>(object, BuiltinTriggerRef.class) - .identical(BuiltinTriggerRef::getType) // This is an enum + .equalAsObjects(BuiltinTriggerRef::getType) // This is an enum .conclusion; } @@ -289,7 +295,7 @@ public Boolean caseMutation(Mutation object) { @Override public Boolean casePreamble(Preamble object) { return new ComparisonMachine<>(object, Preamble.class) - .identical(Preamble::getVisibility) // This is an enum + .equalAsObjects(Preamble::getVisibility) // This is an enum .equivalent(Preamble::getCode) .conclusion; } @@ -310,8 +316,8 @@ public Boolean caseInstantiation(Instantiation object) { public Boolean caseConnection(Connection object) { return new ComparisonMachine<>(object, Connection.class) .listsEquivalent(Connection::getLeftPorts) - .identical(Connection::isIterated) - .identical(Connection::isPhysical) + .equalAsObjects(Connection::isIterated) + .equalAsObjects(Connection::isPhysical) .listsEquivalent(Connection::getRightPorts) .equivalent(Connection::getDelay) .equivalent(Connection::getSerializer) @@ -371,9 +377,13 @@ public Boolean caseVariable(Variable object) { @Override public Boolean caseVarRef(VarRef object) { return new ComparisonMachine<>(object, VarRef.class) - .equivalent(VarRef::getVariable) - .equivalent(VarRef::getContainer) - .identical(VarRef::isInterleaved) + // FIXME: The following few lines break infinite recursion, but they are very hacky. There might be a corner + // case that I am not aware of in which this is wrong. It would perhaps be better to detect the infinite + // recursion and handle it safely. + .equalAsObjects(varRef -> varRef.getVariable() instanceof Mode ? null : varRef.getVariable().getName()) + .equivalent(varRef -> varRef.getVariable() instanceof Mode ? null : varRef.getVariable()) + .equalAsObjects(varRef -> varRef.getContainer() == null ? null : varRef.getContainer().getName()) + .equalAsObjects(VarRef::isInterleaved) .conclusion; } @@ -420,8 +430,12 @@ public Boolean caseParameterReference(ParameterReference object) { @Override public Boolean caseTime(Time object) { return new ComparisonMachine<>(object, Time.class) - .identical(Time::getInterval) - .equalAsObjects(Time::getUnit) + .equalAsObjects(Time::getInterval) + .equalAsObjectsModulo( + Time::getUnit, + ((Function) TimeUnit::getCanonicalName) + .compose(TimeUnit::fromName) + ) .conclusion; } @@ -434,7 +448,7 @@ public Boolean casePort(Port object) { public Boolean caseType(Type object) { return new ComparisonMachine<>(object, Type.class) .equivalent(Type::getCode) - .identical(Type::isTime) + .equalAsObjects(Type::isTime) .equivalent(Type::getArraySpec) .equalAsObjects(Type::getId) .listsEquivalent(Type::getTypeParms) @@ -447,15 +461,15 @@ public Boolean caseType(Type object) { @Override public Boolean caseArraySpec(ArraySpec object) { return new ComparisonMachine<>(object, ArraySpec.class) - .identical(ArraySpec::isOfVariableLength) - .identical(ArraySpec::getLength) + .equalAsObjects(ArraySpec::isOfVariableLength) + .equalAsObjects(ArraySpec::getLength) .conclusion; } @Override public Boolean caseWidthSpec(WidthSpec object) { return new ComparisonMachine<>(object, WidthSpec.class) - .identical(WidthSpec::isOfVariableLength) + .equalAsObjects(WidthSpec::isOfVariableLength) .listsEquivalent(WidthSpec::getTerms) .conclusion; } @@ -463,7 +477,7 @@ public Boolean caseWidthSpec(WidthSpec object) { @Override public Boolean caseWidthTerm(WidthTerm object) { return new ComparisonMachine<>(object, WidthTerm.class) - .identical(WidthTerm::getWidth) + .equalAsObjects(WidthTerm::getWidth) .equivalent(WidthTerm::getParameter) .equivalent(WidthTerm::getPort) .equivalent(WidthTerm::getCode) @@ -490,7 +504,7 @@ public Boolean caseHost(Host object) { return new ComparisonMachine<>(object, Host.class) .equalAsObjects(Host::getUser) .equalAsObjects(Host::getAddr) - .identical(Host::getPort) + .equalAsObjects(Host::getPort) .conclusion; } @@ -499,7 +513,7 @@ public Boolean caseCode(Code object) { return new ComparisonMachine<>(object, Code.class) .equalAsObjectsModulo( Code::getBody, - ((Function) String::strip).compose(String::stripIndent) + s -> s == null ? null : s.strip().stripIndent() ) .conclusion; } @@ -570,21 +584,16 @@ boolean listsEqualish(Function> listGetter, BiPredicate return true; } - /** - * Conclude false if the two properties are not equal as pointers or - * as primitives. - */ - ComparisonMachine identical(Function propertyGetter) { - if (conclusion) conclusion = propertyGetter.apply(object) == propertyGetter.apply(other); - return this; - } - /** Conclude false if the two properties are not equal as objects. */ ComparisonMachine equalAsObjects(Function propertyGetter) { return equalAsObjectsModulo(propertyGetter, Function.identity()); } - /** Conclude false if the two properties are not equal as objects. */ + /** + * Conclude false if the two properties are not equal as objects, + * given that {@code projectionToClassRepresentatives} maps each + * object to some semantically equivalent object. + */ ComparisonMachine equalAsObjectsModulo( Function propertyGetter, Function projectionToClassRepresentatives @@ -604,6 +613,19 @@ ComparisonMachine equalAsObjectsModulo( * parse nodes. */ ComparisonMachine equivalent(Function propertyGetter) { + return equivalentModulo(propertyGetter, Function.identity()); + } + + /** + * Conclude false if the two properties are not semantically equivalent + * parse nodes, given that {@code projectionToClassRepresentatives} + * maps each parse node to some semantically equivalent node. + */ + ComparisonMachine equivalentModulo( + Function propertyGetter, + Function projectionToClassRepresentatives + ) { + propertyGetter = projectionToClassRepresentatives.compose(propertyGetter); if (conclusion) conclusion = new IsEqual(propertyGetter.apply(object)) .doSwitch(propertyGetter.apply(other)); return this; From a68fe47cb3ab5fb4c40ecb6d2290002d6ea8d82e Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 13 Jun 2022 09:09:10 -0700 Subject: [PATCH 021/130] [formatting] Bugfix. --- org.lflang.tests/src/org/lflang/tests/TestRegistry.java | 1 - org.lflang/src/org/lflang/ast/ToText.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/TestRegistry.java b/org.lflang.tests/src/org/lflang/tests/TestRegistry.java index 078cf8af85..1bed12bce7 100644 --- a/org.lflang.tests/src/org/lflang/tests/TestRegistry.java +++ b/org.lflang.tests/src/org/lflang/tests/TestRegistry.java @@ -69,7 +69,6 @@ public TestMap() { public Set getTests(Target t, TestCategory c) { return this.map.get(t).get(c); } - } /** diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index 2b13e7aea9..f0b1feed15 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -98,7 +98,7 @@ public String caseType(Type type) { @Override public String caseTypeParm(TypeParm t) { - if (t.getCode() != null) return doSwitch(t); + if (t.getCode() != null) return doSwitch(t.getCode()); return ToLf.instance.caseTypeParm(t); } From 4147eb6e7305abb5dfbe2ec8d245126b2971e125 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Mon, 13 Jun 2022 18:13:27 -0700 Subject: [PATCH 022/130] basic implementation of line wrap for formatter --- .../lflang/tests/compiler/RoundTripTests.java | 1 + org.lflang/src/org/lflang/ast/ToLf.java | 83 ++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 56e2b64bfc..4593f56213 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -58,6 +58,7 @@ private void run(Path file) throws Exception { Model originalModel = parse(file); System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); + ToLf.instance.setLineWrap(30); String reformattedTestCase = ToLf.instance.doSwitch(originalModel); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = getResultingModel(file, reformattedTestCase); diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 7731691ed2..cda7d21047 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -69,6 +69,11 @@ public class ToLf extends LfSwitch { /** The number of spaces to prepend to a line per indentation level. */ private static final int INDENTATION = 4; + + // Number of characters at which to line wrap. + private int lineWrap = 0; + // Current indentation level. + private int indentLvl = 0; // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 @@ -78,6 +83,17 @@ public class ToLf extends LfSwitch { // private constructor private ToLf() { super(); } + + /** + * Sets the line wrap for code generation. + * @param wrap The line wrap. If set to zero, line wrap is disabled. + */ + public void setLineWrap(int wrap) { + if(wrap < 0) { + throw new IllegalArgumentException("Attempt to set line wrap to negative value."); + } + lineWrap = wrap; + } @Override public String caseArraySpec(ArraySpec spec) { @@ -86,7 +102,9 @@ public String caseArraySpec(ArraySpec spec) { @Override public String caseCode(Code code) { - String content = ToText.instance.doSwitch(code); + indentLvl++; + String content = wrapLines(ToText.instance.doSwitch(code)); + indentLvl--; if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { return String.format("{=%n%s=}", content.strip().indent(INDENTATION)); } @@ -178,7 +196,8 @@ public String caseModel(Model object) { object.getReactors().stream().map(this::doSwitch) .collect(Collectors.joining(System.lineSeparator().repeat(2))) ).append(System.lineSeparator()); - return sb.toString(); + // indentLvl should be zero; wrap unindented lines and over-indented lines here + return wrapLines(sb.toString()); } @Override @@ -691,6 +710,55 @@ public String defaultCase(EObject object) { object.getClass().getName() )); } + + /** + * Wraps a multi-line String based on the current state of lineWrap and indentLvl. + * If lineWrap is 0, returns orgString. Otherwise, breaks lines such that if possible, each line has less than + * (lineWrap - (indentLvl * INDENTATION) % lineWrap) characters, only breaking at spaces. + * @param orgString The String to wrap. + * @return The wrapped String. + */ + private String wrapLines(String orgString) { + if (lineWrap == 0) return orgString; + return orgString.lines().map(this::wrapIndividualLine).collect(Collectors.joining(System.lineSeparator())); + } + + /** + * Wraps a single line of String based on the current state of lineWrap and indentLvl. See wrapLines(). + * @param line The line to wrap. + * @return The wrapped line. + */ + private String wrapIndividualLine(String line) { + int wrapLength = lineWrap - (indentLvl * INDENTATION) % lineWrap; + StringBuilder sb = new StringBuilder(); + while (line.length() > wrapLength) { + // try to wrap at space + int index = line.lastIndexOf(' ', wrapLength); + // if unable to find space in limit, extend to the first space we find + if (index == -1) index = line.indexOf(' ', wrapLength); + if (index != -1 && line.substring(0, index).isBlank()) { + // never break out an all-whitespace line unless it is longer than wrapLength + if(index < wrapLength) { + index = line.indexOf(' ', wrapLength); + } else { + // large indent - don't skip over any space so that indents are consistent + sb.append(line.substring(0, index) + System.lineSeparator()); + line = line.substring(index); + continue; + } + } + if (index != -1) { + sb.append(line.substring(0, index) + System.lineSeparator()); + line = line.substring(index + 1); + } else { + // no spaces remaining at all + sb.append(line); + line = ""; + } + } + if (line.length() > 0) sb.append(line); + return sb.toString(); + } /** * Represent the given EList as a string. @@ -702,7 +770,11 @@ public String defaultCase(EObject object) { */ private String list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { if (nothingIfEmpty && items.isEmpty()) return ""; - return items.stream().map(this::doSwitch).collect(Collectors.joining(delimiter, prefix, suffix)); + return items.stream().map(this::wrapped).collect(Collectors.joining(delimiter, prefix, suffix)); + } + + private String wrapped(E item) { + return wrapLines(doSwitch(item)); } private String list(EList items) { @@ -722,7 +794,8 @@ private String typeAnnotationFor(Type type) { * @return A string representation of {@code statementListList}. */ private String indentedStatements(List> statementListList, int extraSeparation) { - return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( + indentLvl++; + String ret = statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( statementList -> list( statementList, System.lineSeparator().repeat(1 + extraSeparation), @@ -733,5 +806,7 @@ private String indentedStatements(List> statementListLi ).collect( Collectors.joining(System.lineSeparator().repeat(2 + extraSeparation), "", "") ).indent(INDENTATION); + indentLvl--; + return ret; } } From eb92906fc1f2cb9808a568082e90199c758fc64e Mon Sep 17 00:00:00 2001 From: billy-bao Date: Mon, 13 Jun 2022 21:59:38 -0700 Subject: [PATCH 023/130] update docstrings Co-authored-by: Marten Lohstroh --- org.lflang/src/org/lflang/ast/ToLf.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index cda7d21047..a665047c6d 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -712,7 +712,7 @@ public String defaultCase(EObject object) { } /** - * Wraps a multi-line String based on the current state of lineWrap and indentLvl. + * Wrap a multi-line String based on the current state of lineWrap and indentLvl. * If lineWrap is 0, returns orgString. Otherwise, breaks lines such that if possible, each line has less than * (lineWrap - (indentLvl * INDENTATION) % lineWrap) characters, only breaking at spaces. * @param orgString The String to wrap. @@ -724,7 +724,7 @@ private String wrapLines(String orgString) { } /** - * Wraps a single line of String based on the current state of lineWrap and indentLvl. See wrapLines(). + * Wrap a single line of String based on the current state of lineWrap and indentLvl. See wrapLines(). * @param line The line to wrap. * @return The wrapped line. */ From 8973b118ff064903e6f4c5af369a2a5f2a0bbf1c Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 16:10:22 -0700 Subject: [PATCH 024/130] Rename org.lflang.lfc to org.lflang.cli --- {org.lflang.lfc => org.lflang.cli}/build.gradle | 4 ++-- .../src/org/lflang/cli}/LFStandaloneModule.java | 2 +- .../src/org/lflang/cli/Lfc.java | 6 +++--- .../src/org/lflang/cli}/ReportingUtil.kt | 2 +- .../src/org/lflang/cli}/StandaloneErrorReporter.java | 2 +- .../src/org/lflang/cli}/StandaloneIssueAcceptor.java | 2 +- .../kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt | 8 ++++---- .../test/resources/org/lflang/cli}/tests/colors.lf | 0 .../test/resources/org/lflang/cli}/tests/colors.stderr | 0 .../test/resources/org/lflang/cli}/tests/emptyFile.lf | 0 .../test/resources/org/lflang/cli}/tests/emptyFile.stderr | 0 .../test/resources/org/lflang/cli}/tests/issue490.lf | 0 .../test/resources/org/lflang/cli}/tests/issue490.stderr | 0 .../resources/org/lflang/cli}/tests/multilineWarning.lf | 0 .../org/lflang/cli}/tests/multilineWarning.stderr | 0 .../org/lflang/cli}/tests/multilineWarningTooBig.lf | 0 .../org/lflang/cli}/tests/multilineWarningTooBig.stderr | 0 .../test/resources/org/lflang/cli}/tests/simpleWarning.lf | 0 .../resources/org/lflang/cli}/tests/simpleWarning.stderr | 0 .../test/resources/org/lflang/cli}/tests/tabs.lf | 0 .../test/resources/org/lflang/cli}/tests/tabs.stderr | 0 .../resources/org/lflang/cli}/tests/twoLineWarning.lf | 0 .../resources/org/lflang/cli}/tests/twoLineWarning.stderr | 0 settings.gradle | 2 +- 24 files changed, 14 insertions(+), 14 deletions(-) rename {org.lflang.lfc => org.lflang.cli}/build.gradle (95%) rename {org.lflang.lfc/src/org/lflang/lfc => org.lflang.cli/src/org/lflang/cli}/LFStandaloneModule.java (99%) rename org.lflang.lfc/src/org/lflang/lfc/Main.java => org.lflang.cli/src/org/lflang/cli/Lfc.java (99%) rename {org.lflang.lfc/src/org/lflang/lfc => org.lflang.cli/src/org/lflang/cli}/ReportingUtil.kt (99%) rename {org.lflang.lfc/src/org/lflang/lfc => org.lflang.cli/src/org/lflang/cli}/StandaloneErrorReporter.java (99%) rename {org.lflang.lfc/src/org/lflang/lfc => org.lflang.cli/src/org/lflang/cli}/StandaloneIssueAcceptor.java (99%) rename org.lflang.lfc/test/kotlin/org/lflang/lfc/tests/LfIssueReportingTest.kt => org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt (97%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/colors.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/colors.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/emptyFile.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/emptyFile.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/issue490.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/issue490.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/multilineWarning.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/multilineWarning.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/multilineWarningTooBig.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/multilineWarningTooBig.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/simpleWarning.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/simpleWarning.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/tabs.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/tabs.stderr (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/twoLineWarning.lf (100%) rename {org.lflang.lfc/test/resources/org/lflang/lfc => org.lflang.cli/test/resources/org/lflang/cli}/tests/twoLineWarning.stderr (100%) diff --git a/org.lflang.lfc/build.gradle b/org.lflang.cli/build.gradle similarity index 95% rename from org.lflang.lfc/build.gradle rename to org.lflang.cli/build.gradle index 6c26815eca..d60788a5e5 100644 --- a/org.lflang.lfc/build.gradle +++ b/org.lflang.cli/build.gradle @@ -31,7 +31,7 @@ apply plugin: 'com.github.johnrengelman.shadow' task buildLfc() { apply plugin: 'application' apply plugin: 'com.github.johnrengelman.shadow' - mainClassName = 'org.lflang.lfc.Main' + mainClassName = 'org.lflang.cli.Lfc' shadowJar { exclude 'test/*' @@ -57,6 +57,6 @@ task runLfc(type: JavaExec) { description = "Build and run lfc, use --args to pass arguments" group = "application" classpath = sourceSets.main.runtimeClasspath - mainClass = 'org.lflang.lfc.Main' + mainClass = 'org.lflang.cli.Lfc' workingDir = '..' } diff --git a/org.lflang.lfc/src/org/lflang/lfc/LFStandaloneModule.java b/org.lflang.cli/src/org/lflang/cli/LFStandaloneModule.java similarity index 99% rename from org.lflang.lfc/src/org/lflang/lfc/LFStandaloneModule.java rename to org.lflang.cli/src/org/lflang/cli/LFStandaloneModule.java index a26878335d..665efbb90b 100644 --- a/org.lflang.lfc/src/org/lflang/lfc/LFStandaloneModule.java +++ b/org.lflang.cli/src/org/lflang/cli/LFStandaloneModule.java @@ -26,7 +26,7 @@ * generated by Xtext 2.23.0 */ -package org.lflang.lfc; +package org.lflang.cli; import java.util.Objects; diff --git a/org.lflang.lfc/src/org/lflang/lfc/Main.java b/org.lflang.cli/src/org/lflang/cli/Lfc.java similarity index 99% rename from org.lflang.lfc/src/org/lflang/lfc/Main.java rename to org.lflang.cli/src/org/lflang/cli/Lfc.java index e7e44ac747..fa32e39caa 100644 --- a/org.lflang.lfc/src/org/lflang/lfc/Main.java +++ b/org.lflang.cli/src/org/lflang/cli/Lfc.java @@ -2,7 +2,7 @@ * Stand-alone version of the Lingua Franca compiler (lfc). */ -package org.lflang.lfc; +package org.lflang.cli; import java.io.IOException; import java.nio.file.Files; @@ -49,7 +49,7 @@ * @author {Marten Lohstroh } * @author {Christian Menard } */ -public class Main { +public class Lfc { /// current lfc version as printed by --version private static final String VERSION = "0.2.2-SNAPSHOT"; @@ -189,7 +189,7 @@ public static void main(final String[] args) { final Injector injector = new LFStandaloneSetup(new LFRuntimeModule(), new LFStandaloneModule(reporter)) .createInjectorAndDoEMFRegistration(); // Main instance. - final Main main = injector.getInstance(Main.class); + final Lfc main = injector.getInstance(Lfc.class); // Apache Commons Options object configured to according to available CLI arguments. Options options = CLIOption.getOptions(); // CLI arguments parser. diff --git a/org.lflang.lfc/src/org/lflang/lfc/ReportingUtil.kt b/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt similarity index 99% rename from org.lflang.lfc/src/org/lflang/lfc/ReportingUtil.kt rename to org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt index f989dfdae4..77859d9717 100644 --- a/org.lflang.lfc/src/org/lflang/lfc/ReportingUtil.kt +++ b/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt @@ -22,7 +22,7 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.lflang.lfc +package org.lflang.cli import com.google.inject.Inject import com.google.inject.Singleton diff --git a/org.lflang.lfc/src/org/lflang/lfc/StandaloneErrorReporter.java b/org.lflang.cli/src/org/lflang/cli/StandaloneErrorReporter.java similarity index 99% rename from org.lflang.lfc/src/org/lflang/lfc/StandaloneErrorReporter.java rename to org.lflang.cli/src/org/lflang/cli/StandaloneErrorReporter.java index 0893f98d7f..2b4ae6fe46 100644 --- a/org.lflang.lfc/src/org/lflang/lfc/StandaloneErrorReporter.java +++ b/org.lflang.cli/src/org/lflang/cli/StandaloneErrorReporter.java @@ -25,7 +25,7 @@ * POSSIBILITY OF SUCH DAMAGE. ***************/ -package org.lflang.lfc; +package org.lflang.cli; import java.nio.file.Path; diff --git a/org.lflang.lfc/src/org/lflang/lfc/StandaloneIssueAcceptor.java b/org.lflang.cli/src/org/lflang/cli/StandaloneIssueAcceptor.java similarity index 99% rename from org.lflang.lfc/src/org/lflang/lfc/StandaloneIssueAcceptor.java rename to org.lflang.cli/src/org/lflang/cli/StandaloneIssueAcceptor.java index 3e5e3965eb..73ca4bea9e 100644 --- a/org.lflang.lfc/src/org/lflang/lfc/StandaloneIssueAcceptor.java +++ b/org.lflang.cli/src/org/lflang/cli/StandaloneIssueAcceptor.java @@ -1,4 +1,4 @@ -package org.lflang.lfc; +package org.lflang.cli; import java.io.IOException; import java.nio.file.Path; diff --git a/org.lflang.lfc/test/kotlin/org/lflang/lfc/tests/LfIssueReportingTest.kt b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt similarity index 97% rename from org.lflang.lfc/test/kotlin/org/lflang/lfc/tests/LfIssueReportingTest.kt rename to org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt index 8dee00cf03..f781cbb514 100644 --- a/org.lflang.lfc/test/kotlin/org/lflang/lfc/tests/LfIssueReportingTest.kt +++ b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt @@ -21,14 +21,14 @@ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.lflang.lfc.tests +package org.lflang.cli.tests import junit.framework.Assert.assertEquals import junit.framework.AssertionFailedError import org.junit.Test import org.lflang.LFRuntimeModule import org.lflang.LFStandaloneSetup -import org.lflang.lfc.* +import org.lflang.cli.* import java.io.* import java.nio.charset.StandardCharsets import java.nio.file.Files @@ -45,7 +45,7 @@ class SpyPrintStream { } -class LfIssueReportingTest { +class LfcIssueReportingTest { /* Note: when executing these tests in Intellij, I get the following error: @@ -115,7 +115,7 @@ class LfIssueReportingTest { val backend = ReportingBackend(Io(err = stderr.ps), AnsiColors(useColors), 2) val injector = LFStandaloneSetup(LFRuntimeModule(), LFStandaloneModule(backend)) .createInjectorAndDoEMFRegistration() - val main = injector.getInstance(Main::class.java) + val main = injector.getInstance(Lfc::class.java) val packageName = loader.packageName.replace('.', '/') // relative to root of gradle project diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/colors.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/colors.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/colors.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/colors.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/colors.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/colors.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/colors.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/colors.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/emptyFile.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/emptyFile.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/emptyFile.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/emptyFile.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/emptyFile.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/emptyFile.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/emptyFile.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/emptyFile.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/issue490.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/issue490.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/issue490.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/issue490.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/issue490.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/issue490.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/issue490.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/issue490.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarning.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarning.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarning.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarning.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarning.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarning.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarning.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarning.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarningTooBig.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarningTooBig.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarningTooBig.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarningTooBig.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarningTooBig.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarningTooBig.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/multilineWarningTooBig.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/multilineWarningTooBig.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/simpleWarning.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/simpleWarning.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/simpleWarning.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/simpleWarning.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/simpleWarning.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/simpleWarning.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/simpleWarning.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/simpleWarning.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/tabs.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/tabs.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/tabs.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/tabs.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/tabs.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/tabs.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/tabs.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/tabs.stderr diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/twoLineWarning.lf b/org.lflang.cli/test/resources/org/lflang/cli/tests/twoLineWarning.lf similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/twoLineWarning.lf rename to org.lflang.cli/test/resources/org/lflang/cli/tests/twoLineWarning.lf diff --git a/org.lflang.lfc/test/resources/org/lflang/lfc/tests/twoLineWarning.stderr b/org.lflang.cli/test/resources/org/lflang/cli/tests/twoLineWarning.stderr similarity index 100% rename from org.lflang.lfc/test/resources/org/lflang/lfc/tests/twoLineWarning.stderr rename to org.lflang.cli/test/resources/org/lflang/cli/tests/twoLineWarning.stderr diff --git a/settings.gradle b/settings.gradle index c600105b01..3e48c953bb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,3 @@ include 'org.lflang' -include 'org.lflang.lfc' +include 'org.lflang.cli' include 'org.lflang.tests' From 31a1d2c1b799125f85ce532b210cfdaeac7d8c6d Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:09:06 -0700 Subject: [PATCH 025/130] Attempt to update build scripts for lfc --- .github/scripts/package_lfc.sh | 6 +++--- .github/scripts/test-lfc.sh | 2 +- bin/lfc.ps1 | 6 +++--- lib/scripts/build.sh | 2 +- lib/scripts/include.sh | 6 +++--- org.lflang.cli/build.gradle | 1 + org.lflang/src/org/lflang/generator/IntegratedBuilder.java | 2 +- 7 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/scripts/package_lfc.sh b/.github/scripts/package_lfc.sh index 9db50351e2..0ed674b54a 100755 --- a/.github/scripts/package_lfc.sh +++ b/.github/scripts/package_lfc.sh @@ -6,8 +6,8 @@ set -euo pipefail ./gradlew clean buildLfc # find the version number -jar_path="org.lflang.lfc/build/libs/org.lflang.lfc-*-all.jar" -version="$(ls ${jar_path} | xargs -n 1 basename | sed 's/^org.lflang.lfc-\(.*\)-all.jar$/\1/')" +jar_path="org.lflang.cli/build/libs/org.lflang.cli-*-lfc.jar" +version="$(ls ${jar_path} | xargs -n 1 basename | sed 's/^org.lflang.cli-\(.*\)-lfc.jar$/\1/')" # use a different naming convention for nightly build artifacts if [[ "$#" > 0 && "$1" = "nightly" ]]; then @@ -22,7 +22,7 @@ mkdir -p "${outname}/lib/scripts" mkdir -p "${outname}/lib/jars" # move the jar -mv org.lflang.lfc/build/libs/org.lflang.lfc-*-all.jar "${outname}/lib/jars" +mv org.lflang.cli/build/libs/org.lflang.cli-*-lfc.jar "${outname}/lib/jars" # copy the Bash scripts cp -a lib/scripts "${outname}/lib/" diff --git a/.github/scripts/test-lfc.sh b/.github/scripts/test-lfc.sh index d61f708132..822906f925 100755 --- a/.github/scripts/test-lfc.sh +++ b/.github/scripts/test-lfc.sh @@ -3,7 +3,7 @@ # Exit 1 if any command returns with a non-zero exit code. set -euo pipefail -cd $GITHUB_WORKSPACE +# cd $GITHUB_WORKSPACE function test_with_links() { rm -rf foo diff --git a/bin/lfc.ps1 b/bin/lfc.ps1 index 808bb622b3..f4e5187152 100644 --- a/bin/lfc.ps1 +++ b/bin/lfc.ps1 @@ -7,11 +7,11 @@ $base="$PSScriptRoot\.." $java_home = "$Env:JAVA_HOME" $java_cmd = "$java_home\bin\java.exe" -$jarpath_dev="$base\org.lflang.lfc\build\libs\org.lflang.lfc-*-all.jar" -$jarpath_release="$base\lib\jars\org.lflang.lfc-*-all.jar" +$jarpath_dev="$base\org.lflang.cli\build\libs\org.lflang.cli-*-lfc.jar" +$jarpath_release="$base\lib\jars\org.lflang.cli-*-lfc.jar" function Test-Dev { - Test-Path "$base\org.lflang.lfc" -PathType container + Test-Path "$base\org.lflang.cli" -PathType container } function Get-JarPath { diff --git a/lib/scripts/build.sh b/lib/scripts/build.sh index 0191e98f39..6fd54183d2 100755 --- a/lib/scripts/build.sh +++ b/lib/scripts/build.sh @@ -124,7 +124,7 @@ if [ ! -f "${jar_path}" ] || ! "${find_cmd}" "${base}" \ -path "${lfc_src_pkg_path}" \ -prune -o \ -type f \ - -newer "${jar_path}" \ + -newer "${jar_path}" \s -exec false {} +; then # Rebuild. 1>&2 echo "Jar file is missing or out-of-date; starting rebuild..." diff --git a/lib/scripts/include.sh b/lib/scripts/include.sh index 23b39438a8..c8990b0a42 100644 --- a/lib/scripts/include.sh +++ b/lib/scripts/include.sh @@ -21,10 +21,10 @@ set -euo pipefail # Paths (relative to ${base}), which is assumed to have been set. src_pkg_name="org.lflang" src_pkg_path="${base}/${src_pkg_name}" -lfc_src_pkg_name="${src_pkg_name}.lfc" +lfc_src_pkg_name="${src_pkg_name}.cli" lfc_src_pkg_path="${base}/${lfc_src_pkg_name}" -lfc_jar_build_path_pattern="${lfc_src_pkg_name}/build/libs/${lfc_src_pkg_name}-*-all.jar" -lfc_jar_release_path_pattern="lib/jars/${lfc_src_pkg_name}-*-all.jar" +lfc_jar_build_path_pattern="${lfc_src_pkg_name}/build/libs/${lfc_src_pkg_name}-*-lfc.jar" +lfc_jar_release_path_pattern="lib/jars/${lfc_src_pkg_name}-*-lfc.jar" # Enter directory silently (without printing). pushd() { diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index d60788a5e5..c706b3d621 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -34,6 +34,7 @@ task buildLfc() { mainClassName = 'org.lflang.cli.Lfc' shadowJar { + archiveClassifier.set('lfc') exclude 'test/*' minimize() { exclude(dependency('log4j:log4j:.*')) diff --git a/org.lflang/src/org/lflang/generator/IntegratedBuilder.java b/org.lflang/src/org/lflang/generator/IntegratedBuilder.java index f1172cbab9..341b5a029c 100644 --- a/org.lflang/src/org/lflang/generator/IntegratedBuilder.java +++ b/org.lflang/src/org/lflang/generator/IntegratedBuilder.java @@ -79,7 +79,7 @@ public GeneratorResult run( CancelIndicator cancelIndicator ) { // FIXME: A refactoring of the following line is needed. This refactor will affect FileConfig and - // org.lflang.lfc.Main. The issue is that there is duplicated code. + // org.lflang.cli.Lfc. The issue is that there is duplicated code. fileAccess.setOutputPath( FileConfig.findPackageRoot(Path.of(uri.path()), s -> {}).resolve(FileConfig.DEFAULT_SRC_GEN_DIR).toString() ); From 646eae79ce2fa1d86711aa5622007718ff811e27 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:09:30 -0700 Subject: [PATCH 026/130] Update Github CI for lfc --- .github/workflows/cli-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cli-tests.yml b/.github/workflows/cli-tests.yml index 9a16d36aa2..c6342ed464 100644 --- a/.github/workflows/cli-tests.yml +++ b/.github/workflows/cli-tests.yml @@ -15,9 +15,9 @@ jobs: submodules: true - name: Prepare build environment uses: ./.github/actions/prepare-build-env - - name: Run standalone lfc tests + - name: Run standalone cli tests run: | - ./gradlew :org.lflang.lfc:test --stacktrace + ./gradlew :org.lflang.cli:test --stacktrace - name: Test Bash scripts (Linux or macOS only) run: | .github/scripts/test-lfc.sh From 09fe7f16fbf7e1cd25a05621bbadf8854f576f52 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:19:24 -0700 Subject: [PATCH 027/130] Temporarily use the version of CI on this branch instead of master. --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d9ae662d4..5a4c23d73f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,8 +31,9 @@ jobs: needs: cancel # Run tests for the standalone compiler. + # TODO: Change this back to master branch once merged. cli-tests: - uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@master + uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@lfc-to-cli needs: cancel # Run the C benchmark tests. From cae81f95493e0a0722110583a5ca04cfeebac8aa Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:21:32 -0700 Subject: [PATCH 028/130] fix testing change --- .github/scripts/test-lfc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test-lfc.sh b/.github/scripts/test-lfc.sh index 822906f925..d61f708132 100755 --- a/.github/scripts/test-lfc.sh +++ b/.github/scripts/test-lfc.sh @@ -3,7 +3,7 @@ # Exit 1 if any command returns with a non-zero exit code. set -euo pipefail -# cd $GITHUB_WORKSPACE +cd $GITHUB_WORKSPACE function test_with_links() { rm -rf foo From 9acd5388e824fba844e508189a926263f652cadd Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:21:32 -0700 Subject: [PATCH 029/130] fix testing change --- lib/scripts/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/scripts/build.sh b/lib/scripts/build.sh index 6fd54183d2..0191e98f39 100755 --- a/lib/scripts/build.sh +++ b/lib/scripts/build.sh @@ -124,7 +124,7 @@ if [ ! -f "${jar_path}" ] || ! "${find_cmd}" "${base}" \ -path "${lfc_src_pkg_path}" \ -prune -o \ -type f \ - -newer "${jar_path}" \s + -newer "${jar_path}" \ -exec false {} +; then # Rebuild. 1>&2 echo "Jar file is missing or out-of-date; starting rebuild..." From c7937fbc70ae094dd730861e8f9c7d78498402f8 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 15 Jun 2022 17:43:14 -0700 Subject: [PATCH 030/130] rerun CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a4c23d73f..dd19fd6320 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: needs: cancel # Run tests for the standalone compiler. - # TODO: Change this back to master branch once merged. + # TODO: Change this back to master branch once merged! cli-tests: uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@lfc-to-cli needs: cancel From 42f6f69a3bce1066d88e2c34156acada5dbd07de Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Thu, 16 Jun 2022 15:36:45 -0700 Subject: [PATCH 031/130] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd19fd6320..62eea2ce5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: # Run tests for the standalone compiler. # TODO: Change this back to master branch once merged! cli-tests: - uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@lfc-to-cli + uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@master needs: cancel # Run the C benchmark tests. From 7578dc5017ead46e915f5d5494fee23b6d42999a Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Tue, 21 Jun 2022 16:48:41 -0700 Subject: [PATCH 032/130] initial version of lff - command-line options not implemented yet --- org.lflang.cli/build.gradle | 34 +++ org.lflang.cli/src/org/lflang/cli/Lff.java | 302 +++++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 org.lflang.cli/src/org/lflang/cli/Lff.java diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index c706b3d621..1fa2be4c2d 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -61,3 +61,37 @@ task runLfc(type: JavaExec) { mainClass = 'org.lflang.cli.Lfc' workingDir = '..' } + +task buildLff() { + apply plugin: 'application' + apply plugin: 'com.github.johnrengelman.shadow' + mainClassName = 'org.lflang.cli.Lff' + + shadowJar { + archiveClassifier.set('lff') + exclude 'test/*' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' + } + } +} + +buildLff.finalizedBy shadowJar + +task runLff(type: JavaExec) { + // builds and runs lff + // The working directory will be the root directory of the lingua franca project + // CLI arguments can be passed to lff by using --args. Note that you need + // to escape cli flags which start with --.For instance --args ' --help'. + // Otherwise they're parsed as arguments to the Gradle CLI, not lfc. + description = "Build and run lff, use --args to pass arguments" + group = "application" + classpath = sourceSets.main.runtimeClasspath + mainClass = 'org.lflang.cli.Lff' + workingDir = '..' +} \ No newline at end of file diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java new file mode 100644 index 0000000000..54e7f48387 --- /dev/null +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -0,0 +1,302 @@ +/** + * Stand-alone version of the Lingua Franca formatter (lff). + */ + +package org.lflang.cli; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.xtext.diagnostics.Severity; +import org.eclipse.xtext.generator.GeneratorDelegate; +import org.eclipse.xtext.generator.JavaIoFileSystemAccess; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.util.Exceptions; +import org.eclipse.xtext.validation.CheckMode; +import org.eclipse.xtext.validation.IResourceValidator; +import org.eclipse.xtext.validation.Issue; + +import org.lflang.ASTUtils; +import org.lflang.ErrorReporter; +import org.lflang.FileConfig; +import org.lflang.LFRuntimeModule; +import org.lflang.LFStandaloneSetup; +import org.lflang.ast.ToLf; +import org.lflang.generator.LFGeneratorContext; +import org.lflang.generator.MainContext; +import org.lflang.lf.Model; +import org.lflang.util.FileUtil; + +import com.google.inject.Inject; +import com.google.inject.Injector; +import com.google.inject.Provider; + +/** + * Standalone version of the Lingua Franca formatter (lff). + * Based on lfc. + * + * @author {Marten Lohstroh } + * @author {Christian Menard } + * @author {Billy Bao } + */ +public class Lff { + + /// current lff version as printed by --version + private static final String VERSION = "0.2.2-SNAPSHOT"; + + /** + * Object for interpreting command line arguments. + */ + protected CommandLine cmd; + + /** + * Injected resource provider. + */ + @Inject + private Provider resourceSetProvider; + + /** + * Injected resource validator. + */ + @Inject + private IResourceValidator validator; + + /** + * Used to collect all errors that happen during validation/generation. + */ + @Inject + private IssueCollector issueCollector; + + /** + * Used to report error messages at the end. + */ + @Inject + private ReportingBackend reporter; + + + /** + * Supported CLI options. + *

+ * Stores an Apache Commons CLI Option for each entry, sets it to be + * if required if so specified, and stores whether or not to pass the + * option to the code generator. + * + * @author Marten Lohstroh + */ + enum CLIOption { + HELP("h", "help", false, false, "Display this information."), + LINE_WRAP("w", "wrap", true, false, "Causes the formatter to line wrap the files to a specified length."), + NO_RECURSE(null, "no-recurse", false, false, "Do not format files in subdirectories of the specified paths."), + OUTPUT_PATH("o", "output-path", true, false, "If specified, outputs all formatted files into this directory instead of overwriting the original files."), + VERBOSE("v", "verbose", false, false, "Print more details on files affected."), + VERSION(null, "version", false, false, "Print version information."); + + /** + * The corresponding Apache CLI Option object. + */ + public final Option option; + + /** + * Construct a new CLIOption. + * + * @param opt The short option name. E.g.: "f" denotes a flag + * "-f". + * @param longOpt The long option name. E.g.: "foo" denotes a flag + * "--foo". + * @param hasArg Whether or not this option has an argument. E.g.: + * "--foo bar" where "bar" is the argument value. + * @param isReq Whether or not this option is required. If it is + * required but not specified a menu is shown. + * @param description The description used in the menu. + */ + CLIOption(String opt, String longOpt, boolean hasArg, boolean isReq, String description) { + this.option = new Option(opt, longOpt, hasArg, description); + option.setRequired(isReq); + } + + /** + * Create an Apache Commons CLI Options object and add all the options. + * + * @return Options object that includes all the options in this enum. + */ + public static Options getOptions() { + Options opts = new Options(); + Arrays.asList(CLIOption.values()).forEach(o -> opts.addOption(o.option)); + return opts; + } + } + + /** + * Main function of the stand-alone compiler. + * + * @param args CLI arguments + */ + public static void main(final String[] args) { + final ReportingBackend reporter = new ReportingBackend(new Io()); + + // Injector used to obtain Main instance. + final Injector injector = new LFStandaloneSetup(new LFRuntimeModule(), new LFStandaloneModule(reporter)) + .createInjectorAndDoEMFRegistration(); + // Main instance. + final Lff main = injector.getInstance(Lff.class); + // Apache Commons Options object configured to according to available CLI arguments. + Options options = CLIOption.getOptions(); + // CLI arguments parser. + CommandLineParser parser = new DefaultParser(); + // Helper object for printing "help" menu. + HelpFormatter formatter = new HelpFormatter(); + + try { + main.cmd = parser.parse(options, args, true); + + // If requested, print help and abort + if (main.cmd.hasOption(CLIOption.HELP.option.getOpt())) { + formatter.printHelp("lff", options); + System.exit(0); + } + + // If requested, print version and abort + if (main.cmd.hasOption(CLIOption.VERSION.option.getLongOpt())) { + System.out.println("lff " + VERSION); + System.exit(0); + } + + List files = main.cmd.getArgList(); + + if (files.size() < 1) { + reporter.printFatalErrorAndExit("No input files."); + } + try { + List paths = files.stream().map(Paths::get).collect(Collectors.toList()); + main.runFormatter(paths); + } catch (RuntimeException e) { + reporter.printFatalErrorAndExit("An unexpected error occurred:", e); + } + } catch (ParseException e) { + reporter.printFatalError("Unable to parse commandline arguments. Reason: " + e.getMessage()); + formatter.printHelp("lff", options); + System.exit(1); + } + } + + /** + * Load the resource, validate it, and, invoke the formatter. + */ + private void runFormatter(List files) { + String pathOption = CLIOption.OUTPUT_PATH.option.getOpt(); + Path root = null; + if (cmd.hasOption(pathOption)) { + root = Paths.get(cmd.getOptionValue(pathOption)).normalize(); + if (!Files.exists(root)) { // FIXME: Create it instead? + reporter.printFatalErrorAndExit("Output location '" + root + "' does not exist."); + } + if (!Files.isDirectory(root)) { + reporter.printFatalErrorAndExit("Output location '" + root + "' is not a directory."); + } + } + + for (Path path : files) { + if (!Files.exists(path)) { + reporter.printFatalErrorAndExit(path + ": No such file or directory"); + } + } + for (Path path : files) { + path = path.toAbsolutePath(); + final Resource resource = getValidatedResource(path); + Path outputPath = path; + + exitIfCollectedErrors(); + + String res = ToLf.instance.doSwitch(resource.getContents().get(0)); + try { + FileUtil.writeToFile(res, outputPath, true); + } catch (IOException e) { + issueCollector.accept(new LfIssue(e.getMessage(), Severity.ERROR, + null, null, + null, null, + null, path)); + } + + exitIfCollectedErrors(); + // print all other issues (not errors) + issueCollector.getAllIssues().forEach(reporter::printIssue); + + System.out.println("Code formatting finished."); + } + } + + + /** + * If some errors were collected, print them and abort execution. Otherwise return. + */ + private void exitIfCollectedErrors() { + if (issueCollector.getErrorsOccurred() ) { + // if there are errors, don't print warnings. + List errors = printErrorsIfAny(); + String cause = errors.size() == 1 ? "previous error" + : errors.size() + " previous errors"; + reporter.printFatalErrorAndExit("Aborting due to " + cause); + } + } + + // visible in tests + public List printErrorsIfAny() { + List errors = issueCollector.getErrors(); + errors.forEach(reporter::printIssue); + return errors; + } + + /** + * Given a path, obtain a resource and validate it. If issues arise during validation, + * these are recorded using the issue collector. + * + * @param path Path to the resource to validate. + * @return A validated resource + */ + // visible in tests + public Resource getValidatedResource(Path path) { + final Resource resource = getResource(path); + assert resource != null; + + List issues = this.validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); + + for (Issue issue : issues) { + URI uri = issue.getUriToProblem(); // Issues may also relate to imported resources. + try { + issueCollector.accept(new LfIssue(issue.getMessage(), issue.getSeverity(), + issue.getLineNumber(), issue.getColumn(), + issue.getLineNumberEnd(), issue.getColumnEnd(), + issue.getLength(), FileUtil.toPath(uri))); + } catch (IOException e) { + reporter.printError("Unable to convert '" + uri + "' to path." + e); + } + } + return resource; + } + + private Resource getResource(Path path) { + final ResourceSet set = this.resourceSetProvider.get(); + try { + return set.getResource(URI.createFileURI(path.toString()), true); + } catch (RuntimeException e) { + reporter.printFatalErrorAndExit(path + " is not an LF file. Use the .lf file extension to denote LF files."); + return null; + } + } +} From b0b3790495c6e0486a3f7ef0c233621b1e5fda02 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Tue, 21 Jun 2022 17:10:35 -0700 Subject: [PATCH 033/130] update ReportingUtil for both lfc + lff --- org.lflang.cli/src/org/lflang/cli/Lfc.java | 2 +- org.lflang.cli/src/org/lflang/cli/Lff.java | 14 ++------------ org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt | 5 +++-- .../org/lflang/cli/tests/LfcIssueReportingTest.kt | 3 +-- 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/org.lflang.cli/src/org/lflang/cli/Lfc.java b/org.lflang.cli/src/org/lflang/cli/Lfc.java index fa32e39caa..00e9ea3bbd 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lfc.java +++ b/org.lflang.cli/src/org/lflang/cli/Lfc.java @@ -183,7 +183,7 @@ public static List

* Stores an Apache Commons CLI Option for each entry, sets it to be - * if required if so specified, and stores whether or not to pass the + * required if so specified, and stores whether to pass the * option to the code generator. * * @author Marten Lohstroh @@ -148,7 +138,7 @@ public static Options getOptions() { * @param args CLI arguments */ public static void main(final String[] args) { - final ReportingBackend reporter = new ReportingBackend(new Io()); + final ReportingBackend reporter = new ReportingBackend(new Io(), "lff: "); // Injector used to obtain Main instance. final Injector injector = new LFStandaloneSetup(new LFRuntimeModule(), new LFStandaloneModule(reporter)) diff --git a/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt b/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt index 77859d9717..2db16da06d 100644 --- a/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt +++ b/org.lflang.cli/src/org/lflang/cli/ReportingUtil.kt @@ -142,6 +142,8 @@ class IssueCollector { class ReportingBackend constructor( /** Environment of the process, contains IO streams. */ private val io: Io, + /** Header for all messages. */ + private val header: String, /** An instance of the ANSI formatter to use. */ private val colors: AnsiColors, /** @@ -153,11 +155,10 @@ class ReportingBackend constructor( ) { /** Secondary constructor with default arguments and marked with @Inject */ @Inject - constructor(io: Io) : this(io, AnsiColors(true)) + constructor(io: Io, header: String) : this(io, header, AnsiColors(true)) /** *Absolute* path to lines. */ private val fileCache = mutableMapOf?>() - private val header = colors.bold("lfc: ") private fun getLines(path: Path?): List? = if (path == null) null diff --git a/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt index f781cbb514..3c8095a7d6 100644 --- a/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt +++ b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt @@ -34,7 +34,6 @@ import java.nio.charset.StandardCharsets import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths -import java.util.* class SpyPrintStream { @@ -112,7 +111,7 @@ class LfcIssueReportingTest { val stderr = SpyPrintStream() - val backend = ReportingBackend(Io(err = stderr.ps), AnsiColors(useColors), 2) + val backend = ReportingBackend(Io(err = stderr.ps), AnsiColors(useColors).bold("lfc: "), AnsiColors(useColors), 2) val injector = LFStandaloneSetup(LFRuntimeModule(), LFStandaloneModule(backend)) .createInjectorAndDoEMFRegistration() val main = injector.getInstance(Lfc::class.java) From dd83e2e23b73df5b7ee381c04d96824c52483414 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 22 Jun 2022 17:30:19 -0700 Subject: [PATCH 034/130] recursively format subdirectories by default, and implement --no-recurse, -o, -v --- org.lflang.cli/src/org/lflang/cli/Lff.java | 111 +++++++++++++++------ 1 file changed, 83 insertions(+), 28 deletions(-) diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index a9dd4b44a4..dcde777a1f 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -5,6 +5,7 @@ package org.lflang.cli; import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -93,7 +94,8 @@ enum CLIOption { HELP("h", "help", false, false, "Display this information."), LINE_WRAP("w", "wrap", true, false, "Causes the formatter to line wrap the files to a specified length."), NO_RECURSE(null, "no-recurse", false, false, "Do not format files in subdirectories of the specified paths."), - OUTPUT_PATH("o", "output-path", true, false, "If specified, outputs all formatted files into this directory instead of overwriting the original files."), + OUTPUT_PATH("o", "output-path", true, false, "If specified, outputs all formatted files into this directory instead " + + "of overwriting the original files. Subdirectory structure will be preserved."), VERBOSE("v", "verbose", false, false, "Print more details on files affected."), VERSION(null, "version", false, false, "Print version information."); @@ -186,18 +188,18 @@ public static void main(final String[] args) { } /** - * Load the resource, validate it, and, invoke the formatter. + * Checks all given input paths and the output path, then invokes the formatter on all files given. */ private void runFormatter(List files) { String pathOption = CLIOption.OUTPUT_PATH.option.getOpt(); - Path root = null; + Path outputRoot = null; if (cmd.hasOption(pathOption)) { - root = Paths.get(cmd.getOptionValue(pathOption)).normalize(); - if (!Files.exists(root)) { // FIXME: Create it instead? - reporter.printFatalErrorAndExit("Output location '" + root + "' does not exist."); + outputRoot = Paths.get(cmd.getOptionValue(pathOption)).toAbsolutePath().normalize(); + if (!Files.exists(outputRoot)) { // FIXME: Create it instead? + reporter.printFatalErrorAndExit("Output location '" + outputRoot + "' does not exist."); } - if (!Files.isDirectory(root)) { - reporter.printFatalErrorAndExit("Output location '" + root + "' is not a directory."); + if (!Files.isDirectory(outputRoot)) { + reporter.printFatalErrorAndExit("Output location '" + outputRoot + "' is not a directory."); } } @@ -206,32 +208,83 @@ private void runFormatter(List files) { reporter.printFatalErrorAndExit(path + ": No such file or directory"); } } + for (Path path : files) { + if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { + reporter.printInfo("Formatting " + path + ":"); + } path = path.toAbsolutePath(); - final Resource resource = getValidatedResource(path); - Path outputPath = path; - - exitIfCollectedErrors(); + if (Files.isDirectory(path) && !cmd.hasOption(CLIOption.NO_RECURSE.option.getLongOpt())) { + formatRecursive(Paths.get("."), path, outputRoot); + } else { + if (outputRoot == null) { + formatSingleFile(path, path); + } else { + formatSingleFile(path, outputRoot.resolve(path.getFileName())); + } + } + } + reporter.printInfo("Done formatting."); + } - String res = ToLf.instance.doSwitch(resource.getContents().get(0)); - try { - FileUtil.writeToFile(res, outputPath, true); - } catch (IOException e) { - issueCollector.accept(new LfIssue(e.getMessage(), Severity.ERROR, - null, null, - null, null, - null, path)); + /** + * Invokes the formatter on all files in a directory recursively. + * @param curPath Current relative path from inputRoot. + * @param inputRoot Root directory of input files. + * @param outputRoot Root output directory. + */ + private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot) { + Path curDir = inputRoot.resolve(curPath); + try (var dirStream = Files.newDirectoryStream(curDir)) { + for (Path path : dirStream) { + Path newPath = curPath.resolve(path.getFileName()); + if (Files.isDirectory(path)) { + formatRecursive(newPath, inputRoot, outputRoot); + } else { + if (outputRoot == null) { + formatSingleFile(path, path); + } else { + formatSingleFile(path, outputRoot.resolve(newPath)); + } + } } + } catch (IOException e) { + reporter.printError("Error reading directory " + curDir + ": " + e.getMessage()); + } + } + + /** + * Loads and validates a single file, then formats it and outputs to the given outputPath. + */ + private void formatSingleFile(Path file, Path outputPath) { + file = file.normalize(); + outputPath = outputPath.normalize(); + final Resource resource = getValidatedResource(file); + if (resource == null) return; // not an LF file, nothing to do here + + exitIfCollectedErrors(); - exitIfCollectedErrors(); - // print all other issues (not errors) - issueCollector.getAllIssues().forEach(reporter::printIssue); + String res = ToLf.instance.doSwitch(resource.getContents().get(0)); + try { + FileUtil.writeToFile(res, outputPath, true); + } catch (IOException e) { + if (e instanceof FileAlreadyExistsException) { + // only happens if a subdirectory is named with ".lf" at the end + reporter.printFatalErrorAndExit("Error writing to " + outputPath + ": file already exists. Make sure that no file or directory " + + "within provided input paths have the same relative paths."); + } + reporter.printFatalErrorAndExit("Error writing to " + outputPath + ": " + e.getMessage()); + } - System.out.println("Code formatting finished."); + exitIfCollectedErrors(); + issueCollector.getAllIssues().forEach(reporter::printIssue); + if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { + String msg = "Formatted " + file; + if (file != outputPath) msg += " -> " + outputPath; + reporter.printInfo(msg); } } - /** * If some errors were collected, print them and abort execution. Otherwise return. */ @@ -254,7 +307,7 @@ public List printErrorsIfAny() { /** * Given a path, obtain a resource and validate it. If issues arise during validation, - * these are recorded using the issue collector. + * these are recorded using the issue collector. Returns null if path is not an LF file. * * @param path Path to the resource to validate. * @return A validated resource @@ -262,7 +315,7 @@ public List printErrorsIfAny() { // visible in tests public Resource getValidatedResource(Path path) { final Resource resource = getResource(path); - assert resource != null; + if (resource == null) return null; List issues = this.validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); @@ -285,7 +338,9 @@ private Resource getResource(Path path) { try { return set.getResource(URI.createFileURI(path.toString()), true); } catch (RuntimeException e) { - reporter.printFatalErrorAndExit(path + " is not an LF file. Use the .lf file extension to denote LF files."); + if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { + reporter.printInfo("Skipped " + path + ": not an LF file"); + } return null; } } From ff5e07ab9de4a964633c9cb265fccb75ac53c90f Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 22 Jun 2022 17:36:04 -0700 Subject: [PATCH 035/130] add line wrap option --- org.lflang.cli/src/org/lflang/cli/Lff.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index dcde777a1f..1bd45c63fd 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -23,7 +23,6 @@ import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.xtext.diagnostics.Severity; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.validation.CheckMode; import org.eclipse.xtext.validation.IResourceValidator; @@ -89,6 +88,7 @@ public class Lff { * option to the code generator. * * @author Marten Lohstroh + * @author {Billy Bao } */ enum CLIOption { HELP("h", "help", false, false, "Display this information."), @@ -209,6 +209,10 @@ private void runFormatter(List files) { } } + if (cmd.hasOption(CLIOption.LINE_WRAP.option.getOpt())) { + ToLf.instance.setLineWrap(Integer.parseInt(cmd.getOptionValue(CLIOption.LINE_WRAP.option.getOpt()))); + } + for (Path path : files) { if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { reporter.printInfo("Formatting " + path + ":"); From 9f6295555e5bb5b4e994e01742fd436c8d65af15 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 22 Jun 2022 17:37:29 -0700 Subject: [PATCH 036/130] CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62eea2ce5e..9bc1c1298c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: # Run tests for the standalone compiler. # TODO: Change this back to master branch once merged! cli-tests: - uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@master + uses: lf-lang/lingua-franca/.github/workflows/cli-tests.yml@pretty-printer needs: cancel # Run the C benchmark tests. From ee7ffbd4ac5d10668a4046b8714304150609dfdc Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 22 Jun 2022 17:57:49 -0700 Subject: [PATCH 037/130] fix gradle scripts for building lfc/lff --- org.lflang.cli/build.gradle | 54 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index 1fa2be4c2d..dd9840eff6 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -1,3 +1,4 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar sourceSets { test { @@ -30,24 +31,22 @@ apply plugin: 'com.github.johnrengelman.shadow' task buildLfc() { apply plugin: 'application' - apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lfc' +} - shadowJar { - archiveClassifier.set('lfc') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ - resource = 'plugin.properties' - } +task jarLfc(type: ShadowJar) { + archiveClassifier.set('lfc') + exclude 'test/*' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer) { + resource = 'plugin.properties' } } - -buildLfc.finalizedBy shadowJar +buildLfc.finalizedBy jarLfc task runLfc(type: JavaExec) { // builds and runs lfc @@ -64,24 +63,23 @@ task runLfc(type: JavaExec) { task buildLff() { apply plugin: 'application' - apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lff' +} - shadowJar { - archiveClassifier.set('lff') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ - resource = 'plugin.properties' - } +task jarLff(type: ShadowJar) { + archiveClassifier.set('lff') + exclude 'test/*' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' } } -buildLff.finalizedBy shadowJar +buildLff.finalizedBy jarLff task runLff(type: JavaExec) { // builds and runs lff @@ -94,4 +92,4 @@ task runLff(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath mainClass = 'org.lflang.cli.Lff' workingDir = '..' -} \ No newline at end of file +} From fbab0a0c199f3f9431b2d061a9a422decc25e507 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Wed, 22 Jun 2022 18:48:01 -0700 Subject: [PATCH 038/130] revert previous change, which didn't work --- org.lflang.cli/build.gradle | 54 +++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index dd9840eff6..1fa2be4c2d 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -1,4 +1,3 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar sourceSets { test { @@ -31,22 +30,24 @@ apply plugin: 'com.github.johnrengelman.shadow' task buildLfc() { apply plugin: 'application' + apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lfc' -} -task jarLfc(type: ShadowJar) { - archiveClassifier.set('lfc') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer) { - resource = 'plugin.properties' + shadowJar { + archiveClassifier.set('lfc') + exclude 'test/*' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' + } } } -buildLfc.finalizedBy jarLfc + +buildLfc.finalizedBy shadowJar task runLfc(type: JavaExec) { // builds and runs lfc @@ -63,23 +64,24 @@ task runLfc(type: JavaExec) { task buildLff() { apply plugin: 'application' + apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lff' -} -task jarLff(type: ShadowJar) { - archiveClassifier.set('lff') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ - resource = 'plugin.properties' + shadowJar { + archiveClassifier.set('lff') + exclude 'test/*' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' + } } } -buildLff.finalizedBy jarLff +buildLff.finalizedBy shadowJar task runLff(type: JavaExec) { // builds and runs lff @@ -92,4 +94,4 @@ task runLff(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath mainClass = 'org.lflang.cli.Lff' workingDir = '..' -} +} \ No newline at end of file From 678b348ab30a1c38b0c6583848383a9b4b49a59b Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Thu, 23 Jun 2022 16:29:36 -0700 Subject: [PATCH 039/130] actually fix gradle scripts --- org.lflang.cli/build.gradle | 67 ++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index 1fa2be4c2d..40d3a29591 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -1,3 +1,4 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar sourceSets { test { @@ -8,6 +9,12 @@ sourceSets { } } +configurations { + cli_impl { + extendsFrom implementation + } +} + compileTestKotlin { destinationDir = compileTestJava.destinationDir kotlinOptions { @@ -32,22 +39,28 @@ task buildLfc() { apply plugin: 'application' apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lfc' +} - shadowJar { - archiveClassifier.set('lfc') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ - resource = 'plugin.properties' - } +task jarLfc(type: ShadowJar) { + manifest { + attributes('Main-Class': 'org.lflang.cli.Lfc') + } + configurations = [project.configurations.cli_impl] + archiveClassifier.set('lfc') + exclude 'test/*' + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' + } + from sourceSets.main.output } -buildLfc.finalizedBy shadowJar +buildLfc.finalizedBy jarLfc task runLfc(type: JavaExec) { // builds and runs lfc @@ -66,22 +79,28 @@ task buildLff() { apply plugin: 'application' apply plugin: 'com.github.johnrengelman.shadow' mainClassName = 'org.lflang.cli.Lff' +} - shadowJar { - archiveClassifier.set('lff') - exclude 'test/*' - minimize() { - exclude(dependency('log4j:log4j:.*')) - exclude(dependency('com.google.inject:guice:.*')) - exclude(dependency('org.lflang:org.lflang:.*')) - } - transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ - resource = 'plugin.properties' - } +task jarLff(type: ShadowJar) { + manifest { + attributes('Main-Class': 'org.lflang.cli.Lff') + } + configurations = [project.configurations.cli_impl] + archiveClassifier.set('lff') + exclude 'test/*' + exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' + minimize() { + exclude(dependency('log4j:log4j:.*')) + exclude(dependency('com.google.inject:guice:.*')) + exclude(dependency('org.lflang:org.lflang:.*')) + } + transform(com.github.jengelman.gradle.plugins.shadow.transformers.AppendingTransformer){ + resource = 'plugin.properties' } + from sourceSets.main.output } -buildLff.finalizedBy shadowJar +buildLff.finalizedBy jarLff task runLff(type: JavaExec) { // builds and runs lff From c62b1044a3fcb208ef0a7050cf303583c18e2323 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Fri, 24 Jun 2022 15:52:03 -0700 Subject: [PATCH 040/130] formatting fixes --- org.lflang.cli/build.gradle | 2 +- org.lflang.cli/src/org/lflang/cli/Lff.java | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/org.lflang.cli/build.gradle b/org.lflang.cli/build.gradle index 40d3a29591..b5bbc26d15 100644 --- a/org.lflang.cli/build.gradle +++ b/org.lflang.cli/build.gradle @@ -113,4 +113,4 @@ task runLff(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath mainClass = 'org.lflang.cli.Lff' workingDir = '..' -} \ No newline at end of file +} diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index 1bd45c63fd..0704dd9cea 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -147,7 +147,7 @@ public static void main(final String[] args) { .createInjectorAndDoEMFRegistration(); // Main instance. final Lff main = injector.getInstance(Lff.class); - // Apache Commons Options object configured to according to available CLI arguments. + // Apache Commons Options object configured according to available CLI arguments. Options options = CLIOption.getOptions(); // CLI arguments parser. CommandLineParser parser = new DefaultParser(); @@ -188,14 +188,14 @@ public static void main(final String[] args) { } /** - * Checks all given input paths and the output path, then invokes the formatter on all files given. + * Check all given input paths and the output path, then invokes the formatter on all files given. */ private void runFormatter(List files) { String pathOption = CLIOption.OUTPUT_PATH.option.getOpt(); Path outputRoot = null; if (cmd.hasOption(pathOption)) { outputRoot = Paths.get(cmd.getOptionValue(pathOption)).toAbsolutePath().normalize(); - if (!Files.exists(outputRoot)) { // FIXME: Create it instead? + if (!Files.exists(outputRoot)) { reporter.printFatalErrorAndExit("Output location '" + outputRoot + "' does not exist."); } if (!Files.isDirectory(outputRoot)) { @@ -232,7 +232,7 @@ private void runFormatter(List files) { } /** - * Invokes the formatter on all files in a directory recursively. + * Invoke the formatter on all files in a directory recursively. * @param curPath Current relative path from inputRoot. * @param inputRoot Root directory of input files. * @param outputRoot Root output directory. @@ -258,7 +258,7 @@ private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot) { } /** - * Loads and validates a single file, then formats it and outputs to the given outputPath. + * Load and validate a single file, then formats it and outputs to the given outputPath. */ private void formatSingleFile(Path file, Path outputPath) { file = file.normalize(); From fef0eead6abed491ee0b970ceca0f8ceca954441 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Fri, 24 Jun 2022 17:01:36 -0700 Subject: [PATCH 041/130] refactor lfc and lff with a CliBase class --- .../src/org/lflang/cli/CliBase.java | 134 +++++++++++++++++ org.lflang.cli/src/org/lflang/cli/Lfc.java | 135 ++---------------- org.lflang.cli/src/org/lflang/cli/Lff.java | 114 ++------------- .../lflang/cli/tests/LfcIssueReportingTest.kt | 2 +- 4 files changed, 158 insertions(+), 227 deletions(-) create mode 100644 org.lflang.cli/src/org/lflang/cli/CliBase.java diff --git a/org.lflang.cli/src/org/lflang/cli/CliBase.java b/org.lflang.cli/src/org/lflang/cli/CliBase.java new file mode 100644 index 0000000000..c7c1c6bf5e --- /dev/null +++ b/org.lflang.cli/src/org/lflang/cli/CliBase.java @@ -0,0 +1,134 @@ +package org.lflang.cli; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.List; +import java.util.Properties; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.validation.CheckMode; +import org.eclipse.xtext.validation.IResourceValidator; +import org.eclipse.xtext.validation.Issue; + +import org.lflang.util.FileUtil; + +import com.google.inject.Inject; +import com.google.inject.Provider; + +/** + * Base class for standalone CLI applications. + * + * @author {Marten Lohstroh } + * @author {Christian Menard } + * @author {Billy Bao } + */ +public class CliBase { + /** + * Object for interpreting command line arguments. + */ + protected CommandLine cmd; + /** + * Used to collect all errors that happen during validation/generation. + */ + @Inject + protected IssueCollector issueCollector; + /** + * Used to report error messages at the end. + */ + @Inject + protected ReportingBackend reporter; + /** + * Injected resource provider. + */ + @Inject + private Provider resourceSetProvider; + /** + * Injected resource validator. + */ + @Inject + private IResourceValidator validator; + + /** + * Store command-line arguments as properties, to be passed on to the runtime. + * @param passOptions Which options should be passed to the runtime. + * @return Provided arguments in cmd as properties, which should be passed to the runtime. + */ + protected Properties filterProps(List

@@ -258,13 +218,19 @@ private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot) { } /** - * Load and validate a single file, then formats it and outputs to the given outputPath. + * Load and validate a single file, then format it and output to the given outputPath. */ private void formatSingleFile(Path file, Path outputPath) { file = file.normalize(); outputPath = outputPath.normalize(); - final Resource resource = getValidatedResource(file); - if (resource == null) return; // not an LF file, nothing to do here + final Resource resource = getResource(file); + if (resource == null) { + if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { + reporter.printInfo("Skipped " + file + ": not an LF file"); + } + return; // not an LF file, nothing to do here + } + validateResource(resource); exitIfCollectedErrors(); @@ -288,64 +254,4 @@ private void formatSingleFile(Path file, Path outputPath) { reporter.printInfo(msg); } } - - /** - * If some errors were collected, print them and abort execution. Otherwise return. - */ - private void exitIfCollectedErrors() { - if (issueCollector.getErrorsOccurred() ) { - // if there are errors, don't print warnings. - List errors = printErrorsIfAny(); - String cause = errors.size() == 1 ? "previous error" - : errors.size() + " previous errors"; - reporter.printFatalErrorAndExit("Aborting due to " + cause); - } - } - - // visible in tests - public List printErrorsIfAny() { - List errors = issueCollector.getErrors(); - errors.forEach(reporter::printIssue); - return errors; - } - - /** - * Given a path, obtain a resource and validate it. If issues arise during validation, - * these are recorded using the issue collector. Returns null if path is not an LF file. - * - * @param path Path to the resource to validate. - * @return A validated resource - */ - // visible in tests - public Resource getValidatedResource(Path path) { - final Resource resource = getResource(path); - if (resource == null) return null; - - List issues = this.validator.validate(resource, CheckMode.ALL, CancelIndicator.NullImpl); - - for (Issue issue : issues) { - URI uri = issue.getUriToProblem(); // Issues may also relate to imported resources. - try { - issueCollector.accept(new LfIssue(issue.getMessage(), issue.getSeverity(), - issue.getLineNumber(), issue.getColumn(), - issue.getLineNumberEnd(), issue.getColumnEnd(), - issue.getLength(), FileUtil.toPath(uri))); - } catch (IOException e) { - reporter.printError("Unable to convert '" + uri + "' to path." + e); - } - } - return resource; - } - - private Resource getResource(Path path) { - final ResourceSet set = this.resourceSetProvider.get(); - try { - return set.getResource(URI.createFileURI(path.toString()), true); - } catch (RuntimeException e) { - if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { - reporter.printInfo("Skipped " + path + ": not an LF file"); - } - return null; - } - } } diff --git a/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt index 3c8095a7d6..12519a1ca0 100644 --- a/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt +++ b/org.lflang.cli/test/kotlin/org/lflang/cli/tests/LfcIssueReportingTest.kt @@ -124,7 +124,7 @@ class LfcIssueReportingTest { assert(Files.exists(lfFile)) { "Missing test file $lfFile" } // this side-effects on the ReportingBackend - main.getValidatedResource(lfFile) + main.validateResource(main.getResource(lfFile)) main.printErrorsIfAny() val actualOutput = stderr.toString().normalize(lfFile) From 5ecad19cffb6bf706b4a09f50cd269574fe30b13 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Fri, 24 Jun 2022 17:09:18 -0700 Subject: [PATCH 042/130] add javadoc --- org.lflang.cli/src/org/lflang/cli/CliBase.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.lflang.cli/src/org/lflang/cli/CliBase.java b/org.lflang.cli/src/org/lflang/cli/CliBase.java index c7c1c6bf5e..26344be1b9 100644 --- a/org.lflang.cli/src/org/lflang/cli/CliBase.java +++ b/org.lflang.cli/src/org/lflang/cli/CliBase.java @@ -85,6 +85,10 @@ protected void exitIfCollectedErrors() { } } + /** + * If any errors were collected, print them, then return them. + * @return A list of collected errors. + */ // visible in tests public List printErrorsIfAny() { List errors = issueCollector.getErrors(); From ebac69098fc683ad42882a5a719603a9bd3dd6a1 Mon Sep 17 00:00:00 2001 From: Billy Bao Date: Tue, 28 Jun 2022 16:50:02 -0700 Subject: [PATCH 043/130] refactor version string into its own file --- org.lflang.cli/src/org/lflang/cli/Lfc.java | 7 ++----- org.lflang.cli/src/org/lflang/cli/Lff.java | 6 ++---- org.lflang/src/org/lflang/LocalStrings.java | 11 +++++++++++ org.lflang/src/org/lflang/StringsBundle.properties | 1 + 4 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 org.lflang/src/org/lflang/LocalStrings.java create mode 100644 org.lflang/src/org/lflang/StringsBundle.properties diff --git a/org.lflang.cli/src/org/lflang/cli/Lfc.java b/org.lflang.cli/src/org/lflang/cli/Lfc.java index 1d3dd40ac2..77bfba5056 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lfc.java +++ b/org.lflang.cli/src/org/lflang/cli/Lfc.java @@ -28,6 +28,7 @@ import org.lflang.FileConfig; import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; +import org.lflang.LocalStrings; import org.lflang.generator.LFGeneratorContext; import org.lflang.generator.MainContext; @@ -41,10 +42,6 @@ * @author {Christian Menard } */ public class Lfc extends CliBase { - - /// current lfc version as printed by --version - private static final String VERSION = "0.2.2-SNAPSHOT"; - /** * Injected code generator. */ @@ -170,7 +167,7 @@ public static void main(final String[] args) { // If requested, print version and abort if (main.cmd.hasOption(CLIOption.VERSION.option.getLongOpt())) { - System.out.println("lfc " + VERSION); + System.out.println("lfc " + LocalStrings.VERSION); System.exit(0); } diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index 83bfc1cc05..8f18056d0f 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -23,6 +23,7 @@ import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; +import org.lflang.LocalStrings; import org.lflang.ast.ToLf; import org.lflang.util.FileUtil; @@ -37,9 +38,6 @@ * @author {Billy Bao } */ public class Lff extends CliBase { - /// current lff version as printed by --version - private static final String VERSION = "0.2.2-SNAPSHOT"; - /** * Supported CLI options. *

@@ -125,7 +123,7 @@ public static void main(final String[] args) { // If requested, print version and abort if (main.cmd.hasOption(CLIOption.VERSION.option.getLongOpt())) { - System.out.println("lff " + VERSION); + System.out.println("lff " + LocalStrings.VERSION); System.exit(0); } diff --git a/org.lflang/src/org/lflang/LocalStrings.java b/org.lflang/src/org/lflang/LocalStrings.java new file mode 100644 index 0000000000..79f338b39d --- /dev/null +++ b/org.lflang/src/org/lflang/LocalStrings.java @@ -0,0 +1,11 @@ +package org.lflang; + +import java.util.ResourceBundle; + +/** + * Static class for managing strings. + */ +public class LocalStrings { + public static final ResourceBundle res = ResourceBundle.getBundle("org.lflang.StringsBundle"); + public static final String VERSION = res.getString("VERSION"); +} diff --git a/org.lflang/src/org/lflang/StringsBundle.properties b/org.lflang/src/org/lflang/StringsBundle.properties new file mode 100644 index 0000000000..67bcbc35b1 --- /dev/null +++ b/org.lflang/src/org/lflang/StringsBundle.properties @@ -0,0 +1 @@ +VERSION = 0.2.2-SNAPSHOT \ No newline at end of file From 3db47f2f5e025f61f42150fea2c4692bae57feb9 Mon Sep 17 00:00:00 2001 From: Marten Lohstroh Date: Tue, 28 Jun 2022 16:54:37 -0700 Subject: [PATCH 044/130] Update org.lflang/src/org/lflang/StringsBundle.properties --- org.lflang/src/org/lflang/StringsBundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/StringsBundle.properties b/org.lflang/src/org/lflang/StringsBundle.properties index 67bcbc35b1..b1813894c6 100644 --- a/org.lflang/src/org/lflang/StringsBundle.properties +++ b/org.lflang/src/org/lflang/StringsBundle.properties @@ -1 +1 @@ -VERSION = 0.2.2-SNAPSHOT \ No newline at end of file +VERSION = 0.2.2-SNAPSHOT From 5aaf43070a210d3d99d6c0153b352e76024d9426 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 13 Jun 2022 17:59:17 -0700 Subject: [PATCH 045/130] [formatting] Start infrastructure for line wrapping. --- .../lflang/tests/compiler/RoundTripTests.java | 13 +- .../src/org/lflang/ast/MalleableString.java | 262 ++++++++ org.lflang/src/org/lflang/ast/ToLf.java | 571 +++++++++--------- org.lflang/src/org/lflang/ast/ToText.java | 12 +- 4 files changed, 562 insertions(+), 296 deletions(-) create mode 100644 org.lflang/src/org/lflang/ast/MalleableString.java diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 4593f56213..f8e6c25e9d 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -4,7 +4,6 @@ import java.io.FileNotFoundException; import java.io.PrintWriter; import java.nio.file.Path; -import java.util.Locale; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; @@ -12,7 +11,6 @@ import org.eclipse.xtext.resource.XtextResourceSet; import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.extensions.InjectionExtension; -import org.eclipse.xtext.testing.util.ParseHelper; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,19 +25,11 @@ import org.lflang.tests.TestRegistry; import org.lflang.tests.TestRegistry.TestCategory; -import com.google.inject.Inject; import com.google.inject.Injector; @ExtendWith(InjectionExtension.class) @InjectWith(LFInjectorProvider.class) public class RoundTripTests { - @Inject - XtextResourceSet resourceSet; - - @Inject - ParseHelper parser; - - private static final String REFORMATTED_FILE_PREFIX = "reformatted_"; @Test public void roundTripTest() throws Exception { @@ -58,8 +48,7 @@ private void run(Path file) throws Exception { Model originalModel = parse(file); System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); - ToLf.instance.setLineWrap(30); - String reformattedTestCase = ToLf.instance.doSwitch(originalModel); + String reformattedTestCase = ToLf.instance.doSwitch(originalModel).toString(); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = getResultingModel(file, reformattedTestCase); Assertions.assertNotNull(resultingModel); diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java new file mode 100644 index 0000000000..f2efef7364 --- /dev/null +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -0,0 +1,262 @@ +package org.lflang.ast; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import org.jetbrains.annotations.NotNull; + +import com.google.common.collect.ImmutableList; + +public interface MalleableString extends Iterable { + + default MalleableString indent(int indentation) { + if (indentation < 0) { + throw new IllegalArgumentException("Indentation must be nonnegative."); + } + return new Indented(this, indentation); + } + + boolean isEmpty(); + + static MalleableString anyOf(MalleableString... possibilities) { + return new Fork(possibilities); + } + + static MalleableString anyOf(String... possibilities) { + return new Leaf(possibilities); + } + + static MalleableString anyOf(Object... possibilities) { + return new Leaf((String[]) Arrays.stream(possibilities).map(String::valueOf).toArray()); + } + + final class Builder { + + List components = new ArrayList<>(); + + Builder append(MalleableString... possibilities) { + return append(Function.identity(), Fork::new, possibilities); + } + + Builder append(String... content) { + return append(Leaf::new, Leaf::new, content); + } + + Builder append(Object... content) { + return append((String[]) Arrays.stream(content).map(Objects::toString).toArray()); + } + + MalleableString get() { + return new Sequence(ImmutableList.copyOf(components)); + } + + private Builder append( + Function toMalleableString, + Function multiplePossibilitiesRepresenter, + T[] possibilities + ) { + if ( + Arrays.stream(possibilities) + .map(toMalleableString) + .allMatch(MalleableString::isEmpty) + ) { + return this; + } + if (possibilities.length == 1) { + // The resulting MalleableString may be a sequence. + // Stay flat: Let there be no sequences in sequences! + toMalleableString.apply(possibilities[0]).forEach(components::add); + } else { + components.add(multiplePossibilitiesRepresenter.apply(possibilities)); + } + return this; + } + } + + final class Joiner implements Collector< + MalleableString, + Builder, + MalleableString + > { + private final Function appendSeparator; + private final Function appendPrefix; + private final Function appendSuffix; + + public Joiner() { this(MalleableString.anyOf(", ")); } + + public Joiner(MalleableString separator) { + this(separator, MalleableString.anyOf(""), MalleableString.anyOf("")); + } + + public Joiner(MalleableString separator, MalleableString prefix, MalleableString suffix) { + this.appendSeparator = builder -> + builder.components.isEmpty() ? builder : builder.append(separator); + this.appendPrefix = builder -> builder.append(prefix); + this.appendSuffix = builder -> builder.append(suffix); + } + + public Joiner(String separator) { + this(MalleableString.anyOf(separator)); + } + + public Joiner(String separator, String prefix, String suffix) { + this( + MalleableString.anyOf(separator), + MalleableString.anyOf(prefix), + MalleableString.anyOf(suffix) + ); + } + + @Override + public Supplier supplier() { + return () -> appendPrefix.apply(new Builder()); + } + + @Override + public BiConsumer accumulator() { + return (b, ms) -> appendSeparator.apply(b).append(ms); + } + + @Override + public BinaryOperator combiner() { + return (builder0, builder1) -> { + builder1.components.forEach(ms -> accumulator().accept(builder0, ms)); + return builder0; + }; + } + + @Override + public Function finisher() { + return ((Function) Builder::get).compose(appendSuffix); + } + + @Override + public Set characteristics() { + return Set.of(); + } + } + + + @SuppressWarnings("ClassCanBeRecord") + final class Sequence implements MalleableString { + private final ImmutableList components; + private Sequence(ImmutableList components) { + this.components = components; + } + + @Override + public String toString() { + return components.stream() + .map(MalleableString::toString) + .collect(Collectors.joining("")); + } + + @NotNull + @Override + public Iterator iterator() { + return components.iterator(); + } + + @Override + public boolean isEmpty() { + return components.stream().allMatch(MalleableString::isEmpty); + } + } + + final class Indented implements MalleableString { + + private final int indentation; + private final MalleableString nested; + + private Indented(MalleableString toIndent, int indentation) { + this.indentation = indentation; + this.nested = toIndent; + } + + @Override + public MalleableString indent(int indentation) { + return new Indented(nested, this.indentation + indentation); + } + + @Override + public boolean isEmpty() { + return nested.isEmpty(); + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.singleton((MalleableString) this).iterator(); + } + + @Override + public String toString() { + return nested.toString().indent(indentation); + } + } + + abstract class MalleableStringImpl implements MalleableString { + protected abstract List getPossibilities(); + + @Override + public String toString() { + if (getPossibilities().isEmpty()) { + throw new IllegalStateException( + "A MalleableString must be directly or transitively backed " + + "by at least one String." + ); + } + return getPossibilities().get(0).toString(); + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.singleton((MalleableString) this).iterator(); + } + } + + final class Fork extends MalleableStringImpl { + private final ImmutableList possibilities; + private Fork(MalleableString[] possibilities) { + this.possibilities = ImmutableList.copyOf(possibilities); + } + + @Override + protected List getPossibilities() { return this.possibilities; } + + @Override + public boolean isEmpty() { + return possibilities.stream().allMatch(MalleableString::isEmpty); + } + } + + final class Leaf extends MalleableStringImpl { + private final ImmutableList possibilities; + private Leaf(String[] possibilities) { + this.possibilities = ImmutableList.copyOf(possibilities); + } + private Leaf(String possibility) { + this.possibilities = ImmutableList.of(possibility); + } + + @Override + protected List getPossibilities() { return this.possibilities; } + + @Override + public boolean isEmpty() { + return possibilities.stream().allMatch(String::isEmpty); + } + } +} diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index a665047c6d..2bd9ebeeb0 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -1,7 +1,6 @@ package org.lflang.ast; import java.util.List; -import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -10,6 +9,8 @@ import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; +import org.lflang.ast.MalleableString.Builder; +import org.lflang.ast.MalleableString.Joiner; import org.lflang.lf.Action; import org.lflang.lf.Array; import org.lflang.lf.ArraySpec; @@ -65,15 +66,10 @@ * Switch class for converting AST nodes to their textual representation as * it would appear in LF code. */ -public class ToLf extends LfSwitch { +public class ToLf extends LfSwitch { /** The number of spaces to prepend to a line per indentation level. */ private static final int INDENTATION = 4; - - // Number of characters at which to line wrap. - private int lineWrap = 0; - // Current indentation level. - private int indentLvl = 0; // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 @@ -83,150 +79,150 @@ public class ToLf extends LfSwitch { // private constructor private ToLf() { super(); } - - /** - * Sets the line wrap for code generation. - * @param wrap The line wrap. If set to zero, line wrap is disabled. - */ - public void setLineWrap(int wrap) { - if(wrap < 0) { - throw new IllegalArgumentException("Attempt to set line wrap to negative value."); - } - lineWrap = wrap; - } @Override - public String caseArraySpec(ArraySpec spec) { - return (spec.isOfVariableLength()) ? "[]" : "[" + spec.getLength() + "]"; + public MalleableString caseArraySpec(ArraySpec spec) { + return MalleableString.anyOf( + spec.isOfVariableLength() ? "[]" : "[" + spec.getLength() + "]" + ); } @Override - public String caseCode(Code code) { - indentLvl++; - String content = wrapLines(ToText.instance.doSwitch(code)); - indentLvl--; + public MalleableString caseCode(Code code) { + String content = ToText.instance.doSwitch(code); + String singleLineRepresentation = String.format("{= %s =}", content.strip()); + String multilineRepresentation = String.format( + "{=%n%s=}", + content.strip().indent(INDENTATION) + ); if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { - return String.format("{=%n%s=}", content.strip().indent(INDENTATION)); + return MalleableString.anyOf(multilineRepresentation); } - return String.format("{= %s =}", content.strip()); + return MalleableString.anyOf(singleLineRepresentation, multilineRepresentation); } @Override - public String caseHost(Host host) { - StringBuilder sb = new StringBuilder(); + public MalleableString caseHost(Host host) { + Builder msb = new Builder(); if (!StringExtensions.isNullOrEmpty(host.getUser())) { - sb.append(host.getUser()).append("@"); + msb.append(host.getUser()).append("@"); } if (!StringExtensions.isNullOrEmpty(host.getAddr())) { - sb.append(host.getAddr()); + msb.append(host.getAddr()); } if (host.getPort() != 0) { - sb.append(":").append(host.getPort()); + msb.append(":").append(host.getPort()); } - return sb.toString(); + return msb.get(); } @Override - public String caseLiteral(Literal l) { + public MalleableString caseLiteral(Literal l) { // STRING | CHAR_LIT | SignedFloat | SignedInt | Boolean - return l.getLiteral(); + return MalleableString.anyOf(l.getLiteral()); } @Override - public String caseParameterReference(ParameterReference p) { + public MalleableString caseParameterReference(ParameterReference p) { // parameter=[Parameter] - return p.getParameter().getName(); + return MalleableString.anyOf(p.getParameter().getName()); } @Override - public String caseTime(Time t) { + public MalleableString caseTime(Time t) { // (interval=INT unit=TimeUnit) - return ASTUtils.toTimeValue(t).toString(); + return MalleableString.anyOf(ASTUtils.toTimeValue(t).toString()); } @Override - public String caseType(Type type) { + public MalleableString caseType(Type type) { // time?='time' (arraySpec=ArraySpec)? // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? // | code=Code if (type.getCode() != null) return doSwitch(type.getCode()); - StringBuilder sb = new StringBuilder(); + Builder msb = new Builder(); if (type.isTime()) { - sb.append("time"); + msb.append("time"); } else if (type.getId() != null) { - sb.append(type.getId()); + msb.append(type.getId()); if (type.getTypeParms() != null) { - sb.append(list(type.getTypeParms(), ", ", "<", ">", true)); + msb.append(list(type.getTypeParms(), ", ", "<", ">", true)); } - sb.append("*".repeat(type.getStars().size())); + msb.append("*".repeat(type.getStars().size())); } - if (type.getArraySpec() != null) sb.append(doSwitch(type.getArraySpec())); - return sb.toString(); + if (type.getArraySpec() != null) msb.append(doSwitch(type.getArraySpec())); + return msb.get(); } @Override - public String caseTypeParm(TypeParm t) { + public MalleableString caseTypeParm(TypeParm t) { // literal=TypeExpr | code=Code - return !StringExtensions.isNullOrEmpty(t.getLiteral()) ? t.getLiteral() : doSwitch(t.getCode()); + return MalleableString.anyOf( + !StringExtensions.isNullOrEmpty(t.getLiteral()) ? + MalleableString.anyOf(t.getLiteral()) : doSwitch(t.getCode()) + ); } @Override - public String caseVarRef(VarRef v) { + public MalleableString caseVarRef(VarRef v) { // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' - if (!v.isInterleaved()) return ToText.instance.doSwitch(v); - return String.format("interleaved (%s)", ToText.instance.doSwitch(v)); + if (!v.isInterleaved()) return MalleableString.anyOf(ToText.instance.doSwitch(v)); + return MalleableString.anyOf(String.format("interleaved (%s)", ToText.instance.doSwitch(v))); } @Override - public String caseModel(Model object) { + public MalleableString caseModel(Model object) { // target=TargetDecl // (imports+=Import)* // (preambles+=Preamble)* // (reactors+=Reactor)+ - StringBuilder sb = new StringBuilder(); - sb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); - object.getImports().forEach(i -> sb.append(caseImport(i)).append(System.lineSeparator())); - if (!object.getImports().isEmpty()) sb.append(System.lineSeparator()); + Builder msb = new Builder(); + msb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); + object.getImports().forEach(i -> msb.append(caseImport(i)).append(System.lineSeparator())); + if (!object.getImports().isEmpty()) msb.append(System.lineSeparator()); object.getPreambles().forEach( - p -> sb.append(casePreamble(p)).append(System.lineSeparator().repeat(2)) + p -> msb.append(casePreamble(p)).append(System.lineSeparator().repeat(2)) ); - if (!object.getPreambles().isEmpty()) sb.append(System.lineSeparator()); - sb.append( + if (!object.getPreambles().isEmpty()) msb.append(System.lineSeparator()); + msb.append( object.getReactors().stream().map(this::doSwitch) - .collect(Collectors.joining(System.lineSeparator().repeat(2))) + .collect(new Joiner(System.lineSeparator().repeat(2))) ).append(System.lineSeparator()); - // indentLvl should be zero; wrap unindented lines and over-indented lines here - return wrapLines(sb.toString()); + return msb.get(); } @Override - public String caseImport(Import object) { + public MalleableString caseImport(Import object) { // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? - return String.format( + return MalleableString.anyOf(String.format( "import %s from \"%s\"", list(object.getReactorClasses(), ", ", "", "", false), object.getImportURI() - ); + )); } @Override - public String caseReactorDecl(ReactorDecl object) { + public MalleableString caseReactorDecl(ReactorDecl object) { // Reactor | ImportedReactor return defaultCase(object); } @Override - public String caseImportedReactor(ImportedReactor object) { + public MalleableString caseImportedReactor(ImportedReactor object) { // reactorClass=[Reactor] ('as' name=ID)? if (object.getName() != null) { - return String.format("%s as %s", object.getReactorClass().getName(), object.getName()); + return MalleableString.anyOf(String.format( + "%s as %s", + object.getReactorClass().getName(), + object.getName() + )); } - return object.getReactorClass().getName(); + return MalleableString.anyOf(object.getReactorClass().getName()); } @Override - public String caseReactor(Reactor object) { + public MalleableString caseReactor(Reactor object) { // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) 'reactor' (name=ID)? // ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? // ('(' parameters+=Parameter (',' parameters+=Parameter)* ')')? @@ -246,9 +242,9 @@ public String caseReactor(Reactor object) { // | (modes+=Mode) // | (mutations+=Mutation) // )* '}' - StringBuilder sb = new StringBuilder(); - sb.append(reactorHeader(object)); - String smallFeatures = indentedStatements( + Builder msb = new Builder(); + msb.append(reactorHeader(object)); + MalleableString smallFeatures = indentedStatements( List.of( object.getPreambles(), object.getInputs(), @@ -261,7 +257,7 @@ public String caseReactor(Reactor object) { ), 0 ); - String bigFeatures = indentedStatements( + MalleableString bigFeatures = indentedStatements( List.of( object.getReactions(), object.getMethods(), @@ -270,117 +266,117 @@ public String caseReactor(Reactor object) { ), 1 ); - sb.append(smallFeatures); - if (!smallFeatures.isBlank() && !bigFeatures.isBlank()) sb.append(System.lineSeparator()); - sb.append(bigFeatures); - sb.append("}"); - return sb.toString(); + msb.append(smallFeatures); + if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) msb.append(System.lineSeparator()); + msb.append(bigFeatures); + msb.append("}"); + return msb.get(); } /** Return the signature of the given reactor. */ - private String reactorHeader(Reactor object) { - StringBuilder sb = new StringBuilder(); - if (object.isFederated()) sb.append("federated "); - if (object.isMain()) sb.append("main "); - if (object.isRealtime()) sb.append("realtime "); - sb.append("reactor"); - if (object.getName() != null) sb.append(" ").append(object.getName()); - sb.append(list(object.getTypeParms(), ", ", "<", ">", true)); - sb.append(list(object.getParameters())); - if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); + private MalleableString reactorHeader(Reactor object) { + Builder msb = new Builder(); + if (object.isFederated()) msb.append("federated "); + if (object.isMain()) msb.append("main "); + if (object.isRealtime()) msb.append("realtime "); + msb.append("reactor"); + if (object.getName() != null) msb.append(" ").append(object.getName()); + msb.append(list(object.getTypeParms(), ", ", "<", ">", true)); + msb.append(list(object.getParameters())); + if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { - sb.append(" extends ").append( + msb.append(" extends ").append( object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) ); } - sb.append(String.format(" {%n")); - return sb.toString(); + msb.append(String.format(" {%n")); + return msb.get(); } @Override - public String caseTargetDecl(TargetDecl object) { + public MalleableString caseTargetDecl(TargetDecl object) { // 'target' name=ID (config=KeyValuePairs)? ';'? - StringBuilder sb = new StringBuilder(); - sb.append("target ").append(object.getName()); - if (object.getConfig() != null) sb.append(" ").append(doSwitch(object.getConfig())); - return sb.toString(); + Builder msb = new Builder(); + msb.append("target ").append(object.getName()); + if (object.getConfig() != null) msb.append(" ").append(doSwitch(object.getConfig())); + return msb.get(); } @Override - public String caseStateVar(StateVar object) { + public MalleableString caseStateVar(StateVar object) { // 'state' name=ID ( // (':' (type=Type))? // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') // )? // ) ';'? - StringBuilder sb = new StringBuilder(); - sb.append("state ").append(object.getName()); - sb.append(typeAnnotationFor(object.getType())); - if (!object.getParens().isEmpty()) sb.append(list(object.getInit())); - if (!object.getBraces().isEmpty()) sb.append(list(object.getInit(), ", ", "{", "}", true)); - return sb.toString(); + Builder msb = new Builder(); + msb.append("state ").append(object.getName()); + msb.append(typeAnnotationFor(object.getType())); + if (!object.getParens().isEmpty()) msb.append(list(object.getInit())); + if (!object.getBraces().isEmpty()) msb.append(list(object.getInit(), ", ", "{", "}", true)); + return msb.get(); } @Override - public String caseMethod(Method object) { + public MalleableString caseMethod(Method object) { // const?='const'? 'method' name=ID // '(' (arguments+=MethodArgument (',' arguments+=MethodArgument)*)? ')' // (':' return=Type)? // code=Code // ';'? - StringBuilder sb = new StringBuilder(); - if (object.isConst()) sb.append("const "); - sb.append("method ").append(object.getName()); - sb.append(list(object.getArguments(), ", ", "(", ")", false)); - sb.append(typeAnnotationFor(object.getReturn())).append(" ").append(doSwitch(object.getCode())); - return sb.toString(); + Builder msb = new Builder(); + if (object.isConst()) msb.append("const "); + msb.append("method ").append(object.getName()); + msb.append(list(object.getArguments(), ", ", "(", ")", false)); + msb.append(typeAnnotationFor(object.getReturn())).append(" ").append(doSwitch(object.getCode())); + return msb.get(); } @Override - public String caseMethodArgument(MethodArgument object) { + public MalleableString caseMethodArgument(MethodArgument object) { // name=ID (':' type=Type)? - return object.getName() + typeAnnotationFor(object.getType()); + return MalleableString.anyOf(object.getName() + typeAnnotationFor(object.getType())); } @Override - public String caseInput(Input object) { + public MalleableString caseInput(Input object) { // mutable?='mutable'? 'input' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - if (object.isMutable()) sb.append("mutable "); - sb.append("input"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getName()).append(typeAnnotationFor(object.getType())); - return sb.toString(); + Builder msb = new Builder(); + if (object.isMutable()) msb.append("mutable "); + msb.append("input"); + if (object.getWidthSpec() != null) msb.append(doSwitch(object.getWidthSpec())); + msb.append(" ").append(object.getName()).append(typeAnnotationFor(object.getType())); + return msb.get(); } @Override - public String caseOutput(Output object) { + public MalleableString caseOutput(Output object) { // 'output' (widthSpec=WidthSpec)? name=ID (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - sb.append("output"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getName()); - sb.append(typeAnnotationFor(object.getType())); - return sb.toString(); + Builder msb = new Builder(); + msb.append("output"); + if (object.getWidthSpec() != null) msb.append(doSwitch(object.getWidthSpec())); + msb.append(" ").append(object.getName()); + msb.append(typeAnnotationFor(object.getType())); + return msb.get(); } @Override - public String caseTimer(Timer object) { + public MalleableString caseTimer(Timer object) { // 'timer' name=ID ('(' offset=Expression (',' period=Expression)? ')')? ';'? - StringBuilder sb = new StringBuilder(); - sb.append("timer ").append(object.getName()); + Builder msb = new Builder(); + msb.append("timer ").append(object.getName()); if (object.getOffset() != null) { - sb.append("("); - sb.append(doSwitch(object.getOffset())); - if (object.getPeriod() != null) sb.append(", ").append(doSwitch(object.getPeriod())); - sb.append(")"); + msb.append("("); + msb.append(doSwitch(object.getOffset())); + if (object.getPeriod() != null) msb.append(", ").append(doSwitch(object.getPeriod())); + msb.append(")"); } - return sb.toString(); + return msb.get(); } @Override - public String caseMode(Mode object) { + public MalleableString caseMode(Mode object) { // {Mode} (initial?='initial')? 'mode' (name=ID)? // '{' ( // (stateVars+=StateVar) | @@ -390,12 +386,12 @@ public String caseMode(Mode object) { // (connections+=Connection) | // (reactions+=Reaction) // )* '}' - StringBuilder sb = new StringBuilder(); - if (object.isInitial()) sb.append("initial "); - sb.append("mode "); - if (object.getName() != null) sb.append(object.getName()).append(" "); - sb.append(String.format("{%n")); - sb.append(indentedStatements( + Builder msb = new Builder(); + if (object.isInitial()) msb.append("initial "); + msb.append("mode "); + if (object.getName() != null) msb.append(object.getName()).append(" "); + msb.append(String.format("{%n")); + msb.append(indentedStatements( List.of( object.getStateVars(), object.getTimers(), @@ -405,35 +401,35 @@ public String caseMode(Mode object) { ), 0 )); - sb.append(indentedStatements( + msb.append(indentedStatements( List.of(object.getReactions()), 1 )); - sb.append("}"); - return sb.toString(); + msb.append("}"); + return msb.get(); } @Override - public String caseAction(Action object) { + public MalleableString caseAction(Action object) { // (origin=ActionOrigin)? 'action' name=ID // ('(' minDelay=Expression (',' minSpacing=Expression (',' policy=STRING)? )? ')')? // (':' type=Type)? ';'? - StringBuilder sb = new StringBuilder(); - if (object.getOrigin() != null) sb.append(object.getOrigin().getLiteral()).append(" "); - sb.append("action "); - sb.append(object.getName()); + Builder msb = new Builder(); + if (object.getOrigin() != null) msb.append(object.getOrigin().getLiteral()).append(" "); + msb.append("action "); + msb.append(object.getName()); if (object.getMinDelay() != null) { - sb.append("(").append(doSwitch(object.getMinDelay())); - if (object.getMinSpacing() != null) sb.append(", ").append(doSwitch(object.getMinSpacing())); - if (object.getPolicy() != null) sb.append(", \"").append(object.getPolicy()).append("\""); - sb.append(")"); + msb.append("(").append(doSwitch(object.getMinDelay())); + if (object.getMinSpacing() != null) msb.append(", ").append(doSwitch(object.getMinSpacing())); + if (object.getPolicy() != null) msb.append(", \"").append(object.getPolicy()).append("\""); + msb.append(")"); } - sb.append(typeAnnotationFor(object.getType())); - return sb.toString(); + msb.append(typeAnnotationFor(object.getType())); + return msb.get(); } @Override - public String caseReaction(Reaction object) { + public MalleableString caseReaction(Reaction object) { // ('reaction') // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? // (sources+=VarRef (',' sources+=VarRef)*)? @@ -441,21 +437,21 @@ public String caseReaction(Reaction object) { // code=Code // (stp=STP)? // (deadline=Deadline)? - StringBuilder sb = new StringBuilder(); - sb.append("reaction"); - sb.append(list(object.getTriggers())); - sb.append(list(object.getSources(), ", ", " ", "", true)); + Builder msb = new Builder(); + msb.append("reaction"); + msb.append(list(object.getTriggers())); + msb.append(list(object.getSources(), ", ", " ", "", true)); if (!object.getEffects().isEmpty()) { - sb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + msb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); } - sb.append(" ").append(doSwitch(object.getCode())); - if (object.getStp() != null) sb.append(" ").append(doSwitch(object.getStp())); - if (object.getDeadline() != null) sb.append(" ").append(doSwitch(object.getDeadline())); - return sb.toString(); + msb.append(" ").append(doSwitch(object.getCode())); + if (object.getStp() != null) msb.append(" ").append(doSwitch(object.getStp())); + if (object.getDeadline() != null) msb.append(" ").append(doSwitch(object.getDeadline())); + return msb.get(); } @Override - public String caseTriggerRef(TriggerRef object) { + public MalleableString caseTriggerRef(TriggerRef object) { // BuiltinTriggerRef | VarRef throw new UnsupportedOperationException( "TriggerRefs are BuiltinTriggerRefs or VarRefs, so the methods " @@ -463,76 +459,85 @@ public String caseTriggerRef(TriggerRef object) { } @Override - public String caseBuiltinTriggerRef(BuiltinTriggerRef object) { + public MalleableString caseBuiltinTriggerRef(BuiltinTriggerRef object) { // type = BuiltinTrigger - return object.getType().getLiteral(); + return MalleableString.anyOf(object.getType().getLiteral()); } @Override - public String caseDeadline(Deadline object) { + public MalleableString caseDeadline(Deadline object) { // 'deadline' '(' delay=Expression ')' code=Code - return String.format("deadline(%s) %s", doSwitch(object.getDelay()), doSwitch(object.getCode())); + return new Builder() + .append("deadline(") + .append(doSwitch(object.getDelay())) + .append(") ") + .append(caseCode(object.getCode())) + .get(); } @Override - public String caseSTP(STP object) { + public MalleableString caseSTP(STP object) { // 'STP' '(' value=Expression ')' code=Code - return String.format("STP(%s) %s", doSwitch(object.getValue()), doSwitch(object.getCode())); + return new Builder() + .append("STP(") + .append(doSwitch(object.getValue())) + .append(") ") + .append(doSwitch(object.getCode())) + .get(); } @Override - public String caseMutation(Mutation object) { + public MalleableString caseMutation(Mutation object) { // ('mutation') // ('(' (triggers+=TriggerRef (',' triggers+=TriggerRef)*)? ')')? // (sources+=VarRef (',' sources+=VarRef)*)? // ('->' effects+=[VarRef] (',' effects+=[VarRef])*)? // code=Code - StringBuilder sb = new StringBuilder(); - sb.append("mutation"); + Builder msb = new Builder(); + msb.append("mutation"); if (!object.getTriggers().isEmpty()) { - sb.append(object.getTriggers().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "(", ")")) - ); + msb.append(object.getTriggers().stream().map(this::doSwitch).collect( + new Joiner(", ", "(", ")") + )); } - return sb.toString(); + return msb.get(); } @Override - public String casePreamble(Preamble object) { + public MalleableString casePreamble(Preamble object) { // (visibility=Visibility)? 'preamble' code=Code - return String.format( - "%spreamble %s", - object.getVisibility() != null && object.getVisibility() != Visibility.NONE - ? object.getVisibility().getLiteral() + " " : "", - doSwitch(object.getCode()) - ); + Builder msb = new Builder(); + if (object.getVisibility() != null && object.getVisibility() != Visibility.NONE) { + msb.append(object.getVisibility().getLiteral()).append(" "); + } + return msb.append("preamble ").append(doSwitch(object.getCode())).get(); } @Override - public String caseInstantiation(Instantiation object) { + public MalleableString caseInstantiation(Instantiation object) { // name=ID '=' 'new' (widthSpec=WidthSpec)? // reactorClass=[ReactorDecl] ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? '(' // (parameters+=Assignment (',' parameters+=Assignment)*)? // ')' ('at' host=Host)? ';'?; - StringBuilder sb = new StringBuilder(); - sb.append(object.getName()).append(" = new"); - if (object.getWidthSpec() != null) sb.append(doSwitch(object.getWidthSpec())); - sb.append(" ").append(object.getReactorClass().getName()); + Builder msb = new Builder(); + msb.append(object.getName()).append(" = new"); + if (object.getWidthSpec() != null) msb.append(doSwitch(object.getWidthSpec())); + msb.append(" ").append(object.getReactorClass().getName()); if (!object.getTypeParms().isEmpty()) { - sb.append(object.getTypeParms().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "<", ">")) + msb.append(object.getTypeParms().stream().map(this::doSwitch).collect( + new Joiner(", ", "<", ">")) ); } - sb.append(object.getParameters().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "(", ")")) + msb.append(object.getParameters().stream().map(this::doSwitch).collect( + new Joiner(", ", "(", ")")) ); // TODO: Delete the following case when the corresponding feature is removed - if (object.getHost() != null) sb.append(" at ").append(doSwitch(object.getHost())); - return sb.toString(); + if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); + return msb.get(); } @Override - public String caseConnection(Connection object) { + public MalleableString caseConnection(Connection object) { // ((leftPorts += VarRef (',' leftPorts += VarRef)*) // | ( '(' leftPorts += VarRef (',' leftPorts += VarRef)* ')' iterated ?= '+'?)) // ('->' | physical?='~>') @@ -540,25 +545,29 @@ public String caseConnection(Connection object) { // ('after' delay=Expression)? // (serializer=Serializer)? // ';'? - StringBuilder sb = new StringBuilder(); - if (object.isIterated()) sb.append("("); - sb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); - if (object.isIterated()) sb.append(")+"); - sb.append(object.isPhysical() ? " ~> " : " -> "); - sb.append(object.getRightPorts().stream().map(this::doSwitch).collect(Collectors.joining(", "))); - if (object.getDelay() != null) sb.append(" after ").append(doSwitch(object.getDelay())); - if (object.getSerializer() != null) sb.append(" ").append(doSwitch(object.getSerializer())); - return sb.toString(); + Builder msb = new Builder(); + if (object.isIterated()) msb.append("("); + msb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); + if (object.isIterated()) msb.append(")+"); + msb.append(object.isPhysical() ? " ~> " : " -> "); + msb.append(object.getRightPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); + if (object.getDelay() != null) msb.append(" after ").append(doSwitch(object.getDelay())); + if (object.getSerializer() != null) msb.append(" ").append(doSwitch(object.getSerializer())); + return msb.get(); } @Override - public String caseSerializer(Serializer object) { + public MalleableString caseSerializer(Serializer object) { // 'serializer' type=STRING - return String.format("serializer \"%s\"", object.getType()); + return new Builder() + .append("serializer \"") + .append(object.getType()) + .append("\"") + .get(); } @Override - public String caseKeyValuePairs(KeyValuePairs object) { + public MalleableString caseKeyValuePairs(KeyValuePairs object) { // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' return list( object.getPairs(), @@ -570,21 +579,25 @@ public String caseKeyValuePairs(KeyValuePairs object) { } @Override - public String caseKeyValuePair(KeyValuePair object) { + public MalleableString caseKeyValuePair(KeyValuePair object) { // name=Kebab ':' value=Element - return object.getName() + ": " + doSwitch(object.getValue()); + return new Builder() + .append(object.getName()) + .append(": ") + .append(doSwitch(object.getValue())) + .get(); } @Override - public String caseArray(Array object) { + public MalleableString caseArray(Array object) { // '[' elements+=Element (',' (elements+=Element))* ','? ']' return object.getElements().stream().map(this::doSwitch).collect( - Collectors.joining(", ", "[", "]") + new Joiner(", ", "[", "]") ); } @Override - public String caseElement(Element object) { + public MalleableString caseElement(Element object) { // keyvalue=KeyValuePairs // | array=Array // | literal=Literal @@ -592,60 +605,68 @@ public String caseElement(Element object) { // | id=Path if (object.getKeyvalue() != null) return doSwitch(object.getKeyvalue()); if (object.getArray() != null) return doSwitch(object.getArray()); - if (object.getLiteral() != null) return object.getLiteral(); - if (object.getId() != null) return object.getId(); - if (object.getUnit() != null) return String.format("%d %s", object.getTime(), object.getUnit()); - return String.valueOf(object.getTime()); + if (object.getLiteral() != null) return MalleableString.anyOf(object.getLiteral()); + if (object.getId() != null) return MalleableString.anyOf(object.getId()); + if (object.getUnit() != null) return MalleableString.anyOf( + String.format("%d %s", object.getTime(), object.getUnit()) + ); + return MalleableString.anyOf(String.valueOf(object.getTime())); } @Override - public String caseTypedVariable(TypedVariable object) { + public MalleableString caseTypedVariable(TypedVariable object) { // Port | Action return defaultCase(object); } @Override - public String caseVariable(Variable object) { + public MalleableString caseVariable(Variable object) { // TypedVariable | Timer | Mode return defaultCase(object); } @Override - public String caseAssignment(Assignment object) { + public MalleableString caseAssignment(Assignment object) { // (lhs=[Parameter] ( // (equals='=' rhs+=Expression) // | ((equals='=')? ( // parens+='(' (rhs+=Expression (',' rhs+=Expression)*)? parens+=')' // | braces+='{' (rhs+=Expression (',' rhs+=Expression)*)? braces+='}')) // )); - StringBuilder sb = new StringBuilder(); - sb.append(object.getLhs().getName()); - if (object.getEquals() != null) sb.append(" = "); - if (!object.getParens().isEmpty()) sb.append("("); - if (!object.getBraces().isEmpty()) sb.append("{"); - sb.append(object.getRhs().stream().map(this::doSwitch).collect(Collectors.joining(", ", "", ""))); - if (!object.getParens().isEmpty()) sb.append(")"); - if (!object.getBraces().isEmpty()) sb.append("}"); - return sb.toString(); + Builder msb = new Builder(); + msb.append(object.getLhs().getName()); + if (object.getEquals() != null) msb.append(" = "); + if (!object.getParens().isEmpty()) msb.append("("); + if (!object.getBraces().isEmpty()) msb.append("{"); + msb.append(object.getRhs().stream() + .map(this::doSwitch) + .collect(new Joiner(", ", "", ""))); + if (!object.getParens().isEmpty()) msb.append(")"); + if (!object.getBraces().isEmpty()) msb.append("}"); + return msb.get(); } @Override - public String caseParameter(Parameter object) { + public MalleableString caseParameter(Parameter object) { // name=ID (':' (type=Type))? // ((parens+='(' (init+=Expression (',' init+=Expression)*)? parens+=')') // | (braces+='{' (init+=Expression (',' init+=Expression)*)? braces+='}') // )? - return object.getName() + typeAnnotationFor(object.getType()) + list( - object.getInit(), - ", ", - object.getBraces().isEmpty() ? "(" : "{", - object.getBraces().isEmpty() ? ")" : "}", - true - ); + return new Builder() + .append(object.getName()) + .append(typeAnnotationFor(object.getType())) + .append(list( + object.getInit(), + ", ", + object.getBraces().isEmpty() ? "(" : "{", + object.getBraces().isEmpty() ? ")" : "}", + true + )) + .get(); } @Override - public String caseExpression(Expression object) { + public MalleableString caseExpression(Expression object) { // {Literal} literal = Literal // | Time // | ParameterReference @@ -654,56 +675,56 @@ public String caseExpression(Expression object) { } @Override - public String casePort(Port object) { + public MalleableString casePort(Port object) { // Input | Output return defaultCase(object); } @Override - public String caseWidthSpec(WidthSpec object) { + public MalleableString caseWidthSpec(WidthSpec object) { // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; - if (object.isOfVariableLength()) return "[]"; + if (object.isOfVariableLength()) return MalleableString.anyOf("[]"); return list(object.getTerms(), " + ", "[", "]", false); } @Override - public String caseWidthTerm(WidthTerm object) { + public MalleableString caseWidthTerm(WidthTerm object) { // width=INT // | parameter=[Parameter] // | 'widthof(' port=VarRef ')' // | code=Code; if (object.getWidth() != 0) { - return Objects.toString(object.getWidth()); + return MalleableString.anyOf(object.getWidth()); } else if (object.getParameter() != null) { - return object.getParameter().getName(); + return MalleableString.anyOf(object.getParameter().getName()); } else if (object.getPort() != null) { - return String.format("widthof(%s)", object.getPort()); + return new Builder().append("widthof(").append(object.getPort()).append(")").get(); } else if (object.getCode() != null) { return doSwitch(object.getCode()); } - throw new IllegalArgumentException(); + throw new IllegalArgumentException("A WidthTerm should not be totally nullish/zeroish."); } @Override - public String caseIPV4Host(IPV4Host object) { + public MalleableString caseIPV4Host(IPV4Host object) { // (user=Kebab '@')? addr=IPV4Addr (':' port=INT)? return caseHost(object); } @Override - public String caseIPV6Host(IPV6Host object) { + public MalleableString caseIPV6Host(IPV6Host object) { // ('[' (user=Kebab '@')? addr=IPV6Addr ']' (':' port=INT)?) return caseHost(object); } @Override - public String caseNamedHost(NamedHost object) { + public MalleableString caseNamedHost(NamedHost object) { // (user=Kebab '@')? addr=HostName (':' port=INT)? return caseHost(object); } @Override - public String defaultCase(EObject object) { + public MalleableString defaultCase(EObject object) { throw new UnsupportedOperationException(String.format( "ToText has no case for %s or any of its supertypes, or it does have such a case, but " + "the return value of that case was null.", @@ -713,14 +734,15 @@ public String defaultCase(EObject object) { /** * Wrap a multi-line String based on the current state of lineWrap and indentLvl. - * If lineWrap is 0, returns orgString. Otherwise, breaks lines such that if possible, each line has less than + * If lineWrap is 0, returns originalString. Otherwise, breaks lines such that if possible, each line has less than * (lineWrap - (indentLvl * INDENTATION) % lineWrap) characters, only breaking at spaces. - * @param orgString The String to wrap. + * @param originalString The String to wrap. * @return The wrapped String. */ - private String wrapLines(String orgString) { - if (lineWrap == 0) return orgString; - return orgString.lines().map(this::wrapIndividualLine).collect(Collectors.joining(System.lineSeparator())); + private String wrapLines(String originalString, int lineWrap, int indentLevel) { + if (lineWrap == 0) return originalString; + return originalString.lines().map(s -> wrapIndividualLine(s, lineWrap, indentLevel)) + .collect(Collectors.joining(System.lineSeparator())); } /** @@ -728,8 +750,8 @@ private String wrapLines(String orgString) { * @param line The line to wrap. * @return The wrapped line. */ - private String wrapIndividualLine(String line) { - int wrapLength = lineWrap - (indentLvl * INDENTATION) % lineWrap; + private String wrapIndividualLine(String line, int lineWrap, int indentLevel) { + int wrapLength = lineWrap - indentLevel * INDENTATION % lineWrap; StringBuilder sb = new StringBuilder(); while (line.length() > wrapLength) { // try to wrap at space @@ -742,7 +764,7 @@ private String wrapIndividualLine(String line) { index = line.indexOf(' ', wrapLength); } else { // large indent - don't skip over any space so that indents are consistent - sb.append(line.substring(0, index) + System.lineSeparator()); + sb.append(line, 0, index).append(System.lineSeparator()); line = line.substring(index); continue; } @@ -768,22 +790,18 @@ private String wrapIndividualLine(String line) { * @param nothingIfEmpty Whether the result should be simplified to the * empty string as opposed to just the prefix and suffix. */ - private String list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { - if (nothingIfEmpty && items.isEmpty()) return ""; - return items.stream().map(this::wrapped).collect(Collectors.joining(delimiter, prefix, suffix)); - } - - private String wrapped(E item) { - return wrapLines(doSwitch(item)); + private MalleableString list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { + if (nothingIfEmpty && items.isEmpty()) return MalleableString.anyOf(""); + return items.stream().map(this::doSwitch).collect(new Joiner(delimiter, prefix, suffix)); } - private String list(EList items) { + private MalleableString list(EList items) { return list(items, ", ", "(", ")", true); } - private String typeAnnotationFor(Type type) { - if (type == null) return ""; - return String.format(": %s", doSwitch(type)); + private MalleableString typeAnnotationFor(Type type) { + if (type == null) return MalleableString.anyOf(""); + return new Builder().append(": ").append(doSwitch(type)).get(); } /** @@ -793,9 +811,8 @@ private String typeAnnotationFor(Type type) { * minimum, to be inserted between everything. * @return A string representation of {@code statementListList}. */ - private String indentedStatements(List> statementListList, int extraSeparation) { - indentLvl++; - String ret = statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( + private MalleableString indentedStatements(List> statementListList, int extraSeparation) { + return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( statementList -> list( statementList, System.lineSeparator().repeat(1 + extraSeparation), @@ -804,9 +821,7 @@ private String indentedStatements(List> statementListLi true ) ).collect( - Collectors.joining(System.lineSeparator().repeat(2 + extraSeparation), "", "") + new Joiner(System.lineSeparator().repeat(2 + extraSeparation), "", "") ).indent(INDENTATION); - indentLvl--; - return ret; } } diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index f0b1feed15..cf82d733c4 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -33,7 +33,7 @@ public class ToText extends LfSwitch { @Override public String caseArraySpec(ArraySpec spec) { - return ToLf.instance.doSwitch(spec); + return ToLf.instance.doSwitch(spec).toString(); } @Override @@ -71,22 +71,22 @@ public String caseCode(Code code) { @Override public String caseHost(Host host) { - return ToLf.instance.caseHost(host); + return ToLf.instance.caseHost(host).toString(); } @Override public String caseLiteral(Literal l) { - return ToLf.instance.caseLiteral(l); + return ToLf.instance.caseLiteral(l).toString(); } @Override public String caseParameterReference(ParameterReference p) { - return ToLf.instance.caseParameterReference(p); + return ToLf.instance.caseParameterReference(p).toString(); } @Override public String caseTime(Time t) { - return ToLf.instance.caseTime(t); + return ToLf.instance.caseTime(t).toString(); } @Override @@ -99,7 +99,7 @@ public String caseType(Type type) { @Override public String caseTypeParm(TypeParm t) { if (t.getCode() != null) return doSwitch(t.getCode()); - return ToLf.instance.caseTypeParm(t); + return ToLf.instance.caseTypeParm(t).toString(); } @Override From f26efaf6d7d269d5f367b9cac0abcc6d173f1365 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Tue, 28 Jun 2022 21:51:04 -0700 Subject: [PATCH 046/130] [formatting] RoundTripTest passes again. --- .../src/org/lflang/ast/MalleableString.java | 34 +++++++++----- org.lflang/src/org/lflang/ast/ToLf.java | 45 ++++++++++++------- test/TypeScript/src/CountTest.lf | 3 +- 3 files changed, 53 insertions(+), 29 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index f2efef7364..38dd0f7e73 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -9,10 +9,12 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; @@ -38,7 +40,11 @@ static MalleableString anyOf(String... possibilities) { } static MalleableString anyOf(Object... possibilities) { - return new Leaf((String[]) Arrays.stream(possibilities).map(String::valueOf).toArray()); + String[] ret = new String[possibilities.length]; + for (int i = 0; i < possibilities.length; i++) { + ret[i] = String.valueOf(possibilities[i]); + } + return new Leaf(ret); } final class Builder { @@ -46,11 +52,15 @@ final class Builder { List components = new ArrayList<>(); Builder append(MalleableString... possibilities) { - return append(Function.identity(), Fork::new, possibilities); + return insert(Function.identity(), Fork::new, possibilities, components::add); + } + + Builder prepend(MalleableString... possibilities) { + return insert(Function.identity(), Fork::new, possibilities, ms -> components.add(0, ms)); } Builder append(String... content) { - return append(Leaf::new, Leaf::new, content); + return insert(Leaf::new, Leaf::new, content, components::add); } Builder append(Object... content) { @@ -61,10 +71,11 @@ MalleableString get() { return new Sequence(ImmutableList.copyOf(components)); } - private Builder append( + private Builder insert( Function toMalleableString, Function multiplePossibilitiesRepresenter, - T[] possibilities + T[] possibilities, + Consumer addToComponents ) { if ( Arrays.stream(possibilities) @@ -76,9 +87,9 @@ private Builder append( if (possibilities.length == 1) { // The resulting MalleableString may be a sequence. // Stay flat: Let there be no sequences in sequences! - toMalleableString.apply(possibilities[0]).forEach(components::add); + toMalleableString.apply(possibilities[0]).forEach(addToComponents); } else { - components.add(multiplePossibilitiesRepresenter.apply(possibilities)); + addToComponents.accept(multiplePossibilitiesRepresenter.apply(possibilities)); } return this; } @@ -90,7 +101,7 @@ final class Joiner implements Collector< MalleableString > { private final Function appendSeparator; - private final Function appendPrefix; + private final Function prependPrefix; private final Function appendSuffix; public Joiner() { this(MalleableString.anyOf(", ")); } @@ -102,7 +113,7 @@ public Joiner(MalleableString separator) { public Joiner(MalleableString separator, MalleableString prefix, MalleableString suffix) { this.appendSeparator = builder -> builder.components.isEmpty() ? builder : builder.append(separator); - this.appendPrefix = builder -> builder.append(prefix); + this.prependPrefix = builder -> builder.prepend(prefix); this.appendSuffix = builder -> builder.append(suffix); } @@ -116,11 +127,12 @@ public Joiner(String separator, String prefix, String suffix) { MalleableString.anyOf(prefix), MalleableString.anyOf(suffix) ); + } @Override public Supplier supplier() { - return () -> appendPrefix.apply(new Builder()); + return Builder::new; } @Override @@ -138,7 +150,7 @@ public BinaryOperator combiner() { @Override public Function finisher() { - return ((Function) Builder::get).compose(appendSuffix); + return ((Function) Builder::get).compose(appendSuffix).compose(prependPrefix); } @Override diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 2bd9ebeeb0..b8e3b16a05 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -71,9 +71,6 @@ public class ToLf extends LfSwitch { /** The number of spaces to prepend to a line per indentation level. */ private static final int INDENTATION = 4; - // FIXME: This class needs to respect comments, which are lost at the EObject level of abstraction and must be - // obtained using NodeModelUtils like this: https://github.com/lf-lang/lingua-franca/blob/c4dfbd9cebdb9aaf249508360e0bac1ce545458b/org.lflang/src/org/lflang/ASTUtils.java#L1692 - /// public instance initialized when loading the class public static final ToLf instance = new ToLf(); @@ -84,6 +81,7 @@ public class ToLf extends LfSwitch { public MalleableString caseArraySpec(ArraySpec spec) { return MalleableString.anyOf( spec.isOfVariableLength() ? "[]" : "[" + spec.getLength() + "]" + // TODO: Multiline arrayspec ); } @@ -144,7 +142,7 @@ public MalleableString caseType(Type type) { if (type.isTime()) { msb.append("time"); } else if (type.getId() != null) { - msb.append(type.getId()); + msb.append(type.getId()); // TODO: Multiline dottedName? if (type.getTypeParms() != null) { msb.append(list(type.getTypeParms(), ", ", "<", ">", true)); } @@ -168,6 +166,7 @@ public MalleableString caseVarRef(VarRef v) { // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' if (!v.isInterleaved()) return MalleableString.anyOf(ToText.instance.doSwitch(v)); + // TODO: Break in parens after interleaved? return MalleableString.anyOf(String.format("interleaved (%s)", ToText.instance.doSwitch(v))); } @@ -195,6 +194,7 @@ public MalleableString caseModel(Model object) { @Override public MalleableString caseImport(Import object) { // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? + // TODO: Break this. Break string, break at whitespace outside the string. return MalleableString.anyOf(String.format( "import %s from \"%s\"", list(object.getReactorClasses(), ", ", "", "", false), @@ -285,6 +285,7 @@ private MalleableString reactorHeader(Reactor object) { msb.append(list(object.getParameters())); if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { + // TODO: Break here msb.append(" extends ").append( object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) ); @@ -367,6 +368,7 @@ public MalleableString caseTimer(Timer object) { Builder msb = new Builder(); msb.append("timer ").append(object.getName()); if (object.getOffset() != null) { + // TODO: Break this param list msb.append("("); msb.append(doSwitch(object.getOffset())); if (object.getPeriod() != null) msb.append(", ").append(doSwitch(object.getPeriod())); @@ -419,6 +421,7 @@ public MalleableString caseAction(Action object) { msb.append("action "); msb.append(object.getName()); if (object.getMinDelay() != null) { + // TODO: break this msb.append("(").append(doSwitch(object.getMinDelay())); if (object.getMinSpacing() != null) msb.append(", ").append(doSwitch(object.getMinSpacing())); if (object.getPolicy() != null) msb.append(", \"").append(object.getPolicy()).append("\""); @@ -468,7 +471,7 @@ public MalleableString caseBuiltinTriggerRef(BuiltinTriggerRef object) { public MalleableString caseDeadline(Deadline object) { // 'deadline' '(' delay=Expression ')' code=Code return new Builder() - .append("deadline(") + .append("deadline(")// TODO: line break here .append(doSwitch(object.getDelay())) .append(") ") .append(caseCode(object.getCode())) @@ -479,7 +482,7 @@ public MalleableString caseDeadline(Deadline object) { public MalleableString caseSTP(STP object) { // 'STP' '(' value=Expression ')' code=Code return new Builder() - .append("STP(") + .append("STP(") // TODO: Line break here. Also address redundancy with caseDeadline .append(doSwitch(object.getValue())) .append(") ") .append(doSwitch(object.getCode())) @@ -496,6 +499,7 @@ public MalleableString caseMutation(Mutation object) { Builder msb = new Builder(); msb.append("mutation"); if (!object.getTriggers().isEmpty()) { + // TODO: use list method here msb.append(object.getTriggers().stream().map(this::doSwitch).collect( new Joiner(", ", "(", ")") )); @@ -524,10 +528,12 @@ public MalleableString caseInstantiation(Instantiation object) { if (object.getWidthSpec() != null) msb.append(doSwitch(object.getWidthSpec())); msb.append(" ").append(object.getReactorClass().getName()); if (!object.getTypeParms().isEmpty()) { + // TODO: Use list method msb.append(object.getTypeParms().stream().map(this::doSwitch).collect( new Joiner(", ", "<", ">")) ); } + // TODO: Use list method msb.append(object.getParameters().stream().map(this::doSwitch).collect( new Joiner(", ", "(", ")")) ); @@ -546,10 +552,12 @@ public MalleableString caseConnection(Connection object) { // (serializer=Serializer)? // ';'? Builder msb = new Builder(); + // TODO: break lines here if (object.isIterated()) msb.append("("); msb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); if (object.isIterated()) msb.append(")+"); msb.append(object.isPhysical() ? " ~> " : " -> "); + // TODO: break lines here msb.append(object.getRightPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); if (object.getDelay() != null) msb.append(" after ").append(doSwitch(object.getDelay())); if (object.getSerializer() != null) msb.append(" ").append(doSwitch(object.getSerializer())); @@ -569,13 +577,7 @@ public MalleableString caseSerializer(Serializer object) { @Override public MalleableString caseKeyValuePairs(KeyValuePairs object) { // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' - return list( - object.getPairs(), - String.format(",%n "), - String.format("{%n "), - String.format("%n}"), - true - ); + return list(object.getPairs(), ", ", "{", "}", true); } @Override @@ -591,6 +593,7 @@ public MalleableString caseKeyValuePair(KeyValuePair object) { @Override public MalleableString caseArray(Array object) { // '[' elements+=Element (',' (elements+=Element))* ','? ']' + // TODO: Use list method? and break line return object.getElements().stream().map(this::doSwitch).collect( new Joiner(", ", "[", "]") ); @@ -636,6 +639,7 @@ public MalleableString caseAssignment(Assignment object) { Builder msb = new Builder(); msb.append(object.getLhs().getName()); if (object.getEquals() != null) msb.append(" = "); + // TODO: use list method if (!object.getParens().isEmpty()) msb.append("("); if (!object.getBraces().isEmpty()) msb.append("{"); msb.append(object.getRhs().stream() @@ -698,6 +702,7 @@ public MalleableString caseWidthTerm(WidthTerm object) { } else if (object.getParameter() != null) { return MalleableString.anyOf(object.getParameter().getName()); } else if (object.getPort() != null) { + // TODO: break line here return new Builder().append("widthof(").append(object.getPort()).append(")").get(); } else if (object.getCode() != null) { return doSwitch(object.getCode()); @@ -731,7 +736,7 @@ public MalleableString defaultCase(EObject object) { object.getClass().getName() )); } - + /** * Wrap a multi-line String based on the current state of lineWrap and indentLvl. * If lineWrap is 0, returns originalString. Otherwise, breaks lines such that if possible, each line has less than @@ -744,7 +749,7 @@ private String wrapLines(String originalString, int lineWrap, int indentLevel) { return originalString.lines().map(s -> wrapIndividualLine(s, lineWrap, indentLevel)) .collect(Collectors.joining(System.lineSeparator())); } - + /** * Wrap a single line of String based on the current state of lineWrap and indentLvl. See wrapLines(). * @param line The line to wrap. @@ -770,7 +775,7 @@ private String wrapIndividualLine(String line, int lineWrap, int indentLevel) { } } if (index != -1) { - sb.append(line.substring(0, index) + System.lineSeparator()); + sb.append(line, 0, index).append(System.lineSeparator()); line = line.substring(index + 1); } else { // no spaces remaining at all @@ -790,7 +795,13 @@ private String wrapIndividualLine(String line, int lineWrap, int indentLevel) { * @param nothingIfEmpty Whether the result should be simplified to the * empty string as opposed to just the prefix and suffix. */ - private MalleableString list(List items, String delimiter, String prefix, String suffix, boolean nothingIfEmpty) { + private MalleableString list( + List items, + String delimiter, + String prefix, + String suffix, + boolean nothingIfEmpty + ) { if (nothingIfEmpty && items.isEmpty()) return MalleableString.anyOf(""); return items.stream().map(this::doSwitch).collect(new Joiner(delimiter, prefix, suffix)); } diff --git a/test/TypeScript/src/CountTest.lf b/test/TypeScript/src/CountTest.lf index 9a69b080c0..664b870a97 100644 --- a/test/TypeScript/src/CountTest.lf +++ b/test/TypeScript/src/CountTest.lf @@ -2,7 +2,8 @@ target TypeScript{ timeout : 3 sec }; -import Count from "lib/Count.lf"; +import Count from +"lib/Count.lf"; reactor Test { input c:number; state i:number(0); From e7d3e601c6ff0084ac0262d0ff5abf88fbc816f0 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 29 Jun 2022 17:59:33 -0700 Subject: [PATCH 047/130] [formatting] Line wrapping works. The test still passes. Lines are broken in most of the places where I would break them as a programmer. --- org.lflang.cli/src/org/lflang/cli/Lff.java | 30 ++- .../lflang/tests/compiler/RoundTripTests.java | 5 +- .../src/org/lflang/ast/MalleableString.java | 67 ++++- org.lflang/src/org/lflang/ast/ToLf.java | 245 ++++++++++-------- 4 files changed, 219 insertions(+), 128 deletions(-) diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index 8f18056d0f..907bcbcd70 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -24,6 +24,7 @@ import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; import org.lflang.LocalStrings; +import org.lflang.ast.MalleableString; import org.lflang.ast.ToLf; import org.lflang.util.FileUtil; @@ -38,6 +39,8 @@ * @author {Billy Bao } */ public class Lff extends CliBase { + private static final int DEFAULT_LINE_LENGTH = 100; + /** * Supported CLI options. *

@@ -167,9 +170,8 @@ private void runFormatter(List files) { } } - if (cmd.hasOption(CLIOption.LINE_WRAP.option.getOpt())) { - ToLf.instance.setLineWrap(Integer.parseInt(cmd.getOptionValue(CLIOption.LINE_WRAP.option.getOpt()))); - } + final int lineLength = !cmd.hasOption(CLIOption.LINE_WRAP.option.getOpt()) ? DEFAULT_LINE_LENGTH : + Integer.parseInt(cmd.getOptionValue(CLIOption.LINE_WRAP.option.getOpt())); for (Path path : files) { if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { @@ -177,12 +179,12 @@ private void runFormatter(List files) { } path = path.toAbsolutePath(); if (Files.isDirectory(path) && !cmd.hasOption(CLIOption.NO_RECURSE.option.getLongOpt())) { - formatRecursive(Paths.get("."), path, outputRoot); + formatRecursive(Paths.get("."), path, outputRoot, lineLength); } else { if (outputRoot == null) { - formatSingleFile(path, path); + formatSingleFile(path, path, lineLength); } else { - formatSingleFile(path, outputRoot.resolve(path.getFileName())); + formatSingleFile(path, outputRoot.resolve(path.getFileName()), lineLength); } } } @@ -194,19 +196,20 @@ private void runFormatter(List files) { * @param curPath Current relative path from inputRoot. * @param inputRoot Root directory of input files. * @param outputRoot Root output directory. + * @param lineLength The preferred maximum number of columns per line. */ - private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot) { + private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot, int lineLength) { Path curDir = inputRoot.resolve(curPath); try (var dirStream = Files.newDirectoryStream(curDir)) { for (Path path : dirStream) { Path newPath = curPath.resolve(path.getFileName()); if (Files.isDirectory(path)) { - formatRecursive(newPath, inputRoot, outputRoot); + formatRecursive(newPath, inputRoot, outputRoot, lineLength); } else { if (outputRoot == null) { - formatSingleFile(path, path); + formatSingleFile(path, path, lineLength); } else { - formatSingleFile(path, outputRoot.resolve(newPath)); + formatSingleFile(path, outputRoot.resolve(newPath), lineLength); } } } @@ -218,7 +221,7 @@ private void formatRecursive(Path curPath, Path inputRoot, Path outputRoot) { /** * Load and validate a single file, then format it and output to the given outputPath. */ - private void formatSingleFile(Path file, Path outputPath) { + private void formatSingleFile(Path file, Path outputPath, int lineLength) { file = file.normalize(); outputPath = outputPath.normalize(); final Resource resource = getResource(file); @@ -232,9 +235,10 @@ private void formatSingleFile(Path file, Path outputPath) { exitIfCollectedErrors(); - String res = ToLf.instance.doSwitch(resource.getContents().get(0)); + MalleableString rendered = ToLf.instance.doSwitch(resource.getContents().get(0)); + rendered.findBestRepresentation(rendered::toString, ToLf.astRepresentationComparator(lineLength)); try { - FileUtil.writeToFile(res, outputPath, true); + FileUtil.writeToFile(rendered.toString(), outputPath, true); } catch (IOException e) { if (e instanceof FileAlreadyExistsException) { // only happens if a subdirectory is named with ".lf" at the end diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index f8e6c25e9d..50896a25ac 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -18,6 +18,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.Target; import org.lflang.ast.IsEqual; +import org.lflang.ast.MalleableString; import org.lflang.ast.ToLf; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; @@ -48,7 +49,9 @@ private void run(Path file) throws Exception { Model originalModel = parse(file); System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); - String reformattedTestCase = ToLf.instance.doSwitch(originalModel).toString(); + MalleableString ms = ToLf.instance.doSwitch(originalModel); + ms.findBestRepresentation(ms::toString, ToLf.astRepresentationComparator(30)); + String reformattedTestCase = ms.toString(); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = getResultingModel(file, reformattedTestCase); Assertions.assertNotNull(resultingModel); diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 38dd0f7e73..fa96a16f55 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -3,9 +3,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Objects; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; @@ -14,7 +14,6 @@ import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collectors; -import java.util.stream.Stream; import org.jetbrains.annotations.NotNull; @@ -29,6 +28,8 @@ default MalleableString indent(int indentation) { return new Indented(this, indentation); } + void findBestRepresentation(Supplier representationGetter, Comparator whichRepresentationIsBetter); + boolean isEmpty(); static MalleableString anyOf(MalleableString... possibilities) { @@ -40,11 +41,15 @@ static MalleableString anyOf(String... possibilities) { } static MalleableString anyOf(Object... possibilities) { - String[] ret = new String[possibilities.length]; - for (int i = 0; i < possibilities.length; i++) { - ret[i] = String.valueOf(possibilities[i]); + return new Leaf(objectArrayToString(possibilities)); + } + + static String[] objectArrayToString(Object[] objects) { + String[] ret = new String[objects.length]; + for (int i = 0; i < objects.length; i++) { + ret[i] = String.valueOf(objects[i]); } - return new Leaf(ret); + return ret; } final class Builder { @@ -64,7 +69,7 @@ Builder append(String... content) { } Builder append(Object... content) { - return append((String[]) Arrays.stream(content).map(Objects::toString).toArray()); + return append(objectArrayToString(content)); } MalleableString get() { @@ -93,6 +98,7 @@ private Builder insert( } return this; } + } final class Joiner implements Collector< @@ -127,7 +133,6 @@ public Joiner(String separator, String prefix, String suffix) { MalleableString.anyOf(prefix), MalleableString.anyOf(suffix) ); - } @Override @@ -180,6 +185,16 @@ public Iterator iterator() { return components.iterator(); } + @Override + public void findBestRepresentation( + Supplier representationGetter, + Comparator whichRepresentationIsBetter + ) { + for (MalleableString component : components) { + component.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + } + } + @Override public boolean isEmpty() { return components.stream().allMatch(MalleableString::isEmpty); @@ -201,6 +216,14 @@ public MalleableString indent(int indentation) { return new Indented(nested, this.indentation + indentation); } + @Override + public void findBestRepresentation( + Supplier representationGetter, + Comparator whichRepresentationIsBetter + ) { + nested.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + } + @Override public boolean isEmpty() { return nested.isEmpty(); @@ -214,13 +237,20 @@ public Iterator iterator() { @Override public String toString() { - return nested.toString().indent(indentation); + var nestedString = nested.toString(); + var ret = nestedString.indent(indentation); + if (!nested.toString().endsWith(System.lineSeparator())) { + ret = ret.substring(0, ret.length() - System.lineSeparator().length()); + } + return ret; } } abstract class MalleableStringImpl implements MalleableString { protected abstract List getPossibilities(); + protected Object bestPossibility; + @Override public String toString() { if (getPossibilities().isEmpty()) { @@ -229,7 +259,7 @@ public String toString() { + "by at least one String." ); } - return getPossibilities().get(0).toString(); + return bestPossibility == null ? getPossibilities().get(0).toString() : bestPossibility.toString(); } @NotNull @@ -237,6 +267,23 @@ public String toString() { public Iterator iterator() { return Collections.singleton((MalleableString) this).iterator(); } + + @Override + public void findBestRepresentation( + Supplier representationGetter, + Comparator whichRepresentationIsBetter + ) { + bestPossibility = Collections.min(getPossibilities(), (a, b) -> { + bestPossibility = a; + String resultA = representationGetter.get(); + bestPossibility = b; + String resultB = representationGetter.get(); + return whichRepresentationIsBetter.compare(resultA, resultB); + }); + if (bestPossibility instanceof MalleableString ms) { + ms.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + } + } } final class Fork extends MalleableStringImpl { diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index b8e3b16a05..a74c2478c1 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -1,6 +1,10 @@ package org.lflang.ast; +import java.util.Arrays; +import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -77,12 +81,23 @@ public class ToLf extends LfSwitch { // private constructor private ToLf() { super(); } + public static Comparator astRepresentationComparator(int lineLength) { + return Comparator.comparing(countCharactersViolatingLineLength(lineLength)) + .thenComparing(ToLf::countNewlines); + } + + private static Function countCharactersViolatingLineLength(int lineLength) { + return s -> s.lines().mapToInt(it -> Math.max(0, it.length() - lineLength)).sum(); + } + + private static long countNewlines(String s) { + return s.lines().count(); + } + @Override public MalleableString caseArraySpec(ArraySpec spec) { - return MalleableString.anyOf( - spec.isOfVariableLength() ? "[]" : "[" + spec.getLength() + "]" - // TODO: Multiline arrayspec - ); + if (spec.isOfVariableLength()) return MalleableString.anyOf("[]"); + return list("", "[", "]", false, false, spec.getLength()); } @Override @@ -144,7 +159,7 @@ public MalleableString caseType(Type type) { } else if (type.getId() != null) { msb.append(type.getId()); // TODO: Multiline dottedName? if (type.getTypeParms() != null) { - msb.append(list(type.getTypeParms(), ", ", "<", ">", true)); + msb.append(list(", ", "<", ">", true, false, type.getTypeParms())); } msb.append("*".repeat(type.getStars().size())); } @@ -166,8 +181,10 @@ public MalleableString caseVarRef(VarRef v) { // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' if (!v.isInterleaved()) return MalleableString.anyOf(ToText.instance.doSwitch(v)); - // TODO: Break in parens after interleaved? - return MalleableString.anyOf(String.format("interleaved (%s)", ToText.instance.doSwitch(v))); + return new Builder() + .append("interleaved ") + .append(list(false, ToText.instance.doSwitch(v))) + .get(); } @Override @@ -195,11 +212,14 @@ public MalleableString caseModel(Model object) { public MalleableString caseImport(Import object) { // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? // TODO: Break this. Break string, break at whitespace outside the string. - return MalleableString.anyOf(String.format( - "import %s from \"%s\"", - list(object.getReactorClasses(), ", ", "", "", false), - object.getImportURI() - )); + return new Builder() + .append("import ") + // TODO: This is a place where we can use conditional parentheses. + .append(list(", ", "", "", false, true, object.getReactorClasses())) + .append(" from \"") + .append(object.getImportURI()) + .append("\"") + .get(); } @Override @@ -267,9 +287,9 @@ public MalleableString caseReactor(Reactor object) { 1 ); msb.append(smallFeatures); - if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) msb.append(System.lineSeparator()); + if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) msb.append(System.lineSeparator().repeat(2)); msb.append(bigFeatures); - msb.append("}"); + msb.append(String.format("%n}")); return msb.get(); } @@ -281,12 +301,18 @@ private MalleableString reactorHeader(Reactor object) { if (object.isRealtime()) msb.append("realtime "); msb.append("reactor"); if (object.getName() != null) msb.append(" ").append(object.getName()); - msb.append(list(object.getTypeParms(), ", ", "<", ">", true)); - msb.append(list(object.getParameters())); + msb.append(list(", ", "<", ">", true, false, object.getTypeParms())); + msb.append(list(true, object.getParameters())); if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); if (object.getSuperClasses() != null && !object.getSuperClasses().isEmpty()) { - // TODO: Break here - msb.append(" extends ").append( + msb.append( + MalleableString.anyOf(" extends "), + new Builder() + .append(System.lineSeparator()) + .append(MalleableString.anyOf("extends ").indent(INDENTATION).indent(INDENTATION)) + .get() + ) + .append( object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) ); } @@ -299,7 +325,9 @@ public MalleableString caseTargetDecl(TargetDecl object) { // 'target' name=ID (config=KeyValuePairs)? ';'? Builder msb = new Builder(); msb.append("target ").append(object.getName()); - if (object.getConfig() != null) msb.append(" ").append(doSwitch(object.getConfig())); + if (object.getConfig() != null && !object.getConfig().getPairs().isEmpty()) { + msb.append(" ").append(doSwitch(object.getConfig())); + } return msb.get(); } @@ -314,8 +342,8 @@ public MalleableString caseStateVar(StateVar object) { Builder msb = new Builder(); msb.append("state ").append(object.getName()); msb.append(typeAnnotationFor(object.getType())); - if (!object.getParens().isEmpty()) msb.append(list(object.getInit())); - if (!object.getBraces().isEmpty()) msb.append(list(object.getInit(), ", ", "{", "}", true)); + if (!object.getParens().isEmpty()) msb.append(list(true, object.getInit())); + if (!object.getBraces().isEmpty()) msb.append(list(", ", "{", "}", true, false, object.getInit())); return msb.get(); } @@ -329,7 +357,7 @@ public MalleableString caseMethod(Method object) { Builder msb = new Builder(); if (object.isConst()) msb.append("const "); msb.append("method ").append(object.getName()); - msb.append(list(object.getArguments(), ", ", "(", ")", false)); + msb.append(list(false, object.getArguments())); msb.append(typeAnnotationFor(object.getReturn())).append(" ").append(doSwitch(object.getCode())); return msb.get(); } @@ -365,16 +393,11 @@ public MalleableString caseOutput(Output object) { @Override public MalleableString caseTimer(Timer object) { // 'timer' name=ID ('(' offset=Expression (',' period=Expression)? ')')? ';'? - Builder msb = new Builder(); - msb.append("timer ").append(object.getName()); - if (object.getOffset() != null) { - // TODO: Break this param list - msb.append("("); - msb.append(doSwitch(object.getOffset())); - if (object.getPeriod() != null) msb.append(", ").append(doSwitch(object.getPeriod())); - msb.append(")"); - } - return msb.get(); + return new Builder() + .append("timer ") + .append(object.getName()) + .append(list(true, object.getOffset(), object.getPeriod())) + .get(); } @Override @@ -407,7 +430,7 @@ public MalleableString caseMode(Mode object) { List.of(object.getReactions()), 1 )); - msb.append("}"); + msb.append(String.format("%n}")); return msb.get(); } @@ -418,17 +441,16 @@ public MalleableString caseAction(Action object) { // (':' type=Type)? ';'? Builder msb = new Builder(); if (object.getOrigin() != null) msb.append(object.getOrigin().getLiteral()).append(" "); - msb.append("action "); - msb.append(object.getName()); - if (object.getMinDelay() != null) { - // TODO: break this - msb.append("(").append(doSwitch(object.getMinDelay())); - if (object.getMinSpacing() != null) msb.append(", ").append(doSwitch(object.getMinSpacing())); - if (object.getPolicy() != null) msb.append(", \"").append(object.getPolicy()).append("\""); - msb.append(")"); - } - msb.append(typeAnnotationFor(object.getType())); - return msb.get(); + return msb.append("action ") + .append(object.getName()) + .append(list( + true, + object.getMinDelay(), + object.getMinSpacing(), + object.getPolicy() != null ? String.format("\"%s\"", object.getPolicy()) : null + )) + .append(typeAnnotationFor(object.getType())) + .get(); } @Override @@ -442,10 +464,10 @@ public MalleableString caseReaction(Reaction object) { // (deadline=Deadline)? Builder msb = new Builder(); msb.append("reaction"); - msb.append(list(object.getTriggers())); - msb.append(list(object.getSources(), ", ", " ", "", true)); + msb.append(list(true, object.getTriggers())); + msb.append(list(", ", " ", "", true, false, object.getSources())); if (!object.getEffects().isEmpty()) { - msb.append(" ->").append(list(object.getEffects(), ", ", " ", "", true)); + msb.append(" ->").append(list(", ", " ", "", true, false, object.getEffects())); } msb.append(" ").append(doSwitch(object.getCode())); if (object.getStp() != null) msb.append(" ").append(doSwitch(object.getStp())); @@ -471,9 +493,9 @@ public MalleableString caseBuiltinTriggerRef(BuiltinTriggerRef object) { public MalleableString caseDeadline(Deadline object) { // 'deadline' '(' delay=Expression ')' code=Code return new Builder() - .append("deadline(")// TODO: line break here - .append(doSwitch(object.getDelay())) - .append(") ") + .append("deadline") + .append(list(false, object.getDelay())) + .append(" ") .append(caseCode(object.getCode())) .get(); } @@ -482,9 +504,9 @@ public MalleableString caseDeadline(Deadline object) { public MalleableString caseSTP(STP object) { // 'STP' '(' value=Expression ')' code=Code return new Builder() - .append("STP(") // TODO: Line break here. Also address redundancy with caseDeadline - .append(doSwitch(object.getValue())) - .append(") ") + .append("STP") + // TODO: Address redundancy with caseDeadline? + .append(list(false, object.getValue())) .append(doSwitch(object.getCode())) .get(); } @@ -496,15 +518,9 @@ public MalleableString caseMutation(Mutation object) { // (sources+=VarRef (',' sources+=VarRef)*)? // ('->' effects+=[VarRef] (',' effects+=[VarRef])*)? // code=Code - Builder msb = new Builder(); - msb.append("mutation"); - if (!object.getTriggers().isEmpty()) { - // TODO: use list method here - msb.append(object.getTriggers().stream().map(this::doSwitch).collect( - new Joiner(", ", "(", ")") - )); - } - return msb.get(); + return new Builder() + .append("mutation").append(list(true, object.getTriggers())) + .get(); } @Override @@ -527,16 +543,8 @@ public MalleableString caseInstantiation(Instantiation object) { msb.append(object.getName()).append(" = new"); if (object.getWidthSpec() != null) msb.append(doSwitch(object.getWidthSpec())); msb.append(" ").append(object.getReactorClass().getName()); - if (!object.getTypeParms().isEmpty()) { - // TODO: Use list method - msb.append(object.getTypeParms().stream().map(this::doSwitch).collect( - new Joiner(", ", "<", ">")) - ); - } - // TODO: Use list method - msb.append(object.getParameters().stream().map(this::doSwitch).collect( - new Joiner(", ", "(", ")")) - ); + msb.append(list(", ", "<", ">", true, false, object.getTypeParms())); + msb.append(list(false, object.getParameters())); // TODO: Delete the following case when the corresponding feature is removed if (object.getHost() != null) msb.append(" at ").append(doSwitch(object.getHost())); return msb.get(); @@ -556,6 +564,7 @@ public MalleableString caseConnection(Connection object) { if (object.isIterated()) msb.append("("); msb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); if (object.isIterated()) msb.append(")+"); + msb.append("", MalleableString.anyOf(System.lineSeparator()).indent(INDENTATION)); msb.append(object.isPhysical() ? " ~> " : " -> "); // TODO: break lines here msb.append(object.getRightPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); @@ -577,7 +586,7 @@ public MalleableString caseSerializer(Serializer object) { @Override public MalleableString caseKeyValuePairs(KeyValuePairs object) { // {KeyValuePairs} '{' (pairs+=KeyValuePair (',' (pairs+=KeyValuePair))* ','?)? '}' - return list(object.getPairs(), ", ", "{", "}", true); + return list(", ", "{ ", " }", true, false, object.getPairs()); } @Override @@ -593,10 +602,7 @@ public MalleableString caseKeyValuePair(KeyValuePair object) { @Override public MalleableString caseArray(Array object) { // '[' elements+=Element (',' (elements+=Element))* ','? ']' - // TODO: Use list method? and break line - return object.getElements().stream().map(this::doSwitch).collect( - new Joiner(", ", "[", "]") - ); + return list(", ", "[", "]", false, false, object.getElements()); } @Override @@ -639,14 +645,9 @@ public MalleableString caseAssignment(Assignment object) { Builder msb = new Builder(); msb.append(object.getLhs().getName()); if (object.getEquals() != null) msb.append(" = "); - // TODO: use list method - if (!object.getParens().isEmpty()) msb.append("("); - if (!object.getBraces().isEmpty()) msb.append("{"); - msb.append(object.getRhs().stream() - .map(this::doSwitch) - .collect(new Joiner(", ", "", ""))); - if (!object.getParens().isEmpty()) msb.append(")"); - if (!object.getBraces().isEmpty()) msb.append("}"); + String prefix = !object.getParens().isEmpty() ? "(" : !object.getBraces().isEmpty() ? "{" : ""; + String suffix = !object.getParens().isEmpty() ? ")" : !object.getBraces().isEmpty() ? "}" : ""; + msb.append(list(", ", prefix, suffix, false, prefix.isBlank(), object.getRhs())); return msb.get(); } @@ -660,11 +661,12 @@ public MalleableString caseParameter(Parameter object) { .append(object.getName()) .append(typeAnnotationFor(object.getType())) .append(list( - object.getInit(), ", ", object.getBraces().isEmpty() ? "(" : "{", object.getBraces().isEmpty() ? ")" : "}", - true + true, + false, + object.getInit() )) .get(); } @@ -688,7 +690,7 @@ public MalleableString casePort(Port object) { public MalleableString caseWidthSpec(WidthSpec object) { // ofVariableLength?='[]' | '[' (terms+=WidthTerm) ('+' terms+=WidthTerm)* ']'; if (object.isOfVariableLength()) return MalleableString.anyOf("[]"); - return list(object.getTerms(), " + ", "[", "]", false); + return list(" + ", "[", "]", false, false, object.getTerms()); } @Override @@ -702,8 +704,10 @@ public MalleableString caseWidthTerm(WidthTerm object) { } else if (object.getParameter() != null) { return MalleableString.anyOf(object.getParameter().getName()); } else if (object.getPort() != null) { - // TODO: break line here - return new Builder().append("widthof(").append(object.getPort()).append(")").get(); + return new Builder() + .append("widthof") + .append(list(false, object.getPort())) + .get(); } else if (object.getCode() != null) { return doSwitch(object.getCode()); } @@ -789,25 +793,62 @@ private String wrapIndividualLine(String line, int lineWrap, int indentLevel) { /** * Represent the given EList as a string. - * @param delimiter The delimiter separating elements of the list. - * @param prefix The token marking the start of the list. * @param suffix The token marking the end of the list. + * @param separator The separator separating elements of the list. + * @param prefix The token marking the start of the list. * @param nothingIfEmpty Whether the result should be simplified to the * empty string as opposed to just the prefix and suffix. + * @param whitespaceRigid Whether any whitespace appearing in the */ private MalleableString list( - List items, - String delimiter, + String separator, String prefix, String suffix, boolean nothingIfEmpty, boolean whitespaceRigid, List items + ) { + return list( + separator, + prefix, + suffix, + nothingIfEmpty, + whitespaceRigid, + (Object[]) items.toArray(EObject[]::new) + ); + } + + private MalleableString list( + String separator, String prefix, String suffix, - boolean nothingIfEmpty + boolean nothingIfEmpty, + boolean whitespaceRigid, + Object... items ) { - if (nothingIfEmpty && items.isEmpty()) return MalleableString.anyOf(""); - return items.stream().map(this::doSwitch).collect(new Joiner(delimiter, prefix, suffix)); + if (nothingIfEmpty && Arrays.stream(items).allMatch(Objects::isNull)) return MalleableString.anyOf(""); + MalleableString rigid = Arrays.stream(items).sequential().filter(Objects::nonNull).map(it -> { + if (it instanceof MalleableString ms) return ms; + if (it instanceof EObject eObject) return doSwitch(eObject); + return MalleableString.anyOf(Objects.toString(it)); + }).collect(new Joiner(separator, prefix, suffix)); + if (whitespaceRigid) return rigid; + return MalleableString.anyOf( + rigid, + new Builder() + .append(prefix.stripTrailing() + System.lineSeparator()) + .append(list( + separator.strip() + System.lineSeparator(), + "", + "", + nothingIfEmpty, + true, + items + ).indent(INDENTATION)).append(System.lineSeparator() + suffix.stripLeading()).get() + ); + } + + private MalleableString list(boolean nothingIfEmpty, EList items) { + return list(", ", "(", ")", nothingIfEmpty, false, items); } - private MalleableString list(EList items) { - return list(items, ", ", "(", ")", true); + private MalleableString list(boolean nothingIfEmpty, Object... items) { + return list(", ", "(", ")", nothingIfEmpty, false, items); } private MalleableString typeAnnotationFor(Type type) { @@ -825,11 +866,7 @@ private MalleableString typeAnnotationFor(Type type) { private MalleableString indentedStatements(List> statementListList, int extraSeparation) { return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( statementList -> list( - statementList, - System.lineSeparator().repeat(1 + extraSeparation), - "", - "", - true + System.lineSeparator().repeat(1 + extraSeparation), "", "", true, true, statementList ) ).collect( new Joiner(System.lineSeparator().repeat(2 + extraSeparation), "", "") From 1baa4be5de6b2d0d197c8d88800b7c6ccc25b20d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 23 Jun 2022 16:45:30 -0700 Subject: [PATCH 048/130] Hook formatter into the Xtext framework. --- org.lflang/META-INF/MANIFEST.MF | 3 +- .../src/org/lflang/GenerateLinguaFranca.mwe2 | 3 ++ .../src/org/lflang/LFRuntimeModule.java | 10 ++++-- .../org/lflang/formatting2/LFFormatter.java | 33 +++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 org.lflang/src/org/lflang/formatting2/LFFormatter.java diff --git a/org.lflang/META-INF/MANIFEST.MF b/org.lflang/META-INF/MANIFEST.MF index 6d52881818..8ed1ce872f 100644 --- a/org.lflang/META-INF/MANIFEST.MF +++ b/org.lflang/META-INF/MANIFEST.MF @@ -35,7 +35,8 @@ Export-Package: org.lflang, org.lflang.serializer, org.lflang.services, org.lflang.util, - org.lflang.validation + org.lflang.validation, + org.lflang.formatting2 Import-Package: org.eclipse.core.resources, org.eclipse.core.runtime;version="3.5.0", org.apache.log4j diff --git a/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 b/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 index dadc6c1c43..f9fd013a4d 100644 --- a/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 +++ b/org.lflang/src/org/lflang/GenerateLinguaFranca.mwe2 @@ -59,6 +59,9 @@ Workflow { projectWizard = { generate = false } + formatter = { + generateStub = true + } } } } diff --git a/org.lflang/src/org/lflang/LFRuntimeModule.java b/org.lflang/src/org/lflang/LFRuntimeModule.java index 79a73fd556..a7c1e80a19 100644 --- a/org.lflang/src/org/lflang/LFRuntimeModule.java +++ b/org.lflang/src/org/lflang/LFRuntimeModule.java @@ -3,11 +3,13 @@ */ package org.lflang; +import org.eclipse.xtext.formatting2.IFormatter2; import org.eclipse.xtext.parser.antlr.ISyntaxErrorMessageProvider; import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy; import org.eclipse.xtext.scoping.IGlobalScopeProvider; import org.eclipse.xtext.validation.INamesAreUniqueValidationHelper; +import org.lflang.formatting2.LFFormatter; import org.lflang.scoping.LFGlobalScopeProvider; import org.lflang.validation.LFNamesAreUniqueValidationHelper; @@ -17,7 +19,7 @@ *

    *
  • LfIdeModule overrides this module with additional * bindings when running in the IDE. - *
  • {@link LFStandaloneModule} overrides this module when + *
  • {@code org.lflang.lfc.LFStandaloneModule} overrides this module when * running LFC standalone. *
*/ @@ -43,9 +45,13 @@ public Class bindISyntaxErrorMessageProvi return LFSyntaxErrorMessageProvider.class; } - /** The error reporter. {@link LFStandaloneModule} overrides this binding. */ + /** The error reporter. {@code org.lflang.lfc.LFStandaloneModule} overrides this binding. */ public Class bindErrorReporter() { return DefaultErrorReporter.class; } + @Override + public Class bindIFormatter2() { + return LFFormatter.class; + } } diff --git a/org.lflang/src/org/lflang/formatting2/LFFormatter.java b/org.lflang/src/org/lflang/formatting2/LFFormatter.java new file mode 100644 index 0000000000..1ff06d97c3 --- /dev/null +++ b/org.lflang/src/org/lflang/formatting2/LFFormatter.java @@ -0,0 +1,33 @@ +/* + * generated by Xtext 2.26.0 + */ +package org.lflang.formatting2; + +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.formatting2.FormatterRequest; +import org.eclipse.xtext.formatting2.IFormatter2; +import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement; +import org.eclipse.xtext.formatting2.regionaccess.ITextSegment; +import org.eclipse.xtext.formatting2.regionaccess.internal.TextReplacement; + +import org.lflang.ast.ToLf; + +public class LFFormatter implements IFormatter2 { + + @Override + public List format(FormatterRequest request) { + ITextSegment documentRegion = request.getTextRegionAccess().regionForDocument(); + List documentContents = request.getTextRegionAccess().getResource().getContents(); + if (documentContents.isEmpty()) return List.of(); + return List.of( + new TextReplacement( + request.getTextRegionAccess(), + documentRegion.getOffset(), + documentRegion.getLength(), + ToLf.instance.doSwitch(documentContents.get(0)) + ) + ); + } +} From 47ff26b31079f3a858d94aafbed638a358c659c7 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 23 Jun 2022 22:12:01 -0700 Subject: [PATCH 049/130] Preserve preceding comments. --- org.lflang/src/org/lflang/ASTUtils.java | 90 ++++++++++++------------- org.lflang/src/org/lflang/ast/ToLf.java | 11 +++ 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index 0f39e701a5..d63d8001c3 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -32,6 +32,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1686,11 +1687,42 @@ public static Reactor toDefinition(ReactorDecl r) { } return null; } + + /** + * Return all single-line or multi-line comments immediately preceding the + * given EObject. + */ + public static List getPrecedingComments(EObject object, boolean singleLine) { + if (!(object.eResource() instanceof XtextResource)) return List.of(); + ICompositeNode compNode = NodeModelUtils.findActualNodeFor(object); + if (compNode == null) return List.of(); + // Find comment node in AST + // For reactions/timers/action/etc., it is usually the lowermost first child node + INode node = compNode.getFirstChild(); + while (node instanceof CompositeNode) { + node = ((CompositeNode) node).getFirstChild(); + } + // For reactors, it seems to be the next sibling of the first child node + if (node == null && compNode.getFirstChild() != null) { + node = compNode.getFirstChild().getNextSibling(); + } + List ret = new ArrayList<>(); + while (node instanceof HiddenLeafNode hlNode) { + if ( + hlNode.getGrammarElement() instanceof TerminalRule tRule + && (singleLine ? "SL_COMMENT" : "ML_COMMENT").equals(tRule.getName()) + ) { + ret.add(node.getText()); + } + node = node.getNextSibling(); + } + return ret; + } /** - * Retrieve a specific annotation in a JavaDoc style comment associated with the given model element in the AST. + * Retrieve a specific annotation in a comment associated with the given model element in the AST. * - * This will look for a JavaDoc style comment. If one is found, it searches for the given annotation `key`. + * This will look for a comment. If one is found, it searches for the given annotation `key`. * and extracts any string that follows the annotation marker. * * @param object the AST model element to search a comment for @@ -1699,52 +1731,14 @@ public static Reactor toDefinition(ReactorDecl r) { * The string immediately following the annotation marker otherwise. */ public static String findAnnotationInComments(EObject object, String key) { - if (object.eResource() instanceof XtextResource) { - ICompositeNode compNode = NodeModelUtils.findActualNodeFor(object); - if (compNode != null) { - // Find comment node in AST - // For reactions/timers/action/etc., it is usually the lowermost first child node - INode node = compNode.getFirstChild(); - while (node instanceof CompositeNode) { - node = ((CompositeNode) node).getFirstChild(); - } - // For reactors, it seems to be the next sibling of the first child node - if (node == null && compNode.getFirstChild() != null) { - node = compNode.getFirstChild().getNextSibling(); - } - while (node instanceof HiddenLeafNode) { // Only comments preceding start of element - HiddenLeafNode hlNode = (HiddenLeafNode) node; - EObject rule = hlNode.getGrammarElement(); - if (rule instanceof TerminalRule) { - String line = null; - TerminalRule tRule = (TerminalRule) rule; - if ("SL_COMMENT".equals(tRule.getName())) { - if (hlNode.getText().contains(key)) { - line = hlNode.getText(); - } - } else if ("ML_COMMENT".equals(tRule.getName())) { - boolean found = false; - for (String str : hlNode.getText().split("\n")) { - if (!found && str.contains(key)) { - line = str; - } - } - // This is shorter but causes a warning: - //line = node.text.split("\n").filterNull.findFirst[it.contains(key)] - } - if (line != null) { - var value = line.substring(line.indexOf(key) + key.length()).trim(); - if (value.contains("*")) { // in case of single line block comment (e.g. /** @anno 1503 */) - value = value.substring(0, value.indexOf("*")).trim(); - } - return value; - } - } - node = node.getNextSibling(); - } - } - } - return null; + return getPrecedingComments(object, true).stream() + .filter(it -> it.contains(key)) + .findFirst().orElse( + getPrecedingComments(object, false).stream() + .filter(it -> it.contains(key)) + .map(it -> it.contains("*") ? it.substring(it.indexOf("*") + 1).trim() : it) + .findFirst().orElse(null) + ); } /** diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index a74c2478c1..5330c7c589 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -7,6 +7,7 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; @@ -100,6 +101,16 @@ public MalleableString caseArraySpec(ArraySpec spec) { return list("", "[", "]", false, false, spec.getLength()); } + @Override + public MalleableString doSwitch(EObject eObject) { + return Stream.concat(Stream.concat( + ASTUtils.getPrecedingComments(eObject, true).stream() + .map(it -> "// " + it), + ASTUtils.getPrecedingComments(eObject, false).stream() + .map(it -> "/*" + it + "*/") + ), Stream.of(super.doSwitch(eObject))).collect(Collectors.joining(System.lineSeparator())); + } + @Override public MalleableString caseCode(Code code) { String content = ToText.instance.doSwitch(code); From bb248028bf8cf9b57063008dcbd16475cbc85c27 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 23 Jun 2022 23:33:47 -0700 Subject: [PATCH 050/130] Bugfixes. This does not handle special cases such as when a line ends with a single-line comment or when single-line comments are used within parameter lists. It only handles the one most common case (comments before major syntactic elements). --- org.lflang/src/org/lflang/ASTUtils.java | 17 +++++++++-------- org.lflang/src/org/lflang/ast/ToLf.java | 11 +++++++---- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index d63d8001c3..beeea0255c 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -37,6 +37,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.eclipse.emf.common.util.EList; @@ -1731,14 +1732,14 @@ public static List getPrecedingComments(EObject object, boolean singleLi * The string immediately following the annotation marker otherwise. */ public static String findAnnotationInComments(EObject object, String key) { - return getPrecedingComments(object, true).stream() - .filter(it -> it.contains(key)) - .findFirst().orElse( - getPrecedingComments(object, false).stream() - .filter(it -> it.contains(key)) - .map(it -> it.contains("*") ? it.substring(it.indexOf("*") + 1).trim() : it) - .findFirst().orElse(null) - ); + return Stream.concat( + getPrecedingComments(object, true).stream(), + getPrecedingComments(object, false).stream().flatMap(String::lines) + ).filter(line -> line.contains(key)) + .map(String::trim) + .map(it -> it.substring(it.indexOf(key) + key.length())) + .map(it -> it.endsWith("*/") ? it.substring(0, it.length() - "*/".length()) : it) + .findFirst().orElse(null); } /** diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 5330c7c589..f900098ad7 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -104,10 +104,13 @@ public MalleableString caseArraySpec(ArraySpec spec) { @Override public MalleableString doSwitch(EObject eObject) { return Stream.concat(Stream.concat( - ASTUtils.getPrecedingComments(eObject, true).stream() - .map(it -> "// " + it), - ASTUtils.getPrecedingComments(eObject, false).stream() - .map(it -> "/*" + it + "*/") + ASTUtils.getPrecedingComments(eObject, true).stream().map(String::trim), + ASTUtils.getPrecedingComments(eObject, false).stream().map( + it -> it.lines() + .map(String::trim) + .map(trimmed -> trimmed.startsWith("*") ? " " + trimmed : trimmed) + .collect(Collectors.joining(System.lineSeparator())) + ) ), Stream.of(super.doSwitch(eObject))).collect(Collectors.joining(System.lineSeparator())); } From 3b87a68ef4bb6c4087ec1c8252b5265105edaa43 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 27 Jun 2022 13:26:41 -0700 Subject: [PATCH 051/130] [formatting] Clean up, cover edge cases. --- org.lflang/src/org/lflang/ASTUtils.java | 62 +++++++++++++++---------- org.lflang/src/org/lflang/ast/ToLf.java | 43 +++++++++++++++-- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index beeea0255c..f8a9298721 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -32,8 +32,8 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -1693,31 +1693,41 @@ public static Reactor toDefinition(ReactorDecl r) { * Return all single-line or multi-line comments immediately preceding the * given EObject. */ - public static List getPrecedingComments(EObject object, boolean singleLine) { - if (!(object.eResource() instanceof XtextResource)) return List.of(); - ICompositeNode compNode = NodeModelUtils.findActualNodeFor(object); - if (compNode == null) return List.of(); - // Find comment node in AST - // For reactions/timers/action/etc., it is usually the lowermost first child node - INode node = compNode.getFirstChild(); - while (node instanceof CompositeNode) { - node = ((CompositeNode) node).getFirstChild(); - } - // For reactors, it seems to be the next sibling of the first child node - if (node == null && compNode.getFirstChild() != null) { - node = compNode.getFirstChild().getNextSibling(); - } + public static List getPrecedingComments( + ICompositeNode compNode, + boolean singleLine, + Predicate filter + ) { List ret = new ArrayList<>(); - while (node instanceof HiddenLeafNode hlNode) { - if ( - hlNode.getGrammarElement() instanceof TerminalRule tRule - && (singleLine ? "SL_COMMENT" : "ML_COMMENT").equals(tRule.getName()) - ) { - ret.add(node.getText()); + getPrecedingCommentsRecursive( + compNode, + ret, + node -> node instanceof HiddenLeafNode hlNode + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && (singleLine ? "SL_COMMENT" : "ML_COMMENT").equals(tRule.getName()) + && filter.test(hlNode) + ); + return ret; + } + + /** + * Add any text satisfying {@code filter} that is at the beginning of the + * text of {@code node} to the list. Return true if {@code node} contains + * anything of semantic significance. + */ + private static boolean getPrecedingCommentsRecursive( + INode node, + List precedingComments, + Predicate filter + ) { + if (node instanceof ICompositeNode compositeNode) { + for (INode child : compositeNode.getChildren()) { + if (getPrecedingCommentsRecursive(child, precedingComments, filter)) return true; } - node = node.getNextSibling(); + } else if (filter.test(node)) { + precedingComments.add(node.getText()); } - return ret; + return !(node instanceof HiddenLeafNode) && !(node instanceof CompositeNode); } /** @@ -1732,9 +1742,11 @@ public static List getPrecedingComments(EObject object, boolean singleLi * The string immediately following the annotation marker otherwise. */ public static String findAnnotationInComments(EObject object, String key) { + if (!(object.eResource() instanceof XtextResource)) return null; + ICompositeNode node = NodeModelUtils.findActualNodeFor(object); return Stream.concat( - getPrecedingComments(object, true).stream(), - getPrecedingComments(object, false).stream().flatMap(String::lines) + getPrecedingComments(node, true, n -> true).stream(), + getPrecedingComments(node, false, n -> true).stream().flatMap(String::lines) ).filter(line -> line.contains(key)) .map(String::trim) .map(it -> it.substring(it.indexOf(key) + key.length())) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index f900098ad7..9d770ac606 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -11,6 +11,10 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.nodemodel.ICompositeNode; +import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; import org.lflang.ASTUtils; @@ -103,15 +107,48 @@ public MalleableString caseArraySpec(ArraySpec spec) { @Override public MalleableString doSwitch(EObject eObject) { + ICompositeNode node = NodeModelUtils.findActualNodeFor(eObject); + String representation = super.doSwitch(eObject); + String followingComments = getFollowingComments(node); + if (!followingComments.isBlank()) representation += " " + followingComments; + List immediatelyPrecedingComments = ASTUtils.getPrecedingComments(node, false, sameLine(node)); + representation = String.join("", immediatelyPrecedingComments) + representation; + var previous = node.getPreviousSibling(); + Predicate doesNotBelongToPrevious = sameLine(node).negate().and( + previous == null ? n -> true : sameLine(previous).negate() + ); return Stream.concat(Stream.concat( - ASTUtils.getPrecedingComments(eObject, true).stream().map(String::trim), - ASTUtils.getPrecedingComments(eObject, false).stream().map( + ASTUtils.getPrecedingComments(node, true, doesNotBelongToPrevious).stream().map(String::trim), + ASTUtils.getPrecedingComments(node, false, doesNotBelongToPrevious).stream().map( it -> it.lines() .map(String::trim) .map(trimmed -> trimmed.startsWith("*") ? " " + trimmed : trimmed) .collect(Collectors.joining(System.lineSeparator())) ) - ), Stream.of(super.doSwitch(eObject))).collect(Collectors.joining(System.lineSeparator())); + ), Stream.of(representation)).collect(Collectors.joining(System.lineSeparator())); + } + + private ICompositeNode getNextCompositeSibling(INode node) { + INode sibling = node; + while ((sibling = sibling.getNextSibling()) != null) { + if (sibling instanceof ICompositeNode compositeSibling) return compositeSibling; + if (!(sibling.getGrammarElement() instanceof Keyword) || sibling.getText().contains("\n")) break; + } + return null; + } + + private String getFollowingComments(ICompositeNode node) { + ICompositeNode sibling = getNextCompositeSibling(node); + if (sibling == null) return ""; + Predicate filter = sameLine(node).and(sameLine(sibling).negate()); + return Stream.concat( + ASTUtils.getPrecedingComments(sibling, false, filter).stream(), + ASTUtils.getPrecedingComments(sibling, true, filter).stream() + ).collect(Collectors.joining(" ")).trim(); + } + + private Predicate sameLine(INode node) { + return other -> node.getStartLine() <= other.getStartLine() && other.getStartLine() <= node.getEndLine(); } @Override From 129828787df37f121bffb929b9bf7de15f1c30b1 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 30 Jun 2022 21:35:24 -0700 Subject: [PATCH 052/130] [formatting] Comments are inserted. This way of doing it is more complex than the previous implementation, but it may be more general and less prone to awkward edge cases. --- .../lflang/tests/compiler/RoundTripTests.java | 2 +- .../src/org/lflang/ast/MalleableString.java | 224 ++++++++++++++---- org.lflang/src/org/lflang/ast/ToLf.java | 44 ++-- .../org/lflang/formatting2/LFFormatter.java | 2 +- 4 files changed, 205 insertions(+), 67 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 50896a25ac..51ed49c20e 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -49,7 +49,7 @@ private void run(Path file) throws Exception { Model originalModel = parse(file); System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); - MalleableString ms = ToLf.instance.doSwitch(originalModel); + MalleableString ms = new MalleableString.Builder().append(ToLf.instance.doSwitch(originalModel)).get(); ms.findBestRepresentation(ms::toString, ToLf.astRepresentationComparator(30)); String reformattedTestCase = ms.toString(); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index fa96a16f55..7b3b92f0ce 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -12,39 +13,57 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.regex.Pattern; import java.util.stream.Collector; -import java.util.stream.Collectors; - -import org.jetbrains.annotations.NotNull; +import java.util.stream.IntStream; +import java.util.stream.Stream; import com.google.common.collect.ImmutableList; -public interface MalleableString extends Iterable { +public abstract class MalleableString implements Iterable { + + protected List comments = new ArrayList<>(); - default MalleableString indent(int indentation) { + public MalleableString indent(int indentation) { if (indentation < 0) { throw new IllegalArgumentException("Indentation must be nonnegative."); } return new Indented(this, indentation); } - void findBestRepresentation(Supplier representationGetter, Comparator whichRepresentationIsBetter); + public abstract void findBestRepresentation( + Supplier representationGetter, + Comparator whichRepresentationIsBetter + ); + + public abstract boolean isEmpty(); - boolean isEmpty(); + public MalleableString addComments(Collection comments) { + return addComments(comments.stream()); + } + + public MalleableString addComments(Stream comments) { + comments.filter(s -> !s.isBlank()).map(String::strip).forEach(this.comments::add); + return this; + } - static MalleableString anyOf(MalleableString... possibilities) { + protected Stream getUnhandledComments() { + return comments.stream(); + } + + public static MalleableString anyOf(MalleableString... possibilities) { return new Fork(possibilities); } - static MalleableString anyOf(String... possibilities) { + public static MalleableString anyOf(String... possibilities) { return new Leaf(possibilities); } - static MalleableString anyOf(Object... possibilities) { + public static MalleableString anyOf(Object... possibilities) { return new Leaf(objectArrayToString(possibilities)); } - static String[] objectArrayToString(Object[] objects) { + private static String[] objectArrayToString(Object[] objects) { String[] ret = new String[objects.length]; for (int i = 0; i < objects.length; i++) { ret[i] = String.valueOf(objects[i]); @@ -52,27 +71,28 @@ static String[] objectArrayToString(Object[] objects) { return ret; } - final class Builder { + public static final class Builder { - List components = new ArrayList<>(); + private List components = new ArrayList<>(); - Builder append(MalleableString... possibilities) { + public Builder append(MalleableString... possibilities) { return insert(Function.identity(), Fork::new, possibilities, components::add); } - Builder prepend(MalleableString... possibilities) { + public Builder prepend(MalleableString... possibilities) { return insert(Function.identity(), Fork::new, possibilities, ms -> components.add(0, ms)); } - Builder append(String... content) { + public Builder append(String... content) { return insert(Leaf::new, Leaf::new, content, components::add); } - Builder append(Object... content) { + @SuppressWarnings("UnusedReturnValue") + public Builder append(Object... content) { return append(objectArrayToString(content)); } - MalleableString get() { + public MalleableString get() { return new Sequence(ImmutableList.copyOf(components)); } @@ -89,19 +109,19 @@ private Builder insert( ) { return this; } - if (possibilities.length == 1) { - // The resulting MalleableString may be a sequence. - // Stay flat: Let there be no sequences in sequences! - toMalleableString.apply(possibilities[0]).forEach(addToComponents); - } else { +// if (possibilities.length == 1) { +// // The resulting MalleableString may be a sequence. +// // Stay flat: Let there be no sequences in sequences! +// toMalleableString.apply(possibilities[0]).forEach(addToComponents); +// } else { addToComponents.accept(multiplePossibilitiesRepresenter.apply(possibilities)); - } +// } return this; } } - final class Joiner implements Collector< + public static final class Joiner implements Collector< MalleableString, Builder, MalleableString @@ -110,8 +130,6 @@ final class Joiner implements Collector< private final Function prependPrefix; private final Function appendSuffix; - public Joiner() { this(MalleableString.anyOf(", ")); } - public Joiner(MalleableString separator) { this(separator, MalleableString.anyOf(""), MalleableString.anyOf("")); } @@ -164,22 +182,98 @@ public Set characteristics() { } } - - @SuppressWarnings("ClassCanBeRecord") - final class Sequence implements MalleableString { + private static final class Sequence extends MalleableString { private final ImmutableList components; private Sequence(ImmutableList components) { this.components = components; } + private boolean keepCommentsOnSameLine = false; + @Override public String toString() { - return components.stream() + // TODO: + // find out whether you have any unhandled comments + // if so, optimize the components so that they contain as many newlines as possible + // if you still have no newlines, move on + // if you do have newlines, decide whether to put comments before or on the same line (this will have been + // determined in findBestRepresentation) + // you should have a temporary list of strings corresponding to the components. Modify the strings in the + // list so that the comments all have a home. + List> unhandledComments = components.stream() + .map(MalleableString::getUnhandledComments) + .map(Stream::toList) + .toList(); + List stringComponents = components.stream() .map(MalleableString::toString) - .collect(Collectors.joining("")); - } - - @NotNull + .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + List newLineIndices = IntStream.range(0, stringComponents.size()).sequential() + .filter(i -> stringComponents.get(i).endsWith(System.lineSeparator())) + .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + if (unhandledComments.stream().allMatch(List::isEmpty) || newLineIndices.isEmpty()) { + return String.join("", stringComponents); + } + for (int i = 0; i < unhandledComments.size(); i++) { + placeComments( + String.join(System.lineSeparator(), unhandledComments.get(i)), + stringComponents, + i + ); + } + return String.join("", stringComponents); + } + + private static void placeComments(String unhandledComments, List components, int i) { + if (unhandledComments.isBlank()) return; + for (int j = i - 1; j >= 0; j--) { + if (components.get(j).endsWith(System.lineSeparator())) { + components.set( + j, + components.get(j) + + String.join(System.lineSeparator(), unhandledComments) + + System.lineSeparator() // TODO: Represent the comments correctly + ); + return; + } + } + components.add(0, String.format("%s%n", unhandledComments)); +// List currentlyCollectedComments = new ArrayList<>(); +// if (keepCommentsOnSameLine) { +// for (int i = 0; i < components.size(); i++) { +// currentlyCollectedComments.addAll(unhandledComments.get(i)); +// String current = stringComponents.get(i); +// if (current.endsWith(System.lineSeparator()) && !currentlyCollectedComments.isEmpty()) { +// stringComponents.set( +// i, +// current.replaceFirst( +// "\\s*" + Pattern.quote(System.lineSeparator()), +// " " + String.join(System.lineSeparator(), currentlyCollectedComments) + System.lineSeparator() +// ) // TODO: Represent the comments correctly +// ); +// currentlyCollectedComments.clear(); +// } +// } +// } else { +// for (int i = components.size() - 1; i >= 0; i--) { +// String current = stringComponents.get(i); +// if (current.endsWith(System.lineSeparator()) && !currentlyCollectedComments.isEmpty()) { +// stringComponents.set( +// i, +// current +// + String.join(System.lineSeparator(), currentlyCollectedComments) +// + System.lineSeparator() // TODO: Represent the comments correctly +// ); +// currentlyCollectedComments.clear(); +// } +// currentlyCollectedComments.addAll(0, unhandledComments.get(i)); +// } +// } +// if (!currentlyCollectedComments.isEmpty()) { +// stringComponents.add(0, String.join("", currentlyCollectedComments) + "\n"); // TODO: is this right? +// } + } + + @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { return components.iterator(); @@ -190,6 +284,11 @@ public void findBestRepresentation( Supplier representationGetter, Comparator whichRepresentationIsBetter ) { + keepCommentsOnSameLine = true; + var representationTrue = representationGetter.get(); + keepCommentsOnSameLine = false; + var representationFalse = representationGetter.get(); + keepCommentsOnSameLine = whichRepresentationIsBetter.compare(representationTrue, representationFalse) <= 0; for (MalleableString component : components) { component.findBestRepresentation(representationGetter, whichRepresentationIsBetter); } @@ -199,9 +298,19 @@ public void findBestRepresentation( public boolean isEmpty() { return components.stream().allMatch(MalleableString::isEmpty); } + + @Override + protected Stream getUnhandledComments() { + // FIXME: This is very crude. + return Stream.concat( + super.getUnhandledComments(), + components.stream().anyMatch(it -> it.toString().endsWith(System.lineSeparator())) ? Stream.of() + : components.stream().flatMap(MalleableString::getUnhandledComments) + ); + } } - final class Indented implements MalleableString { + private static final class Indented extends MalleableString { private final int indentation; private final MalleableString nested; @@ -229,7 +338,12 @@ public boolean isEmpty() { return nested.isEmpty(); } - @NotNull + @Override + protected Stream getUnhandledComments() { + return Stream.concat(super.getUnhandledComments(), nested.getUnhandledComments()); + } + + @SuppressWarnings("NullableProblems") @Override public Iterator iterator() { return Collections.singleton((MalleableString) this).iterator(); @@ -239,30 +353,23 @@ public Iterator iterator() { public String toString() { var nestedString = nested.toString(); var ret = nestedString.indent(indentation); - if (!nested.toString().endsWith(System.lineSeparator())) { + if (!nestedString.endsWith(System.lineSeparator()) && ret.endsWith(System.lineSeparator())) { ret = ret.substring(0, ret.length() - System.lineSeparator().length()); } return ret; } } - abstract class MalleableStringImpl implements MalleableString { + private abstract static class MalleableStringImpl extends MalleableString { protected abstract List getPossibilities(); - protected Object bestPossibility; + private Object bestPossibility; @Override public String toString() { - if (getPossibilities().isEmpty()) { - throw new IllegalStateException( - "A MalleableString must be directly or transitively backed " - + "by at least one String." - ); - } - return bestPossibility == null ? getPossibilities().get(0).toString() : bestPossibility.toString(); + return getChosenPossibility().toString(); } - @NotNull @Override public Iterator iterator() { return Collections.singleton((MalleableString) this).iterator(); @@ -284,9 +391,19 @@ public void findBestRepresentation( ms.findBestRepresentation(representationGetter, whichRepresentationIsBetter); } } + + protected Object getChosenPossibility() { + if (getPossibilities().isEmpty()) { + throw new IllegalStateException( + "A MalleableString must be directly or transitively backed " + + "by at least one String." + ); + } + return bestPossibility == null ? getPossibilities().get(0) : bestPossibility; + } } - final class Fork extends MalleableStringImpl { + private static final class Fork extends MalleableStringImpl { private final ImmutableList possibilities; private Fork(MalleableString[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); @@ -299,9 +416,16 @@ private Fork(MalleableString[] possibilities) { public boolean isEmpty() { return possibilities.stream().allMatch(MalleableString::isEmpty); } + + @Override + protected Stream getUnhandledComments() { + Stream nestedUnhandled = getChosenPossibility() instanceof MalleableString ms ? + ms.getUnhandledComments() : Stream.of(); + return Stream.concat(super.getUnhandledComments(), nestedUnhandled); + } } - final class Leaf extends MalleableStringImpl { + private static final class Leaf extends MalleableStringImpl { private final ImmutableList possibilities; private Leaf(String[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 9d770ac606..b88519e296 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -108,24 +108,38 @@ public MalleableString caseArraySpec(ArraySpec spec) { @Override public MalleableString doSwitch(EObject eObject) { ICompositeNode node = NodeModelUtils.findActualNodeFor(eObject); - String representation = super.doSwitch(eObject); - String followingComments = getFollowingComments(node); - if (!followingComments.isBlank()) representation += " " + followingComments; - List immediatelyPrecedingComments = ASTUtils.getPrecedingComments(node, false, sameLine(node)); - representation = String.join("", immediatelyPrecedingComments) + representation; + Stream followingComments = getFollowingComments(node); + List immediatelyPrecedingComments = ASTUtils.getPrecedingComments( + node, + false, + sameLine(node) + ); var previous = node.getPreviousSibling(); Predicate doesNotBelongToPrevious = sameLine(node).negate().and( previous == null ? n -> true : sameLine(previous).negate() ); - return Stream.concat(Stream.concat( - ASTUtils.getPrecedingComments(node, true, doesNotBelongToPrevious).stream().map(String::trim), - ASTUtils.getPrecedingComments(node, false, doesNotBelongToPrevious).stream().map( - it -> it.lines() - .map(String::trim) + Stream singleLinePrecedingComments = ASTUtils.getPrecedingComments( + node, + true, + doesNotBelongToPrevious + ).stream().map(String::trim); + Stream multilinePrecedingComments = ASTUtils.getPrecedingComments( + node, + false, + doesNotBelongToPrevious + ).stream().map( + it -> it.lines() + .map(String::strip) .map(trimmed -> trimmed.startsWith("*") ? " " + trimmed : trimmed) .collect(Collectors.joining(System.lineSeparator())) - ) - ), Stream.of(representation)).collect(Collectors.joining(System.lineSeparator())); + ); + MalleableString representation = super.doSwitch(eObject); + representation + .addComments(singleLinePrecedingComments) + .addComments(multilinePrecedingComments) + .addComments(immediatelyPrecedingComments) + .addComments(followingComments); + return representation; } private ICompositeNode getNextCompositeSibling(INode node) { @@ -137,14 +151,14 @@ private ICompositeNode getNextCompositeSibling(INode node) { return null; } - private String getFollowingComments(ICompositeNode node) { + private Stream getFollowingComments(ICompositeNode node) { ICompositeNode sibling = getNextCompositeSibling(node); - if (sibling == null) return ""; + if (sibling == null) return Stream.of(); Predicate filter = sameLine(node).and(sameLine(sibling).negate()); return Stream.concat( ASTUtils.getPrecedingComments(sibling, false, filter).stream(), ASTUtils.getPrecedingComments(sibling, true, filter).stream() - ).collect(Collectors.joining(" ")).trim(); + ); } private Predicate sameLine(INode node) { diff --git a/org.lflang/src/org/lflang/formatting2/LFFormatter.java b/org.lflang/src/org/lflang/formatting2/LFFormatter.java index 1ff06d97c3..15d613b645 100644 --- a/org.lflang/src/org/lflang/formatting2/LFFormatter.java +++ b/org.lflang/src/org/lflang/formatting2/LFFormatter.java @@ -26,7 +26,7 @@ public List format(FormatterRequest request) { request.getTextRegionAccess(), documentRegion.getOffset(), documentRegion.getLength(), - ToLf.instance.doSwitch(documentContents.get(0)) + ToLf.instance.doSwitch(documentContents.get(0)).toString() ) ); } From b1facb13ecc49c7fd85d3180dc16da0aa16a766c Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 01:15:34 -0700 Subject: [PATCH 053/130] [formatting] Line wrapping for comments works. --- org.lflang.cli/src/org/lflang/cli/Lff.java | 6 +- .../lflang/tests/compiler/RoundTripTests.java | 2 +- .../src/org/lflang/ast/FormattingUtils.java | 81 +++++++++++++++++++ .../src/org/lflang/ast/MalleableString.java | 52 ++++++++---- org.lflang/src/org/lflang/ast/ToLf.java | 50 ------------ 5 files changed, 124 insertions(+), 67 deletions(-) create mode 100644 org.lflang/src/org/lflang/ast/FormattingUtils.java diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index 907bcbcd70..71a9d16ef0 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -236,7 +236,11 @@ private void formatSingleFile(Path file, Path outputPath, int lineLength) { exitIfCollectedErrors(); MalleableString rendered = ToLf.instance.doSwitch(resource.getContents().get(0)); - rendered.findBestRepresentation(rendered::toString, ToLf.astRepresentationComparator(lineLength)); + rendered.findBestRepresentation( + rendered::toString, + ToLf.astRepresentationComparator(lineLength), + lineLength + ); try { FileUtil.writeToFile(rendered.toString(), outputPath, true); } catch (IOException e) { diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 51ed49c20e..c8d930d898 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -50,7 +50,7 @@ private void run(Path file) throws Exception { System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); MalleableString ms = new MalleableString.Builder().append(ToLf.instance.doSwitch(originalModel)).get(); - ms.findBestRepresentation(ms::toString, ToLf.astRepresentationComparator(30)); + ms.findBestRepresentation(ms::toString, ToLf.astRepresentationComparator(30), 30); String reformattedTestCase = ms.toString(); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = getResultingModel(file, reformattedTestCase); diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java new file mode 100644 index 0000000000..e398f6d8bb --- /dev/null +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -0,0 +1,81 @@ +package org.lflang.ast; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Utility functions that determine the specific behavior of the LF formatter. + * @author {Peter Donovan } + * @author {Billy Bao } + */ +public class FormattingUtils { + /** + * The minimum number of columns that should be allotted to a comment. + * This is relevant in case of high indentation/small wrapLength. + */ + private static final int MINIMUM_COMMENT_WIDTH_IN_COLUMNS = 15; + + /** Match a multiline comment with lines starting with stars. */ + private static final Pattern MULTILINE_COMMENT_LINES_STARTING_WITH_STARS = Pattern.compile( + "\\s*/(\\s*\\*(\\S*\\h*)*)+" + ); + + /** + * Break lines at spaces so that each line is no more than {@code width} + * columns long, if possible. Normalize whitespace. + */ + public static String lineWrapComment(String comment, int width) { + width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); + List simpleWhitespace = Arrays.stream( + comment.strip() + .replaceAll("^/?((\\*|//)\\s*)+", "") + .replaceAll("\\s*\\*/$", "") + .replaceAll("(?<=" + System.lineSeparator() + ")\\h*(\\*|//)\\h*", "") + .split(String.format("(%n\\s*){2,}")) + ).map(s -> s.replaceAll("\\s+", " ")) + .toList(); + if (MULTILINE_COMMENT_LINES_STARTING_WITH_STARS.matcher(comment).matches()) { + if (comment.length() < width && simpleWhitespace.size() == 1) { + return String.format("/** %s */", simpleWhitespace.get(0)); + } + return String.format("/**%n%s%n */", lineWrapComment(simpleWhitespace, width, " * ")); + } + return lineWrapComment(simpleWhitespace, width, "// "); + } + + private static String lineWrapComment( + List simpleWhitespace, + int width, + String linePrefix + ) { + width = Math.max(width - linePrefix.length(), MINIMUM_COMMENT_WIDTH_IN_COLUMNS); + return wrapLines(simpleWhitespace, width) + .map(s -> (linePrefix + s.stripLeading()).stripTrailing()) + .collect(Collectors.joining(System.lineSeparator())); + } + + private static Stream wrapLines(List paragraphs, int width) { + var ret = new ArrayList(); + for (String s : paragraphs) { + if (!ret.isEmpty()) ret.add(""); + int numCharactersProcessed = 0; + while (numCharactersProcessed + width < s.length()) { + // try to wrap at space + int breakAt = s.lastIndexOf(' ', numCharactersProcessed + width); + // if unable to find space in limit, extend to the first space we find + if (breakAt < numCharactersProcessed) { + breakAt = s.indexOf(' ', numCharactersProcessed + width); + } + if (breakAt < numCharactersProcessed) breakAt = s.length(); + ret.add(s.substring(numCharactersProcessed, breakAt)); + numCharactersProcessed = breakAt + 1; + } + if (numCharactersProcessed < s.length()) ret.add(s.substring(numCharactersProcessed)); + } + return ret.stream(); + } +} diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 7b3b92f0ce..53f2718dc2 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -13,7 +13,6 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import java.util.regex.Pattern; import java.util.stream.Collector; import java.util.stream.IntStream; import java.util.stream.Stream; @@ -33,7 +32,8 @@ public MalleableString indent(int indentation) { public abstract void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter + Comparator whichRepresentationIsBetter, + int width ); public abstract boolean isEmpty(); @@ -73,7 +73,7 @@ private static String[] objectArrayToString(Object[] objects) { public static final class Builder { - private List components = new ArrayList<>(); + private final List components = new ArrayList<>(); public Builder append(MalleableString... possibilities) { return insert(Function.identity(), Fork::new, possibilities, components::add); @@ -189,6 +189,7 @@ private Sequence(ImmutableList components) { } private boolean keepCommentsOnSameLine = false; + private int width = 0; @Override public String toString() { @@ -217,26 +218,35 @@ public String toString() { placeComments( String.join(System.lineSeparator(), unhandledComments.get(i)), stringComponents, - i + i, + width ); } return String.join("", stringComponents); } - private static void placeComments(String unhandledComments, List components, int i) { + private static void placeComments(String unhandledComments, List components, int i, int width) { if (unhandledComments.isBlank()) return; for (int j = i - 1; j >= 0; j--) { if (components.get(j).endsWith(System.lineSeparator())) { components.set( j, - components.get(j) - + String.join(System.lineSeparator(), unhandledComments) - + System.lineSeparator() // TODO: Represent the comments correctly + components.get(j) + String.format( + "%s%n", + FormattingUtils.lineWrapComment(unhandledComments, width) + ) ); return; } } - components.add(0, String.format("%s%n", unhandledComments)); + components.set( + 0, + String.format( + "%s%n%s", + FormattingUtils.lineWrapComment(unhandledComments, width), + components.isEmpty() ? "" : components.get(0) + ) + ); // List currentlyCollectedComments = new ArrayList<>(); // if (keepCommentsOnSameLine) { // for (int i = 0; i < components.size(); i++) { @@ -282,15 +292,17 @@ public Iterator iterator() { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter + Comparator whichRepresentationIsBetter, + int width ) { + this.width = width; keepCommentsOnSameLine = true; var representationTrue = representationGetter.get(); keepCommentsOnSameLine = false; var representationFalse = representationGetter.get(); keepCommentsOnSameLine = whichRepresentationIsBetter.compare(representationTrue, representationFalse) <= 0; for (MalleableString component : components) { - component.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + component.findBestRepresentation(representationGetter, whichRepresentationIsBetter, width); } } @@ -328,9 +340,14 @@ public MalleableString indent(int indentation) { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter + Comparator whichRepresentationIsBetter, + int width ) { - nested.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + nested.findBestRepresentation( + representationGetter, + whichRepresentationIsBetter, + width - this.indentation + ); } @Override @@ -378,7 +395,8 @@ public Iterator iterator() { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter + Comparator whichRepresentationIsBetter, + int width ) { bestPossibility = Collections.min(getPossibilities(), (a, b) -> { bestPossibility = a; @@ -388,7 +406,11 @@ public void findBestRepresentation( return whichRepresentationIsBetter.compare(resultA, resultB); }); if (bestPossibility instanceof MalleableString ms) { - ms.findBestRepresentation(representationGetter, whichRepresentationIsBetter); + ms.findBestRepresentation( + representationGetter, + whichRepresentationIsBetter, + width + ); } } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index b88519e296..6b06bb9bb5 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -806,56 +806,6 @@ public MalleableString defaultCase(EObject object) { )); } - /** - * Wrap a multi-line String based on the current state of lineWrap and indentLvl. - * If lineWrap is 0, returns originalString. Otherwise, breaks lines such that if possible, each line has less than - * (lineWrap - (indentLvl * INDENTATION) % lineWrap) characters, only breaking at spaces. - * @param originalString The String to wrap. - * @return The wrapped String. - */ - private String wrapLines(String originalString, int lineWrap, int indentLevel) { - if (lineWrap == 0) return originalString; - return originalString.lines().map(s -> wrapIndividualLine(s, lineWrap, indentLevel)) - .collect(Collectors.joining(System.lineSeparator())); - } - - /** - * Wrap a single line of String based on the current state of lineWrap and indentLvl. See wrapLines(). - * @param line The line to wrap. - * @return The wrapped line. - */ - private String wrapIndividualLine(String line, int lineWrap, int indentLevel) { - int wrapLength = lineWrap - indentLevel * INDENTATION % lineWrap; - StringBuilder sb = new StringBuilder(); - while (line.length() > wrapLength) { - // try to wrap at space - int index = line.lastIndexOf(' ', wrapLength); - // if unable to find space in limit, extend to the first space we find - if (index == -1) index = line.indexOf(' ', wrapLength); - if (index != -1 && line.substring(0, index).isBlank()) { - // never break out an all-whitespace line unless it is longer than wrapLength - if(index < wrapLength) { - index = line.indexOf(' ', wrapLength); - } else { - // large indent - don't skip over any space so that indents are consistent - sb.append(line, 0, index).append(System.lineSeparator()); - line = line.substring(index); - continue; - } - } - if (index != -1) { - sb.append(line, 0, index).append(System.lineSeparator()); - line = line.substring(index + 1); - } else { - // no spaces remaining at all - sb.append(line); - line = ""; - } - } - if (line.length() > 0) sb.append(line); - return sb.toString(); - } - /** * Represent the given EList as a string. * @param suffix The token marking the end of the list. From 7ee0123c9a3cdac1716e9e252b127eefcef8df66 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 01:35:55 -0700 Subject: [PATCH 054/130] [formatting] Adjust comment placement. Comments can now go on the same line as the textual representation of the AST node with which they are associated. --- .../src/org/lflang/ast/MalleableString.java | 78 ++++++------------- 1 file changed, 24 insertions(+), 54 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 53f2718dc2..8b8ef6a099 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -195,12 +195,7 @@ private Sequence(ImmutableList components) { public String toString() { // TODO: // find out whether you have any unhandled comments - // if so, optimize the components so that they contain as many newlines as possible - // if you still have no newlines, move on - // if you do have newlines, decide whether to put comments before or on the same line (this will have been - // determined in findBestRepresentation) - // you should have a temporary list of strings corresponding to the components. Modify the strings in the - // list so that the comments all have a home. + // if so, optimize the components so that they contain as many newlines as possible? List> unhandledComments = components.stream() .map(MalleableString::getUnhandledComments) .map(Stream::toList) @@ -219,68 +214,43 @@ public String toString() { String.join(System.lineSeparator(), unhandledComments.get(i)), stringComponents, i, - width + width, + keepCommentsOnSameLine ); } return String.join("", stringComponents); } - private static void placeComments(String unhandledComments, List components, int i, int width) { + private static void placeComments( + String unhandledComments, + List components, + int i, + int width, + boolean keepCommentsOnSameLine + ) { + String wrapped = FormattingUtils.lineWrapComment(unhandledComments, width); if (unhandledComments.isBlank()) return; + if (keepCommentsOnSameLine && wrapped.lines().count() == 1) { + for (int j = i; j < components.size(); j++) { + if (components.get(j).endsWith(System.lineSeparator())) { + components.set(j, components.get(j).replaceFirst( + System.lineSeparator() + "$", + String.format(" %s%n", wrapped) + )); + return; + } + } + } for (int j = i - 1; j >= 0; j--) { if (components.get(j).endsWith(System.lineSeparator())) { - components.set( - j, - components.get(j) + String.format( - "%s%n", - FormattingUtils.lineWrapComment(unhandledComments, width) - ) - ); + components.set(j, String.format("%s%s%n", components.get(j), wrapped)); return; } } components.set( 0, - String.format( - "%s%n%s", - FormattingUtils.lineWrapComment(unhandledComments, width), - components.isEmpty() ? "" : components.get(0) - ) + String.format("%s%n%s", wrapped, components.isEmpty() ? "" : components.get(0)) ); -// List currentlyCollectedComments = new ArrayList<>(); -// if (keepCommentsOnSameLine) { -// for (int i = 0; i < components.size(); i++) { -// currentlyCollectedComments.addAll(unhandledComments.get(i)); -// String current = stringComponents.get(i); -// if (current.endsWith(System.lineSeparator()) && !currentlyCollectedComments.isEmpty()) { -// stringComponents.set( -// i, -// current.replaceFirst( -// "\\s*" + Pattern.quote(System.lineSeparator()), -// " " + String.join(System.lineSeparator(), currentlyCollectedComments) + System.lineSeparator() -// ) // TODO: Represent the comments correctly -// ); -// currentlyCollectedComments.clear(); -// } -// } -// } else { -// for (int i = components.size() - 1; i >= 0; i--) { -// String current = stringComponents.get(i); -// if (current.endsWith(System.lineSeparator()) && !currentlyCollectedComments.isEmpty()) { -// stringComponents.set( -// i, -// current -// + String.join(System.lineSeparator(), currentlyCollectedComments) -// + System.lineSeparator() // TODO: Represent the comments correctly -// ); -// currentlyCollectedComments.clear(); -// } -// currentlyCollectedComments.addAll(0, unhandledComments.get(i)); -// } -// } -// if (!currentlyCollectedComments.isEmpty()) { -// stringComponents.add(0, String.join("", currentlyCollectedComments) + "\n"); // TODO: is this right? -// } } @SuppressWarnings("NullableProblems") From ea64b4a44051a93470edbb8fe9af6ae74b5f0e86 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 13:57:33 -0700 Subject: [PATCH 055/130] [formatting] Refactor. --- .../lflang/tests/compiler/RoundTripTests.java | 10 +- .../src/org/lflang/ast/FormattingUtils.java | 101 +++++++++++++- .../src/org/lflang/ast/MalleableString.java | 117 +++++++--------- org.lflang/src/org/lflang/ast/ToLf.java | 126 +++++++++++------- 4 files changed, 229 insertions(+), 125 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index c8d930d898..cff04b290b 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -17,6 +17,7 @@ import org.lflang.LFStandaloneSetup; import org.lflang.Target; +import org.lflang.ast.FormattingUtils; import org.lflang.ast.IsEqual; import org.lflang.ast.MalleableString; import org.lflang.ast.ToLf; @@ -49,9 +50,7 @@ private void run(Path file) throws Exception { Model originalModel = parse(file); System.out.printf("Running formatter on %s%n", file); Assertions.assertTrue(originalModel.eResource().getErrors().isEmpty()); - MalleableString ms = new MalleableString.Builder().append(ToLf.instance.doSwitch(originalModel)).get(); - ms.findBestRepresentation(ms::toString, ToLf.astRepresentationComparator(30), 30); - String reformattedTestCase = ms.toString(); + String reformattedTestCase = FormattingUtils.render(originalModel); System.out.printf("Reformatted test case:%n%s%n%n", reformattedTestCase); Model resultingModel = getResultingModel(file, reformattedTestCase); Assertions.assertNotNull(resultingModel); @@ -62,7 +61,10 @@ private void run(Path file) throws Exception { Assertions.assertTrue(new IsEqual(originalModel).doSwitch(resultingModel)); } - private Model getResultingModel(Path file, String reformattedTestCase) throws FileNotFoundException { + private Model getResultingModel( + Path file, + String reformattedTestCase + ) throws FileNotFoundException { File swap = file.getParent().resolve(file.getFileName().toString() + ".swp").toFile(); file.toFile().renameTo(swap); // FIXME: renameTo may fail. try (PrintWriter out = new PrintWriter(file.toFile())) { diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index e398f6d8bb..b2071b8926 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -2,11 +2,15 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; +import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.emf.ecore.EObject; + /** * Utility functions that determine the specific behavior of the LF formatter. * @author {Peter Donovan } @@ -23,12 +27,54 @@ public class FormattingUtils { private static final Pattern MULTILINE_COMMENT_LINES_STARTING_WITH_STARS = Pattern.compile( "\\s*/(\\s*\\*(\\S*\\h*)*)+" ); + // TODO: Ideally, this would be private its value would be abstracted out of ToLf. + /** The number of spaces to prepend to a line per indentation level. */ + static final int INDENTATION = 4; + + private static final int DEFAULT_LINE_LENGTH = 80; + + /** + * Return a String representation of {@code object}, with lines wrapped at + * {@code lineLength}. + */ + public static String render(EObject object, int lineLength) { + // The following looks useless, but it wraps the representation in an + // enclosing object that ensures that top-level comments are rendered. + MalleableString ms = new MalleableString.Builder() + .append(ToLf.instance.doSwitch(object)) + .get(); + ms.findBestRepresentation( + ms::toString, + astRepresentationComparator(lineLength), + lineLength + ); + return ms.toString(); + } + + /** + * Return a String representation of {@code object} using a reasonable + * default line length. + */ + public static String render(EObject object) { return render(object, DEFAULT_LINE_LENGTH); } + + private static Comparator astRepresentationComparator(int lineLength) { + return Comparator.comparing(countCharactersViolatingLineLength(lineLength)) + .thenComparing(FormattingUtils::countNewlines); + } + + private static Function countCharactersViolatingLineLength(int lineLength) { + return s -> s.lines().mapToInt(it -> Math.max(0, it.length() - lineLength)).sum(); + } + + private static long countNewlines(String s) { + return s.lines().count(); + } /** * Break lines at spaces so that each line is no more than {@code width} * columns long, if possible. Normalize whitespace. */ - public static String lineWrapComment(String comment, int width) { + static String lineWrapComment(String comment, int width) { width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); List simpleWhitespace = Arrays.stream( comment.strip() @@ -47,7 +93,7 @@ public static String lineWrapComment(String comment, int width) { return lineWrapComment(simpleWhitespace, width, "// "); } - private static String lineWrapComment( + static String lineWrapComment( List simpleWhitespace, int width, String linePrefix @@ -58,7 +104,7 @@ private static String lineWrapComment( .collect(Collectors.joining(System.lineSeparator())); } - private static Stream wrapLines(List paragraphs, int width) { + static Stream wrapLines(List paragraphs, int width) { var ret = new ArrayList(); for (String s : paragraphs) { if (!ret.isEmpty()) ret.add(""); @@ -78,4 +124,53 @@ private static Stream wrapLines(List paragraphs, int width) { } return ret.stream(); } + + /** + * Merge {@code comment} into the given list of strings without changing the + * length of the list, preferably in a place that indicates that + * {@code comment} is associated with the {@code i}th string. + * @param comment A comment associated with an element of + * {@code components}. + * @param components A list of strings that will be rendered in sequence. + * @param i The position of the component associated with {@code comment}. + * @param width The ideal number of columns available for comments that + * appear on their own line. + * @param keepCommentsOnSameLine Whether to make a best-effort attempt to + * keep the comment on the same line as the associated string. + */ + static void placeComment( + String comment, + List components, + int i, + int width, + boolean keepCommentsOnSameLine + ) { + String wrapped = FormattingUtils.lineWrapComment(comment, width); + if (comment.isBlank()) return; + if (keepCommentsOnSameLine && wrapped.lines().count() == 1) { + for (int j = i; j < components.size(); j++) { + if (components.get(j).endsWith(System.lineSeparator())) { + components.set(j, components.get(j).replaceFirst( + System.lineSeparator() + "$", + String.format(" %s%n", wrapped) + )); + return; + } + } + } + for (int j = i - 1; j >= 0; j--) { + if (components.get(j).endsWith(System.lineSeparator())) { + components.set(j, String.format("%s%s%n", components.get(j), wrapped)); + return; + } + } + components.set( + 0, + String.format("%s%n%s", wrapped, components.isEmpty() ? "" : components.get(0)) + ); + } + + static String normalizeEol(String s) { + return s.replaceAll("\\r\\n?", "\n"); + } } diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 8b8ef6a099..e7738f91d7 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -14,7 +14,6 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; -import java.util.stream.IntStream; import java.util.stream.Stream; import com.google.common.collect.ImmutableList; @@ -80,7 +79,12 @@ public Builder append(MalleableString... possibilities) { } public Builder prepend(MalleableString... possibilities) { - return insert(Function.identity(), Fork::new, possibilities, ms -> components.add(0, ms)); + return insert( + Function.identity(), + Fork::new, + possibilities, + ms -> components.add(0, ms) + ); } public Builder append(String... content) { @@ -102,20 +106,12 @@ private Builder insert( T[] possibilities, Consumer addToComponents ) { - if ( - Arrays.stream(possibilities) - .map(toMalleableString) - .allMatch(MalleableString::isEmpty) - ) { - return this; - } -// if (possibilities.length == 1) { -// // The resulting MalleableString may be a sequence. -// // Stay flat: Let there be no sequences in sequences! -// toMalleableString.apply(possibilities[0]).forEach(addToComponents); -// } else { + boolean allEmpty = Arrays.stream(possibilities) + .map(toMalleableString) + .allMatch(MalleableString::isEmpty); + if (!allEmpty) { addToComponents.accept(multiplePossibilitiesRepresenter.apply(possibilities)); -// } + } return this; } @@ -173,7 +169,8 @@ public BinaryOperator combiner() { @Override public Function finisher() { - return ((Function) Builder::get).compose(appendSuffix).compose(prependPrefix); + return ((Function) Builder::get) + .compose(appendSuffix).compose(prependPrefix); } @Override @@ -193,64 +190,30 @@ private Sequence(ImmutableList components) { @Override public String toString() { - // TODO: - // find out whether you have any unhandled comments - // if so, optimize the components so that they contain as many newlines as possible? List> unhandledComments = components.stream() .map(MalleableString::getUnhandledComments) + .map(stream -> stream.map(FormattingUtils::normalizeEol)) .map(Stream::toList) .toList(); List stringComponents = components.stream() .map(MalleableString::toString) + .map(FormattingUtils::normalizeEol) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); - List newLineIndices = IntStream.range(0, stringComponents.size()).sequential() - .filter(i -> stringComponents.get(i).endsWith(System.lineSeparator())) - .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); - if (unhandledComments.stream().allMatch(List::isEmpty) || newLineIndices.isEmpty()) { - return String.join("", stringComponents); - } - for (int i = 0; i < unhandledComments.size(); i++) { - placeComments( - String.join(System.lineSeparator(), unhandledComments.get(i)), - stringComponents, - i, - width, - keepCommentsOnSameLine - ); - } - return String.join("", stringComponents); - } - - private static void placeComments( - String unhandledComments, - List components, - int i, - int width, - boolean keepCommentsOnSameLine - ) { - String wrapped = FormattingUtils.lineWrapComment(unhandledComments, width); - if (unhandledComments.isBlank()) return; - if (keepCommentsOnSameLine && wrapped.lines().count() == 1) { - for (int j = i; j < components.size(); j++) { - if (components.get(j).endsWith(System.lineSeparator())) { - components.set(j, components.get(j).replaceFirst( - System.lineSeparator() + "$", - String.format(" %s%n", wrapped) - )); - return; - } - } - } - for (int j = i - 1; j >= 0; j--) { - if (components.get(j).endsWith(System.lineSeparator())) { - components.set(j, String.format("%s%s%n", components.get(j), wrapped)); - return; + if ( + unhandledComments.stream().anyMatch(s -> !s.isEmpty()) + && stringComponents.stream().anyMatch(s -> s.endsWith(System.lineSeparator())) + ) { + for (int i = 0; i < unhandledComments.size(); i++) { + FormattingUtils.placeComment( + String.join(System.lineSeparator(), unhandledComments.get(i)), + stringComponents, + i, + width, + keepCommentsOnSameLine + ); } } - components.set( - 0, - String.format("%s%n%s", wrapped, components.isEmpty() ? "" : components.get(0)) - ); + return String.join("", stringComponents); } @SuppressWarnings("NullableProblems") @@ -265,14 +228,24 @@ public void findBestRepresentation( Comparator whichRepresentationIsBetter, int width ) { + // TODO: + // find out whether you have any unhandled comments + // if so, optimize the components so that they contain as many newlines as possible? this.width = width; keepCommentsOnSameLine = true; var representationTrue = representationGetter.get(); keepCommentsOnSameLine = false; var representationFalse = representationGetter.get(); - keepCommentsOnSameLine = whichRepresentationIsBetter.compare(representationTrue, representationFalse) <= 0; + keepCommentsOnSameLine = whichRepresentationIsBetter.compare( + representationTrue, + representationFalse + ) <= 0; for (MalleableString component : components) { - component.findBestRepresentation(representationGetter, whichRepresentationIsBetter, width); + component.findBestRepresentation( + representationGetter, + whichRepresentationIsBetter, + width + ); } } @@ -283,11 +256,10 @@ public boolean isEmpty() { @Override protected Stream getUnhandledComments() { - // FIXME: This is very crude. return Stream.concat( super.getUnhandledComments(), - components.stream().anyMatch(it -> it.toString().endsWith(System.lineSeparator())) ? Stream.of() - : components.stream().flatMap(MalleableString::getUnhandledComments) + components.stream().anyMatch(it -> it.toString().endsWith(System.lineSeparator())) ? + Stream.of() : components.stream().flatMap(MalleableString::getUnhandledComments) ); } } @@ -340,7 +312,10 @@ public Iterator iterator() { public String toString() { var nestedString = nested.toString(); var ret = nestedString.indent(indentation); - if (!nestedString.endsWith(System.lineSeparator()) && ret.endsWith(System.lineSeparator())) { + if ( + !nestedString.endsWith(System.lineSeparator()) + && ret.endsWith(System.lineSeparator()) + ) { ret = ret.substring(0, ret.length() - System.lineSeparator().length()); } return ret; diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 6b06bb9bb5..d54cb7ade1 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -1,10 +1,8 @@ package org.lflang.ast; import java.util.Arrays; -import java.util.Comparator; import java.util.List; import java.util.Objects; -import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -77,28 +75,12 @@ */ public class ToLf extends LfSwitch { - /** The number of spaces to prepend to a line per indentation level. */ - private static final int INDENTATION = 4; - /// public instance initialized when loading the class public static final ToLf instance = new ToLf(); // private constructor private ToLf() { super(); } - public static Comparator astRepresentationComparator(int lineLength) { - return Comparator.comparing(countCharactersViolatingLineLength(lineLength)) - .thenComparing(ToLf::countNewlines); - } - - private static Function countCharactersViolatingLineLength(int lineLength) { - return s -> s.lines().mapToInt(it -> Math.max(0, it.length() - lineLength)).sum(); - } - - private static long countNewlines(String s) { - return s.lines().count(); - } - @Override public MalleableString caseArraySpec(ArraySpec spec) { if (spec.isOfVariableLength()) return MalleableString.anyOf("[]"); @@ -146,7 +128,10 @@ private ICompositeNode getNextCompositeSibling(INode node) { INode sibling = node; while ((sibling = sibling.getNextSibling()) != null) { if (sibling instanceof ICompositeNode compositeSibling) return compositeSibling; - if (!(sibling.getGrammarElement() instanceof Keyword) || sibling.getText().contains("\n")) break; + if ( + !(sibling.getGrammarElement() instanceof Keyword) + || sibling.getText().contains("\n") + ) break; } return null; } @@ -162,7 +147,8 @@ private Stream getFollowingComments(ICompositeNode node) { } private Predicate sameLine(INode node) { - return other -> node.getStartLine() <= other.getStartLine() && other.getStartLine() <= node.getEndLine(); + return other -> node.getStartLine() <= other.getStartLine() + && other.getStartLine() <= node.getEndLine(); } @Override @@ -171,7 +157,7 @@ public MalleableString caseCode(Code code) { String singleLineRepresentation = String.format("{= %s =}", content.strip()); String multilineRepresentation = String.format( "{=%n%s=}", - content.strip().indent(INDENTATION) + content.strip().indent(FormattingUtils.INDENTATION) ); if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { return MalleableString.anyOf(multilineRepresentation); @@ -215,7 +201,8 @@ public MalleableString caseTime(Time t) { @Override public MalleableString caseType(Type type) { // time?='time' (arraySpec=ArraySpec)? - // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* (arraySpec=ArraySpec)? + // | id=DottedName ('<' typeParms+=Type (',' typeParms+=Type)* '>')? (stars+='*')* + // (arraySpec=ArraySpec)? // | code=Code if (type.getCode() != null) return doSwitch(type.getCode()); Builder msb = new Builder(); @@ -244,7 +231,8 @@ public MalleableString caseTypeParm(TypeParm t) { @Override public MalleableString caseVarRef(VarRef v) { // variable=[Variable] | container=[Instantiation] '.' variable=[Variable] - // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' variable=[Variable]) ')' + // | interleaved?='interleaved' '(' (variable=[Variable] | container=[Instantiation] '.' + // variable=[Variable]) ')' if (!v.isInterleaved()) return MalleableString.anyOf(ToText.instance.doSwitch(v)); return new Builder() .append("interleaved ") @@ -275,7 +263,8 @@ public MalleableString caseModel(Model object) { @Override public MalleableString caseImport(Import object) { - // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* 'from' importURI=STRING ';'? + // 'import' reactorClasses+=ImportedReactor (',' reactorClasses+=ImportedReactor)* + // 'from' importURI=STRING ';'? // TODO: Break this. Break string, break at whitespace outside the string. return new Builder() .append("import ") @@ -308,7 +297,8 @@ public MalleableString caseImportedReactor(ImportedReactor object) { @Override public MalleableString caseReactor(Reactor object) { - // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) 'reactor' (name=ID)? + // {Reactor} ((federated?='federated' | main?='main')? & realtime?='realtime'?) + // 'reactor' (name=ID)? // ('<' typeParms+=TypeParm (',' typeParms+=TypeParm)* '>')? // ('(' parameters+=Parameter (',' parameters+=Parameter)* ')')? // ('at' host=Host)? @@ -352,7 +342,9 @@ public MalleableString caseReactor(Reactor object) { 1 ); msb.append(smallFeatures); - if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) msb.append(System.lineSeparator().repeat(2)); + if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) { + msb.append(System.lineSeparator().repeat(2)); + } msb.append(bigFeatures); msb.append(String.format("%n}")); return msb.get(); @@ -374,11 +366,15 @@ private MalleableString reactorHeader(Reactor object) { MalleableString.anyOf(" extends "), new Builder() .append(System.lineSeparator()) - .append(MalleableString.anyOf("extends ").indent(INDENTATION).indent(INDENTATION)) + .append( + MalleableString.anyOf("extends ").indent(FormattingUtils.INDENTATION * 2) + ) .get() ) .append( - object.getSuperClasses().stream().map(ReactorDecl::getName).collect(Collectors.joining(", ")) + object.getSuperClasses().stream() + .map(ReactorDecl::getName) + .collect(Collectors.joining(", ")) ); } msb.append(String.format(" {%n")); @@ -408,7 +404,9 @@ public MalleableString caseStateVar(StateVar object) { msb.append("state ").append(object.getName()); msb.append(typeAnnotationFor(object.getType())); if (!object.getParens().isEmpty()) msb.append(list(true, object.getInit())); - if (!object.getBraces().isEmpty()) msb.append(list(", ", "{", "}", true, false, object.getInit())); + if (!object.getBraces().isEmpty()) { + msb.append(list(", ", "{", "}", true, false, object.getInit())); + } return msb.get(); } @@ -423,7 +421,9 @@ public MalleableString caseMethod(Method object) { if (object.isConst()) msb.append("const "); msb.append("method ").append(object.getName()); msb.append(list(false, object.getArguments())); - msb.append(typeAnnotationFor(object.getReturn())).append(" ").append(doSwitch(object.getCode())); + msb.append(typeAnnotationFor(object.getReturn())) + .append(" ") + .append(doSwitch(object.getCode())); return msb.get(); } @@ -629,12 +629,17 @@ public MalleableString caseConnection(Connection object) { if (object.isIterated()) msb.append("("); msb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); if (object.isIterated()) msb.append(")+"); - msb.append("", MalleableString.anyOf(System.lineSeparator()).indent(INDENTATION)); + msb.append( + "", + MalleableString.anyOf(System.lineSeparator()).indent(FormattingUtils.INDENTATION) + ); msb.append(object.isPhysical() ? " ~> " : " -> "); // TODO: break lines here msb.append(object.getRightPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); if (object.getDelay() != null) msb.append(" after ").append(doSwitch(object.getDelay())); - if (object.getSerializer() != null) msb.append(" ").append(doSwitch(object.getSerializer())); + if (object.getSerializer() != null) { + msb.append(" ").append(doSwitch(object.getSerializer())); + } return msb.get(); } @@ -710,8 +715,15 @@ public MalleableString caseAssignment(Assignment object) { Builder msb = new Builder(); msb.append(object.getLhs().getName()); if (object.getEquals() != null) msb.append(" = "); - String prefix = !object.getParens().isEmpty() ? "(" : !object.getBraces().isEmpty() ? "{" : ""; - String suffix = !object.getParens().isEmpty() ? ")" : !object.getBraces().isEmpty() ? "}" : ""; + String prefix = ""; + String suffix = ""; + if (!object.getParens().isEmpty()) { + prefix = "("; + suffix = ")"; + } else if (!object.getBraces().isEmpty()) { + prefix = "{"; + suffix = "}"; + } msb.append(list(", ", prefix, suffix, false, prefix.isBlank(), object.getRhs())); return msb.get(); } @@ -816,7 +828,12 @@ public MalleableString defaultCase(EObject object) { * @param whitespaceRigid Whether any whitespace appearing in the */ private MalleableString list( - String separator, String prefix, String suffix, boolean nothingIfEmpty, boolean whitespaceRigid, List items + String separator, + String prefix, + String suffix, + boolean nothingIfEmpty, + boolean whitespaceRigid, + List items ) { return list( separator, @@ -836,12 +853,16 @@ private MalleableString list( boolean whitespaceRigid, Object... items ) { - if (nothingIfEmpty && Arrays.stream(items).allMatch(Objects::isNull)) return MalleableString.anyOf(""); - MalleableString rigid = Arrays.stream(items).sequential().filter(Objects::nonNull).map(it -> { - if (it instanceof MalleableString ms) return ms; - if (it instanceof EObject eObject) return doSwitch(eObject); - return MalleableString.anyOf(Objects.toString(it)); - }).collect(new Joiner(separator, prefix, suffix)); + if (nothingIfEmpty && Arrays.stream(items).allMatch(Objects::isNull)) { + return MalleableString.anyOf(""); + } + MalleableString rigid = Arrays.stream(items).sequential() + .filter(Objects::nonNull) + .map(it -> { + if (it instanceof MalleableString ms) return ms; + if (it instanceof EObject eObject) return doSwitch(eObject); + return MalleableString.anyOf(Objects.toString(it)); + }).collect(new Joiner(separator, prefix, suffix)); if (whitespaceRigid) return rigid; return MalleableString.anyOf( rigid, @@ -854,7 +875,9 @@ private MalleableString list( nothingIfEmpty, true, items - ).indent(INDENTATION)).append(System.lineSeparator() + suffix.stripLeading()).get() + ).indent(FormattingUtils.INDENTATION)) + .append(System.lineSeparator() + suffix.stripLeading()) + .get() ); } @@ -878,13 +901,22 @@ private MalleableString typeAnnotationFor(Type type) { * minimum, to be inserted between everything. * @return A string representation of {@code statementListList}. */ - private MalleableString indentedStatements(List> statementListList, int extraSeparation) { - return statementListList.stream().filter(((Predicate>) List::isEmpty).negate()).map( - statementList -> list( - System.lineSeparator().repeat(1 + extraSeparation), "", "", true, true, statementList + private MalleableString indentedStatements( + List> statementListList, + int extraSeparation + ) { + return statementListList.stream() + .filter(list -> !list.isEmpty()) + .map(statementList -> list( + System.lineSeparator().repeat(1 + extraSeparation), + "", + "", + true, + true, + statementList ) ).collect( new Joiner(System.lineSeparator().repeat(2 + extraSeparation), "", "") - ).indent(INDENTATION); + ).indent(FormattingUtils.INDENTATION); } } From 65dcd62ab5c7d91b41ed2854ea6a11a58ab522ae Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 14:23:27 -0700 Subject: [PATCH 056/130] [formatting] More superficial cleanups. --- org.lflang.cli/src/org/lflang/cli/Lff.java | 82 +++++++++++++------ .../lflang/tests/compiler/RoundTripTests.java | 16 ++-- .../src/org/lflang/ast/FormattingUtils.java | 5 +- .../org/lflang/formatting2/LFFormatter.java | 31 +++---- 4 files changed, 84 insertions(+), 50 deletions(-) diff --git a/org.lflang.cli/src/org/lflang/cli/Lff.java b/org.lflang.cli/src/org/lflang/cli/Lff.java index 71a9d16ef0..dc3234f432 100644 --- a/org.lflang.cli/src/org/lflang/cli/Lff.java +++ b/org.lflang.cli/src/org/lflang/cli/Lff.java @@ -24,8 +24,7 @@ import org.lflang.LFRuntimeModule; import org.lflang.LFStandaloneSetup; import org.lflang.LocalStrings; -import org.lflang.ast.MalleableString; -import org.lflang.ast.ToLf; +import org.lflang.ast.FormattingUtils; import org.lflang.util.FileUtil; import com.google.inject.Injector; @@ -39,7 +38,6 @@ * @author {Billy Bao } */ public class Lff extends CliBase { - private static final int DEFAULT_LINE_LENGTH = 100; /** * Supported CLI options. @@ -53,10 +51,28 @@ public class Lff extends CliBase { */ enum CLIOption { HELP("h", "help", false, false, "Display this information."), - LINE_WRAP("w", "wrap", true, false, "Causes the formatter to line wrap the files to a specified length."), - NO_RECURSE(null, "no-recurse", false, false, "Do not format files in subdirectories of the specified paths."), - OUTPUT_PATH("o", "output-path", true, false, "If specified, outputs all formatted files into this directory instead " - + "of overwriting the original files. Subdirectory structure will be preserved."), + LINE_WRAP( + "w", + "wrap", + true, + false, + "Causes the formatter to line wrap the files to a specified length." + ), + NO_RECURSE( + null, + "no-recurse", + false, + false, + "Do not format files in subdirectories of the specified paths." + ), + OUTPUT_PATH( + "o", + "output-path", + true, + false, + "If specified, outputs all formatted files into this directory instead " + + "of overwriting the original files. Subdirectory structure will be preserved." + ), VERBOSE("v", "verbose", false, false, "Print more details on files affected."), VERSION(null, "version", false, false, "Print version information."); @@ -104,8 +120,10 @@ public static void main(final String[] args) { final ReportingBackend reporter = new ReportingBackend(new Io(), "lff: "); // Injector used to obtain Main instance. - final Injector injector = new LFStandaloneSetup(new LFRuntimeModule(), new LFStandaloneModule(reporter)) - .createInjectorAndDoEMFRegistration(); + final Injector injector = new LFStandaloneSetup( + new LFRuntimeModule(), + new LFStandaloneModule(reporter) + ).createInjectorAndDoEMFRegistration(); // Main instance. final Lff main = injector.getInstance(Lff.class); // Apache Commons Options object configured according to available CLI arguments. @@ -142,14 +160,17 @@ public static void main(final String[] args) { reporter.printFatalErrorAndExit("An unexpected error occurred:", e); } } catch (ParseException e) { - reporter.printFatalError("Unable to parse commandline arguments. Reason: " + e.getMessage()); + reporter.printFatalError( + "Unable to parse commandline arguments. Reason: " + e.getMessage() + ); formatter.printHelp("lff", options); System.exit(1); } } /** - * Check all given input paths and the output path, then invokes the formatter on all files given. + * Check all given input paths and the output path, then invokes the formatter on all files + * given. */ private void runFormatter(List files) { String pathOption = CLIOption.OUTPUT_PATH.option.getOpt(); @@ -157,10 +178,14 @@ private void runFormatter(List files) { if (cmd.hasOption(pathOption)) { outputRoot = Paths.get(cmd.getOptionValue(pathOption)).toAbsolutePath().normalize(); if (!Files.exists(outputRoot)) { - reporter.printFatalErrorAndExit("Output location '" + outputRoot + "' does not exist."); + reporter.printFatalErrorAndExit( + "Output location '" + outputRoot + "' does not exist." + ); } if (!Files.isDirectory(outputRoot)) { - reporter.printFatalErrorAndExit("Output location '" + outputRoot + "' is not a directory."); + reporter.printFatalErrorAndExit( + "Output location '" + outputRoot + "' is not a directory." + ); } } @@ -170,15 +195,18 @@ private void runFormatter(List files) { } } - final int lineLength = !cmd.hasOption(CLIOption.LINE_WRAP.option.getOpt()) ? DEFAULT_LINE_LENGTH : - Integer.parseInt(cmd.getOptionValue(CLIOption.LINE_WRAP.option.getOpt())); + final int lineLength = !cmd.hasOption(CLIOption.LINE_WRAP.option.getOpt()) ? + FormattingUtils.DEFAULT_LINE_LENGTH + : Integer.parseInt(cmd.getOptionValue(CLIOption.LINE_WRAP.option.getOpt())); for (Path path : files) { if (cmd.hasOption(CLIOption.VERBOSE.option.getOpt())) { reporter.printInfo("Formatting " + path + ":"); } path = path.toAbsolutePath(); - if (Files.isDirectory(path) && !cmd.hasOption(CLIOption.NO_RECURSE.option.getLongOpt())) { + if ( + Files.isDirectory(path)&& !cmd.hasOption(CLIOption.NO_RECURSE.option.getLongOpt()) + ) { formatRecursive(Paths.get("."), path, outputRoot, lineLength); } else { if (outputRoot == null) { @@ -235,21 +263,23 @@ private void formatSingleFile(Path file, Path outputPath, int lineLength) { exitIfCollectedErrors(); - MalleableString rendered = ToLf.instance.doSwitch(resource.getContents().get(0)); - rendered.findBestRepresentation( - rendered::toString, - ToLf.astRepresentationComparator(lineLength), - lineLength - ); try { - FileUtil.writeToFile(rendered.toString(), outputPath, true); + FileUtil.writeToFile( + FormattingUtils.render(resource.getContents().get(0), lineLength), + outputPath, + true + ); } catch (IOException e) { if (e instanceof FileAlreadyExistsException) { // only happens if a subdirectory is named with ".lf" at the end - reporter.printFatalErrorAndExit("Error writing to " + outputPath + ": file already exists. Make sure that no file or directory " - + "within provided input paths have the same relative paths."); + reporter.printFatalErrorAndExit( + "Error writing to " + outputPath + ": file already exists. Make sure that no " + + "file or directory within provided input paths have the same relative " + + "paths."); } - reporter.printFatalErrorAndExit("Error writing to " + outputPath + ": " + e.getMessage()); + reporter.printFatalErrorAndExit( + "Error writing to " + outputPath + ": " + e.getMessage() + ); } exitIfCollectedErrors(); diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index cff04b290b..92ae9381df 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -1,7 +1,7 @@ package org.lflang.tests.compiler; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Path; @@ -19,8 +19,6 @@ import org.lflang.Target; import org.lflang.ast.FormattingUtils; import org.lflang.ast.IsEqual; -import org.lflang.ast.MalleableString; -import org.lflang.ast.ToLf; import org.lflang.lf.Model; import org.lflang.tests.LFInjectorProvider; import org.lflang.tests.LFTest; @@ -64,14 +62,15 @@ private void run(Path file) throws Exception { private Model getResultingModel( Path file, String reformattedTestCase - ) throws FileNotFoundException { + ) throws IOException { File swap = file.getParent().resolve(file.getFileName().toString() + ".swp").toFile(); - file.toFile().renameTo(swap); // FIXME: renameTo may fail. + var ioException = new IOException("Failed to move the given test case to a swap file."); + if (!file.toFile().renameTo(swap)) throw ioException; try (PrintWriter out = new PrintWriter(file.toFile())) { out.println(reformattedTestCase); } Model resultingModel = parse(file); - swap.renameTo(file.toFile()); + if (!swap.renameTo(file.toFile())) throw ioException; return resultingModel; } @@ -80,7 +79,10 @@ private Model parse(Path file) { Injector injector = new LFStandaloneSetup().createInjectorAndDoEMFRegistration(); XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class); resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE); - Resource resource = resourceSet.getResource(URI.createFileURI(file.toFile().getAbsolutePath()), true); + Resource resource = resourceSet.getResource( + URI.createFileURI(file.toFile().getAbsolutePath()), + true + ); return (Model) resource.getContents().get(0); } } diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index b2071b8926..a5f5ab71bd 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -27,11 +27,12 @@ public class FormattingUtils { private static final Pattern MULTILINE_COMMENT_LINES_STARTING_WITH_STARS = Pattern.compile( "\\s*/(\\s*\\*(\\S*\\h*)*)+" ); - // TODO: Ideally, this would be private its value would be abstracted out of ToLf. + + // TODO: Ideally, ToLf would not need to access the value of INDENTATION. /** The number of spaces to prepend to a line per indentation level. */ static final int INDENTATION = 4; - private static final int DEFAULT_LINE_LENGTH = 80; + public static final int DEFAULT_LINE_LENGTH = 80; /** * Return a String representation of {@code object}, with lines wrapped at diff --git a/org.lflang/src/org/lflang/formatting2/LFFormatter.java b/org.lflang/src/org/lflang/formatting2/LFFormatter.java index 15d613b645..1f36bae36a 100644 --- a/org.lflang/src/org/lflang/formatting2/LFFormatter.java +++ b/org.lflang/src/org/lflang/formatting2/LFFormatter.java @@ -1,6 +1,7 @@ /* * generated by Xtext 2.26.0 */ + package org.lflang.formatting2; import java.util.List; @@ -12,22 +13,22 @@ import org.eclipse.xtext.formatting2.regionaccess.ITextSegment; import org.eclipse.xtext.formatting2.regionaccess.internal.TextReplacement; -import org.lflang.ast.ToLf; +import org.lflang.ast.FormattingUtils; public class LFFormatter implements IFormatter2 { - @Override - public List format(FormatterRequest request) { - ITextSegment documentRegion = request.getTextRegionAccess().regionForDocument(); - List documentContents = request.getTextRegionAccess().getResource().getContents(); - if (documentContents.isEmpty()) return List.of(); - return List.of( - new TextReplacement( - request.getTextRegionAccess(), - documentRegion.getOffset(), - documentRegion.getLength(), - ToLf.instance.doSwitch(documentContents.get(0)).toString() - ) - ); - } + @Override + public List format(FormatterRequest request) { + ITextSegment documentRegion = request.getTextRegionAccess().regionForDocument(); + List documentContents = request.getTextRegionAccess().getResource().getContents(); + if (documentContents.isEmpty()) return List.of(); + return List.of( + new TextReplacement( + request.getTextRegionAccess(), + documentRegion.getOffset(), + documentRegion.getLength(), + FormattingUtils.render(documentContents.get(0)) + ) + ); + } } From 9bd1792605528d5e6323338291cebbde2a19c3bf Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 23:05:21 -0700 Subject: [PATCH 057/130] Fix IndexOutOfBoundsException when formatting. Addresses https://github.com/lf-lang/vscode-lingua-franca/issues/63. --- .../lflang/diagram/lsp/LFLanguageServer.java | 18 ++++++++++++++++++ .../diagram/lsp/LanguageDiagramServer.java | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/org.lflang.diagram/src/org/lflang/diagram/lsp/LFLanguageServer.java b/org.lflang.diagram/src/org/lflang/diagram/lsp/LFLanguageServer.java index 40ace31cfb..085247028c 100644 --- a/org.lflang.diagram/src/org/lflang/diagram/lsp/LFLanguageServer.java +++ b/org.lflang.diagram/src/org/lflang/diagram/lsp/LFLanguageServer.java @@ -3,6 +3,11 @@ import org.eclipse.lsp4j.WorkDoneProgressCancelParams; import de.cau.cs.kieler.klighd.lsp.KGraphLanguageServerExtension; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.HoverParams; +import org.eclipse.xtext.ide.server.hover.IHoverService; +import org.eclipse.xtext.util.CancelIndicator; + /** * The Lingua Franca language and diagram server. * @@ -13,4 +18,17 @@ public class LFLanguageServer extends KGraphLanguageServerExtension { public void cancelProgress(WorkDoneProgressCancelParams params) { Progress.cancel(params.getToken().getRight().intValue()); } + + @Override + protected Hover hover(HoverParams params, CancelIndicator cancelIndicator) { + // This override is just a hacky little patch that is being applied downstream of the original mistake and + // upstream of the ungraceful handling (IndexOutOfBoundsException) of said mistake. This patch is applied here + // simply because it is easy. This would be done differently were it not for the fact that we plan to rebuild + // this infrastructure from scratch anyway. + try { + return super.hover(params, cancelIndicator); + } catch (IndexOutOfBoundsException e) { + return IHoverService.EMPTY_HOVER; // Fail silently + } + } } diff --git a/org.lflang.diagram/src/org/lflang/diagram/lsp/LanguageDiagramServer.java b/org.lflang.diagram/src/org/lflang/diagram/lsp/LanguageDiagramServer.java index 067d4f2db2..439f290b7c 100644 --- a/org.lflang.diagram/src/org/lflang/diagram/lsp/LanguageDiagramServer.java +++ b/org.lflang.diagram/src/org/lflang/diagram/lsp/LanguageDiagramServer.java @@ -72,7 +72,7 @@ public void onConnect() { private static class LFLanguageRegistration implements ILanguageRegistration { @Override - public void bindAndRegisterLanguages() { + public void bindAndRegisterLanguages() { LFIdeSetup.doSetup(); } } From acc3cc9c2d598c49773cbe0f2b4c361d445ae350 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 23:07:45 -0700 Subject: [PATCH 058/130] [formatting] Adjust comment placement. --- org.lflang/src/org/lflang/ast/FormattingUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index a5f5ab71bd..fe8b272d8f 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -148,11 +148,11 @@ static void placeComment( ) { String wrapped = FormattingUtils.lineWrapComment(comment, width); if (comment.isBlank()) return; - if (keepCommentsOnSameLine && wrapped.lines().count() == 1) { + if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { for (int j = i; j < components.size(); j++) { - if (components.get(j).endsWith(System.lineSeparator())) { + if (components.get(j).contains(System.lineSeparator())) { components.set(j, components.get(j).replaceFirst( - System.lineSeparator() + "$", + System.lineSeparator(), String.format(" %s%n", wrapped) )); return; From 5435cd8d7047ea94df5eb1521f9799c7c238cc08 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 1 Jul 2022 23:08:28 -0700 Subject: [PATCH 059/130] [formatting] Clean up indentation implementation. Do not create trailing whitespace! --- .../src/org/lflang/ast/MalleableString.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index e7738f91d7..18d48b2f50 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -14,6 +14,7 @@ import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; +import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.collect.ImmutableList; @@ -201,7 +202,7 @@ public String toString() { .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); if ( unhandledComments.stream().anyMatch(s -> !s.isEmpty()) - && stringComponents.stream().anyMatch(s -> s.endsWith(System.lineSeparator())) + && stringComponents.stream().anyMatch(s -> s.contains(System.lineSeparator())) ) { for (int i = 0; i < unhandledComments.size(); i++) { FormattingUtils.placeComment( @@ -258,7 +259,7 @@ public boolean isEmpty() { protected Stream getUnhandledComments() { return Stream.concat( super.getUnhandledComments(), - components.stream().anyMatch(it -> it.toString().endsWith(System.lineSeparator())) ? + components.stream().anyMatch(it -> it.toString().contains(System.lineSeparator())) ? Stream.of() : components.stream().flatMap(MalleableString::getUnhandledComments) ); } @@ -310,15 +311,10 @@ public Iterator iterator() { @Override public String toString() { - var nestedString = nested.toString(); - var ret = nestedString.indent(indentation); - if ( - !nestedString.endsWith(System.lineSeparator()) - && ret.endsWith(System.lineSeparator()) - ) { - ret = ret.substring(0, ret.length() - System.lineSeparator().length()); - } - return ret; + String whitespace = " ".repeat(indentation); + return nested.toString().lines() + .map(line -> line.isBlank() ? "" : whitespace + line) + .collect(Collectors.joining(System.lineSeparator())); } } From 586ed25f0df6980b2f1a6ecfdda4563937ca69b3 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 01:13:14 -0700 Subject: [PATCH 060/130] [formatting] Slightly adjust cost function. If a sequence contains elements that have comments associated with them, prefer to smear the sequence across multiple lines. This helps to ensure that the comment can keeps a position that emphasizes its relationship to that particular element of the sequence. --- .../src/org/lflang/ast/FormattingUtils.java | 6 +++- .../src/org/lflang/ast/MalleableString.java | 35 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index fe8b272d8f..3a7b8fcbac 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -58,6 +58,10 @@ public static String render(EObject object, int lineLength) { */ public static String render(EObject object) { return render(object, DEFAULT_LINE_LENGTH); } + /** + * Return a comparator that returns a negative number if the first argument + * is better than the second. + */ private static Comparator astRepresentationComparator(int lineLength) { return Comparator.comparing(countCharactersViolatingLineLength(lineLength)) .thenComparing(FormattingUtils::countNewlines); @@ -172,6 +176,6 @@ static void placeComment( } static String normalizeEol(String s) { - return s.replaceAll("\\r\\n?", "\n"); + return s.replaceAll("(\\r\\n?)|\\n", System.lineSeparator()); } } diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 18d48b2f50..4f3db22e09 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -202,7 +202,7 @@ public String toString() { .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); if ( unhandledComments.stream().anyMatch(s -> !s.isEmpty()) - && stringComponents.stream().anyMatch(s -> s.contains(System.lineSeparator())) + && stringComponents.stream().anyMatch(s -> s.contains("\r") || s.contains("\n")) ) { for (int i = 0; i < unhandledComments.size(); i++) { FormattingUtils.placeComment( @@ -229,9 +229,6 @@ public void findBestRepresentation( Comparator whichRepresentationIsBetter, int width ) { - // TODO: - // find out whether you have any unhandled comments - // if so, optimize the components so that they contain as many newlines as possible? this.width = width; keepCommentsOnSameLine = true; var representationTrue = representationGetter.get(); @@ -241,10 +238,31 @@ public void findBestRepresentation( representationTrue, representationFalse ) <= 0; + if (getUnhandledComments().findAny().isPresent()) { + optimizeComponentsToContainAtLeastTwoLines(whichRepresentationIsBetter); + } else { + for (MalleableString component : components) { + component.findBestRepresentation( + representationGetter, + whichRepresentationIsBetter, + width + ); + } + } + } + + private void optimizeComponentsToContainAtLeastTwoLines(Comparator whichRepresentationIsBetter) { for (MalleableString component : components) { component.findBestRepresentation( - representationGetter, - whichRepresentationIsBetter, + this::toString, + (a, b) -> { + var strippedA = a.strip(); + var strippedB = b.strip(); + // If a comment needs to be rendered, prefer that this sequence has at least two lines. + int lineNumDiff = (int) (strippedB.lines().limit(2).count() - strippedA.lines().limit(2).count()); + if (lineNumDiff != 0) return lineNumDiff; + return whichRepresentationIsBetter.compare(a, b); + }, width ); } @@ -259,8 +277,9 @@ public boolean isEmpty() { protected Stream getUnhandledComments() { return Stream.concat( super.getUnhandledComments(), - components.stream().anyMatch(it -> it.toString().contains(System.lineSeparator())) ? - Stream.of() : components.stream().flatMap(MalleableString::getUnhandledComments) + components.stream().map(MalleableString::toString) + .anyMatch(s -> s.contains("\r") || s.contains("\n")) ? Stream.of() + : components.stream().flatMap(MalleableString::getUnhandledComments) ); } } From 566079527a3c43fd06633dd612f245db4ce62075 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 01:16:10 -0700 Subject: [PATCH 061/130] [formatting] Do not drop sibling comments. Previously, comments appearing after the last element of a sequence would be dropped. --- org.lflang/src/org/lflang/ast/ToLf.java | 31 +++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index d54cb7ade1..6a54139966 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -1,5 +1,6 @@ package org.lflang.ast; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -10,8 +11,10 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.Keyword; +import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; +import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; @@ -128,22 +131,36 @@ private ICompositeNode getNextCompositeSibling(INode node) { INode sibling = node; while ((sibling = sibling.getNextSibling()) != null) { if (sibling instanceof ICompositeNode compositeSibling) return compositeSibling; - if ( - !(sibling.getGrammarElement() instanceof Keyword) - || sibling.getText().contains("\n") - ) break; } return null; } + private Stream getFollowingNonCompositeSiblings(ICompositeNode node) { + INode sibling = node; + List ret = new ArrayList<>(); + while ( + (sibling = sibling.getNextSibling()) != null + && !(sibling instanceof ICompositeNode) + ) { + ret.add(sibling); + } + return ret.stream(); + } + private Stream getFollowingComments(ICompositeNode node) { ICompositeNode sibling = getNextCompositeSibling(node); - if (sibling == null) return Stream.of(); + Stream followingSiblingComments = getFollowingNonCompositeSiblings(node) + .filter( + otherSibling -> otherSibling instanceof HiddenLeafNode hlNode + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().endsWith("COMMENT") + ).map(INode::getText); + if (sibling == null) return followingSiblingComments; Predicate filter = sameLine(node).and(sameLine(sibling).negate()); - return Stream.concat( + return Stream.concat(followingSiblingComments, Stream.concat( ASTUtils.getPrecedingComments(sibling, false, filter).stream(), ASTUtils.getPrecedingComments(sibling, true, filter).stream() - ); + )); } private Predicate sameLine(INode node) { From af8b2b953a674e81f7adc3f8ace5a96b60d38518 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 01:24:40 -0700 Subject: [PATCH 062/130] [formatting] Format C concurrent tests. --- test/C/src/concurrent/AsyncCallback.lf | 31 ++++---- test/C/src/concurrent/AsyncCallbackDrop.lf | 27 ++++--- test/C/src/concurrent/AsyncCallbackReplace.lf | 27 ++++--- test/C/src/concurrent/CompositionThreaded.lf | 36 +++++---- .../DeadlineHandledAboveThreaded.lf | 24 ++++-- test/C/src/concurrent/DeadlineThreaded.lf | 38 +++++----- test/C/src/concurrent/DelayIntThreaded.lf | 35 ++++++--- test/C/src/concurrent/DeterminismThreaded.lf | 40 ++++++---- .../src/concurrent/DoubleReactionThreaded.lf | 43 ++++++----- test/C/src/concurrent/GainThreaded.lf | 30 +++++--- test/C/src/concurrent/HelloThreaded.lf | 46 ++++++----- test/C/src/concurrent/ImportThreaded.lf | 15 ++-- test/C/src/concurrent/MinimalThreaded.lf | 8 +- test/C/src/concurrent/PingPongThreaded.lf | 72 ++++++++++-------- test/C/src/concurrent/ScheduleAt.lf | 76 ++++++++++++++----- test/C/src/concurrent/ScheduleTwice.lf | 12 ++- .../C/src/concurrent/ScheduleTwiceThreaded.lf | 11 ++- .../C/src/concurrent/SendingInsideThreaded.lf | 26 ++++--- test/C/src/concurrent/StarvationThreaded.lf | 34 +++++---- test/C/src/concurrent/StopThreaded.lf | 24 +++--- test/C/src/concurrent/StopZeroThreaded.lf | 30 +++++--- test/C/src/concurrent/Threaded.lf | 67 +++++++++------- test/C/src/concurrent/ThreadedMultiport.lf | 51 ++++++++----- test/C/src/concurrent/ThreadedThreaded.lf | 60 +++++++++------ test/C/src/concurrent/TimeLimitThreaded.lf | 48 +++++++----- test/C/src/concurrent/TimeoutThreaded.lf | 22 +++--- test/C/src/concurrent/TimeoutZeroThreaded.lf | 23 +++--- test/C/src/concurrent/Tracing.lf | 59 ++++++++------ test/C/src/concurrent/Workers.lf | 3 +- 29 files changed, 605 insertions(+), 413 deletions(-) diff --git a/test/C/src/concurrent/AsyncCallback.lf b/test/C/src/concurrent/AsyncCallback.lf index 1f947525ff..f6be050c2a 100644 --- a/test/C/src/concurrent/AsyncCallback.lf +++ b/test/C/src/concurrent/AsyncCallback.lf @@ -1,20 +1,15 @@ /** - * Test asynchronous callbacks that trigger a physical action. - * This test case assumes that target is multithreaded. - * This test will not work with the unthreaded C target because that target - * does not implement any mutex protecting the event queue. + * Test asynchronous callbacks that trigger a physical action. This test case + * assumes that target is multithreaded. This test will not work with the + * unthreaded C target because that target does not implement any mutex + * protecting the event queue. * * Note: This test uses the LF platform support to enable it to run on multiple - * platforms. + * platforms. */ - -target C { - tracing: true, - timeout: 2 sec -}; +target C { tracing: true, timeout: 2 sec } main reactor AsyncCallback { - preamble {= void callback(void* a) { // Schedule twice. If the action is not physical, these should @@ -34,13 +29,15 @@ main reactor AsyncCallback { } lf_thread_t threadId; =} - timer t(0, 200 msec); - state thread_id:lf_thread_t(0); - state expected_time:time(100 msec); - state toggle:bool(false); - physical action a(100 msec):int; - state i:int(0); + timer t(0, 200 msec) + + physical action a(100 msec): int + + state thread_id: lf_thread_t(0) + state expected_time: time(100 msec) + state toggle: bool(false) + state i: int(0) reaction(t) -> a {= // start new thread, provide callback diff --git a/test/C/src/concurrent/AsyncCallbackDrop.lf b/test/C/src/concurrent/AsyncCallbackDrop.lf index 6ceee20954..fc0ce52109 100644 --- a/test/C/src/concurrent/AsyncCallbackDrop.lf +++ b/test/C/src/concurrent/AsyncCallbackDrop.lf @@ -1,13 +1,10 @@ -// Test asynchronous callbacks that trigger a physical action with a DROP policy. -// This test case assumes that the target is multithreaded. -// This test will not work with the unthreaded C target because that target -// does not implement any mutex protecting the event queue. -target C { - timeout: 2 sec -}; +// Test asynchronous callbacks that trigger a physical action with a DROP +// policy. This test case assumes that the target is multithreaded. This test +// will not work with the unthreaded C target because that target does not +// implement any mutex protecting the event queue. +target C { timeout: 2 sec } main reactor { - preamble {= void callback(void* a) { // Schedule twice in rapid succession. @@ -27,13 +24,15 @@ main reactor { } lf_thread_t threadId; =} - timer t(0, 200 msec); - state thread_id:lf_thread_t(0); - state expected_time:time(100 msec); - state toggle:bool(false); - physical action a(100 msec, 100 msec, "drop"):int; - state i:int(0); + timer t(0, 200 msec) + + physical action a(100 msec, 100 msec, "drop"): int + + state thread_id: lf_thread_t(0) + state expected_time: time(100 msec) + state toggle: bool(false) + state i: int(0) reaction(t) -> a {= // start new thread, provide callback diff --git a/test/C/src/concurrent/AsyncCallbackReplace.lf b/test/C/src/concurrent/AsyncCallbackReplace.lf index 3492fb3211..8f4bdf3913 100644 --- a/test/C/src/concurrent/AsyncCallbackReplace.lf +++ b/test/C/src/concurrent/AsyncCallbackReplace.lf @@ -1,13 +1,10 @@ -// Test asynchronous callbacks that trigger a physical action with a "replace" policy. -// This test case assumes that the target is multithreaded. -// This test will not work with the unthreaded C target because that target -// does not implement any mutex protecting the event queue. -target C { - timeout: 2 sec -}; +// Test asynchronous callbacks that trigger a physical action with a "replace" +// policy. This test case assumes that the target is multithreaded. This test +// will not work with the unthreaded C target because that target does not +// implement any mutex protecting the event queue. +target C { timeout: 2 sec } main reactor { - preamble {= void callback(void* a) { // Schedule twice in rapid succession. @@ -27,13 +24,15 @@ main reactor { } lf_thread_t threadId; =} - timer t(0, 200 msec); - state thread_id:lf_thread_t(0); - state expected_time:time(100 msec); - state toggle:bool(false); - physical action a(100 msec, 100 msec, "replace"):int; - state i:int(0); + timer t(0, 200 msec) + + physical action a(100 msec, 100 msec, "replace"): int + + state thread_id: lf_thread_t(0) + state expected_time: time(100 msec) + state toggle: bool(false) + state i: int(0) reaction(t) -> a {= // start new thread, provide callback diff --git a/test/C/src/concurrent/CompositionThreaded.lf b/test/C/src/concurrent/CompositionThreaded.lf index ea7b62dc8e..4f1d332661 100644 --- a/test/C/src/concurrent/CompositionThreaded.lf +++ b/test/C/src/concurrent/CompositionThreaded.lf @@ -1,22 +1,25 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - fast: true, - timeout: 10 sec -}; - -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; lf_set(y, self->count); =} } + reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -28,7 +31,8 @@ reactor Test { } main reactor CompositionThreaded { - s = new Source(); - d = new Test(); - s.y -> d.x; + s = new Source() + d = new Test() + + s.y -> d.x } diff --git a/test/C/src/concurrent/DeadlineHandledAboveThreaded.lf b/test/C/src/concurrent/DeadlineHandledAboveThreaded.lf index 2bd268ce02..349d64dafb 100644 --- a/test/C/src/concurrent/DeadlineHandledAboveThreaded.lf +++ b/test/C/src/concurrent/DeadlineHandledAboveThreaded.lf @@ -1,9 +1,12 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target C; -reactor Deadline(threshold:time(100 msec)) { - input x:int; - output deadline_violation:bool; +// Test a deadline where the deadline violation produces an output and the +// container reacts to that output. +target C + +reactor Deadline(threshold: time(100 msec)) { + input x: int + + output deadline_violation: bool + reaction(x) -> deadline_violation {= printf("ERROR: Deadline violation was not detected!\n"); exit(1); @@ -12,9 +15,12 @@ reactor Deadline(threshold:time(100 msec)) { lf_set(deadline_violation, true); =} } + main reactor { - state violation_detected:bool(false); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected: bool(false) + reaction(startup) -> d.x {= // Do not use nanosleep() here because if this is threaded, // it gets awakened right away. @@ -23,12 +29,14 @@ main reactor { while (lf_time_physical() < start_time + sleep_time) {}; lf_set(d.x, 42); =} + reaction(d.deadline_violation) {= if (d.deadline_violation) { printf("Output successfully produced by deadline miss handler.\n"); self->violation_detected = true; } =} + reaction(shutdown) {= if (self->violation_detected) { printf("SUCCESS. Test passes.\n"); diff --git a/test/C/src/concurrent/DeadlineThreaded.lf b/test/C/src/concurrent/DeadlineThreaded.lf index e39b971667..291eb9bd13 100644 --- a/test/C/src/concurrent/DeadlineThreaded.lf +++ b/test/C/src/concurrent/DeadlineThreaded.lf @@ -1,14 +1,15 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target C { - timeout: 3 sec, -}; - -reactor Source(period:time(1500 msec)) { - output y:int; - timer t(0, period); - state count:int(0); +// This example illustrates local deadline handling. Even numbers are sent by +// the Source immediately, whereas odd numbers are sent after a big enough delay +// to violate the deadline. +target C { timeout: 3 sec } + +reactor Source(period: time(1500 msec)) { + output y: int + + timer t(0, period) + + state count: int(0) + reaction(t) -> y {= if (2 * (self->count / 2) != self->count) { // The count variable is odd. @@ -25,9 +26,11 @@ reactor Source(period:time(1500 msec)) { =} } -reactor Destination(timeout:time(1 sec)) { - input x:int; - state count:int(0); +reactor Destination(timeout: time(1 sec)) { + input x: int + + state count: int(0) + reaction(x) {= printf("Destination receives: %d\n", x->value); if (2 * (self->count / 2) != self->count) { @@ -48,7 +51,8 @@ reactor Destination(timeout:time(1 sec)) { } main reactor { - s = new Source(); - d = new Destination(timeout = 200 msec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 200 msec) + + s.y -> d.x } diff --git a/test/C/src/concurrent/DelayIntThreaded.lf b/test/C/src/concurrent/DelayIntThreaded.lf index bdd29b35ff..7b17bee23e 100644 --- a/test/C/src/concurrent/DelayIntThreaded.lf +++ b/test/C/src/concurrent/DelayIntThreaded.lf @@ -1,26 +1,34 @@ // This tests actions with payloads by delaying an input by a fixed amount. -target C { -}; -reactor Delay(delay:time(100 msec)) { - input in:int; - output out:int; - logical action a:int; +target C + +reactor Delay(delay: time(100 msec)) { + input in: int + + output out: int + + logical action a: int + reaction(a) -> out {= lf_set(out, a->value); =} + reaction(in) -> a {= // Use specialized form of schedule for integer payloads. lf_schedule_int(a, self->delay, in->value); =} } + reactor Test { - input in:int; - state start_time:time(0); - state received_value:bool(false); + input in: int + + state start_time: time(0) + state received_value: bool(false) + reaction(startup) {= // Record the logical time at the start. self->start_time = lf_time_logical(); =} + reaction(in) {= printf("Received: %d.\n", in->value); self->received_value = true; @@ -37,6 +45,7 @@ reactor Test { exit(2); } =} + reaction(shutdown) {= printf("Checking that communication occurred.\n"); if (!self->received_value) { @@ -47,9 +56,11 @@ reactor Test { } main reactor { - d = new Delay(); - t = new Test(); - d.out -> t.in; + d = new Delay() + t = new Test() + + d.out -> t.in + reaction(startup) -> d.in {= lf_set(d.in, 42); =} diff --git a/test/C/src/concurrent/DeterminismThreaded.lf b/test/C/src/concurrent/DeterminismThreaded.lf index e6edddbf43..636a376674 100644 --- a/test/C/src/concurrent/DeterminismThreaded.lf +++ b/test/C/src/concurrent/DeterminismThreaded.lf @@ -1,15 +1,19 @@ -target C { -}; +target C + reactor Source { - output y:int; - timer t; + output y: int + + timer t + reaction(t) -> y {= lf_set(y, 1); =} } + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= int sum = 0; if (x->is_present) { @@ -25,21 +29,25 @@ reactor Destination { } =} } + reactor Pass { - input x:int; - output y:int; + input x: int + + output y: int + reaction(x) -> y {= lf_set(y, x->value); =} } main reactor { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/C/src/concurrent/DoubleReactionThreaded.lf b/test/C/src/concurrent/DoubleReactionThreaded.lf index 56bb2e2f13..676e413a3a 100644 --- a/test/C/src/concurrent/DoubleReactionThreaded.lf +++ b/test/C/src/concurrent/DoubleReactionThreaded.lf @@ -1,23 +1,26 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target C { - timeout: 10 sec, - fast: true, -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that two simultaneous inputs that trigger a reaction trigger it only +// once. Correct output for this 2, 4, 6, 8, etc. +target C { timeout: 10 sec, fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; lf_set(y, self->count); =} } + reactor Destination { - input x:int; - input w:int; - state s:int(2); + input x: int + input w: int + + state s: int(2) + reaction(x, w) {= int sum = 0; if (x->is_present) { @@ -34,10 +37,12 @@ reactor Destination { self->s += 2; =} } + main reactor DoubleReactionThreaded { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/C/src/concurrent/GainThreaded.lf b/test/C/src/concurrent/GainThreaded.lf index 3ba998b549..d8fd54130d 100644 --- a/test/C/src/concurrent/GainThreaded.lf +++ b/test/C/src/concurrent/GainThreaded.lf @@ -1,15 +1,21 @@ -// Example in the Wiki. -target C; -reactor Scale(scale:int(2)) { - input x:int; - output y:int; +/** Example in the Wiki. */ +target C + +reactor Scale(scale: int(2)) { + input x: int + + output y: int + reaction(x) -> y {= lf_set(y, x->value * self->scale); =} } + reactor Test { - input x:int; - state received_value:bool(false); + input x: int + + state received_value: bool(false) + reaction(x) {= printf("Received %d.\n", x->value); self->received_value = true; @@ -18,6 +24,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (!self->received_value) { printf("ERROR: No value received by Test reactor!\n"); @@ -26,10 +33,13 @@ reactor Test { } =} } + main reactor { - g = new Scale(); - d = new Test(); - g.y -> d.x; + g = new Scale() + d = new Test() + + g.y -> d.x + reaction(startup) -> g.x {= lf_set(g.x, 1); =} diff --git a/test/C/src/concurrent/HelloThreaded.lf b/test/C/src/concurrent/HelloThreaded.lf index 0febdbbb74..787edc2997 100644 --- a/test/C/src/concurrent/HelloThreaded.lf +++ b/test/C/src/concurrent/HelloThreaded.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the lf_schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target C { - timeout: 10 sec, - fast: true, -}; -reactor Reschedule(period:time(2 secs), message:string("Hello C")) { - state count:int(0); - state previous_time:time(0); - timer t(1 secs, period); - logical action a; +// This test checks that logical time is incremented an appropriate amount as a +// result of an invocation of the lf_schedule() function at runtime. It also +// performs various smoke tests of timing aligned reactions. The first instance +// has a period of 4 seconds, the second of 2 seconds, and the third (composite) +// or 1 second. +target C { timeout: 10 sec, fast: true } + +reactor Reschedule(period: time(2 sec), message: string("Hello C")) { + timer t(1 sec, period) + + logical action a + + state count: int(0) + state previous_time: time(0) + reaction(t) -> a {= printf("%s\n", self->message); lf_schedule(a, MSEC(200)); @@ -39,12 +40,19 @@ reactor Reschedule(period:time(2 secs), message:string("Hello C")) { } =} } -reactor Inside(period:time(1 sec), message:string("Composite default message.")) { - third_instance = new Reschedule(period = period, message = message); + +reactor Inside( + period: time(1 sec), + message: string("Composite default message.") +) { + third_instance = new Reschedule(period = period, message = message) } main reactor HelloThreaded { - first_instance = new Reschedule(period = 4 sec, message = "Hello from first_instance."); - second_instance = new Reschedule(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new Reschedule( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new Reschedule(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/C/src/concurrent/ImportThreaded.lf b/test/C/src/concurrent/ImportThreaded.lf index ac0e0cbf38..b8bfa7532c 100644 --- a/test/C/src/concurrent/ImportThreaded.lf +++ b/test/C/src/concurrent/ImportThreaded.lf @@ -1,13 +1,14 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target C { -}; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target C -import Imported from "../lib/Imported.lf"; +import Imported from "../lib/Imported.lf" main reactor ImportThreaded { - timer t; - a = new Imported(); + timer t + + a = new Imported() + reaction(t) -> a.x {= lf_set(a.x, 42); =} diff --git a/test/C/src/concurrent/MinimalThreaded.lf b/test/C/src/concurrent/MinimalThreaded.lf index 3e8d0e8804..3227b08665 100644 --- a/test/C/src/concurrent/MinimalThreaded.lf +++ b/test/C/src/concurrent/MinimalThreaded.lf @@ -1,8 +1,8 @@ -// This is a smoke test of a minimal reactor. -target C { -}; +target C // This is a smoke test of a minimal reactor. + main reactor MinimalThreaded { - timer t; + timer t + reaction(t) {= printf("Hello World.\n"); =} diff --git a/test/C/src/concurrent/PingPongThreaded.lf b/test/C/src/concurrent/PingPongThreaded.lf index 88c27ecd5d..b27cf7b3d7 100644 --- a/test/C/src/concurrent/PingPongThreaded.lf +++ b/test/C/src/concurrent/PingPongThreaded.lf @@ -1,38 +1,42 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54. See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * Ping introduces a microstep delay using a logical action - * to break the causality loop. + * Ping introduces a microstep delay using a logical action to break the + * causality loop. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec (168 msec with optimization of executing immediately) + * Unthreaded: 97 msec Threaded: 265 msec (168 msec with optimization of + * executing immediately) * - * There is no parallelism in this application, so it does not benefit from being - * being threaded, just some additional overhead. + * There is no parallelism in this application, so it does not benefit from + * being being threaded, just some additional overhead. * * These measurements are total execution time, including startup and shutdown. - * These are about an order of magnitude faster than anything reported in the paper. + * These are about an order of magnitude faster than anything reported in the + * paper. * * @author Edward A. Lee */ -target C { - fast: true, -}; -reactor Ping(count:int(10)) { - input receive:int; - output send:int; - state pingsLeft:int(count); - logical action serve; - reaction (startup, serve) -> send {= +target C { fast: true } + +reactor Ping(count: int(10)) { + input receive: int + + output send: int + + logical action serve + + state pingsLeft: int(count) + + reaction(startup, serve) -> send {= lf_set(send, self->pingsLeft--); =} - reaction (receive) -> serve {= + + reaction(receive) -> serve {= if (self->pingsLeft > 0) { lf_schedule(serve, 0); } else { @@ -40,14 +44,19 @@ reactor Ping(count:int(10)) { } =} } -reactor Pong(expected:int(10)) { - input receive:int; - output send:int; - state count:int(0); + +reactor Pong(expected: int(10)) { + input receive: int + + output send: int + + state count: int(0) + reaction(receive) -> send {= self->count++; lf_set(send, receive->value); =} + reaction(shutdown) {= if (self->count != self->expected) { fprintf(stderr, "Pong expected to receive %d inputs, but it received %d.\n", @@ -60,8 +69,9 @@ reactor Pong(expected:int(10)) { } main reactor PingPongThreaded { - ping = new Ping(); - pong = new Pong(); - ping.send -> pong.receive; - pong.send -> ping.receive; + ping = new Ping() + pong = new Pong() + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/C/src/concurrent/ScheduleAt.lf b/test/C/src/concurrent/ScheduleAt.lf index 9a6d430398..9e09beccbd 100644 --- a/test/C/src/concurrent/ScheduleAt.lf +++ b/test/C/src/concurrent/ScheduleAt.lf @@ -1,25 +1,67 @@ /** - * Test _lf_schedule_at_tag which is an internal API function - * not meant to be used in user code. + * Test _lf_schedule_at_tag which is an internal API function not meant to be + * used in user code. * * @author Soroush Bateni */ - -target C { - timeout: 1 sec, - keepalive: true, -}; +target C { timeout: 1 sec, keepalive: true } reactor Scheduler { - logical action act; - state microstep_delay_list:uint32_t[](0,1,1,2,2,0,0,1,1,0,2,3,3,4,4,5); // List of microsteps. Size = 16 - state times:int[](0,0,0,0,0, 400 msec, 400 msec, 400 msec, 400 msec, // List of the corresponding times. Size = 16 - 800 msec, 800 msec, 800 msec, 800 msec, 900 msec, - 900 msec, 900 msec); - state action_hit_list_microstep:int[](1, 2, 0, 1, 0, 2, 3, 4, 5); // Size = 9 - state action_hit_list_times:int[](0, 0, 400 msec, 400msec, 800 msec, 800 msec, - 800 msec, 900msec, 900msec); // Size = 9 - state action_hit_list_index:int(0); + logical action act + + // List of microsteps. Size = 16 + state microstep_delay_list: uint32_t[]( + 0, + 1, + 1, + 2, + 2, + 0, + 0, + 1, + 1, + 0, + 2, + 3, + 3, + 4, + 4, + 5 + ) + state times: int[]( + 0, + 0, + 0, + 0, + 0, + 400 msec, + 400 msec, + 400 msec, + 400 msec, // List of the corresponding times. Size = 16 + 800 msec, + 800 msec, + 800 msec, + 800 msec, + 900 msec, + 900 msec, + 900 msec + ) + // Size = 9 + state action_hit_list_microstep: int[](1, 2, 0, 1, 0, 2, 3, 4, 5) + // Size = 9 + state action_hit_list_times: int[]( + 0, + 0, + 400 msec, + 400 msec, + 800 msec, + 800 msec, + 800 msec, + 900 msec, + 900 msec + ) + state action_hit_list_index: int(0) + reaction(startup) -> act {= for (int i=0; i < 16; i++) { _lf_schedule_at_tag(act->trigger, @@ -48,5 +90,5 @@ reactor Scheduler { } main reactor ScheduleAt { - sender = new Scheduler(); + sender = new Scheduler() } diff --git a/test/C/src/concurrent/ScheduleTwice.lf b/test/C/src/concurrent/ScheduleTwice.lf index 78c88592ee..0fdfcdfb47 100644 --- a/test/C/src/concurrent/ScheduleTwice.lf +++ b/test/C/src/concurrent/ScheduleTwice.lf @@ -1,14 +1,19 @@ -target C; +target C + main reactor ScheduleTwice { - logical action a:int; - state rc_count:int(0); preamble {= #define VERBOSE =} + + logical action a: int + + state rc_count: int(0) + reaction(startup) -> a {= lf_schedule_int(a, MSEC(100), 42); lf_schedule_int(a, MSEC(100), 84); =} + reaction(a) {= printf("Received %d at tag(%lld, %u).\n", a->value, lf_time_logical_elapsed(), lf_tag().microstep); if (lf_tag().microstep == 0 && a->value != 42) { @@ -21,6 +26,7 @@ main reactor ScheduleTwice { } self->rc_count++; =} + reaction(shutdown) {= if (self->rc_count < 2) { fprintf(stderr, "Didn't see two events.\n"); diff --git a/test/C/src/concurrent/ScheduleTwiceThreaded.lf b/test/C/src/concurrent/ScheduleTwiceThreaded.lf index d5906ada19..c9cd558de0 100644 --- a/test/C/src/concurrent/ScheduleTwiceThreaded.lf +++ b/test/C/src/concurrent/ScheduleTwiceThreaded.lf @@ -1,11 +1,15 @@ -target C; +target C + main reactor { - logical action a:int; - state rc_count:int(0); + logical action a: int + + state rc_count: int(0) + reaction(startup) -> a {= lf_schedule_int(a, MSEC(100), 42); lf_schedule_int(a, MSEC(100), 84); =} + reaction(a) {= printf("Received %d at tag(%lld, %u).\n", a->value, lf_time_logical_elapsed(), lf_tag().microstep); if (lf_tag().microstep == 0 && a->value != 42) { @@ -18,6 +22,7 @@ main reactor { } self->rc_count++; =} + reaction(shutdown) {= if (self->rc_count < 2) { fprintf(stderr, "Didn't see two events.\n"); diff --git a/test/C/src/concurrent/SendingInsideThreaded.lf b/test/C/src/concurrent/SendingInsideThreaded.lf index 1b4cb04d25..55b2f7319f 100644 --- a/test/C/src/concurrent/SendingInsideThreaded.lf +++ b/test/C/src/concurrent/SendingInsideThreaded.lf @@ -1,12 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. -target C { - timeout: 10 sec, - fast: true -}; +// This tests a reactor that contains another reactor and also has its own +// reaction that routes inputs to the contained reactor. +target C { timeout: 10 sec, fast: true } + reactor Printer { - input x:int; - state count:int(1); + input x: int + + state count: int(1) + reaction(x) {= printf("Inside reactor received: %d\n", x->value); if (x->value != self->count) { @@ -16,10 +16,14 @@ reactor Printer { self->count++; =} } + main reactor SendingInsideThreaded { - state count:int(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count: int(0) + reaction(t) -> p.x {= (self->count)++; lf_set(p.x, self->count); diff --git a/test/C/src/concurrent/StarvationThreaded.lf b/test/C/src/concurrent/StarvationThreaded.lf index 2df6fa5cc9..1060c60d56 100644 --- a/test/C/src/concurrent/StarvationThreaded.lf +++ b/test/C/src/concurrent/StarvationThreaded.lf @@ -1,16 +1,19 @@ /** - * Test that the starvation functionality in absence of - * the "keepalive: true" target property indeed works as - * expected. This version uses the threaded runtime. + * Test that the starvation functionality in absence of the "keepalive: true" + * target property indeed works as expected. This version uses the threaded + * runtime. * * @author Soroush Bateni */ -target C { -}; -reactor SuperDenseSender(number_of_iterations:int(10)){ - logical action loop; - output out:int; - state iterator:int(0); +target C + +reactor SuperDenseSender(number_of_iterations: int(10)) { + output out: int + + logical action loop + + state iterator: int(0) + reaction(startup, loop) -> out {= if (self->iterator < self->number_of_iterations) { lf_schedule(loop, 0); @@ -32,10 +35,11 @@ reactor SuperDenseSender(number_of_iterations:int(10)){ exit(1); } =} - } +} + +reactor SuperDenseReceiver(number_of_iterations: int(10)) { + input in: int - reactor SuperDenseReceiver(number_of_iterations:int(10)) { - input in:int; reaction(in) {= tag_t current_tag = lf_tag(); printf("Received %d at tag (%lld, %u).\n", @@ -60,8 +64,8 @@ reactor SuperDenseSender(number_of_iterations:int(10)){ } main reactor StarvationThreaded { - sender = new[8] SuperDenseSender(); - receiver = new[8] SuperDenseReceiver(); + sender = new[8] SuperDenseSender() + receiver = new[8] SuperDenseReceiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/concurrent/StopThreaded.lf b/test/C/src/concurrent/StopThreaded.lf index c5cc8f690d..658dc186a5 100644 --- a/test/C/src/concurrent/StopThreaded.lf +++ b/test/C/src/concurrent/StopThreaded.lf @@ -1,20 +1,18 @@ -/* - * A test for the lf_request_stop() functionality in Lingua Franca. - * This version of the test is threaded. +/** + * A test for the lf_request_stop() functionality in Lingua Franca. This version + * of the test is threaded. * * @author Soroush Bateni */ -target C { - timeout: 11 msec, - build-type: RelWithDebInfo, - // logging: DEBUG -}; +target C { timeout: 11 msec, build-type: RelWithDebInfo } import Sender from "../lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state reaction_invoked_correctly:bool(false); + input in: int + + state reaction_invoked_correctly: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -58,8 +56,8 @@ reactor Consumer { } main reactor { - consumer = new[4] Consumer(); - producer = new[4] Sender(break_interval = 1 msec); + consumer = new[4] Consumer() + producer = new[4] Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/concurrent/StopZeroThreaded.lf b/test/C/src/concurrent/StopZeroThreaded.lf index 0364eaea2a..d56af9412c 100644 --- a/test/C/src/concurrent/StopZeroThreaded.lf +++ b/test/C/src/concurrent/StopZeroThreaded.lf @@ -1,17 +1,20 @@ /** - * Test for lf_request_stop() at tag (0,0). - * This version uses the threaded runtime. + * Test for lf_request_stop() at tag (0,0). This version uses the threaded + * runtime. * * @author Soroush Bateni */ -target C { -}; +target C reactor Sender { - output out:int; - state reaction_invoked_correctly:bool(false); - timer t(0, 1 usec); - logical action act; + output out: int + + timer t(0, 1 usec) + + logical action act + + state reaction_invoked_correctly: bool(false) + reaction(t) -> out, act {= printf("Sending 42 at (%lld, %u).\n", lf_time_logical_elapsed(), @@ -33,6 +36,7 @@ reactor Sender { exit(1); } =} + reaction(act) {= // Reaction should be invoked at (0,1) tag_t one = (tag_t) { .time = lf_time_start(), .microstep = 1u }; @@ -40,6 +44,7 @@ reactor Sender { self->reaction_invoked_correctly = true; } =} + reaction(shutdown) {= if (lf_time_logical_elapsed() != USEC(0) || lf_tag().microstep != 1) { @@ -62,7 +67,8 @@ reactor Sender { } reactor Receiver { - input in:int; + input in: int + reaction(in) {= printf("Received %d at (%lld, %u).\n", in->value, @@ -96,8 +102,8 @@ reactor Receiver { } main reactor StopZeroThreaded { - sender = new[4] Sender(); - receiver = new[4] Receiver(); + sender = new[4] Sender() + receiver = new[4] Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/concurrent/Threaded.lf b/test/C/src/concurrent/Threaded.lf index bad1b37f2c..ab7a757ecf 100644 --- a/test/C/src/concurrent/Threaded.lf +++ b/test/C/src/concurrent/Threaded.lf @@ -1,29 +1,39 @@ -// Check for speedup of multithreaded execution on multicore machines. -// Each instance of TakeTime takes 200 ms to transport the input to the output. -// Four of them are instantiated. -// Note that without parallel execution, there is no way this can keep up with real time -// since in every 200 msec cycle it has 800 msec of work to do. -// On a quad-core machine, however, it does pretty well, completing 800 msec of work -// in about 225 msec. -// NOTE: This is the non-threaded version, showing that without threads, this takes more -// than 800 msec to complete 200 msec of logical time. -// See ThreadedMultiport for a parameterized version of this. +/** + * Check for speedup of multithreaded execution on multicore machines. Each + * instance of TakeTime takes 200 ms to transport the input to the output. Four + * of them are instantiated. Note that without parallel execution, there is no + * way this can keep up with real time since in every 200 msec cycle it has 800 + * msec of work to do. On a quad-core machine, however, it does pretty well, + * completing 800 msec of work in about 225 msec. + * + * NOTE: This is the non-threaded version, showing that without threads, this + * takes more than 800 msec to complete 200 msec of logical time. See + * ThreadedMultiport for a parameterized version of this. + */ target C { timeout: 2 sec, - flags: "" // Disable compiler optimization so that TakeTime actually takes time. -}; + // Disable compiler optimization so that TakeTime actually takes time. + flags: "" +} + reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor TakeTime { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= // struct timespec sleep_time = {(time_t) 0, (long)200000000}; // struct timespec remaining_time; @@ -35,9 +45,12 @@ reactor TakeTime { lf_set(out, in->value + offset); =} } -reactor Destination(width:int(4)) { - state s:int(400000000); - input[width] in:int; + +reactor Destination(width: int(4)) { + input[width] in: int + + state s: int(400000000) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -51,10 +64,12 @@ reactor Destination(width:int(4)) { self->s += in_width; =} } -main reactor (width:int(4)) { - a = new Source(); - t = new[width] TakeTime(); - (a.out)+ -> t.in; - b = new Destination(width = width); - t.out -> b.in; + +main reactor(width: int(4)) { + a = new Source() + t = new[width] TakeTime() + b = new Destination(width = width) + + (a.out)+ -> t.in + t.out -> b.in } diff --git a/test/C/src/concurrent/ThreadedMultiport.lf b/test/C/src/concurrent/ThreadedMultiport.lf index fefbdf9233..7c49028c14 100644 --- a/test/C/src/concurrent/ThreadedMultiport.lf +++ b/test/C/src/concurrent/ThreadedMultiport.lf @@ -1,12 +1,17 @@ -// Check multiport capabilities on Outputs. +/** Check multiport capabilities on Outputs. */ target C { timeout: 2 sec, - flags: "", // Disable compiler optimization so that TakeTime actually takes time. -}; -reactor Source(width:int(4)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); + // Disable compiler optimization so that TakeTime actually takes time. + flags: "" +} + +reactor Source(width: int(4)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], self->s); @@ -14,9 +19,12 @@ reactor Source(width:int(4)) { self->s++; =} } -reactor Computation(iterations:int(100000000)) { - input in:int; - output out:int; + +reactor Computation(iterations: int(100000000)) { + input in: int + + output out: int + reaction(in) -> out {= // struct timespec sleep_time = {(time_t) 0, (long)200000000}; // struct timespec remaining_time; @@ -28,9 +36,12 @@ reactor Computation(iterations:int(100000000)) { lf_set(out, in->value + offset); =} } -reactor Destination(width:int(4), iterations:int(100000000)) { - state s:int(0); - input[width] in:int; + +reactor Destination(width: int(4), iterations: int(100000000)) { + input[width] in: int + + state s: int(0) + reaction(in) {= int expected = self->iterations * self->width + self->s; int sum = 0; @@ -44,6 +55,7 @@ reactor Destination(width:int(4), iterations:int(100000000)) { } self->s += self->width; =} + reaction(shutdown) {= if (self->s == 0) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -53,10 +65,11 @@ reactor Destination(width:int(4), iterations:int(100000000)) { =} } -main reactor ThreadedMultiport(width:int(4), iterations:int(100000000)) { - a = new Source(width = width); - t = new[width] Computation(iterations = iterations); - b = new Destination(width = width, iterations = iterations); - a.out -> t.in; - t.out -> b.in; +main reactor ThreadedMultiport(width: int(4), iterations: int(100000000)) { + a = new Source(width = width) + t = new[width] Computation(iterations = iterations) + b = new Destination(width = width, iterations = iterations) + + a.out -> t.in + t.out -> b.in } diff --git a/test/C/src/concurrent/ThreadedThreaded.lf b/test/C/src/concurrent/ThreadedThreaded.lf index dbff8b780b..d74b0325e7 100644 --- a/test/C/src/concurrent/ThreadedThreaded.lf +++ b/test/C/src/concurrent/ThreadedThreaded.lf @@ -1,28 +1,35 @@ -// Check for speedup of multithreaded execution on multicore machines. -// Each instance of TakeTime takes 200 ms to transport the input to the output. -// Four of them are instantiated. -// Note that without parallel execution, there is no way this can keep up with real time -// since in every 200 msec cycle it has 800 msec of work to do. -// On a quad-core machine, however, it does pretty well, completing 800 msec of work -// in about 225 msec. -// See ThreadedMultiport for a parameterized version of this. +// Check for speedup of multithreaded execution on multicore machines. Each +// instance of TakeTime takes 200 ms to transport the input to the output. Four +// of them are instantiated. Note that without parallel execution, there is no +// way this can keep up with real time since in every 200 msec cycle it has 800 +// msec of work to do. On a quad-core machine, however, it does pretty well, +// completing 800 msec of work in about 225 msec. See ThreadedMultiport for a +// parameterized version of this. target C { timeout: 2 sec, tracing: true, - flags: "", // Disable compiler optimization so that TakeTime actually takes time. -}; + // Disable compiler optimization so that TakeTime actually takes time. + flags: "" +} + reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor TakeTime { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= // struct timespec sleep_time = {(time_t) 0, (long)200000000}; // struct timespec remaining_time; @@ -34,9 +41,12 @@ reactor TakeTime { lf_set(out, in->value + offset); =} } -reactor Destination(width:int(4)) { - state s:int(400000000); - input[width] in:int; + +reactor Destination(width: int(4)) { + input[width] in: int + + state s: int(400000000) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -50,10 +60,12 @@ reactor Destination(width:int(4)) { self->s += in_width; =} } -main reactor ThreadedThreaded(width:int(4)) { - a = new Source(); - t = new[width] TakeTime(); - (a.out)+ -> t.in; - b = new Destination(width = width); - t.out -> b.in; + +main reactor ThreadedThreaded(width: int(4)) { + a = new Source() + t = new[width] TakeTime() + b = new Destination(width = width) + + (a.out)+ -> t.in + t.out -> b.in } diff --git a/test/C/src/concurrent/TimeLimitThreaded.lf b/test/C/src/concurrent/TimeLimitThreaded.lf index 86feb23294..b5ba58a9a7 100644 --- a/test/C/src/concurrent/TimeLimitThreaded.lf +++ b/test/C/src/concurrent/TimeLimitThreaded.lf @@ -1,25 +1,28 @@ -// Test that the stop function can be used to internally impose a -// a time limit. -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt. -// See [Benchmarks wiki page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). -target C { - flags: "-O2", - fast: true, -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that the stop function can be used to internally impose a a time limit. +// Correct output for this 1, 2, 3, 4. Failure for this test is failing to halt. +// See [Benchmarks wiki +// page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). +target C { flags: "-O2", fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; //printf("Reacting at time %ld.\n", lf_time_logical_elapsed()); lf_set(y, self->count); =} } + reactor Destination { - input x:int; - state s:int(1); + input x: int + + state s: int(1) + reaction(x) {= // printf("%d\n", x->value); if (x->value != self->s) { @@ -28,6 +31,7 @@ reactor Destination { } self->s++; =} + reaction(shutdown) {= printf("**** shutdown reaction invoked.\n"); if (self->s != 10000002) { @@ -37,12 +41,16 @@ reactor Destination { lf_print("Approx. time per reaction: %lldns", lf_time_physical_elapsed()/(self->s+1)); =} } -main reactor (period:time(1 usec)) { - timer stop(10 secs); + +main reactor(period: time(1 usec)) { + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x + reaction(stop) {= lf_request_stop(); =} - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; } diff --git a/test/C/src/concurrent/TimeoutThreaded.lf b/test/C/src/concurrent/TimeoutThreaded.lf index 5dc3258a3b..3dbf9dc85f 100644 --- a/test/C/src/concurrent/TimeoutThreaded.lf +++ b/test/C/src/concurrent/TimeoutThreaded.lf @@ -1,18 +1,18 @@ -/* - * A test for the timeout functionality in Lingua Franca. - * This version of the test is threaded. +/** + * A test for the timeout functionality in Lingua Franca. This version of the + * test is threaded. * * @author Soroush Bateni */ -target C { - timeout: 11 msec, -}; +target C { timeout: 11 msec } import Sender from "../lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state success:bool(false); + input in: int + + state success: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -41,8 +41,8 @@ reactor Consumer { } main reactor { - consumer = new[4] Consumer(); - producer = new[4] Sender(break_interval = 1 msec); + consumer = new[4] Consumer() + producer = new[4] Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/concurrent/TimeoutZeroThreaded.lf b/test/C/src/concurrent/TimeoutZeroThreaded.lf index 92901db0e8..0830f95f9d 100644 --- a/test/C/src/concurrent/TimeoutZeroThreaded.lf +++ b/test/C/src/concurrent/TimeoutZeroThreaded.lf @@ -1,19 +1,18 @@ -/* - * A test for the timeout functionality in Lingua Franca. - * This variant tests timeout at (0,0) and uses the threaded - * runtime. +/** + * A test for the timeout functionality in Lingua Franca. This variant tests + * timeout at (0,0) and uses the threaded runtime. * * @author Soroush Bateni */ -target C { - timeout: 0 sec, -}; +target C { timeout: 0 sec } import Sender from "../lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state success:bool(false); + input in: int + + state success: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -42,8 +41,8 @@ reactor Consumer { } main reactor { - consumer = new[4] Consumer(); - producer = new[4] Sender(break_interval = 1 msec); + consumer = new[4] Consumer() + producer = new[4] Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/concurrent/Tracing.lf b/test/C/src/concurrent/Tracing.lf index ce29149294..faf57978bc 100644 --- a/test/C/src/concurrent/Tracing.lf +++ b/test/C/src/concurrent/Tracing.lf @@ -1,25 +1,32 @@ -// Version of ThreadedThreaded used to test tracing functions. +/** Version of ThreadedThreaded used to test tracing functions. */ target C { timeout: 2 sec, tracing: true, - flags: "", // Disable compiler optimization so that TakeTime actually takes time. + // Disable compiler optimization so that TakeTime actually takes time. + flags: "", logging: DEBUG -}; +} + reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } -reactor TakeTime( - bank_index:int(0) -) { - input in:int; - output out:int; - state event:string("No ID"); + +reactor TakeTime(bank_index: int(0)) { + input in: int + + output out: int + + state event: string("No ID") + reaction(startup) {= // Construct an id string for a user trace event. const char* format = "Count completed by reactor %d."; @@ -33,6 +40,7 @@ reactor TakeTime( exit(1); } =} + reaction(in) -> out {= // struct timespec sleep_time = {(time_t) 0, (long)200000000}; // struct timespec remaining_time; @@ -44,6 +52,7 @@ reactor TakeTime( tracepoint_user_event(self->event); lf_set(out, in->value + offset); =} + reaction(shutdown) {= // NOTE: Can't actually free this because the tracepoint // code runs after shutdown events are processed and the @@ -51,10 +60,13 @@ reactor TakeTime( // free(self->event); =} } -reactor Destination(width:int(4)) { - state s:int(400000000); - state count:int(0); - input[width] in:int; + +reactor Destination(width: int(4)) { + input[width] in: int + + state s: int(400000000) + state count: int(0) + reaction(startup) {= // Register the user value event. if (!register_user_trace_event("Number of Destination invocations")) { @@ -62,6 +74,7 @@ reactor Destination(width:int(4)) { exit(1); } =} + reaction(in) {= self->count++; tracepoint_user_value("Number of Destination invocations", self->count); @@ -77,10 +90,12 @@ reactor Destination(width:int(4)) { self->s += in_width; =} } -main reactor (width:int(4)) { - a = new Source(); - t = new[width] TakeTime(); - (a.out)+ -> t.in; - b = new Destination(width = width); - t.out -> b.in; + +main reactor(width: int(4)) { + a = new Source() + t = new[width] TakeTime() + b = new Destination(width = width) + + (a.out)+ -> t.in + t.out -> b.in } diff --git a/test/C/src/concurrent/Workers.lf b/test/C/src/concurrent/Workers.lf index 879ce62809..09ee603912 100644 --- a/test/C/src/concurrent/Workers.lf +++ b/test/C/src/concurrent/Workers.lf @@ -1,4 +1,5 @@ -target C { workers: 16 }; +target C { workers: 16 } + main reactor { reaction(startup) {= if (NUMBER_OF_WORKERS != 16) { From 26decb59a83432bd6d914905606cc4e61c1365f6 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 01:57:24 -0700 Subject: [PATCH 063/130] [formatting] Do fancier tree climbing :-/ --- org.lflang/src/org/lflang/ast/ToLf.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 6a54139966..ff01f830d0 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -4,13 +4,13 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.Keyword; import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; @@ -99,7 +99,7 @@ public MalleableString doSwitch(EObject eObject) { false, sameLine(node) ); - var previous = node.getPreviousSibling(); + var previous = getNextCompositeSibling(node, INode::getPreviousSibling, true); Predicate doesNotBelongToPrevious = sameLine(node).negate().and( previous == null ? n -> true : sameLine(previous).negate() ); @@ -127,11 +127,18 @@ public MalleableString doSwitch(EObject eObject) { return representation; } - private ICompositeNode getNextCompositeSibling(INode node) { + private ICompositeNode getNextCompositeSibling( + INode node, + Function getNextSibling, + boolean traverseUpwards + ) { INode sibling = node; - while ((sibling = sibling.getNextSibling()) != null) { + while ((sibling = getNextSibling.apply(sibling)) != null) { if (sibling instanceof ICompositeNode compositeSibling) return compositeSibling; } + if (node.getParent() != null && traverseUpwards) { + return getNextCompositeSibling(node.getParent(), getNextSibling, true); + } return null; } @@ -148,7 +155,7 @@ private Stream getFollowingNonCompositeSiblings(ICompositeNode node) { } private Stream getFollowingComments(ICompositeNode node) { - ICompositeNode sibling = getNextCompositeSibling(node); + ICompositeNode sibling = getNextCompositeSibling(node, INode::getNextSibling, false); Stream followingSiblingComments = getFollowingNonCompositeSiblings(node) .filter( otherSibling -> otherSibling instanceof HiddenLeafNode hlNode From 297f1569cc07899ae35f80cf2260958b716b581d Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 02:10:41 -0700 Subject: [PATCH 064/130] [formatting] Format C docker tests. --- .../src/docker/FilesPropertyContainerized.lf | 5 +-- test/C/src/docker/HelloWorldContainerized.lf | 9 +++-- test/C/src/docker/PingPongContainerized.lf | 40 +++++++++---------- .../DistributedCountContainerized.lf | 25 +++++++----- .../DistributedDoublePortContainerized.lf | 27 ++++++------- .../DistributedMultiportContainerized.lf | 15 +++---- ...stributedStopDecentralizedContainerized.lf | 15 ++++--- 7 files changed, 65 insertions(+), 71 deletions(-) diff --git a/test/C/src/docker/FilesPropertyContainerized.lf b/test/C/src/docker/FilesPropertyContainerized.lf index f9a1a240f3..652df06104 100644 --- a/test/C/src/docker/FilesPropertyContainerized.lf +++ b/test/C/src/docker/FilesPropertyContainerized.lf @@ -1,7 +1,4 @@ -target C { - files: "../include/hello.h", - docker: true -} +target C { files: "../include/hello.h", docker: true } preamble {= #include "hello.h" diff --git a/test/C/src/docker/HelloWorldContainerized.lf b/test/C/src/docker/HelloWorldContainerized.lf index 5188ffc9d9..0e5e43a56c 100644 --- a/test/C/src/docker/HelloWorldContainerized.lf +++ b/test/C/src/docker/HelloWorldContainerized.lf @@ -1,12 +1,15 @@ target C { - tracing: {trace-file-name: "HelloWorldTrace"}, // To test generating a custom trace file name. + // To test generating a custom trace file name. + tracing: { + trace-file-name: "HelloWorldTrace" + }, logging: error, docker: true, build-type: Debug -}; +} import HelloWorld2 from "../HelloWorld.lf" main reactor { - a = new HelloWorld2(); + a = new HelloWorld2() } diff --git a/test/C/src/docker/PingPongContainerized.lf b/test/C/src/docker/PingPongContainerized.lf index d451077f70..186092e8fc 100644 --- a/test/C/src/docker/PingPongContainerized.lf +++ b/test/C/src/docker/PingPongContainerized.lf @@ -1,38 +1,34 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * Ping introduces a microstep delay using a logical action - * to break the causality loop. + * Ping introduces a microstep delay using a logical action to break the + * causality loop. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec + * Unthreaded: 97 msec Threaded: 265 msec * - * There is no parallelism in this application, so it does not benefit from being - * being threaded, just some additional overhead. + * There is no parallelism in this application, so it does not benefit from + * being being threaded, just some additional overhead. * * These measurements are total execution time, including startup and shutdown. - * These are about an order of magnitude faster than anything reported in the paper. + * These are about an order of magnitude faster than anything reported in the + * paper. * * @author Edward A. Lee */ -target C { - fast: true, - docker: true -}; +target C { fast: true, docker: true } import Ping from "../PingPong.lf" import Pong from "../PingPong.lf" - main reactor PingPongContainerized { - ping = new Ping(); - pong = new Pong(); - ping.send -> pong.receive; - pong.send -> ping.receive; + ping = new Ping() + pong = new Pong() + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/C/src/docker/federated/DistributedCountContainerized.lf b/test/C/src/docker/federated/DistributedCountContainerized.lf index 7218804392..68da021992 100644 --- a/test/C/src/docker/federated/DistributedCountContainerized.lf +++ b/test/C/src/docker/federated/DistributedCountContainerized.lf @@ -1,21 +1,24 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * + * @author Edward A. Lee */ target C { timeout: 5 sec, logging: DEBUG, coordination: centralized, docker: true -}; +} -import Count from "../../lib/Count.lf"; +import Count from "../../lib/Count.lf" import Print from "../../federated/DistributedCount.lf" -federated reactor DistributedCountContainerized(offset:time(200 msec)) at rti { - c = new Count(); - p = new Print(); - c.out -> p.in after offset; +federated reactor DistributedCountContainerized(offset: time(200 msec)) at rti { + c = new Count() + p = new Print() + + c.out -> p.in after offset } diff --git a/test/C/src/docker/federated/DistributedDoublePortContainerized.lf b/test/C/src/docker/federated/DistributedDoublePortContainerized.lf index e8e8a98d8d..8da9473981 100644 --- a/test/C/src/docker/federated/DistributedDoublePortContainerized.lf +++ b/test/C/src/docker/federated/DistributedDoublePortContainerized.lf @@ -1,9 +1,7 @@ /** - * Test the case for when two upstream federates - * send messages to a downstream federte on two - * different ports. One message should carry a - * microstep delay relative to the other - * message. + * Test the case for when two upstream federates send messages to a downstream + * federate on two different ports. One message should carry a microstep delay + * relative to the other message. * * @author Soroush Bateni */ @@ -12,16 +10,17 @@ target C { logging: DEBUG, coordination: centralized, docker: true -}; +} -import Count from "../../lib/Count.lf"; -import CountMicrostep from "../../federated/DistributedDoublePort.lf"; -import Print from "../../federated/DistributedDoublePort.lf"; +import Count from "../../lib/Count.lf" +import CountMicrostep from "../../federated/DistributedDoublePort.lf" +import Print from "../../federated/DistributedDoublePort.lf" federated reactor DistributedDoublePortContainerized at rti { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.out -> p.in; // Indicating a 'logical' connection. - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.out -> p.in // Indicating a 'logical' connection. + cm.out -> p.in2 } diff --git a/test/C/src/docker/federated/DistributedMultiportContainerized.lf b/test/C/src/docker/federated/DistributedMultiportContainerized.lf index d5cc44f860..b32585d66f 100644 --- a/test/C/src/docker/federated/DistributedMultiportContainerized.lf +++ b/test/C/src/docker/federated/DistributedMultiportContainerized.lf @@ -1,14 +1,11 @@ // Check multiport connections between federates. -target C { - timeout: 1 sec, - coordination: centralized, - docker: true -}; +target C { timeout: 1 sec, coordination: centralized, docker: true } -import Source, Destination from "../../federated/DistributedMultiport.lf"; +import Source, Destination from "../../federated/DistributedMultiport.lf" federated reactor DistributedMultiportContainerized at rti { - s = new Source(); - d = new Destination(); - s.out -> d.in; + s = new Source() + d = new Destination() + + s.out -> d.in } diff --git a/test/C/src/docker/federated/DistributedStopDecentralizedContainerized.lf b/test/C/src/docker/federated/DistributedStopDecentralizedContainerized.lf index e4f0ad0754..ba401dc506 100644 --- a/test/C/src/docker/federated/DistributedStopDecentralizedContainerized.lf +++ b/test/C/src/docker/federated/DistributedStopDecentralizedContainerized.lf @@ -1,17 +1,16 @@ /** - * Test for lf_request_stop() in federated execution with decentralized coordination. + * Test for lf_request_stop() in federated execution with decentralized + * coordination. * * @author Soroush Bateni */ -target C { - coordination: decentralized, - docker: true -}; +target C { coordination: decentralized, docker: true } import Sender, Receiver from "../../federated/DistributedStop.lf" federated reactor DistributedStopDecentralizedContainerized at rti { - sender = new Sender(); - receiver = new Receiver(); - sender.out -> receiver.in; + sender = new Sender() + receiver = new Receiver() + + sender.out -> receiver.in } From b0d13b46e9e1db0c62fe87d3239ec1fc5bc4f760 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 02:11:29 -0700 Subject: [PATCH 065/130] [formatting] Minor aesthetic change. --- org.lflang/src/org/lflang/ast/ToLf.java | 1 - 1 file changed, 1 deletion(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index ff01f830d0..b4cb93e637 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -277,7 +277,6 @@ public MalleableString caseModel(Model object) { object.getPreambles().forEach( p -> msb.append(casePreamble(p)).append(System.lineSeparator().repeat(2)) ); - if (!object.getPreambles().isEmpty()) msb.append(System.lineSeparator()); msb.append( object.getReactors().stream().map(this::doSwitch) .collect(new Joiner(System.lineSeparator().repeat(2))) From e8a67e66c809137fa2939bad4a322e26362d8841 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 11:17:17 -0700 Subject: [PATCH 066/130] Address IOException on Windows. --- .../src/org/lflang/tests/compiler/RoundTripTests.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 92ae9381df..3004057194 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -3,7 +3,10 @@ import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.nio.file.CopyOption; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; @@ -63,14 +66,13 @@ private Model getResultingModel( Path file, String reformattedTestCase ) throws IOException { - File swap = file.getParent().resolve(file.getFileName().toString() + ".swp").toFile(); - var ioException = new IOException("Failed to move the given test case to a swap file."); - if (!file.toFile().renameTo(swap)) throw ioException; + final Path swap = file.getParent().resolve(file.getFileName().toString() + ".swp"); + Files.move(file, swap, StandardCopyOption.REPLACE_EXISTING); try (PrintWriter out = new PrintWriter(file.toFile())) { out.println(reformattedTestCase); } Model resultingModel = parse(file); - if (!swap.renameTo(file.toFile())) throw ioException; + Files.move(swap, file, StandardCopyOption.REPLACE_EXISTING); return resultingModel; } From 85ee02e320bfd43ebbd5c167797664099dee49fe Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 13:19:47 -0700 Subject: [PATCH 067/130] [formatting] Fine-tune the "cost function" idea. --- .../src/org/lflang/ast/FormattingUtils.java | 35 ++++---- .../src/org/lflang/ast/MalleableString.java | 84 ++++++++----------- test/C/src/docker/HelloWorldContainerized.lf | 9 +- 3 files changed, 54 insertions(+), 74 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 3a7b8fcbac..38f9a2feed 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -2,9 +2,8 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.List; -import java.util.function.Function; +import java.util.function.ToLongFunction; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -34,6 +33,12 @@ public class FormattingUtils { public static final int DEFAULT_LINE_LENGTH = 80; + static final long BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH = 20; + + static final long BADNESS_PER_MISPLACED_COMMENT = 1000; + + static final long BADNESS_PER_NEWLINE = 1; + /** * Return a String representation of {@code object}, with lines wrapped at * {@code lineLength}. @@ -41,15 +46,16 @@ public class FormattingUtils { public static String render(EObject object, int lineLength) { // The following looks useless, but it wraps the representation in an // enclosing object that ensures that top-level comments are rendered. - MalleableString ms = new MalleableString.Builder() - .append(ToLf.instance.doSwitch(object)) - .get(); + MalleableString ms = ToLf.instance.doSwitch(object); ms.findBestRepresentation( ms::toString, - astRepresentationComparator(lineLength), + s -> countCharactersViolatingLineLength(lineLength).applyAsLong(s) + * BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH + + countNewlines(s) * BADNESS_PER_NEWLINE, lineLength ); - return ms.toString(); + return ms.getUnhandledComments().map(s -> lineWrapComment(s, lineLength)) + .collect(Collectors.joining(System.lineSeparator())) + ms; } /** @@ -58,16 +64,7 @@ public static String render(EObject object, int lineLength) { */ public static String render(EObject object) { return render(object, DEFAULT_LINE_LENGTH); } - /** - * Return a comparator that returns a negative number if the first argument - * is better than the second. - */ - private static Comparator astRepresentationComparator(int lineLength) { - return Comparator.comparing(countCharactersViolatingLineLength(lineLength)) - .thenComparing(FormattingUtils::countNewlines); - } - - private static Function countCharactersViolatingLineLength(int lineLength) { + private static ToLongFunction countCharactersViolatingLineLength(int lineLength) { return s -> s.lines().mapToInt(it -> Math.max(0, it.length() - lineLength)).sum(); } @@ -169,10 +166,6 @@ static void placeComment( return; } } - components.set( - 0, - String.format("%s%n%s", wrapped, components.isEmpty() ? "" : components.get(0)) - ); } static String normalizeEol(String s) { diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 4f3db22e09..c620bf9e7d 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -13,6 +12,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import java.util.function.ToLongFunction; import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -32,7 +32,7 @@ public MalleableString indent(int indentation) { public abstract void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter, + ToLongFunction badness, int width ); @@ -226,43 +226,21 @@ public Iterator iterator() { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter, + ToLongFunction badness, int width ) { this.width = width; keepCommentsOnSameLine = true; - var representationTrue = representationGetter.get(); + long badnessTrue = badness.applyAsLong(representationGetter.get()); keepCommentsOnSameLine = false; - var representationFalse = representationGetter.get(); - keepCommentsOnSameLine = whichRepresentationIsBetter.compare( - representationTrue, - representationFalse - ) <= 0; - if (getUnhandledComments().findAny().isPresent()) { - optimizeComponentsToContainAtLeastTwoLines(whichRepresentationIsBetter); - } else { - for (MalleableString component : components) { - component.findBestRepresentation( - representationGetter, - whichRepresentationIsBetter, - width - ); - } - } - } - - private void optimizeComponentsToContainAtLeastTwoLines(Comparator whichRepresentationIsBetter) { + long badnessFalse = badness.applyAsLong(representationGetter.get()); + keepCommentsOnSameLine = badnessTrue < badnessFalse; for (MalleableString component : components) { component.findBestRepresentation( - this::toString, - (a, b) -> { - var strippedA = a.strip(); - var strippedB = b.strip(); - // If a comment needs to be rendered, prefer that this sequence has at least two lines. - int lineNumDiff = (int) (strippedB.lines().limit(2).count() - strippedA.lines().limit(2).count()); - if (lineNumDiff != 0) return lineNumDiff; - return whichRepresentationIsBetter.compare(a, b); - }, + representationGetter, + s -> getUnhandledComments().count() + * FormattingUtils.BADNESS_PER_MISPLACED_COMMENT + + badness.applyAsLong(s), width ); } @@ -275,19 +253,25 @@ public boolean isEmpty() { @Override protected Stream getUnhandledComments() { - return Stream.concat( - super.getUnhandledComments(), - components.stream().map(MalleableString::toString) - .anyMatch(s -> s.contains("\r") || s.contains("\n")) ? Stream.of() - : components.stream().flatMap(MalleableString::getUnhandledComments) - ); + Stream unhandledComments = super.getUnhandledComments(); + for (MalleableString ms : components) { + unhandledComments = Stream.concat(unhandledComments, ms.getUnhandledComments()); + String s = ms.toString(); + if (s.contains("\r") || s.contains("\n")) break; + } + return unhandledComments; } } private static final class Indented extends MalleableString { + /** + * The indentation given by this indent alone (i.e., not including + * ancestor indents). + */ private final int indentation; private final MalleableString nested; + private int width; private Indented(MalleableString toIndent, int indentation) { this.indentation = indentation; @@ -302,12 +286,13 @@ public MalleableString indent(int indentation) { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter, + ToLongFunction badness, int width ) { + this.width = width; nested.findBestRepresentation( representationGetter, - whichRepresentationIsBetter, + badness, width - this.indentation ); } @@ -319,7 +304,7 @@ public boolean isEmpty() { @Override protected Stream getUnhandledComments() { - return Stream.concat(super.getUnhandledComments(), nested.getUnhandledComments()); + return Stream.of(); } @SuppressWarnings("NullableProblems") @@ -331,7 +316,12 @@ public Iterator iterator() { @Override public String toString() { String whitespace = " ".repeat(indentation); - return nested.toString().lines() + return Stream.concat( + nested.getUnhandledComments().map( + s -> FormattingUtils.lineWrapComment(s, width - indentation) + ).flatMap(String::lines), + nested.toString().lines() + ) .map(line -> line.isBlank() ? "" : whitespace + line) .collect(Collectors.joining(System.lineSeparator())); } @@ -355,20 +345,20 @@ public Iterator iterator() { @Override public void findBestRepresentation( Supplier representationGetter, - Comparator whichRepresentationIsBetter, + ToLongFunction badness, int width ) { bestPossibility = Collections.min(getPossibilities(), (a, b) -> { bestPossibility = a; - String resultA = representationGetter.get(); + long badnessA = badness.applyAsLong(representationGetter.get()); bestPossibility = b; - String resultB = representationGetter.get(); - return whichRepresentationIsBetter.compare(resultA, resultB); + long badnessB = badness.applyAsLong(representationGetter.get()); + return Math.toIntExact(badnessA - badnessB); }); if (bestPossibility instanceof MalleableString ms) { ms.findBestRepresentation( representationGetter, - whichRepresentationIsBetter, + badness, width ); } diff --git a/test/C/src/docker/HelloWorldContainerized.lf b/test/C/src/docker/HelloWorldContainerized.lf index 0e5e43a56c..5188ffc9d9 100644 --- a/test/C/src/docker/HelloWorldContainerized.lf +++ b/test/C/src/docker/HelloWorldContainerized.lf @@ -1,15 +1,12 @@ target C { - // To test generating a custom trace file name. - tracing: { - trace-file-name: "HelloWorldTrace" - }, + tracing: {trace-file-name: "HelloWorldTrace"}, // To test generating a custom trace file name. logging: error, docker: true, build-type: Debug -} +}; import HelloWorld2 from "../HelloWorld.lf" main reactor { - a = new HelloWorld2() + a = new HelloWorld2(); } From 8d45b7f74dacbd2deb3a5e05f1cc08c88c9a67fb Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sat, 2 Jul 2022 15:45:16 -0700 Subject: [PATCH 068/130] [formatting] More small adjustments. We should have paragraphs and also _subparagraphs_ that start with special symbols such as [\\-@+=] etc. Ganged connections need line breaking. The final element of an indented list should come with its terminating newline to reflect the structure of the representation. --- .../src/org/lflang/ast/FormattingUtils.java | 39 ++++++++++++------- .../src/org/lflang/ast/MalleableString.java | 28 ++++++------- org.lflang/src/org/lflang/ast/ToLf.java | 33 ++++++++++++---- 3 files changed, 63 insertions(+), 37 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 38f9a2feed..58a50bc1e7 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -55,7 +55,8 @@ public static String render(EObject object, int lineLength) { lineLength ); return ms.getUnhandledComments().map(s -> lineWrapComment(s, lineLength)) - .collect(Collectors.joining(System.lineSeparator())) + ms; + .collect(Collectors.joining(System.lineSeparator())) + + System.lineSeparator() + ms; } /** @@ -78,38 +79,46 @@ private static long countNewlines(String s) { */ static String lineWrapComment(String comment, int width) { width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); - List simpleWhitespace = Arrays.stream( + List> paragraphs = Arrays.stream( comment.strip() .replaceAll("^/?((\\*|//)\\s*)+", "") .replaceAll("\\s*\\*/$", "") .replaceAll("(?<=" + System.lineSeparator() + ")\\h*(\\*|//)\\h*", "") .split(String.format("(%n\\s*){2,}")) - ).map(s -> s.replaceAll("\\s+", " ")) + ).map(s -> Arrays.stream(s.split("((\r\n?)|\n)\\s*(?=[@#$%^&*\\-+=:;<>/])"))) + .map(stream -> stream.map(s -> s.replaceAll("\\s+", " "))) + .map(Stream::toList) .toList(); if (MULTILINE_COMMENT_LINES_STARTING_WITH_STARS.matcher(comment).matches()) { - if (comment.length() < width && simpleWhitespace.size() == 1) { - return String.format("/** %s */", simpleWhitespace.get(0)); + if ( + comment.length() < width && paragraphs.size() == 1 && paragraphs.get(0).size() == 1 + ) { + return String.format("/** %s */", paragraphs.get(0).get(0)); } - return String.format("/**%n%s%n */", lineWrapComment(simpleWhitespace, width, " * ")); + return String.format("/**%n%s%n */", lineWrapComment(paragraphs, width, " * ")); } - return lineWrapComment(simpleWhitespace, width, "// "); + return lineWrapComment(paragraphs, width, "// "); } static String lineWrapComment( - List simpleWhitespace, + List> paragraphs, int width, String linePrefix ) { - width = Math.max(width - linePrefix.length(), MINIMUM_COMMENT_WIDTH_IN_COLUMNS); - return wrapLines(simpleWhitespace, width) - .map(s -> (linePrefix + s.stripLeading()).stripTrailing()) - .collect(Collectors.joining(System.lineSeparator())); + int widthAfterPrefix = Math.max( + width - linePrefix.length(), + MINIMUM_COMMENT_WIDTH_IN_COLUMNS + ); + return paragraphs.stream() + .map(paragraph -> wrapLines(paragraph, widthAfterPrefix) + .map(s -> (linePrefix + s.stripLeading()).stripTrailing()) + .collect(Collectors.joining(System.lineSeparator())) + ).collect(Collectors.joining(String.format("%n%s%n", linePrefix.stripTrailing()))); } - static Stream wrapLines(List paragraphs, int width) { + static Stream wrapLines(List subparagraphs, int width) { var ret = new ArrayList(); - for (String s : paragraphs) { - if (!ret.isEmpty()) ret.add(""); + for (String s : subparagraphs) { int numCharactersProcessed = 0; while (numCharactersProcessed + width < s.length()) { // try to wrap at space diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index c620bf9e7d..89e5761c27 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -230,11 +230,6 @@ public void findBestRepresentation( int width ) { this.width = width; - keepCommentsOnSameLine = true; - long badnessTrue = badness.applyAsLong(representationGetter.get()); - keepCommentsOnSameLine = false; - long badnessFalse = badness.applyAsLong(representationGetter.get()); - keepCommentsOnSameLine = badnessTrue < badnessFalse; for (MalleableString component : components) { component.findBestRepresentation( representationGetter, @@ -244,6 +239,11 @@ public void findBestRepresentation( width ); } + keepCommentsOnSameLine = true; + long badnessTrue = badness.applyAsLong(representationGetter.get()); + keepCommentsOnSameLine = false; + long badnessFalse = badness.applyAsLong(representationGetter.get()); + keepCommentsOnSameLine = badnessTrue < badnessFalse; } @Override @@ -315,15 +315,15 @@ public Iterator iterator() { @Override public String toString() { - String whitespace = " ".repeat(indentation); - return Stream.concat( - nested.getUnhandledComments().map( - s -> FormattingUtils.lineWrapComment(s, width - indentation) - ).flatMap(String::lines), - nested.toString().lines() - ) - .map(line -> line.isBlank() ? "" : whitespace + line) - .collect(Collectors.joining(System.lineSeparator())); + return ( + nested.getUnhandledComments().map( + s -> FormattingUtils.lineWrapComment(s, width - indentation) + ).collect(Collectors.joining(System.lineSeparator())) + + nested + ).replaceAll( + "(?<=" + System.lineSeparator() + "|^)(?=\\s*\\S)", + " ".repeat(indentation) + ); } } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index b4cb93e637..2aec3788d8 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -648,17 +648,22 @@ public MalleableString caseConnection(Connection object) { // (serializer=Serializer)? // ';'? Builder msb = new Builder(); - // TODO: break lines here - if (object.isIterated()) msb.append("("); - msb.append(object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); - if (object.isIterated()) msb.append(")+"); + if (object.isIterated()) { + msb.append(list(false, object.getLeftPorts())).append("+"); + } else { + msb.append( + object.getLeftPorts().stream().map(this::doSwitch).collect(new Joiner(", ")), + object.getLeftPorts().stream().map(this::doSwitch).collect( + new Joiner(String.format(",%n")) + ) + ); + } msb.append( "", MalleableString.anyOf(System.lineSeparator()).indent(FormattingUtils.INDENTATION) ); msb.append(object.isPhysical() ? " ~> " : " -> "); - // TODO: break lines here - msb.append(object.getRightPorts().stream().map(this::doSwitch).collect(new Joiner(", "))); + msb.append(minimallyDelimitedList(object.getRightPorts())); if (object.getDelay() != null) msb.append(" after ").append(doSwitch(object.getDelay())); if (object.getSerializer() != null) { msb.append(" ").append(doSwitch(object.getSerializer())); @@ -666,6 +671,18 @@ public MalleableString caseConnection(Connection object) { return msb.get(); } + private MalleableString minimallyDelimitedList(List items) { + return MalleableString.anyOf( + list(", ", "", "", true, true, items), + new Builder() + .append(System.lineSeparator()) + .append( + list(String.format(",%n"), "", "", true, true, items) + .indent(FormattingUtils.INDENTATION) + ).append(String.format("%n;")).get() + ); + } + @Override public MalleableString caseSerializer(Serializer object) { // 'serializer' type=STRING @@ -894,12 +911,12 @@ private MalleableString list( .append(list( separator.strip() + System.lineSeparator(), "", - "", + System.lineSeparator(), nothingIfEmpty, true, items ).indent(FormattingUtils.INDENTATION)) - .append(System.lineSeparator() + suffix.stripLeading()) + .append(suffix.stripLeading()) .get() ); } From 31f14a9ff0d1047247d2085ce2fc4b287624d5c2 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 3 Jul 2022 23:14:52 -0700 Subject: [PATCH 069/130] [formatting] Make badness minimizer work properly. The time and conceptual effort required for this particular commit reflect poorly on the implementation. This was partly because complex logic was implemented in the toString function, which makes debugging exceedingly difficult when setting breakpoints (since the debugger itself invokes toString). However, the complexity also comes from the statefulness of the renderable components (a possible design mistake), as well as from the (possibly inherent) difficulty of keeping track of comments as them bubble up to ever higher syntactic levels in search of a home. --- .../src/org/lflang/ast/FormattingUtils.java | 25 +-- .../src/org/lflang/ast/MalleableString.java | 184 ++++++++---------- 2 files changed, 100 insertions(+), 109 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 58a50bc1e7..a95c4dde6e 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -35,7 +35,7 @@ public class FormattingUtils { static final long BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH = 20; - static final long BADNESS_PER_MISPLACED_COMMENT = 1000; + static final long BADNESS_PER_LEVEL_OF_COMMENT_DISPLACEMENT = 1000; static final long BADNESS_PER_NEWLINE = 1; @@ -48,15 +48,17 @@ public static String render(EObject object, int lineLength) { // enclosing object that ensures that top-level comments are rendered. MalleableString ms = ToLf.instance.doSwitch(object); ms.findBestRepresentation( - ms::toString, - s -> countCharactersViolatingLineLength(lineLength).applyAsLong(s) - * BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH - + countNewlines(s) * BADNESS_PER_NEWLINE, + ms::render, + r -> r.levelsOfCommentDisplacement() * BADNESS_PER_LEVEL_OF_COMMENT_DISPLACEMENT + + countCharactersViolatingLineLength(lineLength).applyAsLong(r.rendering()) + * BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH + + countNewlines(r.rendering()) * BADNESS_PER_NEWLINE, lineLength ); - return ms.getUnhandledComments().map(s -> lineWrapComment(s, lineLength)) + var optimizedRendering = ms.render(); + return optimizedRendering.unplacedComments().map(s -> lineWrapComment(s, lineLength)) .collect(Collectors.joining(System.lineSeparator())) - + System.lineSeparator() + ms; + + System.lineSeparator() + optimizedRendering.rendering(); } /** @@ -149,7 +151,7 @@ static Stream wrapLines(List subparagraphs, int width) { * @param keepCommentsOnSameLine Whether to make a best-effort attempt to * keep the comment on the same line as the associated string. */ - static void placeComment( + static boolean placeComment( String comment, List components, int i, @@ -157,7 +159,7 @@ static void placeComment( boolean keepCommentsOnSameLine ) { String wrapped = FormattingUtils.lineWrapComment(comment, width); - if (comment.isBlank()) return; + if (comment.isBlank()) return true; if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { for (int j = i; j < components.size(); j++) { if (components.get(j).contains(System.lineSeparator())) { @@ -165,16 +167,17 @@ static void placeComment( System.lineSeparator(), String.format(" %s%n", wrapped) )); - return; + return true; } } } for (int j = i - 1; j >= 0; j--) { if (components.get(j).endsWith(System.lineSeparator())) { components.set(j, String.format("%s%s%n", components.get(j), wrapped)); - return; + return true; } } + return false; } static String normalizeEol(String s) { diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 89e5761c27..42c19941fc 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.function.BiConsumer; @@ -19,7 +18,7 @@ import com.google.common.collect.ImmutableList; -public abstract class MalleableString implements Iterable { +public abstract class MalleableString { protected List comments = new ArrayList<>(); @@ -31,8 +30,8 @@ public MalleableString indent(int indentation) { } public abstract void findBestRepresentation( - Supplier representationGetter, - ToLongFunction badness, + Supplier providedRender, + ToLongFunction badness, int width ); @@ -47,9 +46,7 @@ public MalleableString addComments(Stream comments) { return this; } - protected Stream getUnhandledComments() { - return comments.stream(); - } + public abstract RenderResult render(); public static MalleableString anyOf(MalleableString... possibilities) { return new Fork(possibilities); @@ -115,7 +112,6 @@ private Builder insert( } return this; } - } public static final class Joiner implements Collector< @@ -180,7 +176,22 @@ public Set characteristics() { } } + public record RenderResult( + Stream unplacedComments, + String rendering, + int levelsOfCommentDisplacement + ) { + private RenderResult with(Stream moreUnplacedComments) { + return new RenderResult( + Stream.concat(moreUnplacedComments, unplacedComments), + rendering, + levelsOfCommentDisplacement + ); + } + } + private static final class Sequence extends MalleableString { + private final ImmutableList components; private Sequence(ImmutableList components) { this.components = components; @@ -190,59 +201,54 @@ private Sequence(ImmutableList components) { private int width = 0; @Override - public String toString() { - List> unhandledComments = components.stream() - .map(MalleableString::getUnhandledComments) - .map(stream -> stream.map(FormattingUtils::normalizeEol)) - .map(Stream::toList) - .toList(); - List stringComponents = components.stream() - .map(MalleableString::toString) + public RenderResult render() { + List componentRenderings = components.stream() + .map(MalleableString::render).toList(); + List> commentsFromChildren = componentRenderings.stream() + .map(it -> it.unplacedComments).map(Stream::toList).toList(); + List stringComponents = componentRenderings.stream() + .map(it -> it.rendering) .map(FormattingUtils::normalizeEol) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); + List commentsThatCouldNotBeHandledHere = new ArrayList<>(); if ( - unhandledComments.stream().anyMatch(s -> !s.isEmpty()) - && stringComponents.stream().anyMatch(s -> s.contains("\r") || s.contains("\n")) + commentsFromChildren.stream().anyMatch(s -> !s.isEmpty()) ) { - for (int i = 0; i < unhandledComments.size(); i++) { - FormattingUtils.placeComment( - String.join(System.lineSeparator(), unhandledComments.get(i)), + for (int i = 0; i < commentsFromChildren.size(); i++) { + if (!FormattingUtils.placeComment( + String.join(System.lineSeparator(), commentsFromChildren.get(i)), stringComponents, i, width, keepCommentsOnSameLine - ); + )) { + commentsThatCouldNotBeHandledHere.addAll(commentsFromChildren.get(i)); + } } } - return String.join("", stringComponents); - } - - @SuppressWarnings("NullableProblems") - @Override - public Iterator iterator() { - return components.iterator(); + return new RenderResult( + Stream.concat(this.comments.stream(), commentsThatCouldNotBeHandledHere.stream()), + String.join("", stringComponents), + componentRenderings.stream() + .mapToInt(RenderResult::levelsOfCommentDisplacement).sum() + + commentsThatCouldNotBeHandledHere.size() + ); } @Override public void findBestRepresentation( - Supplier representationGetter, - ToLongFunction badness, + Supplier providedRender, + ToLongFunction badness, int width ) { this.width = width; - for (MalleableString component : components) { - component.findBestRepresentation( - representationGetter, - s -> getUnhandledComments().count() - * FormattingUtils.BADNESS_PER_MISPLACED_COMMENT - + badness.applyAsLong(s), - width - ); - } keepCommentsOnSameLine = true; - long badnessTrue = badness.applyAsLong(representationGetter.get()); + components.forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + if (components.stream().noneMatch(it -> it.render().unplacedComments.findAny().isPresent())) return; + long badnessTrue = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = false; - long badnessFalse = badness.applyAsLong(representationGetter.get()); + components.forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + long badnessFalse = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = badnessTrue < badnessFalse; } @@ -250,17 +256,6 @@ public void findBestRepresentation( public boolean isEmpty() { return components.stream().allMatch(MalleableString::isEmpty); } - - @Override - protected Stream getUnhandledComments() { - Stream unhandledComments = super.getUnhandledComments(); - for (MalleableString ms : components) { - unhandledComments = Stream.concat(unhandledComments, ms.getUnhandledComments()); - String s = ms.toString(); - if (s.contains("\r") || s.contains("\n")) break; - } - return unhandledComments; - } } private static final class Indented extends MalleableString { @@ -285,13 +280,13 @@ public MalleableString indent(int indentation) { @Override public void findBestRepresentation( - Supplier representationGetter, - ToLongFunction badness, + Supplier providedRender, + ToLongFunction badness, int width ) { this.width = width; nested.findBestRepresentation( - representationGetter, + providedRender, badness, width - this.indentation ); @@ -303,68 +298,58 @@ public boolean isEmpty() { } @Override - protected Stream getUnhandledComments() { - return Stream.of(); - } - - @SuppressWarnings("NullableProblems") - @Override - public Iterator iterator() { - return Collections.singleton((MalleableString) this).iterator(); - } - - @Override - public String toString() { - return ( - nested.getUnhandledComments().map( - s -> FormattingUtils.lineWrapComment(s, width - indentation) - ).collect(Collectors.joining(System.lineSeparator())) - + nested - ).replaceAll( - "(?<=" + System.lineSeparator() + "|^)(?=\\s*\\S)", - " ".repeat(indentation) + public RenderResult render() { + var result = nested.render(); + String renderedComments = result.unplacedComments.map( + s -> FormattingUtils.lineWrapComment(s, width - indentation) + ).collect(Collectors.joining(System.lineSeparator())); + return new RenderResult( + this.comments.stream(), + ( + renderedComments.isBlank() ? result.rendering + : renderedComments + System.lineSeparator() + result.rendering + ).replaceAll( + "(?<=" + System.lineSeparator() + "|^)(?=\\s*\\S)", + " ".repeat(indentation) + ), + result.levelsOfCommentDisplacement() ); } } - private abstract static class MalleableStringImpl extends MalleableString { - protected abstract List getPossibilities(); + private abstract static class MalleableStringImpl extends MalleableString { + protected abstract List getPossibilities(); - private Object bestPossibility; + private T bestPossibility; @Override public String toString() { return getChosenPossibility().toString(); } - @Override - public Iterator iterator() { - return Collections.singleton((MalleableString) this).iterator(); - } - @Override public void findBestRepresentation( - Supplier representationGetter, - ToLongFunction badness, + Supplier providedRender, + ToLongFunction badness, int width ) { bestPossibility = Collections.min(getPossibilities(), (a, b) -> { bestPossibility = a; - long badnessA = badness.applyAsLong(representationGetter.get()); + long badnessA = badness.applyAsLong(providedRender.get()); bestPossibility = b; - long badnessB = badness.applyAsLong(representationGetter.get()); + long badnessB = badness.applyAsLong(providedRender.get()); return Math.toIntExact(badnessA - badnessB); }); if (bestPossibility instanceof MalleableString ms) { ms.findBestRepresentation( - representationGetter, + providedRender, badness, width ); } } - protected Object getChosenPossibility() { + protected T getChosenPossibility() { if (getPossibilities().isEmpty()) { throw new IllegalStateException( "A MalleableString must be directly or transitively backed " @@ -375,14 +360,14 @@ protected Object getChosenPossibility() { } } - private static final class Fork extends MalleableStringImpl { + private static final class Fork extends MalleableStringImpl { private final ImmutableList possibilities; private Fork(MalleableString[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); } @Override - protected List getPossibilities() { return this.possibilities; } + protected List getPossibilities() { return this.possibilities; } @Override public boolean isEmpty() { @@ -390,14 +375,12 @@ public boolean isEmpty() { } @Override - protected Stream getUnhandledComments() { - Stream nestedUnhandled = getChosenPossibility() instanceof MalleableString ms ? - ms.getUnhandledComments() : Stream.of(); - return Stream.concat(super.getUnhandledComments(), nestedUnhandled); + public RenderResult render() { + return getChosenPossibility().render().with(comments.stream()); } } - private static final class Leaf extends MalleableStringImpl { + private static final class Leaf extends MalleableStringImpl { private final ImmutableList possibilities; private Leaf(String[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); @@ -407,11 +390,16 @@ private Leaf(String possibility) { } @Override - protected List getPossibilities() { return this.possibilities; } + protected List getPossibilities() { return this.possibilities; } @Override public boolean isEmpty() { return possibilities.stream().allMatch(String::isEmpty); } + + @Override + public RenderResult render() { + return new RenderResult(comments.stream(), getChosenPossibility(), 0); + } } } From 6c269cff19ee351c8f47bf63a1ad1f59b172c95a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Sun, 3 Jul 2022 23:27:44 -0700 Subject: [PATCH 070/130] [formatter] Format C federated tests. --- test/C/src/federated/BroadcastFeedback.lf | 23 ++--- .../BroadcastFeedbackWithHierarchy.lf | 33 +++++--- test/C/src/federated/ChainWithDelay.lf | 22 ++--- test/C/src/federated/ClockSync.lf | 66 +++++++-------- test/C/src/federated/CycleDetection.lf | 41 ++++----- test/C/src/federated/DecentralizedP2PComm.lf | 34 +++++--- .../DecentralizedP2PUnbalancedTimeout.lf | 42 ++++++---- ...centralizedP2PUnbalancedTimeoutPhysical.lf | 46 +++++----- test/C/src/federated/DistributedBank.lf | 14 ++-- .../federated/DistributedBankToMultiport.lf | 20 +++-- test/C/src/federated/DistributedCount.lf | 36 ++++---- .../DistributedCountDecentralized.lf | 35 ++++---- .../DistributedCountDecentralizedLate.lf | 44 +++++----- ...ributedCountDecentralizedLateDownstream.lf | 83 +++++++++++-------- ...tributedCountDecentralizedLateHierarchy.lf | 70 +++++++++------- .../src/federated/DistributedCountPhysical.lf | 40 +++++---- .../DistributedCountPhysicalAfterDelay.lf | 29 ++++--- .../DistributedCountPhysicalDecentralized.lf | 40 +++++---- test/C/src/federated/DistributedDoublePort.lf | 44 +++++----- .../DistributedLogicalActionUpstreamLong.lf | 53 +++++++----- .../src/federated/DistributedLoopedAction.lf | 36 ++++---- .../DistributedLoopedActionDecentralized.lf | 75 ++++++++--------- .../DistributedLoopedPhysicalAction.lf | 57 +++++++------ ...ibutedLoopedPhysicalActionDecentralized.lf | 16 ++-- test/C/src/federated/DistributedMultiport.lf | 28 ++++--- .../federated/DistributedMultiportToBank.lf | 27 +++--- .../federated/DistributedMultiportToken.lf | 24 +++--- .../src/federated/DistributedNetworkOrder.lf | 36 ++++---- .../DistributedPhysicalActionUpstream.lf | 36 ++++---- .../DistributedPhysicalActionUpstreamLong.lf | 63 ++++++++------ 30 files changed, 670 insertions(+), 543 deletions(-) diff --git a/test/C/src/federated/BroadcastFeedback.lf b/test/C/src/federated/BroadcastFeedback.lf index f7817bf178..be5b47a3c9 100644 --- a/test/C/src/federated/BroadcastFeedback.lf +++ b/test/C/src/federated/BroadcastFeedback.lf @@ -1,32 +1,35 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target C { - timeout: 1 sec, - build-type: RelWithDebInfo, - logging: DEBUG -}; +target C { timeout: 1 sec, build-type: RelWithDebInfo, logging: DEBUG } + reactor SenderAndReceiver { - output out:int; - input[2] in:int; - state received:bool(false); + input[2] in: int + + output out: int + + state received: bool(false) reaction(startup) -> out {= lf_set(out, 42); =} + reaction(in) {= if (in[0]->is_present && in[1]->is_present && in[0]->value == 42 && in[1]->value == 42) { lf_print("SUCCESS"); self->received = true; } =} + reaction(shutdown) {= if (!self->received == true) { lf_print_error_and_exit("Failed to receive broadcast"); } =} } + federated reactor { - s = new[2] SenderAndReceiver(); - (s.out)+ -> s.in; + s = new[2] SenderAndReceiver() + + (s.out)+ -> s.in } diff --git a/test/C/src/federated/BroadcastFeedbackWithHierarchy.lf b/test/C/src/federated/BroadcastFeedbackWithHierarchy.lf index 66757dc5c8..b1a6e266b9 100644 --- a/test/C/src/federated/BroadcastFeedbackWithHierarchy.lf +++ b/test/C/src/federated/BroadcastFeedbackWithHierarchy.lf @@ -1,24 +1,28 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target C { - timeout: 1 sec -}; +target C { timeout: 1 sec } + reactor SenderAndReceiver { - output out:int; - input[2] in:int; - state received:bool(false); + input[2] in: int + + output out: int + + r = new Receiver() + + in -> r.in + + state received: bool(false) reaction(startup) -> out {= lf_set(out, 42); =} - - r = new Receiver(); - in -> r.in; } + reactor Receiver { - input[2] in:int; - state received:bool(false); + input[2] in: int + + state received: bool(false) reaction(in) {= if (in[0]->is_present && in[1]->is_present && in[0]->value == 42 && in[1]->value == 42) { @@ -26,13 +30,16 @@ reactor Receiver { self->received = true; } =} + reaction(shutdown) {= if (!self->received == true) { lf_print_error_and_exit("Failed to receive broadcast"); } =} } + federated reactor { - s = new[2] SenderAndReceiver(); - (s.out)+ -> s.in; + s = new[2] SenderAndReceiver() + + (s.out)+ -> s.in } diff --git a/test/C/src/federated/ChainWithDelay.lf b/test/C/src/federated/ChainWithDelay.lf index 203dbde968..84bcada7ad 100644 --- a/test/C/src/federated/ChainWithDelay.lf +++ b/test/C/src/federated/ChainWithDelay.lf @@ -3,17 +3,17 @@ * * @author Edward A. Lee */ -target C { - timeout: 3 msec -} -import Count from "../lib/Count.lf"; -import InternalDelay from "../lib/InternalDelay.lf"; -import TestCount from "../lib/TestCount.lf"; +target C { timeout: 3 msec } + +import Count from "../lib/Count.lf" +import InternalDelay from "../lib/InternalDelay.lf" +import TestCount from "../lib/TestCount.lf" federated reactor { - c = new Count(period = 1 msec); - i = new InternalDelay(delay = 500 usec); - t = new TestCount(num_inputs = 3); - c.out -> i.in; - i.out -> t.in; + c = new Count(period = 1 msec) + i = new InternalDelay(delay = 500 usec) + t = new TestCount(num_inputs = 3) + + c.out -> i.in + i.out -> t.in } diff --git a/test/C/src/federated/ClockSync.lf b/test/C/src/federated/ClockSync.lf index b154572726..963e4e1b7f 100644 --- a/test/C/src/federated/ClockSync.lf +++ b/test/C/src/federated/ClockSync.lf @@ -1,48 +1,47 @@ /** - * This program tests clock synchronization. - * It checks the clock synchronization error and fails - * if it exceeds a threshold. Note that failures could - * occur here intermittently because clock synchronization - * accuracy depends on many conditions. But the threshold - * is quite high, so failures should be rare. + * This program tests clock synchronization. It checks the clock synchronization + * error and fails if it exceeds a threshold. Note that failures could occur + * here intermittently because clock synchronization accuracy depends on many + * conditions. But the threshold is quite high, so failures should be rare. * @author Edward A. Lee */ target C { coordination: decentralized, timeout: 10 sec, - clock-sync: on, // Turn on runtime clock synchronization. + clock-sync: on, // Turn on runtime clock synchronization. clock-sync-options: { - local-federates-on: true, // Forces all federates to perform clock sync. - collect-stats: true, // Collect useful statistics like average network delay - // and the standard deviation for the network delay over - // one clock synchronization cycle. Generates a warning - // if the standard deviation is higher than the clock sync - // guard. - test-offset: 200 msec, // Artificially offsets clocks by multiples of 200 msec. - period: 5 msec, // Period with which runtime clock sync is performed. - trials: 10, // Number of messages exchanged to perform clock sync. - attenuation: 10 // Attenuation applied to runtime clock sync adjustments. + // Forces all federates to perform clock sync. + local-federates-on: true, + // Collect useful statistics like average network delay + collect-stats: true, + // and the standard deviation for the network delay over one clock + // synchronization cycle. Generates a warning if the standard deviation + // is higher than the clock sync guard. Artificially offsets clocks by + // multiples of 200 msec. + test-offset: 200 msec, + // Period with which runtime clock sync is performed. + period: 5 msec, + // Number of messages exchanged to perform clock sync. + trials: 10, + // Attenuation applied to runtime clock sync adjustments. + attenuation: 10 } -}; +} -/** - * Reactor that outputs periodically. - */ -reactor Ticker(period:time(1600 msec)) { - output out:int; +/** Reactor that outputs periodically. */ +reactor Ticker(period: time(1600 msec)) { + output out: int - timer tick(0, period); + timer tick(0, period) reaction(tick) -> out {= lf_set(out, 42); =} } -/** - * Print a message when an input arrives. - */ +/** Print a message when an input arrives. */ reactor Printer { - input in:int; + input in: int reaction(startup) {= interval_t offset = _lf_time_physical_clock_offset + _lf_time_test_physical_clock_offset; @@ -65,12 +64,13 @@ reactor Printer { } reactor Federate { - source = new Ticker(); - play = new Printer(); - source.out -> play.in; + source = new Ticker() + play = new Printer() + + source.out -> play.in } federated reactor ClockSync { - fed1 = new Federate(); - fed2 = new Federate(); + fed1 = new Federate() + fed2 = new Federate() } diff --git a/test/C/src/federated/CycleDetection.lf b/test/C/src/federated/CycleDetection.lf index ac55476ad2..73ae963537 100644 --- a/test/C/src/federated/CycleDetection.lf +++ b/test/C/src/federated/CycleDetection.lf @@ -3,16 +3,16 @@ * introduce a cycle or not. The failure for this test is not being compiled. * @author Edward A. Lee */ -target C; +target C reactor CAReplica { - input local_update:int; - input remote_update:int; - input query:int; + input local_update: int + input remote_update: int + input query: int - state balance:int(0); + output response: int - output response:int; + state balance: int(0) reaction(local_update, remote_update) {= if (local_update->is_present) { @@ -27,13 +27,16 @@ reactor CAReplica { lf_set(response, self->balance); =} } + reactor UserInput { - input balance:int; - output deposit:int; + input balance: int + + output deposit: int reaction(startup) -> deposit {= lf_set(deposit, 100); =} + reaction(balance) {= if (balance->value != 200) { lf_print_error_and_exit("Did not receive the expected balance. Expected: 200. Got: %d.", balance->value); @@ -48,15 +51,15 @@ reactor UserInput { } federated reactor { - u1 = new UserInput(); - r1 = new CAReplica(); - u2 = new UserInput(); - r2 = new CAReplica(); - (u1.deposit)+ -> r1.query, r1.local_update; - r1.response -> u1.balance; - u1.deposit -> r2.remote_update; - - (u2.deposit)+ -> r2.query, r2.local_update; - r2.response -> u2.balance; - u2.deposit -> r1.remote_update; + u1 = new UserInput() + r1 = new CAReplica() + u2 = new UserInput() + r2 = new CAReplica() + + (u1.deposit)+ -> r1.query, r1.local_update + r1.response -> u1.balance + u1.deposit -> r2.remote_update + (u2.deposit)+ -> r2.query, r2.local_update + r2.response -> u2.balance + u2.deposit -> r1.remote_update } diff --git a/test/C/src/federated/DecentralizedP2PComm.lf b/test/C/src/federated/DecentralizedP2PComm.lf index 99301ffda9..32a343989c 100644 --- a/test/C/src/federated/DecentralizedP2PComm.lf +++ b/test/C/src/federated/DecentralizedP2PComm.lf @@ -5,15 +5,24 @@ target C { coordination: decentralized } -reactor Platform(start:int(0), expected_start:int(0), stp_offset_param:time(0)) { - input in:int; - output out:int; - timer t(0, 100 msec); - state count:int(start); - state expected:int(expected_start); +reactor Platform( + start: int(0), + expected_start: int(0), + stp_offset_param: time(0) +) { + input in: int + + output out: int + + timer t(0, 100 msec) + + state count: int(start) + state expected: int(expected_start) + reaction(t) -> out {= lf_set(out, self->count++); =} + reaction(in) {= lf_print("Received %d.", in->value); if (in->value != self->expected_start++) { @@ -22,7 +31,7 @@ reactor Platform(start:int(0), expected_start:int(0), stp_offset_param:time(0)) in->value ); } - =} STP (stp_offset_param) {= + =} STP(stp_offset_param){= lf_print("Received %d late.", in->value); tag_t current_tag = lf_tag(); self->expected_start++; @@ -31,6 +40,7 @@ reactor Platform(start:int(0), expected_start:int(0), stp_offset_param:time(0)) current_tag.microstep - in->intended_tag.microstep ); =} + reaction(shutdown) {= lf_print("Shutdown invoked."); if (self->expected == self->expected_start) { @@ -38,9 +48,11 @@ reactor Platform(start:int(0), expected_start:int(0), stp_offset_param:time(0)) } =} } + federated reactor DecentralizedP2PComm { - a = new Platform(expected_start = 100, stp_offset_param = 10 msec); - b = new Platform(start = 100, stp_offset_param = 10 msec); - a.out -> b.in; - b.out -> a.in; + a = new Platform(expected_start = 100, stp_offset_param = 10 msec) + b = new Platform(start = 100, stp_offset_param = 10 msec) + + a.out -> b.in + b.out -> a.in } diff --git a/test/C/src/federated/DecentralizedP2PUnbalancedTimeout.lf b/test/C/src/federated/DecentralizedP2PUnbalancedTimeout.lf index 723962f648..e894c8f069 100644 --- a/test/C/src/federated/DecentralizedP2PUnbalancedTimeout.lf +++ b/test/C/src/federated/DecentralizedP2PUnbalancedTimeout.lf @@ -1,31 +1,36 @@ /** - * Test a source-destination scenario where the source falls behind real-time, and reaches the - * timeout much later than the destination. In this test, the destination closes the connection - * early, causing the transmission to fail. Warnings will be printed about lost messages. + * Test a source-destination scenario where the source falls behind real-time, + * and reaches the timeout much later than the destination. In this test, the + * destination closes the connection early, causing the transmission to fail. + * Warnings will be printed about lost messages. * * The test fails if the federation does not exit. */ -target C { - timeout: 1 msec, - coordination: decentralized -} +target C { timeout: 1 msec, coordination: decentralized } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); reaction(t) -> y {= (self->count)++; lf_print("Sending %d.", self->count); lf_set(y, self->count); =} + reaction(shutdown) {= lf_print("SUCCESS: the source exited successfully."); =} } + reactor Destination { - input x:int; - state s:int(1); + input x: int + + state s: int(1) + reaction(x) {= lf_print("Received %d", x->value); tag_t current_tag = lf_tag(); @@ -36,13 +41,16 @@ reactor Destination { } self->s++; =} + reaction(shutdown) {= lf_print("**** shutdown reaction invoked."); lf_print("Approx. time per reaction: %lldns", lf_time_physical_elapsed()/(self->s+1)); =} } -federated reactor (period:time(10 usec)) { - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; + +federated reactor(period: time(10 usec)) { + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x } diff --git a/test/C/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf b/test/C/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf index 3c8da87246..4157d65ec9 100644 --- a/test/C/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf +++ b/test/C/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf @@ -1,32 +1,37 @@ /** - * Test a source-destination scenario where the source falls behind real-time, and reaches the - * timeout much later than the destination. In this test, the destination closes the connection - * early, causing the transmission to fail. Warnings will be printed. + * Test a source-destination scenario where the source falls behind real-time, + * and reaches the timeout much later than the destination. In this test, the + * destination closes the connection early, causing the transmission to fail. + * Warnings will be printed. * - * The test fails if the federation does not exit amenably. - * This variant has a physical connection between source and destination. + * The test fails if the federation does not exit amenably. This variant has a + * physical connection between source and destination. */ -target C { - timeout: 1 msec, - coordination: decentralized -} +target C { timeout: 1 msec, coordination: decentralized } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); reaction(t) -> y {= (self->count)++; //printf("Reacting at time %ld.\n", lf_time_logical_elapsed()); lf_set(y, self->count); =} + reaction(shutdown) {= lf_print("SUCCESS: the source exited successfully."); =} } + reactor Destination { - input x:int; - state s:int(1); + input x: int + + state s: int(1) + reaction(x) {= // printf("%d\n", x->value); if (x->value != self->s) { @@ -34,13 +39,16 @@ reactor Destination { } self->s++; =} + reaction(shutdown) {= lf_print("**** shutdown reaction invoked."); lf_print("Approx. time per reaction: %lldns", lf_time_physical_elapsed()/(self->s+1)); =} } -federated reactor (period:time(10 usec)) { - c = new Clock(period = period); - d = new Destination(); - c.y ~> d.x; + +federated reactor(period: time(10 usec)) { + c = new Clock(period = period) + d = new Destination() + + c.y ~> d.x } diff --git a/test/C/src/federated/DistributedBank.lf b/test/C/src/federated/DistributedBank.lf index e6ddeb4a30..0002d8a6bd 100644 --- a/test/C/src/federated/DistributedBank.lf +++ b/test/C/src/federated/DistributedBank.lf @@ -1,15 +1,15 @@ // Check bank of federates. -target C { - timeout: 1 sec, - coordination: centralized -}; +target C { timeout: 1 sec, coordination: centralized } reactor Node { - timer t(0, 100 msec); - state count:int(0); + timer t(0, 100 msec) + + state count: int(0) + reaction(t) {= lf_print("Hello world %d.", self->count++); =} + reaction(shutdown) {= if (self->count == 0) { lf_print_error_and_exit("Timer reactions did not execute."); @@ -18,5 +18,5 @@ reactor Node { } federated reactor DistributedBank { - n = new[2] Node(); + n = new[2] Node() } diff --git a/test/C/src/federated/DistributedBankToMultiport.lf b/test/C/src/federated/DistributedBankToMultiport.lf index 83cd2954bb..bdfe9572ae 100644 --- a/test/C/src/federated/DistributedBankToMultiport.lf +++ b/test/C/src/federated/DistributedBankToMultiport.lf @@ -1,13 +1,13 @@ // Check multiport to bank connections between federates. -target C { - timeout: 3 sec -}; +target C { timeout: 3 sec } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Destination { - input[2] in:int; - state count:int(1); + input[2] in: int + + state count: int(1) + reaction(in) {= for (int i = 0; i < in_width; i++) { lf_print("Received %d.", in[i]->value); @@ -17,6 +17,7 @@ reactor Destination { } self->count++; =} + reaction(shutdown) {= if (self->count == 0) { lf_print_error_and_exit("No data received."); @@ -25,7 +26,8 @@ reactor Destination { } federated reactor { - s = new[2] Count(); - d = new Destination(); - s.out -> d.in; + s = new[2] Count() + d = new Destination() + + s.out -> d.in } diff --git a/test/C/src/federated/DistributedCount.lf b/test/C/src/federated/DistributedCount.lf index 1a19ba1645..d0eaadf819 100644 --- a/test/C/src/federated/DistributedCount.lf +++ b/test/C/src/federated/DistributedCount.lf @@ -1,20 +1,20 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * + * @author Edward A. Lee */ -target C { - timeout: 5 sec, - logging: DEBUG, - coordination: centralized -}; +target C { timeout: 5 sec, logging: DEBUG, coordination: centralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - input in:int; - state c:int(1); + input in: int + + state c: int(1) + reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); lf_print("At time %lld, received %d", elapsed_time, in->value); @@ -26,6 +26,7 @@ reactor Print { } self->c++; =} + reaction(shutdown) {= if (self->c != 6) { lf_print_error_and_exit("Expected to receive 5 items."); @@ -33,8 +34,9 @@ reactor Print { =} } -federated reactor DistributedCount(offset:time(200 msec)) { - c = new Count(); - p = new Print(); - c.out -> p.in after offset; +federated reactor DistributedCount(offset: time(200 msec)) { + c = new Count() + p = new Print() + + c.out -> p.in after offset } diff --git a/test/C/src/federated/DistributedCountDecentralized.lf b/test/C/src/federated/DistributedCountDecentralized.lf index 1b8a71f421..26e5d8d57d 100644 --- a/test/C/src/federated/DistributedCountDecentralized.lf +++ b/test/C/src/federated/DistributedCountDecentralized.lf @@ -1,19 +1,20 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * + * @author Edward A. Lee */ -target C { - timeout: 5 sec, - coordination: decentralized -}; +target C { timeout: 5 sec, coordination: decentralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - input in:int; - state c:int(1); + input in: int + + state c: int(1) + reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("At tag (%lld, %u), received %d. " @@ -33,6 +34,7 @@ reactor Print { } self->c++; =} + reaction(shutdown) {= if (self->c != 6) { fprintf(stderr, "Expected to receive 5 items.\n"); @@ -43,8 +45,9 @@ reactor Print { } federated reactor DistributedCountDecentralized { - c = new Count(); - p = new Print(); - c.out -> p.in after 200 msec; // Indicating a 'logical' connection - // with a large enough delay. + c = new Count() + p = new Print() + + // Indicating a 'logical' connection with a large enough delay. + c.out -> p.in after 200 msec } diff --git a/test/C/src/federated/DistributedCountDecentralizedLate.lf b/test/C/src/federated/DistributedCountDecentralizedLate.lf index aa14480ffd..98a89e14d4 100644 --- a/test/C/src/federated/DistributedCountDecentralizedLate.lf +++ b/test/C/src/federated/DistributedCountDecentralizedLate.lf @@ -1,26 +1,27 @@ /** - * Test a form of a distributed deterministic system - * where a federate that receives timestamped messages has a timer in addition to the messages - * as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. * @author Edward A. Lee * @author Soroush Bateni */ -target C { - timeout: 4900 msec, - coordination: decentralized -}; +target C { timeout: 4900 msec, coordination: decentralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - input in:int; // STP () - // STP(in, 30 msec); - state success:int(0); - state success_stp_violation:int(0); - timer t(0, 10 usec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c:int(0); + // STP () + input in: int // STP () + + // Force a timer to be invoke periodically to ensure logical time will + // advance in the absence of incoming messages. + timer t(0, 10 usec) + + state success: int(0) // STP(in, 30 msec); + state success_stp_violation: int(0) + state c: int(0) + reaction(in) {= tag_t current_tag = lf_tag(); printf("At tag (%lld, %u) received %d. Intended tag is (%lld, %u).\n", @@ -34,7 +35,7 @@ reactor Print { self->success++; // Message was on-time } self->c++; - =} STP (0) {= + =} STP(0){= tag_t current_tag = lf_tag(); printf("At tag (%lld, %u), message has violated the STP offset by (%lld, %u).\n", current_tag.time - start_time, current_tag.microstep, @@ -43,6 +44,7 @@ reactor Print { self->success_stp_violation++; self->c++; =} + reaction(t) {= // Do nothing. =} @@ -58,7 +60,9 @@ reactor Print { } federated reactor { - c = new Count(); - p = new Print(); - c.out -> p.in; // Indicating a 'logical' connection. + c = new Count() + p = new Print() + + // Indicating a 'logical' connection. + c.out -> p.in } diff --git a/test/C/src/federated/DistributedCountDecentralizedLateDownstream.lf b/test/C/src/federated/DistributedCountDecentralizedLateDownstream.lf index c987e0d4ff..619a275c8a 100644 --- a/test/C/src/federated/DistributedCountDecentralizedLateDownstream.lf +++ b/test/C/src/federated/DistributedCountDecentralizedLateDownstream.lf @@ -1,37 +1,41 @@ /** - * Test a form of a distributed deterministic system - * where a federate that receives timestamped messages has a timer in addition to the messages - * as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. - * In addition, this test shows that the STP violation is passed down the hierarchy until it is handled. + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. In addition, this test shows that the STP violation is + * passed down the hierarchy until it is handled. * - * An STP violation occurs if when a message with intended tag g1 arrives - * on a port p after the receiving federate has progressed far enough that - * it cannot process an event with tag g1 on the port p. - * This test has a fast timer (10 usec period) in the receiving federate - * so that the receiving federate is continually advancing its current tag, - * and hence an STP violation is more likely to occur. - * Furthermore, this test sets the STP threshold to 0, which makes the - * violation extremely likely to occur. It could still not occur, however, - * if the message arrives between ticks of the 10 usec timer. + * An STP violation occurs if when a message with intended tag g1 arrives on a + * port p after the receiving federate has progressed far enough that it cannot + * process an event with tag g1 on the port p. This test has a fast timer (10 + * usec period) in the receiving federate so that the receiving federate is + * continually advancing its current tag, and hence an STP violation is more + * likely to occur. Furthermore, this test sets the STP threshold to 0, which + * makes the violation extremely likely to occur. It could still not occur, + * however, if the message arrives between ticks of the 10 usec timer. * * @author Edward A. Lee * @author Soroush Bateni */ target C { - timeout: 1900 msec, // 9 msec headroom for the last (probably tardy) message to arrive. + // 9 msec headroom for the last (probably tardy) message to arrive. + timeout: 1900 msec, coordination: decentralized -}; +} -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor ImportantActuator { - input in:int; - state success:int(0); // Count messages that arrive without STP violation. - state success_stp_violation:int(0); - timer t(0, 10 usec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c:int(0); + input in: int + + // Force a timer to be invoke periodically to ensure logical time will + // advance in the absence of incoming messages. + timer t(0, 10 usec) + + state success: int(0) // Count messages that arrive without STP violation. + state success_stp_violation: int(0) + state c: int(0) + reaction(in) {= tag_t current_tag = lf_tag(); lf_print("ImportantActuator: At tag (%lld, %u) received %d. Intended tag is (%lld, %u).", @@ -47,7 +51,7 @@ reactor ImportantActuator { lf_print_error_and_exit("Normal reaction was invoked, but current tag doesn't match expected tag."); } self->c++; - =} STP (0) {= + =} STP(0){= tag_t current_tag = lf_tag(); lf_print("ImportantActuator: At tag (%lld, %u), message has violated the STP offset by (%lld, %u).", current_tag.time - start_time, current_tag.microstep, @@ -56,6 +60,7 @@ reactor ImportantActuator { self->success_stp_violation++; self->c++; =} + reaction(t) {= // Do nothing. =} @@ -70,7 +75,8 @@ reactor ImportantActuator { } reactor Print { - input in:int; + input in: int + reaction(in) {= tag_t current_tag = lf_tag(); lf_print("Print reactor: at tag (%lld, %u) received %d. Intended tag is (%lld, %u).", @@ -80,17 +86,20 @@ reactor Print { in->intended_tag.time - lf_time_start(), in->intended_tag.microstep); =} - } reactor Receiver { - input in:int; - timer t(0, 10 msec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c:int(0); - p = new Print(); - a = new ImportantActuator(); + input in: int + + // Force a timer to be invoke periodically to ensure logical time will + // advance in the absence of incoming messages. + timer t(0, 10 msec) + + p = new Print() + a = new ImportantActuator() + + state c: int(0) + reaction(in) -> p.in, a.in {= lf_set(p.in, in->value + 1); lf_set(a.in, in->value + 1); @@ -102,7 +111,9 @@ reactor Receiver { } federated reactor { - c = new Count(period = 1 sec); - r = new Receiver(); - c.out -> r.in; // Indicating a 'logical' connection. + c = new Count(period = 1 sec) + r = new Receiver() + + // Indicating a 'logical' connection. + c.out -> r.in } diff --git a/test/C/src/federated/DistributedCountDecentralizedLateHierarchy.lf b/test/C/src/federated/DistributedCountDecentralizedLateHierarchy.lf index 4323dcf600..305141d58b 100644 --- a/test/C/src/federated/DistributedCountDecentralizedLateHierarchy.lf +++ b/test/C/src/federated/DistributedCountDecentralizedLateHierarchy.lf @@ -1,28 +1,28 @@ /** - * Test a form of a distributed deterministic system - * where a federate that receives timestamped messages has a timer in addition to the messages - * as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. - * In addition, this test shows that the STP violation of the reaction - * is passed down the hierarchy until it is handled. + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. In addition, this test shows that the STP violation of the + * reaction is passed down the hierarchy until it is handled. * * @author Edward A. Lee * @author Soroush Bateni */ -target C { - timeout: 4900 msec, - coordination: decentralized -}; +target C { timeout: 4900 msec, coordination: decentralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor ImportantActuator { - input in:int; - state success:int(0); - state success_stp_violation:int(0); - timer t(0, 10 usec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c:int(0); + input in: int + + // Force a timer to be invoke periodically to ensure logical time will + // advance in the absence of incoming messages. + timer t(0, 10 usec) + + state success: int(0) + state success_stp_violation: int(0) + state c: int(0) + reaction(in) {= tag_t current_tag = lf_tag(); printf("At tag (%lld, %u) received %d. Intended tag is (%lld, %u).\n", @@ -36,7 +36,7 @@ reactor ImportantActuator { self->success++; // Message was on-time } self->c++; - =} STP (0) {= + =} STP(0){= tag_t current_tag = lf_tag(); printf("Message violated STP offset by (%lld, %u).\n", current_tag.time - in->intended_tag.time, @@ -44,6 +44,7 @@ reactor ImportantActuator { self->success_stp_violation++; self->c++; =} + reaction(t) {= // Do nothing. =} @@ -59,7 +60,8 @@ reactor ImportantActuator { } reactor Print { - input in:int; + input in: int + reaction(in) {= tag_t current_tag = lf_tag(); printf("At tag (%lld, %u) received %d. Intended tag is (%lld, %u).\n", @@ -69,19 +71,21 @@ reactor Print { in->intended_tag.time - lf_time_start(), in->intended_tag.microstep); =} - } reactor Receiver { - input in:int; - timer t(0, 10 msec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c:int(0); - p = new Print(); - a = new ImportantActuator(); - in -> p.in; - in -> a.in; + input in: int + + timer t(0, 10 msec) // Force a timer to be invoke periodically + + p = new Print() + a = new ImportantActuator() + + in -> p.in + in -> a.in + + // to ensure logical time will advance in the absence of incoming messages. + state c: int(0) reaction(t) {= // Do nothing. @@ -89,7 +93,9 @@ reactor Receiver { } federated reactor { - c = new Count(); - r = new Receiver(); - c.out -> r.in; // Indicating a 'logical' connection. + c = new Count() + r = new Receiver() + + // Indicating a 'logical' connection. + c.out -> r.in } diff --git a/test/C/src/federated/DistributedCountPhysical.lf b/test/C/src/federated/DistributedCountPhysical.lf index 7519a1b18d..bde2f151b1 100644 --- a/test/C/src/federated/DistributedCountPhysical.lf +++ b/test/C/src/federated/DistributedCountPhysical.lf @@ -1,28 +1,32 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages only over connections - * that are marked 'physical' (using the ~> arrow). - * Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages only over connections that are + * marked 'physical' (using the ~> arrow). Therefore, no additional coordination + * of the advancement of time (HLA or Ptides) is needed. * * @author Edward A. Lee * @author Soroush Bateni */ -target C { - timeout: 1 sec -}; +target C { timeout: 1 sec } + reactor Count { - timer t(200 msec, 1 sec); - state s:int(0); - output out:int; + output out: int + + timer t(200 msec, 1 sec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor Print { - input in:int; - state c:int(0); + input in: int + + state c: int(0) + reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("At time %lld, received %d.\n", elapsed_time, in->value); @@ -37,6 +41,7 @@ reactor Print { } self->c++; =} + reaction(shutdown) {= if (self->c != 1) { fprintf(stderr, "ERROR: Expected to receive 1 item. Received %d.\n", self->c); @@ -45,8 +50,11 @@ reactor Print { printf("SUCCESS: Successfully received 1 item.\n"); =} } + federated reactor at localhost { - c = new Count(); - p = new Print(); - c.out ~> p.in; // Indicating a 'physical' connection. + c = new Count() + p = new Print() + + // Indicating a 'physical' connection. + c.out ~> p.in } diff --git a/test/C/src/federated/DistributedCountPhysicalAfterDelay.lf b/test/C/src/federated/DistributedCountPhysicalAfterDelay.lf index 4c0f2edab6..83f24ab531 100644 --- a/test/C/src/federated/DistributedCountPhysicalAfterDelay.lf +++ b/test/C/src/federated/DistributedCountPhysicalAfterDelay.lf @@ -1,20 +1,20 @@ /** - * Test a distributed system where a federation - * receives messages only over connections - * that are marked 'physical' (using the - * ~> arrow) with an after delay. The receiver - * verifies that the after delay is correctly - * imposed. + * Test a distributed system where a federation receives messages only over + * connections that are marked 'physical' (using the ~> arrow) with an after + * delay. The receiver verifies that the after delay is correctly imposed. * * @author Edward A. Lee * @author Soroush Bateni */ -target C; +target C + import Count from "../lib/Count.lf" reactor Print { - input in:int; - state c:int(1); + input in: int + + state c: int(1) + reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("At time %ld, received %d.\n", elapsed_time, in->value); @@ -29,6 +29,7 @@ reactor Print { self->c++; lf_request_stop(); =} + reaction(shutdown) {= if (self->c != 2) { fprintf( @@ -40,9 +41,11 @@ reactor Print { printf("SUCCESS: Successfully received 1 item.\n"); =} } + federated reactor at localhost { - c = new Count(offset = 200 msec, period = 0); - p = new Print(); - c.out ~> p.in after 400 msec; // Indicating a 'physical' connection with - // a 400 msec after delay. + c = new Count(offset = 200 msec, period = 0) + p = new Print() + + // Indicating a 'physical' connection with a 400 msec after delay. + c.out ~> p.in after 400 msec } diff --git a/test/C/src/federated/DistributedCountPhysicalDecentralized.lf b/test/C/src/federated/DistributedCountPhysicalDecentralized.lf index af7f835f5a..89dbc54274 100644 --- a/test/C/src/federated/DistributedCountPhysicalDecentralized.lf +++ b/test/C/src/federated/DistributedCountPhysicalDecentralized.lf @@ -1,30 +1,32 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages only over connections - * that are marked 'physical' (using the ~> arrow). - * Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages only over connections that are + * marked 'physical' (using the ~> arrow). Therefore, no additional coordination + * of the advancement of time (HLA or Ptides) is needed. * * @author Edward A. Lee * @author Soroush Bateni */ -target C { - timeout: 1 sec, - coordination: decentralized -}; +target C { timeout: 1 sec, coordination: decentralized } reactor Count { - timer t(200 msec, 1 sec); - state s:int(0); - output out:int; + output out: int + + timer t(200 msec, 1 sec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor Print { - input in:int; - state c:int(0); + input in: int + + state c: int(0) + reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("At time %lld, received %d.\n", elapsed_time, in->value); @@ -38,6 +40,7 @@ reactor Print { } self->c++; =} + reaction(shutdown) {= if (self->c != 1) { fprintf(stderr, "ERROR: Expected to receive 1 item. Received %d.\n", self->c); @@ -46,8 +49,11 @@ reactor Print { printf("SUCCESS: Successfully received 1 item.\n"); =} } + federated reactor at localhost { - c = new Count(); - p = new Print(); - c.out ~> p.in; // Indicating a 'physical' connection. + c = new Count() + p = new Print() + + // Indicating a 'physical' connection. + c.out ~> p.in } diff --git a/test/C/src/federated/DistributedDoublePort.lf b/test/C/src/federated/DistributedDoublePort.lf index 39765a3a35..fa4ba1c24a 100644 --- a/test/C/src/federated/DistributedDoublePort.lf +++ b/test/C/src/federated/DistributedDoublePort.lf @@ -1,25 +1,23 @@ /** - * Test the case for when two upstream federates - * send messages to a downstream federte on two - * different ports. One message should carry a - * microstep delay relative to the other - * message. + * Test the case for when two upstream federates send messages to a downstream + * federte on two different ports. One message should carry a microstep delay + * relative to the other message. * * @author Soroush Bateni */ -target C { - timeout: 900 msec, - logging: DEBUG, - coordination: centralized -}; +target C { timeout: 900 msec, logging: DEBUG, coordination: centralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor CountMicrostep { - state count:int(1); - output out:int; - logical action act:int; - timer t(0, 1 sec); + output out: int + + timer t(0, 1 sec) + + logical action act: int + + state count: int(1) + reaction(t) -> act {= lf_schedule_int(act, 0, self->count++); =} @@ -30,8 +28,9 @@ reactor CountMicrostep { } reactor Print { - input in:int; - input in2:int; + input in: int + input in2: int + reaction(in, in2) {= interval_t elapsed_time = lf_time_logical_elapsed(); lf_print("At tag (%lld, %u), received in = %d and in2 = %d.", elapsed_time, lf_tag().microstep, in->value, in2->value); @@ -46,9 +45,10 @@ reactor Print { } federated reactor DistributedDoublePort { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.out -> p.in; // Indicating a 'logical' connection. - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.out -> p.in // Indicating a 'logical' connection. + cm.out -> p.in2 } diff --git a/test/C/src/federated/DistributedLogicalActionUpstreamLong.lf b/test/C/src/federated/DistributedLogicalActionUpstreamLong.lf index 80bf89b93d..7701141c17 100644 --- a/test/C/src/federated/DistributedLogicalActionUpstreamLong.lf +++ b/test/C/src/federated/DistributedLogicalActionUpstreamLong.lf @@ -2,18 +2,18 @@ * Test that a rapidly produced logical action in an upstream federate can be * properly handled in a long chain of federates. */ -target C { - timeout: 1 msec -}; +target C { timeout: 1 msec } import PassThrough from "../lib/PassThrough.lf" import TestCount from "../lib/TestCount.lf" reactor WithLogicalAction { - output out:int; - state thread_id:lf_thread_t(0); - state counter:int(1); - logical action act(0):int; + output out: int + + logical action act(0): int + + state thread_id: lf_thread_t(0) + state counter: int(1) reaction(startup, act) -> act, out {= SET(out, self->counter); @@ -22,9 +22,8 @@ reactor WithLogicalAction { } federated reactor { - a = new WithLogicalAction(); - test = new TestCount(num_inputs=21); - + a = new WithLogicalAction() + test = new TestCount(num_inputs = 21) passThroughs1 = new PassThrough() passThroughs2 = new PassThrough() passThroughs3 = new PassThrough() @@ -36,15 +35,27 @@ federated reactor { passThroughs9 = new PassThrough() passThroughs10 = new PassThrough() - a.out, passThroughs1.out, - passThroughs2.out, passThroughs3.out, - passThroughs4.out, passThroughs5.out, - passThroughs6.out, passThroughs7.out, - passThroughs8.out, passThroughs9.out, - passThroughs10.out -> passThroughs1.in, - passThroughs2.in, passThroughs3.in, - passThroughs4.in, passThroughs5.in, - passThroughs6.in, passThroughs7.in, - passThroughs8.in, passThroughs9.in, - passThroughs10.in, test.in + a.out, + passThroughs1.out, + passThroughs2.out, + passThroughs3.out, + passThroughs4.out, + passThroughs5.out, + passThroughs6.out, + passThroughs7.out, + passThroughs8.out, + passThroughs9.out, + passThroughs10.out -> + passThroughs1.in, + passThroughs2.in, + passThroughs3.in, + passThroughs4.in, + passThroughs5.in, + passThroughs6.in, + passThroughs7.in, + passThroughs8.in, + passThroughs9.in, + passThroughs10.in, + test.in + ; } diff --git a/test/C/src/federated/DistributedLoopedAction.lf b/test/C/src/federated/DistributedLoopedAction.lf index aef554f701..a2f1988b95 100644 --- a/test/C/src/federated/DistributedLoopedAction.lf +++ b/test/C/src/federated/DistributedLoopedAction.lf @@ -1,25 +1,24 @@ /** - * Test a sender-receiver network system that - * relies on microsteps being taken into account. + * Test a sender-receiver network system that relies on microsteps being taken + * into account. * * @author Soroush Bateni */ - -target C { - timeout: 1 sec -}; +target C { timeout: 1 sec } import Sender from "../lib/LoopedActionSender.lf" -reactor Receiver(take_a_break_after:int(10), break_interval:time(400 msec)) { - input in:int; - state received_messages:int(0); - state total_received_messages:int(0); - state breaks:int(0); - timer t(0, 1 msec); // This will impact the performance - // but forces the logical time to advance - // Comment this line for a more sensible - // log output. +reactor Receiver(take_a_break_after: int(10), break_interval: time(400 msec)) { + input in: int + + // This will impact the performance but forces the logical time to advance. + // Comment this line for a more sensible log output. + timer t(0, 1 msec) + + state received_messages: int(0) + state total_received_messages: int(0) + state breaks: int(0) + reaction(in) {= printf("At tag (%lld, %u) received value %d.\n", lf_time_logical_elapsed(), @@ -57,10 +56,9 @@ reactor Receiver(take_a_break_after:int(10), break_interval:time(400 msec)) { =} } - federated reactor DistributedLoopedAction { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedLoopedActionDecentralized.lf b/test/C/src/federated/DistributedLoopedActionDecentralized.lf index 72a624dbb0..8fb60311e9 100644 --- a/test/C/src/federated/DistributedLoopedActionDecentralized.lf +++ b/test/C/src/federated/DistributedLoopedActionDecentralized.lf @@ -1,37 +1,29 @@ /** - * Test a sender-receiver network system that - * relies on microsteps being taken into account. - * The purpose of this test is to check whether the functionalities - * pertinent to dynamic STP offset adjustments are present and + * Test a sender-receiver network system that relies on microsteps being taken + * into account. The purpose of this test is to check whether the + * functionalities pertinent to dynamic STP offset adjustments are present and * functioning to a degree. * - * This version of the test does not use a centralized - * coordinator to advance tag. Therefore, - * the receiver will rely on an STP offset (initially - * zero) to wait long enough for messages to arrive - * before advancing its tag. In this test, - * the STP offset is initially zero and gradually - * raised every time an STP violation is perceived until - * no STP violation is observed. Therefore, the exact - * outcome of the test will depend on actual runtime - * timing. - * + * This version of the test does not use a centralized coordinator to advance + * tag. Therefore, the receiver will rely on an STP offset (initially zero) to + * wait long enough for messages to arrive before advancing its tag. In this + * test, the STP offset is initially zero and gradually raised every time an STP + * violation is perceived until no STP violation is observed. Therefore, the + * exact outcome of the test will depend on actual runtime timing. * * @author Soroush Bateni */ - -target C { - timeout: 1 sec, - coordination: decentralized -}; +target C { timeout: 1 sec, coordination: decentralized } import Sender from "../lib/LoopedActionSender.lf" -reactor Receiver(take_a_break_after:int(10), break_interval:time(400 msec)) { - input in:int; - state received_messages:int(0); - state total_received_messages:int(0); - state breaks:int(0); +reactor Receiver(take_a_break_after: int(10), break_interval: time(400 msec)) { + input in: int + + state received_messages: int(0) + state total_received_messages: int(0) + state breaks: int(0) + reaction(in) {= tag_t current_tag = lf_tag(); lf_print("At tag (%lld, %u) received value %d with STP violation (%lld, %u).", @@ -82,16 +74,23 @@ reactor Receiver(take_a_break_after:int(10), break_interval:time(400 msec)) { =} } -reactor STPReceiver(take_a_break_after:int(10), break_interval:time(400 msec), stp_offset:time(0)) { - input in:int; - state last_time_updated_stp:time(0); - receiver = new Receiver(take_a_break_after = 10, break_interval = 400 msec); - timer t (0, 1 msec); // Force advancement of logical time +reactor STPReceiver( + take_a_break_after: int(10), + break_interval: time(400 msec), + stp_offset: time(0) +) { + input in: int - reaction (in) -> receiver.in {= + timer t(0, 1 msec) // Force advancement of logical time + + receiver = new Receiver(take_a_break_after = 10, break_interval = 400 msec) + + state last_time_updated_stp: time(0) + + reaction(in) -> receiver.in {= lf_print("Received %d.", in->value); lf_set(receiver.in, in->value); - =} STP (stp_offset) {= + =} STP(stp_offset){= lf_print("Received %d late.", in->value); tag_t current_tag = lf_tag(); lf_print("STP violation of (%lld, %u) perceived on the input.", @@ -108,15 +107,17 @@ reactor STPReceiver(take_a_break_after:int(10), break_interval:time(400 msec), s } =} - reaction (t) {= + reaction(t) {= // Do nothing =} } - federated reactor DistributedLoopedActionDecentralized { - sender = new Sender(take_a_break_after = 10, break_interval = 400 msec); - stpReceiver = new STPReceiver(take_a_break_after = 10, break_interval = 400 msec); + sender = new Sender(take_a_break_after = 10, break_interval = 400 msec) + stpReceiver = new STPReceiver( + take_a_break_after = 10, + break_interval = 400 msec + ) - sender.out -> stpReceiver.in; + sender.out -> stpReceiver.in } diff --git a/test/C/src/federated/DistributedLoopedPhysicalAction.lf b/test/C/src/federated/DistributedLoopedPhysicalAction.lf index be1c2f37f6..6449c2319b 100644 --- a/test/C/src/federated/DistributedLoopedPhysicalAction.lf +++ b/test/C/src/federated/DistributedLoopedPhysicalAction.lf @@ -1,25 +1,27 @@ /** - * Test a sender-receiver network system that - * is similar to DistributedLoopedAction, but it uses a physical - * action rather than a logical action. - * This also demonstrates the advance-message-interval coordination option. - * This specifies the time period between Time Advance Notice (TAN) messages - * sent to the RTI (a form of null message that must be sent because of the - * physical action). The presence of this option also silences a warning + * Test a sender-receiver network system that is similar to + * DistributedLoopedAction, but it uses a physical action rather than a logical + * action. This also demonstrates the advance-message-interval coordination + * option. This specifies the time period between Time Advance Notice (TAN) + * messages sent to the RTI (a form of null message that must be sent because of + * the physical action). The presence of this option also silences a warning * about having a physical action that triggers an output. * * @author Soroush Bateni */ - target C { timeout: 1 sec, - coordination-options: {advance-message-interval: 10 msec} // Silences warning. -}; + // Silences warning. + coordination-options: { advance-message-interval: 10 msec } +} + +reactor Sender(take_a_break_after: int(10), break_interval: time(550 msec)) { + output out: int + + physical action act + + state sent_messages: int(0) -reactor Sender(take_a_break_after:int(10), break_interval:time(550 msec)) { - output out:int; - physical action act; - state sent_messages:int(0); reaction(startup, act) -> act, out {= // Send a message on out lf_set(out, self->sent_messages); @@ -34,15 +36,17 @@ reactor Sender(take_a_break_after:int(10), break_interval:time(550 msec)) { =} } -reactor Receiver(take_a_break_after:int(10), break_interval:time(550 msec)) { - input in:int; - state received_messages:int(0); - state total_received_messages:int(0); - state breaks:int(0); - timer t(0, 1 msec); // This will impact the performance - // but forces the logical time to advance - // Comment this line for a more sensible - // log output. +reactor Receiver(take_a_break_after: int(10), break_interval: time(550 msec)) { + input in: int + + // This will impact the performance but forces the logical time to advance. + // Comment this line for a more sensible log output. + timer t(0, 1 msec) + + state received_messages: int(0) + state total_received_messages: int(0) + state breaks: int(0) + reaction(in) {= tag_t current_tag = lf_tag(); lf_print("At tag (%lld, %u) received %d.", @@ -75,10 +79,9 @@ reactor Receiver(take_a_break_after:int(10), break_interval:time(550 msec)) { =} } - federated reactor DistributedLoopedPhysicalAction { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedLoopedPhysicalActionDecentralized.lf b/test/C/src/federated/DistributedLoopedPhysicalActionDecentralized.lf index 37ab178c84..0aaa58c16d 100644 --- a/test/C/src/federated/DistributedLoopedPhysicalActionDecentralized.lf +++ b/test/C/src/federated/DistributedLoopedPhysicalActionDecentralized.lf @@ -1,20 +1,16 @@ /** - * Test a sender-receiver network system that - * relies on microsteps being taken into account. + * Test a sender-receiver network system that relies on microsteps being taken + * into account. * * @author Soroush Bateni */ - -target C { - timeout: 1 sec, - coordination: decentralized -}; +target C { timeout: 1 sec, coordination: decentralized } import Sender, Receiver from "DistributedLoopedPhysicalAction.lf" federated reactor { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedMultiport.lf b/test/C/src/federated/DistributedMultiport.lf index 80042e340a..d073537a5d 100644 --- a/test/C/src/federated/DistributedMultiport.lf +++ b/test/C/src/federated/DistributedMultiport.lf @@ -1,13 +1,13 @@ // Check multiport connections between federates. -target C { - timeout: 1 sec, - coordination: centralized -}; +target C { timeout: 1 sec, coordination: centralized } reactor Source { - output[4] out:int; - timer t(0, 100 msec); - state count:int(0); + output[4] out: int + + timer t(0, 100 msec) + + state count: int(0) + reaction(t) -> out {= for (int i = 0; i < out_width; i++) { lf_set(out[i], self->count++); @@ -16,8 +16,10 @@ reactor Source { } reactor Destination { - input[4] in:int; - state count:int(0); + input[4] in: int + + state count: int(0) + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { @@ -28,6 +30,7 @@ reactor Destination { } } =} + reaction(shutdown) {= if (self->count == 0) { lf_print_error_and_exit("No data received."); @@ -36,7 +39,8 @@ reactor Destination { } federated reactor DistributedMultiport { - s = new Source(); - d = new Destination(); - s.out -> d.in; + s = new Source() + d = new Destination() + + s.out -> d.in } diff --git a/test/C/src/federated/DistributedMultiportToBank.lf b/test/C/src/federated/DistributedMultiportToBank.lf index e69477943f..943b0af623 100644 --- a/test/C/src/federated/DistributedMultiportToBank.lf +++ b/test/C/src/federated/DistributedMultiportToBank.lf @@ -1,12 +1,13 @@ // Check multiport to bank connections between federates. -target C { - timeout: 1 sec -}; +target C { timeout: 1 sec } reactor Source { - output[2] out:int; - timer t(0, 100 msec); - state count:int(0); + output[2] out: int + + timer t(0, 100 msec) + + state count: int(0) + reaction(t) -> out {= for (int i = 0; i < out_width; i++) { lf_set(out[i], self->count); @@ -16,14 +17,17 @@ reactor Source { } reactor Destination { - input in:int; - state count:int(0); + input in: int + + state count: int(0) + reaction(in) {= lf_print("Received %d.", in->value); if (self->count++ != in->value) { lf_print_error_and_exit("Expected %d.", self->count - 1); } =} + reaction(shutdown) {= if (self->count == 0) { lf_print_error_and_exit("No data received."); @@ -32,7 +36,8 @@ reactor Destination { } federated reactor DistributedMultiportToBank { - s = new Source(); - d = new[2] Destination(); - s.out -> d.in; + s = new Source() + d = new[2] Destination() + + s.out -> d.in } diff --git a/test/C/src/federated/DistributedMultiportToken.lf b/test/C/src/federated/DistributedMultiportToken.lf index 929f384083..52a23ce129 100644 --- a/test/C/src/federated/DistributedMultiportToken.lf +++ b/test/C/src/federated/DistributedMultiportToken.lf @@ -1,14 +1,14 @@ // Check multiport connections between federates where the message is // carried by a Token (in this case, with an array of char). -target C { - timeout: 1 sec, - coordination: centralized -}; +target C { timeout: 1 sec, coordination: centralized } reactor Source { - output[4] out:char*; - timer t(0, 200 msec); - state count:int(0); + output[4] out: char* + + timer t(0, 200 msec) + + state count: int(0) + reaction(t) -> out {= for (int i = 0; i < out_width; i++) { // With NULL, 0 arguments, snprintf tells us how many bytes are needed. @@ -27,7 +27,8 @@ reactor Source { } reactor Destination { - input[4] in:char*; + input[4] in: char* + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { @@ -38,7 +39,8 @@ reactor Destination { } federated reactor DistributedMultiportToken { - s = new Source(); - d = new Destination(); - s.out -> d.in; + s = new Source() + d = new Destination() + + s.out -> d.in } diff --git a/test/C/src/federated/DistributedNetworkOrder.lf b/test/C/src/federated/DistributedNetworkOrder.lf index b155373ff5..f3dd40bb69 100644 --- a/test/C/src/federated/DistributedNetworkOrder.lf +++ b/test/C/src/federated/DistributedNetworkOrder.lf @@ -1,22 +1,23 @@ -/* - * This is a test for send_timed_message, - * which is an internal API. +/** + * This is a test for send_timed_message, which is an internal API. * - * This test sends a second message at time 5 msec that has the same intended tag as - * a message that it had previously sent at time 0 msec. This results in a warning, - * but the message microstep is incremented and correctly received one microstep later. + * This test sends a second message at time 5 msec that has the same intended + * tag as a message that it had previously sent at time 0 msec. This results in + * a warning, but the message microstep is incremented and correctly received + * one microstep later. * * @author Soroush Bateni */ - target C { timeout: 1 sec, build-type: RelWithDebInfo // Release with debug info -}; +} reactor Sender { - output out:int; - timer t(0, 1 msec); + output out: int + + timer t(0, 1 msec) + reaction(t) -> out {= int payload = 1; if (lf_time_logical_elapsed() == 0LL) { @@ -31,8 +32,9 @@ reactor Sender { } reactor Receiver { - input in:int; - state success:int(0); + input in: int + + state success: int(0) reaction(in) {= tag_t current_tag = lf_tag(); @@ -48,7 +50,7 @@ reactor Receiver { lf_time_logical_elapsed(), lf_tag().microstep); =} - + reaction(shutdown) {= if (self->success != 2) { fprintf(stderr, "ERROR: Failed to receive messages.\n"); @@ -59,8 +61,8 @@ reactor Receiver { } federated reactor DistributedNetworkOrder { - sender = new Sender(); - receiver = new Receiver(); - - sender.out -> receiver.in; + sender = new Sender() + receiver = new Receiver() + + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedPhysicalActionUpstream.lf b/test/C/src/federated/DistributedPhysicalActionUpstream.lf index 3e06b9a7df..0da8cb62c8 100644 --- a/test/C/src/federated/DistributedPhysicalActionUpstream.lf +++ b/test/C/src/federated/DistributedPhysicalActionUpstream.lf @@ -2,10 +2,10 @@ * Test that a rapidly produced physical action in an upstream federate can be * properly handled in federated execution. */ -target C { +target C { timeout: 10 secs, - coordination-options: {advance-message-interval: 30 msec} -}; + coordination-options: { advance-message-interval: 30 msec } +} import PassThrough from "../lib/PassThrough.lf" import TestCount from "../lib/TestCount.lf" @@ -27,25 +27,29 @@ preamble {= =} reactor WithPhysicalAction { - output out:int; - state thread_id:lf_thread_t(0); - physical action act(0):int; + output out: int + + physical action act(0): int + + state thread_id: lf_thread_t(0) + reaction(startup) -> act {= - // start new thread, provide callback - lf_thread_create(&self->thread_id, &take_time, act); + // start new thread, provide callback + lf_thread_create(&self->thread_id, &take_time, act); =} - + reaction(act) -> out {= SET(out, act->value); =} } federated reactor { - a = new WithPhysicalAction(); - m1 = new PassThrough(); - m2 = new PassThrough(); - test = new TestCount(num_inputs=14); - a.out -> m1.in; - m1.out -> m2.in; - m2.out -> test.in; + a = new WithPhysicalAction() + m1 = new PassThrough() + m2 = new PassThrough() + test = new TestCount(num_inputs = 14) + + a.out -> m1.in + m1.out -> m2.in + m2.out -> test.in } diff --git a/test/C/src/federated/DistributedPhysicalActionUpstreamLong.lf b/test/C/src/federated/DistributedPhysicalActionUpstreamLong.lf index 089fb0f82f..4f8d632e09 100644 --- a/test/C/src/federated/DistributedPhysicalActionUpstreamLong.lf +++ b/test/C/src/federated/DistributedPhysicalActionUpstreamLong.lf @@ -2,10 +2,10 @@ * Test that a rapidly produced physical action in an upstream federate can be * properly handled in a long chain of federates. */ -target C { +target C { timeout: 1 sec, - coordination-options: {advance-message-interval: 50 usec} -}; + coordination-options: { advance-message-interval: 50 usec } +} import PassThrough from "../lib/PassThrough.lf" import TestCount from "../lib/TestCount.lf" @@ -27,23 +27,25 @@ preamble {= =} reactor WithPhysicalAction { - output out:int; - state thread_id:lf_thread_t(0); - physical action act(0):int; + output out: int + + physical action act(0): int + + state thread_id: lf_thread_t(0) + reaction(startup) -> act {= - // start new thread, provide callback - lf_thread_create(&self->thread_id, &take_time, act); + // start new thread, provide callback + lf_thread_create(&self->thread_id, &take_time, act); =} - + reaction(act) -> out {= SET(out, act->value); =} } federated reactor { - a = new WithPhysicalAction(); - test = new TestCount(num_inputs=19); - + a = new WithPhysicalAction() + test = new TestCount(num_inputs = 19) passThroughs1 = new PassThrough() passThroughs2 = new PassThrough() passThroughs3 = new PassThrough() @@ -54,16 +56,29 @@ federated reactor { passThroughs8 = new PassThrough() passThroughs9 = new PassThrough() passThroughs10 = new PassThrough() - - a.out, passThroughs1.out, - passThroughs2.out, passThroughs3.out, - passThroughs4.out, passThroughs5.out, - passThroughs6.out, passThroughs7.out, - passThroughs8.out, passThroughs9.out, - passThroughs10.out -> passThroughs1.in, - passThroughs2.in, passThroughs3.in, - passThroughs4.in, passThroughs5.in, - passThroughs6.in, passThroughs7.in, - passThroughs8.in, passThroughs9.in, - passThroughs10.in, test.in + + a.out, + passThroughs1.out, + passThroughs2.out, + passThroughs3.out, + passThroughs4.out, + passThroughs5.out, + passThroughs6.out, + passThroughs7.out, + passThroughs8.out, + passThroughs9.out, + passThroughs10.out + -> + passThroughs1.in, + passThroughs2.in, + passThroughs3.in, + passThroughs4.in, + passThroughs5.in, + passThroughs6.in, + passThroughs7.in, + passThroughs8.in, + passThroughs9.in, + passThroughs10.in, + test.in + ; } From 17f750c65a455441b1736a5945f8877150b2cd7e Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 00:32:47 -0700 Subject: [PATCH 071/130] [formatting] Superficial patches. --- .../src/org/lflang/ast/FormattingUtils.java | 9 +++---- .../src/org/lflang/ast/MalleableString.java | 2 +- org.lflang/src/org/lflang/ast/ToLf.java | 27 ++++++++++++------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index a95c4dde6e..dff659c4ca 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -44,8 +44,6 @@ public class FormattingUtils { * {@code lineLength}. */ public static String render(EObject object, int lineLength) { - // The following looks useless, but it wraps the representation in an - // enclosing object that ensures that top-level comments are rendered. MalleableString ms = ToLf.instance.doSwitch(object); ms.findBestRepresentation( ms::render, @@ -56,9 +54,10 @@ public static String render(EObject object, int lineLength) { lineLength ); var optimizedRendering = ms.render(); - return optimizedRendering.unplacedComments().map(s -> lineWrapComment(s, lineLength)) - .collect(Collectors.joining(System.lineSeparator())) - + System.lineSeparator() + optimizedRendering.rendering(); + String comments = optimizedRendering.unplacedComments().map(s -> lineWrapComment(s, lineLength)) + .collect(Collectors.joining(System.lineSeparator())); + return comments.isBlank() ? optimizedRendering.rendering() + : comments + System.lineSeparator() + optimizedRendering.rendering(); } /** diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 42c19941fc..dc6edf19e1 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -309,7 +309,7 @@ public RenderResult render() { renderedComments.isBlank() ? result.rendering : renderedComments + System.lineSeparator() + result.rendering ).replaceAll( - "(?<=" + System.lineSeparator() + "|^)(?=\\s*\\S)", + "(?<=" + System.lineSeparator() + "|^)(?=\\h*\\S)", " ".repeat(indentation) ), result.levelsOfCommentDisplacement() diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 2aec3788d8..2903b07290 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -177,12 +177,15 @@ private Predicate sameLine(INode node) { @Override public MalleableString caseCode(Code code) { - String content = ToText.instance.doSwitch(code); + String content = ToText.instance.doSwitch(code).lines() + .map(String::stripTrailing) + .collect(Collectors.joining(System.lineSeparator())); String singleLineRepresentation = String.format("{= %s =}", content.strip()); - String multilineRepresentation = String.format( - "{=%n%s=}", - content.strip().indent(FormattingUtils.INDENTATION) - ); + String multilineRepresentation = new Builder() + .append(String.format("{=%n")) + .append(MalleableString.anyOf(content).indent(FormattingUtils.INDENTATION)) + .append("=}") + .get().render().rendering(); if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { return MalleableString.anyOf(multilineRepresentation); } @@ -366,10 +369,10 @@ public MalleableString caseReactor(Reactor object) { ); msb.append(smallFeatures); if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) { - msb.append(System.lineSeparator().repeat(2)); + msb.append(System.lineSeparator().repeat(1)); } msb.append(bigFeatures); - msb.append(String.format("%n}")); + msb.append("}"); return msb.get(); } @@ -518,7 +521,7 @@ public MalleableString caseMode(Mode object) { List.of(object.getReactions()), 1 )); - msb.append(String.format("%n}")); + msb.append("}"); return msb.get(); } @@ -950,13 +953,17 @@ private MalleableString indentedStatements( .map(statementList -> list( System.lineSeparator().repeat(1 + extraSeparation), "", - "", + System.lineSeparator(), true, true, statementList ) ).collect( - new Joiner(System.lineSeparator().repeat(2 + extraSeparation), "", "") + new Joiner( + System.lineSeparator().repeat(1 + extraSeparation), + "", + "" + ) ).indent(FormattingUtils.INDENTATION); } } From 0b376bac388bda76f39b7e0ce6d5a6b0605b8437 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 01:16:13 -0700 Subject: [PATCH 072/130] [formatting] More superficial patches. --- org.lflang/src/org/lflang/ast/ToLf.java | 6 +++--- org.lflang/src/org/lflang/util/StringUtil.java | 9 +++------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 2903b07290..0692bab10c 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -184,7 +184,7 @@ public MalleableString caseCode(Code code) { String multilineRepresentation = new Builder() .append(String.format("{=%n")) .append(MalleableString.anyOf(content).indent(FormattingUtils.INDENTATION)) - .append("=}") + .append(String.format("%n=}")) .get().render().rendering(); if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { return MalleableString.anyOf(multilineRepresentation); @@ -665,7 +665,7 @@ public MalleableString caseConnection(Connection object) { "", MalleableString.anyOf(System.lineSeparator()).indent(FormattingUtils.INDENTATION) ); - msb.append(object.isPhysical() ? " ~> " : " -> "); + msb.append(object.isPhysical() ? " ~> " : " ->"); msb.append(minimallyDelimitedList(object.getRightPorts())); if (object.getDelay() != null) msb.append(" after ").append(doSwitch(object.getDelay())); if (object.getSerializer() != null) { @@ -678,7 +678,7 @@ private MalleableString minimallyDelimitedList(List items) { return MalleableString.anyOf( list(", ", "", "", true, true, items), new Builder() - .append(System.lineSeparator()) + .append(String.format(" %n")) .append( list(String.format(",%n"), "", "", true, true, items) .indent(FormattingUtils.INDENTATION) diff --git a/org.lflang/src/org/lflang/util/StringUtil.java b/org.lflang/src/org/lflang/util/StringUtil.java index 6f12d253ad..9ca560ce9c 100644 --- a/org.lflang/src/org/lflang/util/StringUtil.java +++ b/org.lflang/src/org/lflang/util/StringUtil.java @@ -111,7 +111,7 @@ public static String removeQuotes(String str) { * @return trimmed code block */ public static String trimCodeBlock(String code) { - String[] codeLines = code.split("\n"); + String[] codeLines = code.split("(\r\n?)|\n"); String prefix = null; StringBuilder buffer = new StringBuilder(); for (String line : codeLines) { @@ -136,13 +136,10 @@ public static String trimCodeBlock(String code) { } else { buffer.append(line); } - buffer.append("\n"); + buffer.append(System.lineSeparator()); } } - if (buffer.length() > 1) { - buffer.deleteCharAt(buffer.length() - 1); // remove the last newline - } - return buffer.toString(); + return buffer.toString().stripTrailing(); } public static String addDoubleQuotes(String str) { From bf9f119d22597a04096a22f01390374ae8bb6fa2 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 01:17:25 -0700 Subject: [PATCH 073/130] [formatting] Format more C federated tests. --- .../DistributedStopZeroDecentralized.lf | 12 +-- test/C/src/federated/DistributedToken.lf | 64 +++++++-------- test/C/src/federated/FeedbackDelay.lf | 73 ++++++++++-------- test/C/src/federated/FeedbackDelaySimple.lf | 26 ++++--- test/C/src/federated/HelloDistributed.lf | 43 ++++++----- .../federated/LoopDistributedCentralized.lf | 41 ++++++---- .../LoopDistributedCentralizedPrecedence.lf | 37 +++++---- ...stributedCentralizedPrecedenceHierarchy.lf | 62 ++++++++------- .../federated/LoopDistributedDecentralized.lf | 43 ++++++----- test/C/src/federated/LoopDistributedDouble.lf | 52 ++++++++----- test/C/src/federated/ParallelDestinations.lf | 25 +++--- test/C/src/federated/ParallelSources.lf | 24 +++--- .../src/federated/ParallelSourcesMultiport.lf | 37 ++++----- test/C/src/federated/PhysicalSTP.lf | 28 +++---- test/C/src/federated/PingPongDistributed.lf | 40 +++++----- .../federated/PingPongDistributedPhysical.lf | 77 +++++++++++-------- test/C/src/federated/SimpleFederated.lf | 22 +++--- test/C/src/federated/StopAtShutdown.lf | 48 +++++------- test/C/src/federated/TopLevelArtifacts.lf | 46 +++++------ 19 files changed, 430 insertions(+), 370 deletions(-) diff --git a/test/C/src/federated/DistributedStopZeroDecentralized.lf b/test/C/src/federated/DistributedStopZeroDecentralized.lf index 801c39ec67..fe7a6e28cd 100644 --- a/test/C/src/federated/DistributedStopZeroDecentralized.lf +++ b/test/C/src/federated/DistributedStopZeroDecentralized.lf @@ -1,16 +1,16 @@ /** - * Test for lf_request_stop() in federated execution with decentralized coordination - * at tag (0,0). + * Test for lf_request_stop() in federated execution with decentralized + * coordination at tag (0,0). * * @author Soroush Bateni */ -target C; +target C import Sender, Receiver from "DistributedStopZero.lf" federated reactor { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedToken.lf b/test/C/src/federated/DistributedToken.lf index 89f9cecfba..7ea5fb16b3 100644 --- a/test/C/src/federated/DistributedToken.lf +++ b/test/C/src/federated/DistributedToken.lf @@ -1,41 +1,39 @@ /** - * Distributed LF program where a MessageGenerator creates a string - * message that is sent via the RTI (runtime infrastructure) to a - * receiver that prints the message. The type is char*, so this - * tests the transport of token-encapsulated messages. - * Three executable programs are generated, Distributed, - * Distributed_Sender, and Distributed_Receiver. - * The RTI is realized in the first of these and is identified - * as a "launcher," so it launches the other two programs. + * Distributed LF program where a MessageGenerator creates a string message that + * is sent via the RTI (runtime infrastructure) to a receiver that prints the + * message. The type is char*, so this tests the transport of token-encapsulated + * messages. Three executable programs are generated, Distributed, + * Distributed_Sender, and Distributed_Receiver. The RTI is realized in the + * first of these and is identified as a "launcher," so it launches the other + * two programs. * * This program uses a 'logical' connection -> with a STP violation handler, - * decentralized coordination, and an 'after' that is sufficiently - * large to get deterministic timestamps. Hence, it realizes a - * 'poor man's Ptides' that does not require clock synchronization - * nor HLA-style centralized control over the advancement of time. + * decentralized coordination, and an 'after' that is sufficiently large to get + * deterministic timestamps. Hence, it realizes a 'poor man's Ptides' that does + * not require clock synchronization nor HLA-style centralized control over the + * advancement of time. * * @author Edward A. Lee */ -target C { - timeout: 5 secs, - coordination: decentralized -}; +target C { timeout: 5 secs, coordination: decentralized } /** - * Reactor that generates a sequence of messages, one per second. - * The message will be a string consisting of a root string followed - * by a count. + * Reactor that generates a sequence of messages, one per second. The message + * will be a string consisting of a root string followed by a count. * @param root The root string. * @output message The message. */ -reactor MessageGenerator(root:string("")) { +reactor MessageGenerator(root: string("")) { // Output type char* instead of string is used for dynamically // allocated character arrays (as opposed to static constant strings). - output message:char*; - state count:int(1); - // Send first message after 1 sec so that the startup reactions - // do not factor into the transport time measurement on the first message. - timer t(1 sec, 1 sec); + output message: char* + + // Send first message after 1 sec so that the startup reactions do not + // factor into the transport time measurement on the first message. + timer t(1 sec, 1 sec) + + state count: int(1) + reaction(t) -> message {= // With NULL, 0 arguments, snprintf tells us how many bytes are needed. // Add one for the null terminator. @@ -57,8 +55,10 @@ reactor MessageGenerator(root:string("")) { * @input message The message. */ reactor PrintMessage { - input message:char*; - state count:int(0); + input message: char* + + state count: int(0) + reaction(message) {= printf("PrintMessage: At (elapsed) logical time %lld, receiver receives: %s\n", lf_time_logical_elapsed(), @@ -71,7 +71,7 @@ reactor PrintMessage { printf("ERROR: Expected message to be 'Hello World %d'.\n", self->count); exit(1); } - =} STP (0) {= + =} STP(0){= printf("PrintMessage: At (elapsed) tag (%lld, %u), receiver receives: %s\n" "Original intended tag was (%lld, %u).\n", lf_time_logical_elapsed(), @@ -87,6 +87,7 @@ reactor PrintMessage { exit(1); } =} + reaction(shutdown) {= if (self->count == 0) { printf("ERROR: No messages received.\n"); @@ -96,7 +97,8 @@ reactor PrintMessage { } federated reactor DistributedToken { - msg = new MessageGenerator(root = "Hello World"); - dsp = new PrintMessage(); - msg.message -> dsp.message after 40 msec; + msg = new MessageGenerator(root = "Hello World") + dsp = new PrintMessage() + + msg.message -> dsp.message after 40 msec } diff --git a/test/C/src/federated/FeedbackDelay.lf b/test/C/src/federated/FeedbackDelay.lf index 4e8324db12..5ec36f1e0c 100644 --- a/test/C/src/federated/FeedbackDelay.lf +++ b/test/C/src/federated/FeedbackDelay.lf @@ -1,39 +1,40 @@ -target C { - timeout: 1 sec, - logging: DEBUG -} +target C { timeout: 1 sec, logging: DEBUG } + reactor PhysicalPlant { - input control:double; - output sensor:double; - timer t(0, 33 msec); - state last_sensor_time:time(0); - state previous_sensor_time:time(0); + input control: double + + output sensor: double + + timer t(0, 33 msec) + + state last_sensor_time: time(0) + state previous_sensor_time: time(0) + reaction(t) -> sensor {= SET(sensor, 42); self->previous_sensor_time = self->last_sensor_time; self->last_sensor_time = get_physical_time(); =} + reaction(control) {= instant_t control_time = get_physical_time(); info_print("Latency %lld.", control_time - self->previous_sensor_time); info_print("Logical time: %lld.", get_elapsed_logical_time()); - =} STP(33 msec) {= - warning_print("STP violation."); - =} + =} STP(33 msec){= warning_print("STP violation."); =} } + reactor Controller { - input sensor:double; - output control:double; - - state latest_control:double(0.0); - state first:bool(true); - - output request_for_planning:double; - input planning:double; - - reaction(planning) {= - self->latest_control = planning->value; - =} + input sensor: double + input planning: double + + output control: double + output request_for_planning: double + + state latest_control: double(0.0) + state first: bool(true) + + reaction(planning) {= self->latest_control = planning->value; =} + reaction(sensor) -> control, request_for_planning {= if (!self->first) { SET(control, self->latest_control); @@ -42,21 +43,25 @@ reactor Controller { SET(request_for_planning, sensor->value); =} } + reactor Planner { - input request:double; - output response: double; + input request: double + + output response: double + reaction(request) -> response {= lf_nanosleep(MSEC(10)); SET(response, request->value); =} } + federated reactor { - p = new PhysicalPlant(); - c = new Controller(); - pl = new Planner(); - - p.sensor -> c.sensor; - c.request_for_planning -> pl.request; - pl.response -> c.planning after 0; - c.control -> p.control; + p = new PhysicalPlant() + c = new Controller() + pl = new Planner() + + p.sensor -> c.sensor + c.request_for_planning -> pl.request + pl.response -> c.planning after 0 + c.control -> p.control } diff --git a/test/C/src/federated/FeedbackDelaySimple.lf b/test/C/src/federated/FeedbackDelaySimple.lf index 1265b4ad67..2b51354b61 100644 --- a/test/C/src/federated/FeedbackDelaySimple.lf +++ b/test/C/src/federated/FeedbackDelaySimple.lf @@ -1,11 +1,14 @@ -target C { - timeout: 1 sec -} +target C { timeout: 1 sec } + reactor Loop { - input in:int; - output out:int; - timer t(0, 100 msec); - state count:int(1); + input in: int + + output out: int + + timer t(0, 100 msec) + + state count: int(1) + reaction(in) {= info_print("Received %d.", in->value); if (in->value != self->count) { @@ -17,9 +20,9 @@ reactor Loop { } self->count++; =} - reaction(t) -> out {= - SET(out, self->count); - =} + + reaction(t) -> out {= SET(out, self->count); =} + reaction(shutdown) {= if (self->count != 11) { error_print_and_exit( @@ -29,8 +32,9 @@ reactor Loop { } =} } + federated reactor { l = new Loop() - l.out -> l.in after 0; + l.out -> l.in after 0 } diff --git a/test/C/src/federated/HelloDistributed.lf b/test/C/src/federated/HelloDistributed.lf index 4bed5060b6..20e4a87441 100644 --- a/test/C/src/federated/HelloDistributed.lf +++ b/test/C/src/federated/HelloDistributed.lf @@ -1,25 +1,29 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee */ -target C; +target C reactor Source { - output out:string; + output out: string + reaction(startup) -> out {= lf_print("Sending 'Hello World!' message from source federate."); lf_set(out, "Hello World!"); lf_request_stop(); =} } + reactor Destination { - input in:string; - state received:bool(false); - reaction(startup) {= - lf_print("Destination started."); - =} + input in: string + + state received: bool(false) + + reaction(startup) {= lf_print("Destination started."); =} + reaction(in) {= lf_print("At logical time %lld, destination received: %s", lf_time_logical_elapsed(), in->value); if (strcmp(in->value, "Hello World!") != 0) { @@ -28,6 +32,7 @@ reactor Destination { } self->received = true; =} + reaction(shutdown) {= lf_print("Shutdown invoked."); if (!self->received) { @@ -37,10 +42,12 @@ reactor Destination { } federated reactor HelloDistributed at localhost { - reaction(startup) {= - lf_print("Printing something in top-level federated reactor."); - =} - s = new Source(); // Reactor s is in federate Source - d = new Destination(); // Reactor d is in federate Destination - s.out -> d.in; // This version preserves the timestamp. + s = new Source() // Reactor s is in federate Source + d = new Destination() // Reactor d is in federate Destination + + s.out ->d.in // This version preserves the timestamp. + + reaction( + startup + ) {= lf_print("Printing something in top-level federated reactor."); =} } diff --git a/test/C/src/federated/LoopDistributedCentralized.lf b/test/C/src/federated/LoopDistributedCentralized.lf index 557045f5ec..f9d50942c5 100644 --- a/test/C/src/federated/LoopDistributedCentralized.lf +++ b/test/C/src/federated/LoopDistributedCentralized.lf @@ -1,15 +1,16 @@ /** - * This tests a feedback loop with physical actions and - * centralized coordination. + * This tests a feedback loop with physical actions and centralized + * coordination. * * @author Edward A. Lee */ target C { flags: "-Wall", coordination: centralized, - coordination-options: {advance-message-interval: 100 msec}, + coordination-options: { advance-message-interval: 100 msec }, timeout: 5 sec } + preamble {= #include // Defines sleep() bool stop = false; @@ -21,30 +22,36 @@ preamble {= sleep(1); } return NULL; - } -=} - -reactor Looper(incr:int(1), delay:time(0 msec)) { - input in:int; - output out:int; - physical action a(delay); - state count:int(0); + }=} + +reactor Looper(incr: int(1), delay: time(0 msec)) { + input in: int + + output out: int + + physical action a(delay) + + state count: int(0) + reaction(startup) -> a {= // Start the thread that listens for Enter or Return. lf_thread_t thread_id; lf_print("Starting thread."); lf_thread_create(&thread_id, &ping, a); =} + reaction(a) -> out {= lf_set(out, self->count); self->count += self->incr; =} + reaction(in) {= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, time_lag); lf_print("Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); =} + reaction(shutdown) {= lf_print("******* Shutdown invoked."); // Stop the thread that is scheduling actions. @@ -54,9 +61,11 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { } =} } -federated reactor LoopDistributedCentralized(delay:time(0)) { - left = new Looper(); - right = new Looper(incr = -1); - left.out -> right.in; - right.out -> left.in; + +federated reactor LoopDistributedCentralized(delay: time(0)) { + left = new Looper() + right = new Looper(incr = -1) + + left.out ->right.in + right.out ->left.in } diff --git a/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf b/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf index 3ce7dde49a..7346a216e5 100644 --- a/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf +++ b/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf @@ -1,6 +1,6 @@ /** - * This tests that the precedence order of reaction invocation is kept - * when a feedback loop is present in centralized coordination. + * This tests that the precedence order of reaction invocation is kept when a + * feedback loop is present in centralized coordination. * * @author Edward A. Lee * @author Soroush Bateni @@ -8,20 +8,25 @@ target C { flags: "-Wall", coordination: centralized, - coordination-options: {advance-message-interval: 100 msec}, + coordination-options: { advance-message-interval: 100 msec }, timeout: 5 sec } -reactor Looper(incr:int(1), delay:time(0 msec)) { - input in:int; - output out:int; - state count:int(0); - state received_count:int(0); - timer t(0, 1 sec); +reactor Looper(incr: int(1), delay: time(0 msec)) { + input in: int + + output out: int + + timer t(0, 1 sec) + + state count: int(0) + state received_count: int(0) + reaction(t) -> out {= lf_set(out, self->count); self->count += self->incr; =} + reaction(in) {= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 @@ -29,11 +34,13 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { lf_print("Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); self->received_count = self->count; =} + reaction(t) {= if (self->received_count != self->count) { lf_print_error_and_exit("reaction(t) was invoked before reaction(in). Precedence order was not kept."); } =} + reaction(shutdown) {= lf_print("******* Shutdown invoked."); if (self->count != 6 * self->incr) { @@ -41,9 +48,11 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { } =} } -federated reactor (delay:time(0)) { - left = new Looper(); - right = new Looper(incr = -1); - left.out -> right.in; - right.out -> left.in; + +federated reactor(delay: time(0)) { + left = new Looper() + right = new Looper(incr = -1) + + left.out ->right.in + right.out ->left.in } diff --git a/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf b/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf index 92fb61de9c..1077ac72ed 100644 --- a/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf +++ b/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf @@ -1,6 +1,7 @@ /** - * This tests that the precedence order of reaction invocation is kept - * in the hierarchy of reactors when a feedback loop is present in centralized coordination. + * This tests that the precedence order of reaction invocation is kept in the + * hierarchy of reactors when a feedback loop is present in centralized + * coordination. * * @author Edward A. Lee * @author Soroush Bateni @@ -8,21 +9,22 @@ target C { flags: "-Wall", coordination: centralized, - coordination-options: {advance-message-interval: 100 msec}, + coordination-options: { advance-message-interval: 100 msec }, timeout: 5 sec } -reactor Contained (incr:int(1)) { - timer t(0, 1 sec); - input in:int; - state count:int(0); - state received_count:int(0); - reaction(t) {= - self->count += self->incr; - =} - reaction(in) {= - self->received_count = self->count; - =} +reactor Contained(incr: int(1)) { + input in: int + + timer t(0, 1 sec) + + state count: int(0) + state received_count: int(0) + + reaction(t) {= self->count += self->incr; =} + + reaction(in) {= self->received_count = self->count; =} + reaction(t) {= if (self->received_count != self->count) { lf_print_error_and_exit("reaction(t) was invoked before reaction(in). Precedence order was not kept."); @@ -30,26 +32,32 @@ reactor Contained (incr:int(1)) { =} } -reactor Looper(incr:int(1), delay:time(0 msec)) { - input in:int; - output out:int; - state count:int(0); - timer t(0, 1 sec); +reactor Looper(incr: int(1), delay: time(0 msec)) { + input in: int + + output out: int + + timer t(0, 1 sec) + + c = new Contained(incr = incr) + + in ->c.in - c = new Contained(incr = incr); + state count: int(0) reaction(t) -> out {= lf_print("Sending network output %d", self->count); lf_set(out, self->count); self->count += self->incr; =} + reaction(in) {= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, time_lag); lf_print("Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); =} - in->c.in; + reaction(shutdown) {= lf_print("******* Shutdown invoked."); if (self->count != 6 * self->incr) { @@ -57,9 +65,11 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { } =} } -federated reactor (delay:time(0)) { - left = new Looper(); - right = new Looper(incr = -1); - left.out -> right.in; - right.out -> left.in; + +federated reactor(delay: time(0)) { + left = new Looper() + right = new Looper(incr = -1) + + left.out ->right.in + right.out ->left.in } diff --git a/test/C/src/federated/LoopDistributedDecentralized.lf b/test/C/src/federated/LoopDistributedDecentralized.lf index 7983f514e7..48f85a7e19 100644 --- a/test/C/src/federated/LoopDistributedDecentralized.lf +++ b/test/C/src/federated/LoopDistributedDecentralized.lf @@ -1,13 +1,11 @@ /** - * This tests a feedback loop with physical actions and - * decentralized coordination. + * This tests a feedback loop with physical actions and decentralized + * coordination. * * @author Edward A. Lee */ -target C { - coordination: decentralized, - timeout: 5 sec -} +target C { coordination: decentralized, timeout: 5 sec } + preamble {= #include // Defines sleep() bool stop = false; @@ -22,38 +20,45 @@ preamble {= } =} -reactor Looper(incr:int(1), delay:time(0 msec), stp_offset:time(0)) { - input in:int; - output out:int; - physical action a(stp_offset); - state count:int(0); +reactor Looper(incr: int(1), delay: time(0 msec), stp_offset: time(0)) { + input in: int + + output out: int + + physical action a(stp_offset) + + state count: int(0) + reaction(startup) -> a {= // Start the thread that listens for Enter or Return. lf_thread_t thread_id; lf_print("Starting thread."); lf_thread_create(&thread_id, &ping, a); =} + reaction(a) -> out {= lf_print("Setting out."); lf_set(out, self->count); self->count += self->incr; =} + reaction(in) {= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, time_lag); lf_print("Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); - =} STP (stp_offset) {= + =} STP(stp_offset){= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, time_lag); lf_print("STP offset was violated. Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); - =} deadline (10 msec) {= + =} deadline(10 msec) {= instant_t time_lag = lf_time_physical() - lf_time_logical(); char time_buffer[28]; // 28 bytes is enough for the largest 64 bit number: 9,223,372,036,854,775,807 lf_comma_separated_time(time_buffer, time_lag); lf_print("Deadline miss. Received %d. Logical time is behind physical time by %s nsec.", in->value, time_buffer); =} + reaction(shutdown) {= lf_print("******* Shutdown invoked."); // Stop the thread that is scheduling actions. @@ -63,9 +68,11 @@ reactor Looper(incr:int(1), delay:time(0 msec), stp_offset:time(0)) { } =} } -federated reactor LoopDistributedDecentralized(delay:time(0)) { - left = new Looper(stp_offset = 900 usec); - right = new Looper(incr = -1, stp_offset = 2400 usec); - left.out -> right.in; - right.out -> left.in; + +federated reactor LoopDistributedDecentralized(delay: time(0)) { + left = new Looper(stp_offset = 900 usec) + right = new Looper(incr = -1, stp_offset = 2400 usec) + + left.out ->right.in + right.out ->left.in } diff --git a/test/C/src/federated/LoopDistributedDouble.lf b/test/C/src/federated/LoopDistributedDouble.lf index 9c55a5cb96..3e203efe16 100644 --- a/test/C/src/federated/LoopDistributedDouble.lf +++ b/test/C/src/federated/LoopDistributedDouble.lf @@ -1,15 +1,16 @@ /** - * This tests a feedback loop with physical actions and - * centralized coordination. + * This tests a feedback loop with physical actions and centralized + * coordination. * * @author Edward A. Lee */ target C { flags: "-Wall", coordination: centralized, - coordination-options: {advance-message-interval: 100 msec}, + coordination-options: { advance-message-interval: 100 msec }, timeout: 5 sec } + preamble {= #include // Defines sleep() bool stop = false; @@ -21,23 +22,28 @@ preamble {= sleep(1); } return NULL; - } -=} + }=} + +reactor Looper(incr: int(1), delay: time(0 msec)) { + input in: int + input in2: int + + output out: int + output out2: int + + timer t(0, 1 sec) + + physical action a(delay) + + state count: int(0) -reactor Looper(incr:int(1), delay:time(0 msec)) { - input in:int; - input in2:int; - output out:int; - output out2:int; - physical action a(delay); - state count:int(0); - timer t(0, 1 sec); reaction(startup) -> a {= // Start the thread that listens for Enter or Return. lf_thread_t thread_id; lf_print("Starting thread."); lf_thread_create(&thread_id, &ping, a); =} + reaction(a) -> out, out2 {= if (self->count%2 == 0) { lf_set(out, self->count); @@ -46,23 +52,27 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { } self->count += self->incr; =} + reaction(in) {= lf_print("Received %d at logical time (%lld, %d).", in->value, current_tag.time - start_time, current_tag.microstep ); =} + reaction(in2) {= lf_print("Received %d on in2 at logical time (%lld, %d).", in2->value, current_tag.time - start_time, current_tag.microstep ); =} + reaction(t) {= lf_print("Timer triggered at logical time (%lld, %d).", current_tag.time - start_time, current_tag.microstep ); =} + reaction(shutdown) {= lf_print("******* Shutdown invoked."); // Stop the thread that is scheduling actions. @@ -72,11 +82,13 @@ reactor Looper(incr:int(1), delay:time(0 msec)) { } =} } -federated reactor (delay:time(0)) { - left = new Looper(); - right = new Looper(incr = -1); - left.out -> right.in; - right.out -> left.in; - right.out2 -> left.in2; - left.out2 -> right.in2; + +federated reactor(delay: time(0)) { + left = new Looper() + right = new Looper(incr = -1) + + left.out ->right.in + right.out ->left.in + right.out2 ->left.in2 + left.out2 ->right.in2 } diff --git a/test/C/src/federated/ParallelDestinations.lf b/test/C/src/federated/ParallelDestinations.lf index 072980eb50..fbc90b1266 100644 --- a/test/C/src/federated/ParallelDestinations.lf +++ b/test/C/src/federated/ParallelDestinations.lf @@ -1,25 +1,22 @@ -/** - * Test parallel connections for federated execution. - */ -target C { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target C { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Source { - output[2] out:int; - c1 = new Count(); - c2 = new Count(); + output[2] out: int + + c1 = new Count() + c2 = new Count() - c1.out, c2.out -> out; + c1.out, c2.out ->out } federated reactor { - s = new Source(); - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); + s = new Source() + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) - s.out -> t1.in, t2.in; + s.out ->t1.in, t2.in } diff --git a/test/C/src/federated/ParallelSources.lf b/test/C/src/federated/ParallelSources.lf index 6b22cc422d..03d71a1179 100644 --- a/test/C/src/federated/ParallelSources.lf +++ b/test/C/src/federated/ParallelSources.lf @@ -1,26 +1,22 @@ -/** - * Test parallel connections for federated execution. - */ -target C { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target C { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Destination { - input[2] in:int; + input[2] in: int - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) - in -> t1.in, t2.in; + in ->t1.in, t2.in } federated reactor { - c1 = new Count(); - c2 = new Count(); - d = new Destination(); + c1 = new Count() + c2 = new Count() + d = new Destination() - c1.out, c2.out -> d.in; + c1.out, c2.out ->d.in } diff --git a/test/C/src/federated/ParallelSourcesMultiport.lf b/test/C/src/federated/ParallelSourcesMultiport.lf index d3f3a8ae1c..0b49ad9b53 100644 --- a/test/C/src/federated/ParallelSourcesMultiport.lf +++ b/test/C/src/federated/ParallelSourcesMultiport.lf @@ -1,36 +1,33 @@ -/** - * Test parallel connections for federated execution. - */ -target C { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target C { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Source { - output[2] out:int; - c1 = new Count(); - c2 = new Count(); + output[2] out: int + + c1 = new Count() + c2 = new Count() - c1.out, c2.out -> out; + c1.out, c2.out ->out } reactor Destination1 { - input[3] in:int; + input[3] in: int - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); - t3 = new TestCount(num_inputs = 3); + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) + t3 = new TestCount(num_inputs = 3) - in -> t1.in, t2.in, t3.in; + in ->t1.in, t2.in, t3.in } federated reactor { - s1 = new Source(); - s2 = new Source(); - d1 = new Destination1(); - t4 = new TestCount(num_inputs = 3); + s1 = new Source() + s2 = new Source() + d1 = new Destination1() + t4 = new TestCount(num_inputs = 3) - s1.out, s2.out -> d1.in, t4.in; + s1.out, s2.out ->d1.in, t4.in } diff --git a/test/C/src/federated/PhysicalSTP.lf b/test/C/src/federated/PhysicalSTP.lf index 571f1b4aa3..27af23073e 100644 --- a/test/C/src/federated/PhysicalSTP.lf +++ b/test/C/src/federated/PhysicalSTP.lf @@ -1,17 +1,16 @@ /** - * This is a test that detects STP violations according to the - * physical time of message arrival. + * This is a test that detects STP violations according to the physical time of + * message arrival. */ -target C { - timeout: 1900 msec, - coordination: decentralized -}; +target C { timeout: 1900 msec, coordination: decentralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" + +reactor Print(STP_offset_param: time(0)) { + input in: int + + state c: int(1) -reactor Print (STP_offset_param:time(0)) { - input in:int; - state c:int(1); reaction(in) {= interval_t elapsed_time = lf_time_logical_elapsed(); lf_print("At time %lld, received %d", elapsed_time, in->value); @@ -26,11 +25,12 @@ reactor Print (STP_offset_param:time(0)) { } else { lf_print_error_and_exit("Message arrived %lld early.", STP_discrepency); } - =} STP (STP_offset_param) {= + =} STP(STP_offset_param){= // This STP handler should never be invoked because the only source of event // for Print is the Count reactor. lf_print_error_and_exit("Logical STP violation was detected. Only physical STP violations are possible."); =} + reaction(shutdown) {= if (self->c != 3) { lf_print_error_and_exit("Expected to receive 2 items but got %d.", self->c); @@ -39,8 +39,8 @@ reactor Print (STP_offset_param:time(0)) { } federated reactor { - c = new Count(offset = 1 msec, period = 1 sec); - p = new Print(STP_offset_param = 1 usec); + c = new Count(offset = 1 msec, period = 1 sec) + p = new Print(STP_offset_param = 1 usec) - c.out -> p.in; + c.out ->p.in } diff --git a/test/C/src/federated/PingPongDistributed.lf b/test/C/src/federated/PingPongDistributed.lf index 4ad2e4fca5..7633f1bc9f 100644 --- a/test/C/src/federated/PingPongDistributed.lf +++ b/test/C/src/federated/PingPongDistributed.lf @@ -1,28 +1,32 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. * - * This version is distributed, communicating using logical - * connections over sockets. + * This version is distributed, communicating using logical connections over + * sockets. * - * See [Benchmarks wiki page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). - - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * See [Benchmarks wiki + * page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). + * + * This is based on https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * This is a distributed version, where Ping and Pong run in - * separate programs and can be run on different machines. + * This is a distributed version, where Ping and Pong run in separate programs + * and can be run on different machines. * - * There is no parallelism in this application, so it does not benefit from being - * being distributed. + * There is no parallelism in this application, so it does not benefit from + * being being distributed. * * @author Edward A. Lee */ -target C; +target C + import Ping, Pong from "PingPongDistributedPhysical.lf" -federated reactor(count:int(10)) { - ping = new Ping(count = count); - pong = new Pong(expected = count); - ping.send -> pong.receive; - pong.send -> ping.receive; + +federated reactor(count: int(10)) { + ping = new Ping(count = count) + pong = new Pong(expected = count) + + ping.send ->pong.receive + pong.send ->ping.receive } diff --git a/test/C/src/federated/PingPongDistributedPhysical.lf b/test/C/src/federated/PingPongDistributedPhysical.lf index 73a0931480..96c6f32f7c 100644 --- a/test/C/src/federated/PingPongDistributedPhysical.lf +++ b/test/C/src/federated/PingPongDistributedPhysical.lf @@ -1,43 +1,45 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. * - * This version is distributed, communicating using physical - * connections over sockets. + * This version is distributed, communicating using physical connections over + * sockets. * - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * This is based on https://www.scala-lang.org/old/node/54. See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * This is a distributed version, where Ping and Pong run in - * separate programs and can be run on different machines. + * This is a distributed version, where Ping and Pong run in separate programs + * and can be run on different machines. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec - * Distributed: 53 seconds + * Unthreaded: 97 msec Threaded: 265 msec Distributed: 53 seconds * - * There is no parallelism in this application, so it does not benefit from being - * being distributed. + * There is no parallelism in this application, so it does not benefit from + * being being distributed. * - * These measurements are total execution time, including startup and shutdown, of - * all three programs. + * These measurements are total execution time, including startup and shutdown, + * of all three programs. * * @author Edward A. Lee */ -target C; +target C -reactor Ping(count:int(10)) { - input receive:int; - output send:int; - state pingsLeft:int(count); - logical action serve; - reaction (startup, serve) -> send {= +reactor Ping(count: int(10)) { + input receive: int + + output send: int + + logical action serve + + state pingsLeft: int(count) + + reaction(startup, serve) -> send {= printf("At logical time %lld, Ping sending %d.\n", lf_time_logical_elapsed(), self->pingsLeft); lf_set(send, self->pingsLeft--); =} - reaction (receive) -> serve {= + + reaction(receive) -> serve {= if (self->pingsLeft > 0) { lf_schedule(serve, 0); } else { @@ -45,10 +47,14 @@ reactor Ping(count:int(10)) { } =} } -reactor Pong(expected:int(10)) { - input receive:int; - output send:int; - state count:int(0); + +reactor Pong(expected: int(10)) { + input receive: int + + output send: int + + state count: int(0) + reaction(receive) -> send {= self->count++; printf("At logical time %lld, Pong received %d.\n", lf_time_logical_elapsed(), receive->value); @@ -57,6 +63,7 @@ reactor Pong(expected:int(10)) { lf_request_stop(); } =} + reaction(shutdown) {= if (self->count != self->expected) { fprintf(stderr, "Pong expected to receive %d inputs, but it received %d.\n", @@ -67,9 +74,11 @@ reactor Pong(expected:int(10)) { printf("Pong received %d pings.\n", self->count); =} } -federated reactor (count:int(10)) { - ping = new Ping(count = count); - pong = new Pong(expected = count); - ping.send ~> pong.receive; - pong.send ~> ping.receive; + +federated reactor(count: int(10)) { + ping = new Ping(count = count) + pong = new Pong(expected = count) + + ping.send ~> pong.receive + pong.send ~> ping.receive } diff --git a/test/C/src/federated/SimpleFederated.lf b/test/C/src/federated/SimpleFederated.lf index 4ccc78eb9e..78d539c900 100644 --- a/test/C/src/federated/SimpleFederated.lf +++ b/test/C/src/federated/SimpleFederated.lf @@ -1,15 +1,15 @@ -target C { - timeout: 2 secs, - build-type: RelWithDebInfo -}; +target C { timeout: 2 secs, build-type: RelWithDebInfo } + reactor Fed { - input in:int; - output out:int; + input in: int + + output out: int } + federated reactor { - fed1 = new Fed(); - fed2 = new Fed(); - - fed1.out -> fed2.in; - fed2.out -> fed1.in; + fed1 = new Fed() + fed2 = new Fed() + + fed1.out ->fed2.in + fed2.out ->fed1.in } diff --git a/test/C/src/federated/StopAtShutdown.lf b/test/C/src/federated/StopAtShutdown.lf index f17ed81a03..fb86a4d0cc 100644 --- a/test/C/src/federated/StopAtShutdown.lf +++ b/test/C/src/federated/StopAtShutdown.lf @@ -1,43 +1,35 @@ /** - * Check that lf_request_stop() doesn't cause - * any issues at the shutdown tag. + * Check that lf_request_stop() doesn't cause any issues at the shutdown tag. * * Original bug discovered by Steven Wong * * @author Steven Wong */ -target C { - timeout: 2 sec -} +target C { timeout: 2 sec } reactor A { - input in:int; - reaction(startup) {= - lf_print("Hello World!"); - =} - - reaction(in) {= - lf_print("Got it"); - =} - - reaction(shutdown) {= - lf_request_stop(); - =} + input in: int + + reaction(startup) {= lf_print("Hello World!"); =} + + reaction(in) {= lf_print("Got it"); =} + + reaction(shutdown) {= lf_request_stop(); =} } reactor B { - output out:int; - timer t(1 sec); - reaction(t) -> out {= - lf_set(out, 1); - =} - reaction(shutdown) {= - lf_request_stop(); - =} + output out: int + + timer t(1 sec) + + reaction(t) -> out {= lf_set(out, 1); =} + + reaction(shutdown) {= lf_request_stop(); =} } federated reactor { - a = new A(); - b = new B(); - b.out -> a.in; + a = new A() + b = new B() + + b.out ->a.in } diff --git a/test/C/src/federated/TopLevelArtifacts.lf b/test/C/src/federated/TopLevelArtifacts.lf index 1c830ffaa6..1b37a9a5ca 100644 --- a/test/C/src/federated/TopLevelArtifacts.lf +++ b/test/C/src/federated/TopLevelArtifacts.lf @@ -1,39 +1,39 @@ /** - * Test whether top-level reactions, actions, and ports are handled appropriately. + * Test whether top-level reactions, actions, and ports are handled + * appropriately. * * Currently, these artifacts are replicated on all federates. * - * @note This just tests for the correctness of the code generation. These top-level - * artifacts might be disallowed in the future. + * @note This just tests for the correctness of the code generation. These + * top-level artifacts might be disallowed in the future. */ +target C { timeout: 1 msec } -target C { - timeout: 1 msec -}; +import Count from "../lib/Count.lf" +import TestCount from "../lib/TestCount.lf" - import Count from "../lib/Count.lf"; - import TestCount from "../lib/TestCount.lf"; +federated reactor { + timer t(0, 1 sec) - federated reactor { - state successes:int(0); - reaction (startup) {= - self->successes++; - =} - timer t(0, 1 sec); - reaction (t) -> act {= + logical action act(0) + + c = new Count() + tc = new TestCount() + + c.out ->tc.in + + state successes: int(0) + + reaction(startup) {= self->successes++; =} + + reaction(t) -> act {= self->successes++; lf_schedule(act, 0); =} - logical action act(0); - reaction (act) {= - self->successes++; - =} - c = new Count(); - tc = new TestCount(); - c.out -> tc.in; + reaction(act) {= self->successes++; =} - reaction (shutdown) {= + reaction(shutdown) {= if (self->successes != 3) { lf_print_error_and_exit("Failed to properly execute top-level reactions"); } From 331be614505b6c69a7bc12fec9318ddad35ead29 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 01:45:58 -0700 Subject: [PATCH 074/130] [formatting] Format C tests lib dir. --- test/C/src/lib/Count.lf | 18 +++++++++------- test/C/src/lib/Imported.lf | 14 +++++++------ test/C/src/lib/ImportedAgain.lf | 5 +++-- test/C/src/lib/ImportedComposition.lf | 30 +++++++++++++++------------ test/C/src/lib/InternalDelay.lf | 25 +++++++++++----------- test/C/src/lib/LoopedActionSender.lf | 24 +++++++++++---------- test/C/src/lib/PassThrough.lf | 16 +++++++------- test/C/src/lib/Test.lf | 11 ++++++---- test/C/src/lib/TestCount.lf | 14 ++++++++----- test/C/src/lib/TestCountMultiport.lf | 27 ++++++++++++++++-------- 10 files changed, 104 insertions(+), 80 deletions(-) diff --git a/test/C/src/lib/Count.lf b/test/C/src/lib/Count.lf index 2527df63ff..371bce8a81 100644 --- a/test/C/src/lib/Count.lf +++ b/test/C/src/lib/Count.lf @@ -1,9 +1,11 @@ -target C; -reactor Count(offset:time(0), period:time(1 sec)) { - state count:int(1); - output out:int; - timer t(offset, period); - reaction(t) -> out {= - lf_set(out, self->count++); - =} +target C + +reactor Count(offset: time(0), period: time(1 sec)) { + output out: int + + timer t(offset, period) + + state count: int(1) + + reaction(t) -> out {= lf_set(out, self->count++); =} } diff --git a/test/C/src/lib/Imported.lf b/test/C/src/lib/Imported.lf index 02a0534cc3..a59faefe42 100644 --- a/test/C/src/lib/Imported.lf +++ b/test/C/src/lib/Imported.lf @@ -1,11 +1,13 @@ // This is used by the test for the ability to import a reactor definition // that itself imports a reactor definition. -target C; +target C + import ImportedAgain from "./ImportedAgain.lf" + reactor Imported { - input x:int; - a = new ImportedAgain(); - reaction(x) -> a.x {= - lf_set(a.x, x->value); - =} + input x: int + + a = new ImportedAgain() + + reaction(x) -> a.x {= lf_set(a.x, x->value); =} } diff --git a/test/C/src/lib/ImportedAgain.lf b/test/C/src/lib/ImportedAgain.lf index 7f0be2bf4c..93e148c642 100644 --- a/test/C/src/lib/ImportedAgain.lf +++ b/test/C/src/lib/ImportedAgain.lf @@ -1,9 +1,10 @@ // This is used by the test for the ability to import a reactor definition // that itself imports a reactor definition. -target C; +target C reactor ImportedAgain { - input x:int; + input x: int + reaction(x) {= printf("Received: %d.\n", x->value); if (x->value != 42) { diff --git a/test/C/src/lib/ImportedComposition.lf b/test/C/src/lib/ImportedComposition.lf index 1caef740d6..cc8008b720 100644 --- a/test/C/src/lib/ImportedComposition.lf +++ b/test/C/src/lib/ImportedComposition.lf @@ -1,20 +1,24 @@ // This is used by the test for the ability to import a reactor definition // that itself imports a reactor definition. -target C; +target C reactor Gain { - input x:int; - output y:int; - reaction(x) -> y {= - lf_set(y, x->value * 2); - =} + input x: int + + output y: int + + reaction(x) -> y {= lf_set(y, x->value * 2); =} } + reactor ImportedComposition { - input x:int; - output y:int; - g1 = new Gain(); - g2 = new Gain(); - x -> g1.x after 10 msec; - g1.y -> g2.x after 30 msec; - g2.y -> y after 15 msec; + input x: int + + output y: int + + g1 = new Gain() + g2 = new Gain() + + x ->g1.x after 10 msec + g1.y ->g2.x after 30 msec + g2.y ->y after 15 msec } diff --git a/test/C/src/lib/InternalDelay.lf b/test/C/src/lib/InternalDelay.lf index 8571bddc16..d5b1e62f20 100644 --- a/test/C/src/lib/InternalDelay.lf +++ b/test/C/src/lib/InternalDelay.lf @@ -1,14 +1,13 @@ -target C; -reactor InternalDelay ( - delay:int(10 msec) -) { - input in:int; - output out:int; - logical action d:int; - reaction(in) -> d {= - lf_schedule_int(d, self->delay, in->value); - =} - reaction(d) -> out {= - lf_set(out, d->value); - =} +target C + +reactor InternalDelay(delay: int(10 msec)) { + input in: int + + output out: int + + logical action d: int + + reaction(in) -> d {= lf_schedule_int(d, self->delay, in->value); =} + + reaction(d) -> out {= lf_set(out, d->value); =} } diff --git a/test/C/src/lib/LoopedActionSender.lf b/test/C/src/lib/LoopedActionSender.lf index abdd2fcfd6..097816b4f3 100644 --- a/test/C/src/lib/LoopedActionSender.lf +++ b/test/C/src/lib/LoopedActionSender.lf @@ -1,21 +1,23 @@ /** - * A sender reactor that outputs integers - * in superdense time. + * A sender reactor that outputs integers in superdense time. * * @author Soroush Bateni */ -target C; +target C /** - * @param take_a_break_after: Indicates how many messages are sent - * in consecutive superdense time - * @param break_interval: Determines how long the reactor should take - * a break after sending take_a_break_after messages. + * @param take_a_break_after: Indicates how many messages are sent in + * consecutive superdense time + * @param break_interval: Determines how long the reactor should take a break + * after sending take_a_break_after messages. */ -reactor Sender(take_a_break_after:int(10), break_interval:time(400 msec)) { - output out:int; - logical action act; - state sent_messages:int(0); +reactor Sender(take_a_break_after: int(10), break_interval: time(400 msec)) { + output out: int + + logical action act + + state sent_messages: int(0) + reaction(startup, act) -> act, out {= // Send a message on out /* printf("At tag (%lld, %u) sending value %d.\n", diff --git a/test/C/src/lib/PassThrough.lf b/test/C/src/lib/PassThrough.lf index 8add840b79..4ea33d9a92 100644 --- a/test/C/src/lib/PassThrough.lf +++ b/test/C/src/lib/PassThrough.lf @@ -1,12 +1,10 @@ -/** - * Forward the integer input on `in` to the output port `out`. - */ -target C; +/** Forward the integer input on `in` to the output port `out`. */ +target C reactor PassThrough { - input in:int; - output out:int; - reaction(in) -> out {= - SET(out, in->value); - =} + input in: int + + output out: int + + reaction(in) -> out {= SET(out, in->value); =} } diff --git a/test/C/src/lib/Test.lf b/test/C/src/lib/Test.lf index f4c573f009..0b461d2118 100644 --- a/test/C/src/lib/Test.lf +++ b/test/C/src/lib/Test.lf @@ -1,7 +1,10 @@ -target C; -reactor TestDouble(expected:double[](1.0, 1.0, 1.0, 1.0)) { - input in:double; - state count:int(0); +target C + +reactor TestDouble(expected: double[](1.0, 1.0, 1.0, 1.0)) { + input in: double + + state count: int(0) + reaction(in) {= printf("Received: %f\n", in->value); if (in->value != self->expected[self->count]) { diff --git a/test/C/src/lib/TestCount.lf b/test/C/src/lib/TestCount.lf index 7580494f05..9299871d37 100644 --- a/test/C/src/lib/TestCount.lf +++ b/test/C/src/lib/TestCount.lf @@ -7,11 +7,14 @@ * @param stride The increment for the inputs. Default is 1. * @param num_inputs The number of inputs expected. Default is 1. */ -target C; -reactor TestCount(start:int(1), stride:int(1), num_inputs:int(1)) { - state count:int(start); - state inputs_received:int(0); - input in:int; +target C + +reactor TestCount(start: int(1), stride: int(1), num_inputs: int(1)) { + input in: int + + state count: int(start) + state inputs_received: int(0) + reaction(in) {= lf_print("Received %d.", in->value); if (in->value != self->count) { @@ -20,6 +23,7 @@ reactor TestCount(start:int(1), stride:int(1), num_inputs:int(1)) { self->count += self->stride; self->inputs_received++; =} + reaction(shutdown) {= lf_print("Shutdown invoked."); if (self->inputs_received != self->num_inputs) { diff --git a/test/C/src/lib/TestCountMultiport.lf b/test/C/src/lib/TestCountMultiport.lf index 60d1fee312..1a4e83306a 100644 --- a/test/C/src/lib/TestCountMultiport.lf +++ b/test/C/src/lib/TestCountMultiport.lf @@ -1,19 +1,27 @@ /** * Test that a counting sequence of inputs starts with the specified start * parameter value, increments by the specified stride, and receives the - * specified number of inputs. This version has a multiport input, and - * each input is expected to be present and incremented over the previous - * input. + * specified number of inputs. This version has a multiport input, and each + * input is expected to be present and incremented over the previous input. * * @param start The starting value for the expected inputs. Default is 1. * @param stride The increment for the inputs. Default is 1. - * @param num_inputs The number of inputs expected on each channel. Default is 1. + * @param num_inputs The number of inputs expected on each channel. Default is + * 1. */ -target C; -reactor TestCountMultiport(start:int(1), stride:int(1), num_inputs:int(1), width:int(2)) { - state count:int(start); - state inputs_received:int(0); - input[width] in:int; +target C + +reactor TestCountMultiport( + start: int(1), + stride: int(1), + num_inputs: int(1), + width: int(2) +) { + input[width] in: int + + state count: int(start) + state inputs_received: int(0) + reaction(in) {= for (int i = 0; i < in_width; i++) { if (!in[i]->is_present) { @@ -27,6 +35,7 @@ reactor TestCountMultiport(start:int(1), stride:int(1), num_inputs:int(1), width } self->inputs_received++; =} + reaction(shutdown) {= lf_print("Shutdown invoked."); if (self->inputs_received != self->num_inputs) { From 2cc2eeb7e912527d5d46adeaf03dcfbde3f2ac35 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 02:20:06 -0700 Subject: [PATCH 075/130] [formatting] Format multiport, serialization tests. --- org.lflang/src/org/lflang/ast/ToLf.java | 2 +- test/C/src/multiport/BankGangedConnections.lf | 38 ++++++----- test/C/src/multiport/BankIndexInitializer.lf | 42 ++++++------ test/C/src/multiport/BankMulticast.lf | 36 +++++----- .../src/multiport/BankMultiportToReaction.lf | 25 +++---- .../src/multiport/BankReactionsInContainer.lf | 24 ++++--- test/C/src/multiport/BankSelfBroadcast.lf | 35 +++++----- test/C/src/multiport/BankToBank.lf | 40 +++++------ test/C/src/multiport/BankToBankMultiport.lf | 37 ++++++---- .../src/multiport/BankToBankMultiportAfter.lf | 37 ++++++---- test/C/src/multiport/BankToMultiport.lf | 31 ++++----- test/C/src/multiport/BankToReaction.lf | 12 ++-- test/C/src/multiport/Broadcast.lf | 27 ++++---- test/C/src/multiport/BroadcastAfter.lf | 27 ++++---- .../C/src/multiport/BroadcastMultipleAfter.lf | 33 +++++---- test/C/src/multiport/FullyConnected.lf | 27 ++++---- .../multiport/FullyConnectedAddressable.lf | 30 ++++---- .../FullyConnectedAddressableAfter.lf | 11 ++- test/C/src/multiport/MultiportFromBank.lf | 43 ++++++------ .../multiport/MultiportFromBankHierarchy.lf | 29 ++++---- .../MultiportFromBankHierarchyAfter.lf | 17 +++-- .../C/src/multiport/MultiportFromHierarchy.lf | 60 +++++++++------- test/C/src/multiport/MultiportFromReaction.lf | 27 +++++--- test/C/src/multiport/MultiportIn.lf | 60 ++++++++-------- .../src/multiport/MultiportInParameterized.lf | 68 ++++++++++--------- test/C/src/multiport/MultiportMutableInput.lf | 42 +++++++----- .../multiport/MultiportMutableInputArray.lf | 41 ++++++----- test/C/src/multiport/MultiportOut.lf | 47 +++++++------ test/C/src/multiport/MultiportToBank.lf | 49 +++++++------ test/C/src/multiport/MultiportToBankAfter.lf | 35 +++++----- test/C/src/multiport/MultiportToBankDouble.lf | 46 +++++++------ .../src/multiport/MultiportToBankHierarchy.lf | 47 +++++++------ test/C/src/multiport/MultiportToHierarchy.lf | 52 ++++++++------ test/C/src/multiport/MultiportToMultiport.lf | 37 ++++++---- test/C/src/multiport/MultiportToMultiport2.lf | 34 ++++++---- .../multiport/MultiportToMultiport2After.lf | 28 ++++---- .../multiport/MultiportToMultiportArray.lf | 33 +++++---- .../MultiportToMultiportParameter.lf | 37 ++++++---- test/C/src/multiport/MultiportToPort.lf | 32 +++++---- test/C/src/multiport/NestedBanks.lf | 63 ++++++++++------- .../C/src/multiport/NestedInterleavedBanks.lf | 31 ++++++--- test/C/src/multiport/PipelineAfter.lf | 30 ++++---- .../src/multiport/ReactionToContainedBank.lf | 17 +++-- .../src/multiport/ReactionToContainedBank2.lf | 23 +++---- .../ReactionToContainedBankMultiport.lf | 21 +++--- test/C/src/multiport/ReactionsToNested.lf | 40 +++++------ .../TriggerDownstreamOnlyIfPresent.lf | 36 ++++++---- .../serialization/PersonProtocolBuffers.lf | 33 +++++---- test/C/src/serialization/ProtoNoPacking.lf | 48 +++++++------ .../serialization/ROSBuiltInSerialization.lf | 2 +- 50 files changed, 941 insertions(+), 781 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 0692bab10c..dd8d31b898 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -676,7 +676,7 @@ public MalleableString caseConnection(Connection object) { private MalleableString minimallyDelimitedList(List items) { return MalleableString.anyOf( - list(", ", "", "", true, true, items), + list(", ", " ", "", true, true, items), new Builder() .append(String.format(" %n")) .append( diff --git a/test/C/src/multiport/BankGangedConnections.lf b/test/C/src/multiport/BankGangedConnections.lf index caf572cfd9..886c1a6bf1 100644 --- a/test/C/src/multiport/BankGangedConnections.lf +++ b/test/C/src/multiport/BankGangedConnections.lf @@ -1,24 +1,30 @@ -target C { - timeout: 0 sec -} +target C { timeout: 0 sec } + import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" + reactor Through { - input in:int; - output out:int; - reaction(in) -> out {= - lf_set(out, in->value); - =} + input in: int + + output out: int + + reaction(in) -> out {= lf_set(out, in->value); =} } + reactor Bank { - input in:int; - output out:int; - t = new Through(); - in, t.out -> t.in, out; + input in: int + + output out: int + + t = new Through() + + in, t.out -> t.in, out } + main reactor { - b = new[2] Bank(); - s = new Count(); - t = new TestCount(); - s.out, b.out -> b.in, t.in; + b = new[2] Bank() + s = new Count() + t = new TestCount() + + s.out, b.out -> b.in, t.in } diff --git a/test/C/src/multiport/BankIndexInitializer.lf b/test/C/src/multiport/BankIndexInitializer.lf index 84d25b5dda..9196deae88 100644 --- a/test/C/src/multiport/BankIndexInitializer.lf +++ b/test/C/src/multiport/BankIndexInitializer.lf @@ -1,25 +1,20 @@ // Test bank of reactors to multiport input with id parameter in the bank. -target C; - -preamble {= - int table[] = {4, 3, 2, 1}; -=} - -reactor Source( - bank_index:int(0), - value:int(0) -) { - output out:int; - reaction (startup) -> out {= - lf_set(out, self->value); - =} +target C + +preamble {= int table[] = {4, 3, 2, 1}; =} + +reactor Source(bank_index: int(0), value: int(0)) { + output out: int + + reaction(startup) -> out {= lf_set(out, self->value); =} } -reactor Sink(width:int(4)) { - input[width] in:int; - state received:bool(false); +reactor Sink(width: int(4)) { + input[width] in: int - reaction (in) {= + state received: bool(false) + + reaction(in) {= for (int idx = 0; idx < in_width; idx++) { if (in[idx]->is_present) { printf("Received on channel %d: %d\n", idx, in[idx]->value); @@ -30,14 +25,17 @@ reactor Sink(width:int(4)) { } } =} + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("Sink received no data."); } =} } -main reactor(width:int(4)) { - source = new[width] Source(value = {= table[bank_index] =}); - sink = new Sink(width = width); - source.out -> sink.in; + +main reactor(width: int(4)) { + source = new[width] Source(value = {= table[bank_index] =}) + sink = new Sink(width = width) + + source.out -> sink.in } diff --git a/test/C/src/multiport/BankMulticast.lf b/test/C/src/multiport/BankMulticast.lf index 7112a88804..9727c9fa79 100644 --- a/test/C/src/multiport/BankMulticast.lf +++ b/test/C/src/multiport/BankMulticast.lf @@ -1,38 +1,36 @@ /** - * This tests that a contained bank can send not only to a local connection, but also - * multicast via the container's output port. + * This tests that a contained bank can send not only to a local connection, but + * also multicast via the container's output port. */ -target C { - timeout: 3 sec, - fast: true -} +target C { timeout: 3 sec, fast: true } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Foo { - input in:int; - output out:int; + input in: int + + output out: int - c = new Count(); - c.out -> out; + c = new Count() + d = new TestCount(num_inputs = 4) - d = new TestCount(num_inputs = 4); - in -> d.in; + c.out -> out + in -> d.in } reactor Bar { - output[4] out:int; + output[4] out: int - foo = new[4] Foo(); + foo = new[4] Foo() - foo.out -> foo.in; - foo.out -> out; + foo.out -> foo.in + foo.out -> out } main reactor { - bar = new Bar(); + bar = new Bar() + d = new[4] TestCount(num_inputs = 4) - d = new[4] TestCount(num_inputs = 4); - bar.out -> d.in; + bar.out -> d.in } diff --git a/test/C/src/multiport/BankMultiportToReaction.lf b/test/C/src/multiport/BankMultiportToReaction.lf index dd8435925d..55a27379d5 100644 --- a/test/C/src/multiport/BankMultiportToReaction.lf +++ b/test/C/src/multiport/BankMultiportToReaction.lf @@ -1,21 +1,21 @@ -target C { - timeout: 5 sec, - fast: true -}; -import Count from "../lib/Count.lf"; +target C { timeout: 5 sec, fast: true } + +import Count from "../lib/Count.lf" reactor DoubleCount { - output[2] out:int; - c1 = new Count(); - c2 = new Count(); - c1.out, c2.out -> out; + output[2] out: int + + c1 = new Count() + c2 = new Count() + + c1.out, c2.out -> out } main reactor { - state count:int(1); - state received:bool(false); + s = new[2] DoubleCount() - s = new[2] DoubleCount(); + state count: int(1) + state received: bool(false) reaction(s.out) {= for (int i = 0; i < s_width; i++) { @@ -31,6 +31,7 @@ main reactor { } self->count++; =} + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("No inputs present."); diff --git a/test/C/src/multiport/BankReactionsInContainer.lf b/test/C/src/multiport/BankReactionsInContainer.lf index 95103754a5..4a6cc7cb2d 100644 --- a/test/C/src/multiport/BankReactionsInContainer.lf +++ b/test/C/src/multiport/BankReactionsInContainer.lf @@ -1,13 +1,14 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target C { - timeout: 1 sec, -}; -reactor R (bank_index:int(0)) { - output[2] out:int; - input[2] in:int; - state received:bool(false); +target C { timeout: 1 sec } + +reactor R(bank_index: int(0)) { + input[2] in: int + + output[2] out: int + + state received: bool(false) reaction(startup) -> out {= for (int i = 0; i < out_width; i++) { @@ -30,6 +31,7 @@ reactor R (bank_index:int(0)) { } } =} + reaction(shutdown) {= lf_print("Inner shutdown invoked."); if (!self->received) { @@ -37,9 +39,11 @@ reactor R (bank_index:int(0)) { } =} } + main reactor { - s = new[2] R(); - state received:bool(false); + s = new[2] R() + + state received: bool(false) reaction(startup) -> s.in {= int count = 0; @@ -50,6 +54,7 @@ main reactor { } } =} + reaction(s.out) {= for (int j = 0; j < s_width; j++) { for (int i = 0; i < s[j].out_width; i++) { @@ -63,6 +68,7 @@ main reactor { } } =} + reaction(shutdown) {= lf_print("Outer shutdown invoked."); if (!self->received) { diff --git a/test/C/src/multiport/BankSelfBroadcast.lf b/test/C/src/multiport/BankSelfBroadcast.lf index 48296c3500..1f7e84a9a9 100644 --- a/test/C/src/multiport/BankSelfBroadcast.lf +++ b/test/C/src/multiport/BankSelfBroadcast.lf @@ -1,21 +1,21 @@ /** - * Test a bank of reactors that broadcast a single output - * back to a multiport input of the same reactors in the bank - * so that each reactor in the bank receives the output - * produced by itself and each other reactor. + * Test a bank of reactors that broadcast a single output back to a multiport + * input of the same reactors in the bank so that each reactor in the bank + * receives the output produced by itself and each other reactor. * * @author Edward A. Lee */ -target C; -reactor A ( - bank_index:int(0) -) { - input[4] in:int; - output out:int; - state received:bool(false); - reaction(startup) -> out {= - lf_set(out, self->bank_index); - =} +target C + +reactor A(bank_index: int(0)) { + input[4] in: int + + output out: int + + state received: bool(false) + + reaction(startup) -> out {= lf_set(out, self->bank_index); =} + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { @@ -36,13 +36,16 @@ reactor A ( } } =} + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("No inputs received."); } =} } + main reactor { - a = new[4] A(); - (a.out)+ -> a.in; + a = new[4] A() + + (a.out)+ -> a.in } diff --git a/test/C/src/multiport/BankToBank.lf b/test/C/src/multiport/BankToBank.lf index a869ce1116..3b531f5962 100644 --- a/test/C/src/multiport/BankToBank.lf +++ b/test/C/src/multiport/BankToBank.lf @@ -1,24 +1,24 @@ // Check bank of reactors sending to bank of reactors. -target C { - timeout: 2 sec, - fast: true, -}; -reactor Source( - bank_index:int(0) -) { - timer t(0, 200 msec); - output out:int; - state s:int(0); +target C { timeout: 2 sec, fast: true } + +reactor Source(bank_index: int(0)) { + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s += self->bank_index; =} } -reactor Destination( - bank_index:int(0) -) { - state s:int(0); - input in:int; + +reactor Destination(bank_index: int(0)) { + input in: int + + state s: int(0) + reaction(in) {= printf("Destination %d received: %d.\n", self->bank_index, in->value); if (in->value != self->s) { @@ -27,6 +27,7 @@ reactor Destination( } self->s += self->bank_index; =} + reaction(shutdown) {= if (self->s == 0 && self->bank_index != 0) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -36,8 +37,9 @@ reactor Destination( =} } -main reactor BankToBank(width:int(4)) { - a = new[width] Source(); - b = new[width] Destination(); - a.out -> b.in; +main reactor BankToBank(width: int(4)) { + a = new[width] Source() + b = new[width] Destination() + + a.out -> b.in } diff --git a/test/C/src/multiport/BankToBankMultiport.lf b/test/C/src/multiport/BankToBankMultiport.lf index 343600718a..60d4603f0c 100644 --- a/test/C/src/multiport/BankToBankMultiport.lf +++ b/test/C/src/multiport/BankToBankMultiport.lf @@ -1,21 +1,25 @@ // Check bank of reactors sending to bank of reactors with multiports. -target C { - timeout: 2 sec, - fast: true, -}; -reactor Source(width:int(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], self->s++); } =} } -reactor Destination(width:int(1)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: int(1)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -28,6 +32,7 @@ reactor Destination(width:int(1)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -36,8 +41,10 @@ reactor Destination(width:int(1)) { printf("Success.\n"); =} } -main reactor BankToBankMultiport(bank_width:int(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b.in; + +main reactor BankToBankMultiport(bank_width: int(4)) { + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b.in } diff --git a/test/C/src/multiport/BankToBankMultiportAfter.lf b/test/C/src/multiport/BankToBankMultiportAfter.lf index 22aa5c590d..71b647df08 100644 --- a/test/C/src/multiport/BankToBankMultiportAfter.lf +++ b/test/C/src/multiport/BankToBankMultiportAfter.lf @@ -1,21 +1,25 @@ // Check bank of reactors sending to bank of reactors with multiports. -target C { - timeout: 2 sec, - fast: true, -}; -reactor Source(width:int(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], self->s++); } =} } -reactor Destination(width:int(1)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: int(1)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -28,6 +32,7 @@ reactor Destination(width:int(1)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -36,8 +41,10 @@ reactor Destination(width:int(1)) { printf("Success.\n"); =} } -main reactor (bank_width:int(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b.in after 200 msec; + +main reactor(bank_width: int(4)) { + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b.in after 200 msec } diff --git a/test/C/src/multiport/BankToMultiport.lf b/test/C/src/multiport/BankToMultiport.lf index 859eb56426..2b14ef7ef4 100644 --- a/test/C/src/multiport/BankToMultiport.lf +++ b/test/C/src/multiport/BankToMultiport.lf @@ -1,21 +1,18 @@ // Test bank of reactors to multiport input with id parameter in the bank. -target C; +target C -reactor Source( - bank_index:int(0) -) { - output out:int; +reactor Source(bank_index: int(0)) { + output out: int - reaction (startup) -> out {= - lf_set(out, self->bank_index); - =} + reaction(startup) -> out {= lf_set(out, self->bank_index); =} } -reactor Sink(width:int(4)) { - input[width] in:int; - state received:bool(false); +reactor Sink(width: int(4)) { + input[width] in: int + + state received: bool(false) - reaction (in) {= + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { printf("Received on channel %d: %d\n", i, in[i]->value); @@ -27,6 +24,7 @@ reactor Sink(width:int(4)) { } } =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Sink received no data\n"); @@ -35,8 +33,9 @@ reactor Sink(width:int(4)) { =} } -main reactor BankToMultiport(width:int(5)) { - source = new[width] Source(); - sink = new Sink(width = width); - source.out -> sink.in; +main reactor BankToMultiport(width: int(5)) { + source = new[width] Source() + sink = new Sink(width = width) + + source.out -> sink.in } diff --git a/test/C/src/multiport/BankToReaction.lf b/test/C/src/multiport/BankToReaction.lf index 7a832aeee1..bdd7c07d17 100644 --- a/test/C/src/multiport/BankToReaction.lf +++ b/test/C/src/multiport/BankToReaction.lf @@ -1,13 +1,11 @@ -target C { - timeout: 5 sec, - fast: true -}; -import Count from "../lib/Count.lf"; +target C { timeout: 5 sec, fast: true } + +import Count from "../lib/Count.lf" main reactor { - state count:int(1); + s = new[2] Count() - s = new[2] Count(); + state count: int(1) reaction(s.out) {= for (int i = 0; i < s_width; i++) { diff --git a/test/C/src/multiport/Broadcast.lf b/test/C/src/multiport/Broadcast.lf index a02cbf00eb..2105129568 100644 --- a/test/C/src/multiport/Broadcast.lf +++ b/test/C/src/multiport/Broadcast.lf @@ -1,19 +1,16 @@ -target C { - timeout: 2 sec, - fast: true -}; +target C { timeout: 2 sec, fast: true } reactor Source { - output out:int; + output out: int - reaction(startup) -> out {= - lf_set(out, 42); - =} + reaction(startup) -> out {= lf_set(out, 42); =} } -reactor Destination(bank_index:int(0)) { - input in:int; - state received:bool(false); +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (in->value != 42) { @@ -22,6 +19,7 @@ reactor Destination(bank_index:int(0)) { } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -32,7 +30,8 @@ reactor Destination(bank_index:int(0)) { } main reactor { - a = new Source(); - b = new[4] Destination(); - (a.out)+ -> b.in; + a = new Source() + b = new[4] Destination() + + (a.out)+ -> b.in } diff --git a/test/C/src/multiport/BroadcastAfter.lf b/test/C/src/multiport/BroadcastAfter.lf index cc4f82b164..95f179d24b 100644 --- a/test/C/src/multiport/BroadcastAfter.lf +++ b/test/C/src/multiport/BroadcastAfter.lf @@ -1,19 +1,16 @@ -target C { - timeout: 2 sec, - fast: true -}; +target C { timeout: 2 sec, fast: true } reactor Source { - output out:int; + output out: int - reaction(startup) -> out {= - lf_set(out, 42); - =} + reaction(startup) -> out {= lf_set(out, 42); =} } -reactor Destination(bank_index:int(0)) { - input in:int; - state received:bool(false); +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (in->value != 42) { @@ -26,6 +23,7 @@ reactor Destination(bank_index:int(0)) { } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -36,7 +34,8 @@ reactor Destination(bank_index:int(0)) { } main reactor { - a = new Source(); - b = new[4] Destination(); - (a.out)+ -> b.in after 1 sec; + a = new Source() + b = new[4] Destination() + + (a.out)+ -> b.in after 1 sec } diff --git a/test/C/src/multiport/BroadcastMultipleAfter.lf b/test/C/src/multiport/BroadcastMultipleAfter.lf index b410368071..03e513edfe 100644 --- a/test/C/src/multiport/BroadcastMultipleAfter.lf +++ b/test/C/src/multiport/BroadcastMultipleAfter.lf @@ -1,19 +1,16 @@ -target C { - timeout: 2 sec, - fast: true -}; +target C { timeout: 2 sec, fast: true } -reactor Source(value:int(42)) { - output out:int; +reactor Source(value: int(42)) { + output out: int - reaction(startup) -> out {= - lf_set(out, self->value); - =} + reaction(startup) -> out {= lf_set(out, self->value); =} } -reactor Destination(bank_index:int(0)) { - input in:int; - state received:bool(false); +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); int expected = (self->bank_index % 3) + 1; @@ -27,6 +24,7 @@ reactor Destination(bank_index:int(0)) { } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -37,9 +35,10 @@ reactor Destination(bank_index:int(0)) { } main reactor { - a1 = new Source(value=1); - a2 = new Source(value=2); - a3 = new Source(value=3); - b = new[9] Destination(); - (a1.out, a2.out, a3.out)+ -> b.in after 1 sec; + a1 = new Source(value = 1) + a2 = new Source(value = 2) + a3 = new Source(value = 3) + b = new[9] Destination() + + (a1.out, a2.out, a3.out)+ -> b.in after 1 sec } diff --git a/test/C/src/multiport/FullyConnected.lf b/test/C/src/multiport/FullyConnected.lf index 2b4ccb83c8..05c0a74c39 100644 --- a/test/C/src/multiport/FullyConnected.lf +++ b/test/C/src/multiport/FullyConnected.lf @@ -1,21 +1,19 @@ -target C; +target C -reactor Node( - num_nodes: size_t(4), - bank_index: int(0) -) { - input[num_nodes] in: int; - output out: int; +reactor Node(num_nodes: size_t(4), bank_index: int(0)) { + input[num_nodes] in: int - state received: bool(false); + output out: int - reaction (startup) -> out{= + state received: bool(false) + + reaction(startup) -> out {= lf_print("Hello from node %d!", self->bank_index); // broadcast my ID to everyone lf_set(out, self->bank_index); =} - reaction (in) {= + reaction(in) {= printf("Node %d received messages from ", self->bank_index); size_t count = 0; for (int i = 0; i < in_width; i++) { @@ -30,13 +28,16 @@ reactor Node( lf_print_error_and_exit("Received fewer messages than expected!"); } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("Received no input!"); } =} } + main reactor(num_nodes: size_t(4)) { - nodes = new[num_nodes] Node(num_nodes=num_nodes); - (nodes.out)+ -> nodes.in; + nodes = new[num_nodes] Node(num_nodes = num_nodes) + + (nodes.out)+ -> nodes.in } diff --git a/test/C/src/multiport/FullyConnectedAddressable.lf b/test/C/src/multiport/FullyConnectedAddressable.lf index 6562373cb9..8fb0427cb9 100644 --- a/test/C/src/multiport/FullyConnectedAddressable.lf +++ b/test/C/src/multiport/FullyConnectedAddressable.lf @@ -1,18 +1,15 @@ // In this pattern, each node can send direct messages to individual other nodes +target C -target C; +reactor Node(num_nodes: size_t(4), bank_index: int(0)) { + input[num_nodes] in: int -reactor Node( - num_nodes: size_t(4), - bank_index: int(0) -) { - input[num_nodes] in: int; - output[num_nodes] out: int; + output[num_nodes] out: int - state received:int(0); - state triggered:bool(false); + state received: int(0) + state triggered: bool(false) - reaction (startup) -> out {= + reaction(startup) -> out {= int outChannel = (self->bank_index + 1) % self->num_nodes; lf_print("Node %d sending %d out on channel %d.", self->bank_index, self->bank_index, outChannel @@ -21,7 +18,7 @@ reactor Node( lf_set(out[outChannel], self->bank_index); =} - reaction (in) {= + reaction(in) {= self->triggered = true; printf("Node %d received messages from ", self->bank_index); size_t count = 0; @@ -41,7 +38,8 @@ reactor Node( lf_print_error_and_exit("Received %d, but expected %d!", self->received, expected); } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!self->triggered) { lf_print_error_and_exit("Received no input!"); } @@ -49,9 +47,9 @@ reactor Node( } main reactor(num_nodes: size_t(4)) { - nodes1 = new[num_nodes] Node(num_nodes=num_nodes); - nodes1.out -> interleaved(nodes1.in); + nodes1 = new[num_nodes] Node(num_nodes = num_nodes) + nodes2 = new[num_nodes] Node(num_nodes = num_nodes) - nodes2 = new[num_nodes] Node(num_nodes=num_nodes); - interleaved(nodes2.out) -> nodes2.in; + nodes1.out -> interleaved (nodes1.in) + interleaved (nodes2.out) -> nodes2.in } diff --git a/test/C/src/multiport/FullyConnectedAddressableAfter.lf b/test/C/src/multiport/FullyConnectedAddressableAfter.lf index 2dc2e0dfe5..37a418a421 100644 --- a/test/C/src/multiport/FullyConnectedAddressableAfter.lf +++ b/test/C/src/multiport/FullyConnectedAddressableAfter.lf @@ -1,13 +1,12 @@ // In this pattern, each node can send direct messages to individual other nodes - -target C; +target C import Node from "FullyConnectedAddressable.lf" main reactor(num_nodes: size_t(4)) { - nodes1 = new[num_nodes] Node(num_nodes=num_nodes); - nodes1.out -> interleaved(nodes1.in) after 200msec; + nodes1 = new[num_nodes] Node(num_nodes = num_nodes) + nodes2 = new[num_nodes] Node(num_nodes = num_nodes) - nodes2 = new[num_nodes] Node(num_nodes=num_nodes); - interleaved(nodes2.out) -> nodes2.in after 400msec; + nodes1.out -> interleaved (nodes1.in) after 200 msec + interleaved (nodes2.out) -> nodes2.in after 400 msec } diff --git a/test/C/src/multiport/MultiportFromBank.lf b/test/C/src/multiport/MultiportFromBank.lf index 3b4c6c8fe1..d2438b6586 100644 --- a/test/C/src/multiport/MultiportFromBank.lf +++ b/test/C/src/multiport/MultiportFromBank.lf @@ -1,21 +1,20 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source( - check_override:int(0), - bank_index:int(0) -) { - output out:int; - reaction(startup) -> out {= - lf_set(out, self->bank_index * self->check_override); - =} +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target C { timeout: 2 sec, fast: true } + +reactor Source(check_override: int(0), bank_index: int(0)) { + output out: int + + reaction( + startup + ) -> out {= lf_set(out, self->bank_index * self->check_override); =} } -reactor Destination(port_width:int(3)) { - input[port_width] in:int; - state received:bool(false); + +reactor Destination(port_width: int(3)) { + input[port_width] in: int + + state received: bool(false) + reaction(in) {= for (int i = 0; i < in_width; i++) { printf("Destination channel %d received %d.\n", i, in[i]->value); @@ -26,6 +25,7 @@ reactor Destination(port_width:int(3)) { } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -35,8 +35,9 @@ reactor Destination(port_width:int(3)) { =} } -main reactor MultiportFromBank(width:int(4)) { - a = new[width] Source(check_override = 1); - b = new Destination(port_width = width); - a.out -> b.in; +main reactor MultiportFromBank(width: int(4)) { + a = new[width] Source(check_override = 1) + b = new Destination(port_width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportFromBankHierarchy.lf b/test/C/src/multiport/MultiportFromBankHierarchy.lf index 9e440c75c8..4f707c1563 100644 --- a/test/C/src/multiport/MultiportFromBankHierarchy.lf +++ b/test/C/src/multiport/MultiportFromBankHierarchy.lf @@ -1,19 +1,20 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target C { - timeout: 2 sec, - fast: true -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target C { timeout: 2 sec, fast: true } + import Source, Destination from "MultiportFromBank.lf" -reactor Container(port_width:int(3)) { - output[port_width] out:int; - s = new[port_width] Source(check_override = 1); - s.out -> out; +reactor Container(port_width: int(3)) { + output[port_width] out: int + + s = new[port_width] Source(check_override = 1) + + s.out -> out } -main reactor(width:int(4)) { - a = new Container(port_width = width); - b = new Destination(port_width = width); - a.out -> b.in; +main reactor(width: int(4)) { + a = new Container(port_width = width) + b = new Destination(port_width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportFromBankHierarchyAfter.lf b/test/C/src/multiport/MultiportFromBankHierarchyAfter.lf index f71c2674c9..c385f49679 100644 --- a/test/C/src/multiport/MultiportFromBankHierarchyAfter.lf +++ b/test/C/src/multiport/MultiportFromBankHierarchyAfter.lf @@ -1,14 +1,13 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target C { - timeout: 2 sec, - fast: true -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target C { timeout: 2 sec, fast: true } + import Destination from "MultiportFromBank.lf" import Container from "MultiportFromBankHierarchy.lf" main reactor MultiportFromBankHierarchyAfter { - a = new Container(port_width = 4); - b = new Destination(port_width = 4); - a.out -> b.in after 1 sec; + a = new Container(port_width = 4) + b = new Destination(port_width = 4) + + a.out -> b.in after 1 sec } diff --git a/test/C/src/multiport/MultiportFromHierarchy.lf b/test/C/src/multiport/MultiportFromHierarchy.lf index d21c47aa3f..c2aa59f83d 100644 --- a/test/C/src/multiport/MultiportFromHierarchy.lf +++ b/test/C/src/multiport/MultiportFromHierarchy.lf @@ -1,21 +1,26 @@ -// Check multiport output to multiport input, where the former is a hierarchical reactor. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(3)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +// Check multiport output to multiport input, where the former is a hierarchical +// reactor. +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(3)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], self->s++); } =} } -reactor Destination(width:int(3)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: int(3)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -28,6 +33,7 @@ reactor Destination(width:int(3)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -36,20 +42,26 @@ reactor Destination(width:int(3)) { printf("Success.\n"); =} } -reactor Container(width:int(3)) { - output[width] out:int; - src = new InsideContainer(width = width); - src.out -> out; + +reactor Container(width: int(3)) { + output[width] out: int + + src = new InsideContainer(width = width) + + src.out -> out } -reactor InsideContainer(width:int(3)) { - output[width] out:int; - src = new Source(width = width); - src.out -> out; +reactor InsideContainer(width: int(3)) { + output[width] out: int + + src = new Source(width = width) + + src.out -> out } -main reactor MultiportFromHierarchy(width:int(4)) { - a = new Container(width = width); - b = new Destination(width = width); - a.out -> b.in; +main reactor MultiportFromHierarchy(width: int(4)) { + a = new Container(width = width) + b = new Destination(width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportFromReaction.lf b/test/C/src/multiport/MultiportFromReaction.lf index 0e38e2d3e2..7f772e0113 100644 --- a/test/C/src/multiport/MultiportFromReaction.lf +++ b/test/C/src/multiport/MultiportFromReaction.lf @@ -1,11 +1,11 @@ // Check reaction to multiport input of a contained reactor. -target C { - timeout: 2 sec, - fast: true -}; -reactor Destination(width:int(1)) { - state s:int(6); - input[width] in:int; +target C { timeout: 2 sec, fast: true } + +reactor Destination(width: int(1)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -18,6 +18,7 @@ reactor Destination(width:int(1)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -26,9 +27,14 @@ reactor Destination(width:int(1)) { printf("Success.\n"); =} } -main reactor MultiportFromReaction(width:int(4)) { - timer t(0, 200 msec); - state s:int(0); + +main reactor MultiportFromReaction(width: int(4)) { + timer t(0, 200 msec) + + b = new Destination(width = width) + + state s: int(0) + reaction(t) -> b.in {= for(int i = 0; i < b.in_width; i++) { printf("Before lf_set, b.in[%d]->is_present has value %d\n", i, b.in[i]->is_present); @@ -37,5 +43,4 @@ main reactor MultiportFromReaction(width:int(4)) { printf("AFTER set, b.in[%d]->value has value %d\n", i, b.in[i]->value); } =} - b = new Destination(width = width); } diff --git a/test/C/src/multiport/MultiportIn.lf b/test/C/src/multiport/MultiportIn.lf index 7d2b6cc874..3bbef42de4 100644 --- a/test/C/src/multiport/MultiportIn.lf +++ b/test/C/src/multiport/MultiportIn.lf @@ -1,29 +1,33 @@ -// This is a version fo the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target C { - timeout: 2 sec, - fast: true -}; +// This is a version fo the Threaded test that uses a multiport input at the +// destination. Its purpose is to test multiport inputs. +target C { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor Computation { - input in:int; - output out:int; - reaction(in) -> out {= - lf_set(out, in->value); - =} + input in: int + + output out: int + + reaction(in) -> out {= lf_set(out, in->value); =} } + reactor Destination { - state s:int(0); - input[4] in:int; + input[4] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -36,6 +40,7 @@ reactor Destination { } self->s += 4; =} + reaction(shutdown) {= if (self->s == 0) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -46,15 +51,16 @@ reactor Destination { } main reactor MultiportIn { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in; - a.out -> t2.in; - a.out -> t3.in; - a.out -> t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in + a.out -> t2.in + a.out -> t3.in + a.out -> t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/C/src/multiport/MultiportInParameterized.lf b/test/C/src/multiport/MultiportInParameterized.lf index dbfdcd937b..77f274cd07 100644 --- a/test/C/src/multiport/MultiportInParameterized.lf +++ b/test/C/src/multiport/MultiportInParameterized.lf @@ -1,29 +1,33 @@ -// This is a version of the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target C { - timeout: 2 sec, - fast: true -}; +// This is a version of the Threaded test that uses a multiport input at the +// destination. Its purpose is to test multiport inputs. +target C { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= lf_set(out, self->s); self->s++; =} } + reactor Computation { - input in:int; - output out:int; - reaction(in) -> out {= - lf_set(out, in->value); - =} + input in: int + + output out: int + + reaction(in) -> out {= lf_set(out, in->value); =} } -reactor Destination(width:int(1)) { - state s:int(0); - input[width] in:int; + +reactor Destination(width: int(1)) { + input[width] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -36,6 +40,7 @@ reactor Destination(width:int(1)) { } self->s += 4; =} + reaction(shutdown) {= if (self->s == 0) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -46,20 +51,19 @@ reactor Destination(width:int(1)) { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(width = 4); - a.out -> t1.in; - a.out -> t2.in; - a.out -> t3.in; - a.out -> t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; - // I.e.: - // t1.out -> b.in[0]; - // t2.out -> b.in[1]; - // t3.out -> b.in[2]; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination(width = 4) + + a.out -> t1.in + a.out -> t2.in + a.out -> t3.in + a.out -> t4.in + // I.e.: t1.out -> b.in[0]; t2.out -> b.in[1]; t3.out -> b.in[2]; dt4.out -> + // b.in[3]; I.e.: t1.out -> b.in[0]; t2.out -> b.in[1]; t3.out -> b.in[2]; // dt4.out -> b.in[3]; + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/C/src/multiport/MultiportMutableInput.lf b/test/C/src/multiport/MultiportMutableInput.lf index d89b8d66dc..f30e02576f 100644 --- a/test/C/src/multiport/MultiportMutableInput.lf +++ b/test/C/src/multiport/MultiportMutableInput.lf @@ -1,18 +1,22 @@ -// Source produces a ints on a multiport, which it passes -// to Scale. Scale requests a writable copy. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target C; +// Source produces a ints on a multiport, which it passes to Scale. Scale +// requests a writable copy. It modifies it and passes it to Print. It gets +// freed after Print is done with it. +target C + reactor Source { - output[2] out:int; + output[2] out: int + reaction(startup) -> out {= lf_set(out[0], 21); lf_set(out[1], 42); =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input[2] in:int; + +reactor Print( + scale: int(1) // The scale parameter is just for testing. +) { + input[2] in: int + reaction(in) {= int expected = 42; for(int j = 0; j < 2; j++) { @@ -26,9 +30,11 @@ reactor Print(scale:int(1)) { =} } -reactor Scale(scale:int(2)) { - mutable input[2] in:int; - output[2] out:int; +reactor Scale(scale: int(2)) { + mutable input[2] in: int + + output[2] out: int + reaction(in) -> out {= for(int j = 0; j < 2; j++) { // Modify the input, allowed because mutable. @@ -37,10 +43,12 @@ reactor Scale(scale:int(2)) { } =} } + main reactor { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.in + c.out -> p.in } diff --git a/test/C/src/multiport/MultiportMutableInputArray.lf b/test/C/src/multiport/MultiportMutableInputArray.lf index c30e82c245..0e46f48ee6 100644 --- a/test/C/src/multiport/MultiportMutableInputArray.lf +++ b/test/C/src/multiport/MultiportMutableInputArray.lf @@ -1,11 +1,12 @@ -// Source produces a dynamically allocated arrays on a multiport, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target C; +// Source produces a dynamically allocated arrays on a multiport, which it +// passes to Scale. Scale requests a writable copy, which, instead of copying, +// it just gets ownership of the original array. It modifies it and passes it to +// Print. It gets freed after Print is done with it. +target C + reactor Source { - output[2] out:int[]; + output[2] out: int[] + reaction(startup) -> out {= // Dynamically allocate an output array of length 3. SET_NEW_ARRAY(out[0], 3); @@ -24,9 +25,10 @@ reactor Source { out[1]->value[2] = 5; =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input[2] in:int[]; + +reactor Print(scale: int(1)) { + input[2] in: int[] + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -50,9 +52,11 @@ reactor Print(scale:int(1)) { =} } -reactor Scale(scale:int(2)) { - mutable input[2] in:int[]; - output[2] out:int[]; +reactor Scale(scale: int(2)) { + mutable input[2] in: int[] + + output[2] out: int[] + reaction(in) -> out {= for(int j = 0; j < in_width; j++) { for(int i = 0; i < in[j]->length; i++) { @@ -66,9 +70,10 @@ reactor Scale(scale:int(2)) { } main reactor { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.in + c.out -> p.in } diff --git a/test/C/src/multiport/MultiportOut.lf b/test/C/src/multiport/MultiportOut.lf index 008ccfd8c6..3ee5a7bdce 100644 --- a/test/C/src/multiport/MultiportOut.lf +++ b/test/C/src/multiport/MultiportOut.lf @@ -1,12 +1,13 @@ // Check multiport capabilities on Outputs. -target C { - timeout: 2 sec, - fast: true -}; +target C { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out:int; - state s:int(0); + output[4] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 4; i++) { lf_set(out[i], self->s); @@ -14,9 +15,12 @@ reactor Source { self->s++; =} } + reactor Computation { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= // No need to sleep for this test. // struct timespec sleep_time = {(time_t) 0, (long)200000000}; @@ -25,9 +29,12 @@ reactor Computation { lf_set(out, in->value); =} } + reactor Destination { - state s:int(0); - input[4] in:int; + input[4] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -40,6 +47,7 @@ reactor Destination { } self->s += 4; =} + reaction(shutdown) {= if (self->s == 0) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -50,12 +58,13 @@ reactor Destination { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in, t2.in, t3.in, t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in, t2.in, t3.in, t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/C/src/multiport/MultiportToBank.lf b/test/C/src/multiport/MultiportToBank.lf index 2081059987..7c7da2d785 100644 --- a/test/C/src/multiport/MultiportToBank.lf +++ b/test/C/src/multiport/MultiportToBank.lf @@ -1,29 +1,32 @@ // Check multiport output to bank of recipients. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(2)) { - output[width] out:int; // Connected to a bank of Destination reactors - input dummy:int; // Not connected to anything +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(2)) { + input dummy: int // Not connected to anything + + output[width] out: int // Connected to a bank of Destination reactors + reaction(startup) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} - // Test also that multiple appearances of the same effect port - // do not result in multiple allocations of memory for the port. - reaction(dummy) -> out {= // Contents of the reactions does not matter (either could be empty) - for(int i = 0; i < out_width; i++) { - lf_set(out[i], i); - } + + // Test also that multiple appearances of the same effect port do not result + // in multiple allocations of memory for the port. + reaction(dummy) -> out {= + // Contents of the reactions does not matter (either could be empty) + for(int i = 0; i < out_width; i++) { + lf_set(out[i], i); + } =} } -reactor Destination( - bank_index:int(0) -) { - input in:int; - state received:bool(false); + +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (self->bank_index != in->value) { @@ -32,6 +35,7 @@ reactor Destination( } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -41,8 +45,9 @@ reactor Destination( =} } -main reactor MultiportToBank(width:int(3)) { - a = new Source(width = width); - b = new[width] Destination(); - a.out -> b.in; +main reactor MultiportToBank(width: int(3)) { + a = new Source(width = width) + b = new[width] Destination() + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToBankAfter.lf b/test/C/src/multiport/MultiportToBankAfter.lf index 743ef31664..082831d8ef 100644 --- a/test/C/src/multiport/MultiportToBankAfter.lf +++ b/test/C/src/multiport/MultiportToBankAfter.lf @@ -1,21 +1,22 @@ -// Check multiport output to bank of recipients where the width of the bank is inferred. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(2)) { - output[width] out:int; +// Check multiport output to bank of recipients where the width of the bank is +// inferred. +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(2)) { + output[width] out: int + reaction(startup) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} } -reactor Destination( - bank_index:int(0) -) { - input in:int; - state received:bool(false); + +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (self->bank_index != in->value) { @@ -28,6 +29,7 @@ reactor Destination( } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -37,8 +39,9 @@ reactor Destination( =} } -main reactor(width:int(3)) { - a = new Source(width = width); - b = new[width] Destination(); - a.out -> b.in after 1 sec; // Width of the bank of delays will be inferred. +main reactor(width: int(3)) { + a = new Source(width = width) + b = new[width] Destination() + + a.out -> b.in after 1 sec // Width of the bank of delays will be inferred. } diff --git a/test/C/src/multiport/MultiportToBankDouble.lf b/test/C/src/multiport/MultiportToBankDouble.lf index 277194d313..6e05738ff0 100644 --- a/test/C/src/multiport/MultiportToBankDouble.lf +++ b/test/C/src/multiport/MultiportToBankDouble.lf @@ -1,29 +1,31 @@ -// Check multiport output to bank of recipients where the source -// has two reactions that write to the output. -target C { - timeout: 2 sec, - fast: true -}; +// Check multiport output to bank of recipients where the source has two +// reactions that write to the output. +target C { timeout: 2 sec, fast: true } + reactor Source { - output[3] out:int; // Connected to a bank of Destination reactors + output[3] out: int // Connected to a bank of Destination reactors + reaction(startup) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} - // Test also that multiple appearances of the same effect port - // do not result in multiple allocations of memory for the port. - reaction(startup) -> out {= // Contents of the reactions does not matter (either could be empty) - for(int i = 0; i < out_width; i++) { - lf_set(out[i], i * 2); - } + + // Test also that multiple appearances of the same effect port do not result + // in multiple allocations of memory for the port. + reaction(startup) -> out {= + // Contents of the reactions does not matter (either could be empty) + for(int i = 0; i < out_width; i++) { + lf_set(out[i], i * 2); + } =} } -reactor Destination( - bank_index:int(0) -) { - input in:int; - state received:bool(false); + +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (self->bank_index * 2 != in->value) { @@ -32,6 +34,7 @@ reactor Destination( } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -42,7 +45,8 @@ reactor Destination( } main reactor { - a = new Source(); - b = new[3] Destination(); - a.out -> b.in; + a = new Source() + b = new[3] Destination() + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToBankHierarchy.lf b/test/C/src/multiport/MultiportToBankHierarchy.lf index a286698d1c..2bd9806841 100644 --- a/test/C/src/multiport/MultiportToBankHierarchy.lf +++ b/test/C/src/multiport/MultiportToBankHierarchy.lf @@ -1,22 +1,22 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(2)) { - output[width] out:int; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(2)) { + output[width] out: int + reaction(startup) -> out {= for(int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} } -reactor Destination( - bank_index:int(0) -) { - input in:int; - state received:bool(false); + +reactor Destination(bank_index: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Destination %d received %d.\n", self->bank_index, in->value); if (self->bank_index != in->value) { @@ -25,6 +25,7 @@ reactor Destination( } self->received = true; =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination %d received no input!\n", self->bank_index); @@ -33,14 +34,18 @@ reactor Destination( printf("Success.\n"); =} } -reactor Container(width:int(2)) { - input[width] in:int; - c = new[width] Destination(); - in -> c.in; + +reactor Container(width: int(2)) { + input[width] in: int + + c = new[width] Destination() + + in -> c.in } -main reactor MultiportToBankHierarchy(width:int(3)) { - a = new Source(width = width); - b = new Container(width = width); - a.out -> b.in; +main reactor MultiportToBankHierarchy(width: int(3)) { + a = new Source(width = width) + b = new Container(width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToHierarchy.lf b/test/C/src/multiport/MultiportToHierarchy.lf index c8740986c6..99b081dd86 100644 --- a/test/C/src/multiport/MultiportToHierarchy.lf +++ b/test/C/src/multiport/MultiportToHierarchy.lf @@ -1,22 +1,27 @@ -// Check multiport output to multiport input, where the latter is a hierarchical reactor. - // Note that the destination reactor has width wider than the sender, so one input is dangling. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(2)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +// Check multiport output to multiport input, where the latter is a hierarchical +// reactor. Note that the destination reactor has width wider than the sender, +// so one input is dangling. +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(2)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 4; i++) { lf_set(out[i], self->s++); } =} } -reactor Destination(width:int(4)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: int(4)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -29,6 +34,7 @@ reactor Destination(width:int(4)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -37,14 +43,18 @@ reactor Destination(width:int(4)) { printf("Success.\n"); =} } -reactor Container(width:int(4)) { - input[width] in:int; - dst = new Destination(); - in -> dst.in; + +reactor Container(width: int(4)) { + input[width] in: int + + dst = new Destination() + + in -> dst.in } -main reactor MultiportToHierarchy(width:int(4)) { - a = new Source(width = width); - b = new Container(width = width); - a.out -> b.in; +main reactor MultiportToHierarchy(width: int(4)) { + a = new Source(width = width) + b = new Container(width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToMultiport.lf b/test/C/src/multiport/MultiportToMultiport.lf index 3cd560360f..a2dfb14929 100644 --- a/test/C/src/multiport/MultiportToMultiport.lf +++ b/test/C/src/multiport/MultiportToMultiport.lf @@ -1,12 +1,13 @@ // Check multiport output to multiport input. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { printf("Before lf_set, out[%d]->is_present has value %d\n", i, out[i]->is_present); @@ -16,9 +17,12 @@ reactor Source(width:int(1)) { } =} } -reactor Destination(width:int(1)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: int(1)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -31,6 +35,7 @@ reactor Destination(width:int(1)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -39,8 +44,10 @@ reactor Destination(width:int(1)) { printf("Success.\n"); =} } -main reactor MultiportToMultiport(width:int(4)) { - a = new Source(width = width); - b = new Destination(width = width); - a.out -> b.in; + +main reactor MultiportToMultiport(width: int(4)) { + a = new Source(width = width) + b = new Destination(width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToMultiport2.lf b/test/C/src/multiport/MultiportToMultiport2.lf index 6212b94373..f701e42041 100644 --- a/test/C/src/multiport/MultiportToMultiport2.lf +++ b/test/C/src/multiport/MultiportToMultiport2.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target C; +// Test multiport to multiport connections. See also MultiportToMultiport. +target C -reactor Source(width:int(2)) { - output[width] out:int; - reaction (startup) -> out {= +reactor Source(width: int(2)) { + output[width] out: int + + reaction(startup) -> out {= for (int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} } -reactor Destination(width:int(2)) { - input[width] in:int; - reaction (in) {= +reactor Destination(width: int(2)) { + input[width] in: int + + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { printf("Received on channel %d: %d\n", i, in[i]->value); @@ -28,9 +29,14 @@ reactor Destination(width:int(2)) { =} } -main reactor MultiportToMultiport2(width1:int(3), width2:int(2), width3:int(5)) { - a1 = new Source(width = width1); - a2 = new Source(width = width2); - b = new Destination(width = width3); - a1.out, a2.out -> b.in; +main reactor MultiportToMultiport2( + width1: int(3), + width2: int(2), + width3: int(5) +) { + a1 = new Source(width = width1) + a2 = new Source(width = width2) + b = new Destination(width = width3) + + a1.out, a2.out -> b.in } diff --git a/test/C/src/multiport/MultiportToMultiport2After.lf b/test/C/src/multiport/MultiportToMultiport2After.lf index 4928cb5cb4..106a9150fd 100644 --- a/test/C/src/multiport/MultiportToMultiport2After.lf +++ b/test/C/src/multiport/MultiportToMultiport2After.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target C; +// Test multiport to multiport connections. See also MultiportToMultiport. +target C -reactor Source(width:int(2)) { - output[width] out:int; - reaction (startup) -> out {= +reactor Source(width: int(2)) { + output[width] out: int + + reaction(startup) -> out {= for (int i = 0; i < out_width; i++) { lf_set(out[i], i); } =} } -reactor Destination(width:int(2)) { - input[width] in:int; - reaction (in) {= +reactor Destination(width: int(2)) { + input[width] in: int + + reaction(in) {= for (int i = 0; i < in_width; i++) { if (in[i]->is_present) { printf("Received on channel %d: %d\n", i, in[i]->value); @@ -33,8 +34,9 @@ reactor Destination(width:int(2)) { } main reactor MultiportToMultiport2After { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.in after 1 sec; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.in after 1 sec } diff --git a/test/C/src/multiport/MultiportToMultiportArray.lf b/test/C/src/multiport/MultiportToMultiportArray.lf index abccb3e6c7..aa76aeb7a2 100644 --- a/test/C/src/multiport/MultiportToMultiportArray.lf +++ b/test/C/src/multiport/MultiportToMultiportArray.lf @@ -1,13 +1,14 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target C { - timeout: 2 sec, - fast: true -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target C { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[2] out:int[]; - state s:int(0); + output[2] out: int[] + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 2; i++) { // Dynamically allocate an output array of length 3. @@ -22,8 +23,10 @@ reactor Source { } reactor Destination { - state s:int(15); - input[2] in:int[]; + input[2] in: int[] + + state s: int(15) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -40,6 +43,7 @@ reactor Destination { } self->s += 36; =} + reaction(shutdown) {= if (self->s <= 15) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -50,7 +54,8 @@ reactor Destination { } main reactor MultiportToMultiportArray { - a = new Source(); - b = new Destination(); - a.out -> b.in; + a = new Source() + b = new Destination() + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToMultiportParameter.lf b/test/C/src/multiport/MultiportToMultiportParameter.lf index 850b24ab1e..572bfa3374 100644 --- a/test/C/src/multiport/MultiportToMultiportParameter.lf +++ b/test/C/src/multiport/MultiportToMultiportParameter.lf @@ -1,12 +1,13 @@ // Check multiport output to multiport input. -target C { - timeout: 2 sec, - fast: true -}; -reactor Source(width:int(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target C { timeout: 2 sec, fast: true } + +reactor Source(width: int(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < out_width; i++) { printf("Before lf_set, out[%d]->is_present has value %d\n", i, out[i]->is_present); @@ -16,9 +17,12 @@ reactor Source(width:int(1)) { } =} } -reactor Destination(width:int(1)) { - state s:int(6); - input[width] in:int; // Width is one larger than that of the source. + +reactor Destination(width: int(1)) { + input[width] in: int // Width is one larger than that of the source. + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in_width; i++) { @@ -31,6 +35,7 @@ reactor Destination(width:int(1)) { } self->s += 16; =} + reaction(shutdown) {= if (self->s <= 6) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -39,8 +44,10 @@ reactor Destination(width:int(1)) { printf("Success.\n"); =} } -main reactor (width:int(4)) { - a = new Source(width = width); - b = new Destination(width = width); - a.out -> b.in; + +main reactor(width: int(4)) { + a = new Source(width = width) + b = new Destination(width = width) + + a.out -> b.in } diff --git a/test/C/src/multiport/MultiportToPort.lf b/test/C/src/multiport/MultiportToPort.lf index 12bd6eb435..7660dc911b 100644 --- a/test/C/src/multiport/MultiportToPort.lf +++ b/test/C/src/multiport/MultiportToPort.lf @@ -1,11 +1,10 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target C { - timeout: 2 sec, - fast: true -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target C { timeout: 2 sec, fast: true } + reactor Source { - output[2] out:int; + output[2] out: int + reaction(startup) -> out {= for(int i = 0; i < out_width; i++) { printf("Source sending %d.\n", i); @@ -13,9 +12,12 @@ reactor Source { } =} } -reactor Destination(expected:int(0)) { - input in:int; - state received:bool(false); + +reactor Destination(expected: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= printf("Received: %d.\n", in->value); self->received = true; @@ -24,6 +26,7 @@ reactor Destination(expected:int(0)) { exit(1); } =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Destination received no input!\n"); @@ -34,8 +37,9 @@ reactor Destination(expected:int(0)) { } main reactor MultiportToPort { - a = new Source(); - b1 = new Destination(); - b2 = new Destination(expected = 1); - a.out -> b1.in, b2.in; + a = new Source() + b1 = new Destination() + b2 = new Destination(expected = 1) + + a.out -> b1.in, b2.in } diff --git a/test/C/src/multiport/NestedBanks.lf b/test/C/src/multiport/NestedBanks.lf index 841ee9e1f5..47ea464eb8 100644 --- a/test/C/src/multiport/NestedBanks.lf +++ b/test/C/src/multiport/NestedBanks.lf @@ -2,36 +2,47 @@ * Test of nested banks with multiports. * @author Edward A. Lee */ -target C; +target C + main reactor { - a = new[2] A(); - c = new[3] C(); - d = new D(); - e = new E(); + a = new[2] A() + c = new[3] C() + d = new D() + e = new E() - (a.x)+ -> c.z, d.u, e.t; + (a.x)+ -> c.z, d.u, e.t } -reactor A(bank_index:int(0)) { - output[4] x:int; - b = new[2] B(a_bank_index = bank_index); - b.y -> x; + +reactor A(bank_index: int(0)) { + output[4] x: int + + b = new[2] B(a_bank_index = bank_index) + + b.y -> x } -reactor B(a_bank_index:int(0), bank_index:int(0)) { - output[2] y:int; + +reactor B(a_bank_index: int(0), bank_index: int(0)) { + output[2] y: int + reaction(startup) -> y {= int base = self->a_bank_index * 4 + self->bank_index * 2; lf_set(y[0], base); lf_set(y[1], base + 1); =} } -reactor C(bank_index:int(0)) { - input[2] z:int; - f = new F(c_bank_index = bank_index); - g = new G(c_bank_index = bank_index); - z -> f.w, g.s; + +reactor C(bank_index: int(0)) { + input[2] z: int + + f = new F(c_bank_index = bank_index) + g = new G(c_bank_index = bank_index) + + z -> f.w, g.s } + reactor D { - input[2] u:int; + input[2] u: int + reaction(u) {= for (int i = 0; i < u_width; i++) { lf_print("d.u[%d] received %d.", i, u[i]->value); @@ -41,16 +52,20 @@ reactor D { } =} } + reactor E { - input[8] t:int; + input[8] t: int + reaction(t) {= for (int i = 0; i < t_width; i++) { lf_print("e.t[%d] received %d.", i, t[i]->value); } =} } -reactor F(c_bank_index:int(0)) { - input w:int; + +reactor F(c_bank_index: int(0)) { + input w: int + reaction(w) {= lf_print("c[%d].f.w received %d.", self->c_bank_index, w->value); if (w->value != self->c_bank_index * 2) { @@ -58,8 +73,10 @@ reactor F(c_bank_index:int(0)) { } =} } -reactor G(c_bank_index:int(0)) { - input s:int; + +reactor G(c_bank_index: int(0)) { + input s: int + reaction(s) {= lf_print("c[%d].g.s received %d.", self->c_bank_index, s->value); if (s->value != self->c_bank_index * 2 + 1) { diff --git a/test/C/src/multiport/NestedInterleavedBanks.lf b/test/C/src/multiport/NestedInterleavedBanks.lf index a4729b99dd..5d6a3f5882 100644 --- a/test/C/src/multiport/NestedInterleavedBanks.lf +++ b/test/C/src/multiport/NestedInterleavedBanks.lf @@ -2,9 +2,11 @@ * Test nested banks with interleaving. * @author Edward A. Lee */ -target C; -reactor A(bank_index:int(0), outer_bank_index:int(0)) { - output[2] p:int; +target C + +reactor A(bank_index: int(0), outer_bank_index: int(0)) { + output[2] p: int + reaction(startup) -> p {= for (int i = 0; i < p_width; i++) { lf_set(p[i], self->outer_bank_index * 4 + self->bank_index * 2 + i + 1); @@ -12,13 +14,18 @@ reactor A(bank_index:int(0), outer_bank_index:int(0)) { } =} } -reactor B(bank_index:int(0)) { - output[4] q:int; - a = new[2] A(outer_bank_index = bank_index); - interleaved(a.p) -> q; + +reactor B(bank_index: int(0)) { + output[4] q: int + + a = new[2] A(outer_bank_index = bank_index) + + interleaved (a.p) -> q } + reactor C { - input[8] i:int; + input[8] i: int + reaction(i) {= int expected[] = {1, 3, 2, 4, 5, 7, 6, 8}; for(int j = 0; j < i_width; j++) { @@ -29,8 +36,10 @@ reactor C { } =} } + main reactor { - b = new[2] B(); - c = new C(); - b.q -> c.i; + b = new[2] B() + c = new C() + + b.q -> c.i } diff --git a/test/C/src/multiport/PipelineAfter.lf b/test/C/src/multiport/PipelineAfter.lf index ba4b2fc88a..5b8e02176e 100644 --- a/test/C/src/multiport/PipelineAfter.lf +++ b/test/C/src/multiport/PipelineAfter.lf @@ -1,26 +1,23 @@ -target C; +target C reactor Source { - output out:unsigned; + output out: unsigned - reaction (startup) -> out {= - lf_set(out, 40); - =} + reaction(startup) -> out {= lf_set(out, 40); =} } reactor Compute { - input in:unsigned; - output out:unsigned; + input in: unsigned - reaction (in) -> out {= - lf_set(out, in->value + 2); - =} + output out: unsigned + + reaction(in) -> out {= lf_set(out, in->value + 2); =} } reactor Sink { - input in:unsigned; + input in: unsigned - reaction (in) {= + reaction(in) {= printf("Received %d\n", in->value); if (in->value != 42) { printf("ERROR: expected 42!\n"); @@ -31,13 +28,12 @@ reactor Sink { exit(2); } =} - } main reactor { - source = new Source(); - compute = new Compute(); - sink = new Sink(); + source = new Source() + compute = new Compute() + sink = new Sink() - source.out, compute.out -> compute.in, sink.in after 500 msec; + source.out, compute.out -> compute.in, sink.in after 500 msec } diff --git a/test/C/src/multiport/ReactionToContainedBank.lf b/test/C/src/multiport/ReactionToContainedBank.lf index 5beb13d52b..09ae593a47 100644 --- a/test/C/src/multiport/ReactionToContainedBank.lf +++ b/test/C/src/multiport/ReactionToContainedBank.lf @@ -1,15 +1,14 @@ // Test reaction sending messages to a contained bank of reactors. -target C { - timeout: 1 sec, - fast: true -}; -import TestCount from "../lib/TestCount.lf"; +target C { timeout: 1 sec, fast: true } -main reactor ReactionToContainedBank(width:int(2)) { - timer t(0, 100 msec); - state count:int(1); +import TestCount from "../lib/TestCount.lf" - test = new[width] TestCount(num_inputs = 11); +main reactor ReactionToContainedBank(width: int(2)) { + timer t(0, 100 msec) + + test = new[width] TestCount(num_inputs = 11) + + state count: int(1) reaction(t) -> test.in {= for (int i = 0; i < self->width; i++) { diff --git a/test/C/src/multiport/ReactionToContainedBank2.lf b/test/C/src/multiport/ReactionToContainedBank2.lf index 0cea7cbb22..1b2157b17d 100644 --- a/test/C/src/multiport/ReactionToContainedBank2.lf +++ b/test/C/src/multiport/ReactionToContainedBank2.lf @@ -1,15 +1,14 @@ // Test reaction sending messages to a contained bank of reactors. -target C { - timeout: 1 sec, - fast: true -}; -import TestCount from "../lib/TestCount.lf"; +target C { timeout: 1 sec, fast: true } -reactor ReactionToContainedBank(width:int(2)) { - timer t(0, 100 msec); - state count:int(1); +import TestCount from "../lib/TestCount.lf" - test = new[width] TestCount(num_inputs = 11); +reactor ReactionToContainedBank(width: int(2)) { + timer t(0, 100 msec) + + test = new[width] TestCount(num_inputs = 11) + + state count: int(1) reaction(t) -> test.in {= for (int i = 0; i < self->width; i++) { @@ -19,7 +18,7 @@ reactor ReactionToContainedBank(width:int(2)) { =} } -main reactor (width:int(2)) { - a = new ReactionToContainedBank(width = width); - b = new ReactionToContainedBank(width = 4); +main reactor(width: int(2)) { + a = new ReactionToContainedBank(width = width) + b = new ReactionToContainedBank(width = 4) } diff --git a/test/C/src/multiport/ReactionToContainedBankMultiport.lf b/test/C/src/multiport/ReactionToContainedBankMultiport.lf index e9bb65da6d..5554b4174d 100644 --- a/test/C/src/multiport/ReactionToContainedBankMultiport.lf +++ b/test/C/src/multiport/ReactionToContainedBankMultiport.lf @@ -1,16 +1,15 @@ -// Test reaction sending messages to a contained bank of reactors -// with a multiport input. -target C { - timeout: 1 sec, - fast: true -}; -import TestCountMultiport from "../lib/TestCountMultiport.lf"; +// Test reaction sending messages to a contained bank of reactors with a +// multiport input. +target C { timeout: 1 sec, fast: true } -main reactor(width:int(2)) { - timer t(0, 100 msec); - state count:int(1); +import TestCountMultiport from "../lib/TestCountMultiport.lf" - test = new[width] TestCountMultiport(num_inputs = 11, width = width); +main reactor(width: int(2)) { + timer t(0, 100 msec) + + test = new[width] TestCountMultiport(num_inputs = 11, width = width) + + state count: int(1) reaction(t) -> test.in {= for (int i = 0; i < self->width; i++) { diff --git a/test/C/src/multiport/ReactionsToNested.lf b/test/C/src/multiport/ReactionsToNested.lf index 990e5431a8..32993ea4d5 100644 --- a/test/C/src/multiport/ReactionsToNested.lf +++ b/test/C/src/multiport/ReactionsToNested.lf @@ -1,11 +1,12 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - timeout: 1 sec -}; -reactor T(expected:int(0)) { - input z:int; - state received:bool(false); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { timeout: 1 sec } + +reactor T(expected: int(0)) { + input z: int + + state received: bool(false) + reaction(z) {= lf_print("T received %d", z->value); self->received = true; @@ -13,6 +14,7 @@ reactor T(expected:int(0)) { lf_print_error_and_exit("Expected %d", self->expected); } =} + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("No input received"); @@ -21,18 +23,18 @@ reactor T(expected:int(0)) { } reactor D { - input[2] y:int; - t1 = new T(expected = 42); - t2 = new T(expected = 43); - y -> t1.z, t2.z; + input[2] y: int + + t1 = new T(expected = 42) + t2 = new T(expected = 43) + + y -> t1.z, t2.z } main reactor { - d = new D(); - reaction(startup) -> d.y {= - lf_set(d.y[0], 42); - =} - reaction(startup) -> d.y {= - lf_set(d.y[1], 43); - =} + d = new D() + + reaction(startup) -> d.y {= lf_set(d.y[0], 42); =} + + reaction(startup) -> d.y {= lf_set(d.y[1], 43); =} } diff --git a/test/C/src/multiport/TriggerDownstreamOnlyIfPresent.lf b/test/C/src/multiport/TriggerDownstreamOnlyIfPresent.lf index 3fc68f7439..7714d65396 100644 --- a/test/C/src/multiport/TriggerDownstreamOnlyIfPresent.lf +++ b/test/C/src/multiport/TriggerDownstreamOnlyIfPresent.lf @@ -1,15 +1,17 @@ /** - * This test checks that a downstream reaction is triggered only if its trigger is present. + * This test checks that a downstream reaction is triggered only if its trigger + * is present. */ -target C { - timeout: 1 sec, - fast: true -}; +target C { timeout: 1 sec, fast: true } + reactor Source { - output a:int; - output b:int; - state count:int(0); - timer t(0, 200 msec); + output a: int + output b: int + + timer t(0, 200 msec) + + state count: int(0) + reaction(t) -> a, b {= if (self->count++ % 2 == 0) { lf_set(a, self->count); @@ -18,15 +20,18 @@ reactor Source { } =} } + reactor Destination { - input a:int; - input b:int; + input a: int + input b: int + reaction(a) {= if (!a->is_present) { fprintf(stderr, "Reaction to a triggered even though all inputs are absent!\n"); exit(1); } =} + reaction(b) {= if (!b->is_present) { fprintf(stderr, "Reaction to b triggered even though all inputs are absent!\n"); @@ -36,8 +41,9 @@ reactor Destination { } main reactor TriggerDownstreamOnlyIfPresent { - s = new[2] Source(); - d = new[2] Destination(); - s.a -> d.a; - s.b -> d.b; + s = new[2] Source() + d = new[2] Destination() + + s.a -> d.a + s.b -> d.b } diff --git a/test/C/src/serialization/PersonProtocolBuffers.lf b/test/C/src/serialization/PersonProtocolBuffers.lf index 62c5efd2e3..daf0c873e2 100644 --- a/test/C/src/serialization/PersonProtocolBuffers.lf +++ b/test/C/src/serialization/PersonProtocolBuffers.lf @@ -1,26 +1,25 @@ -/** This example demonstrates a very simple use of protocol buffers - * within a reactor. It encodes and decodes a very simple protocol - * buffer definition in Person.proto. This reactor is heavily - * based on the examples at https://github.com/protobuf-c/protobuf-c/wiki/Examples. - * This example just packs and unpacks a message. +/** + * This example demonstrates a very simple use of protocol buffers within a + * reactor. It encodes and decodes a very simple protocol buffer definition in + * Person.proto. This reactor is heavily based on the examples at + * https://github.com/protobuf-c/protobuf-c/wiki/Examples. This example just + * packs and unpacks a message. * - * To run this example first install the protocol buffers compiler - * from https://github.com/protocolbuffers/protobuf. It is also - * available from homebrew on a Mac via + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from + * homebrew on a Mac via * - * $ brew install protobuf + * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that - * if possible. Next install the C plugin for protocol buffers from + * Building protobuf from source is slow, so avoid doing that if possible. Next + * install the C plugin for protocol buffers from * - * https://github.com/protobuf-c/protobuf-c + * https://github.com/protobuf-c/protobuf-c * - * The code generator assumes - * that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. + * The code generator assumes that executables are installed within the PATH. On + * a Mac, this is typically at /usr/local/bin. */ - -target C {protobufs: Person.proto}; +target C { protobufs: Person.proto } main reactor { reaction(startup) {= diff --git a/test/C/src/serialization/ProtoNoPacking.lf b/test/C/src/serialization/ProtoNoPacking.lf index c593f3e839..ab14f4be4e 100644 --- a/test/C/src/serialization/ProtoNoPacking.lf +++ b/test/C/src/serialization/ProtoNoPacking.lf @@ -1,27 +1,28 @@ -/** This example creates a Protocol Buffer message and passes it to - * another reactor without packing and unpacking. This demonstrates - * that local communication, within one shared-memory machine, need - * not incur the overhead of packing and unpacking. +/** + * This example creates a Protocol Buffer message and passes it to another + * reactor without packing and unpacking. This demonstrates that local + * communication, within one shared-memory machine, need not incur the overhead + * of packing and unpacking. * - * To run this example first install the protocol buffers compiler - * from https://github.com/protocolbuffers/protobuf. It is also - * available from homebrew on a Mac via + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from + * homebrew on a Mac via * - * $ brew install protobuf + * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that - * if possible. Next install the C plugin for protocol buffers from + * Building protobuf from source is slow, so avoid doing that if possible. Next + * install the C plugin for protocol buffers from * - * https://github.com/protobuf-c/protobuf-c + * https://github.com/protobuf-c/protobuf-c * - * The code generator assumes - * that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. + * The code generator assumes that executables are installed within the PATH. On + * a Mac, this is typically at /usr/local/bin. */ -target C {protobufs: [ProtoHelloWorld.proto]}; +target C { protobufs: [ProtoHelloWorld.proto] } reactor SourceProto { - output out:ProtoHelloWorld; + output out: ProtoHelloWorld + reaction(startup) -> out {= out->value.name = "Hello World"; out->value.number = 42; @@ -30,13 +31,18 @@ reactor SourceProto { } reactor SinkProto { - input in:ProtoHelloWorld; - reaction(in) {= + input in: ProtoHelloWorld + + reaction( + in + ) {= printf("Received: name=\"%s\", number=%d.\n", in->value.name, in->value.number); =} } + main reactor ProtoNoPacking { - s = new SourceProto(); - d = new SinkProto(); - s.out -> d.in; + s = new SourceProto() + d = new SinkProto() + + s.out -> d.in } diff --git a/test/C/src/serialization/ROSBuiltInSerialization.lf b/test/C/src/serialization/ROSBuiltInSerialization.lf index bf90730bb8..53f35d1aa6 100644 --- a/test/C/src/serialization/ROSBuiltInSerialization.lf +++ b/test/C/src/serialization/ROSBuiltInSerialization.lf @@ -33,7 +33,7 @@ preamble {= reactor Sender { output out:std_msgs::msg::Int32; - // state serialized_msg_pcl:rclcpp::SerializedMessage({=0u=}); + /* state serialized_msg_pcl:rclcpp::SerializedMessage({=0u=}); */ state count:int(0); timer t (0, 1 sec); From 587c3c8e6eb4eb4b768daa742411574df23147a1 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 02:20:51 -0700 Subject: [PATCH 076/130] [formatting] Wrap single-line file-level comments. This makes treatment of those comments consistent with treatment of other comments. --- org.lflang/src/org/lflang/ast/FormattingUtils.java | 4 ++-- org.lflang/src/org/lflang/ast/MalleableString.java | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index dff659c4ca..1061f3cf44 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -54,10 +54,10 @@ public static String render(EObject object, int lineLength) { lineLength ); var optimizedRendering = ms.render(); - String comments = optimizedRendering.unplacedComments().map(s -> lineWrapComment(s, lineLength)) + String comments = optimizedRendering.unplacedComments() .collect(Collectors.joining(System.lineSeparator())); return comments.isBlank() ? optimizedRendering.rendering() - : comments + System.lineSeparator() + optimizedRendering.rendering(); + : lineWrapComment(comments, lineLength) + System.lineSeparator() + optimizedRendering.rendering(); } /** diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index dc6edf19e1..7c6ffd559f 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -300,9 +300,10 @@ public boolean isEmpty() { @Override public RenderResult render() { var result = nested.render(); - String renderedComments = result.unplacedComments.map( - s -> FormattingUtils.lineWrapComment(s, width - indentation) - ).collect(Collectors.joining(System.lineSeparator())); + String renderedComments = FormattingUtils.lineWrapComment( + result.unplacedComments.collect(Collectors.joining(System.lineSeparator())), + width - indentation + ); return new RenderResult( this.comments.stream(), ( From a73af37d821c48142a46cc068d2b970d2dc340ab Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 02:42:13 -0700 Subject: [PATCH 077/130] [formatting] Address CI failure. --- org.lflang/src/org/lflang/ast/ToLf.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index dd8d31b898..5dcf8a3cce 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -456,7 +456,7 @@ public MalleableString caseMethod(Method object) { @Override public MalleableString caseMethodArgument(MethodArgument object) { // name=ID (':' type=Type)? - return MalleableString.anyOf(object.getName() + typeAnnotationFor(object.getType())); + return new Builder().append(object.getName()).append(typeAnnotationFor(object.getType())).get(); } @Override From 89f4b5257c94e0969f90130f55d6e82c31ab7582 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Mon, 4 Jul 2022 02:42:47 -0700 Subject: [PATCH 078/130] [formatting] Format more C tests. --- test/C/src/ActionDelay.lf | 40 +++++++------ test/C/src/ActionIsPresent.lf | 12 ++-- test/C/src/ActionWithNoReaction.lf | 42 +++++++------- test/C/src/After.lf | 45 ++++++++------- test/C/src/AfterCycles.lf | 35 ++++++------ test/C/src/AfterOverlapped.lf | 24 ++++---- test/C/src/AfterZero.lf | 45 ++++++++------- test/C/src/Alignment.lf | 58 ++++++++++--------- test/C/src/ArrayAsParameter.lf | 38 ++++++++----- test/C/src/ArrayAsType.lf | 25 +++++---- test/C/src/ArrayFree.lf | 35 ++++++------ test/C/src/ArrayParallel.lf | 33 ++++++----- test/C/src/ArrayPrint.lf | 24 ++++---- test/C/src/ArrayScale.lf | 34 ++++++----- test/C/src/CharLiteralInitializer.lf | 6 +- test/C/src/Composition.lf | 35 +++++++----- test/C/src/CompositionAfter.lf | 37 ++++++------ test/C/src/CompositionGain.lf | 32 +++++++---- test/C/src/CompositionInheritance.lf | 44 +++++++++------ test/C/src/CountSelf.lf | 25 +++++---- test/C/src/CountTest.lf | 17 +++--- test/C/src/DanglingOutput.lf | 28 ++++++---- test/C/src/Deadline.lf | 38 +++++++------ test/C/src/DeadlineAnytime.lf | 18 +++--- test/C/src/DeadlineHandledAbove.lf | 24 +++++--- test/C/src/DeadlineZero.lf | 31 +++++----- test/C/src/DelayArray.lf | 42 ++++++++------ test/C/src/DelayArrayWithAfter.lf | 39 +++++++------ test/C/src/DelayInt.lf | 44 +++++++++------ test/C/src/DelayPointer.lf | 43 +++++++++----- test/C/src/DelayString.lf | 42 ++++++++------ test/C/src/DelayStruct.lf | 37 +++++++----- test/C/src/DelayStructWithAfter.lf | 20 ++++--- test/C/src/DelayStructWithAfterOverlapped.lf | 34 ++++++----- test/C/src/DelayedAction.lf | 19 +++---- test/C/src/DelayedReaction.lf | 23 ++++---- test/C/src/Determinism.lf | 47 +++++++++------- test/C/src/DoubleInvocation.lf | 59 ++++++++++---------- test/C/src/DoublePort.lf | 56 +++++++++---------- test/C/src/DoubleReaction.lf | 42 +++++++------- test/C/src/DoubleTrigger.lf | 19 ++++--- 41 files changed, 779 insertions(+), 612 deletions(-) diff --git a/test/C/src/ActionDelay.lf b/test/C/src/ActionDelay.lf index 2c062cb774..528321a709 100644 --- a/test/C/src/ActionDelay.lf +++ b/test/C/src/ActionDelay.lf @@ -1,28 +1,32 @@ // Test logical action with delay. -target C; +target C reactor GeneratedDelay { - input y_in:int; - output y_out:int; - state y_state:int(0); - logical action act(100 msec); + input y_in: int + + output y_out: int + + logical action act(100 msec) + + state y_state: int(0) + reaction(y_in) -> act {= self->y_state = y_in->value; lf_schedule(act, MSEC(0)); =} - reaction(act) -> y_out {= - lf_set(y_out, self->y_state); - =} + reaction(act) -> y_out {= lf_set(y_out, self->y_state); =} } + reactor Source { - output out:int; - reaction(startup) -> out {= - lf_set(out, 1); - =} + output out: int + + reaction(startup) -> out {= lf_set(out, 1); =} } + reactor Sink { - input in:int; + input in: int + reaction(in) {= interval_t elapsed_logical = lf_time_logical_elapsed(); interval_t logical = lf_time_logical(); @@ -38,10 +42,10 @@ reactor Sink { } main reactor ActionDelay { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); + source = new Source() + sink = new Sink() + g = new GeneratedDelay() - source.out -> g.y_in; - g.y_out -> sink.in; + source.out -> g.y_in + g.y_out -> sink.in } diff --git a/test/C/src/ActionIsPresent.lf b/test/C/src/ActionIsPresent.lf index 2431d9ed24..b5831c278e 100644 --- a/test/C/src/ActionIsPresent.lf +++ b/test/C/src/ActionIsPresent.lf @@ -1,8 +1,11 @@ // Tests the is_present variable for actions. -target C; -main reactor ActionIsPresent(offset:time(1 nsec), period:time(500 msec)) { - logical action a; - state success:bool(false); +target C + +main reactor ActionIsPresent(offset: time(1 nsec), period: time(500 msec)) { + logical action a + + state success: bool(false) + reaction(startup, a) -> a {= if (!a->is_present) { if (self->offset == 0) { @@ -16,6 +19,7 @@ main reactor ActionIsPresent(offset:time(1 nsec), period:time(500 msec)) { self->success = true; } =} + reaction(shutdown) {= if (!self->success) { fprintf(stderr, "Failed to print 'Hello World'\n"); diff --git a/test/C/src/ActionWithNoReaction.lf b/test/C/src/ActionWithNoReaction.lf index 9eb8f7fd5a..5b48c2f630 100644 --- a/test/C/src/ActionWithNoReaction.lf +++ b/test/C/src/ActionWithNoReaction.lf @@ -1,23 +1,24 @@ -// This checks that action can be created even if there is no reaction. -// This test passes merely by compiling and executing without a segfault. -// Its other functionality is tested by other tests. -target C { - fast: true, - timeout: 3 sec -}; +// This checks that action can be created even if there is no reaction. This +// test passes merely by compiling and executing without a segfault. Its other +// functionality is tested by other tests. +target C { fast: true, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - logical action a:int*; - reaction(x) -> y, a {= + input x: int + + output y: int + + logical action a: int* + + reaction(x) -> y, a {= // reaction(a) {= =} lf_set(y, 2*x->value); lf_schedule(a, MSEC(500)); =} - // reaction(a) {= =} } reactor print { - input x:int; + input x: int + reaction(x) {= printf("Result is %d\n", x->value); printf("Current logical time is: %lld\n", lf_time_logical_elapsed()); @@ -26,11 +27,12 @@ reactor print { } main reactor ActionWithNoReaction { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - lf_set(f.x, 42); - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= lf_set(f.x, 42); =} } diff --git a/test/C/src/After.lf b/test/C/src/After.lf index d05084c443..99fcdbb239 100644 --- a/test/C/src/After.lf +++ b/test/C/src/After.lf @@ -1,20 +1,21 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target C { - fast: false, - timeout: 3 sec -}; +// This checks that the after keyword adjusts logical time, not using physical +// time. +target C { fast: false, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - reaction(x) -> y {= - lf_set(y, 2*x->value); - =} + input x: int + + output y: int + + reaction(x) -> y {= lf_set(y, 2*x->value); =} } + reactor print { - state expected_time:time(10 msec); - state received:int(0); - input x:int; + input x: int + + state expected_time: time(10 msec) + state received: int(0) + reaction(x) {= self->received++; interval_t elapsed_time = lf_time_logical_elapsed(); @@ -31,6 +32,7 @@ reactor print { } self->expected_time += SEC(1); =} + reaction(shutdown) {= if (self->received == 0) { printf("ERROR: Final reactor received no data.\n"); @@ -40,11 +42,12 @@ reactor print { } main reactor After { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - lf_set(f.x, 42); - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= lf_set(f.x, 42); =} } diff --git a/test/C/src/AfterCycles.lf b/test/C/src/AfterCycles.lf index 193ad05741..64dd04bf7d 100644 --- a/test/C/src/AfterCycles.lf +++ b/test/C/src/AfterCycles.lf @@ -1,31 +1,30 @@ -// This tests that "after" does not introduce spurious cycles. -// Success if running without detected a cycle. -target C; +// This tests that "after" does not introduce spurious cycles. Success if +// running without detected a cycle. +target C reactor Source { - output out:unsigned; + output out: unsigned - reaction(startup) -> out {= - lf_set(out, 1); - =} + reaction(startup) -> out {= lf_set(out, 1); =} } + reactor Work { - input in:unsigned; - output out:unsigned; + input in: unsigned - reaction(in) -> out {= - lf_set(out, in->value); - =} + output out: unsigned + + reaction(in) -> out {= lf_set(out, in->value); =} } main reactor AfterCycles { - state count:int(0); - s = new Source(); - w0 = new Work(); - w1 = new Work(); + s = new Source() + w0 = new Work() + w1 = new Work() + + s.out -> w0.in after 10 msec + s.out -> w1.in after 20 msec - s.out -> w0.in after 10 msec; - s.out -> w1.in after 20 msec; + state count: int(0) reaction(w0.out) {= self->count++; diff --git a/test/C/src/AfterOverlapped.lf b/test/C/src/AfterOverlapped.lf index b086536a1e..f19697e734 100644 --- a/test/C/src/AfterOverlapped.lf +++ b/test/C/src/AfterOverlapped.lf @@ -1,14 +1,14 @@ // This the after keyword with overlapped time intervals. -target C { - fast: true, - timeout: 5 sec -}; -import Count from "lib/Count.lf"; +target C { fast: true, timeout: 5 sec } + +import Count from "lib/Count.lf" reactor Test { - input c:int; - state i:int(0); - state received:int(0); + input c: int + + state i: int(0) + state received: int(0) + reaction(c) {= self->received++; printf("Received %d.\n", c->value); @@ -28,6 +28,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (self->received == 0) { printf("ERROR: Final reactor received no data.\n"); @@ -37,7 +38,8 @@ reactor Test { } main reactor AfterOverlapped { - count = new Count(); - test = new Test(); - count.out -> test.c after 2 sec; + count = new Count() + test = new Test() + + count.out -> test.c after 2 sec } diff --git a/test/C/src/AfterZero.lf b/test/C/src/AfterZero.lf index b40ea77079..54904961bb 100644 --- a/test/C/src/AfterZero.lf +++ b/test/C/src/AfterZero.lf @@ -1,20 +1,21 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target C { - fast: false, - timeout: 3 sec -}; +// This checks that the after keyword adjusts logical time, not using physical +// time. +target C { fast: false, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - reaction(x) -> y {= - SET(y, 2*x->value); - =} + input x: int + + output y: int + + reaction(x) -> y {= SET(y, 2*x->value); =} } + reactor print { - state expected_time:time(0); - state received:int(0); - input x:int; + input x: int + + state expected_time: time(0) + state received: int(0) + reaction(x) {= self->received++; interval_t elapsed_time = get_elapsed_logical_time(); @@ -36,6 +37,7 @@ reactor print { } self->expected_time += SEC(1); =} + reaction(shutdown) {= if (self->received == 0) { printf("ERROR: Final reactor received no data.\n"); @@ -45,11 +47,12 @@ reactor print { } main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - SET(f.x, 42); - =} - f.y -> p.x after 0; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 0 + + reaction(t) -> f.x {= SET(f.x, 42); =} } diff --git a/test/C/src/Alignment.lf b/test/C/src/Alignment.lf index b1b8239d73..4d168dbe96 100644 --- a/test/C/src/Alignment.lf +++ b/test/C/src/Alignment.lf @@ -1,28 +1,32 @@ -// This test checks that the downstream reaction is not invoked more -// than once at a logical time. -target C { - logging: LOG, - timeout: 1 sec -} +// This test checks that the downstream reaction is not invoked more than once +// at a logical time. +target C { logging: LOG, timeout: 1 sec } + reactor Source { - output out:int; - state count:int(1); - timer t(0, 100 msec); - reaction(t) -> out {= - lf_set(out, self->count++); - =} + output out: int + + timer t(0, 100 msec) + + state count: int(1) + + reaction(t) -> out {= lf_set(out, self->count++); =} } + reactor Sieve { - input in:int; - output out:bool; - state primes:int*({= NULL =}); - state last_prime:int(0); + input in: int + + output out: bool + + state primes: int*({= NULL =}) + state last_prime: int(0) + reaction(startup) {= // There are 1229 primes between 1 and 10,000. self->primes = (int*)calloc(1229, sizeof(int)); // Primes 1 and 2 are not on the list. self->primes[0] = 3; =} + reaction(in) -> out {= // Reject inputs that are out of bounds. if (in->value <= 0 || in->value > 10000) { @@ -69,9 +73,11 @@ reactor Sieve { } reactor Destination { - input ok:bool; - input in:int; - state last_invoked:tag_t({= NEVER_TAG_INITIALIZER =}); + input ok: bool + input in: int + + state last_invoked: tag_t({= NEVER_TAG_INITIALIZER =}) + reaction(ok, in) {= if (ok->is_present && in->is_present) { lf_print("Destination: Input %d is prime at tag (%lld, %d).", @@ -89,11 +95,13 @@ reactor Destination { self->last_invoked = current_tag; =} } + main reactor { - source = new Source(); - sieve = new Sieve(); - destination = new Destination(); - source.out -> sieve.in; - sieve.out -> destination.ok; - source.out -> destination.in; + source = new Source() + sieve = new Sieve() + destination = new Destination() + + source.out -> sieve.in + sieve.out -> destination.ok + source.out -> destination.in } diff --git a/test/C/src/ArrayAsParameter.lf b/test/C/src/ArrayAsParameter.lf index c1a2304fb9..27049f6274 100644 --- a/test/C/src/ArrayAsParameter.lf +++ b/test/C/src/ArrayAsParameter.lf @@ -1,11 +1,15 @@ -// Source has an array as a parameter, the elements of which it passes -// to Print. The length of the array has to also be a parameter because -// C arrays do not encode their own length. -target C; -reactor Source(sequence:int[](0, 1, 2), n_sequence:int(3)) { - output out:int; - state count:int(0); - logical action next; +// Source has an array as a parameter, the elements of which it passes to Print. +// The length of the array has to also be a parameter because C arrays do not +// encode their own length. +target C + +reactor Source(sequence: int[](0, 1, 2), n_sequence: int(3)) { + output out: int + + logical action next + + state count: int(0) + reaction(startup, next) -> out, next {= lf_set(out, self->sequence[self->count]); self->count++; @@ -14,10 +18,13 @@ reactor Source(sequence:int[](0, 1, 2), n_sequence:int(3)) { } =} } + reactor Print { - input in:int; - state count:int(1); - state received:int(0); + input in: int + + state count: int(1) + state received: int(0) + reaction(in) {= self->received++; printf("Received: %d\n", in->value); @@ -27,6 +34,7 @@ reactor Print { } self->count++; =} + reaction(shutdown) {= if (self->received == 0) { printf("ERROR: Final reactor received no data.\n"); @@ -34,8 +42,10 @@ reactor Print { } =} } + main reactor ArrayAsParameter { - s = new Source(sequence = (1, 2, 3, 4), n_sequence=4); - p = new Print(); - s.out -> p.in; + s = new Source(sequence = (1, 2, 3, 4), n_sequence = 4) + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/ArrayAsType.lf b/test/C/src/ArrayAsType.lf index 3d056c075b..b9c40fe894 100644 --- a/test/C/src/ArrayAsType.lf +++ b/test/C/src/ArrayAsType.lf @@ -1,8 +1,10 @@ -// Source produces a statically allocated array, which it passes -// to Print. The destination references the array directly. -target C; +// Source produces a statically allocated array, which it passes to Print. The +// destination references the array directly. +target C + reactor Source { - output out:int[3]; + output out: int[3] + reaction(startup) -> out {= out->value[0] = 0; out->value[1] = 1; @@ -10,9 +12,10 @@ reactor Source { SET_PRESENT(out); =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int[3]; + +reactor Print(scale: int(1)) { // The scale parameter is just for testing. + input in: int[3] + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -33,8 +36,10 @@ reactor Print(scale:int(1)) { } =} } + main reactor ArrayAsType { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/ArrayFree.lf b/test/C/src/ArrayFree.lf index 64c0d5d8fd..29cd422eea 100644 --- a/test/C/src/ArrayFree.lf +++ b/test/C/src/ArrayFree.lf @@ -1,26 +1,29 @@ -// Source produces a dynamically allocated array, which it passes -// to Free. Free requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It then does nothing further with it. This test checks +// Source produces a dynamically allocated array, which it passes to Free. Free +// requests a writable copy, which, instead of copying, it just gets ownership +// of the original array. It then does nothing further with it. This test checks // that the memory gets freed automatically even with the mutable input. -target C; -import Source, Print from "ArrayPrint.lf"; -import Scale from "ArrayScale.lf"; +target C + +import Source, Print from "ArrayPrint.lf" +import Scale from "ArrayScale.lf" + +reactor Free(scale: int(2)) { + mutable input in: int[] -reactor Free(scale:int(2)) { - mutable input in:int[]; reaction(in) {= for(int i = 0; i < in->length; i++) { in->value[i] *= self->scale; } =} } + main reactor ArrayFree { - s = new Source(); - c = new Free(); - c2 = new Scale(); - p = new Print(scale = 2); - s.out -> c.in; - s.out -> c2.in; - c2.out -> p.in; + s = new Source() + c = new Free() + c2 = new Scale() + p = new Print(scale = 2) + + s.out -> c.in + s.out -> c2.in + c2.out -> p.in } diff --git a/test/C/src/ArrayParallel.lf b/test/C/src/ArrayParallel.lf index 7dfe222420..9026a374db 100644 --- a/test/C/src/ArrayParallel.lf +++ b/test/C/src/ArrayParallel.lf @@ -1,19 +1,22 @@ -// Source allocates an array dynamically and then sends it to two reactors, -// each of which want to modify it. -// NOTE: Ideally, only one copy would be made, but this requires -// modifying the precedence graph between reactions. -target C; -import Scale from "ArrayScale.lf"; +// Source allocates an array dynamically and then sends it to two reactors, each +// of which want to modify it. +// +// NOTE: Ideally, only one copy would be made, but this requires modifying the +// precedence graph between reactions. +target C + +import Scale from "ArrayScale.lf" import Source, Print from "ArrayPrint.lf" main reactor ArrayParallel { - s = new Source(); - c1 = new Scale(); - c2 = new Scale(scale = 3); - p1 = new Print(scale = 2); - p2 = new Print(scale = 3); - s.out -> c1.in; - s.out -> c2.in; - c1.out -> p1.in; - c2.out -> p2.in; + s = new Source() + c1 = new Scale() + c2 = new Scale(scale = 3) + p1 = new Print(scale = 2) + p2 = new Print(scale = 3) + + s.out -> c1.in + s.out -> c2.in + c1.out -> p1.in + c2.out -> p2.in } diff --git a/test/C/src/ArrayPrint.lf b/test/C/src/ArrayPrint.lf index 0a1b8549ac..1f0a7bf34b 100644 --- a/test/C/src/ArrayPrint.lf +++ b/test/C/src/ArrayPrint.lf @@ -1,8 +1,10 @@ -// Source produces a dynamically allocated array, which it passes -// to Print. Reference counting ensures that the array is freed. -target C; +// Source produces a dynamically allocated array, which it passes to Print. +// Reference counting ensures that the array is freed. +target C + reactor Source { - output out:int[]; + output out: int[] + reaction(startup) -> out {= // Dynamically allocate an output array of length 3. SET_NEW_ARRAY(out, 3); @@ -13,9 +15,10 @@ reactor Source { out->value[2] = 2; =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int[]; + +reactor Print(scale: int(1)) { // The scale parameter is just for testing. + input in: int[] + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -38,7 +41,8 @@ reactor Print(scale:int(1)) { } main reactor ArrayPrint { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/ArrayScale.lf b/test/C/src/ArrayScale.lf index ef3d056ca8..209007192f 100644 --- a/test/C/src/ArrayScale.lf +++ b/test/C/src/ArrayScale.lf @@ -1,14 +1,16 @@ -// Source produces a dynamically allocated array, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target C; -import Print, Source from "ArrayPrint.lf"; +// Source produces a dynamically allocated array, which it passes to Scale. +// Scale requests a writable copy, which, instead of copying, it just gets +// ownership of the original array. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target C + +import Print, Source from "ArrayPrint.lf" + +reactor Scale(scale: int(2)) { + mutable input in: int[] + + output out: int[] -reactor Scale(scale:int(2)) { - mutable input in:int[]; - output out:int[]; reaction(in) -> out {= for(int i = 0; i < in->length; i++) { in->value[i] *= self->scale; @@ -16,10 +18,12 @@ reactor Scale(scale:int(2)) { lf_set_token(out, in->token); =} } + main reactor ArrayScale { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.in + c.out -> p.in } diff --git a/test/C/src/CharLiteralInitializer.lf b/test/C/src/CharLiteralInitializer.lf index f881e72c78..9ee206efbf 100644 --- a/test/C/src/CharLiteralInitializer.lf +++ b/test/C/src/CharLiteralInitializer.lf @@ -1,7 +1,9 @@ // Check that a state variable can have a char literal initializer -target C; +target C + main reactor CharLiteralInitializer { - state c: char('x'); + state c: char('x') + reaction(startup) {= if (self->c != 'x') { fprintf(stderr, "FAILED: Expected 'x', got %c.\n", self->c); diff --git a/test/C/src/Composition.lf b/test/C/src/Composition.lf index 468f1c5c5f..98ac349f71 100644 --- a/test/C/src/Composition.lf +++ b/test/C/src/Composition.lf @@ -1,13 +1,14 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; printf("Source sending %d.\n", self->count); @@ -16,8 +17,10 @@ reactor Source(period:time(2 sec)) { } reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -26,15 +29,17 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (self->count == 0) { fprintf(stderr, "FAILURE: No data received.\n"); } =} } + main reactor Composition { - s = new Source(); + s = new Source() + d = new Test() - d = new Test(); - s.y -> d.x; + s.y -> d.x } diff --git a/test/C/src/CompositionAfter.lf b/test/C/src/CompositionAfter.lf index 10b93329b7..7c9c9c5e06 100644 --- a/test/C/src/CompositionAfter.lf +++ b/test/C/src/CompositionAfter.lf @@ -1,14 +1,14 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - fast: true, - timeout: 10 sec -}; - -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; lf_set(y, self->count); @@ -16,8 +16,10 @@ reactor Source(period:time(2 sec)) { } reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -28,8 +30,9 @@ reactor Test { =} } -main reactor CompositionAfter(delay:time(5 sec)) { - s = new Source(); - d = new Test(); - s.y -> d.x after delay; +main reactor CompositionAfter(delay: time(5 sec)) { + s = new Source() + d = new Test() + + s.y -> d.x after delay } diff --git a/test/C/src/CompositionGain.lf b/test/C/src/CompositionGain.lf index 39be56cf43..f364251398 100644 --- a/test/C/src/CompositionGain.lf +++ b/test/C/src/CompositionGain.lf @@ -1,25 +1,33 @@ // This tests send data through a contained reactor. -target C; +target C + reactor Gain { - input gainin:int; - output y:int; + input gainin: int + + output y: int + reaction(gainin) -> y {= printf("Gain received %d\n", gainin->value); lf_set(y, gainin->value * 2); =} } + reactor Wrapper { - input x:int; - output y:int; - gain = new Gain(); - x -> gain.gainin; - gain.y -> y; + input x: int + + output y: int + + gain = new Gain() + + x -> gain.gainin + gain.y -> y } + main reactor CompositionGain { - wrapper = new Wrapper(); - reaction(startup) -> wrapper.x {= - lf_set(wrapper.x, 42); - =} + wrapper = new Wrapper() + + reaction(startup) -> wrapper.x {= lf_set(wrapper.x, 42); =} + reaction(wrapper.y) {= printf("Received %d\n", wrapper.y->value); if (wrapper.y->value != 42 * 2) { diff --git a/test/C/src/CompositionInheritance.lf b/test/C/src/CompositionInheritance.lf index 568a7aa3d5..31c2f0c060 100644 --- a/test/C/src/CompositionInheritance.lf +++ b/test/C/src/CompositionInheritance.lf @@ -1,14 +1,16 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - input foo:int; - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + input foo: int + + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= printf("Hello World. At time %lld, my count is: %d.\n", lf_time_logical_elapsed(), self->count); lf_set(y, self->count); @@ -16,8 +18,10 @@ reactor Source(period:time(2 sec)) { } reactor SourceExtended extends Source { - output y2: int; - timer t2(1 sec, 3 sec); + output y2: int + + timer t2(1 sec, 3 sec) + reaction(t2) -> y2 {= (self->count)++; printf("At time %lld, source sending %d.\n", lf_time_logical_elapsed(), self->count); @@ -26,8 +30,10 @@ reactor SourceExtended extends Source { } reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -36,15 +42,17 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (self->count == 0) { fprintf(stderr, "FAILURE: No data received.\n"); } =} } + main reactor CompositionInheritance { - s = new SourceExtended(period = 2 sec); + s = new SourceExtended(period = 2 sec) + d = new Test() - d = new Test(); - s.y2 -> d.x; + s.y2 -> d.x } diff --git a/test/C/src/CountSelf.lf b/test/C/src/CountSelf.lf index c0e7429352..171d488677 100644 --- a/test/C/src/CountSelf.lf +++ b/test/C/src/CountSelf.lf @@ -1,24 +1,27 @@ // This tests actions with payloads by delaying an input by a fixed amount. -target C { - timeout: 1 sec, - fast: true -}; -import TestCount from "lib/TestCount.lf"; +target C { timeout: 1 sec, fast: true } + +import TestCount from "lib/TestCount.lf" + +reactor CountSelf2(delay: time(100 msec)) { + output out: int + + logical action a: int -reactor CountSelf2(delay:time(100 msec)) { - output out:int; - logical action a:int; reaction(startup) -> a, out {= lf_set(out, 0); lf_schedule_int(a, self->delay, 1); =} + reaction(a) -> a, out {= lf_set(out, a->value); lf_schedule_int(a, self->delay, a->value + 1); =} } + main reactor { - d = new CountSelf2(); - t = new TestCount(num_inputs = 11, start = 0); - d.out -> t.in; + d = new CountSelf2() + t = new TestCount(num_inputs = 11, start = 0) + + d.out -> t.in } diff --git a/test/C/src/CountTest.lf b/test/C/src/CountTest.lf index 5aa1e6eed0..7ab7d697ed 100644 --- a/test/C/src/CountTest.lf +++ b/test/C/src/CountTest.lf @@ -1,14 +1,11 @@ -target C { - timeout: 3 sec, - tracing: true, - fast: true -}; +target C { timeout: 3 sec, tracing: true, fast: true } -import Count from "lib/Count.lf"; -import TestCount from "lib/TestCount.lf"; +import Count from "lib/Count.lf" +import TestCount from "lib/TestCount.lf" main reactor CountTest { - count = new Count(); - test = new TestCount(num_inputs = 4); - count.out -> test.in; + count = new Count() + test = new TestCount(num_inputs = 4) + + count.out -> test.in } diff --git a/test/C/src/DanglingOutput.lf b/test/C/src/DanglingOutput.lf index d7625c697e..5de6c25b47 100644 --- a/test/C/src/DanglingOutput.lf +++ b/test/C/src/DanglingOutput.lf @@ -1,17 +1,20 @@ // This tests that an output that is not connected to anything does not result -// in a compilation error. Passing the test is just compiling and running. -target C; +// in a compilation error. Passing the test is just compiling and running. +target C + reactor Source { - output out:int; - timer t; - reaction(t) -> out {= - lf_set(out, 1); - =} + output out: int + + timer t + + reaction(t) -> out {= lf_set(out, 1); =} } reactor Gain { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= printf("Received %d.\n", in->value); lf_set(out, in->value * 2); @@ -19,7 +22,8 @@ reactor Gain { } main reactor DanglingOutput { - source = new Source(); - container = new Gain(); - source.out -> container.in; + source = new Source() + container = new Gain() + + source.out -> container.in } diff --git a/test/C/src/Deadline.lf b/test/C/src/Deadline.lf index 890944971a..a85dac4bee 100644 --- a/test/C/src/Deadline.lf +++ b/test/C/src/Deadline.lf @@ -1,13 +1,15 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target C { - timeout: 6 sec -}; -reactor Source(period:time(3 sec)) { - output y:int; - timer t(0, period); - state count:int(0); +// This example illustrates local deadline handling. Even numbers are sent by +// the Source immediately, whereas odd numbers are sent after a big enough delay +// to violate the deadline. +target C { timeout: 6 sec } + +reactor Source(period: time(3 sec)) { + output y: int + + timer t(0, period) + + state count: int(0) + reaction(t) -> y {= if (2 * (self->count / 2) != self->count) { // The count variable is odd. @@ -24,9 +26,11 @@ reactor Source(period:time(3 sec)) { =} } -reactor Destination(timeout:time(1 sec)) { - input x:int; - state count:int(0); +reactor Destination(timeout: time(1 sec)) { + input x: int + + state count: int(0) + reaction(x) {= printf("Destination receives: %d\n", x->value); if (2 * (self->count / 2) != self->count) { @@ -45,8 +49,10 @@ reactor Destination(timeout:time(1 sec)) { (self->count)++; =} } + main reactor Deadline { - s = new Source(); - d = new Destination(timeout = 1 sec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 1 sec) + + s.y -> d.x } diff --git a/test/C/src/DeadlineAnytime.lf b/test/C/src/DeadlineAnytime.lf index e6760e4546..6f91fa0fbd 100644 --- a/test/C/src/DeadlineAnytime.lf +++ b/test/C/src/DeadlineAnytime.lf @@ -1,19 +1,17 @@ // Test whether the lf_check_deadline function works. -target C; +target C reactor A { - state i:int; - logical action a; + logical action a + + state i: int + reaction(startup) -> a {= self->i = 0; while (!lf_check_deadline(self, true)); - =} deadline(10 msec) {= - lf_schedule(a, 0); - =} + =} deadline(10 msec) {= lf_schedule(a, 0); =} - reaction(a) {= - self->i = 42; - =} + reaction(a) {= self->i = 42; =} reaction(shutdown) {= if (self->i == 42) { @@ -25,5 +23,5 @@ reactor A { } main reactor { - a = new A(); + a = new A() } diff --git a/test/C/src/DeadlineHandledAbove.lf b/test/C/src/DeadlineHandledAbove.lf index 3adf42b760..dcdc53f47b 100644 --- a/test/C/src/DeadlineHandledAbove.lf +++ b/test/C/src/DeadlineHandledAbove.lf @@ -1,9 +1,12 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target C; -reactor Deadline(threshold:time(100 msec)) { - input x:int; - output deadline_violation:bool; +// Test a deadline where the deadline violation produces an output and the +// container reacts to that output. +target C + +reactor Deadline(threshold: time(100 msec)) { + input x: int + + output deadline_violation: bool + reaction(x) -> deadline_violation {= printf("ERROR: Deadline violation was not detected!\n"); exit(1); @@ -12,9 +15,12 @@ reactor Deadline(threshold:time(100 msec)) { lf_set(deadline_violation, true); =} } + main reactor DeadlineHandledAbove { - state violation_detected:bool(false); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected: bool(false) + reaction(startup) -> d.x {= // Do not use nanosleep() here because if this is threaded, // it gets awakened right away. @@ -23,12 +29,14 @@ main reactor DeadlineHandledAbove { while (lf_time_physical() < start_time + sleep_time) {}; lf_set(d.x, 42); =} + reaction(d.deadline_violation) {= if (d.deadline_violation->value) { printf("Output successfully produced by deadline miss handler.\n"); self->violation_detected = true; } =} + reaction(shutdown) {= if (self->violation_detected) { printf("SUCCESS. Test passes.\n"); diff --git a/test/C/src/DeadlineZero.lf b/test/C/src/DeadlineZero.lf index 35e08908ca..08ae1a68a9 100644 --- a/test/C/src/DeadlineZero.lf +++ b/test/C/src/DeadlineZero.lf @@ -1,29 +1,28 @@ // Tests that specified deadlines with zero duration are always violated. -target C { - timeout: 1 sec -}; +target C { timeout: 1 sec } reactor Detector { - input trigger:int; - state cnt:int(0); + input trigger: int + + state cnt: int(0) + reaction(trigger) {= printf("ERROR: failed to detect zero-duration deadline at iteration %d.\n", self->cnt); exit(1); - =} deadline(0 msec) {= - self->cnt++; - =} + =} deadline(0 msec) {= self->cnt++; =} } reactor Generator { - output pulse:int; - timer t(0, 100 msec); - reaction(t) -> pulse {= - lf_set(pulse, 0); - =} + output pulse: int + + timer t(0, 100 msec) + + reaction(t) -> pulse {= lf_set(pulse, 0); =} } main reactor { - g = new Generator(); - d = new Detector(); - g.pulse -> d.trigger; + g = new Generator() + d = new Detector() + + g.pulse -> d.trigger } diff --git a/test/C/src/DelayArray.lf b/test/C/src/DelayArray.lf index e39c4764d8..642059481d 100644 --- a/test/C/src/DelayArray.lf +++ b/test/C/src/DelayArray.lf @@ -1,19 +1,24 @@ // This tests delaying an array type. -target C; -reactor DelayPointer(delay:time(100 msec)) { - mutable input in:int[]; - output out:int[]; - logical action a:int[]; +target C + +reactor DelayPointer(delay: time(100 msec)) { + mutable input in: int[] + + output out: int[] + + logical action a: int[] + reaction(in) -> a {= // mutable input guarantees *in will not be freed. lf_schedule_token(a, self->delay, in->token); =} - reaction(a) -> out {= - lf_set_token(out, a->token); - =} + + reaction(a) -> out {= lf_set_token(out, a->token); =} } + reactor Source { - output out:int[]; + output out: int[] + reaction(startup) -> out {= // Dynamically allocate an output array of length 3. SET_NEW_ARRAY(out, 3); @@ -24,9 +29,10 @@ reactor Source { out->value[2] = 2; =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int[]; + +reactor Print(scale: int(1)) { // The scale parameter is just for testing. + input in: int[] + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -47,10 +53,12 @@ reactor Print(scale:int(1)) { } =} } + main reactor DelayArray { - s = new Source(); - d = new DelayPointer(); - p = new Print(); - s.out -> d.in; - d.out -> p.in; + s = new Source() + d = new DelayPointer() + p = new Print() + + s.out -> d.in + d.out -> p.in } diff --git a/test/C/src/DelayArrayWithAfter.lf b/test/C/src/DelayArrayWithAfter.lf index cf0aaec393..27bc4ff2a7 100644 --- a/test/C/src/DelayArrayWithAfter.lf +++ b/test/C/src/DelayArrayWithAfter.lf @@ -1,13 +1,14 @@ -// This tests transport of dynamically allocated arrays over -// connections with 'after'. -target C { - timeout: 5 sec, - fast: true -}; +// This tests transport of dynamically allocated arrays over connections with +// 'after'. +target C { timeout: 5 sec, fast: true } + reactor Source { - output out:int[]; - state iteration:int(1); - timer t(0, 1 sec); + output out: int[] + + timer t(0, 1 sec) + + state iteration: int(1) + reaction(t) -> out {= // Dynamically allocate an output array of length 3. SET_NEW_ARRAY(out, 3); @@ -21,11 +22,12 @@ reactor Source { =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int[]; - state iteration:int(1); - state inputs_received:int(0); +reactor Print(scale: int(1)) { // The scale parameter is just for testing. + input in: int[] + + state iteration: int(1) + state inputs_received: int(0) + reaction(in) {= self->inputs_received++; int count = 1; // For testing. @@ -52,6 +54,7 @@ reactor Print(scale:int(1)) { } self->iteration++; =} + reaction(shutdown) {= if (self->inputs_received == 0) { printf("ERROR: Print reactor received no inputs.\n"); @@ -59,8 +62,10 @@ reactor Print(scale:int(1)) { } =} } + main reactor DelayArrayWithAfter { - s = new Source(); - p = new Print(); - s.out -> p.in after 1500 msec; + s = new Source() + p = new Print() + + s.out -> p.in after 1500 msec } diff --git a/test/C/src/DelayInt.lf b/test/C/src/DelayInt.lf index c6d047890c..ebefdf52df 100644 --- a/test/C/src/DelayInt.lf +++ b/test/C/src/DelayInt.lf @@ -1,25 +1,34 @@ // This tests actions with payloads by delaying an input by a fixed amount. -target C; -reactor Delay(delay:time(100 msec)) { - input in:int; - output out:int; - logical action a:int; - reaction(a) -> out {= - if (a->has_value && a->is_present) lf_set(out, a->value); - =} +target C + +reactor Delay(delay: time(100 msec)) { + input in: int + + output out: int + + logical action a: int + + reaction( + a + ) -> out {= if (a->has_value && a->is_present) lf_set(out, a->value); =} + reaction(in) -> a {= // Use specialized form of schedule for integer payloads. lf_schedule_int(a, self->delay, in->value); =} } + reactor Test { - input in:int; - state start_time:time(0); - state received_value:bool(false); + input in: int + + state start_time: time(0) + state received_value: bool(false) + reaction(startup) {= // Record the logical time at the start. self->start_time = lf_time_logical(); =} + reaction(in) {= printf("Received: %d.\n", in->value); self->received_value = true; @@ -36,6 +45,7 @@ reactor Test { exit(2); } =} + reaction(shutdown) {= printf("Checking that communication occurred.\n"); if (!self->received_value) { @@ -46,10 +56,10 @@ reactor Test { } main reactor DelayInt { - d = new Delay(); - t = new Test(); - d.out -> t.in; - reaction(startup) -> d.in {= - lf_set(d.in, 42); - =} + d = new Delay() + t = new Test() + + d.out -> t.in + + reaction(startup) -> d.in {= lf_set(d.in, 42); =} } diff --git a/test/C/src/DelayPointer.lf b/test/C/src/DelayPointer.lf index 55ac36c51c..c378f5eaf0 100644 --- a/test/C/src/DelayPointer.lf +++ b/test/C/src/DelayPointer.lf @@ -1,35 +1,46 @@ // Test delaying a pointer type. -target C; -reactor DelayPointer2(delay:time(100 msec)) { - input in:int*; - output out:int*; - logical action a:int*; +target C + +reactor DelayPointer2(delay: time(100 msec)) { + input in: int* + + output out: int* + + logical action a: int* + reaction(a) -> out {= // Using lf_set_token delegates responsibility for // freeing the allocated memory downstream. lf_set_token(out, a->token); =} + reaction(in) -> a {= // Schedule the actual token from the input rather than // a new token with a copy of the input value. lf_schedule_token(a, self->delay, in->token); =} } + reactor Source { - output out:int*; + output out: int* + reaction(startup) -> out {= SET_NEW(out); *(out->value) = 42; =} } + reactor Test { - input in:int*; - state start_time:time(0); - state received_value:bool(false); + input in: int* + + state start_time: time(0) + state received_value: bool(false) + reaction(startup) {= // Record the logical time at the start. self->start_time = lf_time_logical(); =} + reaction(in) {= printf("Received: %d.\n", *(in->value)); self->received_value = true; @@ -46,6 +57,7 @@ reactor Test { exit(2); } =} + reaction(shutdown) {= printf("Checking that communication occurred.\n"); if (!self->received_value) { @@ -55,10 +67,11 @@ reactor Test { =} } -main reactor { - s = new Source(); - d = new DelayPointer2(); - t = new Test(); - s.out -> d.in; - d.out -> t.in; +main reactor { + s = new Source() + d = new DelayPointer2() + t = new Test() + + s.out -> d.in + d.out -> t.in } diff --git a/test/C/src/DelayString.lf b/test/C/src/DelayString.lf index 8830aa7730..2d3dd55f1a 100644 --- a/test/C/src/DelayString.lf +++ b/test/C/src/DelayString.lf @@ -1,21 +1,27 @@ -// This tests actions with immutable payloads that are neither malloc'd nor freed. -target C; - -reactor DelayString2(delay:time(100 msec)) { - input in:string; - output out:string; - logical action a:string; - reaction(a) -> out {= - lf_set(out, a->value); - =} +// This tests actions with immutable payloads that are neither malloc'd nor +// freed. +target C + +reactor DelayString2(delay: time(100 msec)) { + input in: string + + output out: string + + logical action a: string + + reaction(a) -> out {= lf_set(out, a->value); =} + reaction(in) -> a {= // The following copies the char*, not the string. lf_schedule_copy(a, self->delay, &(in->value), 1); =} } + reactor Test { - input in:string; - state start_time:time(0); + input in: string + + state start_time: time(0) + reaction(in) {= printf("Received: %s.\n", in->value); // Check the time of the input. @@ -33,10 +39,10 @@ reactor Test { } main reactor { - d = new DelayString2(); - t = new Test(); - d.out -> t.in; - reaction(startup) -> d.in {= - lf_set(d.in, "Hello"); - =} + d = new DelayString2() + t = new Test() + + d.out -> t.in + + reaction(startup) -> d.in {= lf_set(d.in, "Hello"); =} } diff --git a/test/C/src/DelayStruct.lf b/test/C/src/DelayStruct.lf index 977bdf3bb0..6aa8a95fb3 100644 --- a/test/C/src/DelayStruct.lf +++ b/test/C/src/DelayStruct.lf @@ -1,27 +1,33 @@ // Test delaying a struct pointer type. -target C {files: ["include/hello.h"]}; +target C { files: ["include/hello.h"] } preamble {= #include "hello.h" =} -reactor DelayPointer(delay:time(100 msec)) { - input in:hello_t*; - output out:hello_t*; - logical action a:hello_t*; +reactor DelayPointer(delay: time(100 msec)) { + input in: hello_t* + + output out: hello_t* + + logical action a: hello_t* + reaction(a) -> out {= // Using lf_set_token delegates responsibility for // freeing the allocated memory downstream. lf_set_token(out, a->token); =} + reaction(in) -> a {= // Schedule the actual token from the input rather than // a new token with a copy of the input value. lf_schedule_token(a, self->delay, in->token); =} } + reactor Source { - output out:hello_t*; + output out: hello_t* + reaction(startup) -> out {= // Dynamically allocate an output struct. SET_NEW(out); @@ -31,9 +37,10 @@ reactor Source { out->value->value = 42; =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:hello_t*; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: hello_t* + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); if (in->value->value != self->expected) { @@ -42,10 +49,12 @@ reactor Print(expected:int(42)) { } =} } + main reactor DelayStruct { - s = new Source(); - d = new DelayPointer(); - p = new Print(); - s.out -> d.in; - d.out -> p.in; + s = new Source() + d = new DelayPointer() + p = new Print() + + s.out -> d.in + d.out -> p.in } diff --git a/test/C/src/DelayStructWithAfter.lf b/test/C/src/DelayStructWithAfter.lf index edb5a6baf9..2fb4753ca2 100644 --- a/test/C/src/DelayStructWithAfter.lf +++ b/test/C/src/DelayStructWithAfter.lf @@ -1,12 +1,13 @@ // This tests delaying a struct using after. -target C {files: include/hello.h}; +target C { files: include/hello.h } preamble {= #include "hello.h" =} reactor Source { - output out:hello_t*; + output out: hello_t* + reaction(startup) -> out {= // Dynamically allocate an output struct. SET_NEW(out); @@ -16,9 +17,10 @@ reactor Source { out->value->value = 42; =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:hello_t*; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: hello_t* + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); if (in->value->value != self->expected) { @@ -27,8 +29,10 @@ reactor Print(expected:int(42)) { } =} } + main reactor DelayStructWithAfter { - s = new Source(); - p = new Print(); - s.out -> p.in after 100 msec; + s = new Source() + p = new Print() + + s.out -> p.in after 100 msec } diff --git a/test/C/src/DelayStructWithAfterOverlapped.lf b/test/C/src/DelayStructWithAfterOverlapped.lf index a93c819588..0a04aa9a67 100644 --- a/test/C/src/DelayStructWithAfterOverlapped.lf +++ b/test/C/src/DelayStructWithAfterOverlapped.lf @@ -1,18 +1,17 @@ // This tests delaying a struct using after. -target C { - timeout: 5 sec, - fast: true, - files: ["include/hello.h"] -}; +target C { timeout: 5 sec, fast: true, files: ["include/hello.h"] } preamble {= #include "hello.h" =} reactor Source { - output out:hello_t*; - timer t(0, 1 sec); - state s:int(0); + output out: hello_t* + + timer t(0, 1 sec) + + state s: int(0) + reaction(t) -> out {= self->s++; // Dynamically allocate an output struct. @@ -23,10 +22,12 @@ reactor Source { out->value->value = 42 * self->s; =} } -// expected parameter is for testing. -reactor Print { - input in:hello_t*; - state s:int(0); + +reactor Print { // expected parameter is for testing. + input in: hello_t* + + state s: int(0) + reaction(in) {= self->s++; printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); @@ -35,6 +36,7 @@ reactor Print { exit(1); } =} + reaction(shutdown) {= if (self->s == 0) { printf("ERROR: Print received no data.\n"); @@ -42,8 +44,10 @@ reactor Print { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in after 1500 msec; + s = new Source() + p = new Print() + + s.out -> p.in after 1500 msec } diff --git a/test/C/src/DelayedAction.lf b/test/C/src/DelayedAction.lf index 455cf4373c..6e13a2d683 100644 --- a/test/C/src/DelayedAction.lf +++ b/test/C/src/DelayedAction.lf @@ -1,14 +1,13 @@ -target C { - fast: true, - timeout: 5 sec -}; +target C { fast: true, timeout: 5 sec } + main reactor DelayedAction { - timer t(0, 1 sec); - logical action a; - state count:int(0); - reaction(t) -> a {= - lf_schedule(a, MSEC(100)); - =} + timer t(0, 1 sec) + + logical action a + + state count: int(0) + + reaction(t) -> a {= lf_schedule(a, MSEC(100)); =} reaction(a) {= interval_t elapsed = lf_time_logical_elapsed(); diff --git a/test/C/src/DelayedReaction.lf b/test/C/src/DelayedReaction.lf index c58a9bd3db..6f94d408ae 100644 --- a/test/C/src/DelayedReaction.lf +++ b/test/C/src/DelayedReaction.lf @@ -1,15 +1,17 @@ // Test delay made on a connection. -target C; +target C reactor Source { - output out:int; - timer t; - reaction(t) -> out {= - lf_set(out, 1); - =} + output out: int + + timer t + + reaction(t) -> out {= lf_set(out, 1); =} } + reactor Sink { - input in:int; + input in: int + reaction(in) {= interval_t elapsed = lf_time_logical_elapsed(); printf("Nanoseconds since start: %lld.\n", elapsed); @@ -19,9 +21,10 @@ reactor Sink { } =} } + main reactor DelayedReaction { + source = new Source() + sink = new Sink() - source = new Source(); - sink = new Sink(); - source.out -> sink.in after 100 msec; + source.out -> sink.in after 100 msec } diff --git a/test/C/src/Determinism.lf b/test/C/src/Determinism.lf index cfd35308d7..30e7b7d10d 100644 --- a/test/C/src/Determinism.lf +++ b/test/C/src/Determinism.lf @@ -1,14 +1,17 @@ -target C; +target C + reactor Source { - output y:int; - timer t; - reaction(t) -> y {= - lf_set(y, 1); - =} + output y: int + + timer t + + reaction(t) -> y {= lf_set(y, 1); =} } + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= int sum = 0; if (x->is_present) { @@ -24,21 +27,23 @@ reactor Destination { } =} } + reactor Pass { - input x:int; - output y:int; - reaction(x) -> y {= - lf_set(y, x->value); - =} + input x: int + + output y: int + + reaction(x) -> y {= lf_set(y, x->value); =} } main reactor Determinism { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/C/src/DoubleInvocation.lf b/test/C/src/DoubleInvocation.lf index 4b66006156..a02583bcc1 100644 --- a/test/C/src/DoubleInvocation.lf +++ b/test/C/src/DoubleInvocation.lf @@ -1,37 +1,38 @@ -// This illustrates a very strange bug that showed up -// and has now been fixed. This test ensures it does -// not reappear. -// At logical time zero, the two Print reactors used to be -// fired twice each at the same logical time. -// They should only be fired once. -// This behavior was oddly eliminated by either of the following -// actions, neither of which should affect this behavior: +// This illustrates a very strange bug that showed up and has now been fixed. +// This test ensures it does not reappear. At logical time zero, the two Print +// reactors used to be fired twice each at the same logical time. They should +// only be fired once. This behavior was oddly eliminated by either of the +// following actions, neither of which should affect this behavior: // * Removing the startup reaction in Print. // * Sending only position, not velocity from Ball. +target C { timeout: 5 sec, fast: true } -target C { - timeout: 5 sec, - fast: true -}; reactor Ball { - output position:int; - output velocity:int; - state p:int(200); - timer trigger(0, 1 sec); + output position: int + output velocity: int + + timer trigger(0, 1 sec) + + state p: int(200) + reaction(trigger) -> position, velocity {= lf_set(position, self->p); lf_set(velocity, -1); self->p -= 1; =} } + reactor Print { - input velocity:int; - input position:int; - state previous:int(-1); - reaction (startup) {= + input velocity: int + input position: int + + state previous: int(-1) + + reaction(startup) {= printf("####### Print startup\n"); =} - reaction (position, velocity) {= + + reaction(position, velocity) {= if (position->is_present) { printf("Position: %d.\n", position->value); } @@ -41,12 +42,14 @@ reactor Print { } =} } + main reactor DoubleInvocation { - b1 = new Ball(); - p = new Print(); - plot = new Print(); - b1.position -> p.position; - b1.velocity -> p.velocity; - b1.position -> plot.position; - b1.velocity -> plot.velocity; + b1 = new Ball() + p = new Print() + plot = new Print() + + b1.position -> p.position + b1.velocity -> p.velocity + b1.position -> plot.position + b1.velocity -> plot.velocity } diff --git a/test/C/src/DoublePort.lf b/test/C/src/DoublePort.lf index b0d6afbb80..9f2d9bf37b 100644 --- a/test/C/src/DoublePort.lf +++ b/test/C/src/DoublePort.lf @@ -1,35 +1,32 @@ /** - * Test the case where two upstream reactors - * pass messages to a downstream reactor on two - * different ports. One message carries - * a microstep delay relative to the other. + * Test the case where two upstream reactors pass messages to a downstream + * reactor on two different ports. One message carries a microstep delay + * relative to the other. * * @author Soroush Bateni */ -target C { - timeout: 900 msec, - fast: true -}; +target C { timeout: 900 msec, fast: true } -import Count from "lib/Count.lf"; +import Count from "lib/Count.lf" reactor CountMicrostep { - state count:int(1); - output out:int; - logical action act:int; - timer t(0, 1 sec); - reaction(t) -> act {= - lf_schedule_int(act, 0, self->count++); - =} + output out: int - reaction(act) -> out {= - lf_set(out, act->value); - =} + timer t(0, 1 sec) + + logical action act: int + + state count: int(1) + + reaction(t) -> act {= lf_schedule_int(act, 0, self->count++); =} + + reaction(act) -> out {= lf_set(out, act->value); =} } reactor Print { - input in:int; - input in2:int; + input in: int + input in2: int + reaction(in, in2) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("At tag (%lld, %u), received in = %d and in2 = %d.\n", elapsed_time, lf_tag().microstep, in->value, in2->value); @@ -39,15 +36,16 @@ reactor Print { } =} - reaction(shutdown) {= - printf("SUCCESS: messages were at least one microstep apart.\n"); - =} + reaction( + shutdown + ) {= printf("SUCCESS: messages were at least one microstep apart.\n"); =} } main reactor DoublePort { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.out -> p.in; - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.out -> p.in + cm.out -> p.in2 } diff --git a/test/C/src/DoubleReaction.lf b/test/C/src/DoubleReaction.lf index dfa6a913d3..cd58178c33 100644 --- a/test/C/src/DoubleReaction.lf +++ b/test/C/src/DoubleReaction.lf @@ -1,14 +1,14 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target C { - timeout: 10 sec, - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that two simultaneous inputs that trigger a reaction trigger it only +// once. Correct output for this 2, 4, 6, 8, etc. +target C { timeout: 10 sec, fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; lf_set(y, self->count); @@ -16,9 +16,11 @@ reactor Clock(offset:time(0), period:time(1 sec)) { } reactor Destination { - input x:int; - input w:int; - state s:int(2); + input x: int + input w: int + + state s: int(2) + reaction(x, w) {= int sum = 0; if (x->is_present) { @@ -35,10 +37,12 @@ reactor Destination { self->s += 2; =} } + main reactor DoubleReaction { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/C/src/DoubleTrigger.lf b/test/C/src/DoubleTrigger.lf index e8cf8e5a88..e5f141274e 100644 --- a/test/C/src/DoubleTrigger.lf +++ b/test/C/src/DoubleTrigger.lf @@ -1,13 +1,13 @@ -// Test that two simultaneous triggers don't cause -// a reaction to execute twice at the same tag. -target C { - timeout: 1 sec, - fast: true -}; +// Test that two simultaneous triggers don't cause a reaction to execute twice +// at the same tag. +target C { timeout: 1 sec, fast: true } + main reactor DoubleTrigger { - timer t1; - timer t2; - state s:int(0); + timer t1 + timer t2 + + state s: int(0) + reaction(t1, t2) {= self->s++; if (self->s > 1) { @@ -15,6 +15,7 @@ main reactor DoubleTrigger { exit(1); } =} + reaction(shutdown) {= if (self->s == 1) { printf("SUCCESS.\n"); From a52f32f30bc083a2ce79f8716937823260910df3 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 22:14:43 -0700 Subject: [PATCH 079/130] [formatter] Fix two more non-superficial mistakes. Mistake #1 is that the algorithm for associating comments to AST nodes was too complicated and also very wrong. Mistake #2 is that the penalty for displacing comments up to parents shouldn't be applied to first children, because visually, there is no actual intervening text. --- .../lflang/tests/compiler/RoundTripTests.java | 19 ++--- org.lflang/src/org/lflang/ASTUtils.java | 73 ++++++++++-------- .../src/org/lflang/ast/MalleableString.java | 4 +- org.lflang/src/org/lflang/ast/ToLf.java | 75 ++++++------------- test/C/src/federated/DistributedStop.lf | 37 +++++---- .../federated/DistributedStopDecentralized.lf | 13 ++-- test/C/src/federated/DistributedStopZero.lf | 23 +++--- test/C/src/federated/HelloDistributed.lf | 2 +- 8 files changed, 119 insertions(+), 127 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 3004057194..0fcc2500df 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -36,15 +36,16 @@ public class RoundTripTests { @Test public void roundTripTest() throws Exception { - int nonFailures = 0; - for (Target target : Target.values()) { - for (TestCategory category : TestCategory.values()) { - for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { - run(test.srcFile); - System.out.printf("%s non-failures%n", ++nonFailures); - } - } - } + run(Path.of("/home/peter/vscode-lingua-franca/lingua-franca/test/C/src/federated/HelloDistributed.lf")); +// int nonFailures = 0; +// for (Target target : Target.values()) { +// for (TestCategory category : TestCategory.values()) { +// for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { +// run(test.srcFile); +// System.out.printf("%s non-failures%n", ++nonFailures); +// } +// } +// } } private void run(Path file) throws Exception { diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index f8a9298721..c0584b10dc 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -48,7 +48,6 @@ import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; -import org.eclipse.xtext.nodemodel.impl.CompositeNode; import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.resource.XtextResource; @@ -1693,41 +1692,51 @@ public static Reactor toDefinition(ReactorDecl r) { * Return all single-line or multi-line comments immediately preceding the * given EObject. */ - public static List getPrecedingComments( + public static Stream getPrecedingComments( ICompositeNode compNode, - boolean singleLine, Predicate filter ) { - List ret = new ArrayList<>(); - getPrecedingCommentsRecursive( - compNode, - ret, - node -> node instanceof HiddenLeafNode hlNode - && hlNode.getGrammarElement() instanceof TerminalRule tRule - && (singleLine ? "SL_COMMENT" : "ML_COMMENT").equals(tRule.getName()) - && filter.test(hlNode) - ); - return ret; + List ret = new ArrayList<>(); + for (INode node : compNode.getAsTreeIterable()) { + if (!(node instanceof ICompositeNode)) { + if (node.getGrammarElement() instanceof TerminalRule r && r.getName().endsWith("_COMMENT")) { + if (filter.test(node)) ret.add(node); + } else if (!node.getText().isBlank() && node.getParent() != compNode) { + break; + } + } + } + return ret.stream().map(INode::getText); + } + + /** Return whether {@code node} is a comment. */ + public static boolean isComment(INode node) { + return node instanceof HiddenLeafNode hlNode + && hlNode.getGrammarElement() instanceof TerminalRule tRule + && tRule.getName().endsWith("_COMMENT"); } /** - * Add any text satisfying {@code filter} that is at the beginning of the - * text of {@code node} to the list. Return true if {@code node} contains - * anything of semantic significance. + * Return true if the given node contains semantically significant text on + * the same line as the given other node. */ - private static boolean getPrecedingCommentsRecursive( - INode node, - List precedingComments, - Predicate filter - ) { - if (node instanceof ICompositeNode compositeNode) { - for (INode child : compositeNode.getChildren()) { - if (getPrecedingCommentsRecursive(child, precedingComments, filter)) return true; + public static Predicate sameLine(ICompositeNode compNode) { + return other -> { + for (INode node : compNode.getAsTreeIterable()) { + if ( + !(node instanceof ICompositeNode) + && !( + node instanceof TerminalRule terminalRule + && terminalRule.getName().endsWith("_COMMENT") + ) && !node.getText().isBlank() + && node.getStartLine() <= other.getEndLine() + && node.getEndLine() >= other.getStartLine() + ) { + return true; + } } - } else if (filter.test(node)) { - precedingComments.add(node.getText()); - } - return !(node instanceof HiddenLeafNode) && !(node instanceof CompositeNode); + return false; + }; } /** @@ -1744,10 +1753,8 @@ private static boolean getPrecedingCommentsRecursive( public static String findAnnotationInComments(EObject object, String key) { if (!(object.eResource() instanceof XtextResource)) return null; ICompositeNode node = NodeModelUtils.findActualNodeFor(object); - return Stream.concat( - getPrecedingComments(node, true, n -> true).stream(), - getPrecedingComments(node, false, n -> true).stream().flatMap(String::lines) - ).filter(line -> line.contains(key)) + return getPrecedingComments(node, n -> true).flatMap(String::lines) + .filter(line -> line.contains(key)) .map(String::trim) .map(it -> it.substring(it.indexOf(key) + key.length())) .map(it -> it.endsWith("*/") ? it.substring(0, it.length() - "*/".length()) : it) @@ -1822,7 +1829,7 @@ public static TargetDecl targetDecl(Resource model) { //// Private methods /** - * Returns the list if it is not null. Otherwise return an empty list. + * Returns the list if it is not null. Otherwise, return an empty list. */ public static List convertToEmptyListIfNull(List list) { return list != null ? list : new ArrayList<>(); diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index 7c6ffd559f..de444d584b 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -211,6 +211,7 @@ public RenderResult render() { .map(FormattingUtils::normalizeEol) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); List commentsThatCouldNotBeHandledHere = new ArrayList<>(); + int numCommentsDisplacedHere = 0; if ( commentsFromChildren.stream().anyMatch(s -> !s.isEmpty()) ) { @@ -223,6 +224,7 @@ public RenderResult render() { keepCommentsOnSameLine )) { commentsThatCouldNotBeHandledHere.addAll(commentsFromChildren.get(i)); + if (i != 0) numCommentsDisplacedHere++; } } } @@ -231,7 +233,7 @@ public RenderResult render() { String.join("", stringComponents), componentRenderings.stream() .mapToInt(RenderResult::levelsOfCommentDisplacement).sum() - + commentsThatCouldNotBeHandledHere.size() + + numCommentsDisplacedHere ); } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 5dcf8a3cce..62e6b99b15 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -11,10 +11,8 @@ import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.TerminalRule; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.INode; -import org.eclipse.xtext.nodemodel.impl.HiddenLeafNode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.eclipse.xtext.xbase.lib.StringExtensions; @@ -93,56 +91,38 @@ public MalleableString caseArraySpec(ArraySpec spec) { @Override public MalleableString doSwitch(EObject eObject) { ICompositeNode node = NodeModelUtils.findActualNodeFor(eObject); - Stream followingComments = getFollowingComments(node); - List immediatelyPrecedingComments = ASTUtils.getPrecedingComments( - node, - false, - sameLine(node) - ); + Stream followingComments = getFollowingComments(node, ASTUtils.sameLine(node)); var previous = getNextCompositeSibling(node, INode::getPreviousSibling, true); - Predicate doesNotBelongToPrevious = sameLine(node).negate().and( - previous == null ? n -> true : sameLine(previous).negate() - ); - Stream singleLinePrecedingComments = ASTUtils.getPrecedingComments( + Predicate doesNotBelongToPrevious = previous == null ? + n -> true : ASTUtils.sameLine(previous).negate(); + Stream precedingComments = ASTUtils.getPrecedingComments( node, - true, doesNotBelongToPrevious - ).stream().map(String::trim); - Stream multilinePrecedingComments = ASTUtils.getPrecedingComments( - node, - false, - doesNotBelongToPrevious - ).stream().map( - it -> it.lines() - .map(String::strip) - .map(trimmed -> trimmed.startsWith("*") ? " " + trimmed : trimmed) - .collect(Collectors.joining(System.lineSeparator())) - ); + ).map(String::strip); MalleableString representation = super.doSwitch(eObject); - representation - .addComments(singleLinePrecedingComments) - .addComments(multilinePrecedingComments) - .addComments(immediatelyPrecedingComments) + return representation + .addComments(precedingComments) .addComments(followingComments); - return representation; } - private ICompositeNode getNextCompositeSibling( + private static ICompositeNode getNextCompositeSibling( INode node, Function getNextSibling, boolean traverseUpwards ) { INode sibling = node; while ((sibling = getNextSibling.apply(sibling)) != null) { - if (sibling instanceof ICompositeNode compositeSibling) return compositeSibling; - } - if (node.getParent() != null && traverseUpwards) { - return getNextCompositeSibling(node.getParent(), getNextSibling, true); + if ( + sibling instanceof ICompositeNode compositeSibling + && !sibling.getText().isBlank() + ) return compositeSibling; } + ICompositeNode parent = node.getParent(); + if (traverseUpwards) return parent; return null; } - private Stream getFollowingNonCompositeSiblings(ICompositeNode node) { + private static Stream getFollowingNonCompositeSiblings(ICompositeNode node) { INode sibling = node; List ret = new ArrayList<>(); while ( @@ -154,25 +134,18 @@ private Stream getFollowingNonCompositeSiblings(ICompositeNode node) { return ret.stream(); } - private Stream getFollowingComments(ICompositeNode node) { + private static Stream getFollowingComments( + ICompositeNode node, + Predicate filter + ) { ICompositeNode sibling = getNextCompositeSibling(node, INode::getNextSibling, false); Stream followingSiblingComments = getFollowingNonCompositeSiblings(node) - .filter( - otherSibling -> otherSibling instanceof HiddenLeafNode hlNode - && hlNode.getGrammarElement() instanceof TerminalRule tRule - && tRule.getName().endsWith("COMMENT") - ).map(INode::getText); + .filter(ASTUtils::isComment).map(INode::getText); if (sibling == null) return followingSiblingComments; - Predicate filter = sameLine(node).and(sameLine(sibling).negate()); - return Stream.concat(followingSiblingComments, Stream.concat( - ASTUtils.getPrecedingComments(sibling, false, filter).stream(), - ASTUtils.getPrecedingComments(sibling, true, filter).stream() - )); - } - - private Predicate sameLine(INode node) { - return other -> node.getStartLine() <= other.getStartLine() - && other.getStartLine() <= node.getEndLine(); + return Stream.concat( + followingSiblingComments, + ASTUtils.getPrecedingComments(sibling, filter) + ); } @Override diff --git a/test/C/src/federated/DistributedStop.lf b/test/C/src/federated/DistributedStop.lf index 7b274b1720..cab9bf82e3 100644 --- a/test/C/src/federated/DistributedStop.lf +++ b/test/C/src/federated/DistributedStop.lf @@ -1,15 +1,20 @@ /** - * Test for lf_request_stop() in federated execution with centralized coordination. + * Test for lf_request_stop() in federated execution with centralized + * coordination. * * @author Soroush Bateni */ -target C; +target C reactor Sender { - output out:int; - timer t(0, 1 usec); - logical action act; - state reaction_invoked_correctly:bool(false); + output out: int + + timer t(0, 1 usec) + + logical action act + + state reaction_invoked_correctly: bool(false) + reaction(t, act) -> out, act {= lf_print("Sending 42 at (%lld, %u).", lf_time_logical_elapsed(), @@ -30,7 +35,7 @@ reactor Sender { lf_tag().microstep); lf_request_stop(); } - + tag_t _1usec1 = (tag_t) { .time = USEC(1) + lf_time_start(), .microstep = 1u }; if (lf_tag_compare(lf_tag(), _1usec1) == 0) { // The reaction was invoked at (1 usec, 1) as expected @@ -60,11 +65,13 @@ reactor Sender { =} } -reactor Receiver ( - stp_offset:time(10 msec) // Used in the decentralized variant of the test +reactor Receiver( + stp_offset: time(10 msec) // Used in the decentralized variant of the test ) { - input in:int; - state reaction_invoked_correctly:bool(false); + input in: int + + state reaction_invoked_correctly: bool(false) + reaction(in) {= lf_print("Received %d at (%lld, %u).", in->value, @@ -79,7 +86,7 @@ reactor Receiver ( // (1 usec, 1) and trigger this reaction self->reaction_invoked_correctly = true; } - + tag_t _1usec1 = (tag_t) { .time = USEC(1) + lf_time_start(), .microstep = 1u }; if (lf_tag_compare(lf_tag(), _1usec1) > 0) { self->reaction_invoked_correctly = false; @@ -109,8 +116,8 @@ reactor Receiver ( } federated reactor DistributedStop { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedStopDecentralized.lf b/test/C/src/federated/DistributedStopDecentralized.lf index 81c9ca5706..19f92ac513 100644 --- a/test/C/src/federated/DistributedStopDecentralized.lf +++ b/test/C/src/federated/DistributedStopDecentralized.lf @@ -1,17 +1,16 @@ /** - * Test for lf_request_stop() in federated execution with decentralized coordination. + * Test for lf_request_stop() in federated execution with decentralized + * coordination. * * @author Soroush Bateni */ -target C { - coordination: decentralized -}; +target C { coordination: decentralized } import Sender, Receiver from "DistributedStop.lf" federated reactor DistributedStopDecentralized { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/DistributedStopZero.lf b/test/C/src/federated/DistributedStopZero.lf index 21570abe20..b4ac29b4a0 100644 --- a/test/C/src/federated/DistributedStopZero.lf +++ b/test/C/src/federated/DistributedStopZero.lf @@ -1,15 +1,17 @@ /** - * Test for lf_request_stop() in federated execution with centralized coordination - * at tag (0,0). + * Test for lf_request_stop() in federated execution with centralized + * coordination at tag (0,0). * * @author Soroush Bateni */ -target C; +target C reactor Sender { - output out:int; - timer t(0, 1 usec); - reaction(t) -> out{= + output out: int + + timer t(0, 1 usec) + + reaction(t) -> out {= printf("Sending 42 at (%lld, %u).\n", lf_time_logical_elapsed(), lf_tag().microstep); @@ -41,7 +43,8 @@ reactor Sender { } reactor Receiver { - input in:int; + input in: int + reaction(in) {= printf("Received %d at (%lld, %u).\n", in->value, @@ -76,8 +79,8 @@ reactor Receiver { } federated reactor { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/federated/HelloDistributed.lf b/test/C/src/federated/HelloDistributed.lf index 20e4a87441..28e1d7f0d3 100644 --- a/test/C/src/federated/HelloDistributed.lf +++ b/test/C/src/federated/HelloDistributed.lf @@ -45,7 +45,7 @@ federated reactor HelloDistributed at localhost { s = new Source() // Reactor s is in federate Source d = new Destination() // Reactor d is in federate Destination - s.out ->d.in // This version preserves the timestamp. + s.out -> d.in // This version preserves the timestamp. reaction( startup From 1652b5dba6a1dc6942e6106b6d5fc6ac169b43a6 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 22:39:14 -0700 Subject: [PATCH 080/130] [formatting] Two spaces before same-line comments. --- org.lflang/src/org/lflang/ast/FormattingUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 1061f3cf44..b4ab0d23eb 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -164,7 +164,7 @@ static boolean placeComment( if (components.get(j).contains(System.lineSeparator())) { components.set(j, components.get(j).replaceFirst( System.lineSeparator(), - String.format(" %s%n", wrapped) + String.format(" %s%n", wrapped) )); return true; } From 956bfaf96656a850d2f2a256a3aa1a0e32e57e5a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 23:09:46 -0700 Subject: [PATCH 081/130] [formatting] Simple bugfix. --- org.lflang/src/org/lflang/ASTUtils.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index c0584b10dc..7f5bcfd95c 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -1699,7 +1699,11 @@ public static Stream getPrecedingComments( List ret = new ArrayList<>(); for (INode node : compNode.getAsTreeIterable()) { if (!(node instanceof ICompositeNode)) { - if (node.getGrammarElement() instanceof TerminalRule r && r.getName().endsWith("_COMMENT")) { + if ( + node.getGrammarElement() instanceof TerminalRule r + && r.getName().endsWith("_COMMENT") + && !node.getParent().getText().stripLeading().startsWith("{=") + ) { if (filter.test(node)) ret.add(node); } else if (!node.getText().isBlank() && node.getParent() != compNode) { break; From 1d4d4bfbe0859f0df98412c555ea1456b6ee39d0 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 23:10:14 -0700 Subject: [PATCH 082/130] [formatting] Format more C tests. --- test/C/src/FloatLiteral.lf | 15 ++-- test/C/src/Gain.lf | 76 ++++++++++--------- test/C/src/GetMicroStep.lf | 12 +-- test/C/src/GetTime.lf | 13 ++-- test/C/src/Hello.lf | 48 +++++++----- test/C/src/HelloWorld.lf | 12 ++- test/C/src/Hierarchy.lf | 58 ++++++++------ test/C/src/Hierarchy2.lf | 72 +++++++++++------- test/C/src/IdentifierLength.lf | 42 ++++++---- test/C/src/Import.lf | 18 +++-- test/C/src/ImportComposition.lf | 21 ++--- test/C/src/ImportRenamed.lf | 21 ++--- test/C/src/InheritanceAction.lf | 38 +++++----- test/C/src/ManualDelayedReaction.lf | 59 +++++++------- test/C/src/Microsteps.lf | 23 +++--- test/C/src/Minimal.lf | 8 +- test/C/src/MovingAverage.lf | 48 +++++++----- test/C/src/MultipleContained.lf | 29 ++++--- test/C/src/NativeListsAndTimes.lf | 38 +++++----- test/C/src/ParameterHierarchy.lf | 18 +++-- test/C/src/ParameterizedState.lf | 13 ++-- test/C/src/PeriodicDesugared.lf | 13 +--- test/C/src/PhysicalConnection.lf | 22 +++--- test/C/src/PingPong.lf | 73 ++++++++++-------- test/C/src/Preamble.lf | 10 +-- test/C/src/ReadOutputOfContainedReactor.lf | 23 +++--- test/C/src/RepeatedInheritance.lf | 48 +++++++----- test/C/src/RequestStop.lf | 6 +- test/C/src/Schedule.lf | 25 +++--- test/C/src/ScheduleLogicalAction.lf | 47 +++++++----- test/C/src/ScheduleValue.lf | 9 ++- test/C/src/SelfLoop.lf | 31 ++++---- test/C/src/SendingInside.lf | 26 ++++--- test/C/src/SendingInside2.lf | 17 +++-- test/C/src/SendsPointerTest.lf | 32 ++++---- test/C/src/SetArray.lf | 29 ++++--- test/C/src/SetCopyConstructor.lf | 24 +++--- test/C/src/SetDestructor.lf | 25 +++--- test/C/src/SetToken.lf | 33 ++++---- test/C/src/SimpleDeadline.lf | 31 +++++--- test/C/src/SimpleImport.lf | 9 ++- test/C/src/SlowingClock.lf | 26 +++---- test/C/src/SlowingClockPhysical.lf | 24 +++--- test/C/src/StartupOutFromInside.lf | 12 +-- test/C/src/Starvation.lf | 30 ++++---- test/C/src/Stop.lf | 18 ++--- test/C/src/StopZero.lf | 36 +++++---- test/C/src/Stride.lf | 36 +++++---- test/C/src/StructAsState.lf | 11 ++- test/C/src/StructAsType.lf | 27 ++++--- test/C/src/StructAsTypeDirect.lf | 23 +++--- test/C/src/StructParallel.lf | 54 +++++++------ test/C/src/StructPrint.lf | 26 ++++--- test/C/src/StructScale.lf | 47 +++++++----- test/C/src/SubclassesAndStartup.lf | 20 ++--- test/C/src/TestForPreviousOutput.lf | 28 ++++--- test/C/src/TimeLimit.lf | 64 +++++++++------- test/C/src/TimeState.lf | 12 ++- test/C/src/Timeout.lf | 18 ++--- test/C/src/TimeoutZero.lf | 22 +++--- test/C/src/ToReactionNested.lf | 23 +++--- test/C/src/TriggerDownstreamOnlyIfPresent2.lf | 29 ++++--- test/C/src/UnconnectedInput.lf | 47 +++++++----- test/C/src/Wcet.lf | 40 +++++----- 64 files changed, 1064 insertions(+), 824 deletions(-) diff --git a/test/C/src/FloatLiteral.lf b/test/C/src/FloatLiteral.lf index 617a02c7a9..6d55f6e988 100644 --- a/test/C/src/FloatLiteral.lf +++ b/test/C/src/FloatLiteral.lf @@ -1,15 +1,16 @@ -target C; -// This test verifies that floating-point literals are handled -// correctly. +target C + +// This test verifies that floating-point literals are handled correctly. main reactor { preamble {= #include =} - state N:double(6.0221409e+23) - state charge:double(-1.6021766E-19) - state minus_epsilon:double(-.01e0) - state expected:double(.964853323188E5) + state N: double(6.0221409e+23) + state charge: double(-1.6021766E-19) + state minus_epsilon: double(-.01e0) + state expected: double(.964853323188E5) + reaction(startup) {= double F = - self->N * self->charge; if (fabs(F - self->expected) < fabs(self->minus_epsilon)) { diff --git a/test/C/src/Gain.lf b/test/C/src/Gain.lf index 05e6210974..26dee49336 100644 --- a/test/C/src/Gain.lf +++ b/test/C/src/Gain.lf @@ -1,36 +1,42 @@ // Example in the Wiki. - target C; - reactor Scale(scale:int(2)) { - input x:int; - output y:int; - reaction(x) -> y {= - lf_set(y, x->value * self->scale); - =} - } - reactor Test { - input x:int; - state received_value:bool(false); - reaction(x) {= - printf("Received %d.\n", x->value); - self->received_value = true; - if (x->value != 2) { - printf("ERROR: Expected 2!\n"); - exit(1); - } - =} - reaction(shutdown) {= - if (!self->received_value) { - printf("ERROR: No value received by Test reactor!\n"); - } else { - printf("Test passes.\n"); - } - =} - } - main reactor Gain { - g = new Scale(); - d = new Test(); - g.y -> d.x; - reaction(startup) -> g.x {= - lf_set(g.x, 1); - =} - } +target C + +reactor Scale(scale: int(2)) { + input x: int + + output y: int + + reaction(x) -> y {= lf_set(y, x->value * self->scale); =} +} + +reactor Test { + input x: int + + state received_value: bool(false) + + reaction(x) {= + printf("Received %d.\n", x->value); + self->received_value = true; + if (x->value != 2) { + printf("ERROR: Expected 2!\n"); + exit(1); + } + =} + + reaction(shutdown) {= + if (!self->received_value) { + printf("ERROR: No value received by Test reactor!\n"); + } else { + printf("Test passes.\n"); + } + =} +} + +main reactor Gain { + g = new Scale() + d = new Test() + + g.y -> d.x + + reaction(startup) -> g.x {= lf_set(g.x, 1); =} +} diff --git a/test/C/src/GetMicroStep.lf b/test/C/src/GetMicroStep.lf index 0eca6c6843..a10b38f763 100644 --- a/test/C/src/GetMicroStep.lf +++ b/test/C/src/GetMicroStep.lf @@ -1,12 +1,12 @@ // Tests the lf_tag().microstep function in the C target. -target C; +target C + main reactor GetMicroStep { - state s:int(1); + logical action l - logical action l; - reaction(startup) -> l {= - lf_schedule(l, 0); - =} + state s: int(1) + + reaction(startup) -> l {= lf_schedule(l, 0); =} reaction(l) -> l {= microstep_t microstep = lf_tag().microstep; diff --git a/test/C/src/GetTime.lf b/test/C/src/GetTime.lf index 6988aec45b..dee85f8126 100644 --- a/test/C/src/GetTime.lf +++ b/test/C/src/GetTime.lf @@ -1,11 +1,10 @@ -// This file includes code documented on the Wiki. -// For this test, success is just compiling and running. -target C { - timeout: 2 sec, - fast: false -}; +// This file includes code documented on the Wiki. For this test, success is +// just compiling and running. +target C { timeout: 2 sec, fast: false } + main reactor GetTime { - timer t(0, 1 sec); + timer t(0, 1 sec) + reaction(t) {= instant_t logical = lf_time_logical(); printf("Logical time is %lld.\n", logical); diff --git a/test/C/src/Hello.lf b/test/C/src/Hello.lf index 63b51f4b6f..951e875162 100644 --- a/test/C/src/Hello.lf +++ b/test/C/src/Hello.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the lf_schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target C { - timeout: 10 sec, - fast: true -}; -reactor Reschedule(period:time(2 secs), message:string("Hello C")) { - state count:int(0); - state previous_time:time(0); - timer t(1 secs, period); - logical action a; +// This test checks that logical time is incremented an appropriate amount as a +// result of an invocation of the lf_schedule() function at runtime. It also +// performs various smoke tests of timing aligned reactions. The first instance +// has a period of 4 seconds, the second of 2 seconds, and the third (composite) +// or 1 second. +target C { timeout: 10 sec, fast: true } + +reactor Reschedule(period: time(2 sec), message: string("Hello C")) { + timer t(1 sec, period) + + logical action a + + state count: int(0) + state previous_time: time(0) + reaction(t) -> a {= printf("%s\n", self->message); lf_schedule(a, MSEC(200)); @@ -21,6 +22,7 @@ reactor Reschedule(period:time(2 secs), message:string("Hello C")) { printf("Current time is %lld\n", self->previous_time); printf("Which is %sPlus %lld nanoseconds.\n", ctime(&secs), self->previous_time % BILLION); =} + reaction(a) {= (self->count)++; printf("***** action %d at time %lld\n", self->count, lf_time_logical()); @@ -38,11 +40,19 @@ reactor Reschedule(period:time(2 secs), message:string("Hello C")) { } =} } -reactor Inside(period:time(1 sec), message:string("Composite default message.")) { - third_instance = new Reschedule(period = period, message = message); + +reactor Inside( + period: time(1 sec), + message: string("Composite default message.") +) { + third_instance = new Reschedule(period = period, message = message) } + main reactor Hello { - first_instance = new Reschedule(period = 4 sec, message = "Hello from first_instance."); - second_instance = new Reschedule(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new Reschedule( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new Reschedule(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/C/src/HelloWorld.lf b/test/C/src/HelloWorld.lf index e85fd19c23..4a50b2da91 100644 --- a/test/C/src/HelloWorld.lf +++ b/test/C/src/HelloWorld.lf @@ -1,14 +1,18 @@ target C { - tracing: {trace-file-name: "HelloWorldTrace"}, // To test generating a custom trace file name. + // To test generating a custom trace file name. + tracing: { trace-file-name: "HelloWorldTrace" }, logging: error, build-type: Debug -}; +} + reactor HelloWorld2 { - state success:bool(false); + state success: bool(false) + reaction(startup) {= printf("Hello World.\n"); self->success = true; =} + reaction(shutdown) {= printf("Shutdown invoked.\n"); if (!self->success) { @@ -19,5 +23,5 @@ reactor HelloWorld2 { } main reactor HelloWorld { - a = new HelloWorld2(); + a = new HelloWorld2() } diff --git a/test/C/src/Hierarchy.lf b/test/C/src/Hierarchy.lf index bb41461ef3..4f8e6afdde 100644 --- a/test/C/src/Hierarchy.lf +++ b/test/C/src/Hierarchy.lf @@ -1,22 +1,28 @@ // Test data transport across hierarchy. -target C; +target C + reactor Source { - output out:int; - timer t; - reaction(t) -> out {= - lf_set(out, 1); - =} + output out: int + + timer t + + reaction(t) -> out {= lf_set(out, 1); =} } + reactor Gain { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= printf("Gain received %d.\n", in->value); lf_set(out, in->value * 2); =} } + reactor Print { - input in:int; + input in: int + reaction(in) {= printf("Received: %d.\n", in->value); if (in->value != 2) { @@ -25,21 +31,27 @@ reactor Print { } =} } + reactor GainContainer { - input in:int; - output out:int; - output out2:int; - gain = new Gain(); - in -> gain.in; - gain.out -> out; - gain.out -> out2; + input in: int + + output out: int + output out2: int + + gain = new Gain() + + in -> gain.in + gain.out -> out + gain.out -> out2 } + main reactor Hierarchy { - source = new Source(); - container = new GainContainer(); - print = new Print(); - print2 = new Print(); - source.out -> container.in; - container.out -> print.in; - container.out -> print2.in; + source = new Source() + container = new GainContainer() + print = new Print() + print2 = new Print() + + source.out -> container.in + container.out -> print.in + container.out -> print2.in } diff --git a/test/C/src/Hierarchy2.lf b/test/C/src/Hierarchy2.lf index d6146c70d6..c599ef7966 100644 --- a/test/C/src/Hierarchy2.lf +++ b/test/C/src/Hierarchy2.lf @@ -1,28 +1,33 @@ // Test data transport across hierarchy. -target C { - timeout: 5 sec, - fast: true -}; +target C { timeout: 5 sec, fast: true } + reactor Source { - output out:int; - timer t(0, 1 sec); - reaction(t) -> out {= - lf_set(out, 1); - =} + output out: int + + timer t(0, 1 sec) + + reaction(t) -> out {= lf_set(out, 1); =} } + reactor Count { - output out:int; - timer t(0, 1 sec); - state i:int(0); + output out: int + + timer t(0, 1 sec) + + state i: int(0) + reaction(t) -> out {= (self->i)++; lf_set(out, self->i); =} } + reactor Add { - input in1:int; - input in2:int; - output out:int; + input in1: int + input in2: int + + output out: int + reaction(in1, in2) -> out {= int result = 0; if (in1->is_present) result += in1->value; @@ -30,9 +35,12 @@ reactor Add { lf_set(out, result); =} } + reactor Print { - input in:int; - state expected:int(2); + input in: int + + state expected: int(2) + reaction(in) {= printf("Received: %d.\n", in->value); if (in->value != self->expected) { @@ -42,19 +50,25 @@ reactor Print { self->expected++; =} } + reactor AddCount { - input in:int; - output out:int; - count = new Count(); - add = new Add(); - in -> add.in1; - count.out -> add.in2; - add.out -> out; + input in: int + + output out: int + + count = new Count() + add = new Add() + + in -> add.in1 + count.out -> add.in2 + add.out -> out } + main reactor Hierarchy2 { - source = new Source(); - addCount = new AddCount(); - print = new Print(); - source.out -> addCount.in; - addCount.out -> print.in; + source = new Source() + addCount = new AddCount() + print = new Print() + + source.out -> addCount.in + addCount.out -> print.in } diff --git a/test/C/src/IdentifierLength.lf b/test/C/src/IdentifierLength.lf index 42558cced8..f98f5c413d 100644 --- a/test/C/src/IdentifierLength.lf +++ b/test/C/src/IdentifierLength.lf @@ -1,21 +1,25 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - timeout: 10 sec, - fast: true -}; -reactor A_Really_Long_Name_For_A_Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target C { timeout: 10 sec, fast: true } + +reactor A_Really_Long_Name_For_A_Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; lf_set(y, self->count); =} } + reactor Another_Really_Long_Name_For_A_Test_Class { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -25,8 +29,16 @@ reactor Another_Really_Long_Name_For_A_Test_Class { } =} } + main reactor IdentifierLength { - a_really_long_name_for_a_source_instance = new A_Really_Long_Name_For_A_Source(); - another_really_long_name_for_a_test_instance = new Another_Really_Long_Name_For_A_Test_Class(); - a_really_long_name_for_a_source_instance.y -> another_really_long_name_for_a_test_instance.x; + a_really_long_name_for_a_source_instance = new A_Really_Long_Name_For_A_Source( + + ) + another_really_long_name_for_a_test_instance = new Another_Really_Long_Name_For_A_Test_Class( + + ) + + a_really_long_name_for_a_source_instance.y -> + another_really_long_name_for_a_test_instance.x + ; } diff --git a/test/C/src/Import.lf b/test/C/src/Import.lf index 33fabaeb45..c18036f9b1 100644 --- a/test/C/src/Import.lf +++ b/test/C/src/Import.lf @@ -1,11 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target C; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target C + import Imported from "lib/Imported.lf" + main reactor Import { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - lf_set(a.x, 42); - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= lf_set(a.x, 42); =} } diff --git a/test/C/src/ImportComposition.lf b/test/C/src/ImportComposition.lf index 2fe2650eaa..9143a85b86 100644 --- a/test/C/src/ImportComposition.lf +++ b/test/C/src/ImportComposition.lf @@ -1,14 +1,16 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target C; -import ImportedComposition from "lib/ImportedComposition.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target C + +import ImportedComposition from "lib/ImportedComposition.lf" main reactor ImportComposition { - a = new ImportedComposition(); - state received:bool(false); - reaction(startup) -> a.x {= - lf_set(a.x, 42); - =} + a = new ImportedComposition() + + state received: bool(false) + + reaction(startup) -> a.x {= lf_set(a.x, 42); =} + reaction(a.y) {= interval_t receive_time = lf_time_logical_elapsed(); printf("Received %d at time %lld\n", a.y->value, receive_time); @@ -22,6 +24,7 @@ main reactor ImportComposition { exit(2); } =} + reaction(shutdown) {= if (!self->received) { fprintf(stderr, "ERROR: Nothing received.\n"); diff --git a/test/C/src/ImportRenamed.lf b/test/C/src/ImportRenamed.lf index d1a1042629..b1d4cccd4d 100644 --- a/test/C/src/ImportRenamed.lf +++ b/test/C/src/ImportRenamed.lf @@ -1,16 +1,17 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target C; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target C + import Imported as X from "lib/Imported.lf" import Imported as Y from "lib/Imported.lf" import ImportedAgain as Z from "lib/ImportedAgain.lf" + main reactor { - timer t; - a = new X(); - b = new Y(); - c = new Z(); + timer t + + a = new X() + b = new Y() + c = new Z() - reaction(t) -> a.x {= - lf_set(a.x, 42); - =} + reaction(t) -> a.x {= lf_set(a.x, 42); =} } diff --git a/test/C/src/InheritanceAction.lf b/test/C/src/InheritanceAction.lf index 85295c6632..776e37f5ba 100644 --- a/test/C/src/InheritanceAction.lf +++ b/test/C/src/InheritanceAction.lf @@ -1,25 +1,24 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target C { - fast: true -}; +// This test connects a simple counting source to tester that checks against its +// own count. +target C { fast: true } + reactor Source { - logical action foo:int; - output y:int; - reaction(foo) -> y {= - lf_set(y, foo->value); - =} + output y: int + + logical action foo: int + + reaction(foo) -> y {= lf_set(y, foo->value); =} } reactor SourceExtended extends Source { - reaction(startup) -> foo {= - lf_schedule_int(foo, 0, 42); - =} + reaction(startup) -> foo {= lf_schedule_int(foo, 0, 42); =} } reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= (self->count)++; printf("Received %d\n", x->value); @@ -28,14 +27,17 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (self->count == 0) { fprintf(stderr, "FAILURE: No data received.\n"); } =} } + main reactor { - s = new SourceExtended(); - d = new Test(); - s.y -> d.x; + s = new SourceExtended() + d = new Test() + + s.y -> d.x } diff --git a/test/C/src/ManualDelayedReaction.lf b/test/C/src/ManualDelayedReaction.lf index bbaa1ad133..60b2e2547a 100644 --- a/test/C/src/ManualDelayedReaction.lf +++ b/test/C/src/ManualDelayedReaction.lf @@ -1,42 +1,40 @@ target C { - keepalive: false // Set keepalive to false since - // this is a test and schedule is - // called on a physical action from - // within a reaction. This is one of - // the special rare cases where the - // user might want to manually override - // keepalive. -}; + // Set keepalive to false since this is a test and schedule is called on a + // physical action from within a reaction. This is one of the special rare + // cases where the user might want to manually override keepalive. + keepalive: false +} // That's the stuff that shall be generated for the after reactor GeneratedDelay { - input y_in:int; - output y_out:int; - state y_state:int(0); + input y_in: int + + output y_out: int + + physical action act(0 msec) // TODO: delay in act or the schedule call? - // TODO: delay in act or the schedule call? - physical action act(0 msec); + state y_state: int(0) reaction(y_in) -> act {= self->y_state = y_in->value; lf_schedule(act, MSEC(100)); =} - reaction(act) -> y_out {= - lf_set(y_out, self->y_state); - =} + reaction(act) -> y_out {= lf_set(y_out, self->y_state); =} } + reactor Source { - output out:int; - timer t; + output out: int + + timer t + // reaction(t) -> out after 100 msec {= - reaction(t) -> out {= - lf_set(out, 1); - =} + reaction(t) -> out {= lf_set(out, 1); =} } reactor Sink { - input in:int; + input in: int + reaction(in) {= interval_t elapsed_logical = lf_time_logical_elapsed(); interval_t logical = lf_time_logical(); @@ -46,15 +44,14 @@ reactor Sink { printf("Expected %lld but got %lld.\n", MSEC(100), elapsed_logical); exit(1); } - =} deadline(200 msec) {= =} + =} deadline(200 msec) {= =} } + main reactor ManualDelayedReaction { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); - - // source.out -> sink.in; - // rewritten above - source.out -> g.y_in; - g.y_out -> sink.in; + source = new Source() + sink = new Sink() + g = new GeneratedDelay() + + source.out -> g.y_in // source.out -> sink.in + g.y_out -> sink.in } diff --git a/test/C/src/Microsteps.lf b/test/C/src/Microsteps.lf index 0a7616d07c..8238325056 100644 --- a/test/C/src/Microsteps.lf +++ b/test/C/src/Microsteps.lf @@ -1,7 +1,9 @@ -target C; +target C + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= interval_t elapsed = lf_time_logical_elapsed(); printf("Time since start: %lld.\n", elapsed); @@ -24,15 +26,18 @@ reactor Destination { } =} } + main reactor Microsteps { - timer start; - logical action repeat; - d = new Destination(); + timer start + + logical action repeat + + d = new Destination() + reaction(start) -> d.x, repeat {= lf_set(d.x, 1); lf_schedule(repeat, 0); =} - reaction(repeat) -> d.y {= - lf_set(d.y, 1); - =} + + reaction(repeat) -> d.y {= lf_set(d.y, 1); =} } diff --git a/test/C/src/Minimal.lf b/test/C/src/Minimal.lf index 4b0a72aa82..350f92a795 100644 --- a/test/C/src/Minimal.lf +++ b/test/C/src/Minimal.lf @@ -1,8 +1,6 @@ // This is a smoke test of a minimal reactor. -target C; -main reactor Minimal { - reaction(startup) {= - printf("Hello World.\n"); - =} +target C +main reactor Minimal { + reaction(startup) {= printf("Hello World.\n"); =} } diff --git a/test/C/src/MovingAverage.lf b/test/C/src/MovingAverage.lf index e7bc27d089..62edef08cb 100644 --- a/test/C/src/MovingAverage.lf +++ b/test/C/src/MovingAverage.lf @@ -1,29 +1,34 @@ -// Demonstration of a state variable that is an array. -// The MovingAverage reactor computes the moving average of the last -// four inputs and produces that as output. The source is a counting -// sequence. -target C { - timeout: 1 sec, - fast: true -}; +// Demonstration of a state variable that is an array. The MovingAverage reactor +// computes the moving average of the last four inputs and produces that as +// output. The source is a counting sequence. +target C { timeout: 1 sec, fast: true } + import TestDouble from "lib/Test.lf" reactor MASource { - output out:double; - state count:int(0); - timer clock(0, 200 msec); + output out: double + + timer clock(0, 200 msec) + + state count: int(0) + reaction(clock) -> out {= lf_set(out, self->count); self->count++; =} } + reactor MovingAverageImpl { - state delay_line:double[](0.0, 0.0, 0.0); - state index:int(0); - input in:double; - output out:double; + input in: double + + output out: double - reaction(in) -> out {= + state delay_line: double[](0.0, 0.0, 0.0) + state index: int(0) + + reaction(in) -> + out + {= // Calculate the output. // Calculate the output. double sum = in->value; for (int i = 0; i < 3; i++) { @@ -43,9 +48,10 @@ reactor MovingAverageImpl { } main reactor MovingAverage { - s = new MASource(); - m = new MovingAverageImpl(); - p = new TestDouble(expected=(0.0, 0.25, 0.75, 1.5, 2.5, 3.5)); - s.out -> m.in; - m.out -> p.in; + s = new MASource() + m = new MovingAverageImpl() + p = new TestDouble(expected = (0.0, 0.25, 0.75, 1.5, 2.5, 3.5)) + + s.out -> m.in + m.out -> p.in } diff --git a/test/C/src/MultipleContained.lf b/test/C/src/MultipleContained.lf index 5d498cf0ea..4bbfcde08a 100644 --- a/test/C/src/MultipleContained.lf +++ b/test/C/src/MultipleContained.lf @@ -1,14 +1,17 @@ -// Test that a reaction can react to and send two multiple -// ports of a contained reactor. -target C; +// Test that a reaction can react to and send two multiple ports of a contained +// reactor. +target C + reactor Contained { - output trigger:int; - input in1:int; - input in2:int; - state count:int(0); - reaction(startup) -> trigger {= - lf_set(trigger, 42); - =} + input in1: int + input in2: int + + output trigger: int + + state count: int(0) + + reaction(startup) -> trigger {= lf_set(trigger, 42); =} + reaction(in1) {= printf("in1 received %d.\n", in1->value); if (in1->value != 42) { @@ -17,6 +20,7 @@ reactor Contained { } self->count++; =} + reaction(in2) {= printf("in2 received %d.\n", in2->value); if (in2->value != 42) { @@ -25,14 +29,17 @@ reactor Contained { } self->count++; =} + reaction(shutdown) {= if (self->count != 2) { lf_print_error_and_exit("FAILED: Expected two inputs!"); } =} } + main reactor MultipleContained { - c = new Contained(); + c = new Contained() + reaction(c.trigger) -> c.in1, c.in2 {= lf_set(c.in1, c.trigger->value); lf_set(c.in2, c.trigger->value); diff --git a/test/C/src/NativeListsAndTimes.lf b/test/C/src/NativeListsAndTimes.lf index 4218f5d088..e59bb0402c 100644 --- a/test/C/src/NativeListsAndTimes.lf +++ b/test/C/src/NativeListsAndTimes.lf @@ -1,24 +1,26 @@ -target C; +target C // This test passes if it is successfully compiled into valid target code. +main reactor( + x: int(0), + y: time(0), // Units are missing but not required + z(1 msec), // Type is missing but not required + p: int[](1, 2, 3, 4), // List of integers + q: interval_t[](1 msec, 2 msec, 3 msec), // list of time values + r: time({= 0 =}), // Zero-valued target code also is a valid time + g: time[](1 msec, 2 msec) // List of time values +) { + timer tick(0) // Units missing but not required + timer tock(1 sec) // Implicit type time + timer toe(z) // Implicit type time + + state s: time(y) // Reference to explicitly typed time parameter + state t: time(z) // Reference to implicitly typed time parameter + state v: bool // Uninitialized boolean state variable + state w: time // Uninitialized time state variable + state baz(p) // Implicit type int[] + state period(z) // Implicit type time -main reactor(x:int(0), - y:time(0), // Units are missing but not required - z(1 msec), // Type is missing but not required - p:int[](1, 2, 3, 4), // List of integers - q:interval_t[](1 msec, 2 msec, 3 msec), // list of time values - r:time({=0=}), // Zero-valued target code also is a valid time - g:time[](1 msec, 2 msec) // List of time values - ) { - state s:time(y); // Reference to explicitly typed time parameter - state t:time(z); // Reference to implicitly typed time parameter - state v:bool; // Uninitialized boolean state variable - state w:time; // Uninitialized time state variable - timer tick(0); // Units missing but not required - timer tock(1 sec); // Implicit type time - timer toe(z); // Implicit type time - state baz(p); // Implicit type int[] - state period(z); // Implicit type time reaction(tick) {= // Target code =} diff --git a/test/C/src/ParameterHierarchy.lf b/test/C/src/ParameterHierarchy.lf index 77faeb495c..433948bd2b 100644 --- a/test/C/src/ParameterHierarchy.lf +++ b/test/C/src/ParameterHierarchy.lf @@ -1,6 +1,7 @@ // Test that parameter values pass down a deep hierarchy. -target C; -reactor Deep(p:int(0)) { +target C + +reactor Deep(p: int(0)) { reaction(startup) {= if (self->p != 42) { lf_print_error_and_exit("Parameter value is %d. Should have been 42."); @@ -9,12 +10,15 @@ reactor Deep(p:int(0)) { } =} } -reactor Intermediate(p:int(10)) { - a = new Deep(p = p); + +reactor Intermediate(p: int(10)) { + a = new Deep(p = p) } -reactor Another(p:int(20)) { - a = new Intermediate(p = p); + +reactor Another(p: int(20)) { + a = new Intermediate(p = p) } + main reactor ParameterHierarchy { - a = new Intermediate(p = 42); + a = new Intermediate(p = 42) } diff --git a/test/C/src/ParameterizedState.lf b/test/C/src/ParameterizedState.lf index 028ce86262..1965fa1929 100644 --- a/test/C/src/ParameterizedState.lf +++ b/test/C/src/ParameterizedState.lf @@ -1,12 +1,11 @@ -target C; +target C -reactor Foo(bar:int(42)) { - state baz(bar); +reactor Foo(bar: int(42)) { + state baz(bar) - reaction (startup) {= - printf("Baz: %d\n", self->baz); - =} + reaction(startup) {= printf("Baz: %d\n", self->baz); =} } + main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/C/src/PeriodicDesugared.lf b/test/C/src/PeriodicDesugared.lf index 3dc7b23ec7..af192f7d28 100644 --- a/test/C/src/PeriodicDesugared.lf +++ b/test/C/src/PeriodicDesugared.lf @@ -1,13 +1,8 @@ -target C { - fast: true, - timeout: 1 sec -}; +target C { fast: true, timeout: 1 sec } -main reactor ( - offset:time(0), - period:time(500 msec)) { - logical action init(offset); - logical action recur(period); +main reactor(offset: time(0), period: time(500 msec)) { + logical action init(offset) + logical action recur(period) reaction(startup) -> init, recur {= if (self->offset == 0) { diff --git a/test/C/src/PhysicalConnection.lf b/test/C/src/PhysicalConnection.lf index 20d213d37d..a0ae185113 100644 --- a/test/C/src/PhysicalConnection.lf +++ b/test/C/src/PhysicalConnection.lf @@ -1,13 +1,15 @@ /** Test physical connections. */ -target C; +target C + reactor Source { - output out:int; - reaction(startup) -> out {= - lf_set(out, 42); - =} + output out: int + + reaction(startup) -> out {= lf_set(out, 42); =} } + reactor Destination { - input in:int; + input in: int + reaction(in) {= interval_t time = lf_time_physical_elapsed(); printf("Received %d at logical time %lld.\n", in->value, time); @@ -17,8 +19,10 @@ reactor Destination { } =} } + main reactor PhysicalConnection { - source = new Source(); - destination = new Destination(); - source.out ~> destination.in; + source = new Source() + destination = new Destination() + + source.out ~> destination.in } diff --git a/test/C/src/PingPong.lf b/test/C/src/PingPong.lf index d01783627e..b57d9682e2 100644 --- a/test/C/src/PingPong.lf +++ b/test/C/src/PingPong.lf @@ -1,38 +1,39 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * Ping introduces a microstep delay using a logical action - * to break the causality loop. + * Ping introduces a microstep delay using a logical action to break the + * causality loop. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec + * Unthreaded: 97 msec Threaded: 265 msec * - * There is no parallelism in this application, so it does not benefit from being - * being threaded, just some additional overhead. + * There is no parallelism in this application, so it does not benefit from + * being being threaded, just some additional overhead. * * These measurements are total execution time, including startup and shutdown. - * These are about an order of magnitude faster than anything reported in the paper. + * These are about an order of magnitude faster than anything reported in the + * paper. * * @author Edward A. Lee */ -target C { - fast: true -}; -reactor Ping(count:int(10)) { - input receive:int; - output send:int; - state pingsLeft:int(count); - logical action serve; - reaction (startup, serve) -> send {= - lf_set(send, self->pingsLeft--); - =} - reaction (receive) -> serve {= +target C { fast: true } + +reactor Ping(count: int(10)) { + input receive: int + + output send: int + + logical action serve + + state pingsLeft: int(count) + + reaction(startup, serve) -> send {= lf_set(send, self->pingsLeft--); =} + + reaction(receive) -> serve {= if (self->pingsLeft > 0) { lf_schedule(serve, 0); } else { @@ -40,14 +41,19 @@ reactor Ping(count:int(10)) { } =} } -reactor Pong(expected:int(10)) { - input receive:int; - output send:int; - state count:int(0); + +reactor Pong(expected: int(10)) { + input receive: int + + output send: int + + state count: int(0) + reaction(receive) -> send {= self->count++; lf_set(send, receive->value); =} + reaction(shutdown) {= if (self->count != self->expected) { fprintf(stderr, "ERROR: Pong expected to receive %d inputs, but it received %d.\n", @@ -60,8 +66,9 @@ reactor Pong(expected:int(10)) { } main reactor PingPong { - ping = new Ping(); - pong = new Pong(); - ping.send -> pong.receive; - pong.send -> ping.receive; + ping = new Ping() + pong = new Pong() + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/C/src/Preamble.lf b/test/C/src/Preamble.lf index 875757e2f4..9e2e3f3509 100644 --- a/test/C/src/Preamble.lf +++ b/test/C/src/Preamble.lf @@ -1,7 +1,5 @@ -target C { - timeout: 2 sec, - fast: true -}; +target C { timeout: 2 sec, fast: true } + main reactor Preamble { preamble {= #include @@ -9,7 +7,9 @@ main reactor Preamble { return i + 42; } =} - timer t; + + timer t + reaction(t) {= char* s = "42"; int i = atoi(s); diff --git a/test/C/src/ReadOutputOfContainedReactor.lf b/test/C/src/ReadOutputOfContainedReactor.lf index a18c29d4ca..003e5742e5 100644 --- a/test/C/src/ReadOutputOfContainedReactor.lf +++ b/test/C/src/ReadOutputOfContainedReactor.lf @@ -1,16 +1,18 @@ -// Test reacting to and reading outputs from a contained -// reactor in various permutations. +// Test reacting to and reading outputs from a contained reactor in various +// permutations. +target C -target C; reactor Contained { - output out:int; - reaction(startup) -> out {= - lf_set(out, 42); - =} + output out: int + + reaction(startup) -> out {= lf_set(out, 42); =} } + main reactor ReadOutputOfContainedReactor { - c = new Contained(); - state count:int(0); + c = new Contained() + + state count: int(0) + reaction(startup) c.out {= printf("Startup reaction reading output of contained reactor: %d.\n", c.out->value); if (c.out->value != 42) { @@ -19,6 +21,7 @@ main reactor ReadOutputOfContainedReactor { } self->count++; =} + reaction(c.out) {= printf("Reading output of contained reactor: %d.\n", c.out->value); if (c.out->value != 42) { @@ -27,6 +30,7 @@ main reactor ReadOutputOfContainedReactor { } self->count++; =} + reaction(startup, c.out) {= printf("Alternate triggering reading output of contained reactor: %d.\n", c.out->value); if (c.out->value != 42) { @@ -35,6 +39,7 @@ main reactor ReadOutputOfContainedReactor { } self->count++; =} + reaction(shutdown) {= if (self->count != 3) { printf("FAILURE: One of the reactions failed to trigger.\n"); diff --git a/test/C/src/RepeatedInheritance.lf b/test/C/src/RepeatedInheritance.lf index 63ecafbff1..fa9ae2e273 100644 --- a/test/C/src/RepeatedInheritance.lf +++ b/test/C/src/RepeatedInheritance.lf @@ -1,37 +1,43 @@ /** - * This tests for the situation where a reactor extends two other reactors - * that each extend a common reactor. + * This tests for the situation where a reactor extends two other reactors that + * each extend a common reactor. * @author{Edward A. Lee} */ -target C { - timeout: 5 sec, - fast: true -} +target C { timeout: 5 sec, fast: true } -import Count from "lib/Count.lf"; -import TestCount from "lib/TestCount.lf"; +import Count from "lib/Count.lf" +import TestCount from "lib/TestCount.lf" reactor D { - input d:int; + input d: int } + reactor C extends D { - input c:int; + input c: int } + reactor B extends D { - input b:int; + input b: int } + reactor A extends B, C { - input a:int; - output out:int; - reaction(a, b, c, d) -> out {= - lf_set(out, a->value + b->value + c->value + d->value); - =} + input a: int + + output out: int + + reaction( + a, + b, + c, + d + ) -> out {= lf_set(out, a->value + b->value + c->value + d->value); =} } main reactor { - c = new Count(); - a = new A(); - t = new TestCount(start = 4, stride = 4, num_inputs = 6); - (c.out)+ -> a.a, a.b, a.c, a.d; - a.out -> t.in; + c = new Count() + a = new A() + t = new TestCount(start = 4, stride = 4, num_inputs = 6) + + (c.out)+ -> a.a, a.b, a.c, a.d + a.out -> t.in } diff --git a/test/C/src/RequestStop.lf b/test/C/src/RequestStop.lf index 282712aa6d..58a2d6de6a 100644 --- a/test/C/src/RequestStop.lf +++ b/test/C/src/RequestStop.lf @@ -1,5 +1,7 @@ -// Test verifying that lf_request_stop() called in a shutdown reaction is ignored. -target C; +// Test verifying that lf_request_stop() called in a shutdown reaction is +// ignored. +target C + main reactor { reaction(shutdown) {= tag_t current_time = lf_tag(); diff --git a/test/C/src/Schedule.lf b/test/C/src/Schedule.lf index 5ad4b3d718..f82e488cfd 100644 --- a/test/C/src/Schedule.lf +++ b/test/C/src/Schedule.lf @@ -1,11 +1,13 @@ // Example from Schedule section of the C Reactor Target wiki page. -target C; +target C + reactor Schedule2 { - input x:int; - logical action a; - reaction(x) -> a {= - lf_schedule(a, MSEC(200)); - =} + input x: int + + logical action a + + reaction(x) -> a {= lf_schedule(a, MSEC(200)); =} + reaction(a) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("Action triggered at logical time %lld nsec after start.\n", elapsed_time); @@ -15,10 +17,11 @@ reactor Schedule2 { } =} } + main reactor { - a = new Schedule2(); - timer t; - reaction(t) -> a.x {= - lf_set(a.x, 1); - =} + timer t + + a = new Schedule2() + + reaction(t) -> a.x {= lf_set(a.x, 1); =} } diff --git a/test/C/src/ScheduleLogicalAction.lf b/test/C/src/ScheduleLogicalAction.lf index 37e9e08bc0..3075254572 100644 --- a/test/C/src/ScheduleLogicalAction.lf +++ b/test/C/src/ScheduleLogicalAction.lf @@ -1,25 +1,28 @@ -// This checks that a logical action is scheduled the specified -// logical time after the current logical time. -target C { - fast: true, - timeout: 3 sec -}; +// This checks that a logical action is scheduled the specified logical time +// after the current logical time. +target C { fast: true, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - logical action a:int*; + input x: int + + output y: int + + logical action a: int* + reaction(x) -> y, a {= lf_set(y, 2*x->value); // The following uses physical time, incorrectly. lf_schedule(a, MSEC(500)); =} - reaction(a) -> y {= - lf_set(y, -42); - =} + + reaction(a) -> y {= lf_set(y, -42); =} } + reactor print { - state expected_time:time(0); - input x:int; + input x: int + + state expected_time: time(0) + reaction(x) {= interval_t elapsed_time = lf_time_logical_elapsed(); printf("Result is %d\n", x->value); @@ -32,12 +35,14 @@ reactor print { self->expected_time += MSEC(500); =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - lf_set(f.x, 42); - =} - f.y -> p.x; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x + + reaction(t) -> f.x {= lf_set(f.x, 42); =} } diff --git a/test/C/src/ScheduleValue.lf b/test/C/src/ScheduleValue.lf index 2227235dae..48ab957994 100644 --- a/test/C/src/ScheduleValue.lf +++ b/test/C/src/ScheduleValue.lf @@ -1,14 +1,15 @@ /** Test of schedule_value. */ -target C { - timeout: 3 sec -}; +target C { timeout: 3 sec } + main reactor ScheduleValue { - logical action a:char*; + logical action a: char* + reaction(startup) -> a {= char* value = (char*)malloc(6); strcpy(value, "Hello"); lf_schedule_value(a, 0, value, 6); =} + reaction(a) {= printf("Received: %s\n", a->value); if (strcmp(a->value, "Hello") != 0) { diff --git a/test/C/src/SelfLoop.lf b/test/C/src/SelfLoop.lf index 8eee0171f0..e8103a577c 100644 --- a/test/C/src/SelfLoop.lf +++ b/test/C/src/SelfLoop.lf @@ -1,16 +1,19 @@ -target C { - timeout: 1 sec, - fast: true -}; +target C { timeout: 1 sec, fast: true } + reactor Self { - input x:int; - output y:int; - logical action a:int; - state expected:int(43); + input x: int + + output y: int + + logical action a: int + + state expected: int(43) + reaction(a) -> y {= printf("a = %d\n", a->value); lf_set(y, a->value + 1); =} + reaction(x) -> a {= printf("x = %d\n", x->value); if (x->value != self->expected) { @@ -20,9 +23,9 @@ reactor Self { self->expected++; lf_schedule_int(a, MSEC(100), x->value); =} - reaction(startup) -> a {= - lf_schedule_int(a, 0, 42); - =} + + reaction(startup) -> a {= lf_schedule_int(a, 0, 42); =} + reaction(shutdown) {= if (self->expected <= 43) { fprintf(stderr, "Received no data.\n"); @@ -30,7 +33,9 @@ reactor Self { } =} } + main reactor SelfLoop { - u = new Self(); - u.y -> u.x; + u = new Self() + + u.y -> u.x } diff --git a/test/C/src/SendingInside.lf b/test/C/src/SendingInside.lf index 155a8e83fe..5e5c28eb02 100644 --- a/test/C/src/SendingInside.lf +++ b/test/C/src/SendingInside.lf @@ -1,12 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. -target C { - timeout: 10 sec, - fast: true -}; +// This tests a reactor that contains another reactor and also has its own +// reaction that routes inputs to the contained reactor. +target C { timeout: 10 sec, fast: true } + reactor Printer { - input x:int; - state count:int(1); + input x: int + + state count: int(1) + reaction(x) {= printf("Inside reactor received: %d\n", x->value); if (x->value != self->count) { @@ -16,10 +16,14 @@ reactor Printer { self->count++; =} } + main reactor SendingInside { - state count:int(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count: int(0) + reaction(t) -> p.x {= (self->count)++; lf_set(p.x, self->count); diff --git a/test/C/src/SendingInside2.lf b/test/C/src/SendingInside2.lf index 1833d84035..c9df03bf7b 100644 --- a/test/C/src/SendingInside2.lf +++ b/test/C/src/SendingInside2.lf @@ -1,6 +1,8 @@ -target C; +target C + reactor Printer { - input x:int; + input x: int + reaction(x) {= printf("Inside reactor received: %d\n", x->value); if (x->value != 1) { @@ -9,10 +11,11 @@ reactor Printer { } =} } + main reactor SendingInside2 { - timer t; - p = new Printer(); - reaction(t) -> p.x {= - lf_set(p.x, 1); - =} + timer t + + p = new Printer() + + reaction(t) -> p.x {= lf_set(p.x, 1); =} } diff --git a/test/C/src/SendsPointerTest.lf b/test/C/src/SendsPointerTest.lf index 00466a3fff..38142730c1 100644 --- a/test/C/src/SendsPointerTest.lf +++ b/test/C/src/SendsPointerTest.lf @@ -1,19 +1,21 @@ -// Source produces a dynamically allocated struct, which it passes -// to Print. Reference counting ensures that the struct is freed. -target C; -preamble {= - typedef int* int_pointer; -=} -reactor SendsPointer { - output out:int_pointer; +// Source produces a dynamically allocated struct, which it passes to Print. +// Reference counting ensures that the struct is freed. +target C + +preamble {= typedef int* int_pointer; =} + +reactor SendsPointer { + output out: int_pointer + reaction(startup) -> out {= static int my_constant = 42; lf_set(out, &my_constant); =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:int_pointer; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: int_pointer + reaction(in) {= printf("Received: %d\n", *in->value); if (*in->value != self->expected) { @@ -22,8 +24,10 @@ reactor Print(expected:int(42)) { } =} } + main reactor SendsPointerTest { - s = new SendsPointer(); - p = new Print(); - s.out -> p.in; + s = new SendsPointer() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/SetArray.lf b/test/C/src/SetArray.lf index fcc0312894..f04aee9431 100644 --- a/test/C/src/SetArray.lf +++ b/test/C/src/SetArray.lf @@ -1,10 +1,13 @@ -// This tests SET_ARRAY() -// This tests the use of the "polymorphic" delay reactor on a struct. -// It delays by a logical time any pointer datatype. -target C; +// This tests SET_ARRAY(). This tests the use of the "polymorphic" delay reactor +// on a struct. It delays by a logical time any pointer datatype. +target C + reactor Source { - output out:int[]; - reaction(startup) -> out {= + output out: int[] + + reaction(startup) -> + out + {= // Dynamically allocate an output array of length 3. // Dynamically allocate an output array of length 3. int* array = (int*)malloc(3 * sizeof(int)); SET_ARRAY(out, array, sizeof(int), 3); @@ -15,9 +18,11 @@ reactor Source { out->value[2] = 2; =} } + // The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int[]; +reactor Print(scale: int(1)) { + input in: int[] + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -38,8 +43,10 @@ reactor Print(scale:int(1)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/SetCopyConstructor.lf b/test/C/src/SetCopyConstructor.lf index ad61a9cf26..e6da7a906a 100644 --- a/test/C/src/SetCopyConstructor.lf +++ b/test/C/src/SetCopyConstructor.lf @@ -1,14 +1,14 @@ -// This tests lf_set_copy_constructor() -// This tests the use of the "polymorphic" delay reactor on a struct. -// It delays by a logical time any pointer datatype. -target C {files: ["include/array.h"]}; +// This tests lf_set_copy_constructor(). This tests the use of the "polymorphic" +// delay reactor on a struct. It delays by a logical time any pointer datatype. +target C { files: ["include/array.h"] } preamble {= #include "array.h" =} reactor Source { - output out:int_array_t*; + output out: int_array_t* + reaction(startup) -> out {= lf_set_copy_constructor(out, int_array_copy_constructor); lf_set_destructor(out, int_array_destructor); @@ -20,7 +20,8 @@ reactor Source { } reactor Destination { - mutable input in:int_array_t*; + mutable input in: int_array_t* + reaction(in) {= if (in->value->data[0] != 42 || in->value->data[1] != 24) { lf_print_error_and_exit("ERROR: Input data does not match expected data"); @@ -33,9 +34,10 @@ reactor Destination { } main reactor { - s = new Source(); - d1 = new Destination(); - d2 = new Destination(); - s.out -> d1.in; - s.out -> d2.in; + s = new Source() + d1 = new Destination() + d2 = new Destination() + + s.out -> d1.in + s.out -> d2.in } diff --git a/test/C/src/SetDestructor.lf b/test/C/src/SetDestructor.lf index 9e9b4b96c6..c429b79e4f 100644 --- a/test/C/src/SetDestructor.lf +++ b/test/C/src/SetDestructor.lf @@ -1,14 +1,14 @@ -// This tests lf_set_destructor() -// This tests the use of the "polymorphic" delay reactor on a struct. -// It delays by a logical time any pointer datatype. -target C {files: ["include/array.h"]}; +// This tests lf_set_destructor(). This tests the use of the "polymorphic" delay +// reactor on a struct. It delays by a logical time any pointer datatype. +target C { files: ["include/array.h"] } preamble {= #include "array.h" =} reactor Source { - output out:int_array_t*; + output out: int_array_t* + reaction(startup) -> out {= lf_print("%d", out->destructor); lf_set_destructor(out, int_array_destructor); @@ -19,9 +19,10 @@ reactor Source { lf_set(out, array); =} } -// The scale parameter is just for testing. -reactor Print(scale:int(1)) { - input in:int_array_t*; + +reactor Print(scale: int(1)) { // The scale parameter is just for testing. + input in: int_array_t* + reaction(in) {= int count = 0; // For testing. bool failed = false; // For testing. @@ -40,8 +41,10 @@ reactor Print(scale:int(1)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/SetToken.lf b/test/C/src/SetToken.lf index 9fa13875cd..381f2b01e6 100644 --- a/test/C/src/SetToken.lf +++ b/test/C/src/SetToken.lf @@ -1,18 +1,19 @@ // Illustration of lf_set_token() in the wiki. -target C; +target C + reactor Source { - output out:int*; - logical action a:int; - reaction(startup) -> a {= - lf_schedule_int(a, MSEC(200), 42); - =} - reaction(a) -> out {= - lf_set_token(out, a->token); - =} + output out: int* + + logical action a: int + + reaction(startup) -> a {= lf_schedule_int(a, MSEC(200), 42); =} + + reaction(a) -> out {= lf_set_token(out, a->token); =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:int*; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: int* + reaction(in) {= printf("Received %d\n", *(in->value)); if (*(in->value) != 42) { @@ -21,8 +22,10 @@ reactor Print(expected:int(42)) { } =} } + main reactor SetToken { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/SimpleDeadline.lf b/test/C/src/SimpleDeadline.lf index 3de7cc3ec5..c559193c14 100644 --- a/test/C/src/SimpleDeadline.lf +++ b/test/C/src/SimpleDeadline.lf @@ -1,10 +1,13 @@ // Test local deadline, where a deadline is associated with a reaction -// definition. This test triggers a reaction exactly once with a -// deadline violation. -target C; -reactor Deadline(threshold:time(100 msec)) { - input x:int; - output deadlineViolation:bool; +// definition. This test triggers a reaction exactly once with a deadline +// violation. +target C + +reactor Deadline(threshold: time(100 msec)) { + input x: int + + output deadlineViolation: bool + reaction(x) -> deadlineViolation {= printf("ERROR: Deadline violation was not detected!\n"); exit(1); @@ -13,19 +16,25 @@ reactor Deadline(threshold:time(100 msec)) { lf_set(deadlineViolation, true); =} } + reactor Print { - input in:bool; + input in: bool + reaction(in) {= if (in) { printf("Output successfully produced by deadline handler.\n"); } =} } + main reactor SimpleDeadline { - timer start; - d = new Deadline(threshold = 10 msec); - p = new Print(); - d.deadlineViolation -> p.in; + timer start + + d = new Deadline(threshold = 10 msec) + p = new Print() + + d.deadlineViolation -> p.in + reaction(start) -> d.x {= instant_t sleep_time_ns = 20000000; lf_nanosleep(sleep_time_ns); diff --git a/test/C/src/SimpleImport.lf b/test/C/src/SimpleImport.lf index 37e5715a86..71258bd678 100644 --- a/test/C/src/SimpleImport.lf +++ b/test/C/src/SimpleImport.lf @@ -1,7 +1,8 @@ -target C; -import HelloWorld2 from "HelloWorld.lf"; +target C + +import HelloWorld2 from "HelloWorld.lf" main reactor SimpleImport { - a = new HelloWorld2(); - b = new HelloWorld2(); + a = new HelloWorld2() + b = new HelloWorld2() } diff --git a/test/C/src/SlowingClock.lf b/test/C/src/SlowingClock.lf index 16b32f9951..49a44c90f1 100644 --- a/test/C/src/SlowingClock.lf +++ b/test/C/src/SlowingClock.lf @@ -1,20 +1,19 @@ /** * Events are scheduled with increasing additional delays of 0, 100, 300, 600 - * msec on a logical action with a minimum delay of 100 msec. - * The use of the logical action ensures the elapsed time jumps exactly from - * 0 to 100, 300, 600, and 1000 msec. + * msec on a logical action with a minimum delay of 100 msec. The use of the + * logical action ensures the elapsed time jumps exactly from 0 to 100, 300, + * 600, and 1000 msec. */ -target C { - timeout: 1 sec, - fast: true, -}; +target C { timeout: 1 sec, fast: true } + main reactor SlowingClock { - logical action a(100 msec); - state interval:time(100 msec); - state expected_time:time(100 msec); - reaction(startup) -> a {= - lf_schedule(a, 0); - =} + logical action a(100 msec) + + state interval: time(100 msec) + state expected_time: time(100 msec) + + reaction(startup) -> a {= lf_schedule(a, 0); =} + reaction(a) -> a {= instant_t elapsed_logical_time = lf_time_logical_elapsed(); printf("Logical time since start: \%lld nsec.\n", @@ -30,6 +29,7 @@ main reactor SlowingClock { self->expected_time += MSEC(100) + self->interval; self->interval += MSEC(100); =} + reaction(shutdown) {= if (self->expected_time != MSEC(1500)) { printf("ERROR: Expected the next expected time to be: 1500000000 nsec.\n"); diff --git a/test/C/src/SlowingClockPhysical.lf b/test/C/src/SlowingClockPhysical.lf index 1bf257f54d..daaca1321d 100644 --- a/test/C/src/SlowingClockPhysical.lf +++ b/test/C/src/SlowingClockPhysical.lf @@ -1,22 +1,23 @@ /** -/* * Events are scheduled with increasing additional delays of 0, 100, 300, 600 - * msec on a physical action with a minimum delay of 100 msec. - * The use of the physical action makes the elapsed time jumps from 0 to - * approximately 100 msec, to approximatly 300 msec thereafter, drifting away - * further with each new event. + * msec on a physical action with a minimum delay of 100 msec. The use of the + * physical action makes the elapsed time jumps from 0 to approximately 100 + * msec, to approximatly 300 msec thereafter, drifting away further with each + * new event. */ -target C { - timeout: 1500 msec -}; +target C { timeout: 1500 msec } + main reactor SlowingClockPhysical { - physical action a(100 msec); - state interval:time(100 msec); - state expected_time:time(100 msec); + physical action a(100 msec) + + state interval: time(100 msec) + state expected_time: time(100 msec) + reaction(startup) -> a {= self->expected_time = MSEC(100); lf_schedule(a, 0); =} + reaction(a) -> a {= instant_t elapsed_logical_time = lf_time_logical_elapsed(); printf("Logical time since start: \%lld nsec.\n", @@ -33,6 +34,7 @@ main reactor SlowingClockPhysical { lf_schedule(a, self->interval); printf("Scheduling next to occur approximately after: \%lld nsec.\n", self->interval); =} + reaction(shutdown) {= if (self->expected_time < MSEC(500)) { printf("ERROR: Expected the next expected time to be at least: 500000000 nsec.\n"); diff --git a/test/C/src/StartupOutFromInside.lf b/test/C/src/StartupOutFromInside.lf index 806abb7482..cad2d282bf 100644 --- a/test/C/src/StartupOutFromInside.lf +++ b/test/C/src/StartupOutFromInside.lf @@ -1,14 +1,14 @@ -target C; +target C reactor Bar { - output out:int; - reaction(startup) -> out {= - lf_set(out, 42); - =} + output out: int + + reaction(startup) -> out {= lf_set(out, 42); =} } main reactor StartupOutFromInside { - bar = new Bar(); + bar = new Bar() + reaction(startup) bar.out {= printf("Output from bar: %d\n", bar.out->value); if (bar.out->value != 42) { diff --git a/test/C/src/Starvation.lf b/test/C/src/Starvation.lf index dea4b0d718..4c561c52cb 100644 --- a/test/C/src/Starvation.lf +++ b/test/C/src/Starvation.lf @@ -1,15 +1,18 @@ /** - * Test that the starvation functionality in absence of - * the "keepalive: true" target property indeed works as - * expected. + * Test that the starvation functionality in absence of the "keepalive: true" + * target property indeed works as expected. * * @author Soroush Bateni */ -target C; -reactor SuperDenseSender(number_of_iterations:int(10)){ - logical action loop; - output out:int; - state iterator:int(0); +target C + +reactor SuperDenseSender(number_of_iterations: int(10)) { + output out: int + + logical action loop + + state iterator: int(0) + reaction(startup, loop) -> out {= if (self->iterator < self->number_of_iterations) { lf_schedule(loop, 0); @@ -33,8 +36,9 @@ reactor SuperDenseSender(number_of_iterations:int(10)){ =} } - reactor SuperDenseReceiver(number_of_iterations:int(10)) { - input in:int; +reactor SuperDenseReceiver(number_of_iterations: int(10)) { + input in: int + reaction(in) {= tag_t current_tag = lf_tag(); printf("Received %d at tag (%lld, %u).\n", @@ -59,8 +63,8 @@ reactor SuperDenseSender(number_of_iterations:int(10)){ } main reactor Starvation { - sender = new SuperDenseSender(); - receiver = new SuperDenseReceiver(); + sender = new SuperDenseSender() + receiver = new SuperDenseReceiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/Stop.lf b/test/C/src/Stop.lf index cba17dffd9..35df6e95ec 100644 --- a/test/C/src/Stop.lf +++ b/test/C/src/Stop.lf @@ -1,17 +1,17 @@ -/* +/** * A test for the lf_request_stop() functionality in Lingua Franca. * * @author Soroush Bateni */ - target C { - timeout: 11 msec -}; +target C { timeout: 11 msec } import Sender from "lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state reaction_invoked_correctly:bool(false); + input in: int + + state reaction_invoked_correctly: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -54,8 +54,8 @@ reactor Consumer { } main reactor { - consumer = new Consumer(); - producer = new Sender(break_interval = 1 msec); + consumer = new Consumer() + producer = new Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/StopZero.lf b/test/C/src/StopZero.lf index a5d9da364f..687a4b5be4 100644 --- a/test/C/src/StopZero.lf +++ b/test/C/src/StopZero.lf @@ -1,17 +1,20 @@ /** - * Test for lf_request_stop() at tag (0,0). - * This also tests for logically simultaneous calls - * to lf_request_stop(). + * Test for lf_request_stop() at tag (0,0). This also tests for logically + * simultaneous calls to lf_request_stop(). * * @author Soroush Bateni */ -target C; +target C reactor Sender { - output out:int; - state reaction_invoked_correctly:bool(false); - timer t(0, 1 usec); - logical action act; + output out: int + + timer t(0, 1 usec) + + logical action act + + state reaction_invoked_correctly: bool(false) + reaction(t) -> out, act {= printf("Sending 42 at (%lld, %u).\n", lf_time_logical_elapsed(), @@ -33,13 +36,15 @@ reactor Sender { exit(1); } =} - reaction(act) {= + + reaction(act) {= // Reaction should be invoked at (0,1) // Reaction should be invoked at (0,1) tag_t one = (tag_t) { .time = lf_time_start(), .microstep = 1u }; if (lf_tag_compare(lf_tag(), one) == 0) { self->reaction_invoked_correctly = true; } =} + reaction(shutdown) {= if (lf_time_logical_elapsed() != USEC(0) || lf_tag().microstep != 1) { @@ -62,7 +67,8 @@ reactor Sender { } reactor Receiver { - input in:int; + input in: int + reaction(in) {= printf("Received %d at (%lld, %u).\n", in->value, @@ -78,7 +84,9 @@ reactor Receiver { } =} - reaction(shutdown) {= + reaction( + shutdown + ) {= // Shutdown events must occur at (0, 1) on the receiver. // Shutdown events must occur at (0, 1) on the // receiver. if (lf_time_logical_elapsed() != USEC(0) || @@ -96,8 +104,8 @@ reactor Receiver { } main reactor StopZero { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in; + sender.out -> receiver.in } diff --git a/test/C/src/Stride.lf b/test/C/src/Stride.lf index de73fbd78b..eb55da256d 100644 --- a/test/C/src/Stride.lf +++ b/test/C/src/Stride.lf @@ -1,21 +1,25 @@ -// This example illustrates state variables and parameters on the wiki. -// For this test, success is just compiling and running. -target C { - timeout: 2 sec, - fast: true -}; -reactor Count(stride:int(1)) { - state count:int(1); - output y:int; - timer t(0, 100 msec); +// This example illustrates state variables and parameters on the wiki. For this +// test, success is just compiling and running. +target C { timeout: 2 sec, fast: true } + +reactor Count(stride: int(1)) { + output y: int + + timer t(0, 100 msec) + + state count: int(1) + reaction(t) -> y {= lf_set(y, self->count); self->count += self->stride; =} } + reactor Display { - input x:int; - state expected:int(1); // for testing. + input x: int + + state expected: int(1) // for testing. + reaction(x) {= printf("Received: %d.\n", x->value); if (x->value != self->expected) { @@ -24,8 +28,10 @@ reactor Display { self->expected += 2; =} } + main reactor Stride { - c = new Count(stride = 2); - d = new Display(); - c.y -> d.x; + c = new Count(stride = 2) + d = new Display() + + c.y -> d.x } diff --git a/test/C/src/StructAsState.lf b/test/C/src/StructAsState.lf index 2dc942285f..c8f119010c 100644 --- a/test/C/src/StructAsState.lf +++ b/test/C/src/StructAsState.lf @@ -1,5 +1,7 @@ -// Check that a state variable can have a statically initialized struct as a value. -target C; +// Check that a state variable can have a statically initialized struct as a +// value. +target C + main reactor StructAsState { preamble {= typedef struct hello_t { @@ -7,7 +9,10 @@ main reactor StructAsState { int value; } hello_t; =} - state s:hello_t("Earth", 42); // Notice that target code delimiters are no longer necessary. + + // Notice that target code delimiters are no longer necessary. + state s: hello_t("Earth", 42) + reaction(startup) {= printf("State s.name=\"%s\", value=%d.\n", self->s.name, self->s.value); if (self->s.value != 42) { diff --git a/test/C/src/StructAsType.lf b/test/C/src/StructAsType.lf index c8ba4e5f43..3d90b2903f 100644 --- a/test/C/src/StructAsType.lf +++ b/test/C/src/StructAsType.lf @@ -1,15 +1,17 @@ -// Source produces a struct directly, rather than a pointer to -// a struct. -target C {files: include/hello.h}; +// Source produces a struct directly, rather than a pointer to a struct. +target C { files: include/hello.h } preamble {= #include "hello.h" =} reactor Source { - output out:hello_t; + output out: hello_t - reaction(startup) -> out {= + reaction(startup) -> + out + // Create the struct on the stack and then copy it to the output as follows: + {= // Create the struct on the stack and then copy // it to the output as follows: struct hello_t temp = {"Earth", 42}; @@ -21,9 +23,10 @@ reactor Source { // lf_set(out, ((hello_t){"Earth", 42})); =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:hello_t; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: hello_t + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value.name, in->value.value); if (in->value.value != self->expected) { @@ -32,8 +35,10 @@ reactor Print(expected:int(42)) { } =} } + main reactor StructAsType { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/StructAsTypeDirect.lf b/test/C/src/StructAsTypeDirect.lf index 651b10d3f2..90a40b9182 100644 --- a/test/C/src/StructAsTypeDirect.lf +++ b/test/C/src/StructAsTypeDirect.lf @@ -1,22 +1,23 @@ -// Source produces a struct directly, rather than a pointer to -// a struct. -target C {files: include/hello.h}; +// Source produces a struct directly, rather than a pointer to a struct. +target C { files: include/hello.h } preamble {= #include "hello.h" =} reactor Source { - output out:hello_t; + output out: hello_t + reaction(startup) -> out {= out->value.name = "Earth"; out->value.value = 42; SET_PRESENT(out); =} } -// expected parameter is for testing. -reactor Print(expected:int(42)) { - input in:hello_t; + +reactor Print(expected: int(42)) { // expected parameter is for testing. + input in: hello_t + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value.name, in->value.value); if (in->value.value != self->expected) { @@ -25,8 +26,10 @@ reactor Print(expected:int(42)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/C/src/StructParallel.lf b/test/C/src/StructParallel.lf index 16bfbacb4a..baeec7626b 100644 --- a/test/C/src/StructParallel.lf +++ b/test/C/src/StructParallel.lf @@ -1,17 +1,23 @@ -// Source allocates an array dynamically and then sends it to two reactors, -// each of which want to modify it. -// NOTE: Ideally, only one copy would be made, but this requires -// modifying the precedence graph between reactions. -target C {files: ["include/hello.h"]}; -import Source from "StructScale.lf"; +/** + * Source allocates an array dynamically and then sends it to two reactors, each + * of which want to modify it. + * + * NOTE: Ideally, only one copy would be made, but this requires modifying the + * precedence graph between reactions. + */ +target C { files: ["include/hello.h"] } + +import Source from "StructScale.lf" preamble {= #include "hello.h" =} -reactor Check(expected:int(42)) { - input in:hello_t*; - state invoked:bool(false); +reactor Check(expected: int(42)) { + input in: hello_t* + + state invoked: bool(false) + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); if (in->value->value != self->expected) { @@ -20,6 +26,7 @@ reactor Check(expected:int(42)) { } self->invoked = true; =} + reaction(shutdown) {= if (self->invoked == false) { fprintf(stderr, "ERROR: No data received.\n"); @@ -28,11 +35,13 @@ reactor Check(expected:int(42)) { =} } -reactor Print(scale:int(2)) { - // Mutable keyword indicates that this reactor wants a writable copy of the input. - mutable input in:hello_t*; +reactor Print(scale: int(2)) { + // Mutable keyword indicates that this reactor wants a writable copy of the + // input. + mutable input in: hello_t* + + output out: hello_t* - output out:hello_t*; reaction(in) -> out {= in->value->value *= self->scale; printf("Print received name = %s, value = %d\n", in->value->name, in->value->value); @@ -41,13 +50,14 @@ reactor Print(scale:int(2)) { } main reactor StructParallel { - s = new Source(); - c1 = new Print(); - c2 = new Print(scale = 3); - p1 = new Check(expected = 84); - p2 = new Check(expected = 126); - s.out -> c1.in; - s.out -> c2.in; - c1.out -> p1.in; - c2.out -> p2.in; + s = new Source() + c1 = new Print() + c2 = new Print(scale = 3) + p1 = new Check(expected = 84) + p2 = new Check(expected = 126) + + s.out -> c1.in + s.out -> c2.in + c1.out -> p1.in + c2.out -> p2.in } diff --git a/test/C/src/StructPrint.lf b/test/C/src/StructPrint.lf index a34dee51a3..0a0cb4edb7 100644 --- a/test/C/src/StructPrint.lf +++ b/test/C/src/StructPrint.lf @@ -1,14 +1,17 @@ -// Source produces a dynamically allocated struct, which it passes -// to Print. Reference counting ensures that the struct is freed. -target C {files: ["include/hello.h"]}; +// Source produces a dynamically allocated struct, which it passes to Print. +// Reference counting ensures that the struct is freed. +target C { files: ["include/hello.h"] } preamble {= #include "hello.h" =} reactor Print { - output out:hello_t*; - reaction(startup) -> out {= + output out: hello_t* + + reaction(startup) -> + out + {= // Dynamically allocate an output struct. // Dynamically allocate an output struct. SET_NEW(out); // Above allocates a struct, which then must be populated. @@ -17,9 +20,9 @@ reactor Print { =} } -// expected parameter is for testing. -reactor Check(expected:int(42)) { - input in:hello_t*; +reactor Check(expected: int(42)) { // expected parameter is for testing. + input in: hello_t* + reaction(in) {= printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); if (in->value->value != self->expected) { @@ -30,7 +33,8 @@ reactor Check(expected:int(42)) { } main reactor { - s = new Print(); - p = new Check(); - s.out -> p.in; + s = new Print() + p = new Check() + + s.out -> p.in } diff --git a/test/C/src/StructScale.lf b/test/C/src/StructScale.lf index 3068dbde5b..b7a6036136 100644 --- a/test/C/src/StructScale.lf +++ b/test/C/src/StructScale.lf @@ -1,17 +1,19 @@ -// Source produces a dynamically allocated struct, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original struct. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target C {files: ["include/hello.h"]}; +// Source produces a dynamically allocated struct, which it passes to Scale. +// Scale requests a writable copy, which, instead of copying, it just gets +// ownership of the original struct. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target C { files: ["include/hello.h"] } preamble {= #include "hello.h" =} reactor Source { - output out:hello_t*; - reaction(startup) -> out {= + output out: hello_t* + + reaction(startup) -> + out + {= // Dynamically allocate an output struct. // Dynamically allocate an output struct. SET_NEW(out); // Above allocates a struct, which then must be populated. @@ -20,11 +22,10 @@ reactor Source { =} } -// expected parameter is for testing. -reactor TestInput(expected:int(42)) { +reactor TestInput(expected: int(42)) { // expected parameter is for testing. + input in: hello_t* - input in:hello_t*; - state invoked:bool(false); + state invoked: bool(false) reaction(in) {= printf("Received: name = %s, value = %d\n", in->value->name, in->value->value); @@ -34,6 +35,7 @@ reactor TestInput(expected:int(42)) { } self->invoked = true; =} + reaction(shutdown) {= if (self->invoked == false) { fprintf(stderr, "ERROR: No data received.\n"); @@ -42,11 +44,13 @@ reactor TestInput(expected:int(42)) { =} } -reactor Print(scale:int(2)) { - // Mutable keyword indicates that this reactor wants a writable copy of the input. - mutable input in:hello_t*; +reactor Print(scale: int(2)) { + // Mutable keyword indicates that this reactor wants a writable copy of the + // input. + mutable input in: hello_t* + + output out: hello_t* - output out:hello_t*; reaction(in) -> out {= in->value->value *= self->scale; lf_set_token(out, in->token); @@ -54,9 +58,10 @@ reactor Print(scale:int(2)) { } main reactor StructScale { - s = new Source(); - c = new Print(); - p = new TestInput(expected=84); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Print() + p = new TestInput(expected = 84) + + s.out -> c.in + c.out -> p.in } diff --git a/test/C/src/SubclassesAndStartup.lf b/test/C/src/SubclassesAndStartup.lf index d08a335fb7..a8001a907d 100644 --- a/test/C/src/SubclassesAndStartup.lf +++ b/test/C/src/SubclassesAndStartup.lf @@ -1,11 +1,13 @@ -target C; +target C reactor Super { - state count:int(0); - reaction (startup) {= + state count: int(0) + + reaction(startup) {= printf("%s(Super) started\n", self->name); self->count++; =} + reaction(shutdown) {= if (self->count == 0) { fprintf(stderr, "No startup reaction was invoked!\n"); @@ -14,8 +16,8 @@ reactor Super { =} } -reactor SubA(name:string("SubA")) extends Super { - reaction (startup) {= +reactor SubA(name: string("SubA")) extends Super { + reaction(startup) {= printf("%s started\n", self->name); if (self->count == 0) { fprintf(stderr, "Base class startup reaction was not invoked!\n"); @@ -24,8 +26,8 @@ reactor SubA(name:string("SubA")) extends Super { =} } -reactor SubB(name:string("SubB")) extends Super { - reaction (startup) {= +reactor SubB(name: string("SubB")) extends Super { + reaction(startup) {= printf("%s started\n", self->name); if (self->count == 0) { fprintf(stderr, "Base class startup reaction was not invoked!\n"); @@ -35,6 +37,6 @@ reactor SubB(name:string("SubB")) extends Super { } main reactor SubclassesAndStartup { - a = new SubA(); - b = new SubB(); + a = new SubA() + b = new SubB() } diff --git a/test/C/src/TestForPreviousOutput.lf b/test/C/src/TestForPreviousOutput.lf index deb29ca943..396ceaf0d1 100644 --- a/test/C/src/TestForPreviousOutput.lf +++ b/test/C/src/TestForPreviousOutput.lf @@ -1,9 +1,14 @@ -// This tests the mechanism for testing whether a previous reaction has -// produced a given output. The output should always be 42. -target C; +// This tests the mechanism for testing whether a previous reaction has produced +// a given output. The output should always be 42. +target C + reactor Source { - output out:int; - reaction(startup) -> out {= + output out: int + + reaction(startup) -> + out + // Set a seed for random number generation based on the current time. + {= // Set a seed for random number generation based on the current time. srand(time(0)); // Randomly produce an output or not. @@ -11,6 +16,7 @@ reactor Source { lf_set(out, 21); } =} + reaction(startup) -> out {= if (out->is_present) { lf_set(out, 2 * out->value); @@ -19,8 +25,10 @@ reactor Source { } =} } + reactor Sink { - input in:int; + input in: int + reaction(in) {= printf("Received %d.\n", in->value); if (in->value != 42) { @@ -29,8 +37,10 @@ reactor Sink { } =} } + main reactor TestForPreviousOutput { - s = new Source(); - d = new Sink(); - s.out -> d.in; + s = new Source() + d = new Sink() + + s.out -> d.in } diff --git a/test/C/src/TimeLimit.lf b/test/C/src/TimeLimit.lf index 107cbf8126..4e31f0e768 100644 --- a/test/C/src/TimeLimit.lf +++ b/test/C/src/TimeLimit.lf @@ -1,31 +1,34 @@ -// Test that the stop function can be used to internally impose a -// a time limit. -// This is also used to test performance (number of reactions per second). -// See [Benchmarks wiki page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt or getting the wrong data. -// On a 2.6 GHz Intel Core i7 running MacOS Mojave, using a single core, -// this executes 10,000,000 cycles (two reactions in each cycle) in 0.6 seconds, -// for over 32 million reactions per second. -// This translates to 31 nanoseconds per reaction invocation. -target C { - flags: "-O2", - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that the stop function can be used to internally impose a a time limit. +// This is also used to test performance (number of reactions per second). See +// [Benchmarks wiki +// page](https://github.com/icyphy/lingua-franca/wiki/Benchmarks). Correct +// output for this 1, 2, 3, 4. Failure for this test is failing to halt or +// getting the wrong data. On a 2.6 GHz Intel Core i7 running MacOS Mojave, +// using a single core, this executes 10,000,000 cycles (two reactions in each +// cycle) in 0.6 seconds, for over 32 million reactions per second. This +// translates to 31 nanoseconds per reaction invocation. +target C { flags: "-O2", fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= (self->count)++; //printf("Reacting at time %ld.\n", lf_time_logical_elapsed()); lf_set(y, self->count); =} } + reactor Destination { - input x:int; - state s:int(1); - reaction(x) {= + input x: int + + state s: int(1) + + reaction(x) {= // printf("%dn", x->value); // printf("%d\n", x->value); if (x->value != self->s) { printf("Error: Expected %d and got %d.\n", self->s, x->value); @@ -33,6 +36,7 @@ reactor Destination { } self->s++; =} + reaction(shutdown) {= printf("**** shutdown reaction invoked.\n"); if (self->s != 10000002) { @@ -42,12 +46,14 @@ reactor Destination { lf_print("Approx. time per reaction: %lldns", lf_time_physical_elapsed()/(self->s+1)); =} } -main reactor TimeLimit(period:time(1 usec)) { - timer stop(10 secs); - reaction(stop) {= - lf_request_stop(); - =} - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; + +main reactor TimeLimit(period: time(1 usec)) { + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x + + reaction(stop) {= lf_request_stop(); =} } diff --git a/test/C/src/TimeState.lf b/test/C/src/TimeState.lf index 4f680df27b..790679ccda 100644 --- a/test/C/src/TimeState.lf +++ b/test/C/src/TimeState.lf @@ -1,13 +1,11 @@ -target C; +target C -reactor Foo(bar:int(42)) { - state baz:time(500 msec); +reactor Foo(bar: int(42)) { + state baz: time(500 msec) - reaction (startup) {= - printf("Baz: %lld\n", self->baz); - =} + reaction(startup) {= printf("Baz: %lld\n", self->baz); =} } main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/C/src/Timeout.lf b/test/C/src/Timeout.lf index 49dbe232e6..d638f54045 100644 --- a/test/C/src/Timeout.lf +++ b/test/C/src/Timeout.lf @@ -1,17 +1,17 @@ -/* +/** * A test for the timeout functionality in Lingua Franca. * * @author Soroush Bateni */ -target C { - timeout: 11 msec -}; +target C { timeout: 11 msec } import Sender from "lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state success:bool(false); + input in: int + + state success: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -40,8 +40,8 @@ reactor Consumer { } main reactor Timeout { - consumer = new Consumer(); - producer = new Sender(break_interval = 1 msec); + consumer = new Consumer() + producer = new Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/TimeoutZero.lf b/test/C/src/TimeoutZero.lf index 3feee6e010..eed2f94b22 100644 --- a/test/C/src/TimeoutZero.lf +++ b/test/C/src/TimeoutZero.lf @@ -1,18 +1,18 @@ -/* - * A test for the timeout functionality in Lingua Franca. - * This variant tests timeout at (0,0). +/** + * A test for the timeout functionality in Lingua Franca. This variant tests + * timeout at (0,0). * * @author Soroush Bateni */ -target C { - timeout: 0 sec -}; +target C { timeout: 0 sec } import Sender from "lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state success:bool(false); + input in: int + + state success: bool(false) + reaction(in) {= tag_t current_tag = lf_tag(); if (lf_tag_compare(current_tag, @@ -41,8 +41,8 @@ reactor Consumer { } main reactor { - consumer = new Consumer(); - producer = new Sender(break_interval = 1 msec); + consumer = new Consumer() + producer = new Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/C/src/ToReactionNested.lf b/test/C/src/ToReactionNested.lf index 847c983e2f..15002ca417 100644 --- a/test/C/src/ToReactionNested.lf +++ b/test/C/src/ToReactionNested.lf @@ -1,20 +1,20 @@ -target C { - timeout: 5 sec, - fast: true -}; -import Count from "lib/Count.lf"; +target C { timeout: 5 sec, fast: true } + +import Count from "lib/Count.lf" reactor CountContainer { - output out:int; - c1 = new Count(); - c1.out -> out; + output out: int + + c1 = new Count() + + c1.out -> out } main reactor { - state count:int(1); - state received:bool(false); + s = new CountContainer() - s = new CountContainer(); + state count: int(1) + state received: bool(false) reaction(s.out) {= if (s.out->is_present) { @@ -26,6 +26,7 @@ main reactor { } self->count++; =} + reaction(shutdown) {= if (!self->received) { lf_print_error_and_exit("No inputs present."); diff --git a/test/C/src/TriggerDownstreamOnlyIfPresent2.lf b/test/C/src/TriggerDownstreamOnlyIfPresent2.lf index ca7deb1bae..a824d37b20 100644 --- a/test/C/src/TriggerDownstreamOnlyIfPresent2.lf +++ b/test/C/src/TriggerDownstreamOnlyIfPresent2.lf @@ -1,14 +1,16 @@ /** - * This test checks that a downstream reaction is triggered only if its trigger is present. + * This test checks that a downstream reaction is triggered only if its trigger + * is present. */ -target C { - timeout: 1 sec, - fast: true -}; +target C { timeout: 1 sec, fast: true } + reactor Source { - output[2] out:int; - state count:int(0); - timer t(0, 200 msec); + output[2] out: int + + timer t(0, 200 msec) + + state count: int(0) + reaction(t) -> out {= if (self->count++ % 2 == 0) { lf_set(out[0], self->count); @@ -17,8 +19,10 @@ reactor Source { } =} } + reactor Destination { - input in:int; + input in: int + reaction(in) {= if (!in->is_present) { fprintf(stderr, "Reaction to input of triggered even though all inputs are absent!\n"); @@ -28,7 +32,8 @@ reactor Destination { } main reactor TriggerDownstreamOnlyIfPresent2 { - s = new Source(); - d = new[2] Destination(); - s.out -> d.in; + s = new Source() + d = new[2] Destination() + + s.out -> d.in } diff --git a/test/C/src/UnconnectedInput.lf b/test/C/src/UnconnectedInput.lf index 1335e6c155..3117399a44 100644 --- a/test/C/src/UnconnectedInput.lf +++ b/test/C/src/UnconnectedInput.lf @@ -1,20 +1,22 @@ // Test unconnected input. -target C { - timeout: 5 sec, - fast: true -}; +target C { timeout: 5 sec, fast: true } + reactor Source { - output out:int; - timer t(0, 1 sec); - state s:int(1); - reaction(t) -> out {= - lf_set(out, self->s++); - =} + output out: int + + timer t(0, 1 sec) + + state s: int(1) + + reaction(t) -> out {= lf_set(out, self->s++); =} } + reactor Add { - input in1:int; - input in2:int; - output out:int; + input in1: int + input in2: int + + output out: int + reaction(in1, in2) -> out {= int result = 0; if (in1->is_present) result += in1->value; @@ -22,9 +24,12 @@ reactor Add { lf_set(out, result); =} } + reactor Print { - input in:int; - state expected:int(1); + input in: int + + state expected: int(1) + reaction(in) {= printf("Received: %d.\n", in->value); if (in->value != self->expected) { @@ -34,10 +39,12 @@ reactor Print { self->expected++; =} } + main reactor UnconnectedInput { - source = new Source(); - add = new Add(); - print = new Print(); - source.out -> add.in2; - add.out -> print.in; + source = new Source() + add = new Add() + print = new Print() + + source.out -> add.in2 + add.out -> print.in } diff --git a/test/C/src/Wcet.lf b/test/C/src/Wcet.lf index 3bd6ea6a4e..39d1c0c584 100644 --- a/test/C/src/Wcet.lf +++ b/test/C/src/Wcet.lf @@ -1,18 +1,24 @@ // Setup for WCET analysis of Worker -target C; +target C + reactor Source { - output out1: int; - output out2: int; - timer t; + output out1: int + output out2: int + + timer t + reaction(t) -> out1, out2 {= lf_set(out1, 5); lf_set(out2, 10); =} } + reactor Work { - input in1: int; - input in2: int; - output out:int; + input in1: int + input in2: int + + output out: int + reaction(in1, in2) -> out {= int ret; if (in1->value > 10) { @@ -23,19 +29,19 @@ reactor Work { lf_set(out, ret); =} } + reactor Print { - input in:int; - reaction(in) {= - printf("Received: %d\n", in->value); - =} + input in: int + + reaction(in) {= printf("Received: %d\n", in->value); =} } main reactor Wcet { - source = new Source(); - work = new Work(); - print = new Print(); + source = new Source() + work = new Work() + print = new Print() - source.out1 -> work.in1; - source.out2 -> work.in2; - work.out -> print.in; + source.out1 -> work.in1 + source.out2 -> work.in2 + work.out -> print.in } From e96144e7243cc6ca15c5d0b7293af6c138112889 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 23:20:47 -0700 Subject: [PATCH 083/130] [formatting] Aesthetic adjustment. That this aesthetic improvement should have to be done in this way is concerning. Ideally, it would be performed by changing the badness function, but the badness function itself already could in principle do the job in some cases -- but in the implementation, it doesn't, for an algorithm that with certainty minimizes global badness would be have exponential time complexity. That said, this is a sensible and probably reasonably future-proof heuristic. Programming constructs tend to have bodies at the end (or lists of expressions, or whatever) and metadata at the beginning (types, mutability, etc.), so usually, the expression at the end is the largest, and the consequences of representing it differently are the greatest (in particular, in terms of reducing line length violations). --- org.lflang/src/org/lflang/ast/MalleableString.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index de444d584b..f4228785e6 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -245,11 +245,16 @@ public void findBestRepresentation( ) { this.width = width; keepCommentsOnSameLine = true; - components.forEach(it -> it.findBestRepresentation(providedRender, badness, width)); - if (components.stream().noneMatch(it -> it.render().unplacedComments.findAny().isPresent())) return; + components.reverse() + .forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + if ( + components.stream() + .noneMatch(it -> it.render().unplacedComments.findAny().isPresent()) + ) return; long badnessTrue = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = false; - components.forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + components.reverse() + .forEach(it -> it.findBestRepresentation(providedRender, badness, width)); long badnessFalse = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = badnessTrue < badnessFalse; } From ce6a97d9d51801cc7568f264fbd2ddb21cc75b02 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Wed, 6 Jul 2022 23:32:08 -0700 Subject: [PATCH 084/130] [tests] Fix formatter test. --- .../lflang/tests/compiler/RoundTripTests.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java index 0fcc2500df..3004057194 100644 --- a/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java +++ b/org.lflang.tests/src/org/lflang/tests/compiler/RoundTripTests.java @@ -36,16 +36,15 @@ public class RoundTripTests { @Test public void roundTripTest() throws Exception { - run(Path.of("/home/peter/vscode-lingua-franca/lingua-franca/test/C/src/federated/HelloDistributed.lf")); -// int nonFailures = 0; -// for (Target target : Target.values()) { -// for (TestCategory category : TestCategory.values()) { -// for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { -// run(test.srcFile); -// System.out.printf("%s non-failures%n", ++nonFailures); -// } -// } -// } + int nonFailures = 0; + for (Target target : Target.values()) { + for (TestCategory category : TestCategory.values()) { + for (LFTest test : TestRegistry.getRegisteredTests(target, category, false)) { + run(test.srcFile); + System.out.printf("%s non-failures%n", ++nonFailures); + } + } + } } private void run(Path file) throws Exception { From a6bc6dc20c22eec8dbfb5e6614d732e3f07650d2 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 7 Jul 2022 15:43:44 -0700 Subject: [PATCH 085/130] [formatting] Associate comments to ancestors. Comments already have been associated with ancestors, but this makes it possible for that to happen even if there are intervening non-whitespace AST nodes. The issue is that we have a policy of putting comments sometimes at the end of the first line of the representation of an AST node, and in that case, we do not want the comment to become associated with child nodes that are also on that line. --- org.lflang/src/org/lflang/ASTUtils.java | 24 +++------- org.lflang/src/org/lflang/ast/ToLf.java | 56 ++++++++++++++++++++--- org.lflang/src/org/lflang/ast/ToText.java | 19 +++++++- 3 files changed, 74 insertions(+), 25 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index 7f5bcfd95c..e79555f476 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -1699,13 +1699,9 @@ public static Stream getPrecedingComments( List ret = new ArrayList<>(); for (INode node : compNode.getAsTreeIterable()) { if (!(node instanceof ICompositeNode)) { - if ( - node.getGrammarElement() instanceof TerminalRule r - && r.getName().endsWith("_COMMENT") - && !node.getParent().getText().stripLeading().startsWith("{=") - ) { + if (isComment(node)) { if (filter.test(node)) ret.add(node); - } else if (!node.getText().isBlank() && node.getParent() != compNode) { + } else if (!node.getText().isBlank()) { break; } } @@ -1721,22 +1717,14 @@ public static boolean isComment(INode node) { } /** - * Return true if the given node contains semantically significant text on - * the same line as the given other node. + * Return true if the given node starts on the same line as the given other + * node. */ public static Predicate sameLine(ICompositeNode compNode) { return other -> { for (INode node : compNode.getAsTreeIterable()) { - if ( - !(node instanceof ICompositeNode) - && !( - node instanceof TerminalRule terminalRule - && terminalRule.getName().endsWith("_COMMENT") - ) && !node.getText().isBlank() - && node.getStartLine() <= other.getEndLine() - && node.getEndLine() >= other.getStartLine() - ) { - return true; + if (!(node instanceof ICompositeNode) && !node.getText().isBlank()) { + return !isComment(node) && node.getStartLine() == other.getStartLine(); } } return false; diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index 62e6b99b15..e263d09354 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -2,8 +2,10 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -91,21 +93,40 @@ public MalleableString caseArraySpec(ArraySpec spec) { @Override public MalleableString doSwitch(EObject eObject) { ICompositeNode node = NodeModelUtils.findActualNodeFor(eObject); - Stream followingComments = getFollowingComments(node, ASTUtils.sameLine(node)); + var ancestorComments = getAncestorComments(node); + Predicate doesNotBelongToAncestor = n -> !ancestorComments.contains(n); + Stream followingComments = getFollowingComments( + node, + ASTUtils.sameLine(node).and(doesNotBelongToAncestor) + ); var previous = getNextCompositeSibling(node, INode::getPreviousSibling, true); - Predicate doesNotBelongToPrevious = previous == null ? - n -> true : ASTUtils.sameLine(previous).negate(); + Predicate doesNotBelongToPrevious = doesNotBelongToAncestor.and( + previous == null ? n -> true : ASTUtils.sameLine(previous).negate() + ); Stream precedingComments = ASTUtils.getPrecedingComments( node, - doesNotBelongToPrevious + doesNotBelongToPrevious ).map(String::strip); MalleableString representation = super.doSwitch(eObject); return representation .addComments(precedingComments) - .addComments(followingComments); + .addComments( + getContainedComments(node).stream() + .filter(doesNotBelongToAncestor) + .map(INode::getText) + ).addComments(followingComments); + } + + private static Set getAncestorComments(INode node) { + Set ancestorComments = new HashSet<>(); + var ancestor = node; + while ((ancestor = ancestor.getParent()) != null) { + ancestorComments.addAll(getContainedComments(ancestor)); + } + return ancestorComments; } - private static ICompositeNode getNextCompositeSibling( + static ICompositeNode getNextCompositeSibling( INode node, Function getNextSibling, boolean traverseUpwards @@ -148,6 +169,29 @@ private static Stream getFollowingComments( ); } + /** + * Return comments contained by {@code node} that logically belong to this + * node (and not to any of its children). + */ + private static List getContainedComments(INode node) { + ArrayList ret = new ArrayList<>(); + boolean inSemanticallyInsignificantLeadingRubbish = true; + for (INode child : node.getAsTreeIterable()) { + if (!inSemanticallyInsignificantLeadingRubbish && ASTUtils.isComment(child)) { + ret.add(child); + } else if (!(child instanceof ICompositeNode) && !child.getText().isBlank()) { + inSemanticallyInsignificantLeadingRubbish = false; + } + if (!(child instanceof ICompositeNode) + && (child.getText().contains("\n") || child.getText().contains("\r")) + && !inSemanticallyInsignificantLeadingRubbish + ) { + break; + } + } + return ret; + } + @Override public MalleableString caseCode(Code code) { String content = ToText.instance.doSwitch(code).lines() diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index cf82d733c4..bd76b375bb 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -1,8 +1,14 @@ package org.lflang.ast; +import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Stream; + import org.eclipse.emf.ecore.EObject; import org.eclipse.xtext.nodemodel.ICompositeNode; import org.eclipse.xtext.nodemodel.ILeafNode; +import org.eclipse.xtext.nodemodel.INode; import org.eclipse.xtext.nodemodel.util.NodeModelUtils; import org.lflang.ASTUtils; @@ -48,13 +54,18 @@ public String caseCode(Code code) { // Remove the code delimiters (and any surrounding comments). // This assumes any comment before {= does not include {=. int start = str.indexOf("{="); - int end = str.indexOf("=}", start); + int end = str.lastIndexOf("=}"); if (start == -1 || end == -1) { // Silent failure is needed here because toText is needed to create the intermediate representation, // which the validator uses. return str; } str = str.substring(start + 2, end); + for (String comment : + (Iterable) () -> precedingCommentsThatDoNotBelong(node).iterator() + ) { + str = str.replaceFirst(Pattern.quote(comment), ""); + } if (str.split("\n").length > 1) { // multi line code return StringUtil.trimCodeBlock(str); @@ -69,6 +80,12 @@ public String caseCode(Code code) { return ""; } + public static Stream precedingCommentsThatDoNotBelong(ICompositeNode node) { + var previous = ToLf.getNextCompositeSibling(node, INode::getPreviousSibling, true); + if (previous == null) return Stream.of(); + return ASTUtils.getPrecedingComments(node, ASTUtils.sameLine(previous)).map(String::strip); + } + @Override public String caseHost(Host host) { return ToLf.instance.caseHost(host).toString(); From 88e4bf3a55690f57178d57965d1ae35f2d1dd154 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 7 Jul 2022 21:32:17 -0700 Subject: [PATCH 086/130] [formatting] Format C++ tests. --- test/Cpp/src/ActionDelay.lf | 38 ++--- test/Cpp/src/ActionIsPresent.lf | 13 +- test/Cpp/src/ActionValues.lf | 11 +- test/Cpp/src/ActionWithNoReaction.lf | 38 ++--- test/Cpp/src/After.lf | 42 ++--- test/Cpp/src/AfterOverlapped.lf | 21 +-- test/Cpp/src/AfterZero.lf | 42 ++--- test/Cpp/src/Alignment.lf | 146 +++++++++--------- test/Cpp/src/ArrayAsParameter.lf | 31 ++-- test/Cpp/src/ArrayAsType.lf | 17 +- test/Cpp/src/ArrayParallel.lf | 38 ++--- test/Cpp/src/ArrayPrint.lf | 21 +-- test/Cpp/src/ArrayScale.lf | 28 ++-- test/Cpp/src/CharLiteralInitializer.lf | 6 +- test/Cpp/src/Composition.lf | 37 +++-- test/Cpp/src/CompositionAfter.lf | 39 +++-- test/Cpp/src/CompositionGain.lf | 32 ++-- test/Cpp/src/CountTest.lf | 22 +-- test/Cpp/src/DanglingOutput.lf | 30 ++-- test/Cpp/src/Deadline.lf | 40 +++-- test/Cpp/src/DeadlineHandledAbove.lf | 25 +-- test/Cpp/src/DelayInt.lf | 46 +++--- test/Cpp/src/DelayedAction.lf | 20 +-- test/Cpp/src/DelayedReaction.lf | 19 +-- test/Cpp/src/Determinism.lf | 49 +++--- test/Cpp/src/DoubleInvocation.lf | 64 ++++---- test/Cpp/src/DoublePort.lf | 46 +++--- test/Cpp/src/DoubleReaction.lf | 43 +++--- test/Cpp/src/DoubleTrigger.lf | 15 +- test/Cpp/src/FloatLiteral.lf | 15 +- test/Cpp/src/Gain.lf | 36 +++-- test/Cpp/src/GetMicroStep.lf | 16 +- test/Cpp/src/GetTime.lf | 13 +- test/Cpp/src/Hello.lf | 50 +++--- test/Cpp/src/HelloWorld.lf | 13 +- test/Cpp/src/Hierarchy.lf | 62 ++++---- test/Cpp/src/Hierarchy2.lf | 72 +++++---- test/Cpp/src/Import.lf | 20 +-- test/Cpp/src/ImportComposition.lf | 32 ++-- test/Cpp/src/ImportRenamed.lf | 32 ++-- test/Cpp/src/ManualDelayedReaction.lf | 46 +++--- test/Cpp/src/Microsteps.lf | 23 +-- test/Cpp/src/Minimal.lf | 7 +- test/Cpp/src/MovingAverage.lf | 52 ++++--- test/Cpp/src/MultipleContained.lf | 25 +-- test/Cpp/src/NativeListsAndTimes.lf | 42 ++--- test/Cpp/src/ParameterHierarchy.lf | 31 ++-- test/Cpp/src/ParameterizedState.lf | 12 +- test/Cpp/src/PeriodicDesugared.lf | 20 +-- test/Cpp/src/Pipeline.lf | 41 ++--- test/Cpp/src/PreambleTest.lf | 18 +-- test/Cpp/src/ReadOutputOfContainedReactor.lf | 24 +-- test/Cpp/src/Schedule.lf | 25 +-- test/Cpp/src/ScheduleLogicalAction.lf | 57 +++---- test/Cpp/src/SelfLoop.lf | 40 ++--- test/Cpp/src/SendingInside.lf | 28 ++-- test/Cpp/src/SendingInside2.lf | 17 +- test/Cpp/src/SimpleDeadline.lf | 29 ++-- test/Cpp/src/SimpleImport.lf | 9 +- test/Cpp/src/SlowingClock.lf | 39 +++-- test/Cpp/src/SlowingClockPhysical.lf | 34 ++-- test/Cpp/src/StartupOutFromInside.lf | 21 ++- test/Cpp/src/Stride.lf | 37 +++-- test/Cpp/src/StructAsState.lf | 7 +- test/Cpp/src/StructAsType.lf | 15 +- test/Cpp/src/StructAsTypeDirect.lf | 15 +- test/Cpp/src/StructParallel.lf | 36 +++-- test/Cpp/src/StructPrint.lf | 22 ++- test/Cpp/src/StructScale.lf | 30 ++-- test/Cpp/src/TestForPreviousOutput.lf | 23 ++- test/Cpp/src/TimeLimit.lf | 54 ++++--- test/Cpp/src/TimeState.lf | 12 +- test/Cpp/src/Timeout_Test.lf | 29 ++-- test/Cpp/src/ToReactionNested.lf | 22 +-- .../src/TriggerDownstreamOnlyIfPresent2.lf | 39 +++-- test/Cpp/src/concurrent/AsyncCallback.lf | 15 +- test/Cpp/src/concurrent/AsyncCallback2.lf | 11 +- .../Cpp/src/concurrent/CompositionThreaded.lf | 37 +++-- .../DeadlineHandledAboveThreaded.lf | 24 ++- test/Cpp/src/concurrent/DeadlineThreaded.lf | 40 +++-- test/Cpp/src/concurrent/DelayIntThreaded.lf | 45 +++--- .../Cpp/src/concurrent/DeterminismThreaded.lf | 48 +++--- .../src/concurrent/DoubleReactionThreaded.lf | 43 +++--- test/Cpp/src/concurrent/GainThreaded.lf | 35 +++-- test/Cpp/src/concurrent/HelloThreaded.lf | 50 +++--- test/Cpp/src/concurrent/ImportThreaded.lf | 20 +-- test/Cpp/src/concurrent/MinimalThreaded.lf | 6 +- .../src/concurrent/SendingInsideThreaded.lf | 26 ++-- test/Cpp/src/concurrent/Threaded.lf | 80 +++++----- test/Cpp/src/concurrent/ThreadedThreaded.lf | 57 ++++--- test/Cpp/src/concurrent/TimeLimitThreaded.lf | 54 ++++--- test/Cpp/src/concurrent/Workers.lf | 3 +- test/Cpp/src/lib/Count.lf | 12 +- test/Cpp/src/lib/Imported.lf | 19 +-- test/Cpp/src/lib/ImportedAgain.lf | 10 +- test/Cpp/src/lib/ImportedComposition.lf | 45 +++--- test/Cpp/src/lib/LoopedActionSender.lf | 24 +-- test/Cpp/src/multiport/BankSelfBroadcast.lf | 33 ++-- test/Cpp/src/multiport/BankToBank.lf | 36 +++-- test/Cpp/src/multiport/BankToBankMultiport.lf | 37 +++-- .../src/multiport/BankToBankMultiportAfter.lf | 39 +++-- test/Cpp/src/multiport/BankToMultiport.lf | 28 ++-- test/Cpp/src/multiport/Broadcast.lf | 21 ++- test/Cpp/src/multiport/BroadcastAfter.lf | 24 ++- .../src/multiport/BroadcastMultipleAfter.lf | 30 ++-- test/Cpp/src/multiport/FullyConnected.lf | 18 ++- .../multiport/FullyConnectedAddressable.lf | 23 ++- .../FullyConnectedAddressableAfter.lf | 12 +- test/Cpp/src/multiport/MultiportFromBank.lf | 38 ++--- .../MultiportFromBankHierarchyAfter.lf | 43 +++--- .../src/multiport/MultiportFromHierarchy.lf | 52 ++++--- test/Cpp/src/multiport/MultiportIn.lf | 64 ++++---- test/Cpp/src/multiport/MultiportOut.lf | 47 +++--- test/Cpp/src/multiport/MultiportToBank.lf | 19 +-- .../Cpp/src/multiport/MultiportToBankAfter.lf | 19 +-- .../src/multiport/MultiportToBankHierarchy.lf | 39 +++-- .../Cpp/src/multiport/MultiportToHierarchy.lf | 52 ++++--- .../Cpp/src/multiport/MultiportToMultiport.lf | 23 +-- .../src/multiport/MultiportToMultiport2.lf | 28 ++-- .../multiport/MultiportToMultiport2After.lf | 28 ++-- .../multiport/MultiportToMultiportArray.lf | 33 ++-- test/Cpp/src/multiport/MultiportToPort.lf | 32 ++-- test/Cpp/src/multiport/PipelineAfter.lf | 30 ++-- .../ReadMultiportOutputOfContainedBank.lf | 21 ++- .../multiport/ReadOutputOfContainedBank.lf | 25 +-- test/Cpp/src/multiport/WidthGivenByCode.lf | 17 +- .../multiport/WriteInputOfContainedBank.lf | 17 +- .../WriteMultiportInputOfContainedBank.lf | 17 +- test/Cpp/src/properties/Fast.lf | 12 +- test/Cpp/src/properties/Keepalive.lf | 8 +- test/Cpp/src/properties/Timeout.lf | 8 +- test/Cpp/src/target/AfterVoid.lf | 31 ++-- .../src/target/BraceAndParenInitialization.lf | 18 ++- test/Cpp/src/target/CMakeInclude.lf | 15 +- .../src/target/CliParserGenericArguments.lf | 120 +++++++------- test/Cpp/src/target/GenericDelay.lf | 34 ++-- .../src/target/GenericParameterAndState.lf | 28 ++-- test/Cpp/src/target/Methods.lf | 20 +-- test/Cpp/src/target/PreambleFile.lf | 29 ++-- 139 files changed, 2379 insertions(+), 1954 deletions(-) diff --git a/test/Cpp/src/ActionDelay.lf b/test/Cpp/src/ActionDelay.lf index fb930ad1c3..522c62ee1b 100644 --- a/test/Cpp/src/ActionDelay.lf +++ b/test/Cpp/src/ActionDelay.lf @@ -1,30 +1,32 @@ // Test logical action with delay. -target Cpp; +target Cpp reactor GeneratedDelay { - input y_in:int; - output y_out:int; - state y_state: int{0}; - logical action act(100 msec):void; + input y_in: int + + output y_out: int + + logical action act(100 msec): void + + state y_state: int{0} + reaction(y_in) -> act {= y_state = *y_in.get(); act.schedule(); =} - reaction(act) -> y_out {= - y_out.set(y_state); - =} + reaction(act) -> y_out {= y_out.set(y_state); =} } reactor Source { - output out:int; - reaction(startup) -> out {= - out.set(1); - =} + output out: int + + reaction(startup) -> out {= out.set(1); =} } reactor Sink { - input in:int; + input in: int + reaction(in) {= auto elapsed_logical = get_elapsed_logical_time(); auto logical = get_logical_time(); @@ -42,10 +44,10 @@ reactor Sink { } main reactor ActionDelay { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); + source = new Source() + sink = new Sink() + g = new GeneratedDelay() - source.out -> g.y_in; - g.y_out -> sink.in; + source.out -> g.y_in + g.y_out -> sink.in } diff --git a/test/Cpp/src/ActionIsPresent.lf b/test/Cpp/src/ActionIsPresent.lf index f2b2bfd01e..0c5aec71b6 100644 --- a/test/Cpp/src/ActionIsPresent.lf +++ b/test/Cpp/src/ActionIsPresent.lf @@ -1,10 +1,12 @@ // Tests the is_present variable for actions in cpp -target Cpp; +target Cpp + +main reactor ActionIsPresent(offset: time(1 nsec), period: time(500 msec)) { + logical action a + + state success: bool(false) + state zero: time(0 nsec) -main reactor ActionIsPresent(offset:time(1 nsec), period:time(500 msec)) { - logical action a; - state success:bool(false); - state zero:time(0 nsec); reaction(startup, a) -> a {= if (!a.is_present()) { if (offset == zero) { @@ -18,6 +20,7 @@ main reactor ActionIsPresent(offset:time(1 nsec), period:time(500 msec)) { success = true; } =} + reaction(shutdown) {= if (!success) { std::cerr << "Failed to print 'Hello World!'" << '\n'; diff --git a/test/Cpp/src/ActionValues.lf b/test/Cpp/src/ActionValues.lf index be6de2c7f3..58cf90d7ed 100644 --- a/test/Cpp/src/ActionValues.lf +++ b/test/Cpp/src/ActionValues.lf @@ -1,10 +1,11 @@ // Test logical action with delay. -target Cpp; +target Cpp main reactor ActionValues { - state r1done: bool(false); - state r2done: bool(false); - logical action act(100 msec): int; + logical action act(100 msec): int + + state r1done: bool(false) + state r2done: bool(false) reaction(startup) -> act {= act.schedule(100); // scheduled in 100 ms @@ -38,7 +39,7 @@ main reactor ActionValues { } =} - reaction (shutdown) {= + reaction(shutdown) {= if (!r1done || !r2done) { std::cerr << "ERROR: Expected 2 reaction invocations\n"; exit(1); diff --git a/test/Cpp/src/ActionWithNoReaction.lf b/test/Cpp/src/ActionWithNoReaction.lf index 74c96ad75a..a52c02a84c 100644 --- a/test/Cpp/src/ActionWithNoReaction.lf +++ b/test/Cpp/src/ActionWithNoReaction.lf @@ -1,15 +1,15 @@ -// This checks that action can be created even if there is no reaction. -// This test passes merely by compiling and executing without a segfault. -// Its other functionality is tested by other tests. -target Cpp { - fast: true, - timeout: 3 sec -}; +// This checks that action can be created even if there is no reaction. This +// test passes merely by compiling and executing without a segfault. Its other +// functionality is tested by other tests. +target Cpp { fast: true, timeout: 3 sec } reactor foo { - input x:int; - output y:int; - logical action a; + input x: int + + output y: int + + logical action a + reaction(x) -> y, a {= y.set(2*(*x.get())); a.schedule(500ms); @@ -17,7 +17,8 @@ reactor foo { } reactor print { - input x:int; + input x: int + reaction(x) {= std::cout << "Result is " << *x.get() << '\n'; std::cout << "Current logical time is: " << get_elapsed_logical_time() << '\n'; @@ -26,11 +27,12 @@ reactor print { } main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42); - =} - f.y -> p.x; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x + + reaction(t) -> f.x {= f.x.set(42); =} } diff --git a/test/Cpp/src/After.lf b/test/Cpp/src/After.lf index 0434ce55eb..4ba38ce9b5 100644 --- a/test/Cpp/src/After.lf +++ b/test/Cpp/src/After.lf @@ -1,20 +1,21 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target Cpp { - fast: false, - timeout: 3 sec -}; +// This checks that the after keyword adjusts logical time, not using physical +// time. +target Cpp { fast: false, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(2*(*x.get())); - =} + input x: int + + output y: int + + reaction(x) -> y {= y.set(2*(*x.get())); =} } + reactor print { - state expected_time:time(10 msec); - state i:int(0); - input x:int; + input x: int + + state expected_time: time(10 msec) + state i: int(0) + reaction(x) {= i++; auto elapsed_time = get_elapsed_logical_time(); @@ -31,6 +32,7 @@ reactor print { } expected_time += 1s; =} + reaction(shutdown) {= if (i == 0) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -38,13 +40,17 @@ reactor print { } =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + reaction(t) -> f.x {= f.x.set(42); std::cout << "Timer!\n"; =} - f.y -> p.x after 10 msec; } diff --git a/test/Cpp/src/AfterOverlapped.lf b/test/Cpp/src/AfterOverlapped.lf index bc1933dedc..66ad46a75a 100644 --- a/test/Cpp/src/AfterOverlapped.lf +++ b/test/Cpp/src/AfterOverlapped.lf @@ -1,14 +1,12 @@ // This the after keyword with overlapped time intervals. -target Cpp { - fast: true, - timeout: 5 sec -}; +target Cpp { fast: true, timeout: 5 sec } -import Count from "lib/Count.lf"; +import Count from "lib/Count.lf" reactor Test { - input c:int; - state i:int(0); + input c: int + + state i: int(0) reaction(c) {= std::cout << "Received " << *c.get() << '\n'; @@ -27,6 +25,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (i == 0) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -34,8 +33,10 @@ reactor Test { } =} } + main reactor { - count = new Count(); - test = new Test(); - count.c -> test.c after 2 sec; + count = new Count() + test = new Test() + + count.c -> test.c after 2 sec } diff --git a/test/Cpp/src/AfterZero.lf b/test/Cpp/src/AfterZero.lf index 82450c71e4..31ca06ac16 100644 --- a/test/Cpp/src/AfterZero.lf +++ b/test/Cpp/src/AfterZero.lf @@ -1,20 +1,21 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target Cpp { - fast: false, - timeout: 3 sec -}; +// This checks that the after keyword adjusts logical time, not using physical +// time. +target Cpp { fast: false, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(2*(*x.get())); - =} + input x: int + + output y: int + + reaction(x) -> y {= y.set(2*(*x.get())); =} } + reactor print { - state expected_time:time(0); - state i:int(0); - input x:int; + input x: int + + state expected_time: time(0) + state i: int(0) + reaction(x) {= i++; auto elapsed_time = get_elapsed_logical_time(); @@ -36,6 +37,7 @@ reactor print { } expected_time += 1s; =} + reaction(shutdown) {= if (i == 0) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -43,13 +45,17 @@ reactor print { } =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 0 + reaction(t) -> f.x {= f.x.set(42); std::cout << "Timer!\n"; =} - f.y -> p.x after 0; } diff --git a/test/Cpp/src/Alignment.lf b/test/Cpp/src/Alignment.lf index 2cd58de2c1..7badfed77d 100644 --- a/test/Cpp/src/Alignment.lf +++ b/test/Cpp/src/Alignment.lf @@ -1,15 +1,14 @@ -// This test checks that the downstream reaction is not invoked more -// than once at a logical time. -target Cpp { - logging: LOG, - timeout: 1 sec, - build-type: Debug -} +// This test checks that the downstream reaction is not invoked more than once +// at a logical time. +target Cpp { logging: LOG, timeout: 1 sec, build-type: Debug } reactor Source { - output out:int; - state count:int(1); - timer t(0, 100 msec); + output out: int + + timer t(0, 100 msec) + + state count: int(1) + reaction(t) -> out {= count++; out.set(count); @@ -17,66 +16,73 @@ reactor Source { } reactor Sieve { - private preamble {= - #include "reactor-cpp/logging.hh" - =} - input in:int; - output out:bool; - state primes:std::vector; - reaction(startup) {= - // There are 1229 primes between 1 and 10,000. - // Primes 1 and 2 are not on the list. - primes.push_back(3); - =} - reaction(in) -> out {= - // Reject out of bounds inputs - if(*in.get() <= 0 || *in.get() > 10000) { - reactor::log::Warn() << "Sieve: Input value out of range: " << *in.get(); - } - // Primes 1 and 2 are not on the list. - if (*in.get() == 1 || *in.get() == 2) { - out.set(true); - return; - } - // If the input is greater than the last found prime, then - // we have to expand the list of primes before checking to - // see whether this is prime. - int candidate = primes.back(); - reactor::log::Info() << "Sieve: Checking prime: " << candidate; - while (*in.get() > primes.back()) { - candidate += 2; - bool prime = true; - for (auto i : primes) { - if(candidate % i == 0) { - // Candidate is not prime. Break and add 2 by starting the loop again - prime = false; - break; - } - } - // If the candidate is not divisible by any prime in the list, it is prime - if (prime) { - primes.push_back(candidate); - reactor::log::Info() << "Sieve: Found prime: " << candidate; + private preamble {= + #include "reactor-cpp/logging.hh" + =} + + input in: int + + output out: bool + + state primes: std::vector + + reaction(startup) {= + // There are 1229 primes between 1 and 10,000. + // Primes 1 and 2 are not on the list. + primes.push_back(3); + =} + + reaction(in) -> out {= + // Reject out of bounds inputs + if(*in.get() <= 0 || *in.get() > 10000) { + reactor::log::Warn() << "Sieve: Input value out of range: " << *in.get(); + } + // Primes 1 and 2 are not on the list. + if (*in.get() == 1 || *in.get() == 2) { + out.set(true); + return; + } + // If the input is greater than the last found prime, then + // we have to expand the list of primes before checking to + // see whether this is prime. + int candidate = primes.back(); + reactor::log::Info() << "Sieve: Checking prime: " << candidate; + while (*in.get() > primes.back()) { + candidate += 2; + bool prime = true; + for (auto i : primes) { + if(candidate % i == 0) { + // Candidate is not prime. Break and add 2 by starting the loop again + prime = false; + break; } } + // If the candidate is not divisible by any prime in the list, it is prime + if (prime) { + primes.push_back(candidate); + reactor::log::Info() << "Sieve: Found prime: " << candidate; + } + } - // We are now assured that the input is less than or - // equal to the last prime on the list. - // See whether the input is an already found prime. - // Search the primes from the end, where they are sparser. - for (auto i = primes.rbegin(); i != primes.rend(); ++i) { - if(*i == *in.get()) { - out.set(true); - return; - } + // We are now assured that the input is less than or + // equal to the last prime on the list. + // See whether the input is an already found prime. + // Search the primes from the end, where they are sparser. + for (auto i = primes.rbegin(); i != primes.rend(); ++i) { + if(*i == *in.get()) { + out.set(true); + return; } - =} + } + =} } reactor Destination { - input ok:bool; - input in:int; - state last_invoked:{=reactor::TimePoint=}; + input ok: bool + input in: int + + state last_invoked: {= reactor::TimePoint =} + reaction(ok, in) {= if (ok.is_present() && in.is_present()) { reactor::log::Info() << "Destination: Input " << *in.get() << " is a prime at logical time ( " @@ -90,11 +96,13 @@ reactor Destination { last_invoked = get_logical_time(); =} } + main reactor { - source = new Source(); - sieve = new Sieve(); - destination = new Destination(); - source.out -> sieve.in; - sieve.out -> destination.ok; - source.out -> destination.in; + source = new Source() + sieve = new Sieve() + destination = new Destination() + + source.out -> sieve.in + sieve.out -> destination.ok + source.out -> destination.in } diff --git a/test/Cpp/src/ArrayAsParameter.lf b/test/Cpp/src/ArrayAsParameter.lf index 0bd5e36344..ca435b1379 100644 --- a/test/Cpp/src/ArrayAsParameter.lf +++ b/test/Cpp/src/ArrayAsParameter.lf @@ -1,10 +1,14 @@ -// Source has an variable sized list as a parameter, the elements of which it passes to Print. -target Cpp; +// Source has an variable sized list as a parameter, the elements of which it +// passes to Print. +target Cpp + +reactor Source(sequence: int[]{0, 1, 2}) { + output out: size_t + + logical action next: void + + state count: size_t{0} -reactor Source(sequence:int[]{0, 1, 2}) { - output out: size_t; - state count: size_t{0}; - logical action next:void; reaction(startup, next) -> out, next {= out.set(sequence[count]); count++; @@ -15,8 +19,10 @@ reactor Source(sequence:int[]{0, 1, 2}) { } reactor Print { - input in: size_t; - state count: size_t{1}; + input in: size_t + + state count: size_t{1} + reaction(in) {= std::cout << "Received: " << *in.get() << '\n'; if (*in.get() != count) { @@ -25,6 +31,7 @@ reactor Print { } count++; =} + reaction(shutdown) {= if (count == 1) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -32,8 +39,10 @@ reactor Print { } =} } + main reactor ArrayAsParameter { - s = new Source(sequence{1, 2, 3, 4}); - p = new Print(); - s.out -> p.in; + s = new Source(sequence{1, 2, 3, 4}) + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/ArrayAsType.lf b/test/Cpp/src/ArrayAsType.lf index fd0b36e570..0163d03704 100644 --- a/test/Cpp/src/ArrayAsType.lf +++ b/test/Cpp/src/ArrayAsType.lf @@ -1,9 +1,9 @@ -// Source produces a statically allocated array, which it passes -// to Print. The destination references the array directly. -target Cpp; +// Source produces a statically allocated array, which it passes to Print. The +// destination references the array directly. +target Cpp reactor Source { - output out:int[3]; + output out: int[3] reaction(startup) -> out {= // create a statically allocated array @@ -14,7 +14,7 @@ reactor Source { } reactor Print { - input in:int[3]; + input in: int[3] reaction(in) {= int expected = 3; @@ -45,7 +45,8 @@ reactor Print { } main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/ArrayParallel.lf b/test/Cpp/src/ArrayParallel.lf index ba09d11e58..67d2fbd7bf 100644 --- a/test/Cpp/src/ArrayParallel.lf +++ b/test/Cpp/src/ArrayParallel.lf @@ -1,22 +1,24 @@ -// Source allocates an array dynamically and then sends it to two reactors, -// each of which want to modify it. +/** + * Source allocates an array dynamically and then sends it to two reactors, each + * of which want to modify it. + * + * NOTE: Ideally, only one copy would be made, but this is not supported yet by + * the C++ runtime. + */ +target Cpp -// NOTE: Ideally, only one copy would be made, but this is not -// supported yet by the C++ runtime. - -target Cpp; - -import Scale from "ArrayScale.lf"; -import Source, Print from "ArrayPrint.lf"; +import Scale from "ArrayScale.lf" +import Source, Print from "ArrayPrint.lf" main reactor ArrayParallel { - s = new Source(); - c1 = new Scale(); - c2 = new Scale(scale = 3); - p1 = new Print(scale = 2); - p2 = new Print(scale = 3); - s.out -> c1.in; - s.out -> c2.in; - c1.out -> p1.in; - c2.out -> p2.in; + s = new Source() + c1 = new Scale() + c2 = new Scale(scale = 3) + p1 = new Print(scale = 2) + p2 = new Print(scale = 3) + + s.out -> c1.in + s.out -> c2.in + c1.out -> p1.in + c2.out -> p2.in } diff --git a/test/Cpp/src/ArrayPrint.lf b/test/Cpp/src/ArrayPrint.lf index d9cf43a722..afa617f9e9 100644 --- a/test/Cpp/src/ArrayPrint.lf +++ b/test/Cpp/src/ArrayPrint.lf @@ -1,10 +1,10 @@ -// Source produces a dynamically allocated array, which it passes -// to Print. The ownership semantics of values ensure that the array -// is automatically deleted if it does have no owner. -target Cpp; +// Source produces a dynamically allocated array, which it passes to Print. The +// ownership semantics of values ensure that the array is automatically deleted +// if it does have no owner. +target Cpp reactor Source { - output out:int[3]; + output out: int[3] reaction(startup) -> out {= // create a dynamically allocated mutable array @@ -18,8 +18,8 @@ reactor Source { =} } -reactor Print(scale:int(1)) { - input in:int[3]; +reactor Print(scale: int(1)) { + input in: int[3] reaction(in) {= int expected = 0; @@ -50,7 +50,8 @@ reactor Print(scale:int(1)) { } main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/ArrayScale.lf b/test/Cpp/src/ArrayScale.lf index c335ac3a13..b1bb2bf587 100644 --- a/test/Cpp/src/ArrayScale.lf +++ b/test/Cpp/src/ArrayScale.lf @@ -1,15 +1,14 @@ -// Source produces a dynamically allocated array, which it passes -// to Scale. Scale requests a writable copy. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target Cpp; +// Source produces a dynamically allocated array, which it passes to Scale. +// Scale requests a writable copy. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target Cpp -import Source, Print from "ArrayPrint.lf"; +import Source, Print from "ArrayPrint.lf" -reactor Scale(scale:int(2)) { - input in:int[3]; +reactor Scale(scale: int(2)) { + input in: int[3] - output out:int[3]; + output out: int[3] reaction(in) -> out {= // create a mutable copy of the received input @@ -24,9 +23,10 @@ reactor Scale(scale:int(2)) { } main reactor ArrayScale { - s = new Source(); - c = new Scale(scale(2)); - p = new Print(scale(2)); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Scale(scale(2)) + p = new Print(scale(2)) + + s.out -> c.in + c.out -> p.in } diff --git a/test/Cpp/src/CharLiteralInitializer.lf b/test/Cpp/src/CharLiteralInitializer.lf index 3e0583ae53..2d0edb71b8 100644 --- a/test/Cpp/src/CharLiteralInitializer.lf +++ b/test/Cpp/src/CharLiteralInitializer.lf @@ -1,7 +1,9 @@ // Check that a state variable can have a char literal initializer -target Cpp; +target Cpp + main reactor CharLiteralInitializer { - state c: char('x'); + state c: char('x') + reaction(startup) {= if (c != 'x') { std::cout << "FAILED: Expected 'x', got " << c << '\n'; diff --git a/test/Cpp/src/Composition.lf b/test/Cpp/src/Composition.lf index f7e7f4ada6..23f3d8228c 100644 --- a/test/Cpp/src/Composition.lf +++ b/test/Cpp/src/Composition.lf @@ -1,21 +1,25 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Cpp { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target Cpp { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= count++; y.set(count); =} } + reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= count++; auto value = *x.get(); @@ -25,6 +29,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (count != 5) { std::cerr << "ERROR: expected to receive 5 values but got " << count << '\n'; @@ -32,8 +37,10 @@ reactor Test { } =} } + main reactor Composition { - s = new Source(); - d = new Test(); - s.y -> d.x; + s = new Source() + d = new Test() + + s.y -> d.x } diff --git a/test/Cpp/src/CompositionAfter.lf b/test/Cpp/src/CompositionAfter.lf index 30b1dc1808..b3c35304cd 100644 --- a/test/Cpp/src/CompositionAfter.lf +++ b/test/Cpp/src/CompositionAfter.lf @@ -1,21 +1,25 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Cpp { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target Cpp { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= count++; y.set(count); =} } + reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= count++; auto value = *x.get(); @@ -25,6 +29,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (count != 3) { std::cerr << "ERROR: expected to receive 3 values but got " << count << '\n'; @@ -32,8 +37,10 @@ reactor Test { } =} } -main reactor (delay:time(5 sec)) { - s = new Source(); - d = new Test(); - s.y -> d.x after delay; + +main reactor(delay: time(5 sec)) { + s = new Source() + d = new Test() + + s.y -> d.x after delay } diff --git a/test/Cpp/src/CompositionGain.lf b/test/Cpp/src/CompositionGain.lf index 8a8a19d132..0139e90b52 100644 --- a/test/Cpp/src/CompositionGain.lf +++ b/test/Cpp/src/CompositionGain.lf @@ -1,25 +1,33 @@ // This tests send data through a contained reactor -target Cpp; +target Cpp + reactor Gain { - input gainin:int; - output y:int; + input gainin: int + + output y: int + reaction(gainin) -> y {= reactor::log::Info() << "Gain received " << *gainin.get(); y.set(*gainin.get()*2); =} } + reactor Wrapper { - input x:int; - output y:int; - gain = new Gain(); - x -> gain.gainin; - gain.y -> y; + input x: int + + output y: int + + gain = new Gain() + + x -> gain.gainin + gain.y -> y } + main reactor CompositionGain { - wrapper = new Wrapper(); - reaction(startup) -> wrapper.x {= - wrapper.x.set(42); - =} + wrapper = new Wrapper() + + reaction(startup) -> wrapper.x {= wrapper.x.set(42); =} + reaction(wrapper.y) {= reactor::log::Info() << "Received " << *wrapper.y.get(); if (*wrapper.y.get() != 42*2) { diff --git a/test/Cpp/src/CountTest.lf b/test/Cpp/src/CountTest.lf index bd761bf5a7..f16e2311fe 100644 --- a/test/Cpp/src/CountTest.lf +++ b/test/Cpp/src/CountTest.lf @@ -1,12 +1,12 @@ -target Cpp { - timeout: 3 sec, - fast: true -}; -import Count from "lib/Count.lf"; +target Cpp { timeout: 3 sec, fast: true } + +import Count from "lib/Count.lf" reactor Test { - input c:int; - state i:int(0); + input c: int + + state i: int(0) + reaction(c) {= i++; if (*c.get() != i) { @@ -15,8 +15,10 @@ reactor Test { } =} } + main reactor CountTest { - count = new Count(); - test = new Test(); - count.c -> test.c; + count = new Count() + test = new Test() + + count.c -> test.c } diff --git a/test/Cpp/src/DanglingOutput.lf b/test/Cpp/src/DanglingOutput.lf index 4744ee16d0..8ef7279960 100644 --- a/test/Cpp/src/DanglingOutput.lf +++ b/test/Cpp/src/DanglingOutput.lf @@ -1,23 +1,29 @@ // This tests that an output that is not connected to anything does not result -// in a compilation error. Passing the test is just compiling and running. -target Cpp; +// in a compilation error. Passing the test is just compiling and running. +target Cpp + reactor Source { - output out:int; - timer t; - reaction(t) -> out {= - out.set(1); - =} + output out: int + + timer t + + reaction(t) -> out {= out.set(1); =} } + reactor Gain { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= std::cout << "Received " << *in.get() << std::endl; out.set(*in.get() * 2); =} } + main reactor DanglingOutput { - source = new Source(); - container = new Gain(); - source.out -> container.in; + source = new Source() + container = new Gain() + + source.out -> container.in } diff --git a/test/Cpp/src/Deadline.lf b/test/Cpp/src/Deadline.lf index 88479822b9..227d92e039 100644 --- a/test/Cpp/src/Deadline.lf +++ b/test/Cpp/src/Deadline.lf @@ -1,16 +1,19 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target Cpp { - timeout: 4 sec -}; -reactor Source(period:time(2 sec)) { +// This example illustrates local deadline handling. Even numbers are sent by +// the Source immediately, whereas odd numbers are sent after a big enough delay +// to violate the deadline. +target Cpp { timeout: 4 sec } + +reactor Source(period: time(2 sec)) { private preamble {= #include =} - output y:int; - timer t(0, period); - state count:int(0); + + output y: int + + timer t(0, period) + + state count: int(0) + reaction(t) -> y {= if (count % 2 == 1) { // The count variable is odd. @@ -22,9 +25,12 @@ reactor Source(period:time(2 sec)) { count++; =} } -reactor Destination(timeout:time(1 sec)) { - input x:int; - state count:int(0); + +reactor Destination(timeout: time(1 sec)) { + input x: int + + state count: int(0) + reaction(x) {= std::cout << "Destination receives: " << *x.get() << std::endl; if (count % 2 == 1) { @@ -47,8 +53,10 @@ reactor Destination(timeout:time(1 sec)) { count++; =} } + main reactor Deadline { - s = new Source(); - d = new Destination(timeout = 200 msec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 200 msec) + + s.y -> d.x } diff --git a/test/Cpp/src/DeadlineHandledAbove.lf b/test/Cpp/src/DeadlineHandledAbove.lf index 5d9bc3b73c..37d6d92478 100644 --- a/test/Cpp/src/DeadlineHandledAbove.lf +++ b/test/Cpp/src/DeadlineHandledAbove.lf @@ -1,10 +1,12 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target Cpp{ -}; -reactor Deadline(threshold:time(100 msec)) { - input x:int; - output deadline_violation:bool; +// Test a deadline where the deadline violation produces an output and the +// container reacts to that output. +target Cpp + +reactor Deadline(threshold: time(100 msec)) { + input x: int + + output deadline_violation: bool + reaction(x) -> deadline_violation {= std::cerr << "ERROR: Deadline violation was not detected!" << std::endl; exit(1); @@ -13,19 +15,24 @@ reactor Deadline(threshold:time(100 msec)) { deadline_violation.set(true); =} } + main reactor DeadlineHandledAbove { - state violation_detected:bool({=false=}); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected: bool({= false =}) + reaction(startup) -> d.x {= std::this_thread::sleep_for(std::chrono::milliseconds(20)); d.x.set(42); =} + reaction(d.deadline_violation) {= if (*d.deadline_violation.get()) { std::cout << "Output successfully produced by deadline miss handler." << std::endl; violation_detected = true; } =} + reaction(shutdown) {= if (violation_detected) { std::cout << "SUCCESS. Test passes." << std::endl; diff --git a/test/Cpp/src/DelayInt.lf b/test/Cpp/src/DelayInt.lf index b92319c4ef..e150de6846 100644 --- a/test/Cpp/src/DelayInt.lf +++ b/test/Cpp/src/DelayInt.lf @@ -1,27 +1,34 @@ // This tests actions with payloads by delaying an input by a fixed amount. -target Cpp{ -}; -reactor Delay(delay:time(100 msec)) { - input in:int; - output out:int; - logical action d:int; - reaction(in) -> d {= - d.schedule(in.get(), delay); - =} +target Cpp + +reactor Delay(delay: time(100 msec)) { + input in: int + + output out: int + + logical action d: int + + reaction(in) -> d {= d.schedule(in.get(), delay); =} + reaction(d) -> out {= if (d.is_present()) { out.set(d.get()); } =} } + reactor Test { - input in:int; - state start_time:{=reactor::TimePoint=}(); - timer start; + input in: int + + timer start + + state start_time: {= reactor::TimePoint =} + reaction(start) {= // Record the logical time at the start. start_time = get_logical_time(); =} + reaction(in) {= std::cout << "Received: " << *in.get() << std::endl; // Check the time of the input. @@ -42,11 +49,12 @@ reactor Test { } main reactor DelayInt { - timer t; - d = new Delay(); - test = new Test(); - d.out -> test.in; - reaction(t) -> d.in {= - d.in.set(42); - =} + timer t + + d = new Delay() + test = new Test() + + d.out -> test.in + + reaction(t) -> d.in {= d.in.set(42); =} } diff --git a/test/Cpp/src/DelayedAction.lf b/test/Cpp/src/DelayedAction.lf index 02d2f5d40e..1866d478ec 100644 --- a/test/Cpp/src/DelayedAction.lf +++ b/test/Cpp/src/DelayedAction.lf @@ -1,14 +1,14 @@ -target Cpp { - timeout: 5 sec, - fast: true -}; +target Cpp { timeout: 5 sec, fast: true } + main reactor DelayedAction { - timer t(0, 1 sec); - logical action a:void; - state count:int(0); - reaction(t) -> a {= - a.schedule(100ms); - =} + timer t(0, 1 sec) + + logical action a: void + + state count: int(0) + + reaction(t) -> a {= a.schedule(100ms); =} + reaction(a) {= auto elapsed = get_elapsed_logical_time(); std::cout << "Nanoseconds since start: " << elapsed << std::endl; diff --git a/test/Cpp/src/DelayedReaction.lf b/test/Cpp/src/DelayedReaction.lf index 36b9572da5..9a98b98adf 100644 --- a/test/Cpp/src/DelayedReaction.lf +++ b/test/Cpp/src/DelayedReaction.lf @@ -1,15 +1,15 @@ // Test delay made on a connection. -target Cpp; +target Cpp reactor Source { - output out:void; - reaction(startup) -> out {= - out.set(); - =} + output out: void + + reaction(startup) -> out {= out.set(); =} } reactor Sink { - input in:void; + input in: void + reaction(in) {= auto elapsed = get_elapsed_logical_time(); std::cout << "Nanoseconds since start: " << elapsed << '\n'; @@ -21,7 +21,8 @@ reactor Sink { } main reactor DelayedReaction { - source = new Source(); - sink = new Sink(); - source.out -> sink.in after 100 msec; + source = new Source() + sink = new Sink() + + source.out -> sink.in after 100 msec } diff --git a/test/Cpp/src/Determinism.lf b/test/Cpp/src/Determinism.lf index 37045e145f..5d184ac7e0 100644 --- a/test/Cpp/src/Determinism.lf +++ b/test/Cpp/src/Determinism.lf @@ -1,15 +1,17 @@ -target Cpp{ -}; +target Cpp + reactor Source { - output y:int; - timer t; - reaction(t) -> y {= - y.set(1); - =} + output y: int + + timer t + + reaction(t) -> y {= y.set(1); =} } + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= int sum = 0; if (x.is_present()) { @@ -25,20 +27,23 @@ reactor Destination { } =} } + reactor Pass { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(x.get()); - =} + input x: int + + output y: int + + reaction(x) -> y {= y.set(x.get()); =} } + main reactor Determinism { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/Cpp/src/DoubleInvocation.lf b/test/Cpp/src/DoubleInvocation.lf index 73a6ea832b..4692a2f864 100644 --- a/test/Cpp/src/DoubleInvocation.lf +++ b/test/Cpp/src/DoubleInvocation.lf @@ -1,38 +1,39 @@ -// This illustrates a very strange bug that showed up -// and has now been fixed. This test ensures it does -// not reappear. -// At logical time zero, the two Print reactors used to be -// fired twice each at the same logical time. -// They should only be fired once. -// This behavior was oddly eliminated by either of the following -// actions, neither of which should affect this behavior: +// This illustrates a very strange bug that showed up and has now been fixed. +// This test ensures it does not reappear. At logical time zero, the two Print +// reactors used to be fired twice each at the same logical time. They should +// only be fired once. This behavior was oddly eliminated by either of the +// following actions, neither of which should affect this behavior: // * Removing the startup reaction in Print. -// * Sending only position, not velocity from Ball. -// (copied from the c version of the test) +// * Sending only position, not velocity from Ball. (copied from the c version +// of the test) +target Cpp { timeout: 5 sec, fast: true } -target Cpp{ - timeout: 5 sec, - fast: true -} reactor Ball { - output position:int; - output velocity:int; - state p:int(200); - timer trigger(0, 1 sec); + output position: int + output velocity: int + + timer trigger(0, 1 sec) + + state p: int(200) + reaction(trigger) -> position, velocity {= position.set(p); velocity.set(-1); p -= 1; =} } + reactor Print { - input velocity:int; - input position:int; - state previous:int(-1); - reaction (startup) {= + input velocity: int + input position: int + + state previous: int(-1) + + reaction(startup) {= reactor::log::Info() << "####### Print startup"; =} - reaction (position, velocity) {= + + reaction(position, velocity) {= if (position.is_present()) { reactor::log::Info() << "Position: " << *position.get(); } @@ -41,14 +42,15 @@ reactor Print { exit(1); } =} - } + main reactor DoubleInvocation { - b1 = new Ball(); - p = new Print(); - plot = new Print(); - b1.position -> p.position; - b1.velocity -> p.velocity; - b1.position -> plot.position; - b1.velocity -> plot.velocity; + b1 = new Ball() + p = new Print() + plot = new Print() + + b1.position -> p.position + b1.velocity -> p.velocity + b1.position -> plot.position + b1.velocity -> plot.velocity } diff --git a/test/Cpp/src/DoublePort.lf b/test/Cpp/src/DoublePort.lf index c14133ec1f..716cb600d8 100644 --- a/test/Cpp/src/DoublePort.lf +++ b/test/Cpp/src/DoublePort.lf @@ -1,36 +1,35 @@ /** - * Test the case where two upstream reactors - * pass messages to a downstream reactor on two - * different ports. One message carries - * a microstep delay relative to the other. + * Test the case where two upstream reactors pass messages to a downstream + * reactor on two different ports. One message carries a microstep delay + * relative to the other. * * @author Maiko Brants */ -target Cpp { - timeout: 900 msec, - fast: true -}; +target Cpp { timeout: 900 msec, fast: true } -import Count from "lib/Count.lf"; +import Count from "lib/Count.lf" reactor CountMicrostep { - state count:int(1); - output out:int; - logical action act:int; - timer t(0, 1 sec); + output out: int + + timer t(0, 1 sec) + + logical action act: int + + state count: int(1) + reaction(t) -> act {= act.schedule( count); count++; =} - reaction(act) -> out {= - out.set(act.get()); - =} + reaction(act) -> out {= out.set(act.get()); =} } reactor Print { - input in:int; - input in2:int; + input in: int + input in2: int + reaction(in, in2) {= if(in.is_present()){ reactor::log::Info() << "At tag (" << get_elapsed_logical_time() << ", " << environment()->logical_time().micro_step() @@ -53,9 +52,10 @@ reactor Print { } main reactor DoublePort { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.c -> p.in; - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.c -> p.in + cm.out -> p.in2 } diff --git a/test/Cpp/src/DoubleReaction.lf b/test/Cpp/src/DoubleReaction.lf index 887fc35de6..f84c6cf30a 100644 --- a/test/Cpp/src/DoubleReaction.lf +++ b/test/Cpp/src/DoubleReaction.lf @@ -1,23 +1,26 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target Cpp { - timeout: 10 sec, - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that two simultaneous inputs that trigger a reaction trigger it only +// once. Correct output for this 2, 4, 6, 8, etc. +target Cpp { timeout: 10 sec, fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= count++; y.set(count); =} } + reactor Destination { - input x:int; - input w:int; - state s:int(2); + input x: int + input w: int + + state s: int(2) + reaction(x, w) {= int sum = 0; if (x.is_present()) { @@ -35,10 +38,12 @@ reactor Destination { s += 2; =} } + main reactor DoubleReaction { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/Cpp/src/DoubleTrigger.lf b/test/Cpp/src/DoubleTrigger.lf index e1493c81b3..37b85c8e84 100644 --- a/test/Cpp/src/DoubleTrigger.lf +++ b/test/Cpp/src/DoubleTrigger.lf @@ -1,11 +1,13 @@ -// Test that two simultaneous triggers don't cause -// a reaction to execute twice at the same tag. -target Cpp; +// Test that two simultaneous triggers don't cause a reaction to execute twice +// at the same tag. +target Cpp main reactor DoubleTrigger { - timer t1; - timer t2; - state s:int(0); + timer t1 + timer t2 + + state s: int(0) + reaction(t1, t2) {= s++; if (s > 1) { @@ -13,6 +15,7 @@ main reactor DoubleTrigger { exit(1); } =} + reaction(shutdown) {= if (s == 1) { std::cout << "SUCCESS" << std::endl; diff --git a/test/Cpp/src/FloatLiteral.lf b/test/Cpp/src/FloatLiteral.lf index eb0efdecbe..a65af798b4 100644 --- a/test/Cpp/src/FloatLiteral.lf +++ b/test/Cpp/src/FloatLiteral.lf @@ -1,11 +1,12 @@ -target Cpp; -// This test verifies that floating-point literals are handled -// correctly. +target Cpp + +// This test verifies that floating-point literals are handled correctly. main reactor { - state N:double(6.0221409e+23) - state charge:double(-1.6021766E-19) - state minus_epsilon:double(-.01e0) - state expected:double(.964853323188E5) + state N: double(6.0221409e+23) + state charge: double(-1.6021766E-19) + state minus_epsilon: double(-.01e0) + state expected: double(.964853323188E5) + reaction(startup) {= auto F = - N * charge; if (std::abs(F - expected) < std::abs(minus_epsilon)) { diff --git a/test/Cpp/src/Gain.lf b/test/Cpp/src/Gain.lf index 69492856f0..5f8fb277e4 100644 --- a/test/Cpp/src/Gain.lf +++ b/test/Cpp/src/Gain.lf @@ -1,15 +1,17 @@ // Example in the Wiki. -target Cpp{ -}; -reactor Scale(scale:int(2)) { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(*x.get() * scale); - =} +target Cpp + +reactor Scale(scale: int(2)) { + input x: int + + output y: int + + reaction(x) -> y {= y.set(*x.get() * scale); =} } + reactor Test { - input x:int; + input x: int + reaction(x) {= auto value = *x.get(); std::cout << "Received " << value << std::endl; @@ -19,12 +21,14 @@ reactor Test { } =} } + main reactor Gain { - g = new Scale(); - t = new Test(); - g.y -> t.x; - timer tim; - reaction(tim) -> g.x {= - g.x.set(1); - =} + timer tim + + g = new Scale() + t = new Test() + + g.y -> t.x + + reaction(tim) -> g.x {= g.x.set(1); =} } diff --git a/test/Cpp/src/GetMicroStep.lf b/test/Cpp/src/GetMicroStep.lf index 98ae854abd..965ecedb14 100644 --- a/test/Cpp/src/GetMicroStep.lf +++ b/test/Cpp/src/GetMicroStep.lf @@ -1,12 +1,12 @@ // Tests the get_microstep() function in the C target. -target Cpp; +target Cpp + main reactor GetMicroStep { - state s: {=reactor::mstep_t=} (1); + logical action l - logical action l; - reaction(startup) -> l {= - l.schedule(reactor::Duration::zero()); - =} + state s: {= reactor::mstep_t =}(1) + + reaction(startup) -> l {= l.schedule(reactor::Duration::zero()); =} reaction(l) -> l {= auto microstep = get_microstep(); @@ -19,11 +19,11 @@ main reactor GetMicroStep { } =} - reaction(shutdown) {= + reaction(shutdown) {= if (s != 11) { std::cerr << "Error: unexpected state!\n"; exit(2); } std::cout << "Success!\n"; - =} + =} } diff --git a/test/Cpp/src/GetTime.lf b/test/Cpp/src/GetTime.lf index 509826b1f7..685cb9cd1c 100644 --- a/test/Cpp/src/GetTime.lf +++ b/test/Cpp/src/GetTime.lf @@ -1,11 +1,10 @@ -// This file includes code documented on the Wiki. -// For this test, success is just compiling and running. -target Cpp { - timeout: 2 sec, - fast: true -}; +// This file includes code documented on the Wiki. For this test, success is +// just compiling and running. +target Cpp { timeout: 2 sec, fast: true } + main reactor GetTime { - timer t(0, 1 sec); + timer t(0, 1 sec) + reaction(t) {= auto logical = get_logical_time(); std::cout << "Logical time is " << logical << std::endl; diff --git a/test/Cpp/src/Hello.lf b/test/Cpp/src/Hello.lf index ab3fb05bb0..7793e3522f 100644 --- a/test/Cpp/src/Hello.lf +++ b/test/Cpp/src/Hello.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target Cpp { - timeout: 10 sec, - fast: true -}; -reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { - state count:int(0); - state previous_time:{=reactor::TimePoint=}(); - timer t(1 secs, period); - logical action a:void; +// This test checks that logical time is incremented an appropriate amount as a +// result of an invocation of the schedule() function at runtime. It also +// performs various smoke tests of timing aligned reactions. The first instance +// has a period of 4 seconds, the second of 2 seconds, and the third (composite) +// or 1 second. +target Cpp { timeout: 10 sec, fast: true } + +reactor HelloCpp(period: time(2 sec), message: {= std::string =}("Hello C++")) { + timer t(1 sec, period) + + logical action a: void + + state count: int(0) + state previous_time: {= reactor::TimePoint =} + reaction(t) -> a {= std::cout << message << std::endl; a.schedule(200ms); // No payload. @@ -19,6 +20,7 @@ reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { previous_time = get_logical_time(); std::cout << "Current time is " << previous_time << std::endl; =} + reaction(a) {= count++; auto time = get_logical_time(); @@ -32,13 +34,19 @@ reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { } =} } -reactor Inside(period:time(1 sec), - message:{=std::string=}("Composite default message.")) { - third_instance = new HelloCpp(period = period, message = message); + +reactor Inside( + period: time(1 sec), + message: {= std::string =}("Composite default message.") +) { + third_instance = new HelloCpp(period = period, message = message) } + main reactor Hello { - first_instance = new HelloCpp(period = 4 sec, - message = "Hello from first_instance."); - second_instance = new HelloCpp(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new HelloCpp( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new HelloCpp(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/Cpp/src/HelloWorld.lf b/test/Cpp/src/HelloWorld.lf index 83490b55c0..8d32d55553 100644 --- a/test/Cpp/src/HelloWorld.lf +++ b/test/Cpp/src/HelloWorld.lf @@ -1,10 +1,11 @@ -target Cpp; +target Cpp + reactor HelloWorld2 { - timer t; - reaction(t) {= - std::cout << "Hello World." << std::endl; - =} + timer t + + reaction(t) {= std::cout << "Hello World." << std::endl; =} } + main reactor { - a = new HelloWorld2(); + a = new HelloWorld2() } diff --git a/test/Cpp/src/Hierarchy.lf b/test/Cpp/src/Hierarchy.lf index 6609fe02be..267a3a47a1 100644 --- a/test/Cpp/src/Hierarchy.lf +++ b/test/Cpp/src/Hierarchy.lf @@ -1,21 +1,25 @@ // Test data transport across hierarchy. -target Cpp; +target Cpp + reactor Source { - output out:int; - timer t; - reaction(t) -> out {= - out.set(1); - =} + output out: int + + timer t + + reaction(t) -> out {= out.set(1); =} } + reactor Gain { - input in:int; - output out:int; - reaction(in) -> out {= - out.set((*in.get()) * 2); - =} + input in: int + + output out: int + + reaction(in) -> out {= out.set((*in.get()) * 2); =} } + reactor Print { - input in:int; + input in: int + reaction(in) {= auto value = *in.get(); std::cout << "Received: " << value << std::endl; @@ -25,21 +29,27 @@ reactor Print { } =} } + reactor GainContainer { - input in:int; - output out:int; - output out2:int; - gain = new Gain(); - in -> gain.in; - gain.out -> out; - gain.out -> out2; + input in: int + + output out: int + output out2: int + + gain = new Gain() + + in -> gain.in + gain.out -> out + gain.out -> out2 } + main reactor Hierarchy { - source = new Source(); - container = new GainContainer(); - print = new Print(); - print2 = new Print(); - source.out -> container.in; - container.out -> print.in; - container.out -> print2.in; + source = new Source() + container = new GainContainer() + print = new Print() + print2 = new Print() + + source.out -> container.in + container.out -> print.in + container.out -> print2.in } diff --git a/test/Cpp/src/Hierarchy2.lf b/test/Cpp/src/Hierarchy2.lf index 39cc171923..943b5e1c91 100644 --- a/test/Cpp/src/Hierarchy2.lf +++ b/test/Cpp/src/Hierarchy2.lf @@ -1,28 +1,33 @@ // Test data transport across hierarchy. -target Cpp { - timeout: 5 sec, - fast: true -}; +target Cpp { timeout: 5 sec, fast: true } + reactor Source { - output out:int; - timer t(0, 1 sec); - reaction(t) -> out {= - out.set(1); - =} + output out: int + + timer t(0, 1 sec) + + reaction(t) -> out {= out.set(1); =} } + reactor Count { - output out:int; - timer t(0, 1 sec); - state i:int(0); + output out: int + + timer t(0, 1 sec) + + state i: int(0) + reaction(t) -> out {= i++; out.set(i); =} } + reactor Add { - input in1:int; - input in2:int; - output out:int; + input in1: int + input in2: int + + output out: int + reaction(in1, in2) -> out {= int result = 0; if (in1.is_present()) result += *in1.get(); @@ -30,9 +35,12 @@ reactor Add { out.set(result); =} } + reactor Print { - input in:int; - state expected:int(2); + input in: int + + state expected: int(2) + reaction(in) {= auto value = *in.get(); std::cout << "Received: " << value << std::endl; @@ -43,19 +51,25 @@ reactor Print { expected++; =} } + reactor AddCount { - input in:int; - output out:int; - count = new Count(); - add = new Add(); - in -> add.in1; - count.out -> add.in2; - add.out -> out; + input in: int + + output out: int + + count = new Count() + add = new Add() + + in -> add.in1 + count.out -> add.in2 + add.out -> out } + main reactor Hierarchy2 { - source = new Source(); - addCount = new AddCount(); - print = new Print(); - source.out -> addCount.in; - addCount.out -> print.in; + source = new Source() + addCount = new AddCount() + print = new Print() + + source.out -> addCount.in + addCount.out -> print.in } diff --git a/test/Cpp/src/Import.lf b/test/Cpp/src/Import.lf index a8fdfb1d4a..578e872fcd 100644 --- a/test/Cpp/src/Import.lf +++ b/test/Cpp/src/Import.lf @@ -1,13 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Cpp{ -}; -import Imported from "lib/Imported.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target Cpp + +import Imported from "lib/Imported.lf" main reactor Import { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - a.x.set(42); - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= a.x.set(42); =} } diff --git a/test/Cpp/src/ImportComposition.lf b/test/Cpp/src/ImportComposition.lf index bf5f94da8a..a87711b82d 100644 --- a/test/Cpp/src/ImportComposition.lf +++ b/test/Cpp/src/ImportComposition.lf @@ -1,25 +1,26 @@ /** -* -* @author Maiko Brants TU Dresden -* -* This tests the ability to import a reactor definition -* that itself imports a reactor definition. -* -* modeled after the C version of this test -**/ -target Cpp; -import ImportedComposition from "lib/ImportedComposition.lf"; + * @author Maiko Brants TU Dresden + * + * This tests the ability to import a reactor definition that itself imports a + * reactor definition. + * + * modeled after the C version of this test + */ +target Cpp + +import ImportedComposition from "lib/ImportedComposition.lf" main reactor ImportComposition { public preamble {= #include "reactor-cpp/logging.hh" =} - imp_comp = new ImportedComposition(); - state received:bool(false); - reaction(startup) -> imp_comp.x {= - imp_comp.x.set(42); - =} + imp_comp = new ImportedComposition() + + state received: bool(false) + + reaction(startup) -> imp_comp.x {= imp_comp.x.set(42); =} + reaction(imp_comp.y) {= auto receive_time = get_elapsed_logical_time(); reactor::log::Info() << "Received " << *imp_comp.y.get() << " at time " << receive_time; @@ -33,6 +34,7 @@ main reactor ImportComposition { exit(2); } =} + reaction(shutdown) {= if(!received){ reactor::log::Error() << "ERROR: Nothing received."; diff --git a/test/Cpp/src/ImportRenamed.lf b/test/Cpp/src/ImportRenamed.lf index c400f51406..c3f31396c8 100644 --- a/test/Cpp/src/ImportRenamed.lf +++ b/test/Cpp/src/ImportRenamed.lf @@ -1,23 +1,23 @@ /** -* -* @author Maiko Brants TU Dresden -* -* This tests the ability to import a reactor definition -* that itself imports a reactor definition. -* -* modeled after the C version of this test -**/ -target Cpp; + * @author Maiko Brants TU Dresden + * + * This tests the ability to import a reactor definition that itself imports a + * reactor definition. + * + * modeled after the C version of this test + */ +target Cpp + import Imported as X from "lib/Imported.lf" import Imported as Y from "lib/Imported.lf" import ImportedAgain as Z from "lib/ImportedAgain.lf" + main reactor { - timer t; - a = new X(); - b = new Y(); - c = new Z(); + timer t + + a = new X() + b = new Y() + c = new Z() - reaction(t) -> a.x {= - a.x.set(42); - =} + reaction(t) -> a.x {= a.x.set(42); =} } diff --git a/test/Cpp/src/ManualDelayedReaction.lf b/test/Cpp/src/ManualDelayedReaction.lf index c935889239..35b7c343d7 100644 --- a/test/Cpp/src/ManualDelayedReaction.lf +++ b/test/Cpp/src/ManualDelayedReaction.lf @@ -1,33 +1,32 @@ -target Cpp; +target Cpp // That's the stuff that shall be generated for the after reactor GeneratedDelay { - input y_in:int; - output y_out:int; - state y_state:int(0); + input y_in: int - logical action act(100 msec):int; + output y_out: int - reaction(y_in) -> act {= - act.schedule(y_in.get()); - =} + logical action act(100 msec): int - reaction(act) -> y_out {= - y_out.set(act.get()); - =} + state y_state: int(0) + + reaction(y_in) -> act {= act.schedule(y_in.get()); =} + + reaction(act) -> y_out {= y_out.set(act.get()); =} } reactor Source { - output out:int; - timer t; + output out: int + + timer t + // reaction(t) -> out after 100 msec {= - reaction(t) -> out {= - out.set(1); - =} + reaction(t) -> out {= out.set(1); =} } reactor Sink { - input in:int; + input in: int + reaction(in) {= auto elapsed_logical = get_elapsed_logical_time(); std::cout << "Elapsed logical time: " << elapsed_logical << '\n'; @@ -39,13 +38,10 @@ reactor Sink { } main reactor ManualDelayedReaction { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); - - // source.out -> sink.in; - // rewritten above - source.out -> g.y_in; - g.y_out -> sink.in; + source = new Source() + sink = new Sink() + g = new GeneratedDelay() + source.out -> g.y_in // source.out -> sink.in; rewritten above + g.y_out -> sink.in } diff --git a/test/Cpp/src/Microsteps.lf b/test/Cpp/src/Microsteps.lf index 31cca6fb6e..540b2e0d3c 100644 --- a/test/Cpp/src/Microsteps.lf +++ b/test/Cpp/src/Microsteps.lf @@ -1,7 +1,9 @@ -target Cpp; +target Cpp + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= auto elapsed = get_elapsed_logical_time(); std::cout << "Time since start: " << elapsed << std::endl; @@ -26,15 +28,18 @@ reactor Destination { } =} } + main reactor Microsteps { - timer start; - logical action repeat:void; - d = new Destination(); + timer start + + logical action repeat: void + + d = new Destination() + reaction(start) -> d.x, repeat {= d.x.set(1); repeat.schedule(); =} - reaction(repeat) -> d.y {= - d.y.set(1); - =} + + reaction(repeat) -> d.y {= d.y.set(1); =} } diff --git a/test/Cpp/src/Minimal.lf b/test/Cpp/src/Minimal.lf index 777463a887..77238dbd30 100644 --- a/test/Cpp/src/Minimal.lf +++ b/test/Cpp/src/Minimal.lf @@ -1,9 +1,6 @@ // This is a smoke test of a minimal reactor. -target Cpp { -}; +target Cpp main reactor Minimal { - reaction(startup) {= - std::cout << "Hello World!\n"; - =} + reaction(startup) {= std::cout << "Hello World!\n"; =} } diff --git a/test/Cpp/src/MovingAverage.lf b/test/Cpp/src/MovingAverage.lf index 606fd9e8ba..c8edd2cdd0 100644 --- a/test/Cpp/src/MovingAverage.lf +++ b/test/Cpp/src/MovingAverage.lf @@ -1,25 +1,28 @@ -// Demonstration of a state variable that is a fixed size list. -// The MovingAverage reactor computes the moving average of the last -// four inputs and produces that as output. The source is a counting -// sequence. -target Cpp { - timeout: 1 sec, - fast: true -}; +// Demonstration of a state variable that is a fixed size list. The +// MovingAverage reactor computes the moving average of the last four inputs and +// produces that as output. The source is a counting sequence. +target Cpp { timeout: 1 sec, fast: true } + reactor Source { - output out: double; - state count: int{0}; - timer clock(0, 200 msec); + output out: double + + timer clock(0, 200 msec) + + state count: int{0} + reaction(clock) -> out {= out.set(count); count++; =} } + reactor MovingAverageImpl { - state delay_line: double[3] {0.0, 0.0, 0.0}; - state index: int{0}; - input in:double; - output out:double; + input in: double + + output out: double + + state delay_line: double[3]{0.0, 0.0, 0.0} + state index: int{0} reaction(in) -> out {= // Calculate the output. @@ -41,8 +44,10 @@ reactor MovingAverageImpl { } reactor Print { - input in:double; - state count: int{0}; + input in: double + + state count: int{0} + reaction(in) {= std::cout << "Received: " << *in.get() << '\n'; constexpr double expected[6] = {0.0, 0.25, 0.75, 1.5, 2.5, 3.5}; @@ -52,6 +57,7 @@ reactor Print { } count++; =} + reaction(shutdown) {= if(count != 6) { std::cerr << "ERROR: Expected 6 values but got " << count << '\n'; @@ -59,10 +65,12 @@ reactor Print { } =} } + main reactor MovingAverage { - s = new Source(); - m = new MovingAverageImpl(); - p = new Print(); - s.out -> m.in; - m.out -> p.in; + s = new Source() + m = new MovingAverageImpl() + p = new Print() + + s.out -> m.in + m.out -> p.in } diff --git a/test/Cpp/src/MultipleContained.lf b/test/Cpp/src/MultipleContained.lf index 1c5c05d7c4..c62ee71239 100644 --- a/test/Cpp/src/MultipleContained.lf +++ b/test/Cpp/src/MultipleContained.lf @@ -1,13 +1,15 @@ -// Test that a reaction can react to and send two multiple -// ports of a contained reactor. -target Cpp; +// Test that a reaction can react to and send two multiple ports of a contained +// reactor. +target Cpp + reactor Contained { - output trigger:int; - input in1:int; - input in2:int; - reaction(startup) -> trigger {= - trigger.set(42); - =} + input in1: int + input in2: int + + output trigger: int + + reaction(startup) -> trigger {= trigger.set(42); =} + reaction(in1) {= std::cout << "in1 received " << *in1.get() << '\n'; if (*in1.get() != 42) { @@ -15,6 +17,7 @@ reactor Contained { exit(1); } =} + reaction(in2) {= std::cout << "in2 received " << *in2.get() << '\n'; if (*in2.get() != 42) { @@ -23,8 +26,10 @@ reactor Contained { } =} } + main reactor MultipleContained { - c = new Contained(); + c = new Contained() + reaction(c.trigger) -> c.in1, c.in2 {= c.in1.set(c.trigger.get()); c.in2.set(c.trigger.get()); diff --git a/test/Cpp/src/NativeListsAndTimes.lf b/test/Cpp/src/NativeListsAndTimes.lf index 132f8a69e8..68127dd3d8 100644 --- a/test/Cpp/src/NativeListsAndTimes.lf +++ b/test/Cpp/src/NativeListsAndTimes.lf @@ -1,30 +1,32 @@ -target Cpp; +target Cpp // This test passes if it is successfully compiled into valid target code. +reactor Foo( + x: int(0), + y: time(0), // Units are missing but not required + z(1 msec), // Type is missing but not required + p: int[]{1, 2, 3, 4}, // List of integers + q: {= std::vector =}{1 msec, 2 msec, 3 msec}, // list of time values + r: time({= 0 =}), // Zero-valued target code also is a valid time + g: time[]{1 msec, 2 msec} // List of time values +) { + timer tick(0) // Units missing but not required + timer tock(1 sec) // Implicit type time + timer toe(z) // Implicit type time + + state s: time(y) // Reference to explicitly typed time parameter + state t: time(z) // Reference to implicitly typed time parameter + state v: bool // Uninitialized boolean state variable + state w: time // Uninitialized time state variable + state baz(p) // Implicit type int[] + state period(z) // Implicit type time + state times: std::vector>{q, g} // a list of lists -reactor Foo(x:int(0), - y:time(0), // Units are missing but not required - z(1 msec), // Type is missing but not required - p:int[]{1, 2, 3, 4}, // List of integers - q:{=std::vector=}{1 msec, 2 msec, 3 msec}, // list of time values - r:time({=0=}), // Zero-valued target code also is a valid time - g:time[]{1 msec, 2 msec} // List of time values - ) { - state s:time(y); // Reference to explicitly typed time parameter - state t:time(z); // Reference to implicitly typed time parameter - state v:bool; // Uninitialized boolean state variable - state w:time; // Uninitialized time state variable - timer tick(0); // Units missing but not required - timer tock(1 sec); // Implicit type time - timer toe(z); // Implicit type time - state baz(p); // Implicit type int[] - state period(z); // Implicit type time - state times: std::vector>{q, g}; // a list of lists reaction(tick) {= // Target code =} } main reactor NativeListsAndTimes { - foo = new Foo(); + foo = new Foo() } diff --git a/test/Cpp/src/ParameterHierarchy.lf b/test/Cpp/src/ParameterHierarchy.lf index b06cdc3305..2d5550b74a 100644 --- a/test/Cpp/src/ParameterHierarchy.lf +++ b/test/Cpp/src/ParameterHierarchy.lf @@ -1,13 +1,13 @@ /** -* -* @author Maiko Brants TU Dresden -* -* Test that parameter values pass down a deep hierarchy. -* -* modeled after the C version of this test -**/ -target Cpp; -reactor Deep(p:int(0)) { + * @author Maiko Brants TU Dresden + * + * Test that parameter values pass down a deep hierarchy. + * + * modeled after the C version of this test + */ +target Cpp + +reactor Deep(p: int(0)) { reaction(startup) {= if(p != 42) { reactor::log::Error() << "Parameter value is: " << p << ". Should have been 42."; @@ -17,12 +17,15 @@ reactor Deep(p:int(0)) { } =} } -reactor Intermediate(p:int(10)) { - a = new Deep(p = p); + +reactor Intermediate(p: int(10)) { + a = new Deep(p = p) } -reactor Another(p:int(20)) { - a = new Intermediate(p = p); + +reactor Another(p: int(20)) { + a = new Intermediate(p = p) } + main reactor ParameterHierarchy { - a = new Intermediate(p = 42); + a = new Intermediate(p = 42) } diff --git a/test/Cpp/src/ParameterizedState.lf b/test/Cpp/src/ParameterizedState.lf index 0b1206e923..be03a52b9a 100644 --- a/test/Cpp/src/ParameterizedState.lf +++ b/test/Cpp/src/ParameterizedState.lf @@ -1,14 +1,16 @@ -target Cpp; +target Cpp -reactor Foo(bar:int(4)) { - state baz(bar); - reaction (startup) {= +reactor Foo(bar: int(4)) { + state baz(bar) + + reaction(startup) {= std::cout << "Baz: " << baz << std::endl; if (baz != 42) { exit(1); } =} } + main reactor ParameterizedState { - a = new Foo(bar = 42); + a = new Foo(bar = 42) } diff --git a/test/Cpp/src/PeriodicDesugared.lf b/test/Cpp/src/PeriodicDesugared.lf index 45578a7938..26f3948cad 100644 --- a/test/Cpp/src/PeriodicDesugared.lf +++ b/test/Cpp/src/PeriodicDesugared.lf @@ -1,23 +1,17 @@ -target Cpp { - fast: true, - timeout: 5 secs -}; +target Cpp { fast: true, timeout: 5 secs } -main reactor ( - offset:time(50 msec), - period:time(500 msec)) { - logical action init(offset):void; - logical action recur(period):void; - state expected(offset); +main reactor(offset: time(50 msec), period: time(500 msec)) { + logical action init(offset): void + logical action recur(period): void + + state expected(offset) reaction(startup) -> init {= std::cout << "Hello from Periodic!\n"; init.schedule(); =} - reaction(init) -> recur {= - recur.schedule(); - =} + reaction(init) -> recur {= recur.schedule(); =} reaction(init, recur) -> recur {= std::cout << "Periodic trigger!\n"; diff --git a/test/Cpp/src/Pipeline.lf b/test/Cpp/src/Pipeline.lf index db9d02627e..118434fcaf 100644 --- a/test/Cpp/src/Pipeline.lf +++ b/test/Cpp/src/Pipeline.lf @@ -1,11 +1,12 @@ -target Cpp { - timeout: 2 sec -}; -import Computation from "concurrent/Threaded.lf"; +target Cpp { timeout: 2 sec } + +import Computation from "concurrent/Threaded.lf" reactor Print { - input in:int; - state count:int(0); + input in: int + + state count: int(0) + reaction(in) {= std::cout << "Received: " << *in.get() << '\n'; if (*in.get() != count) { @@ -14,6 +15,7 @@ reactor Print { } count++; =} + reaction(shutdown) {= if (count == 1) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -23,21 +25,20 @@ reactor Print { } main reactor Pipeline { - timer t(0, 200 msec); - state count:int(0); + timer t(0, 200 msec) - c1 = new Computation(); - c2 = new Computation(); - c3 = new Computation(); - c4 = new Computation(); - p = new Print(); + c1 = new Computation() + c2 = new Computation() + c3 = new Computation() + c4 = new Computation() + p = new Print() - reaction(t) -> c1.in {= - c1.in.set(count++); - =} + c1.out -> c2.in after 200 msec + c2.out -> c3.in after 200 msec + c3.out -> c4.in after 200 msec + c4.out -> p.in + + state count: int(0) - c1.out -> c2.in after 200 msec; - c2.out -> c3.in after 200 msec; - c3.out -> c4.in after 200 msec; - c4.out -> p.in; + reaction(t) -> c1.in {= c1.in.set(count++); =} } diff --git a/test/Cpp/src/PreambleTest.lf b/test/Cpp/src/PreambleTest.lf index 84e3ff97f3..26e91ea6b1 100644 --- a/test/Cpp/src/PreambleTest.lf +++ b/test/Cpp/src/PreambleTest.lf @@ -1,4 +1,4 @@ -target Cpp; +target Cpp main reactor { // This declaration is required on the public reactor interface and @@ -10,20 +10,20 @@ main reactor { std::string bar; }; =} - // this is only used inside reactions and therefore goes to the generated source file - // This function is only used inside a reaction and therefore is part of the private - // interface. Moreover, we need to make sure that the function is only defined once - // within a source file. This goes to Preamble/Preamble.cc + // this is only used inside reactions and therefore goes to the generated + // source file This function is only used inside a reaction and therefore is + // part of the private interface. Moreover, we need to make sure that the + // function is only defined once within a source file. This goes to + // Preamble/Preamble.cc private preamble {= int add_42(int i) { return i + 42; } =} - logical action a:MyStruct; - reaction(startup) -> a {= - a.schedule({add_42(42), "baz"}); - =} + logical action a: MyStruct + + reaction(startup) -> a {= a.schedule({add_42(42), "baz"}); =} reaction(a) {= auto& value = *a.get(); diff --git a/test/Cpp/src/ReadOutputOfContainedReactor.lf b/test/Cpp/src/ReadOutputOfContainedReactor.lf index 68379854a5..fda4ab0e98 100644 --- a/test/Cpp/src/ReadOutputOfContainedReactor.lf +++ b/test/Cpp/src/ReadOutputOfContainedReactor.lf @@ -1,15 +1,18 @@ -// Test reacting to and reading outputs from a contained -// reactor in various permutations. -target Cpp; +// Test reacting to and reading outputs from a contained reactor in various +// permutations. +target Cpp + reactor Contained { - output out:int; - reaction(startup) -> out {= - out.set(42); - =} + output out: int + + reaction(startup) -> out {= out.set(42); =} } + main reactor ReadOutputOfContainedReactor { - c = new Contained(); - state count:int(0); + c = new Contained() + + state count: int(0) + reaction(startup) c.out {= std::cout << "Startup reaction reading output of contained " << "reactor: " << *c.out.get() << std::endl; @@ -19,6 +22,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(c.out) {= std::cout << "Reading output of contained reactor: " << *c.out.get() << std::endl; @@ -28,6 +32,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(startup, c.out) {= std::cout << "Alternate triggering reading output of contained " << "reactor: " << *c.out.get() << std::endl; @@ -37,6 +42,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(shutdown) {= if (count != 3) { std::cerr << "ERROR: One of the reactions failed to trigger." diff --git a/test/Cpp/src/Schedule.lf b/test/Cpp/src/Schedule.lf index 392a3c08fa..549ab637e8 100644 --- a/test/Cpp/src/Schedule.lf +++ b/test/Cpp/src/Schedule.lf @@ -1,11 +1,13 @@ // Example from Schedule section of the C++ Reactor Target wiki page. -target Cpp; +target Cpp + reactor ScheduleTest { - input x:int; - logical action a:void; - reaction(x) -> a {= - a.schedule(200ms); - =} + input x: int + + logical action a: void + + reaction(x) -> a {= a.schedule(200ms); =} + reaction(a) {= auto elapsed_time = get_elapsed_logical_time(); std::cout << "Action triggered at logical time " << elapsed_time.count() @@ -17,10 +19,11 @@ reactor ScheduleTest { } =} } + main reactor Schedule { - a = new ScheduleTest(); - timer t; - reaction(t) -> a.x {= - a.x.set(1); - =} + timer t + + a = new ScheduleTest() + + reaction(t) -> a.x {= a.x.set(1); =} } diff --git a/test/Cpp/src/ScheduleLogicalAction.lf b/test/Cpp/src/ScheduleLogicalAction.lf index 1218c74ad4..1bbbfa31bc 100644 --- a/test/Cpp/src/ScheduleLogicalAction.lf +++ b/test/Cpp/src/ScheduleLogicalAction.lf @@ -1,33 +1,34 @@ /** -* -* @author Maiko Brants TU Dresden -* -* This checks that a logical action is scheduled the specified -* logical time after the current logical time. -* -* Modeled after the C version of this test. -**/ -target Cpp { - fast: true, - timeout: 3 sec -}; + * @author Maiko Brants TU Dresden + * + * This checks that a logical action is scheduled the specified logical time + * after the current logical time. + * + * Modeled after the C version of this test. + */ +target Cpp { fast: true, timeout: 3 sec } + reactor foo { - input x:int; - output y:int; - logical action a:void; + input x: int + + output y: int + + logical action a: void + reaction(x) -> y, a {= y.set( 2*(*x.get())); // The following uses physical time, incorrectly. a.schedule(500ms); =} - reaction(a) -> y {= - y.set(-42); - =} + + reaction(a) -> y {= y.set(-42); =} } reactor print { - state expected_time:time(0); - input x:int; + input x: int + + state expected_time: time(0) + reaction(x) {= auto elapsed_time = get_elapsed_logical_time(); reactor::log::Info() << "Result is " << *x.get(); @@ -40,12 +41,14 @@ reactor print { expected_time += 500ms; =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42); - =} - f.y -> p.x; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x + + reaction(t) -> f.x {= f.x.set(42); =} } diff --git a/test/Cpp/src/SelfLoop.lf b/test/Cpp/src/SelfLoop.lf index e16a92cbab..bd9796dca0 100644 --- a/test/Cpp/src/SelfLoop.lf +++ b/test/Cpp/src/SelfLoop.lf @@ -1,22 +1,24 @@ /** -* -* @author Maiko Brants TU Dresden -* -* Modeled after the C version of this test. -**/ -target Cpp { - timeout: 1 sec, - fast: true -}; + * @author Maiko Brants TU Dresden + * + * Modeled after the C version of this test. + */ +target Cpp { timeout: 1 sec, fast: true } + reactor Self { - input x:int; - output y:int; - logical action a:int; - state expected:int(43); + input x: int + + output y: int + + logical action a: int + + state expected: int(43) + reaction(a) -> y {= reactor::log::Info() << "a = " << *a.get(); y.set(*a.get()+1); =} + reaction(x) -> a {= reactor::log::Info() << "x = " << *x.get(); if(*x.get() != expected){ @@ -26,9 +28,9 @@ reactor Self { expected++; a.schedule(x.get(), 100ms); =} - reaction(startup) -> a {= - a.schedule(42, 0ns); - =} + + reaction(startup) -> a {= a.schedule(42, 0ns); =} + reaction(shutdown) {= if(expected <= 43) { reactor::log::Error() << "Received no data."; @@ -36,7 +38,9 @@ reactor Self { } =} } + main reactor SelfLoop { - u = new Self(); - u.y -> u.x; + u = new Self() + + u.y -> u.x } diff --git a/test/Cpp/src/SendingInside.lf b/test/Cpp/src/SendingInside.lf index 9b1baad990..22209dcc7f 100644 --- a/test/Cpp/src/SendingInside.lf +++ b/test/Cpp/src/SendingInside.lf @@ -1,12 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. -target Cpp { - timeout: 10 sec, - fast: true -}; +// This tests a reactor that contains another reactor and also has its own +// reaction that routes inputs to the contained reactor. +target Cpp { timeout: 10 sec, fast: true } + reactor Printer { - input x:int; - state count:int(1); + input x: int + + state count: int(1) + reaction(x) {= std::cout << "Inside reactor received: " << *x.get() << std::endl; if (*x.get() != count) { @@ -16,12 +16,16 @@ reactor Printer { count++; =} } + main reactor SendingInside { - state count:int(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count: int(0) + reaction(t) -> p.x {= count++; - p.x.set(count); + p.x.set(count); =} } diff --git a/test/Cpp/src/SendingInside2.lf b/test/Cpp/src/SendingInside2.lf index 7dfbbd905a..8865ee70ca 100644 --- a/test/Cpp/src/SendingInside2.lf +++ b/test/Cpp/src/SendingInside2.lf @@ -1,6 +1,8 @@ -target Cpp; +target Cpp + reactor Printer { - input x:int; + input x: int + reaction(x) {= std::cout << "Inside reactor received: " << *x.get() << std::endl; if (*x.get() != 1) { @@ -9,10 +11,11 @@ reactor Printer { } =} } + main reactor SendingInside2 { - timer t; - p = new Printer(); - reaction(t) -> p.x {= - p.x.set(1); - =} + timer t + + p = new Printer() + + reaction(t) -> p.x {= p.x.set(1); =} } diff --git a/test/Cpp/src/SimpleDeadline.lf b/test/Cpp/src/SimpleDeadline.lf index d7933499ba..fa4a0882d7 100644 --- a/test/Cpp/src/SimpleDeadline.lf +++ b/test/Cpp/src/SimpleDeadline.lf @@ -1,13 +1,17 @@ // Test local deadline, where a deadline is associated with a reaction -// definition. This test triggers a reaction exactly once with a -// deadline violation. -target Cpp; -reactor Deadline(threshold:time(100 msec)) { +// definition. This test triggers a reaction exactly once with a deadline +// violation. +target Cpp + +reactor Deadline(threshold: time(100 msec)) { private preamble {= #include =} - input x:int; - output deadlineViolation:bool; + + input x: int + + output deadlineViolation: bool + reaction(x) -> deadlineViolation {= std::cerr << "ERROR: Deadline violation was not detected!" << std::endl; exit(1); @@ -16,8 +20,10 @@ reactor Deadline(threshold:time(100 msec)) { deadlineViolation.set(true); =} } + reactor Print { - input in:bool; + input in: bool + reaction(in) {= if (*in.get()) { std::cout << "Output successfully produced by deadline handler." @@ -25,10 +31,13 @@ reactor Print { } =} } + main reactor SimpleDeadline { - d = new Deadline(threshold = 10 msec); - p = new Print(); - d.deadlineViolation -> p.in; + d = new Deadline(threshold = 10 msec) + p = new Print() + + d.deadlineViolation -> p.in + reaction(startup) -> d.x {= std::this_thread::sleep_for(std::chrono::milliseconds(20)); d.x.set(42); diff --git a/test/Cpp/src/SimpleImport.lf b/test/Cpp/src/SimpleImport.lf index 1951128a96..0054bf1040 100644 --- a/test/Cpp/src/SimpleImport.lf +++ b/test/Cpp/src/SimpleImport.lf @@ -1,7 +1,8 @@ -target Cpp; -import HelloWorld2 from "HelloWorld.lf"; +target Cpp + +import HelloWorld2 from "HelloWorld.lf" main reactor SimpleImport { - a = new HelloWorld2(); - b = new HelloWorld2(); + a = new HelloWorld2() + b = new HelloWorld2() } diff --git a/test/Cpp/src/SlowingClock.lf b/test/Cpp/src/SlowingClock.lf index 3863d348f9..510257df45 100644 --- a/test/Cpp/src/SlowingClock.lf +++ b/test/Cpp/src/SlowingClock.lf @@ -1,25 +1,23 @@ /** -* -* @author Maiko Brants TU Dresden -* -* Events are scheduled with increasing additional delays of 0, 100, 300, 600 -* msec on a logical action with a minimum delay of 100 msec. -* The use of the logical action ensures the elapsed time jumps exactly from -* 0 to 100, 300, 600, and 1000 msec. -* -* Modeled after the C version of this test. -**/ -target Cpp { - timeout: 1 sec, - fast: true, -}; + * @author Maiko Brants TU Dresden + * + * Events are scheduled with increasing additional delays of 0, 100, 300, 600 + * msec on a logical action with a minimum delay of 100 msec. The use of the + * logical action ensures the elapsed time jumps exactly from 0 to 100, 300, + * 600, and 1000 msec. + * + * Modeled after the C version of this test. + */ +target Cpp { timeout: 1 sec, fast: true } + main reactor SlowingClock { - logical action a(100 msec); - state interval:time(100 msec); - state expected_time:time(100 msec); - reaction(startup) -> a {= - a.schedule(0ns); - =} + logical action a(100 msec) + + state interval: time(100 msec) + state expected_time: time(100 msec) + + reaction(startup) -> a {= a.schedule(0ns); =} + reaction(a) -> a {= auto elapsed_logical_time = get_elapsed_logical_time(); reactor::log::Info() << "Logical time since start: " << elapsed_logical_time; @@ -31,6 +29,7 @@ main reactor SlowingClock { expected_time += 100ms + interval; interval += 100ms; =} + reaction(shutdown) {= if(expected_time != 1500ms){ reactor::log::Error() << "Expected the next expected time to be: 1500000000 nsec."; diff --git a/test/Cpp/src/SlowingClockPhysical.lf b/test/Cpp/src/SlowingClockPhysical.lf index 9f55dd5ade..9f7501fc93 100644 --- a/test/Cpp/src/SlowingClockPhysical.lf +++ b/test/Cpp/src/SlowingClockPhysical.lf @@ -1,26 +1,27 @@ /** -* -* @author Maiko Brants TU Dresden -* + * @author Maiko Brants TU Dresden + * * Events are scheduled with increasing additional delays of 0, 100, 300, 600 - * msec on a physical action with a minimum delay of 100 msec. - * The use of the physical action makes the elapsed time jumps from 0 to - * approximately 100 msec, to approximatly 300 msec thereafter, drifting away - * further with each new event. -* -* Modeled after the C version of this test. -**/ -target Cpp { - timeout: 1500 msec -}; + * msec on a physical action with a minimum delay of 100 msec. The use of the + * physical action makes the elapsed time jumps from 0 to approximately 100 + * msec, to approximatly 300 msec thereafter, drifting away further with each + * new event. + * + * Modeled after the C version of this test. + */ +target Cpp { timeout: 1500 msec } + main reactor SlowingClockPhysical { - physical action a; - state interval:time(100 msec); - state expected_time:time(100 msec); + physical action a + + state interval: time(100 msec) + state expected_time: time(100 msec) + reaction(startup) -> a {= expected_time=100ms; a.schedule(100ms); =} + reaction(a) -> a {= auto elapsed_logical_time{get_elapsed_logical_time()}; reactor::log::Info() << "Logical time since start: " << elapsed_logical_time; @@ -33,6 +34,7 @@ main reactor SlowingClockPhysical { a.schedule(interval); reactor::log::Info() << "Scheduling next to occur approximately after: " << interval; =} + reaction(shutdown) {= if(expected_time < 500ms){ reactor::log::Error() << "Expected the next expected time to be at least: 500000000 nsec."; diff --git a/test/Cpp/src/StartupOutFromInside.lf b/test/Cpp/src/StartupOutFromInside.lf index a18db51966..1832d01d92 100644 --- a/test/Cpp/src/StartupOutFromInside.lf +++ b/test/Cpp/src/StartupOutFromInside.lf @@ -1,20 +1,19 @@ /** -* -* @author Maiko Brants TU Dresden -* -* Modeled after the C version of this test. -**/ -target Cpp; + * @author Maiko Brants TU Dresden + * + * Modeled after the C version of this test. + */ +target Cpp reactor Bar { - output out:int; - reaction(startup) -> out {= - out.set(42); - =} + output out: int + + reaction(startup) -> out {= out.set(42); =} } main reactor StartupOutFromInside { - bar = new Bar(); + bar = new Bar() + reaction(startup) bar.out {= reactor::log::Info() << "Output from bar: " << *bar.out.get(); if(*bar.out.get() != 42) { diff --git a/test/Cpp/src/Stride.lf b/test/Cpp/src/Stride.lf index a1c84d2e56..4b774f8edd 100644 --- a/test/Cpp/src/Stride.lf +++ b/test/Cpp/src/Stride.lf @@ -1,26 +1,29 @@ -// This example illustrates state variables and parameters on the wiki. -// For this test, success is just compiling and running. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Count(stride:int(1)) { - state count:int(0); - output y:int; - timer t(0, 100 msec); +// This example illustrates state variables and parameters on the wiki. For this +// test, success is just compiling and running. +target Cpp { timeout: 2 sec, fast: true } + +reactor Count(stride: int(1)) { + output y: int + + timer t(0, 100 msec) + + state count: int(0) + reaction(t) -> y {= y.set(count); count += stride; =} } + reactor Display { - input x:int; - reaction(x) {= - std::cout << "Received " << *x.get() << std::endl; - =} + input x: int + + reaction(x) {= std::cout << "Received " << *x.get() << std::endl; =} } + main reactor Stride { - c = new Count(stride = 2); - d = new Display(); - c.y -> d.x; + c = new Count(stride = 2) + d = new Display() + + c.y -> d.x } diff --git a/test/Cpp/src/StructAsState.lf b/test/Cpp/src/StructAsState.lf index 808a79e38c..fd48d50d25 100644 --- a/test/Cpp/src/StructAsState.lf +++ b/test/Cpp/src/StructAsState.lf @@ -1,12 +1,13 @@ // Check that a state variable can be a statically initialized struct -target Cpp { -}; +target Cpp + public preamble {= #include "include/hello.h" =} main reactor StructAsState { - state s: Hello{"Earth", 42}; + state s: Hello{"Earth", 42} + reaction(startup) {= std::cout << "State s.name=" << s.name << ", s.value=" << s.value << '\n'; if (s.value != 42 && s.name != "Earth") { diff --git a/test/Cpp/src/StructAsType.lf b/test/Cpp/src/StructAsType.lf index f1aef0c7fd..b10796600f 100644 --- a/test/Cpp/src/StructAsType.lf +++ b/test/Cpp/src/StructAsType.lf @@ -1,15 +1,15 @@ // Source produces a statically allocated struct and sends a copy. -target Cpp { -}; +target Cpp -import Print from "StructPrint.lf"; +import Print from "StructPrint.lf" public preamble {= #include "include/hello.h" =} reactor StaticSource { - output out:Hello; + output out: Hello + reaction(startup) -> out {= Hello hello{"Earth", 42}; // this implicitly sends a dynamically allocated copy of the hello object @@ -18,7 +18,8 @@ reactor StaticSource { } main reactor StructAsType { - s = new StaticSource(); - p = new Print(); - s.out -> p.in; + s = new StaticSource() + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/StructAsTypeDirect.lf b/test/Cpp/src/StructAsTypeDirect.lf index 44f811890f..22aaec3c2a 100644 --- a/test/Cpp/src/StructAsTypeDirect.lf +++ b/test/Cpp/src/StructAsTypeDirect.lf @@ -1,15 +1,15 @@ // Source directly sends an implicitly dynamically created object -target Cpp { -}; +target Cpp -import Print from "StructPrint.lf"; +import Print from "StructPrint.lf" public preamble {= #include "include/hello.h" =} reactor DirectSource { - output out:Hello; + output out: Hello + reaction(startup) -> out {= // this implicitly creates a new hello object which is then send out.set({"Earth", 42}); @@ -17,7 +17,8 @@ reactor DirectSource { } main reactor { - s = new DirectSource(); - p = new Print(); - s.out -> p.in; + s = new DirectSource() + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/StructParallel.lf b/test/Cpp/src/StructParallel.lf index 81039ae851..8b333f21b3 100644 --- a/test/Cpp/src/StructParallel.lf +++ b/test/Cpp/src/StructParallel.lf @@ -1,10 +1,13 @@ -// Source allocates an array dynamically and then sends it to two reactors, -// each of which want to modify it. -// NOTE: Ideally, only one copy would be made, but this requires -// is currently not supported by the C++ runtime. -target Cpp { -}; -import Scale from "StructScale.lf"; +/** + * Source allocates an array dynamically and then sends it to two reactors, each + * of which want to modify it. + * + * NOTE: Ideally, only one copy would be made, but this requires is currently + * not supported by the C++ runtime. + */ +target Cpp + +import Scale from "StructScale.lf" import Source, Print from "StructPrint.lf" public preamble {= @@ -12,13 +15,14 @@ public preamble {= =} main reactor { - s = new Source(); - c1 = new Scale(); - c2 = new Scale(scale = 3); - p1 = new Print(expected_value = 84); - p2 = new Print(expected_value = 126); - s.out -> c1.in; - s.out -> c2.in; - c1.out -> p1.in; - c2.out -> p2.in; + s = new Source() + c1 = new Scale() + c2 = new Scale(scale = 3) + p1 = new Print(expected_value = 84) + p2 = new Print(expected_value = 126) + + s.out -> c1.in + s.out -> c2.in + c1.out -> p1.in + c2.out -> p2.in } diff --git a/test/Cpp/src/StructPrint.lf b/test/Cpp/src/StructPrint.lf index 525e475cad..9607caca40 100644 --- a/test/Cpp/src/StructPrint.lf +++ b/test/Cpp/src/StructPrint.lf @@ -1,12 +1,13 @@ // Source directly sends an implicitly dynamically created object -target Cpp { -}; +target Cpp + public preamble {= #include "include/hello.h" =} reactor Source { - output out:Hello; + output out: Hello + reaction(startup) -> out {= // create an dynamically allocated mutable Hello object auto hello = reactor::make_mutable_value(); @@ -17,8 +18,12 @@ reactor Source { =} } -reactor Print(expected_value:int(42), expected_name:{=std::string=}("Earth")) { - input in:Hello; +reactor Print( + expected_value: int(42), + expected_name: {= std::string =}("Earth") +) { + input in: Hello + reaction(in) {= // get a reference to the received struct for convenience auto& s = *in.get(); @@ -31,7 +36,8 @@ reactor Print(expected_value:int(42), expected_name:{=std::string=}("Earth")) { } main reactor { - s = new Source(); - p = new Print(); - s.out -> p.in; + s = new Source() + p = new Print() + + s.out -> p.in } diff --git a/test/Cpp/src/StructScale.lf b/test/Cpp/src/StructScale.lf index 6bb0606db7..4f5a76ef08 100644 --- a/test/Cpp/src/StructScale.lf +++ b/test/Cpp/src/StructScale.lf @@ -1,20 +1,19 @@ -// Source produces a dynamically allocated struct, which it passes -// to Scale. Scale requests a writable copy. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target Cpp { -}; +// Source produces a dynamically allocated struct, which it passes to Scale. +// Scale requests a writable copy. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target Cpp -import Source, Print from "StructPrint.lf"; +import Source, Print from "StructPrint.lf" public preamble {= #include "include/hello.h" =} -reactor Scale(scale:int(2)) { - input in:Hello; +reactor Scale(scale: int(2)) { + input in: Hello + + output out: Hello - output out:Hello; reaction(in) -> out {= auto hello = in.get().get_mutable_copy(); hello->value *= scale; @@ -23,9 +22,10 @@ reactor Scale(scale:int(2)) { } main reactor StructScale { - s = new Source(); - c = new Scale(); - p = new Print(expected_value=84); - s.out -> c.in; - c.out -> p.in; + s = new Source() + c = new Scale() + p = new Print(expected_value = 84) + + s.out -> c.in + c.out -> p.in } diff --git a/test/Cpp/src/TestForPreviousOutput.lf b/test/Cpp/src/TestForPreviousOutput.lf index a98545ea05..5772a0136e 100644 --- a/test/Cpp/src/TestForPreviousOutput.lf +++ b/test/Cpp/src/TestForPreviousOutput.lf @@ -1,8 +1,10 @@ -// This tests the mechanism for testing whether a previous reaction has -// produced a given output. The output should always be 42. -target Cpp; +// This tests the mechanism for testing whether a previous reaction has produced +// a given output. The output should always be 42. +target Cpp + reactor Source { - output out:int; + output out: int + reaction(startup) -> out {= // Set a seed for random number generation based on the current time. std::srand(std::time(nullptr)); @@ -11,6 +13,7 @@ reactor Source { out.set(21); } =} + reaction(startup) -> out {= if (out.is_present()) { int previous_output = *out.get(); @@ -20,8 +23,10 @@ reactor Source { } =} } + reactor Sink { - input in:int; + input in: int + reaction(in) {= std::cout << "Received: " << *in.get() << '\n'; if (*in.get() != 42) { @@ -30,8 +35,10 @@ reactor Sink { } =} } + main reactor TestForPreviousOutput { - s = new Source(); - d = new Sink(); - s.out -> d.in; + s = new Source() + d = new Sink() + + s.out -> d.in } diff --git a/test/Cpp/src/TimeLimit.lf b/test/Cpp/src/TimeLimit.lf index 67db942676..26ff52a91f 100644 --- a/test/Cpp/src/TimeLimit.lf +++ b/test/Cpp/src/TimeLimit.lf @@ -1,24 +1,28 @@ -// Test that the stop function can be used to internally to impose a -// a time limit. -// This is also used to test performance (number of reactions per second). -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt or getting the wrong data. -target Cpp { - fast: true, -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that the stop function can be used to internally to impose a a time +// limit. This is also used to test performance (number of reactions per +// second). Correct output for this 1, 2, 3, 4. Failure for this test is failing +// to halt or getting the wrong data. +target Cpp { fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= count++; //std::cout << "Reacting at time " << get_elapsed_logical_time() << '\n'; y.set(count); =} } + reactor Destination { - input x:int; - state s:int(1); + input x: int + + state s: int(1) + reaction(x) {= //std::cout << "Received " << *x.get() << '\n'; if (*x.get() != s) { @@ -29,15 +33,15 @@ reactor Destination { =} } -main reactor TimeLimit(period:time(100 usec)) { - timer stop(10 secs); - reaction(stop) {= - environment()->sync_shutdown(); - =} - reaction(shutdown) {= - std::cout << "**** shutdown reaction invoked.\n"; - =} - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; +main reactor TimeLimit(period: time(100 usec)) { + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x + + reaction(stop) {= environment()->sync_shutdown(); =} + + reaction(shutdown) {= std::cout << "**** shutdown reaction invoked.\n"; =} } diff --git a/test/Cpp/src/TimeState.lf b/test/Cpp/src/TimeState.lf index 626120a4c7..28228c11ec 100644 --- a/test/Cpp/src/TimeState.lf +++ b/test/Cpp/src/TimeState.lf @@ -1,13 +1,11 @@ -target Cpp; +target Cpp -reactor Foo(bar:time(42 msec)) { - state baz(bar); +reactor Foo(bar: time(42 msec)) { + state baz(bar) - reaction (startup) {= - std::cout << "Baz: " << baz << std::endl; - =} + reaction(startup) {= std::cout << "Baz: " << baz << std::endl; =} } main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/Cpp/src/Timeout_Test.lf b/test/Cpp/src/Timeout_Test.lf index b7c66d7c89..9b7f931aa2 100644 --- a/test/Cpp/src/Timeout_Test.lf +++ b/test/Cpp/src/Timeout_Test.lf @@ -1,19 +1,19 @@ /** -* A test for the timeout functionality in Lingua Franca. -* -* @author Maiko Brants TU Dresden -* -* Modeled after the C version of this test. -**/ -target Cpp{ - timeout: 11 msec -} + * A test for the timeout functionality in Lingua Franca. + * + * @author Maiko Brants TU Dresden + * + * Modeled after the C version of this test. + */ +target Cpp { timeout: 11 msec } import Sender from "lib/LoopedActionSender.lf" reactor Consumer { - input in:int; - state success:bool(false); + input in: int + + state success: bool(false) + reaction(in) {= auto current{get_elapsed_logical_time()}; if(current > 11ms ){ @@ -32,13 +32,12 @@ reactor Consumer { reactor::log::Error() << "Shutdown invoked at: " << get_elapsed_logical_time() << ". Failed to enforce timeout."; exit(1); } - =} } main reactor Timeout_Test { - consumer = new Consumer(); - producer = new Sender(break_interval = 1 msec); + consumer = new Consumer() + producer = new Sender(break_interval = 1 msec) - producer.out -> consumer.in; + producer.out -> consumer.in } diff --git a/test/Cpp/src/ToReactionNested.lf b/test/Cpp/src/ToReactionNested.lf index 19799eddc3..8406e873a8 100644 --- a/test/Cpp/src/ToReactionNested.lf +++ b/test/Cpp/src/ToReactionNested.lf @@ -1,21 +1,20 @@ -target Cpp { - timeout: 5 sec, - fast: true -}; +target Cpp { timeout: 5 sec, fast: true } -import Count from "lib/Count.lf"; +import Count from "lib/Count.lf" reactor CountContainer { - output out:int; - c1 = new Count(); - c1.c -> out; + output out: int + + c1 = new Count() + + c1.c -> out } main reactor { - state count:int(1); - state received:bool(false); + s = new CountContainer() - s = new CountContainer(); + state count: int(1) + state received: bool(false) reaction(s.out) {= if (s.out.is_present()){ @@ -27,6 +26,7 @@ main reactor { } count++; =} + reaction(shutdown) {= if(!received) { reactor::log::Error() << "No inputs present."; diff --git a/test/Cpp/src/TriggerDownstreamOnlyIfPresent2.lf b/test/Cpp/src/TriggerDownstreamOnlyIfPresent2.lf index caa59f2591..6d5db082b2 100644 --- a/test/Cpp/src/TriggerDownstreamOnlyIfPresent2.lf +++ b/test/Cpp/src/TriggerDownstreamOnlyIfPresent2.lf @@ -1,18 +1,20 @@ /** -* This test checks that a downstream reaction is triggered only if its trigger is present. -* -* @author Maiko Brants TU Dresden -* -* Modeled after the C version of this test. -**/ -target Cpp { - timeout: 1 sec, - fast: true -}; + * This test checks that a downstream reaction is triggered only if its trigger + * is present. + * + * @author Maiko Brants TU Dresden + * + * Modeled after the C version of this test. + */ +target Cpp { timeout: 1 sec, fast: true } + reactor Source { - output[2] out:int; - state count:int(0); - timer t(0, 200 msec); + output[2] out: int + + timer t(0, 200 msec) + + state count: int(0) + reaction(t) -> out {= if(count++ % 2 == 0) { out[0].set(count); @@ -21,8 +23,10 @@ reactor Source { } =} } + reactor Destination { - input in:int; + input in: int + reaction(in) {= if(!in.is_present()){ reactor::log::Error() << "Reaction to input of triggered even though all inputs are absent!"; @@ -32,7 +36,8 @@ reactor Destination { } main reactor TriggerDownstreamOnlyIfPresent2 { - s = new Source(); - d = new[2] Destination(); - s.out -> d.in; + s = new Source() + d = new[2] Destination() + + s.out -> d.in } diff --git a/test/Cpp/src/concurrent/AsyncCallback.lf b/test/Cpp/src/concurrent/AsyncCallback.lf index 5123ae4a4c..3b9713aa72 100644 --- a/test/Cpp/src/concurrent/AsyncCallback.lf +++ b/test/Cpp/src/concurrent/AsyncCallback.lf @@ -3,20 +3,21 @@ target Cpp { timeout: 2 sec, keepalive: true, cmake-include: "AsyncCallback.cmake" -}; +} main reactor AsyncCallback { public preamble {= #include =} - timer t(0, 200 msec); - state thread:{=std::thread=}; - state expected_time:time(100 msec); - state toggle:bool(false); + timer t(0, 200 msec) + + physical action a: int - physical action a:int; - state i:int(0); + state thread: {= std::thread =} + state expected_time: time(100 msec) + state toggle: bool(false) + state i: int(0) reaction(t) -> a {= // make sure to join the old thread first diff --git a/test/Cpp/src/concurrent/AsyncCallback2.lf b/test/Cpp/src/concurrent/AsyncCallback2.lf index 643294c3a2..16467da915 100644 --- a/test/Cpp/src/concurrent/AsyncCallback2.lf +++ b/test/Cpp/src/concurrent/AsyncCallback2.lf @@ -3,18 +3,19 @@ target Cpp { timeout: 2 sec, keepalive: true, cmake-include: "AsyncCallback.cmake" -}; +} main reactor AsyncCallback2 { private preamble {= #include =} - timer t(0, 200 msec); - state expected_time:time(0); + timer t(0, 200 msec) + + logical action a: int - logical action a:int; - state i:int(0); + state expected_time: time(0) + state i: int(0) reaction(t) -> a {= // start new thread diff --git a/test/Cpp/src/concurrent/CompositionThreaded.lf b/test/Cpp/src/concurrent/CompositionThreaded.lf index 9fe0e65750..72a142af86 100644 --- a/test/Cpp/src/concurrent/CompositionThreaded.lf +++ b/test/Cpp/src/concurrent/CompositionThreaded.lf @@ -1,21 +1,25 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Cpp { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - output y:int; - timer t(1 sec, period); - state count:int(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target Cpp { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: int + + timer t(1 sec, period) + + state count: int(0) + reaction(t) -> y {= count++; y.set(count); =} } + reactor Test { - input x:int; - state count:int(0); + input x: int + + state count: int(0) + reaction(x) {= count++; auto value = *x.get(); @@ -25,6 +29,7 @@ reactor Test { exit(1); } =} + reaction(shutdown) {= if (count != 5) { std::cerr << "ERROR: expected to receive 5 values but got " << count << '\n'; @@ -32,8 +37,10 @@ reactor Test { } =} } + main reactor { - s = new Source(); - d = new Test(); - s.y -> d.x; + s = new Source() + d = new Test() + + s.y -> d.x } diff --git a/test/Cpp/src/concurrent/DeadlineHandledAboveThreaded.lf b/test/Cpp/src/concurrent/DeadlineHandledAboveThreaded.lf index e0ae0e334b..2124379d5a 100644 --- a/test/Cpp/src/concurrent/DeadlineHandledAboveThreaded.lf +++ b/test/Cpp/src/concurrent/DeadlineHandledAboveThreaded.lf @@ -1,9 +1,12 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target Cpp; -reactor Deadline(threshold:time(100 msec)) { - input x:int; - output deadline_violation:bool; +// Test a deadline where the deadline violation produces an output and the +// container reacts to that output. +target Cpp + +reactor Deadline(threshold: time(100 msec)) { + input x: int + + output deadline_violation: bool + reaction(x) -> deadline_violation {= std::cerr << "ERROR: Deadline violation was not detected!" << std::endl; exit(1); @@ -12,19 +15,24 @@ reactor Deadline(threshold:time(100 msec)) { deadline_violation.set(true); =} } + main reactor { - state violation_detected:bool({=false=}); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected: bool({= false =}) + reaction(startup) -> d.x {= std::this_thread::sleep_for(std::chrono::milliseconds(20)); d.x.set(42); =} + reaction(d.deadline_violation) {= if (*d.deadline_violation.get()) { std::cout << "Output successfully produced by deadline miss handler." << std::endl; violation_detected = true; } =} + reaction(shutdown) {= if (violation_detected) { std::cout << "SUCCESS. Test passes." << std::endl; diff --git a/test/Cpp/src/concurrent/DeadlineThreaded.lf b/test/Cpp/src/concurrent/DeadlineThreaded.lf index fe434a357e..f6b8fff951 100644 --- a/test/Cpp/src/concurrent/DeadlineThreaded.lf +++ b/test/Cpp/src/concurrent/DeadlineThreaded.lf @@ -1,16 +1,19 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target Cpp { - timeout: 4 sec -}; -reactor Source(period:time(2 sec)) { +// This example illustrates local deadline handling. Even numbers are sent by +// the Source immediately, whereas odd numbers are sent after a big enough delay +// to violate the deadline. +target Cpp { timeout: 4 sec } + +reactor Source(period: time(2 sec)) { private preamble {= #include =} - output y:int; - timer t(0, period); - state count:int(0); + + output y: int + + timer t(0, period) + + state count: int(0) + reaction(t) -> y {= if (count % 2 == 1) { // The count variable is odd. @@ -22,9 +25,12 @@ reactor Source(period:time(2 sec)) { count++; =} } -reactor Destination(timeout:time(1 sec)) { - input x:int; - state count:int(0); + +reactor Destination(timeout: time(1 sec)) { + input x: int + + state count: int(0) + reaction(x) {= std::cout << "Destination receives: " << *x.get() << std::endl; if (count % 2 == 1) { @@ -47,8 +53,10 @@ reactor Destination(timeout:time(1 sec)) { count++; =} } + main reactor { - s = new Source(); - d = new Destination(timeout = 200 msec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 200 msec) + + s.y -> d.x } diff --git a/test/Cpp/src/concurrent/DelayIntThreaded.lf b/test/Cpp/src/concurrent/DelayIntThreaded.lf index 8f2e2e3cd4..e67b4f9ebb 100644 --- a/test/Cpp/src/concurrent/DelayIntThreaded.lf +++ b/test/Cpp/src/concurrent/DelayIntThreaded.lf @@ -1,26 +1,34 @@ // This tests actions with payloads by delaying an input by a fixed amount. -target Cpp; -reactor Delay(delay:time(100 msec)) { - input in:int; - output out:int; - logical action d:int; - reaction(in) -> d {= - d.schedule(in.get(), delay); - =} +target Cpp + +reactor Delay(delay: time(100 msec)) { + input in: int + + output out: int + + logical action d: int + + reaction(in) -> d {= d.schedule(in.get(), delay); =} + reaction(d) -> out {= if (d.is_present()) { out.set(d.get()); } =} } + reactor Test { - input in:int; - state start_time:{=reactor::TimePoint=}(); - timer start; + input in: int + + timer start + + state start_time: {= reactor::TimePoint =} + reaction(start) {= // Record the logical time at the start. start_time = get_logical_time(); =} + reaction(in) {= std::cout << "Received: " << *in.get() << std::endl; // Check the time of the input. @@ -41,11 +49,12 @@ reactor Test { } main reactor { - timer t; - d = new Delay(); - test = new Test(); - d.out -> test.in; - reaction(t) -> d.in {= - d.in.set(42); - =} + timer t + + d = new Delay() + test = new Test() + + d.out -> test.in + + reaction(t) -> d.in {= d.in.set(42); =} } diff --git a/test/Cpp/src/concurrent/DeterminismThreaded.lf b/test/Cpp/src/concurrent/DeterminismThreaded.lf index 00f84d6da0..ecda16e4d6 100644 --- a/test/Cpp/src/concurrent/DeterminismThreaded.lf +++ b/test/Cpp/src/concurrent/DeterminismThreaded.lf @@ -1,14 +1,17 @@ -target Cpp; +target Cpp + reactor Source { - output y:int; - timer t; - reaction(t) -> y {= - y.set(1); - =} + output y: int + + timer t + + reaction(t) -> y {= y.set(1); =} } + reactor Destination { - input x:int; - input y:int; + input x: int + input y: int + reaction(x, y) {= int sum = 0; if (x.is_present()) { @@ -24,20 +27,23 @@ reactor Destination { } =} } + reactor Pass { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(x.get()); - =} + input x: int + + output y: int + + reaction(x) -> y {= y.set(x.get()); =} } + main reactor { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/Cpp/src/concurrent/DoubleReactionThreaded.lf b/test/Cpp/src/concurrent/DoubleReactionThreaded.lf index d85b2682dc..56a68f897b 100644 --- a/test/Cpp/src/concurrent/DoubleReactionThreaded.lf +++ b/test/Cpp/src/concurrent/DoubleReactionThreaded.lf @@ -1,23 +1,26 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target Cpp { - timeout: 10 sec, - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that two simultaneous inputs that trigger a reaction trigger it only +// once. Correct output for this 2, 4, 6, 8, etc. +target Cpp { timeout: 10 sec, fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= count++; y.set(count); =} } + reactor Destination { - input x:int; - input w:int; - state s:int(2); + input x: int + input w: int + + state s: int(2) + reaction(x, w) {= int sum = 0; if (x.is_present()) { @@ -35,10 +38,12 @@ reactor Destination { s += 2; =} } + main reactor { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/Cpp/src/concurrent/GainThreaded.lf b/test/Cpp/src/concurrent/GainThreaded.lf index da15af4b7c..ac658f99d9 100644 --- a/test/Cpp/src/concurrent/GainThreaded.lf +++ b/test/Cpp/src/concurrent/GainThreaded.lf @@ -1,14 +1,17 @@ // Example in the Wiki. -target Cpp; -reactor Scale(scale:int(2)) { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(*x.get() * scale); - =} +target Cpp + +reactor Scale(scale: int(2)) { + input x: int + + output y: int + + reaction(x) -> y {= y.set(*x.get() * scale); =} } + reactor Test { - input x:int; + input x: int + reaction(x) {= auto value = *x.get(); std::cout << "Received " << value << std::endl; @@ -18,12 +21,14 @@ reactor Test { } =} } + main reactor { - g = new Scale(); - t = new Test(); - g.y -> t.x; - timer tim; - reaction(tim) -> g.x {= - g.x.set(1); - =} + timer tim + + g = new Scale() + t = new Test() + + g.y -> t.x + + reaction(tim) -> g.x {= g.x.set(1); =} } diff --git a/test/Cpp/src/concurrent/HelloThreaded.lf b/test/Cpp/src/concurrent/HelloThreaded.lf index c6725d59e8..632d93425c 100644 --- a/test/Cpp/src/concurrent/HelloThreaded.lf +++ b/test/Cpp/src/concurrent/HelloThreaded.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target Cpp { - timeout: 10 sec, - fast: true -}; -reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { - state count:int(0); - state previous_time:{=reactor::TimePoint=}(); - timer t(1 secs, period); - logical action a:void; +// This test checks that logical time is incremented an appropriate amount as a +// result of an invocation of the schedule() function at runtime. It also +// performs various smoke tests of timing aligned reactions. The first instance +// has a period of 4 seconds, the second of 2 seconds, and the third (composite) +// or 1 second. +target Cpp { timeout: 10 sec, fast: true } + +reactor HelloCpp(period: time(2 sec), message: {= std::string =}("Hello C++")) { + timer t(1 sec, period) + + logical action a: void + + state count: int(0) + state previous_time: {= reactor::TimePoint =} + reaction(t) -> a {= std::cout << message << std::endl; a.schedule(200ms); // No payload. @@ -19,6 +20,7 @@ reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { previous_time = get_logical_time(); std::cout << "Current time is " << previous_time << std::endl; =} + reaction(a) {= count++; auto time = get_logical_time(); @@ -32,13 +34,19 @@ reactor HelloCpp(period:time(2 secs), message:{=std::string=}("Hello C++")) { } =} } -reactor Inside(period:time(1 sec), - message:{=std::string=}("Composite default message.")) { - third_instance = new HelloCpp(period = period, message = message); + +reactor Inside( + period: time(1 sec), + message: {= std::string =}("Composite default message.") +) { + third_instance = new HelloCpp(period = period, message = message) } + main reactor { - first_instance = new HelloCpp(period = 4 sec, - message = "Hello from first_instance."); - second_instance = new HelloCpp(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new HelloCpp( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new HelloCpp(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/Cpp/src/concurrent/ImportThreaded.lf b/test/Cpp/src/concurrent/ImportThreaded.lf index 0dbd8d40bf..181b3efd1b 100644 --- a/test/Cpp/src/concurrent/ImportThreaded.lf +++ b/test/Cpp/src/concurrent/ImportThreaded.lf @@ -1,11 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Cpp; -import Imported from "../lib/Imported.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target Cpp + +import Imported from "../lib/Imported.lf" + main reactor { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - a.x.set(42); - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= a.x.set(42); =} } diff --git a/test/Cpp/src/concurrent/MinimalThreaded.lf b/test/Cpp/src/concurrent/MinimalThreaded.lf index bd58692e4b..f13148781d 100644 --- a/test/Cpp/src/concurrent/MinimalThreaded.lf +++ b/test/Cpp/src/concurrent/MinimalThreaded.lf @@ -1,8 +1,6 @@ // This is a smoke test of a minimal reactor. -target Cpp; +target Cpp main reactor { - reaction(startup) {= - std::cout << "Hello World!\n"; - =} + reaction(startup) {= std::cout << "Hello World!\n"; =} } diff --git a/test/Cpp/src/concurrent/SendingInsideThreaded.lf b/test/Cpp/src/concurrent/SendingInsideThreaded.lf index 1ba5ce6878..9dea987adb 100644 --- a/test/Cpp/src/concurrent/SendingInsideThreaded.lf +++ b/test/Cpp/src/concurrent/SendingInsideThreaded.lf @@ -1,12 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. -target Cpp { - timeout: 10 sec, - fast: true -}; +// This tests a reactor that contains another reactor and also has its own +// reaction that routes inputs to the contained reactor. +target Cpp { timeout: 10 sec, fast: true } + reactor Printer { - input x:int; - state count:int(1); + input x: int + + state count: int(1) + reaction(x) {= std::cout << "Inside reactor received: " << *x.get() << std::endl; if (*x.get() != count) { @@ -16,10 +16,14 @@ reactor Printer { count++; =} } + main reactor { - state count:int(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count: int(0) + reaction(t) -> p.x {= count++; p.x.set(count); diff --git a/test/Cpp/src/concurrent/Threaded.lf b/test/Cpp/src/concurrent/Threaded.lf index 5a11bfb02a..ca8a723909 100644 --- a/test/Cpp/src/concurrent/Threaded.lf +++ b/test/Cpp/src/concurrent/Threaded.lf @@ -1,42 +1,49 @@ -// Check for speedup of multithreaded execution on multicore machines. -// Each instance of TakeTime takes 200 ms to transport the input to the output. -// Four of them are instantiated. -// Note that without parallel execution, there is no way this can keep up with real time -// since in every 200 msec cycle it has 800 msec of work to do. -// On a quad-core machine, however, it does pretty well, completing 800 msec of work -// in about 225 msec. -// NOTE: This is the non-threaded version, showing that without threads, this takes more -// than 800 msec to complete 200 msec of logical time. -target Cpp { - timeout: 2 sec, -}; +// Check for speedup of multithreaded execution on multicore machines. Each +// instance of TakeTime takes 200 ms to transport the input to the output. Four +// of them are instantiated. Note that without parallel execution, there is no +// way this can keep up with real time since in every 200 msec cycle it has 800 +// msec of work to do. On a quad-core machine, however, it does pretty well, +// completing 800 msec of work in about 225 msec. NOTE: This is the non-threaded +// version, showing that without threads, this takes more than 800 msec to +// complete 200 msec of logical time. +target Cpp { timeout: 2 sec } reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= out.set(s); s++; =} } + reactor Computation { private preamble {= #include =} - input in:int; - output out:int; + + input in: int + + output out: int + reaction(in) -> out {= std::this_thread::sleep_for(200ms); out.set(in.get()); =} } + reactor Destination { - state s:int(0); - input in1:int; - input in2:int; - input in3:int; - input in4:int; + input in1: int + input in2: int + input in3: int + input in4: int + + state s: int(0) + reaction(in1, in2, in3, in4) {= int sum = *in1.get() + *in2.get() + *in3.get() + *in4.get(); std::cout << "Sum of received: " << sum << '\n'; @@ -49,18 +56,19 @@ reactor Destination { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in; - a.out -> t2.in; - a.out -> t3.in; - a.out -> t4.in; - t1.out -> b.in1; - t2.out -> b.in2; - t3.out -> b.in3; - t4.out -> b.in4; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in + a.out -> t2.in + a.out -> t3.in + a.out -> t4.in + t1.out -> b.in1 + t2.out -> b.in2 + t3.out -> b.in3 + t4.out -> b.in4 } diff --git a/test/Cpp/src/concurrent/ThreadedThreaded.lf b/test/Cpp/src/concurrent/ThreadedThreaded.lf index cc5a5ffd99..125ee04338 100644 --- a/test/Cpp/src/concurrent/ThreadedThreaded.lf +++ b/test/Cpp/src/concurrent/ThreadedThreaded.lf @@ -1,39 +1,47 @@ -// Check for speedup of multithreaded execution on multicore machines. -// Each instance of TakeTime takes 200 ms to transport the input to the output. -// Four of them are instantiated. -// Note that without parallel execution, there is no way this can keep up with real time -// since in every 200 msec cycle it has 800 msec of work to do. -// On a quad-core machine, however, it does pretty well, completing 800 msec of work -// in about 225 msec. -// NOTE: This is the non-threaded version, showing that without threads, this takes more -// than 800 msec to complete 200 msec of logical time. -target Cpp { - timeout: 2 sec -}; +// Check for speedup of multithreaded execution on multicore machines. Each +// instance of TakeTime takes 200 ms to transport the input to the output. Four +// of them are instantiated. Note that without parallel execution, there is no +// way this can keep up with real time since in every 200 msec cycle it has 800 +// msec of work to do. On a quad-core machine, however, it does pretty well, +// completing 800 msec of work in about 225 msec. +// +// NOTE: This is the non-threaded version, showing that without threads, this +// takes more than 800 msec to complete 200 msec of logical time. +target Cpp { timeout: 2 sec } reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= out.set(s); s++; =} } + reactor Computation { private preamble {= #include =} - input in:int; - output out:int; + + input in: int + + output out: int + reaction(in) -> out {= std::this_thread::sleep_for(200ms); out.set(in.get()); =} } + reactor Destination { - state s:int(0); - input[4] in:int; + input[4] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in.size(); i++) { @@ -49,9 +57,10 @@ reactor Destination { } main reactor { - a = new Source(); - t = new[4] Computation(); - b = new Destination(); - (a.out)+ -> t.in; - t.out -> b.in; + a = new Source() + t = new[4] Computation() + b = new Destination() + + (a.out)+ -> t.in + t.out -> b.in } diff --git a/test/Cpp/src/concurrent/TimeLimitThreaded.lf b/test/Cpp/src/concurrent/TimeLimitThreaded.lf index 4ad60a9fff..88ae71bbb2 100644 --- a/test/Cpp/src/concurrent/TimeLimitThreaded.lf +++ b/test/Cpp/src/concurrent/TimeLimitThreaded.lf @@ -1,24 +1,28 @@ -// Test that the stop function can be used to internally to impose a -// a time limit. -// This is also used to test performance (number of reactions per second). -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt or getting the wrong data. -target Cpp { - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:int; - timer t(offset, period); - state count:int(0); +// Test that the stop function can be used to internally to impose a a time +// limit. This is also used to test performance (number of reactions per +// second). Correct output for this 1, 2, 3, 4. Failure for this test is failing +// to halt or getting the wrong data. +target Cpp { fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: int + + timer t(offset, period) + + state count: int(0) + reaction(t) -> y {= count++; //std::cout << "Reacting at time " << get_elapsed_logical_time() << '\n'; y.set(count); =} } + reactor Destination { - input x:int; - state s:int(1); + input x: int + + state s: int(1) + reaction(x) {= //std::cout << "Received " << *x.get() << '\n'; if (*x.get() != s) { @@ -29,15 +33,15 @@ reactor Destination { =} } -main reactor (period:time(100 usec)) { - timer stop(10 secs); - reaction(stop) {= - environment()->sync_shutdown(); - =} - reaction(shutdown) {= - std::cout << "**** shutdown reaction invoked.\n"; - =} - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; +main reactor(period: time(100 usec)) { + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x + + reaction(stop) {= environment()->sync_shutdown(); =} + + reaction(shutdown) {= std::cout << "**** shutdown reaction invoked.\n"; =} } diff --git a/test/Cpp/src/concurrent/Workers.lf b/test/Cpp/src/concurrent/Workers.lf index a20eeea57d..a6d009561e 100644 --- a/test/Cpp/src/concurrent/Workers.lf +++ b/test/Cpp/src/concurrent/Workers.lf @@ -1,4 +1,5 @@ -target Cpp { workers: 16 }; +target Cpp { workers: 16 } + main reactor { reaction(startup) {= if (environment()->num_workers() != 16) { diff --git a/test/Cpp/src/lib/Count.lf b/test/Cpp/src/lib/Count.lf index 2837711b5a..1f70986409 100644 --- a/test/Cpp/src/lib/Count.lf +++ b/test/Cpp/src/lib/Count.lf @@ -1,8 +1,12 @@ -target Cpp; +target Cpp + reactor Count { - output c:int; - timer t(0, 1 sec); - state i:int(0); + output c: int + + timer t(0, 1 sec) + + state i: int(0) + reaction(t) -> c {= i++; c.set(i); diff --git a/test/Cpp/src/lib/Imported.lf b/test/Cpp/src/lib/Imported.lf index ab21168b30..1b72eef759 100644 --- a/test/Cpp/src/lib/Imported.lf +++ b/test/Cpp/src/lib/Imported.lf @@ -1,12 +1,13 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Cpp; -import ImportedAgain from "ImportedAgain.lf"; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target Cpp + +import ImportedAgain from "ImportedAgain.lf" reactor Imported { - input x:int; - a = new ImportedAgain(); - reaction(x) -> a.x {= - a.x.set(x.get()); - =} + input x: int + + a = new ImportedAgain() + + reaction(x) -> a.x {= a.x.set(x.get()); =} } diff --git a/test/Cpp/src/lib/ImportedAgain.lf b/test/Cpp/src/lib/ImportedAgain.lf index f055bf08e1..048bdef364 100644 --- a/test/Cpp/src/lib/ImportedAgain.lf +++ b/test/Cpp/src/lib/ImportedAgain.lf @@ -1,8 +1,10 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Cpp; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target Cpp + reactor ImportedAgain { - input x:int; + input x: int + reaction(x) {= auto value = *x.get(); if (value != 42) { diff --git a/test/Cpp/src/lib/ImportedComposition.lf b/test/Cpp/src/lib/ImportedComposition.lf index 9f4871e3b6..2a0c5c10af 100644 --- a/test/Cpp/src/lib/ImportedComposition.lf +++ b/test/Cpp/src/lib/ImportedComposition.lf @@ -1,27 +1,30 @@ /** -* -* @author Maiko Brants TU Dresden -* -* This is used by the test for the ability to import a reactor definition -* that itself imports a reactor definition. -* -* modeled after the C version of this test -**/ -target Cpp; + * @author Maiko Brants TU Dresden + * + * This is used by the test for the ability to import a reactor definition that + * itself imports a reactor definition. + * + * modeled after the C version of this test + */ +target Cpp reactor Gain { - input x:int; - output y:int; - reaction(x) -> y {= - y.set(*x.get() * 2); - =} + input x: int + + output y: int + + reaction(x) -> y {= y.set(*x.get() * 2); =} } + reactor ImportedComposition { - input x:int; - output y:int; - g1 = new Gain(); - g2 = new Gain(); - x -> g1.x after 10 msec; - g1.y -> g2.x after 30 msec; - g2.y -> y after 15 msec; + input x: int + + output y: int + + g1 = new Gain() + g2 = new Gain() + + x -> g1.x after 10 msec + g1.y -> g2.x after 30 msec + g2.y -> y after 15 msec } diff --git a/test/Cpp/src/lib/LoopedActionSender.lf b/test/Cpp/src/lib/LoopedActionSender.lf index a6d9dcb323..c00ca41280 100644 --- a/test/Cpp/src/lib/LoopedActionSender.lf +++ b/test/Cpp/src/lib/LoopedActionSender.lf @@ -1,23 +1,25 @@ /** - * A sender reactor that outputs integers - * in superdense time. + * A sender reactor that outputs integers in superdense time. * * Modeled after the C version of this file. * * @author Maiko Brants */ -target Cpp; +target Cpp /** - * @param take_a_break_after: Indicates how many messages are sent - * in consecutive superdense time - * @param break_interval: Determines how long the reactor should take - * a break after sending take_a_break_after messages. + * @param take_a_break_after: Indicates how many messages are sent in + * consecutive superdense time + * @param break_interval: Determines how long the reactor should take a break + * after sending take_a_break_after messages. */ -reactor Sender(take_a_break_after:int(10), break_interval:time(400 msec)) { - output out:int; - logical action act; - state sent_messages:int(0); +reactor Sender(take_a_break_after: int(10), break_interval: time(400 msec)) { + output out: int + + logical action act + + state sent_messages: int(0) + reaction(startup, act) -> act, out {= out.set(sent_messages); sent_messages++; diff --git a/test/Cpp/src/multiport/BankSelfBroadcast.lf b/test/Cpp/src/multiport/BankSelfBroadcast.lf index 6373484a8d..4218890e48 100644 --- a/test/Cpp/src/multiport/BankSelfBroadcast.lf +++ b/test/Cpp/src/multiport/BankSelfBroadcast.lf @@ -1,20 +1,22 @@ /** - * Test a bank of reactors that broadcast a single output - * back to a multiport input of the same reactors in the bank - * so that each reactor in the bank receives the output - * produced by itself and each other reactor. + * Test a bank of reactors that broadcast a single output back to a multiport + * input of the same reactors in the bank so that each reactor in the bank + * receives the output produced by itself and each other reactor. * * @author Edward A. Lee * @author Christian Menard */ -target Cpp; -reactor A(bank_index:size_t(0)) { - input[4] in:size_t; - output out:size_t; - state received:bool(false); - reaction(startup) -> out {= - out.set(bank_index); - =} +target Cpp + +reactor A(bank_index: size_t(0)) { + input[4] in: size_t + + output out: size_t + + state received: bool(false) + + reaction(startup) -> out {= out.set(bank_index); =} + reaction(in) {= for (size_t i = 0; i < in.size(); i++) { if (in[i].is_present()) { @@ -32,6 +34,7 @@ reactor A(bank_index:size_t(0)) { } } =} + reaction(shutdown) {= if (!received) { std::cerr << "ERROR: No inputs received.\n"; @@ -39,7 +42,9 @@ reactor A(bank_index:size_t(0)) { } =} } + main reactor { - a = new[4] A(); - (a.out)+ -> a.in; + a = new[4] A() + + (a.out)+ -> a.in } diff --git a/test/Cpp/src/multiport/BankToBank.lf b/test/Cpp/src/multiport/BankToBank.lf index 96a7a7c7a5..e2e95a4b74 100644 --- a/test/Cpp/src/multiport/BankToBank.lf +++ b/test/Cpp/src/multiport/BankToBank.lf @@ -1,20 +1,24 @@ // Check bank of reactors sending to bank of reactors. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Source(bank_index:size_t(0)) { - timer t(0, 200 msec); - output out:int; - state s:int(0); +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(bank_index: size_t(0)) { + output out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= out.set(s); s += bank_index; =} } -reactor Destination(bank_index:size_t(0)) { - state s:int(0); - input in:int; + +reactor Destination(bank_index: size_t(0)) { + input in: int + + state s: int(0) + reaction(in) {= std::cout << "Destination " << bank_index << " received: " << *in.get() << "\n"; if (*in.get() != s) { @@ -23,6 +27,7 @@ reactor Destination(bank_index:size_t(0)) { } s += bank_index; =} + reaction(shutdown) {= if (s == 0 && bank_index != 0) { std::cerr << "ERROR: Destination " << bank_index << " received no input!\n"; @@ -32,9 +37,10 @@ reactor Destination(bank_index:size_t(0)) { =} } -main reactor BankToBank(width:int(4)) { +main reactor BankToBank(width: int(4)) { // FIXME: Should set the width to "width" rather than "4". - a = new[4] Source(); - b = new[4] Destination(); - a.out -> b.in; + a = new[4] Source() + b = new[4] Destination() + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/BankToBankMultiport.lf b/test/Cpp/src/multiport/BankToBankMultiport.lf index 7a31b339a0..9fbaa63cfa 100644 --- a/test/Cpp/src/multiport/BankToBankMultiport.lf +++ b/test/Cpp/src/multiport/BankToBankMultiport.lf @@ -1,21 +1,25 @@ // Check bank of reactors sending to bank of reactors with multiports. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Source(width:size_t(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(width: size_t(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(size_t i = 0; i < out.size(); i++) { out[i].set(s++); } =} } -reactor Destination(width:size_t(1)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: size_t(1)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (size_t i = 0; i < in.size(); i++) { @@ -28,6 +32,7 @@ reactor Destination(width:size_t(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { std::cerr << "ERROR: Destination received no input!\n"; @@ -36,8 +41,10 @@ reactor Destination(width:size_t(1)) { std::cout << "Success.\n"; =} } -main reactor (bank_width:size_t(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b.in; + +main reactor(bank_width: size_t(4)) { + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/BankToBankMultiportAfter.lf b/test/Cpp/src/multiport/BankToBankMultiportAfter.lf index 1710f6ee5f..be14cd4527 100644 --- a/test/Cpp/src/multiport/BankToBankMultiportAfter.lf +++ b/test/Cpp/src/multiport/BankToBankMultiportAfter.lf @@ -1,22 +1,26 @@ // Check bank of reactors sending to bank of reactors with multiports. -target Cpp { - timeout: 2 sec, - fast: true, -}; -reactor Source(width:size_t(1)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(width: size_t(1)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(size_t i = 0; i < out.size(); i++) { out[i].set(s++); } =} } -reactor Destination(width:size_t(1)) { - state s:int(6); - state iterations:unsigned(0); - input[width] in:int; + +reactor Destination(width: size_t(1)) { + input[width] in: int + + state s: int(6) + state iterations: unsigned(0) + reaction(in) {= iterations++; auto lt = get_elapsed_logical_time(); @@ -37,6 +41,7 @@ reactor Destination(width:size_t(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { std::cerr << "ERROR: Destination received no input!\n"; @@ -45,8 +50,10 @@ reactor Destination(width:size_t(1)) { std::cout << "Success.\n"; =} } -main reactor (bank_width:size_t(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b.in after 200 msec; + +main reactor(bank_width: size_t(4)) { + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b.in after 200 msec } diff --git a/test/Cpp/src/multiport/BankToMultiport.lf b/test/Cpp/src/multiport/BankToMultiport.lf index 6682340c24..11db9f9d5a 100644 --- a/test/Cpp/src/multiport/BankToMultiport.lf +++ b/test/Cpp/src/multiport/BankToMultiport.lf @@ -1,18 +1,18 @@ // Test bank of reactors to multiport input with id parameter in the bank. -target Cpp; -reactor Source(bank_index:size_t(0)) { - output out:unsigned; +target Cpp - reaction (startup) -> out {= - out.set(bank_index); - =} +reactor Source(bank_index: size_t(0)) { + output out: unsigned + + reaction(startup) -> out {= out.set(bank_index); =} } reactor Sink { - input[4] in:unsigned; - state received:bool(false); + input[4] in: unsigned + + state received: bool(false) - reaction (in) {= + reaction(in) {= for (unsigned i = 0; i < in.size(); i++) { received = true; std::cout << "Received " << *in[i].get() << '\n'; @@ -22,7 +22,8 @@ reactor Sink { } } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { std::cerr << "Error: received no input!\n"; exit(2); @@ -31,7 +32,8 @@ reactor Sink { } main reactor BankToMultiport { - source = new[4] Source(); - sink = new Sink(); - source.out -> sink.in; + source = new[4] Source() + sink = new Sink() + + source.out -> sink.in } diff --git a/test/Cpp/src/multiport/Broadcast.lf b/test/Cpp/src/multiport/Broadcast.lf index dd9f71663a..3896cf901d 100644 --- a/test/Cpp/src/multiport/Broadcast.lf +++ b/test/Cpp/src/multiport/Broadcast.lf @@ -1,17 +1,15 @@ -target Cpp; +target Cpp reactor Source { - output out:unsigned; + output out: unsigned - reaction (startup) -> out {= - out.set(42); - =} + reaction(startup) -> out {= out.set(42); =} } -reactor Sink(bank_index:size_t(0)) { - input in:unsigned; +reactor Sink(bank_index: size_t(0)) { + input in: unsigned - reaction (in) {= + reaction(in) {= std::cout << "Received " << *in.get() << '\n'; if (*in.get() != 42) { std::cerr << "Error: expected " << 42 << "!\n"; @@ -21,7 +19,8 @@ reactor Sink(bank_index:size_t(0)) { } main reactor { - source = new Source(); - sink = new[4] Sink(); - (source.out)+ -> sink.in; + source = new Source() + sink = new[4] Sink() + + (source.out)+ -> sink.in } diff --git a/test/Cpp/src/multiport/BroadcastAfter.lf b/test/Cpp/src/multiport/BroadcastAfter.lf index 5694383a3e..b777405d2e 100644 --- a/test/Cpp/src/multiport/BroadcastAfter.lf +++ b/test/Cpp/src/multiport/BroadcastAfter.lf @@ -1,20 +1,17 @@ -target Cpp{ - fast: true -} +target Cpp { fast: true } reactor Source { - output out:unsigned; + output out: unsigned - reaction (startup) -> out {= - out.set(42); - =} + reaction(startup) -> out {= out.set(42); =} } reactor Sink(bank_index: size_t(0)) { - input in:unsigned; - state received: bool{false}; + input in: unsigned - reaction (in) {= + state received: bool{false} + + reaction(in) {= std::cout << bank_index << " received " << *in.get() << '\n'; if (*in.get() != 42) { std::cerr << "Error: expected " << 42 << "!\n"; @@ -37,7 +34,8 @@ reactor Sink(bank_index: size_t(0)) { } main reactor { - source = new Source(); - sink = new[4] Sink(); - (source.out)+ -> sink.in after 1 sec; + source = new Source() + sink = new[4] Sink() + + (source.out)+ -> sink.in after 1 sec } diff --git a/test/Cpp/src/multiport/BroadcastMultipleAfter.lf b/test/Cpp/src/multiport/BroadcastMultipleAfter.lf index 75f938c27d..4ef0ab166f 100644 --- a/test/Cpp/src/multiport/BroadcastMultipleAfter.lf +++ b/test/Cpp/src/multiport/BroadcastMultipleAfter.lf @@ -1,20 +1,17 @@ -target Cpp{ - fast: true -} +target Cpp { fast: true } -reactor Source(value:unsigned(42)) { - output out:unsigned; +reactor Source(value: unsigned(42)) { + output out: unsigned - reaction (startup) -> out {= - out.set(value); - =} + reaction(startup) -> out {= out.set(value); =} } reactor Sink(bank_index: size_t(0)) { - input in:unsigned; - state received: bool{false}; + input in: unsigned - reaction (in) {= + state received: bool{false} + + reaction(in) {= std::cout << bank_index << " received " << *in.get() << '\n'; auto expected = (bank_index % 3) + 1; if (*in.get() != expected) { @@ -38,9 +35,10 @@ reactor Sink(bank_index: size_t(0)) { } main reactor { - source1 = new Source(value=1); - source2 = new Source(value=2); - source3 = new Source(value=3); - sink = new[9] Sink(); - (source1.out, source2.out, source3.out)+ -> sink.in after 1 sec; + source1 = new Source(value = 1) + source2 = new Source(value = 2) + source3 = new Source(value = 3) + sink = new[9] Sink() + + (source1.out, source2.out, source3.out)+ -> sink.in after 1 sec } diff --git a/test/Cpp/src/multiport/FullyConnected.lf b/test/Cpp/src/multiport/FullyConnected.lf index 9b0233d43e..8634fafdc7 100644 --- a/test/Cpp/src/multiport/FullyConnected.lf +++ b/test/Cpp/src/multiport/FullyConnected.lf @@ -1,19 +1,19 @@ -target Cpp { -} +target Cpp reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { input[num_nodes] in: size_t + output out: size_t - state received: bool{false}; + state received: bool{false} - reaction (startup) -> out{= + reaction(startup) -> out {= std::cout << "Hello from node " << bank_index << "!\n"; // broadcast my ID to everyone out.set(bank_index); =} - reaction (in) {= + reaction(in) {= std::cout << "Node " << bank_index << " received messages from "; received = true; size_t count{0}; @@ -29,7 +29,8 @@ reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { exit(1); } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { std::cerr << "Error: received no input!\n"; exit(2); @@ -38,6 +39,7 @@ reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { } main reactor(num_nodes: size_t(4)) { - nodes = new[num_nodes] Node(num_nodes=num_nodes); - (nodes.out)+ -> nodes.in; + nodes = new[num_nodes] Node(num_nodes = num_nodes) + + (nodes.out)+ -> nodes.in } diff --git a/test/Cpp/src/multiport/FullyConnectedAddressable.lf b/test/Cpp/src/multiport/FullyConnectedAddressable.lf index bac6f76fba..f277d93c04 100644 --- a/test/Cpp/src/multiport/FullyConnectedAddressable.lf +++ b/test/Cpp/src/multiport/FullyConnectedAddressable.lf @@ -1,21 +1,20 @@ // In this pattern, each node can send direct messages to individual other nodes - -target Cpp { -} +target Cpp reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { input[num_nodes] in: size_t + output[num_nodes] out: size_t - state received: bool{false}; + state received: bool{false} - reaction (startup) -> out{= + reaction(startup) -> out {= std::cout << "Hello from node " << bank_index << "!\n"; // send my ID only to my right neighbour out[(bank_index + 1) % num_nodes].set(bank_index); =} - reaction (in) {= + reaction(in) {= std::cout << "Node " << bank_index << " received messages from "; received = true; size_t count{0}; @@ -34,9 +33,9 @@ reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { std::cerr << "ERROR: received an unexpected message!\n"; exit(1); } - =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { std::cerr << "Error: received no input!\n"; exit(2); @@ -45,9 +44,9 @@ reactor Node(bank_index: size_t(0), num_nodes: size_t(4)) { } main reactor(num_nodes: size_t(4)) { - nodes1 = new[num_nodes] Node(num_nodes=num_nodes); - nodes1.out -> interleaved(nodes1.in); + nodes1 = new[num_nodes] Node(num_nodes = num_nodes) + nodes2 = new[num_nodes] Node(num_nodes = num_nodes) - nodes2 = new[num_nodes] Node(num_nodes=num_nodes); - interleaved(nodes2.out) -> nodes2.in; + nodes1.out -> interleaved (nodes1.in) + interleaved (nodes2.out) -> nodes2.in } diff --git a/test/Cpp/src/multiport/FullyConnectedAddressableAfter.lf b/test/Cpp/src/multiport/FullyConnectedAddressableAfter.lf index d4c8240c95..3920a21739 100644 --- a/test/Cpp/src/multiport/FullyConnectedAddressableAfter.lf +++ b/test/Cpp/src/multiport/FullyConnectedAddressableAfter.lf @@ -1,14 +1,12 @@ // In this pattern, each node can send direct messages to individual other nodes - -target Cpp { -} +target Cpp import Node from "FullyConnectedAddressable.lf" main reactor(num_nodes: size_t(4)) { - nodes1 = new[num_nodes] Node(num_nodes=num_nodes); - nodes1.out -> interleaved(nodes1.in) after 200msec; + nodes1 = new[num_nodes] Node(num_nodes = num_nodes) + nodes2 = new[num_nodes] Node(num_nodes = num_nodes) - nodes2 = new[num_nodes] Node(num_nodes=num_nodes); - interleaved(nodes2.out) -> nodes2.in after 400msec; + nodes1.out -> interleaved (nodes1.in) after 200 msec + interleaved (nodes2.out) -> nodes2.in after 400 msec } diff --git a/test/Cpp/src/multiport/MultiportFromBank.lf b/test/Cpp/src/multiport/MultiportFromBank.lf index 0b53ab5f5b..06a946fcf2 100644 --- a/test/Cpp/src/multiport/MultiportFromBank.lf +++ b/test/Cpp/src/multiport/MultiportFromBank.lf @@ -1,18 +1,18 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Source(bank_index:size_t(0)) { - output out:unsigned; - reaction(startup) -> out {= - out.set(bank_index); - =} +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(bank_index: size_t(0)) { + output out: unsigned + + reaction(startup) -> out {= out.set(bank_index); =} } -reactor Destination(port_width:size_t(2)) { - input[port_width] in:unsigned; - state received:bool(false); + +reactor Destination(port_width: size_t(2)) { + input[port_width] in: unsigned + + state received: bool(false) + reaction(in) {= for (size_t i = 0; i < in.size(); i++) { std::cout << "Destination channel " << i << " received " << *in[i].get() << ".\n"; @@ -23,6 +23,7 @@ reactor Destination(port_width:size_t(2)) { } received = true; =} + reaction(shutdown) {= if (!received) { std::cerr << "ERROR: Destination received no input!\n"; @@ -32,8 +33,9 @@ reactor Destination(port_width:size_t(2)) { =} } -main reactor (width:size_t(4)) { - a = new[width] Source(); - b = new Destination(port_width = width); - a.out -> b.in; +main reactor(width: size_t(4)) { + a = new[width] Source() + b = new Destination(port_width = width) + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportFromBankHierarchyAfter.lf b/test/Cpp/src/multiport/MultiportFromBankHierarchyAfter.lf index 40b89efd32..5c7dc71947 100644 --- a/test/Cpp/src/multiport/MultiportFromBankHierarchyAfter.lf +++ b/test/Cpp/src/multiport/MultiportFromBankHierarchyAfter.lf @@ -1,23 +1,26 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Source(bank_index:int(0)) { - output out:int; - reaction(startup) -> out {= - out.set(bank_index); - =} +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(bank_index: int(0)) { + output out: int + + reaction(startup) -> out {= out.set(bank_index); =} } + reactor Container { - output[3] out:int; - s = new[3] Source(); - s.out -> out; + output[3] out: int + + s = new[3] Source() + + s.out -> out } + reactor Destination { - input[3] in:int; - state received:bool(false); + input[3] in: int + + state received: bool(false) + reaction(in) {= for (int i = 0; i < in.size(); i++) { int value = *in[i].get(); @@ -33,6 +36,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { std::cerr << "ERROR: Destination received no input!\n"; @@ -43,7 +47,8 @@ reactor Destination { } main reactor MultiportFromBankHierarchyAfter { - a = new Container(); - b = new Destination(); - a.out -> b.in after 1 sec; + a = new Container() + b = new Destination() + + a.out -> b.in after 1 sec } diff --git a/test/Cpp/src/multiport/MultiportFromHierarchy.lf b/test/Cpp/src/multiport/MultiportFromHierarchy.lf index a9454c5730..e7d95fb4d7 100644 --- a/test/Cpp/src/multiport/MultiportFromHierarchy.lf +++ b/test/Cpp/src/multiport/MultiportFromHierarchy.lf @@ -1,21 +1,26 @@ -// Check multiport output to multiport input, where the former is a hierarchical reactor. -target Cpp { - timeout: 2 sec, - fast: true -}; +// Check multiport output to multiport input, where the former is a hierarchical +// reactor. +target Cpp { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out:int; - state s:int(0); + output[4] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 4; i++) { out[i].set(s++); } =} } + reactor Destination { - state s:int(6); - input[4] in:int; + input[4] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (int i = 0; i < in.size(); i++) { @@ -28,6 +33,7 @@ reactor Destination { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { std::cerr << "ERROR: Destination received no input!\n"; @@ -36,20 +42,26 @@ reactor Destination { std::cout << "Success.\n"; =} } + reactor Container { - output[4] out:int; - src = new InsideContainer(); - src.out -> out; + output[4] out: int + + src = new InsideContainer() + + src.out -> out } reactor InsideContainer { - output[4] out:int; - src = new Source(); - src.out -> out; + output[4] out: int + + src = new Source() + + src.out -> out } -main reactor MultiportFromHierarchy { - a = new Container(); - b = new Destination(); - a.out -> b.in; +main reactor MultiportFromHierarchy { + a = new Container() + b = new Destination() + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportIn.lf b/test/Cpp/src/multiport/MultiportIn.lf index bda94b6204..3c0cbe9e83 100644 --- a/test/Cpp/src/multiport/MultiportIn.lf +++ b/test/Cpp/src/multiport/MultiportIn.lf @@ -1,28 +1,30 @@ -// This is a version fo the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target Cpp { - timeout: 2 sec, - fast: true -}; +// This is a version fo the Threaded test that uses a multiport input at the +// destination. Its purpose is to test multiport inputs. +target Cpp { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out:int; - state s:int(0); - reaction(t) -> out {= - out.set(s++); - =} + output out: int + + timer t(0, 200 msec) + + state s: int(0) + + reaction(t) -> out {= out.set(s++); =} } + reactor Computation { - input in:int; - output out:int; - reaction(in) -> out {= - out.set(*in.get()); - =} + input in: int + + output out: int + + reaction(in) -> out {= out.set(*in.get()); =} } + reactor Destination { - state s:int(0); - input[4] in:int; + input[4] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in.size(); i++) { @@ -35,6 +37,7 @@ reactor Destination { } s += 4; =} + reaction(shutdown) {= if (s == 0) { std::cerr << "ERROR: Destination received no input!\n"; @@ -45,15 +48,16 @@ reactor Destination { } main reactor MultiportIn { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in; - a.out -> t2.in; - a.out -> t3.in; - a.out -> t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in + a.out -> t2.in + a.out -> t3.in + a.out -> t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportOut.lf b/test/Cpp/src/multiport/MultiportOut.lf index 0d86c22c37..88be6c28a1 100644 --- a/test/Cpp/src/multiport/MultiportOut.lf +++ b/test/Cpp/src/multiport/MultiportOut.lf @@ -1,12 +1,13 @@ // Check multiport capabilities on Outputs. -target Cpp { - timeout: 2 sec, - fast: true -}; +target Cpp { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out:int; - state s:int(0); + output[4] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 4; i++) { out[i].set(s); @@ -14,9 +15,12 @@ reactor Source { s++; =} } + reactor Computation { - input in:int; - output out:int; + input in: int + + output out: int + reaction(in) -> out {= // No need to sleep for this test. // struct timespec sleep_time = {(time_t) 0, (long)200000000}; @@ -25,9 +29,12 @@ reactor Computation { out.set(*in.get()); =} } + reactor Destination { - state s:int(0); - input[4] in:int; + input[4] in: int + + state s: int(0) + reaction(in) {= int sum = 0; for (int i = 0; i < in.size(); i++) { @@ -40,6 +47,7 @@ reactor Destination { } s += 4; =} + reaction(shutdown) {= if (s == 0) { std::cerr << "ERROR: Destination received no input!\n"; @@ -50,12 +58,13 @@ reactor Destination { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in, t2.in, t3.in, t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in, t2.in, t3.in, t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportToBank.lf b/test/Cpp/src/multiport/MultiportToBank.lf index 4d8605f612..44d1c12051 100644 --- a/test/Cpp/src/multiport/MultiportToBank.lf +++ b/test/Cpp/src/multiport/MultiportToBank.lf @@ -1,19 +1,19 @@ -target Cpp; +target Cpp reactor Source { - output[4] out:unsigned; + output[4] out: unsigned - reaction (startup) -> out {= + reaction(startup) -> out {= for (unsigned i = 0 ; i < out.size(); i++) { out[i].set(i); } =} } -reactor Sink(bank_index:size_t(0)) { - input in:unsigned; +reactor Sink(bank_index: size_t(0)) { + input in: unsigned - reaction (in) {= + reaction(in) {= std::cout << "Received " << *in.get() << '\n'; if (*in.get() != bank_index) { std::cerr << "Error: expected " << bank_index << "!\n"; @@ -23,7 +23,8 @@ reactor Sink(bank_index:size_t(0)) { } main reactor MultiportToBank { - source = new Source(); - sink = new[4] Sink(); - source.out -> sink.in; + source = new Source() + sink = new[4] Sink() + + source.out -> sink.in } diff --git a/test/Cpp/src/multiport/MultiportToBankAfter.lf b/test/Cpp/src/multiport/MultiportToBankAfter.lf index efd7692057..46c5c0f758 100644 --- a/test/Cpp/src/multiport/MultiportToBankAfter.lf +++ b/test/Cpp/src/multiport/MultiportToBankAfter.lf @@ -1,19 +1,19 @@ -target Cpp; +target Cpp reactor Source { - output[4] out:unsigned; + output[4] out: unsigned - reaction (startup) -> out {= + reaction(startup) -> out {= for (unsigned i = 0 ; i < out.size(); i++) { out[i].set(i); } =} } -reactor Sink(bank_index:size_t(0)) { - input in:unsigned; +reactor Sink(bank_index: size_t(0)) { + input in: unsigned - reaction (in) {= + reaction(in) {= std::cout << "Received " << *in.get() << '\n'; if (*in.get() != bank_index) { std::cerr << "Error: expected " << bank_index << "!\n"; @@ -27,7 +27,8 @@ reactor Sink(bank_index:size_t(0)) { } main reactor MultiportToBankAfter { - source = new Source(); - sink = new[4] Sink(); - source.out -> sink.in after 1 sec; + source = new Source() + sink = new[4] Sink() + + source.out -> sink.in after 1 sec } diff --git a/test/Cpp/src/multiport/MultiportToBankHierarchy.lf b/test/Cpp/src/multiport/MultiportToBankHierarchy.lf index 9d19657aa5..df95955f13 100644 --- a/test/Cpp/src/multiport/MultiportToBankHierarchy.lf +++ b/test/Cpp/src/multiport/MultiportToBankHierarchy.lf @@ -1,20 +1,22 @@ -// Check multiport output to bank of recipients. - // Here, the bank is smaller than the width of the sending port. -target Cpp { - timeout: 2 sec, - fast: true -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target Cpp { timeout: 2 sec, fast: true } + reactor Source { - output[3] out:unsigned; + output[3] out: unsigned + reaction(startup) -> out {= for(size_t i = 0; i < out.size(); i++) { out[i].set(i); } =} } -reactor Destination(bank_index:size_t(0)) { - input in:unsigned; - state received:bool(false); + +reactor Destination(bank_index: size_t(0)) { + input in: unsigned + + state received: bool(false) + reaction(in) {= std::cout << "Destination " << bank_index << " received " << *in.get() << ".\n"; if (bank_index != *in.get()) { @@ -23,6 +25,7 @@ reactor Destination(bank_index:size_t(0)) { } received = true; =} + reaction(shutdown) {= if (!received) { std::cerr << "ERROR: Destination " << bank_index << " received no input!\n"; @@ -31,14 +34,18 @@ reactor Destination(bank_index:size_t(0)) { std::cout << "Success.\n"; =} } + reactor Container { - input[3] in:unsigned; - c = new[3] Destination(); - in -> c.in; + input[3] in: unsigned + + c = new[3] Destination() + + in -> c.in } main reactor MultiportToBankHierarchy { - a = new Source(); - b = new Container(); - a.out -> b.in; + a = new Source() + b = new Container() + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportToHierarchy.lf b/test/Cpp/src/multiport/MultiportToHierarchy.lf index d7fb946dea..ff2936b302 100644 --- a/test/Cpp/src/multiport/MultiportToHierarchy.lf +++ b/test/Cpp/src/multiport/MultiportToHierarchy.lf @@ -1,22 +1,27 @@ -// Check multiport output to multiport input, where the latter is a hierarchical reactor. -// Note that the destination reactor has width wider than the sender, so one input is dangling. -target Cpp { - timeout: 2 sec, - fast: true -}; -reactor Source(width:size_t(4)) { - timer t(0, 200 msec); - output[width] out:int; - state s:int(0); +// Check multiport output to multiport input, where the latter is a hierarchical +// reactor. Note that the destination reactor has width wider than the sender, +// so one input is dangling. +target Cpp { timeout: 2 sec, fast: true } + +reactor Source(width: size_t(4)) { + output[width] out: int + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(size_t i = 0; i < 4; i++) { out[i].set(s++); } =} } -reactor Destination(width:size_t(4)) { - state s:int(6); - input[width] in:int; + +reactor Destination(width: size_t(4)) { + input[width] in: int + + state s: int(6) + reaction(in) {= int sum = 0; for (size_t i = 0; i < in.size(); i++) { @@ -29,6 +34,7 @@ reactor Destination(width:size_t(4)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { std::cerr << "ERROR: Destination received no input!\n"; @@ -37,14 +43,18 @@ reactor Destination(width:size_t(4)) { std::cout << "Success.\n"; =} } -reactor Container(width:size_t(4)) { - input[width] in:int; - dst = new Destination(); - in -> dst.in; + +reactor Container(width: size_t(4)) { + input[width] in: int + + dst = new Destination() + + in -> dst.in } -main reactor MultiportToHierarchy(width:size_t(4)) { - a = new Source(width=width); - b = new Container(width=width); - a.out -> b.in; +main reactor MultiportToHierarchy(width: size_t(4)) { + a = new Source(width = width) + b = new Container(width = width) + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportToMultiport.lf b/test/Cpp/src/multiport/MultiportToMultiport.lf index 43130f5a7e..ad6042bc80 100644 --- a/test/Cpp/src/multiport/MultiportToMultiport.lf +++ b/test/Cpp/src/multiport/MultiportToMultiport.lf @@ -1,9 +1,9 @@ -target Cpp; +target Cpp reactor Source { - output[4] out:unsigned; + output[4] out: unsigned - reaction (startup) -> out {= + reaction(startup) -> out {= for (unsigned i = 0; i < out.size(); i++) { out[i].set(i); } @@ -11,10 +11,11 @@ reactor Source { } reactor Sink { - input[4] in:unsigned; - state received:bool(false); + input[4] in: unsigned - reaction (in) {= + state received: bool(false) + + reaction(in) {= for (unsigned i = 0; i < in.size(); i++) { std::cout << "Received " << *in[i].get() << '\n'; received = true; @@ -24,7 +25,8 @@ reactor Sink { } } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { std::cerr << "Error: No data received!\n"; exit(2); @@ -33,7 +35,8 @@ reactor Sink { } main reactor MultiportToMultiport { - source = new Source(); - sink = new Sink(); - source.out -> sink.in; + source = new Source() + sink = new Sink() + + source.out -> sink.in } diff --git a/test/Cpp/src/multiport/MultiportToMultiport2.lf b/test/Cpp/src/multiport/MultiportToMultiport2.lf index 0ea63c75fd..62e366a21e 100644 --- a/test/Cpp/src/multiport/MultiportToMultiport2.lf +++ b/test/Cpp/src/multiport/MultiportToMultiport2.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target Cpp; +// Test multiport to multiport connections. See also MultiportToMultiport. +target Cpp -reactor Source(width:size_t(2)) { - output[width] out:size_t; - reaction (startup) -> out {= +reactor Source(width: size_t(2)) { + output[width] out: size_t + + reaction(startup) -> out {= for (size_t i = 0; i < out.size(); i++) { out[i].set(i); } =} } -reactor Destination(width:size_t(2)) { - input[width] in:size_t; - reaction (in) {= +reactor Destination(width: size_t(2)) { + input[width] in: size_t + + reaction(in) {= for (size_t i = 0; i < in.size(); i++) { if (in[i].is_present()) { size_t value = *in[i].get(); @@ -30,8 +31,9 @@ reactor Destination(width:size_t(2)) { } main reactor MultiportToMultiport2 { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.in; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportToMultiport2After.lf b/test/Cpp/src/multiport/MultiportToMultiport2After.lf index 9c2bff8486..5d5dab6c87 100644 --- a/test/Cpp/src/multiport/MultiportToMultiport2After.lf +++ b/test/Cpp/src/multiport/MultiportToMultiport2After.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target Cpp; +// Test multiport to multiport connections. See also MultiportToMultiport. +target Cpp -reactor Source(width:size_t(2)) { - output[width] out:size_t; - reaction (startup) -> out {= +reactor Source(width: size_t(2)) { + output[width] out: size_t + + reaction(startup) -> out {= for (size_t i = 0; i < out.size(); i++) { out[i].set(i); } =} } -reactor Destination(width:size_t(2)) { - input[width] in:size_t; - reaction (in) {= +reactor Destination(width: size_t(2)) { + input[width] in: size_t + + reaction(in) {= for (size_t i = 0; i < in.size(); i++) { if (in[i].is_present()) { size_t value = *in[i].get(); @@ -34,8 +35,9 @@ reactor Destination(width:size_t(2)) { } main reactor { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.in after 1 sec; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.in after 1 sec } diff --git a/test/Cpp/src/multiport/MultiportToMultiportArray.lf b/test/Cpp/src/multiport/MultiportToMultiportArray.lf index 21e95cd2a8..aefdce37ef 100644 --- a/test/Cpp/src/multiport/MultiportToMultiportArray.lf +++ b/test/Cpp/src/multiport/MultiportToMultiportArray.lf @@ -1,13 +1,14 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target Cpp { - timeout: 2 sec, - fast: true -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target Cpp { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[2] out:int[3]; - state s:int(0); + output[2] out: int[3] + + timer t(0, 200 msec) + + state s: int(0) + reaction(t) -> out {= for(int i = 0; i < 2; i++) { // Dynamically allocate a new output array @@ -23,8 +24,10 @@ reactor Source { } reactor Destination { - state s:int(15); - input[2] in:int[3]; + input[2] in: int[3] + + state s: int(15) + reaction(in) {= int sum = 0; for (size_t i = 0; i < in.size(); i++) { @@ -42,6 +45,7 @@ reactor Destination { } s += 36; =} + reaction(shutdown) {= if (s <= 15) { std::cerr << "ERROR: Destination received no input!\n"; @@ -52,7 +56,8 @@ reactor Destination { } main reactor MultiportToMultiportArray { - a = new Source(); - b = new Destination(); - a.out -> b.in; + a = new Source() + b = new Destination() + + a.out -> b.in } diff --git a/test/Cpp/src/multiport/MultiportToPort.lf b/test/Cpp/src/multiport/MultiportToPort.lf index a3cda51866..af7f86b0c3 100644 --- a/test/Cpp/src/multiport/MultiportToPort.lf +++ b/test/Cpp/src/multiport/MultiportToPort.lf @@ -1,11 +1,10 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target Cpp { - timeout: 2 sec, - fast: true -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target Cpp { timeout: 2 sec, fast: true } + reactor Source { - output[2] out:int; + output[2] out: int + reaction(startup) -> out {= for(int i = 0; i < out.size(); i++) { std::cout << "Source sending " << i << ".\n"; @@ -13,9 +12,12 @@ reactor Source { } =} } -reactor Destination(expected:int(0)) { - input in:int; - state received:bool(false); + +reactor Destination(expected: int(0)) { + input in: int + + state received: bool(false) + reaction(in) {= std::cout << "Received: " << *in.get() << ".\n"; received = true; @@ -24,6 +26,7 @@ reactor Destination(expected:int(0)) { exit(1); } =} + reaction(shutdown) {= if (!received) { std::cerr << "ERROR: Destination received no input!\n"; @@ -34,8 +37,9 @@ reactor Destination(expected:int(0)) { } main reactor MultiportToPort { - a = new Source(); - b1 = new Destination(); - b2 = new Destination(expected = 1); - a.out -> b1.in, b2.in; + a = new Source() + b1 = new Destination() + b2 = new Destination(expected = 1) + + a.out -> b1.in, b2.in } diff --git a/test/Cpp/src/multiport/PipelineAfter.lf b/test/Cpp/src/multiport/PipelineAfter.lf index b504a0a6e7..e2dcea50db 100644 --- a/test/Cpp/src/multiport/PipelineAfter.lf +++ b/test/Cpp/src/multiport/PipelineAfter.lf @@ -1,26 +1,23 @@ -target Cpp; +target Cpp reactor Source { - output out:unsigned; + output out: unsigned - reaction (startup) -> out {= - out.set(40); - =} + reaction(startup) -> out {= out.set(40); =} } reactor Compute { - input in:unsigned; - output out:unsigned; + input in: unsigned - reaction (in) -> out {= - out.set(*in.get() + 2); - =} + output out: unsigned + + reaction(in) -> out {= out.set(*in.get() + 2); =} } reactor Sink { - input in:unsigned; + input in: unsigned - reaction (in) {= + reaction(in) {= std::cout << "Received " << *in.get() << '\n'; if (*in.get() != 42) { std::cerr << "Error: expected 42!\n"; @@ -31,13 +28,12 @@ reactor Sink { exit(2); } =} - } main reactor { - source = new Source(); - compute = new Compute(); - sink = new Sink(); + source = new Source() + compute = new Compute() + sink = new Sink() - source.out, compute.out -> compute.in, sink.in after 500 msec; + source.out, compute.out -> compute.in, sink.in after 500 msec } diff --git a/test/Cpp/src/multiport/ReadMultiportOutputOfContainedBank.lf b/test/Cpp/src/multiport/ReadMultiportOutputOfContainedBank.lf index 52aa04df9e..1ee37ef00e 100644 --- a/test/Cpp/src/multiport/ReadMultiportOutputOfContainedBank.lf +++ b/test/Cpp/src/multiport/ReadMultiportOutputOfContainedBank.lf @@ -1,8 +1,10 @@ -// Test reacting to and reading outputs from a contained -// reactor bank with a multiport -target Cpp; -reactor Contained(bank_index:size_t(0)) { - output[3] out:unsigned; +// Test reacting to and reading outputs from a contained reactor bank with a +// multiport +target Cpp + +reactor Contained(bank_index: size_t(0)) { + output[3] out: unsigned + reaction(startup) -> out {= for (size_t i = 0; i < 3; i++) { out[i].set(bank_index * i); @@ -11,8 +13,10 @@ reactor Contained(bank_index:size_t(0)) { } main reactor { - c = new[3] Contained(); - state count:int(0); + c = new[3] Contained() + + state count: int(0) + reaction(startup) c.out {= for (size_t i = 0; i < c.size(); i++) { for (size_t j = 0; j < c[i].out.size(); j++) { @@ -27,6 +31,7 @@ main reactor { } count++; =} + reaction(c.out) {= for (size_t i = 0; i < c.size(); i++) { for (size_t j = 0; j < c[i].out.size(); j++) { @@ -40,6 +45,7 @@ main reactor { } count++; =} + reaction(startup, c.out) {= for (size_t i = 0; i < c.size(); i++) { for (size_t j = 0; j < c[i].out.size(); j++) { @@ -54,6 +60,7 @@ main reactor { } count++; =} + reaction(shutdown) {= if (count != 3) { std::cerr << "ERROR: One of the reactions failed to trigger." diff --git a/test/Cpp/src/multiport/ReadOutputOfContainedBank.lf b/test/Cpp/src/multiport/ReadOutputOfContainedBank.lf index 8b08b4ca06..d4185bde9b 100644 --- a/test/Cpp/src/multiport/ReadOutputOfContainedBank.lf +++ b/test/Cpp/src/multiport/ReadOutputOfContainedBank.lf @@ -1,16 +1,18 @@ -// Test reacting to and reading outputs from a contained -// reactor bank in various permutations. -target Cpp; -reactor Contained(bank_index:size_t(0)) { - output out:unsigned; - reaction(startup) -> out {= - out.set(42 * bank_index); - =} +// Test reacting to and reading outputs from a contained reactor bank in various +// permutations. +target Cpp + +reactor Contained(bank_index: size_t(0)) { + output out: unsigned + + reaction(startup) -> out {= out.set(42 * bank_index); =} } main reactor { - c = new[4] Contained(); - state count:int(0); + c = new[4] Contained() + + state count: int(0) + reaction(startup) c.out {= for (size_t i = 0; i < c.size(); i++) { unsigned result = *c[i].out.get(); @@ -23,6 +25,7 @@ main reactor { } count++; =} + reaction(c.out) {= for (size_t i = 0; i < c.size(); i++) { unsigned result = *c[i].out.get(); @@ -35,6 +38,7 @@ main reactor { } count++; =} + reaction(startup, c.out) {= for (size_t i = 0; i < c.size(); i++) { unsigned result = *c[i].out.get(); @@ -47,6 +51,7 @@ main reactor { } count++; =} + reaction(shutdown) {= if (count != 3) { std::cerr << "ERROR: One of the reactions failed to trigger." diff --git a/test/Cpp/src/multiport/WidthGivenByCode.lf b/test/Cpp/src/multiport/WidthGivenByCode.lf index 34cd5d5bb7..bcf244806d 100644 --- a/test/Cpp/src/multiport/WidthGivenByCode.lf +++ b/test/Cpp/src/multiport/WidthGivenByCode.lf @@ -1,10 +1,11 @@ target Cpp reactor Foo(a: size_t{8}, b: size_t{2}) { - input[{=a*b=}] in: size_t; - output[{=a/b=}] out: size_t; + input[{= a*b =}] in: size_t - reaction (startup) in -> out {= + output[{= a/b =}] out: size_t + + reaction(startup) in -> out {= if (in.size() != a*b) { std::cerr << "ERROR: expected in to have a width of " << a*b << '\n'; exit(1); @@ -17,12 +18,12 @@ reactor Foo(a: size_t{8}, b: size_t{2}) { } main reactor { - foo1 = new Foo(); - foo2 = new Foo(a=10, b=3); - foo3 = new Foo(a=9, b=9); - foo_bank = new[{=42=}] Foo(); + foo1 = new Foo() + foo2 = new Foo(a = 10, b = 3) + foo3 = new Foo(a = 9, b = 9) + foo_bank = new[{= 42 =}] Foo() - reaction (startup) foo_bank.out {= + reaction(startup) foo_bank.out {= if (foo_bank.size() != 42) { std::cerr << "ERROR: expected foo_bank to have a width of " << 42 << '\n'; exit(3); diff --git a/test/Cpp/src/multiport/WriteInputOfContainedBank.lf b/test/Cpp/src/multiport/WriteInputOfContainedBank.lf index 4d2c95b093..7eceeb726d 100644 --- a/test/Cpp/src/multiport/WriteInputOfContainedBank.lf +++ b/test/Cpp/src/multiport/WriteInputOfContainedBank.lf @@ -1,9 +1,12 @@ // Test writing inputs to a contained reactor bank -target Cpp; -reactor Contained(bank_index:size_t(0)) { - input in:unsigned; - state count:int(0); - reaction(in) {= +target Cpp + +reactor Contained(bank_index: size_t(0)) { + input in: unsigned + + state count: int(0) + + reaction(in) {= unsigned result = *in.get(); std::cout << "Instance " << bank_index << " received " << result << '\n'; if (result != bank_index * 42) { @@ -12,6 +15,7 @@ reactor Contained(bank_index:size_t(0)) { } count++; =} + reaction(shutdown) {= if (count != 1) { std::cerr << "ERROR: One of the reactions failed to trigger.\n"; @@ -21,7 +25,8 @@ reactor Contained(bank_index:size_t(0)) { } main reactor { - c = new[4] Contained(); + c = new[4] Contained() + reaction(startup) -> c.in {= for (size_t i = 0; i < c.size(); i++) { c[i].in.set(i*42); diff --git a/test/Cpp/src/multiport/WriteMultiportInputOfContainedBank.lf b/test/Cpp/src/multiport/WriteMultiportInputOfContainedBank.lf index 6ea717db95..5d5b554de2 100644 --- a/test/Cpp/src/multiport/WriteMultiportInputOfContainedBank.lf +++ b/test/Cpp/src/multiport/WriteMultiportInputOfContainedBank.lf @@ -1,9 +1,12 @@ // Test writing multiport inputs to a contained reactor bank -target Cpp; -reactor Contained(bank_index:size_t(0)) { - input[4] in:unsigned; - state count:int(0); - reaction(in) {= +target Cpp + +reactor Contained(bank_index: size_t(0)) { + input[4] in: unsigned + + state count: int(0) + + reaction(in) {= for (size_t i = 0; i < 3; i++) { unsigned result = *in[i].get(); std::cout << "Instance " << bank_index << " received " << result << '\n'; @@ -14,6 +17,7 @@ reactor Contained(bank_index:size_t(0)) { } count++; =} + reaction(shutdown) {= if (count != 1) { std::cerr << "ERROR: One of the reactions failed to trigger.\n"; @@ -23,7 +27,8 @@ reactor Contained(bank_index:size_t(0)) { } main reactor { - c = new[4] Contained(); + c = new[4] Contained() + reaction(startup) -> c.in {= for (size_t i = 0; i < c.size(); i++) { for (size_t j = 0; j < c[i].in.size(); j++) { diff --git a/test/Cpp/src/properties/Fast.lf b/test/Cpp/src/properties/Fast.lf index f30b6fb311..1bb48258bf 100644 --- a/test/Cpp/src/properties/Fast.lf +++ b/test/Cpp/src/properties/Fast.lf @@ -1,15 +1,11 @@ -target Cpp { - fast: true -}; +target Cpp { fast: true } main reactor { - logical action a; + logical action a - state triggered: bool{false}; + state triggered: bool{false} - reaction(startup) -> a {= - a.schedule(2s); - =} + reaction(startup) -> a {= a.schedule(2s); =} reaction(a) {= triggered = true; diff --git a/test/Cpp/src/properties/Keepalive.lf b/test/Cpp/src/properties/Keepalive.lf index e5318980c4..4cb3a65d8a 100644 --- a/test/Cpp/src/properties/Keepalive.lf +++ b/test/Cpp/src/properties/Keepalive.lf @@ -1,17 +1,17 @@ target Cpp { keepalive: true, cmake-include: "../concurrent/AsyncCallback.cmake" -}; +} main reactor { public preamble {= #include =} - state thread: std::thread; + physical action a - physical action a; - state success: bool{false}; + state thread: std::thread + state success: bool{false} reaction(startup) -> a {= // start new thread diff --git a/test/Cpp/src/properties/Timeout.lf b/test/Cpp/src/properties/Timeout.lf index d9bba44af3..e764a1157a 100644 --- a/test/Cpp/src/properties/Timeout.lf +++ b/test/Cpp/src/properties/Timeout.lf @@ -1,11 +1,9 @@ -target Cpp { - timeout: 1 sec -}; +target Cpp { timeout: 1 sec } main reactor { - timer t(1 sec, 1 sec); + timer t(1 sec, 1 sec) - state triggered: bool{false}; + state triggered: bool{false} reaction(t) {= triggered = true; diff --git a/test/Cpp/src/target/AfterVoid.lf b/test/Cpp/src/target/AfterVoid.lf index 53a24080aa..538c5472f0 100644 --- a/test/Cpp/src/target/AfterVoid.lf +++ b/test/Cpp/src/target/AfterVoid.lf @@ -1,21 +1,20 @@ // This checks that the after keyword also works with void ports -target Cpp { - fast: false, - timeout: 3 sec -}; +target Cpp { fast: false, timeout: 3 sec } reactor foo { - timer t(0, 1 sec); - output y:void; - reaction(t) -> y {= - y.set(); - =} + output y: void + + timer t(0, 1 sec) + + reaction(t) -> y {= y.set(); =} } reactor print { - state expected_time:time(10 msec); - state i:int(0); - input x:void; + input x: void + + state expected_time: time(10 msec) + state i: int(0) + reaction(x) {= i++; auto elapsed_time = get_elapsed_logical_time(); @@ -27,6 +26,7 @@ reactor print { } expected_time += 1s; =} + reaction(shutdown) {= if (i == 0) { std::cerr << "ERROR: Final reactor received no data.\n"; @@ -34,9 +34,10 @@ reactor print { } =} } + main reactor { - f = new foo(); - p = new print(); + f = new foo() + p = new print() - f.y -> p.x after 10 msec; + f.y -> p.x after 10 msec } diff --git a/test/Cpp/src/target/BraceAndParenInitialization.lf b/test/Cpp/src/target/BraceAndParenInitialization.lf index 46df6e86ee..3e2688dfac 100644 --- a/test/Cpp/src/target/BraceAndParenInitialization.lf +++ b/test/Cpp/src/target/BraceAndParenInitialization.lf @@ -1,16 +1,18 @@ -target Cpp; +target Cpp reactor Foo( - param_list_1: std::vector(4, 2), // list containing [2,2,2,2] - param_list_2: std::vector{4, 2}, // list containing [4,2] - param_list_3: std::vector(4, 2), // list containing [2,2,2,2] + param_list_1: std::vector(4, 2), // list containing [2,2,2,2] + param_list_2: std::vector{4, 2}, // list containing [4,2] + param_list_3: std::vector(4, 2), // list containing [2,2,2,2] param_list_4: std::vector{4, 2} // list containing [4,2] ) { - state state_list_1: std::vector(6,42); // list containing [42,42,42,42,42,42] - state state_list_2: std::vector{6,42}; // list containing [6,42] + // list containing [42,42,42,42,42,42] + state state_list_1: std::vector(6, 42) + // list containing [6,42] + state state_list_2: std::vector{6, 42} reaction(startup) {= - std::cerr << "Hello!\n"; + std::cerr << "Hello!\n"; if (param_list_1.size() != 4 || param_list_1[0] != 2 || param_list_2.size() != 2 || param_list_2[0] != 4 || param_list_3.size() != 3 || param_list_3[0] != 5 || @@ -24,5 +26,5 @@ reactor Foo( } main reactor { - foo = new Foo(param_list_3(3,5), param_list_4{3,5}); + foo = new Foo(param_list_3(3, 5), param_list_4{3, 5}) } diff --git a/test/Cpp/src/target/CMakeInclude.lf b/test/Cpp/src/target/CMakeInclude.lf index 6f230ee50f..a6e883a2d9 100644 --- a/test/Cpp/src/target/CMakeInclude.lf +++ b/test/Cpp/src/target/CMakeInclude.lf @@ -1,18 +1,21 @@ /** - * Test that cmake-include is working correctly. - * The failure for this test is failure to compile. + * Test that cmake-include is working correctly. The failure for this test is + * failure to compile. */ target Cpp { - cmake-include: ["../include/mlib-cmake-extension.cmake", "../include/bar-cmake-compile-definition.txt"], + cmake-include: [ + "../include/mlib-cmake-extension.cmake", + "../include/bar-cmake-compile-definition.txt" + ], timeout: 0 sec -}; - +} main reactor { private preamble {= #include =} - reaction (startup) {= + + reaction(startup) {= std::cout << "Maximum of 4.20 and " << BAR << " is " << fmax(4.20, BAR) << std::endl; =} } diff --git a/test/Cpp/src/target/CliParserGenericArguments.lf b/test/Cpp/src/target/CliParserGenericArguments.lf index 0a7aa5ca93..eb75ac2ef6 100644 --- a/test/Cpp/src/target/CliParserGenericArguments.lf +++ b/test/Cpp/src/target/CliParserGenericArguments.lf @@ -1,66 +1,62 @@ /** -* This tests a wide range of possible Arguments for the command line parser -* -* @author Maiko Brants -**/ -target Cpp; - - public preamble {= - using unsigned_long = unsigned long; - using long_long = long long; - using uns_long_long = unsigned long long; - using long_double = long double; - - #include - #include - using namespace std; - class CustomClass { - public: - std::string name; - CustomClass(std::string new_name="John") : name{new_name} - {} - std::string get_name() const {return this->name;} - void set_name(std::string updated_name){this->name = updated_name;} - }; - - ostream& operator<<(ostream& os, const CustomClass& cc); - - stringstream& operator>>(stringstream& in, CustomClass& cc); - =} - - private preamble {= - - stringstream& operator>>(stringstream& in, CustomClass& cc) - { - cc.set_name(in.str()); - return in; - } - - ostream& operator<<(ostream& os, const CustomClass& cc) - { - os << cc.get_name(); - return os; - } - =} - + * This tests a wide range of possible Arguments for the command line parser + * + * @author Maiko Brants + */ +target Cpp + +public preamble {= + using unsigned_long = unsigned long; + using long_long = long long; + using uns_long_long = unsigned long long; + using long_double = long double; + + #include + #include + using namespace std; + class CustomClass { + public: + std::string name; + CustomClass(std::string new_name="John") : name{new_name} + {} + std::string get_name() const {return this->name;} + void set_name(std::string updated_name){this->name = updated_name;} + }; + + ostream& operator<<(ostream& os, const CustomClass& cc); + + stringstream& operator>>(stringstream& in, CustomClass& cc); +=} + +private preamble {= + stringstream& operator>>(stringstream& in, CustomClass& cc) + { + cc.set_name(in.str()); + return in; + } + + ostream& operator<<(ostream& os, const CustomClass& cc) + { + os << cc.get_name(); + return os; + } +=} main reactor CliParserGenericArguments( - int_value:int(10), - signed_value:signed(-10), - unsigned_value:unsigned(11), - long_value:long(-100), - unsigned_long_value:{=unsigned_long=}(42), - long_long_value:{=long_long=}(-42), - ull_value:{=uns_long_long=}(42), - bool_value:bool(false), - char_value:char('T'), - double_value:double(4.2), - long_double_value:{=long_double=}(4.2), - float_value:float(10.5), - string_value:string("This is a testvalue"), - custom_class_value:{=CustomClass=}("Peter") -){ - reaction(startup) {= - std::cout << "Hello World!\n"; - =} + int_value: int(10), + signed_value: signed(-10), + unsigned_value: unsigned(11), + long_value: long(-100), + unsigned_long_value: {= unsigned_long =}(42), + long_long_value: {= long_long =}(-42), + ull_value: {= uns_long_long =}(42), + bool_value: bool(false), + char_value: char('T'), + double_value: double(4.2), + long_double_value: {= long_double =}(4.2), + float_value: float(10.5), + string_value: string("This is a testvalue"), + custom_class_value: {= CustomClass =}("Peter") +) { + reaction(startup) {= std::cout << "Hello World!\n"; =} } diff --git a/test/Cpp/src/target/GenericDelay.lf b/test/Cpp/src/target/GenericDelay.lf index 1b3d3484f1..9dbba85166 100644 --- a/test/Cpp/src/target/GenericDelay.lf +++ b/test/Cpp/src/target/GenericDelay.lf @@ -1,26 +1,24 @@ -target Cpp; +target Cpp -import Test from "../DelayInt.lf"; +import Test from "../DelayInt.lf" -reactor Delay(delay:time(0)) { - output out:T; - input in:T; - logical action a(delay):T; +reactor Delay(delay: time(0)) { + input in: T - reaction (a) -> out {= - out.set(a.get()); - =} + output out: T - reaction (in) -> a {= - a.schedule(in.get()); - =} + logical action a(delay): T + + reaction(a) -> out {= out.set(a.get()); =} + + reaction(in) -> a {= a.schedule(in.get()); =} } main reactor { - d = new Delay(delay=100 msec); - test = new Test(); - d.out -> test.in; - reaction(startup) -> d.in {= - d.in.set(42); - =} + d = new Delay(delay = 100 msec) + test = new Test() + + d.out -> test.in + + reaction(startup) -> d.in {= d.in.set(42); =} } diff --git a/test/Cpp/src/target/GenericParameterAndState.lf b/test/Cpp/src/target/GenericParameterAndState.lf index 84396782e4..6b3e6a28a5 100644 --- a/test/Cpp/src/target/GenericParameterAndState.lf +++ b/test/Cpp/src/target/GenericParameterAndState.lf @@ -1,20 +1,20 @@ -target Cpp; +target Cpp -reactor Foo (bar:T(0)) { - state baz:T(bar) +reactor Foo(bar: T(0)) { + state baz: T(bar) - reaction (startup) {= - if (bar != 42) { - std::cerr << "ERROR: Expected baz=42 but got baz=" << bar << '\n'; - exit(1); - } - if (baz != 42) { - std::cerr << "ERROR: Expected baz=42 but got baz=" << baz << '\n'; - exit(1); - } - =} + reaction(startup) {= + if (bar != 42) { + std::cerr << "ERROR: Expected baz=42 but got baz=" << bar << '\n'; + exit(1); + } + if (baz != 42) { + std::cerr << "ERROR: Expected baz=42 but got baz=" << baz << '\n'; + exit(1); + } + =} } main reactor { - foo = new Foo(bar=42) + foo = new Foo(bar = 42) } diff --git a/test/Cpp/src/target/Methods.lf b/test/Cpp/src/target/Methods.lf index 8d375fd7ad..0b5e47681d 100644 --- a/test/Cpp/src/target/Methods.lf +++ b/test/Cpp/src/target/Methods.lf @@ -1,18 +1,9 @@ -target Cpp; +target Cpp main reactor { + state foo: int(2) - state foo:int(2); - - const method getFoo(): int {= - return foo; - =} - - method add(x:int) {= - foo += x; - =} - - reaction(startup){= + reaction(startup) {= std::cout << "Foo is initialized to " << getFoo() << '\n'; if (getFoo() != 2) { std::cerr << "Error: expected 2!\n"; @@ -26,4 +17,9 @@ main reactor { exit(2); } =} + + + const method getFoo(): int {= return foo; =} + + method add(x: int) {= foo += x; =} } diff --git a/test/Cpp/src/target/PreambleFile.lf b/test/Cpp/src/target/PreambleFile.lf index 31a87e2900..6c058d3f44 100644 --- a/test/Cpp/src/target/PreambleFile.lf +++ b/test/Cpp/src/target/PreambleFile.lf @@ -1,7 +1,7 @@ -target Cpp; +target Cpp -// These declarations are used by multiple reactors within this file -// and should be placed in a header. This goes to PreampleFile/preamble.hh. +// These declarations are used by multiple reactors within this file and should +// be placed in a header. This goes to PreambleFile/preamble.hh. public preamble {= struct MyStruct { int foo; @@ -11,9 +11,9 @@ public preamble {= int add_42(int i); =} -// This definition is used by multiple reactors within this file. Since -// the same function can only be defined once, this needs to go to a -// source file. This goes to PreampleFile/preamble.cc. +// This definition is used by multiple reactors within this file. Since the same +// function can only be defined once, this needs to go to a source file. This +// goes to PreambleFile/preamble.cc. private preamble {= int add_42(int i) { return i + 42; @@ -21,7 +21,8 @@ private preamble {= =} reactor Source { - output x:MyStruct; + output x: MyStruct + reaction(startup) -> x {= int a = add_42(0); x.set({a, "baz"}); @@ -30,13 +31,16 @@ reactor Source { reactor Print { // This helper function is only used within the Print reactor and is - // therefore part of its private interface. This goes to PreambleFile/Print.cc + // therefore part of its private interface. This goes to + // PreambleFile/Print.cc private preamble {= void print(const MyStruct& x) { std::cout << "Received " << x.foo << " and '" << x.bar << "'\n"; } =} - input x:MyStruct; + + input x: MyStruct + reaction(x) {= MyStruct value = *x.get(); // implicit copy value.foo = add_42(value.foo); @@ -45,7 +49,8 @@ reactor Print { } main reactor PreambleFile { - s = new Source(); - p = new Print(); - s.x -> p.x; + s = new Source() + p = new Print() + + s.x -> p.x } From 03d1059f511a149aeb0721399b7f376047db85ec Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 7 Jul 2022 21:35:02 -0700 Subject: [PATCH 087/130] [formatting] Small patches. Detect multiline comments differently; fix duplicate comment inclusion. --- org.lflang/src/org/lflang/ASTUtils.java | 18 ++++++-- .../src/org/lflang/ast/FormattingUtils.java | 43 +++++++++++++------ .../src/org/lflang/ast/MalleableString.java | 11 ++--- org.lflang/src/org/lflang/ast/ToLf.java | 26 +++++------ org.lflang/src/org/lflang/ast/ToText.java | 4 +- 5 files changed, 64 insertions(+), 38 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index e79555f476..588afa17b3 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -1696,6 +1696,18 @@ public static Stream getPrecedingComments( ICompositeNode compNode, Predicate filter ) { + return getPrecedingCommentNodes(compNode, filter).map(INode::getText); + } + + /** + * Return all single-line or multi-line comments immediately preceding the + * given EObject. + */ + public static Stream getPrecedingCommentNodes( + ICompositeNode compNode, + Predicate filter + ) { + if (compNode == null) return Stream.of(); List ret = new ArrayList<>(); for (INode node : compNode.getAsTreeIterable()) { if (!(node instanceof ICompositeNode)) { @@ -1706,7 +1718,7 @@ public static Stream getPrecedingComments( } } } - return ret.stream().map(INode::getText); + return ret.stream(); } /** Return whether {@code node} is a comment. */ @@ -1723,8 +1735,8 @@ public static boolean isComment(INode node) { public static Predicate sameLine(ICompositeNode compNode) { return other -> { for (INode node : compNode.getAsTreeIterable()) { - if (!(node instanceof ICompositeNode) && !node.getText().isBlank()) { - return !isComment(node) && node.getStartLine() == other.getStartLine(); + if (!(node instanceof ICompositeNode) && !node.getText().isBlank() && !isComment(node)) { + return node.getStartLine() == other.getStartLine(); } } return false; diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index b4ab0d23eb..d9bb6fcf25 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -22,9 +22,9 @@ public class FormattingUtils { */ private static final int MINIMUM_COMMENT_WIDTH_IN_COLUMNS = 15; - /** Match a multiline comment with lines starting with stars. */ - private static final Pattern MULTILINE_COMMENT_LINES_STARTING_WITH_STARS = Pattern.compile( - "\\s*/(\\s*\\*(\\S*\\h*)*)+" + /** Match a multiline comment. */ + private static final Pattern MULTILINE_COMMENT = Pattern.compile( + "\\s*/\\*\\v?(\\V*\\v+)+\\V*" ); // TODO: Ideally, ToLf would not need to access the value of INDENTATION. @@ -54,10 +54,9 @@ public static String render(EObject object, int lineLength) { lineLength ); var optimizedRendering = ms.render(); - String comments = optimizedRendering.unplacedComments() - .collect(Collectors.joining(System.lineSeparator())); - return comments.isBlank() ? optimizedRendering.rendering() - : lineWrapComment(comments, lineLength) + System.lineSeparator() + optimizedRendering.rendering(); + List comments = optimizedRendering.unplacedComments().toList(); + return comments.stream().allMatch(String::isBlank) ? optimizedRendering.rendering() + : lineWrapComments(comments, lineLength) + "\n" + optimizedRendering.rendering(); } /** @@ -78,19 +77,35 @@ private static long countNewlines(String s) { * Break lines at spaces so that each line is no more than {@code width} * columns long, if possible. Normalize whitespace. */ + static String lineWrapComments(List comments, int width) { + StringBuilder ret = new StringBuilder(); + StringBuilder current = new StringBuilder(); + for (String comment : comments) { + if (comment.stripLeading().startsWith("/*")) { + ret.append(lineWrapComment(current.toString(), width)); + current.setLength(0); + ret.append(lineWrapComment(comment, width)).append("\n"); + } else { + current.append(comment).append("\n"); + } + } + if (!current.isEmpty()) ret.append(lineWrapComment(current.toString(), width)); + else if (!ret.isEmpty()) ret.deleteCharAt(ret.length() - 1); // Delete final newline + return ret.toString(); + } static String lineWrapComment(String comment, int width) { width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); List> paragraphs = Arrays.stream( comment.strip() - .replaceAll("^/?((\\*|//)\\s*)+", "") + .replaceAll("^/?((\\*|//|#)\\s*)+", "") .replaceAll("\\s*\\*/$", "") - .replaceAll("(?<=" + System.lineSeparator() + ")\\h*(\\*|//)\\h*", "") + .replaceAll("(?<=" + System.lineSeparator() + ")\\h*(\\*|//|#)\\h*", "") .split(String.format("(%n\\s*){2,}")) ).map(s -> Arrays.stream(s.split("((\r\n?)|\n)\\s*(?=[@#$%^&*\\-+=:;<>/])"))) .map(stream -> stream.map(s -> s.replaceAll("\\s+", " "))) .map(Stream::toList) .toList(); - if (MULTILINE_COMMENT_LINES_STARTING_WITH_STARS.matcher(comment).matches()) { + if (MULTILINE_COMMENT.matcher(comment).matches()) { if ( comment.length() < width && paragraphs.size() == 1 && paragraphs.get(0).size() == 1 ) { @@ -98,7 +113,7 @@ static String lineWrapComment(String comment, int width) { } return String.format("/**%n%s%n */", lineWrapComment(paragraphs, width, " * ")); } - return lineWrapComment(paragraphs, width, "// "); + return lineWrapComment(paragraphs, width, "// "); // TODO: Change to # for Python } static String lineWrapComment( @@ -151,14 +166,14 @@ static Stream wrapLines(List subparagraphs, int width) { * keep the comment on the same line as the associated string. */ static boolean placeComment( - String comment, + List comment, List components, int i, int width, boolean keepCommentsOnSameLine ) { - String wrapped = FormattingUtils.lineWrapComment(comment, width); - if (comment.isBlank()) return true; + if (comment.stream().allMatch(String::isBlank)) return true; + String wrapped = FormattingUtils.lineWrapComments(comment, width); if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { for (int j = i; j < components.size(); j++) { if (components.get(j).contains(System.lineSeparator())) { diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index f4228785e6..dd210853e5 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -13,7 +13,6 @@ import java.util.function.Supplier; import java.util.function.ToLongFunction; import java.util.stream.Collector; -import java.util.stream.Collectors; import java.util.stream.Stream; import com.google.common.collect.ImmutableList; @@ -37,10 +36,6 @@ public abstract void findBestRepresentation( public abstract boolean isEmpty(); - public MalleableString addComments(Collection comments) { - return addComments(comments.stream()); - } - public MalleableString addComments(Stream comments) { comments.filter(s -> !s.isBlank()).map(String::strip).forEach(this.comments::add); return this; @@ -217,7 +212,7 @@ public RenderResult render() { ) { for (int i = 0; i < commentsFromChildren.size(); i++) { if (!FormattingUtils.placeComment( - String.join(System.lineSeparator(), commentsFromChildren.get(i)), + commentsFromChildren.get(i), stringComponents, i, width, @@ -307,8 +302,8 @@ public boolean isEmpty() { @Override public RenderResult render() { var result = nested.render(); - String renderedComments = FormattingUtils.lineWrapComment( - result.unplacedComments.collect(Collectors.joining(System.lineSeparator())), + String renderedComments = FormattingUtils.lineWrapComments( + result.unplacedComments.toList(), width - indentation ); return new RenderResult( diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index e263d09354..cfc6a748a3 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -99,7 +99,7 @@ public MalleableString doSwitch(EObject eObject) { node, ASTUtils.sameLine(node).and(doesNotBelongToAncestor) ); - var previous = getNextCompositeSibling(node, INode::getPreviousSibling, true); + var previous = getNextCompositeSibling(node, INode::getPreviousSibling); Predicate doesNotBelongToPrevious = doesNotBelongToAncestor.and( previous == null ? n -> true : ASTUtils.sameLine(previous).negate() ); @@ -119,17 +119,21 @@ public MalleableString doSwitch(EObject eObject) { private static Set getAncestorComments(INode node) { Set ancestorComments = new HashSet<>(); - var ancestor = node; - while ((ancestor = ancestor.getParent()) != null) { + for ( + ICompositeNode ancestor = node.getParent(); + ancestor != null; + ancestor = ancestor.getParent() + ) { ancestorComments.addAll(getContainedComments(ancestor)); + ASTUtils.getPrecedingCommentNodes(ancestor, u -> true) + .forEachOrdered(ancestorComments::add); } return ancestorComments; } static ICompositeNode getNextCompositeSibling( INode node, - Function getNextSibling, - boolean traverseUpwards + Function getNextSibling ) { INode sibling = node; while ((sibling = getNextSibling.apply(sibling)) != null) { @@ -138,8 +142,6 @@ static ICompositeNode getNextCompositeSibling( && !sibling.getText().isBlank() ) return compositeSibling; } - ICompositeNode parent = node.getParent(); - if (traverseUpwards) return parent; return null; } @@ -159,7 +161,7 @@ private static Stream getFollowingComments( ICompositeNode node, Predicate filter ) { - ICompositeNode sibling = getNextCompositeSibling(node, INode::getNextSibling, false); + ICompositeNode sibling = getNextCompositeSibling(node, INode::getNextSibling); Stream followingSiblingComments = getFollowingNonCompositeSiblings(node) .filter(ASTUtils::isComment).map(INode::getText); if (sibling == null) return followingSiblingComments; @@ -291,11 +293,11 @@ public MalleableString caseModel(Model object) { // (preambles+=Preamble)* // (reactors+=Reactor)+ Builder msb = new Builder(); - msb.append(caseTargetDecl(object.getTarget())).append(System.lineSeparator().repeat(2)); - object.getImports().forEach(i -> msb.append(caseImport(i)).append(System.lineSeparator())); + msb.append(doSwitch(object.getTarget())).append(System.lineSeparator().repeat(2)); + object.getImports().forEach(i -> msb.append(doSwitch(i)).append(System.lineSeparator())); if (!object.getImports().isEmpty()) msb.append(System.lineSeparator()); object.getPreambles().forEach( - p -> msb.append(casePreamble(p)).append(System.lineSeparator().repeat(2)) + p -> msb.append(doSwitch(p)).append(System.lineSeparator().repeat(2)) ); msb.append( object.getReactors().stream().map(this::doSwitch) @@ -604,7 +606,7 @@ public MalleableString caseDeadline(Deadline object) { .append("deadline") .append(list(false, object.getDelay())) .append(" ") - .append(caseCode(object.getCode())) + .append(doSwitch(object.getCode())) .get(); } diff --git a/org.lflang/src/org/lflang/ast/ToText.java b/org.lflang/src/org/lflang/ast/ToText.java index bd76b375bb..06636bc4fe 100644 --- a/org.lflang/src/org/lflang/ast/ToText.java +++ b/org.lflang/src/org/lflang/ast/ToText.java @@ -81,7 +81,9 @@ public String caseCode(Code code) { } public static Stream precedingCommentsThatDoNotBelong(ICompositeNode node) { - var previous = ToLf.getNextCompositeSibling(node, INode::getPreviousSibling, true); + // FIXME: This is brittle. It only works for certain cases. + var previous = ToLf.getNextCompositeSibling(node, INode::getPreviousSibling); + if (previous == null) previous = node.getParent(); if (previous == null) return Stream.of(); return ASTUtils.getPrecedingComments(node, ASTUtils.sameLine(previous)).map(String::strip); } From 1d8c2f4893d7c83822cda407492c1ec3a686f793 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 7 Jul 2022 23:43:20 -0700 Subject: [PATCH 088/130] [formatting] Adjust StringUtil::trimCodeBlock. This prevents code immediately following the opening {= from breaking Python code (by ruining the whitespace). An example of such code would be a single-line comment. --- .../src/org/lflang/util/StringUtil.java | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/org.lflang/src/org/lflang/util/StringUtil.java b/org.lflang/src/org/lflang/util/StringUtil.java index 9ca560ce9c..afac108808 100644 --- a/org.lflang/src/org/lflang/util/StringUtil.java +++ b/org.lflang/src/org/lflang/util/StringUtil.java @@ -103,43 +103,40 @@ public static String removeQuotes(String str) { * } * } * - * In addition, if the very first line has whitespace only, then - * that line is removed. This just means that the {= delimiter - * is followed by a newline. + * The very first line of the given code is treated specially. Typically, it + * should be blank, but it contains code if code is placed on the same line + * as the opening {= symbol. That line is not used to determine the + * whitespace prefix. * * @param code the code block to be trimmed * @return trimmed code block */ public static String trimCodeBlock(String code) { String[] codeLines = code.split("(\r\n?)|\n"); - String prefix = null; + String prefix = getWhitespacePrefix(code); StringBuilder buffer = new StringBuilder(); + boolean stillProcessingLeadingBlankLines = true; for (String line : codeLines) { - if (prefix == null && line.trim().length() > 0) { - // this is the first code line - // find the index of the first code line - int firstCharacter = 0; - for (var i = 0; i < line.length(); i++) { - if (!Character.isWhitespace(line.charAt(i))) { - firstCharacter = i; - break; - } - } - // extract the whitespace prefix - prefix = line.substring(0, firstCharacter); - } + if (!line.isBlank()) stillProcessingLeadingBlankLines = false; + if (stillProcessingLeadingBlankLines) continue; + if (line.startsWith(prefix)) buffer.append(line.substring(prefix.length())); + else buffer.append(line); + buffer.append("\n"); + } + return buffer.toString().strip(); + } - // try to remove the prefix from all subsequent lines - if (prefix != null) { - if (line.startsWith(prefix)) { - buffer.append(line.substring(prefix.length())); - } else { - buffer.append(line); + private static String getWhitespacePrefix(String code) { + String[] codeLines = code.split("(\r\n?)|\n"); + for (int j = 1; j < codeLines.length; j++) { + String line = codeLines[j]; + for (var i = 0; i < line.length(); i++) { + if (!Character.isWhitespace(line.charAt(i))) { + return line.substring(0, i); } - buffer.append(System.lineSeparator()); } } - return buffer.toString().stripTrailing(); + return ""; } public static String addDoubleQuotes(String str) { From cbd65652004910970a832e832b18fad0964a7968 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Thu, 7 Jul 2022 23:46:18 -0700 Subject: [PATCH 089/130] [formatting] Parameterize render method. This lets indentation and single-line comment prefix to be specified at the last moment. --- .../src/org/lflang/ast/FormattingUtils.java | 55 ++++++++---- .../src/org/lflang/ast/MalleableString.java | 89 +++++++++++-------- org.lflang/src/org/lflang/ast/ToLf.java | 22 ++--- 3 files changed, 103 insertions(+), 63 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index d9bb6fcf25..cffa844a82 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -10,6 +10,9 @@ import org.eclipse.emf.ecore.EObject; +import org.lflang.ASTUtils; +import org.lflang.lf.Model; + /** * Utility functions that determine the specific behavior of the LF formatter. * @author {Peter Donovan } @@ -27,9 +30,8 @@ public class FormattingUtils { "\\s*/\\*\\v?(\\V*\\v+)+\\V*" ); - // TODO: Ideally, ToLf would not need to access the value of INDENTATION. /** The number of spaces to prepend to a line per indentation level. */ - static final int INDENTATION = 4; + private static final int INDENTATION = 4; public static final int DEFAULT_LINE_LENGTH = 80; @@ -45,18 +47,32 @@ public class FormattingUtils { */ public static String render(EObject object, int lineLength) { MalleableString ms = ToLf.instance.doSwitch(object); + String singleLineCommentPrefix = getSingleLineCommentPrefix(object); ms.findBestRepresentation( - ms::render, + () -> ms.render(INDENTATION, singleLineCommentPrefix), r -> r.levelsOfCommentDisplacement() * BADNESS_PER_LEVEL_OF_COMMENT_DISPLACEMENT + countCharactersViolatingLineLength(lineLength).applyAsLong(r.rendering()) * BADNESS_PER_CHARACTER_VIOLATING_LINE_LENGTH + countNewlines(r.rendering()) * BADNESS_PER_NEWLINE, - lineLength + lineLength, + INDENTATION, + singleLineCommentPrefix ); - var optimizedRendering = ms.render(); + var optimizedRendering = ms.render(INDENTATION, singleLineCommentPrefix); List comments = optimizedRendering.unplacedComments().toList(); return comments.stream().allMatch(String::isBlank) ? optimizedRendering.rendering() - : lineWrapComments(comments, lineLength) + "\n" + optimizedRendering.rendering(); + : lineWrapComments(comments, lineLength, singleLineCommentPrefix) + + "\n" + optimizedRendering.rendering(); + } + + private static String getSingleLineCommentPrefix(EObject object) { + if (object instanceof Model model) { + var targetDecl = ASTUtils.targetDecl(model); + if (targetDecl != null && targetDecl.getName().toUpperCase().contains("PYTHON")) { + return "#"; + } + } + return "//"; } /** @@ -77,23 +93,30 @@ private static long countNewlines(String s) { * Break lines at spaces so that each line is no more than {@code width} * columns long, if possible. Normalize whitespace. */ - static String lineWrapComments(List comments, int width) { + static String lineWrapComments( + List comments, + int width, + String singleLineCommentPrefix + ) { StringBuilder ret = new StringBuilder(); StringBuilder current = new StringBuilder(); for (String comment : comments) { if (comment.stripLeading().startsWith("/*")) { - ret.append(lineWrapComment(current.toString(), width)); + ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); current.setLength(0); - ret.append(lineWrapComment(comment, width)).append("\n"); + ret.append(lineWrapComment(comment, width, singleLineCommentPrefix)).append("\n"); } else { current.append(comment).append("\n"); } } - if (!current.isEmpty()) ret.append(lineWrapComment(current.toString(), width)); - else if (!ret.isEmpty()) ret.deleteCharAt(ret.length() - 1); // Delete final newline + if (!current.isEmpty()) { + ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); + } else if (!ret.isEmpty()) { + ret.deleteCharAt(ret.length() - 1); // Delete final newline + } return ret.toString(); } - static String lineWrapComment(String comment, int width) { + static String lineWrapComment(String comment, int width, String singleLineCommentPrefix) { width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); List> paragraphs = Arrays.stream( comment.strip() @@ -113,7 +136,7 @@ static String lineWrapComment(String comment, int width) { } return String.format("/**%n%s%n */", lineWrapComment(paragraphs, width, " * ")); } - return lineWrapComment(paragraphs, width, "// "); // TODO: Change to # for Python + return lineWrapComment(paragraphs, width, singleLineCommentPrefix + " "); } static String lineWrapComment( @@ -164,16 +187,18 @@ static Stream wrapLines(List subparagraphs, int width) { * appear on their own line. * @param keepCommentsOnSameLine Whether to make a best-effort attempt to * keep the comment on the same line as the associated string. + * */ static boolean placeComment( List comment, List components, int i, int width, - boolean keepCommentsOnSameLine + boolean keepCommentsOnSameLine, + String singleLineCommentPrefix ) { if (comment.stream().allMatch(String::isBlank)) return true; - String wrapped = FormattingUtils.lineWrapComments(comment, width); + String wrapped = FormattingUtils.lineWrapComments(comment, width, singleLineCommentPrefix); if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { for (int j = i; j < components.size(); j++) { if (components.get(j).contains(System.lineSeparator())) { diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index dd210853e5..bd880fd43e 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; @@ -21,17 +20,16 @@ public abstract class MalleableString { protected List comments = new ArrayList<>(); - public MalleableString indent(int indentation) { - if (indentation < 0) { - throw new IllegalArgumentException("Indentation must be nonnegative."); - } - return new Indented(this, indentation); + public MalleableString indent() { + return new Indented(this); } public abstract void findBestRepresentation( Supplier providedRender, ToLongFunction badness, - int width + int width, + int indentation, + String singleLineCommentPrefix ); public abstract boolean isEmpty(); @@ -41,7 +39,7 @@ public MalleableString addComments(Stream comments) { return this; } - public abstract RenderResult render(); + public abstract RenderResult render(int indentation, String singleLineCommentMarker); public static MalleableString anyOf(MalleableString... possibilities) { return new Fork(possibilities); @@ -196,9 +194,11 @@ private Sequence(ImmutableList components) { private int width = 0; @Override - public RenderResult render() { + public RenderResult render(int indentation, String singleLineCommentPrefix) { List componentRenderings = components.stream() - .map(MalleableString::render).toList(); + .map(malleableString -> + malleableString.render(indentation, singleLineCommentPrefix) + ).toList(); List> commentsFromChildren = componentRenderings.stream() .map(it -> it.unplacedComments).map(Stream::toList).toList(); List stringComponents = componentRenderings.stream() @@ -216,7 +216,8 @@ public RenderResult render() { stringComponents, i, width, - keepCommentsOnSameLine + keepCommentsOnSameLine, + singleLineCommentPrefix )) { commentsThatCouldNotBeHandledHere.addAll(commentsFromChildren.get(i)); if (i != 0) numCommentsDisplacedHere++; @@ -236,20 +237,30 @@ public RenderResult render() { public void findBestRepresentation( Supplier providedRender, ToLongFunction badness, - int width + int width, + int indentation, + String singleLineCommentPrefix ) { this.width = width; keepCommentsOnSameLine = true; - components.reverse() - .forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + components.reverse().forEach(it -> it.findBestRepresentation( + providedRender, + badness, + width, + indentation, + singleLineCommentPrefix + )); if ( - components.stream() - .noneMatch(it -> it.render().unplacedComments.findAny().isPresent()) + components.stream().noneMatch( + it -> it.render(indentation, singleLineCommentPrefix) + .unplacedComments.findAny().isPresent() + ) ) return; long badnessTrue = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = false; - components.reverse() - .forEach(it -> it.findBestRepresentation(providedRender, badness, width)); + components.reverse().forEach(it -> it.findBestRepresentation( + providedRender, badness, width, indentation, singleLineCommentPrefix + )); long badnessFalse = badness.applyAsLong(providedRender.get()); keepCommentsOnSameLine = badnessTrue < badnessFalse; } @@ -262,35 +273,33 @@ public boolean isEmpty() { private static final class Indented extends MalleableString { - /** - * The indentation given by this indent alone (i.e., not including - * ancestor indents). - */ - private final int indentation; private final MalleableString nested; private int width; - private Indented(MalleableString toIndent, int indentation) { - this.indentation = indentation; + private Indented(MalleableString toIndent) { this.nested = toIndent; } @Override - public MalleableString indent(int indentation) { - return new Indented(nested, this.indentation + indentation); + public MalleableString indent() { + return new Indented(this); } @Override public void findBestRepresentation( Supplier providedRender, ToLongFunction badness, - int width + int width, + int indentation, + String singleLineCommentPrefix ) { this.width = width; nested.findBestRepresentation( providedRender, badness, - width - this.indentation + width - indentation, + indentation, + singleLineCommentPrefix ); } @@ -300,11 +309,12 @@ public boolean isEmpty() { } @Override - public RenderResult render() { - var result = nested.render(); + public RenderResult render(int indentation, String singleLineCommentPrefix) { + var result = nested.render(indentation, singleLineCommentPrefix); String renderedComments = FormattingUtils.lineWrapComments( result.unplacedComments.toList(), - width - indentation + width - indentation, + singleLineCommentPrefix ); return new RenderResult( this.comments.stream(), @@ -334,8 +344,8 @@ public String toString() { public void findBestRepresentation( Supplier providedRender, ToLongFunction badness, - int width - ) { + int width, + int indentation, String singleLineCommentPrefix) { bestPossibility = Collections.min(getPossibilities(), (a, b) -> { bestPossibility = a; long badnessA = badness.applyAsLong(providedRender.get()); @@ -347,7 +357,9 @@ public void findBestRepresentation( ms.findBestRepresentation( providedRender, badness, - width + width, + indentation, + singleLineCommentPrefix ); } } @@ -378,8 +390,9 @@ public boolean isEmpty() { } @Override - public RenderResult render() { - return getChosenPossibility().render().with(comments.stream()); + public RenderResult render(int indentation, String singleLineCommentPrefix) { + return getChosenPossibility().render(indentation, singleLineCommentPrefix) + .with(comments.stream()); } } @@ -401,7 +414,7 @@ public boolean isEmpty() { } @Override - public RenderResult render() { + public RenderResult render(int indentation, String singleLineCommentPrefix) { return new RenderResult(comments.stream(), getChosenPossibility(), 0); } } diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index cfc6a748a3..e67d6d2614 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -199,14 +199,16 @@ public MalleableString caseCode(Code code) { String content = ToText.instance.doSwitch(code).lines() .map(String::stripTrailing) .collect(Collectors.joining(System.lineSeparator())); - String singleLineRepresentation = String.format("{= %s =}", content.strip()); - String multilineRepresentation = new Builder() + MalleableString singleLineRepresentation = MalleableString.anyOf( + String.format("{= %s =}", content.strip()) + ); + MalleableString multilineRepresentation = new Builder() .append(String.format("{=%n")) - .append(MalleableString.anyOf(content).indent(FormattingUtils.INDENTATION)) + .append(MalleableString.anyOf(content).indent()) .append(String.format("%n=}")) - .get().render().rendering(); + .get(); if (content.lines().count() > 1 || content.contains("#") || content.contains("//")) { - return MalleableString.anyOf(multilineRepresentation); + return multilineRepresentation; } return MalleableString.anyOf(singleLineRepresentation, multilineRepresentation); } @@ -412,7 +414,7 @@ private MalleableString reactorHeader(Reactor object) { new Builder() .append(System.lineSeparator()) .append( - MalleableString.anyOf("extends ").indent(FormattingUtils.INDENTATION * 2) + MalleableString.anyOf("extends ").indent().indent() ) .get() ) @@ -682,7 +684,7 @@ public MalleableString caseConnection(Connection object) { } msb.append( "", - MalleableString.anyOf(System.lineSeparator()).indent(FormattingUtils.INDENTATION) + MalleableString.anyOf(System.lineSeparator()).indent() ); msb.append(object.isPhysical() ? " ~> " : " ->"); msb.append(minimallyDelimitedList(object.getRightPorts())); @@ -700,7 +702,7 @@ private MalleableString minimallyDelimitedList(List items) { .append(String.format(" %n")) .append( list(String.format(",%n"), "", "", true, true, items) - .indent(FormattingUtils.INDENTATION) + .indent() ).append(String.format("%n;")).get() ); } @@ -937,7 +939,7 @@ private MalleableString list( nothingIfEmpty, true, items - ).indent(FormattingUtils.INDENTATION)) + ).indent()) .append(suffix.stripLeading()) .get() ); @@ -983,6 +985,6 @@ private MalleableString indentedStatements( "", "" ) - ).indent(FormattingUtils.INDENTATION); + ).indent(); } } From e79427a916017b9861b5c3c06aa6b9a848eb5237 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 00:06:17 -0700 Subject: [PATCH 090/130] [formatting] Format Python tests. --- test/Python/src/ActionDelay.lf | 42 ++++---- test/Python/src/ActionIsPresent.lf | 14 ++- test/Python/src/ActionWithNoReaction.lf | 43 ++++---- test/Python/src/After.lf | 46 ++++---- test/Python/src/AfterCycles.lf | 34 +++--- test/Python/src/AfterOverlapped.lf | 27 ++--- test/Python/src/ArrayAsParameter.lf | 33 +++--- test/Python/src/ArrayAsType.lf | 25 +++-- test/Python/src/ArrayFree.lf | 35 +++--- test/Python/src/ArrayParallel.lf | 33 +++--- test/Python/src/ArrayPrint.lf | 25 +++-- test/Python/src/ArrayScale.lf | 31 +++--- test/Python/src/CompareTags.lf | 19 ++-- test/Python/src/Composition.lf | 32 +++--- test/Python/src/CompositionAfter.lf | 32 +++--- test/Python/src/CompositionGain.lf | 34 +++--- test/Python/src/CompositionInheritance.lf | 42 +++++--- test/Python/src/CountSelf.lf | 29 ++--- test/Python/src/CountTest.lf | 21 ++-- test/Python/src/DanglingOutput.lf | 30 +++--- test/Python/src/Deadline.lf | 34 +++--- test/Python/src/DeadlineHandledAbove.lf | 22 ++-- test/Python/src/DelayArray.lf | 44 +++++--- test/Python/src/DelayArrayWithAfter.lf | 38 ++++--- test/Python/src/DelayInt.lf | 42 +++++--- test/Python/src/DelayString.lf | 42 ++++---- test/Python/src/DelayStruct.lf | 49 +++++---- test/Python/src/DelayStructWithAfter.lf | 30 +++--- .../src/DelayStructWithAfterOverlapped.lf | 40 +++---- test/Python/src/DelayedAction.lf | 19 ++-- test/Python/src/DelayedReaction.lf | 25 +++-- test/Python/src/Determinism.lf | 47 ++++---- test/Python/src/DoubleInvocation.lf | 65 ++++++------ test/Python/src/DoubleReaction.lf | 40 +++---- test/Python/src/FloatLiteral.lf | 7 +- test/Python/src/Gain.lf | 37 ++++--- test/Python/src/GetMicroStep.lf | 22 ++-- test/Python/src/GetTime.lf | 13 ++- test/Python/src/Hello.lf | 43 ++++---- test/Python/src/HelloWorld.lf | 12 ++- test/Python/src/Hierarchy.lf | 60 ++++++----- test/Python/src/Hierarchy2.lf | 74 +++++++------ test/Python/src/IdentifierLength.lf | 44 +++++--- test/Python/src/Import.lf | 17 +-- test/Python/src/ImportComposition.lf | 21 ++-- test/Python/src/ImportRenamed.lf | 21 ++-- test/Python/src/ManualDelayedReaction.lf | 64 ++++++----- test/Python/src/Microsteps.lf | 23 ++-- test/Python/src/Minimal.lf | 9 +- test/Python/src/MovingAverage.lf | 44 ++++---- test/Python/src/MultipleContained.lf | 29 +++-- test/Python/src/NativeListsAndTimes.lf | 44 ++++---- test/Python/src/ParameterizedState.lf | 11 +- test/Python/src/PeriodicDesugared.lf | 13 +-- test/Python/src/PingPong.lf | 67 +++++++----- test/Python/src/Pipeline.lf | 45 ++++---- test/Python/src/Preamble.lf | 14 +-- .../src/ReadOutputOfContainedReactor.lf | 23 ++-- test/Python/src/Schedule.lf | 27 ++--- test/Python/src/ScheduleLogicalAction.lf | 47 ++++---- test/Python/src/ScheduleValue.lf | 9 +- test/Python/src/SelfLoop.lf | 31 +++--- test/Python/src/SendingInside.lf | 26 +++-- test/Python/src/SendingInside2.lf | 17 +-- test/Python/src/SetArray.lf | 31 +++--- test/Python/src/SimpleDeadline.lf | 36 ++++--- test/Python/src/SimpleImport.lf | 9 +- test/Python/src/SlowingClock.lf | 29 +++-- test/Python/src/SlowingClockPhysical.lf | 35 +++--- test/Python/src/StartupOutFromInside.lf | 12 +-- test/Python/src/Stride.lf | 34 +++--- test/Python/src/StructAsState.lf | 10 +- test/Python/src/StructAsType.lf | 23 ++-- test/Python/src/StructAsTypeDirect.lf | 24 +++-- test/Python/src/StructParallel.lf | 44 ++++---- test/Python/src/StructPrint.lf | 30 +++--- test/Python/src/StructScale.lf | 43 ++++---- test/Python/src/SubclassesAndStartup.lf | 16 +-- test/Python/src/TestForPreviousOutput.lf | 27 +++-- test/Python/src/TimeLimit.lf | 54 +++++----- test/Python/src/TimeState.lf | 10 +- test/Python/src/Timers.lf | 27 +++-- .../src/TriggerDownstreamOnlyIfPresent.lf | 36 ++++--- .../src/TriggerDownstreamOnlyIfPresent2.lf | 34 +++--- test/Python/src/UnconnectedInput.lf | 45 ++++---- test/Python/src/Wcet.lf | 42 ++++---- test/Python/src/concurrent/AsyncCallback.lf | 25 +++-- .../src/concurrent/AsyncCallbackNoTimer.lf | 30 +++--- .../src/docker/FilesPropertyContainerized.lf | 15 ++- .../src/docker/HelloWorldContainerized.lf | 6 +- .../src/docker/PingPongContainerized.lf | 40 ++++--- .../DistributedCountContainerized.lf | 22 ++-- .../DistributedDoublePortContainerized.lf | 27 +++-- .../DistributedMultiportContainerized.lf | 17 ++- .../DistributedSendClassContainerized.lf | 14 ++- ...stributedStopDecentralizedContainerized.lf | 15 ++- .../Python/src/federated/BroadcastFeedback.lf | 25 +++-- .../BroadcastFeedbackWithHierarchy.lf | 40 +++---- test/Python/src/federated/ChainWithDelay.lf | 22 ++-- test/Python/src/federated/CycleDetection.lf | 58 +++++----- .../src/federated/DecentralizedP2PComm.lf | 33 +++--- .../DecentralizedP2PUnbalancedTimeout.lf | 56 +++++----- ...centralizedP2PUnbalancedTimeoutPhysical.lf | 49 +++++---- test/Python/src/federated/DistributedBank.lf | 19 ++-- .../federated/DistributedBankToMultiport.lf | 27 ++--- test/Python/src/federated/DistributedCount.lf | 38 +++---- .../DistributedCountDecentralized.lf | 39 ++++--- .../DistributedCountDecentralizedLate.lf | 48 ++++----- ...ributedCountDecentralizedLateDownstream.lf | 100 ++++++++++-------- ...tributedCountDecentralizedLateHierarchy.lf | 54 +++++----- .../src/federated/DistributedCountPhysical.lf | 44 ++++---- .../DistributedCountPhysicalAfterDelay.lf | 44 ++++---- .../DistributedCountPhysicalDecentralized.lf | 44 ++++---- .../src/federated/DistributedDoublePort.lf | 53 +++++----- .../src/federated/DistributedLoopedAction.lf | 39 ++++--- .../DistributedLoopedPhysicalAction.lf | 63 ++++++----- ...ibutedLoopedPhysicalActionDecentralized.lf | 17 ++- .../src/federated/DistributedMultiport.lf | 35 +++--- .../federated/DistributedMultiportToBank.lf | 34 +++--- .../federated/DistributedMultiportToken.lf | 28 ++--- .../src/federated/DistributedNoReact.lf | 14 +-- .../src/federated/DistributedSendClass.lf | 19 ++-- test/Python/src/federated/DistributedStop.lf | 33 +++--- .../federated/DistributedStopDecentralized.lf | 18 ++-- .../src/federated/DistributedStopZero.lf | 40 ++++--- .../src/federated/DistributedStructAsType.lf | 13 ++- .../DistributedStructAsTypeDirect.lf | 13 ++- .../federated/DistributedStructParallel.lf | 32 +++--- .../src/federated/DistributedStructPrint.lf | 18 ++-- .../src/federated/DistributedStructScale.lf | 24 ++--- test/Python/src/federated/HelloDistributed.lf | 42 ++++---- ...stributedCentralizedPrecedenceHierarchy.lf | 68 +++++++----- .../src/federated/ParallelDestinations.lf | 25 ++--- test/Python/src/federated/ParallelSources.lf | 24 ++--- .../src/federated/ParallelSourcesMultiport.lf | 37 +++---- test/Python/src/federated/PhysicalSTP.lf | 32 +++--- .../src/federated/PingPongDistributed.lf | 73 +++++++------ test/Python/src/federated/StopAtShutdown.lf | 48 ++++----- test/Python/src/lib/Count.lf | 12 ++- test/Python/src/lib/Imported.lf | 18 ++-- test/Python/src/lib/ImportedAgain.lf | 14 +-- test/Python/src/lib/ImportedComposition.lf | 35 +++--- test/Python/src/lib/InternalDelay.lf | 25 +++-- test/Python/src/lib/LoopedActionSender.lf | 22 ++-- test/Python/src/lib/Test.lf | 8 +- test/Python/src/lib/TestCount.lf | 17 +-- test/Python/src/lib/TestCountMultiport.lf | 25 +++-- .../src/modal_models/util/TraceTesting.lf | 14 +-- .../src/multiport/BankIndexInitializer.lf | 40 ++++--- .../src/multiport/BankReactionsInContainer.lf | 24 +++-- test/Python/src/multiport/BankToBank.lf | 40 +++---- .../src/multiport/BankToBankMultiport.lf | 33 +++--- .../src/multiport/BankToBankMultiportAfter.lf | 16 +-- test/Python/src/multiport/BankToMultiport.lf | 33 +++--- test/Python/src/multiport/Broadcast.lf | 19 ++-- test/Python/src/multiport/BroadcastAfter.lf | 12 +-- .../src/multiport/BroadcastMultipleAfter.lf | 19 ++-- .../Python/src/multiport/MultiportFromBank.lf | 33 +++--- .../multiport/MultiportFromBankHierarchy.lf | 39 +++---- .../MultiportFromBankHierarchyAfter.lf | 18 ++-- .../src/multiport/MultiportFromHierarchy.lf | 52 +++++---- .../src/multiport/MultiportFromReaction.lf | 25 +++-- test/Python/src/multiport/MultiportIn.lf | 60 ++++++----- .../src/multiport/MultiportInParameterized.lf | 67 ++++++------ .../src/multiport/MultiportMutableInput.lf | 38 ++++--- .../multiport/MultiportMutableInputArray.lf | 39 ++++--- test/Python/src/multiport/MultiportOut.lf | 53 ++++++---- test/Python/src/multiport/MultiportToBank.lf | 30 +++--- .../src/multiport/MultiportToBankAfter.lf | 28 ++--- .../src/multiport/MultiportToBankHierarchy.lf | 38 ++++--- .../src/multiport/MultiportToHierarchy.lf | 46 ++++---- .../src/multiport/MultiportToMultiport.lf | 26 +++-- .../src/multiport/MultiportToMultiport2.lf | 24 +++-- .../multiport/MultiportToMultiport2After.lf | 20 ++-- .../multiport/MultiportToMultiportArray.lf | 33 +++--- .../MultiportToMultiportParameter.lf | 18 ++-- test/Python/src/multiport/MultiportToPort.lf | 30 +++--- .../src/multiport/MultiportToReaction.lf | 25 +++-- test/Python/src/multiport/NestedBanks.lf | 61 +++++++---- .../src/multiport/NestedInterleavedBanks.lf | 27 +++-- test/Python/src/multiport/PipelineAfter.lf | 30 +++--- .../Python/src/multiport/ReactionsToNested.lf | 38 +++---- .../serialization/PersonProtocolBuffers.lf | 33 +++--- .../src/serialization/ProtoNoPacking.lf | 43 ++++---- test/Python/src/target/AfterNoTypes.lf | 45 ++++---- 185 files changed, 3205 insertions(+), 2762 deletions(-) diff --git a/test/Python/src/ActionDelay.lf b/test/Python/src/ActionDelay.lf index 9c3815008e..20802bc992 100644 --- a/test/Python/src/ActionDelay.lf +++ b/test/Python/src/ActionDelay.lf @@ -1,29 +1,32 @@ -// Test logical action with delay. -target Python; +# Test logical action with delay. +target Python reactor GeneratedDelay { - input y_in; - output y_out; - state y_state(0); - logical action act(100 msec); + input y_in + + output y_out + + logical action act(100 msec) + + state y_state(0) + reaction(y_in) -> act {= self.y_state = y_in.value act.schedule(MSEC(0)) =} - reaction(act) -> y_out {= - y_out.set(self.y_state) - =} + reaction(act) -> y_out {= y_out.set(self.y_state) =} } reactor Source { - output out; - reaction(startup) -> out {= - out.set(1) - =} + output out + + reaction(startup) -> out {= out.set(1) =} } + reactor Sink { - input _in; + input _in + reaction(_in) {= elapsed_logical = lf.time.logical_elapsed() logical = lf.time.logical() @@ -36,11 +39,12 @@ reactor Sink { print("SUCCESS. Elapsed logical time is 100 msec.\n") =} } + main reactor ActionDelay { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); + source = new Source() + sink = new Sink() + g = new GeneratedDelay() - source.out -> g.y_in; - g.y_out -> sink._in; + source.out -> g.y_in + g.y_out -> sink._in } diff --git a/test/Python/src/ActionIsPresent.lf b/test/Python/src/ActionIsPresent.lf index a50ad58ad4..7291ca5c76 100644 --- a/test/Python/src/ActionIsPresent.lf +++ b/test/Python/src/ActionIsPresent.lf @@ -1,9 +1,12 @@ -// Tests the is_present variable for actions. -target Python; +# Tests the is_present variable for actions. +target Python + main reactor ActionIsPresent(offset(1 nsec), period(500 msec)) { - logical action a; - state first_time(True); - state success(False); + logical action a + + state first_time(True) + state success(False) + reaction(startup, a) -> a {= # The is_present field should be initially False if a.is_present is not True: @@ -18,6 +21,7 @@ main reactor ActionIsPresent(offset(1 nsec), period(500 msec)) { if self.first_time is not True: self.success = True =} + reaction(shutdown) {= if self.success is not True: sys.stderr.write("Failed to print 'Hello World'\n") diff --git a/test/Python/src/ActionWithNoReaction.lf b/test/Python/src/ActionWithNoReaction.lf index 9e3b657999..69a1ea11aa 100644 --- a/test/Python/src/ActionWithNoReaction.lf +++ b/test/Python/src/ActionWithNoReaction.lf @@ -1,22 +1,24 @@ -// This checks that action can be created even if there is no reaction. -// This test passes merely by compiling and executing without a segfault. -// Its other functionality is tested by other tests. -target Python { - fast: true, - timeout: 3 sec -}; +# This checks that action can be created even if there is no reaction. This test +# passes merely by compiling and executing without a segfault. Its other +# functionality is tested by other tests. +target Python { fast: true, timeout: 3 sec } + reactor foo { - input x; - output y; - logical action a; - reaction(x) -> y, a {= + input x + + output y + + logical action a + + reaction(x) -> y, a {= # reaction(a) {= =} y.set(2*x.value) a.schedule(MSEC(500)) =} - // reaction(a) {= =} } + reactor print { - input x; + input x + reaction(x) {= print("Result is {:d}\n".format(x.value)) print("Current logical time is: {:d}\n".format(lf.time.logical_elapsed())) @@ -25,11 +27,12 @@ reactor print { } main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42) - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= f.x.set(42) =} } diff --git a/test/Python/src/After.lf b/test/Python/src/After.lf index 301c51ddf1..1b6c834b17 100644 --- a/test/Python/src/After.lf +++ b/test/Python/src/After.lf @@ -1,20 +1,21 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target Python { - fast: false, - timeout: 3 sec -}; +# This checks that the after keyword adjusts logical time, not using physical +# time. +target Python { fast: false, timeout: 3 sec } + reactor foo { - input x; - output y; - reaction(x) -> y {= - y.set(2*x.value) - =} + input x + + output y + + reaction(x) -> y {= y.set(2*x.value) =} } + reactor print { - state expected_time(10 msec); - state received(0); - input x; + input x + + state expected_time(10 msec) + state received(0) + reaction(x) {= self.received+=1 elapsed_time = lf.time.logical_elapsed() @@ -30,18 +31,21 @@ reactor print { exit(2) self.expected_time += SEC(1) =} + reaction(shutdown) {= if (self.received == 0): sys.stderr.write("ERROR: Final reactor received no data.\n") exit(3) =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42) - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= f.x.set(42) =} } diff --git a/test/Python/src/AfterCycles.lf b/test/Python/src/AfterCycles.lf index 4c03136f28..33db730925 100644 --- a/test/Python/src/AfterCycles.lf +++ b/test/Python/src/AfterCycles.lf @@ -1,32 +1,30 @@ -// This tests that "after" does not introduce spurious cycles. -// Success if running without detected a cycle. -target Python; +# This tests that "after" does not introduce spurious cycles. Success if running +# without detected a cycle. +target Python reactor Source { - output out; + output out - reaction(startup) -> out {= - out.set(1) - =} + reaction(startup) -> out {= out.set(1) =} } reactor Work { - input _in; - output out; + input _in - reaction(_in) -> out {= - out.set(_in.value) - =} + output out + + reaction(_in) -> out {= out.set(_in.value) =} } main reactor AfterCycles { - state count(0); - s = new Source(); - w0 = new Work(); - w1 = new Work(); + s = new Source() + w0 = new Work() + w1 = new Work() + + s.out -> w0._in after 10 msec + s.out -> w1._in after 20 msec - s.out -> w0._in after 10 msec; - s.out -> w1._in after 20 msec; + state count(0) reaction(w0.out) {= self.count+=1 diff --git a/test/Python/src/AfterOverlapped.lf b/test/Python/src/AfterOverlapped.lf index 36f716f4e2..194b8cc0a3 100644 --- a/test/Python/src/AfterOverlapped.lf +++ b/test/Python/src/AfterOverlapped.lf @@ -1,14 +1,14 @@ -// This the after keyword with overlapped time intervals. -target Python { - fast: true, - timeout: 5 sec -}; -import Count from "lib/Count.lf"; +# This the after keyword with overlapped time intervals. +target Python { fast: true, timeout: 5 sec } + +import Count from "lib/Count.lf" reactor Test { - input c; - state i(0); - state received(0); + input c + + state i(0) + state received(0) + reaction(c) {= self.received += 1 print(f"Received {c.value}.") @@ -24,14 +24,17 @@ reactor Test { sys.stderr.write("ERROR: Expected logical time to be {:d} but got {:d}\n.".format(expected_logical_time, elapsed_time)) exit(1) =} + reaction(shutdown) {= if self.received == 0: sys.stderr.write("ERROR: Final reactor received no data.\n") exit(3) =} } + main reactor AfterOverlapped { - count = new Count(); - test = new Test(); - count.out -> test.c after 2 sec; + count = new Count() + test = new Test() + + count.out -> test.c after 2 sec } diff --git a/test/Python/src/ArrayAsParameter.lf b/test/Python/src/ArrayAsParameter.lf index 54b4e7ea2c..58dfcb833a 100644 --- a/test/Python/src/ArrayAsParameter.lf +++ b/test/Python/src/ArrayAsParameter.lf @@ -1,10 +1,13 @@ -// Source has an array as a parameter, the elements of which it passes -// to Print. -target Python; +# Source has an array as a parameter, the elements of which it passes to Print. +target Python + reactor Source(sequence(0, 1, 2)) { - output out; - state count(0); - logical action next; + output out + + logical action next + + state count(0) + reaction(startup, next) -> out, next {= out.set(self.sequence[self.count]) self.count+=1 @@ -12,10 +15,13 @@ reactor Source(sequence(0, 1, 2)) { next.schedule(0) =} } + reactor Print { - input _in; - state count(1); - state received(0); + input _in + + state count(1) + state received(0) + reaction(_in) {= self.received+=1 print("Received: {:d}\n".format(_in.value)) @@ -24,14 +30,17 @@ reactor Print { exit(1) self.count+=1 =} + reaction(shutdown) {= if self.received == 0: sys.stderr.write("ERROR: Final reactor received no data.\n") exit(3) =} } + main reactor ArrayAsParameter { - s = new Source(sequence = (1, 2, 3, 4)); - p = new Print(); - s.out -> p._in; + s = new Source(sequence = (1, 2, 3, 4)) + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/ArrayAsType.lf b/test/Python/src/ArrayAsType.lf index ea2cc5c2c2..b717921939 100644 --- a/test/Python/src/ArrayAsType.lf +++ b/test/Python/src/ArrayAsType.lf @@ -1,16 +1,19 @@ -// Source produces a statically allocated array, which it passes -// to Print. The destination references the array directly. -target Python; +# Source produces a statically allocated array, which it passes to Print. The +# destination references the array directly. +target Python + reactor Source { - output out; + output out + reaction(startup) -> out {= # Pass on a tuple to out out.set((0, 2.8, "hello")) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input _in + reaction(_in) {= print("Received: [%s]" % ", ".join(map(str, _in.value))) if _in.value != (0, 2.8, "hello"): @@ -18,8 +21,10 @@ reactor Print(scale(1)) { exit(1) =} } + main reactor ArrayAsType { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/ArrayFree.lf b/test/Python/src/ArrayFree.lf index e926bd1022..d5629b0e63 100644 --- a/test/Python/src/ArrayFree.lf +++ b/test/Python/src/ArrayFree.lf @@ -1,25 +1,28 @@ -// Source produces a dynamically allocated array, which it passes -// to Free. Free requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It then does nothing further with it. This test checks -// that the memory gets freed automatically even with the mutable input. -target Python; -import Source, Print from "ArrayPrint.lf"; -import Scale from "ArrayScale.lf"; +# Source produces a dynamically allocated array, which it passes to Free. Free +# requests a writable copy, which, instead of copying, it just gets ownership of +# the original array. It then does nothing further with it. This test checks +# that the memory gets freed automatically even with the mutable input. +target Python + +import Source, Print from "ArrayPrint.lf" +import Scale from "ArrayScale.lf" reactor Free(scale(2)) { - mutable input _in; + mutable input _in + reaction(_in) {= for i in range(len(_in.value)): _in.value[i] *= self.scale =} } + main reactor ArrayFree { - s = new Source(); - c = new Free(); - c2 = new Scale(); - p = new Print(scale = 2); - s.out -> c._in; - s.out -> c2._in; - c2.out -> p._in; + s = new Source() + c = new Free() + c2 = new Scale() + p = new Print(scale = 2) + + s.out -> c._in + s.out -> c2._in + c2.out -> p._in } diff --git a/test/Python/src/ArrayParallel.lf b/test/Python/src/ArrayParallel.lf index a13df61916..80d602a973 100644 --- a/test/Python/src/ArrayParallel.lf +++ b/test/Python/src/ArrayParallel.lf @@ -1,19 +1,22 @@ -// Source allocates an array dynamically and then sends it to two reactors, -// each of which want to modify it. -// NOTE: Ideally, only one copy would be made, but this requires -// modifying the precedence graph between reactions. -target Python; -import Scale from "ArrayScale.lf"; +/** + * Source allocates an array dynamically and then sends it to two reactors, each + * of which want to modify it. NOTE: Ideally, only one copy would be made, but + * this requires modifying the precedence graph between reactions. + */ +target Python + +import Scale from "ArrayScale.lf" import Source, Print from "ArrayPrint.lf" main reactor ArrayParallel { - s = new Source(); - c1 = new Scale(); - c2 = new Scale(scale = 3); - p1 = new Print(scale = 2); - p2 = new Print(scale = 3); - s.out -> c1._in; - s.out -> c2._in; - c1.out -> p1._in; - c2.out -> p2._in; + s = new Source() + c1 = new Scale() + c2 = new Scale(scale = 3) + p1 = new Print(scale = 2) + p2 = new Print(scale = 3) + + s.out -> c1._in + s.out -> c2._in + c1.out -> p1._in + c2.out -> p2._in } diff --git a/test/Python/src/ArrayPrint.lf b/test/Python/src/ArrayPrint.lf index a69be1e590..279109286c 100644 --- a/test/Python/src/ArrayPrint.lf +++ b/test/Python/src/ArrayPrint.lf @@ -1,16 +1,19 @@ -// Source produces a dynamically allocated array, which it passes -// to Print. Reference counting ensures that the array is freed. -target Python; +# Source produces a dynamically allocated array, which it passes to Print. +# Reference counting ensures that the array is freed. +target Python + reactor Source { - output out; + output out + reaction(startup) -> out {= # Dynamically allocate an output array of length 3 and populate it. out.set([0,1,2]) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input _in + reaction(_in) {= print("Received: [%s]" % ", ".join(map(str, _in.value))) if _in.value != [x * self.scale for x in [0, 1, 2]]: @@ -18,8 +21,10 @@ reactor Print(scale(1)) { exit(1) =} } + main reactor ArrayPrint { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/ArrayScale.lf b/test/Python/src/ArrayScale.lf index 81589edc5d..d820776e24 100644 --- a/test/Python/src/ArrayScale.lf +++ b/test/Python/src/ArrayScale.lf @@ -1,14 +1,16 @@ -// Source produces a dynamically allocated array, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target Python; -import Print, Source from "ArrayPrint.lf"; +# Source produces a dynamically allocated array, which it passes to Scale. Scale +# requests a writable copy, which, instead of copying, it just gets ownership of +# the original array. It modifies it and passes it to Print. It gets freed after +# Print is done with it. +target Python + +import Print, Source from "ArrayPrint.lf" reactor Scale(scale(2)) { - mutable input _in; - output out; + mutable input _in + + output out + reaction(_in) -> out {= for i in range(len(_in.value)): _in.value[i] *= self.scale @@ -17,9 +19,10 @@ reactor Scale(scale(2)) { } main reactor ArrayScale { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c._in; - c.out -> p._in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c._in + c.out -> p._in } diff --git a/test/Python/src/CompareTags.lf b/test/Python/src/CompareTags.lf index fbe3c72d43..f44c58fce4 100644 --- a/test/Python/src/CompareTags.lf +++ b/test/Python/src/CompareTags.lf @@ -1,14 +1,13 @@ -// Tests the lf.tag_compare() function in the python target. -target Python { - timeout: 10 msec, - fast: false -}; +# Tests the lf.tag_compare() function in the python target. +target Python { timeout: 10 msec, fast: false } + main reactor CompareTags { - preamble {= - import sys - =} - timer t(0, 1 msec); - logical action l; + preamble {= import sys =} + + timer t(0, 1 msec) + + logical action l + reaction(t) -> l {= tag1 = get_current_tag() tag2 = get_current_tag() diff --git a/test/Python/src/Composition.lf b/test/Python/src/Composition.lf index 2e5d8f425d..aa723267ec 100644 --- a/test/Python/src/Composition.lf +++ b/test/Python/src/Composition.lf @@ -1,14 +1,14 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Python { - fast: true, - timeout: 10 sec -}; +# This test connects a simple counting source to tester that checks against its +# own count. +target Python { fast: true, timeout: 10 sec } reactor Source(period(2 sec)) { - output y; - timer t(1 sec, period); - state count(0); + output y + + timer t(1 sec, period) + + state count(0) + reaction(t) -> y {= self.count += 1 print("Source sending " + str(self.count)) @@ -18,8 +18,10 @@ reactor Source(period(2 sec)) { } reactor Test { - input x; - state count(0); + input x + + state count(0) + reaction(x) {= self.count += 1 print("Recieved " + str(x.value)) @@ -27,14 +29,16 @@ reactor Test { sys.stderr.write("FAILURE: Expected " + str(self.count) + "\n") exit(1) =} + reaction(shutdown) {= if(self.count == 0): sys.stderr.write("FAILURE: No data received.\n") =} } + main reactor Composition { - s = new Source(); + s = new Source() + d = new Test() - d = new Test(); - s.y -> d.x; + s.y -> d.x } diff --git a/test/Python/src/CompositionAfter.lf b/test/Python/src/CompositionAfter.lf index 1c901fb276..1740c79d6b 100644 --- a/test/Python/src/CompositionAfter.lf +++ b/test/Python/src/CompositionAfter.lf @@ -1,14 +1,14 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Python { - fast: true, - timeout: 10 sec -}; +# This test connects a simple counting source to tester that checks against its +# own count. +target Python { fast: true, timeout: 10 sec } reactor Source(period(2 sec)) { - output y; - timer t(1 sec, period); - state count(0); + output y + + timer t(1 sec, period) + + state count(0) + reaction(t) -> y {= self.count += 1 y.set(self.count) @@ -16,8 +16,10 @@ reactor Source(period(2 sec)) { } reactor Test { - input x; - state count(0); + input x + + state count(0) + reaction(x) {= self.count += 1 print("Received ", x.value) @@ -26,8 +28,10 @@ reactor Test { exit(1) =} } + main reactor(delay(5 sec)) { - s = new Source(); - d = new Test(); - s.y -> d.x after delay; + s = new Source() + d = new Test() + + s.y -> d.x after delay } diff --git a/test/Python/src/CompositionGain.lf b/test/Python/src/CompositionGain.lf index 939e386348..f5eb3b4fe3 100644 --- a/test/Python/src/CompositionGain.lf +++ b/test/Python/src/CompositionGain.lf @@ -1,25 +1,33 @@ -// This tests send data through a contained reactor. -target Python; +# This tests send data through a contained reactor. +target Python + reactor Gain { - input gainin; - output y; + input gainin + + output y + reaction(gainin) -> y {= print("Gain received " + str(gainin.value)) y.set(gainin.value * 2) =} } + reactor Wrapper { - input x; - output y; - gain = new Gain(); - x -> gain.gainin; - gain.y -> y; + input x + + output y + + gain = new Gain() + + x -> gain.gainin + gain.y -> y } + main reactor { - wrapper = new Wrapper(); - reaction(startup) -> wrapper.x {= - wrapper_x.set(42) - =} + wrapper = new Wrapper() + + reaction(startup) -> wrapper.x {= wrapper_x.set(42) =} + reaction(wrapper.y) {= print("Received " + str(wrapper_y.value)) if (wrapper_y.value != 42 * 2): diff --git a/test/Python/src/CompositionInheritance.lf b/test/Python/src/CompositionInheritance.lf index 83aa4c45da..a37e15f728 100644 --- a/test/Python/src/CompositionInheritance.lf +++ b/test/Python/src/CompositionInheritance.lf @@ -1,14 +1,16 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Python { - fast: true, - timeout: 10 sec -}; +# This test connects a simple counting source to tester that checks against its +# own count. +target Python { fast: true, timeout: 10 sec } + reactor Source(period(2 sec)) { - input foo; - output y; - timer t(1 sec, period); - state count(0); + input foo + + output y + + timer t(1 sec, period) + + state count(0) + reaction(t) -> y {= print("Hello World. My count is: ", self.count) y.set(self.count) @@ -16,8 +18,10 @@ reactor Source(period(2 sec)) { } reactor SourceExtended extends Source { - output y2; - timer t2(1 sec, 3 sec); + output y2 + + timer t2(1 sec, 3 sec) + reaction(t2) -> y2 {= self.count += 1 print("Source sending ", self.count) @@ -26,8 +30,10 @@ reactor SourceExtended extends Source { } reactor Test { - input x; - state count(0); + input x + + state count(0) + reaction(x) {= self.count += 1 print("Received ", x.value) @@ -35,14 +41,16 @@ reactor Test { sys.stderr.write("FAILURE: Expected %d\n", self.count) exit(1) =} + reaction(shutdown) {= if self.count == 0: sys.stderr.write("FAILURE: No data received.\n") =} } + main reactor { - s = new SourceExtended(); + s = new SourceExtended() + d = new Test() - d = new Test(); - s.y2 -> d.x; + s.y2 -> d.x } diff --git a/test/Python/src/CountSelf.lf b/test/Python/src/CountSelf.lf index ebdf249c8a..a243a9d429 100644 --- a/test/Python/src/CountSelf.lf +++ b/test/Python/src/CountSelf.lf @@ -1,23 +1,27 @@ -// This tests actions with payloads by delaying an input by a fixed amount. -target Python { - timeout: 1 sec, - fast: true -}; +# This tests actions with payloads by delaying an input by a fixed amount. +target Python { timeout: 1 sec, fast: true } + reactor CountSelf2(delay(100 msec)) { - output out; - logical action a; + output out + + logical action a + reaction(startup) -> a, out {= out.set(0) a.schedule(self.delay, 1) =} + reaction(a) -> a, out {= out.set(a.value) a.schedule(self.delay, a.value + 1) =} } + reactor Test { - input _in; - state count(0); + input _in + + state count(0) + reaction(_in) {= print("Received: {:d}".format(_in.value)) if _in.value != self.count: @@ -29,7 +33,8 @@ reactor Test { } main reactor { - d = new CountSelf2(); - t = new Test(); - d.out -> t._in; + d = new CountSelf2() + t = new Test() + + d.out -> t._in } diff --git a/test/Python/src/CountTest.lf b/test/Python/src/CountTest.lf index c52b0877e2..6f29ddeae7 100644 --- a/test/Python/src/CountTest.lf +++ b/test/Python/src/CountTest.lf @@ -1,13 +1,12 @@ -target Python { - timeout: 3 sec, - fast: true -}; +target Python { timeout: 3 sec, fast: true } -import Count from "lib/Count.lf"; +import Count from "lib/Count.lf" reactor Test { - input c; - state i(0); + input c + + state i(0) + reaction(c) {= print("Received ", c.value) self.i +=1 @@ -15,6 +14,7 @@ reactor Test { sys.stderr.write("ERROR: Expected {:d} but got {:d}\n.".format(self.i, c.value)) exit(1) =} + reaction(shutdown) {= if self.i != 4: sys.stderr.write("ERROR: Test should have reacted 4 times, but reacted {:d} times.\n".format(self.i)) @@ -23,7 +23,8 @@ reactor Test { } main reactor CountTest { - count = new Count(); - test = new Test(); - count.out -> test.c; + count = new Count() + test = new Test() + + count.out -> test.c } diff --git a/test/Python/src/DanglingOutput.lf b/test/Python/src/DanglingOutput.lf index ac3b58648d..a6a4c2184a 100644 --- a/test/Python/src/DanglingOutput.lf +++ b/test/Python/src/DanglingOutput.lf @@ -1,17 +1,20 @@ -// This tests that an output that is not connected to anything does not result -// in a compilation error. Passing the test is just compiling and running. -target Python; +# This tests that an output that is not connected to anything does not result in +# a compilation error. Passing the test is just compiling and running. +target Python + reactor Source { - output out; - timer t; - reaction(t) -> out {= - out.set(1); - =} + output out + + timer t + + reaction(t) -> out {= out.set(1); =} } reactor Gain { - input _in; - output out; + input _in + + output out + reaction(_in) -> out {= print("Received ", _in.value) out.set(_in.value * 2) @@ -19,7 +22,8 @@ reactor Gain { } main reactor DanglingOutput { - source = new Source(); - container = new Gain(); - source.out -> container._in; + source = new Source() + container = new Gain() + + source.out -> container._in } diff --git a/test/Python/src/Deadline.lf b/test/Python/src/Deadline.lf index a421ed73ee..84f3d191a2 100644 --- a/test/Python/src/Deadline.lf +++ b/test/Python/src/Deadline.lf @@ -1,13 +1,15 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target Python { - timeout: 6 sec -}; +# This example illustrates local deadline handling. Even numbers are sent by the +# Source immediately, whereas odd numbers are sent after a big enough delay to +# violate the deadline. +target Python { timeout: 6 sec } + reactor Source(period(3 sec)) { - output y; - timer t(0, period); - state count(0); + output y + + timer t(0, period) + + state count(0) + reaction(t) -> y {= if self.count % 2 != 0: # The count variable is odd. @@ -24,8 +26,10 @@ reactor Source(period(3 sec)) { } reactor Destination(timeout(1 sec)) { - input x; - state count(0); + input x + + state count(0) + reaction(x) {= print("Destination receives: ", x.value) if self.count % 2 != 0: @@ -43,8 +47,10 @@ reactor Destination(timeout(1 sec)) { self.count += 1 =} } + main reactor Deadline { - s = new Source(); - d = new Destination(timeout = 1 sec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 1 sec) + + s.y -> d.x } diff --git a/test/Python/src/DeadlineHandledAbove.lf b/test/Python/src/DeadlineHandledAbove.lf index 793c509149..eba789d28c 100644 --- a/test/Python/src/DeadlineHandledAbove.lf +++ b/test/Python/src/DeadlineHandledAbove.lf @@ -1,9 +1,12 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target Python; +# Test a deadline where the deadline violation produces an output and the +# container reacts to that output. +target Python + reactor Deadline(threshold(100 msec)) { - input x; - output deadline_violation; + input x + + output deadline_violation + reaction(x) -> deadline_violation {= sys.stderr.write("ERROR: Deadline violation was not detected!\n") exit(1) @@ -12,9 +15,12 @@ reactor Deadline(threshold(100 msec)) { deadline_violation.set(True) =} } + main reactor DeadlineHandledAbove { - state violation_detected(false); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected(false) + reaction(startup) -> d.x {= sleep_time = MSEC(200) start_time = lf.time.physical() @@ -22,11 +28,13 @@ main reactor DeadlineHandledAbove { pass d.x.set(42) =} + reaction(d.deadline_violation) {= if d.deadline_violation.value is True: print("Output successfully produced by deadline miss handler.") self.violation_detected = True =} + reaction(shutdown) {= if self.violation_detected is True: print("SUCCESS. Test passes.") diff --git a/test/Python/src/DelayArray.lf b/test/Python/src/DelayArray.lf index 9435965798..e48aab9730 100644 --- a/test/Python/src/DelayArray.lf +++ b/test/Python/src/DelayArray.lf @@ -1,27 +1,35 @@ -// This tests delaying an array type. -target Python; +# This tests delaying an array type. +target Python + reactor DelayPointer(delay(100 msec)) { - mutable input _in; // The Python target does not require explicit type allocation for types other than time - output out; - logical action a; + # The Python target does not require explicit type allocation for types + # other than time + mutable input _in + + output out + + logical action a + reaction(_in) -> a {= # mutable input guarantees in will not be freed. a.schedule(self.delay, _in.value); =} - reaction(a) -> out {= - out.set(a.value); - =} + + reaction(a) -> out {= out.set(a.value); =} } + reactor Source { - output out; + output out + reaction(startup) -> out {= # Send an output list of length 3. out.set([0, 1, 2]) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input _in + reaction(_in) {= print("Received: [%s]" % ", ".join(map(str, _in.value))) if _in.value != [x * self.scale for x in [0, 1, 2]]: @@ -29,10 +37,12 @@ reactor Print(scale(1)) { exit(1) =} } + main reactor DelayArray { - s = new Source(); - d = new DelayPointer(); - p = new Print(); - s.out -> d._in; - d.out -> p._in; + s = new Source() + d = new DelayPointer() + p = new Print() + + s.out -> d._in + d.out -> p._in } diff --git a/test/Python/src/DelayArrayWithAfter.lf b/test/Python/src/DelayArrayWithAfter.lf index 568ed7933f..77f29aba33 100644 --- a/test/Python/src/DelayArrayWithAfter.lf +++ b/test/Python/src/DelayArrayWithAfter.lf @@ -1,13 +1,14 @@ -// This tests transport of dynamically allocated arrays over -// connections with 'after'. -target Python { - timeout: 5 sec, - fast: true -}; +# This tests transport of dynamically allocated arrays over connections with +# 'after'. +target Python { timeout: 5 sec, fast: true } + reactor Source { - output out; - state iteration(1); - timer t(0, 1 sec); + output out + + timer t(0, 1 sec) + + state iteration(1) + reaction(t) -> out {= out.set([(x * self.iteration) for x in [1,2,3]]) print("At time {:d}, sending list ".format(lf.time.logical_elapsed()), out.value) @@ -16,11 +17,12 @@ reactor Source { =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input _in; - state iteration(1); - state inputs_received(0); +reactor Print(scale(1)) { # The scale parameter is just for testing. + input _in + + state iteration(1) + state inputs_received(0) + reaction(_in) {= self.inputs_received += 1 @@ -42,8 +44,10 @@ reactor Print(scale(1)) { exit(3) =} } + main reactor DelayArrayWithAfter { - s = new Source(); - p = new Print(); - s.out -> p._in after 1500 msec; + s = new Source() + p = new Print() + + s.out -> p._in after 1500 msec } diff --git a/test/Python/src/DelayInt.lf b/test/Python/src/DelayInt.lf index fe41891ba5..d696f3ad27 100644 --- a/test/Python/src/DelayInt.lf +++ b/test/Python/src/DelayInt.lf @@ -1,25 +1,32 @@ -// This tests actions with payloads by delaying an input by a fixed amount. -target Python; +# This tests actions with payloads by delaying an input by a fixed amount. +target Python + reactor Delay(delay(100 msec)) { - input _in; - output out; - logical action a; + input _in + + output out + + logical action a + reaction(a) -> out {= if (a.value is not None) and a.is_present: out.set(a.value) =} - reaction(_in) -> a {= - a.schedule(self.delay, _in.value) - =} + + reaction(_in) -> a {= a.schedule(self.delay, _in.value) =} } + reactor Test { - input _in; - state start_time(0); - state received_value(false); + input _in + + state start_time(0) + state received_value(false) + reaction(startup) {= # Record the logical time at the start. self.start_time = lf.time.logical() =} + reaction(_in) {= print("Received: ", _in.value) self.received_value = True @@ -34,6 +41,7 @@ reactor Test { sys.stderr.write("ERROR: Expected input value to be 42. It was {:d}.\n".format(_in.value)) exit(2) =} + reaction(shutdown) {= print("Checking that communication occurred.") if self.received_value is not True: @@ -43,10 +51,10 @@ reactor Test { } main reactor DelayInt { - d = new Delay(); - t = new Test(); - d.out -> t._in; - reaction(startup) -> d._in {= - d._in.set(42) - =} + d = new Delay() + t = new Test() + + d.out -> t._in + + reaction(startup) -> d._in {= d._in.set(42) =} } diff --git a/test/Python/src/DelayString.lf b/test/Python/src/DelayString.lf index a21d161599..988a26d851 100644 --- a/test/Python/src/DelayString.lf +++ b/test/Python/src/DelayString.lf @@ -1,20 +1,24 @@ -// This tests actions with immutable payloads that are neither malloc'd nor freed. -target Python; +# This tests actions with immutable payloads that are neither malloc'd nor +# freed. +target Python reactor DelayString2(delay(100 msec)) { - input _in; - output out; - logical action a; - reaction(a) -> out {= - out.set(a.value) - =} - reaction(_in) -> a {= - a.schedule(self.delay, _in.value) - =} + input _in + + output out + + logical action a + + reaction(a) -> out {= out.set(a.value) =} + + reaction(_in) -> a {= a.schedule(self.delay, _in.value) =} } + reactor Test { - input _in; - state start_time(0); + input _in + + state start_time(0) + reaction(_in) {= print("Received: ", _in.value) # Check the time of the input. @@ -30,10 +34,10 @@ reactor Test { } main reactor { - d = new DelayString2(); - t = new Test(); - d.out -> t._in; - reaction(startup) -> d._in {= - d._in.set("Hello") - =} + d = new DelayString2() + t = new Test() + + d.out -> t._in + + reaction(startup) -> d._in {= d._in.set("Hello") =} } diff --git a/test/Python/src/DelayStruct.lf b/test/Python/src/DelayStruct.lf index bd741a4edd..741cdff841 100644 --- a/test/Python/src/DelayStruct.lf +++ b/test/Python/src/DelayStruct.lf @@ -1,32 +1,33 @@ -// Test delaying a struct pointer type. -target Python {files: ["include/hello.py"]}; +# Test delaying a struct pointer type. +target Python { files: ["include/hello.py"] } -preamble {= -import hello -=} +preamble {= import hello =} reactor DelayPointer(delay(100 msec)) { - input _in; - output out; - logical action a; - reaction(a) -> out {= - out.set(a.value); - =} + input _in + + output out + + logical action a + + reaction(a) -> out {= out.set(a.value); =} + reaction(_in) -> a {= # Schedule the actual token from the input rather than # a new token with a copy of the input value. a.schedule(self.delay, _in.value); =} } + reactor Source { - output out; - reaction(startup) -> out {= - out.set(hello.hello("Earth", 42)) - =} + output out + + reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -// expected parameter is for testing. -reactor Print(expected(42)) { - input _in; + +reactor Print(expected(42)) { # expected parameter is for testing. + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -34,10 +35,12 @@ reactor Print(expected(42)) { exit(1) =} } + main reactor DelayStruct { - s = new Source(); - d = new DelayPointer(); - p = new Print(); - s.out -> d._in; - d.out -> p._in; + s = new Source() + d = new DelayPointer() + p = new Print() + + s.out -> d._in + d.out -> p._in } diff --git a/test/Python/src/DelayStructWithAfter.lf b/test/Python/src/DelayStructWithAfter.lf index 8704749054..2b3b337eec 100644 --- a/test/Python/src/DelayStructWithAfter.lf +++ b/test/Python/src/DelayStructWithAfter.lf @@ -1,19 +1,17 @@ -// This tests delaying a struct using after. -target Python {files: include/hello.py}; +# This tests delaying a struct using after. +target Python { files: include/hello.py } -preamble {= -import hello -=} +preamble {= import hello =} reactor Source { - output out; - reaction(startup) -> out {= - out.set(hello.hello("Earth", 42)) - =} + output out + + reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -// expected parameter is for testing. -reactor Print(expected(42)) { - input _in; + +reactor Print(expected(42)) { # expected parameter is for testing. + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -21,8 +19,10 @@ reactor Print(expected(42)) { exit(1) =} } + main reactor DelayStructWithAfter { - s = new Source(); - p = new Print(); - s.out -> p._in after 100 msec; + s = new Source() + p = new Print() + + s.out -> p._in after 100 msec } diff --git a/test/Python/src/DelayStructWithAfterOverlapped.lf b/test/Python/src/DelayStructWithAfterOverlapped.lf index e0b4fb3c11..0328909481 100644 --- a/test/Python/src/DelayStructWithAfterOverlapped.lf +++ b/test/Python/src/DelayStructWithAfterOverlapped.lf @@ -1,27 +1,26 @@ -// This tests delaying a struct using after. -target Python { - timeout: 5 sec, - fast: true, - files: ["include/hello.py"] -}; +# This tests delaying a struct using after. +target Python { timeout: 5 sec, fast: true, files: ["include/hello.py"] } -preamble {= -import hello -=} +preamble {= import hello =} reactor Source { - output out; - timer t(0, 1 sec); - state s(0); + output out + + timer t(0, 1 sec) + + state s(0) + reaction(t) -> out {= self.s += 1 out.set(hello.hello("Earth", 42 * self.s)) =} } -// expected parameter is for testing. -reactor Print { - input _in; - state s(0); + +reactor Print { # expected parameter is for testing. + input _in + + state s(0) + reaction(_in) {= self.s += 1 print("Received: name = {:s}, value = {:d}".format(_in.value.name, _in.value.value)) @@ -29,14 +28,17 @@ reactor Print { sys.stderr.write("ERROR: Expected value to be {:d}.\n".format(42 * self.s)) exit(1) =} + reaction(shutdown) {= if self.s == 0: sys.stderr.write("ERROR: Print received no data.\n") exit(2) =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p._in after 1500 msec; + s = new Source() + p = new Print() + + s.out -> p._in after 1500 msec } diff --git a/test/Python/src/DelayedAction.lf b/test/Python/src/DelayedAction.lf index 0895e02cc7..3a74f083f6 100644 --- a/test/Python/src/DelayedAction.lf +++ b/test/Python/src/DelayedAction.lf @@ -1,14 +1,13 @@ -target Python { - fast: true, - timeout: 5 sec -}; +target Python { fast: true, timeout: 5 sec } + main reactor DelayedAction { - timer t(0, 1 sec); - logical action a; - state count(0); - reaction(t) -> a {= - a.schedule(MSEC(100)) - =} + timer t(0, 1 sec) + + logical action a + + state count(0) + + reaction(t) -> a {= a.schedule(MSEC(100)) =} reaction(a) {= elapsed = lf.time.logical_elapsed() diff --git a/test/Python/src/DelayedReaction.lf b/test/Python/src/DelayedReaction.lf index 9c48986480..9ac1be6955 100644 --- a/test/Python/src/DelayedReaction.lf +++ b/test/Python/src/DelayedReaction.lf @@ -1,15 +1,17 @@ -// Test delay made on a connection. -target Python; +# Test delay made on a connection. +target Python reactor Source { - output out; - timer t; - reaction(t) -> out {= - out.set(1) - =} + output out + + timer t + + reaction(t) -> out {= out.set(1) =} } + reactor Sink { - input _in; + input _in + reaction(_in) {= elapsed = lf.time.logical_elapsed() print("Nanoseconds since start: ", elapsed) @@ -18,9 +20,10 @@ reactor Sink { exit(1) =} } + main reactor DelayedReaction { + source = new Source() + sink = new Sink() - source = new Source(); - sink = new Sink(); - source.out -> sink._in after 100 msec; + source.out -> sink._in after 100 msec } diff --git a/test/Python/src/Determinism.lf b/test/Python/src/Determinism.lf index 003b6c7e9e..0b08f41279 100644 --- a/test/Python/src/Determinism.lf +++ b/test/Python/src/Determinism.lf @@ -1,14 +1,17 @@ -target Python; +target Python + reactor Source { - output y; - timer t; - reaction(t) -> y {= - y.set(1) - =} + output y + + timer t + + reaction(t) -> y {= y.set(1) =} } + reactor Destination { - input x; - input y; + input x + input y + reaction(x, y) {= sm = 0 if x.is_present: @@ -21,21 +24,23 @@ reactor Destination { exit(4) =} } + reactor Pass { - input x; - output y; - reaction(x) -> y {= - y.set(x.value) - =} + input x + + output y + + reaction(x) -> y {= y.set(x.value) =} } main reactor Determinism { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/Python/src/DoubleInvocation.lf b/test/Python/src/DoubleInvocation.lf index a24512fb7e..237cb98523 100644 --- a/test/Python/src/DoubleInvocation.lf +++ b/test/Python/src/DoubleInvocation.lf @@ -1,37 +1,38 @@ -// This illustrates a very strange bug that showed up -// and has now been fixed. This test ensures it does -// not reappear. -// At logical time zero, the two Print reactors used to be -// fired twice each at the same logical time. -// They should only be fired once. -// This behavior was oddly eliminated by either of the following -// actions, neither of which should affect this behavior: -// * Removing the startup reaction in Print. -// * Sending only position, not velocity from Ball. - -target Python { - timeout: 5 sec, - fast: true -}; +# This illustrates a very strange bug that showed up and has now been fixed. +# This test ensures it does not reappear. At logical time zero, the two Print +# reactors used to be fired twice each at the same logical time. They should +# only be fired once. This behavior was oddly eliminated by either of the +# following actions, neither of which should affect this behavior: +# * Removing the startup reaction in Print. +# * Sending only position, not velocity from Ball. +target Python { timeout: 5 sec, fast: true } + reactor Ball { - output position; - output velocity; - state p(200); - timer trigger(0, 1 sec); + output position + output velocity + + timer trigger(0, 1 sec) + + state p(200) + reaction(trigger) -> position, velocity {= position.set(self.p) velocity.set(-1) self.p -= 1 =} } + reactor Print { - input velocity; - input position; - state previous(-1); - reaction (startup) {= + input velocity + input position + + state previous(-1) + + reaction(startup) {= print("####### Print startup\n") =} - reaction (position, velocity) {= + + reaction(position, velocity) {= if position.is_present: print("Position: ", position.value) if position.value == self.previous: @@ -39,12 +40,14 @@ reactor Print { exit(1) =} } + main reactor DoubleInvocation { - b1 = new Ball(); - p = new Print(); - plot = new Print(); - b1.position -> p.position; - b1.velocity -> p.velocity; - b1.position -> plot.position; - b1.velocity -> plot.velocity; + b1 = new Ball() + p = new Print() + plot = new Print() + + b1.position -> p.position + b1.velocity -> p.velocity + b1.position -> plot.position + b1.velocity -> plot.velocity } diff --git a/test/Python/src/DoubleReaction.lf b/test/Python/src/DoubleReaction.lf index 5f16ff6329..822a061e11 100644 --- a/test/Python/src/DoubleReaction.lf +++ b/test/Python/src/DoubleReaction.lf @@ -1,14 +1,14 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target Python { - timeout: 10 sec, - fast: true -}; +# Test that two simultaneous inputs that trigger a reaction trigger it only +# once. Correct output for this 2, 4, 6, 8, etc. +target Python { timeout: 10 sec, fast: true } + reactor Clock(offset(0), period(1 sec)) { - output y; - timer t(offset, period); - state count(0); + output y + + timer t(offset, period) + + state count(0) + reaction(t) -> y {= self.count += 1 y.set(self.count) @@ -16,9 +16,11 @@ reactor Clock(offset(0), period(1 sec)) { } reactor Destination { - input x; - input w; - state s(2); + input x + input w + + state s(2) + reaction(x, w) {= sm = 0 if x.is_present: @@ -32,10 +34,12 @@ reactor Destination { self.s += 2 =} } + main reactor DoubleReaction { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/Python/src/FloatLiteral.lf b/test/Python/src/FloatLiteral.lf index 48601910a1..5ed6202429 100644 --- a/test/Python/src/FloatLiteral.lf +++ b/test/Python/src/FloatLiteral.lf @@ -1,11 +1,12 @@ -target Python; -// This test verifies that floating-point literals are handled -// correctly. +target Python + +# This test verifies that floating-point literals are handled correctly. main reactor { state N(6.0221409e+23) state charge(-1.6021766E-19) state minus_epsilon(-.01e0) state expected(.964853323188E5) + reaction(startup) {= F = - self.N * self.charge if abs(F - self.expected) < abs(self.minus_epsilon): diff --git a/test/Python/src/Gain.lf b/test/Python/src/Gain.lf index 48e7af9d3b..c5d5604e09 100644 --- a/test/Python/src/Gain.lf +++ b/test/Python/src/Gain.lf @@ -1,15 +1,19 @@ -// Example in the Wiki. -target Python; +# Example in the Wiki. +target Python + reactor Scale(scale(2)) { - input x; - output y; - reaction(x) -> y {= - y.set(x.value * self.scale) - =} + input x + + output y + + reaction(x) -> y {= y.set(x.value * self.scale) =} } + reactor Test { - input x; - state received_value(0); + input x + + state received_value(0) + reaction(x) {= print("Received " + str(x.value)) self.received_value = True @@ -17,19 +21,20 @@ reactor Test { sys.stderr.write("ERROR: Expected 2!") exit(1) =} + reaction(shutdown) {= if self.received_value is None: sys.stderr.write("ERROR: No value received by Test reactor!") else: sys.stderr.write("Test passes.") - =} } + main reactor Gain { - g = new Scale(); - d = new Test(); - g.y -> d.x; - reaction(startup) -> g.x {= - g.x.set(1) - =} + g = new Scale() + d = new Test() + + g.y -> d.x + + reaction(startup) -> g.x {= g.x.set(1) =} } diff --git a/test/Python/src/GetMicroStep.lf b/test/Python/src/GetMicroStep.lf index 8dd7c0e841..715c3cb543 100644 --- a/test/Python/src/GetMicroStep.lf +++ b/test/Python/src/GetMicroStep.lf @@ -1,18 +1,14 @@ -// Tests the get_microstep() function in the python target. -target Python { - fast: false -}; +# Tests the get_microstep() function in the python target. +target Python { fast: false } + main reactor GetMicroStep { - preamble {= - import sys - =} - state s(1); + preamble {= import sys =} - // timer t(0, 1 msec); - logical action l; - reaction(startup) -> l {= - l.schedule(0); - =} + logical action l # timer t(0, 1 msec); + + state s(1) + + reaction(startup) -> l {= l.schedule(0); =} reaction(l) -> l {= microstep = get_microstep() diff --git a/test/Python/src/GetTime.lf b/test/Python/src/GetTime.lf index ed03f3afb5..36add49f69 100644 --- a/test/Python/src/GetTime.lf +++ b/test/Python/src/GetTime.lf @@ -1,11 +1,10 @@ -// This file includes code documented on the Wiki. -// For this test, success is just compiling and running. -target Python { - timeout: 2 sec, - fast: false -}; +# This file includes code documented on the Wiki. For this test, success is just +# compiling and running. +target Python { timeout: 2 sec, fast: false } + main reactor GetTime { - timer t(0, 1 sec); + timer t(0, 1 sec) + reaction(t) {= logical = lf.time.logical() print("Logical time is ", logical) diff --git a/test/Python/src/Hello.lf b/test/Python/src/Hello.lf index 7042482877..098c6078df 100644 --- a/test/Python/src/Hello.lf +++ b/test/Python/src/Hello.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target Python { - timeout: 10 sec, - fast: true -}; -reactor Reschedule(period(2 secs), message("Hello Python")) { - state count(0); - state previous_time(0); - timer t(1 secs, period); - logical action a; +# This test checks that logical time is incremented an appropriate amount as a +# result of an invocation of the schedule() function at runtime. It also +# performs various smoke tests of timing aligned reactions. The first instance +# has a period of 4 seconds, the second of 2 seconds, and the third (composite) +# or 1 second. +target Python { timeout: 10 sec, fast: true } + +reactor Reschedule(period(2 sec), message("Hello Python")) { + timer t(1 sec, period) + + logical action a + + state count(0) + state previous_time(0) + reaction(t) -> a {= print(self.message) a.schedule(MSEC(200)) @@ -21,6 +22,7 @@ reactor Reschedule(period(2 secs), message("Hello Python")) { print("Current time is ", self.previous_time) print("Which is {:f} Plus {:d} nanoseconds.\n".format(secs, self.previous_time % BILLION)) =} + reaction(a) {= self.count += 1 print("***** action {:d} at time {:d}\n".format(self.count, lf.time.logical())) @@ -34,11 +36,16 @@ reactor Reschedule(period(2 secs), message("Hello Python")) { exit(1) =} } + reactor Inside(period(1 sec), message("Composite default message.")) { - third_instance = new Reschedule(period = period, message = message); + third_instance = new Reschedule(period = period, message = message) } + main reactor Hello { - first_instance = new Reschedule(period = 4 sec, message = "Hello from first_instance."); - second_instance = new Reschedule(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new Reschedule( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new Reschedule(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/Python/src/HelloWorld.lf b/test/Python/src/HelloWorld.lf index 7b260fc474..ff0addacec 100644 --- a/test/Python/src/HelloWorld.lf +++ b/test/Python/src/HelloWorld.lf @@ -1,12 +1,13 @@ -target Python { - tracing: true -}; +target Python { tracing: true } + reactor HelloWorld2 { - state success(False); + state success(False) + reaction(startup) {= print("Hello World.") self.success = True =} + reaction(shutdown) {= print("Shutdown invoked.") if not self.success: @@ -14,6 +15,7 @@ reactor HelloWorld2 { sys.exit(1) =} } + main reactor HelloWorld { - a = new HelloWorld2(); + a = new HelloWorld2() } diff --git a/test/Python/src/Hierarchy.lf b/test/Python/src/Hierarchy.lf index 143f06fe01..e34ad926e1 100644 --- a/test/Python/src/Hierarchy.lf +++ b/test/Python/src/Hierarchy.lf @@ -1,22 +1,28 @@ -// Test data transport across hierarchy. -target Python; +# Test data transport across hierarchy. +target Python + reactor Source { - output out; - timer t; - reaction(t) -> out {= - out.set(1) - =} + output out + + timer t + + reaction(t) -> out {= out.set(1) =} } + reactor Gain { - input _in; - output out; + input _in + + output out + reaction(_in) -> out {= print("Gain received ", _in.value) out.set(_in.value * 2) =} } + reactor Print { - input _in; + input _in + reaction(_in) {= print("Received: ", _in.value) if _in.value != 2: @@ -24,21 +30,27 @@ reactor Print { exit(1) =} } + reactor GainContainer { - input _in; - output out; - output out2; - gain = new Gain(); - _in -> gain._in; - gain.out -> out; - gain.out -> out2; + input _in + + output out + output out2 + + gain = new Gain() + + _in -> gain._in + gain.out -> out + gain.out -> out2 } + main reactor Hierarchy { - source = new Source(); - container = new GainContainer(); - print = new Print(); - print2 = new Print(); - source.out -> container._in; - container.out -> print._in; - container.out -> print2._in; + source = new Source() + container = new GainContainer() + print = new Print() + print2 = new Print() + + source.out -> container._in + container.out -> print._in + container.out -> print2._in } diff --git a/test/Python/src/Hierarchy2.lf b/test/Python/src/Hierarchy2.lf index 4e8e3717ee..a24bc39c2e 100644 --- a/test/Python/src/Hierarchy2.lf +++ b/test/Python/src/Hierarchy2.lf @@ -1,28 +1,33 @@ -// Test data transport across hierarchy. -target Python { - timeout: 5 sec, - fast: true -}; +# Test data transport across hierarchy. +target Python { timeout: 5 sec, fast: true } + reactor Source { - output out; - timer t(0, 1 sec); - reaction(t) -> out {= - out.set(1) - =} + output out + + timer t(0, 1 sec) + + reaction(t) -> out {= out.set(1) =} } + reactor Count { - output out; - timer t(0, 1 sec); - state i(0); + output out + + timer t(0, 1 sec) + + state i(0) + reaction(t) -> out {= self.i += 1 out.set(self.i) =} } + reactor Add { - input in1; - input in2; - output out; + input in1 + input in2 + + output out + reaction(in1, in2) -> out {= result = 0 if in1.is_present: @@ -32,9 +37,12 @@ reactor Add { out.set(result) =} } + reactor Print { - input _in; - state expected(2); + input _in + + state expected(2) + reaction(_in) {= print("Received: ", _in.value) if _in.value != self.expected: @@ -43,19 +51,25 @@ reactor Print { self.expected+=1 =} } + reactor AddCount { - input _in; - output out; - count = new Count(); - add = new Add(); - _in -> add.in1; - count.out -> add.in2; - add.out -> out; + input _in + + output out + + count = new Count() + add = new Add() + + _in -> add.in1 + count.out -> add.in2 + add.out -> out } + main reactor Hierarchy2 { - source = new Source(); - addCount = new AddCount(); - print = new Print(); - source.out -> addCount._in; - addCount.out -> print._in; + source = new Source() + addCount = new AddCount() + print = new Print() + + source.out -> addCount._in + addCount.out -> print._in } diff --git a/test/Python/src/IdentifierLength.lf b/test/Python/src/IdentifierLength.lf index c38c0951ef..7df83ccdfc 100644 --- a/test/Python/src/IdentifierLength.lf +++ b/test/Python/src/IdentifierLength.lf @@ -1,21 +1,27 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Python { - timeout: 10 sec, - fast: true -}; -reactor A_Really_Long_Name_For_A_Source_But_Not_Quite_255_Characters_Which_Is_The_Maximum_For_The_Python_Target(period(2 sec)) { - output y; - timer t(1 sec, period); - state count(0); +# This test connects a simple counting source to tester that checks against its +# own count. +target Python { timeout: 10 sec, fast: true } + +reactor A_Really_Long_Name_For_A_Source_But_Not_Quite_255_Characters_Which_Is_The_Maximum_For_The_Python_Target( + period(2 sec) +) { + output y + + timer t(1 sec, period) + + state count(0) + reaction(t) -> y {= self.count += 1 y.set(self.count) =} } + reactor Another_Really_Long_Name_For_A_Test_Class { - input x; - state count(0); + input x + + state count(0) + reaction(x) {= self.count += 1 print("Received ", x.value) @@ -24,8 +30,16 @@ reactor Another_Really_Long_Name_For_A_Test_Class { exit(1) =} } + main reactor IdentifierLength { - a_really_long_name_for_a_source_instance = new A_Really_Long_Name_For_A_Source_But_Not_Quite_255_Characters_Which_Is_The_Maximum_For_The_Python_Target(); - another_really_long_name_for_a_test_instance = new Another_Really_Long_Name_For_A_Test_Class(); - a_really_long_name_for_a_source_instance.y -> another_really_long_name_for_a_test_instance.x; + a_really_long_name_for_a_source_instance = new A_Really_Long_Name_For_A_Source_But_Not_Quite_255_Characters_Which_Is_The_Maximum_For_The_Python_Target( + + ) + another_really_long_name_for_a_test_instance = new Another_Really_Long_Name_For_A_Test_Class( + + ) + + a_really_long_name_for_a_source_instance.y -> + another_really_long_name_for_a_test_instance.x + ; } diff --git a/test/Python/src/Import.lf b/test/Python/src/Import.lf index 723b437f25..ee2f91e51a 100644 --- a/test/Python/src/Import.lf +++ b/test/Python/src/Import.lf @@ -1,12 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; +# This tests the ability to import a reactor definition that itself imports a +# reactor definition. +target Python + import Imported from "lib/Imported.lf" main reactor Import { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - a.x.set(42) - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= a.x.set(42) =} } diff --git a/test/Python/src/ImportComposition.lf b/test/Python/src/ImportComposition.lf index ffbd2d2795..eebc113199 100644 --- a/test/Python/src/ImportComposition.lf +++ b/test/Python/src/ImportComposition.lf @@ -1,14 +1,16 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; -import ImportedComposition from "lib/ImportedComposition.lf"; +# This tests the ability to import a reactor definition that itself imports a +# reactor definition. +target Python + +import ImportedComposition from "lib/ImportedComposition.lf" main reactor ImportComposition { - a = new ImportedComposition(); - state received(false); - reaction(startup) -> a.x {= - a.x.set(42) - =} + a = new ImportedComposition() + + state received(false) + + reaction(startup) -> a.x {= a.x.set(42) =} + reaction(a.y) {= receive_time = lf.time.logical_elapsed() print("Received {:d} at time {:d}".format(a.y.value, receive_time)) @@ -20,6 +22,7 @@ main reactor ImportComposition { sys.stderr.write("ERROR: Received value should have been {:d}.\n".format(42 * 2 * 2)) exit(2) =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write("ERROR: Nothing received.\n"); diff --git a/test/Python/src/ImportRenamed.lf b/test/Python/src/ImportRenamed.lf index 0dcf72e571..942ea4350b 100644 --- a/test/Python/src/ImportRenamed.lf +++ b/test/Python/src/ImportRenamed.lf @@ -1,16 +1,17 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; +# This tests the ability to import a reactor definition that itself imports a +# reactor definition. +target Python + import Imported as X from "lib/Imported.lf" import Imported as Y from "lib/Imported.lf" import ImportedAgain as Z from "lib/ImportedAgain.lf" + main reactor { - timer t; - a = new X(); - b = new Y(); - c = new Z(); + timer t + + a = new X() + b = new Y() + c = new Z() - reaction(t) -> a.x {= - a.x.set(42) - =} + reaction(t) -> a.x {= a.x.set(42) =} } diff --git a/test/Python/src/ManualDelayedReaction.lf b/test/Python/src/ManualDelayedReaction.lf index 6a2e08362c..d70f5c9157 100644 --- a/test/Python/src/ManualDelayedReaction.lf +++ b/test/Python/src/ManualDelayedReaction.lf @@ -1,42 +1,39 @@ target Python { - keepalive: false // Set keepalive to false since - // this is a test and schedule is - // called on a physical action from - // within a reaction. This is one of - // the special rare cases where the - // user might want to manually override - // keepalive. -}; - -// That's the stuff that shall be generated for the after + # Set keepalive to false since this is a test and schedule is called on a + # physical action from within a reaction. This is one of the special rare + # cases where the user might want to manually override keepalive. + keepalive: false +} + +# That's the stuff that shall be generated for the after reactor GeneratedDelay { - input y_in; - output y_out; - state y_state(0); + input y_in + + output y_out - // TODO: delay in act or the schedule call? - physical action act(0 msec); + physical action act(0 msec) # TODO: delay in act or the schedule call? + + state y_state(0) reaction(y_in) -> act {= self.y_state = y_in.value act.schedule(MSEC(100)) =} - reaction(act) -> y_out {= - y_out.set(self.y_state) - =} + reaction(act) -> y_out {= y_out.set(self.y_state) =} } + reactor Source { - output out; - timer t; - // reaction(t) -> out after 100 msec {= - reaction(t) -> out {= - out.set(1) - =} + output out + + timer t + + reaction(t) -> out {= out.set(1) =} # reaction(t) -> out after 100 msec {= } reactor Sink { - input s_in; + input s_in + reaction(s_in) {= elapsed_logical = lf.time.logical_elapsed() logical = lf.time.logical() @@ -45,15 +42,14 @@ reactor Sink { if elapsed_logical < MSEC(100): sys.stderr.write("Expected {:d} but got {:d}.\n".format(MSEC(100), elapsed_logical)) exit(1) - =} deadline(200 msec) {= =} + =} deadline(200 msec) {= =} } + main reactor ManualDelayedReaction { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); - - // source.out -> sink.s_in; - // rewritten above - source.out -> g.y_in; - g.y_out -> sink.s_in; + source = new Source() + sink = new Sink() + g = new GeneratedDelay() + + source.out -> g.y_in # source.out -> sink.s_in; rewritten above + g.y_out -> sink.s_in } diff --git a/test/Python/src/Microsteps.lf b/test/Python/src/Microsteps.lf index 2bcdd6c831..95a1f85429 100644 --- a/test/Python/src/Microsteps.lf +++ b/test/Python/src/Microsteps.lf @@ -1,7 +1,9 @@ -target Python; +target Python + reactor Destination { - input x; - input y; + input x + input y + reaction(x, y) {= elapsed = lf.time.logical_elapsed() print("Time since start: ", elapsed) @@ -20,15 +22,18 @@ reactor Destination { exit(1) =} } + main reactor Microsteps { - timer start; - logical action repeat; - d = new Destination(); + timer start + + logical action repeat + + d = new Destination() + reaction(start) -> d.x, repeat {= d.x.set(1) repeat.schedule(0) =} - reaction(repeat) -> d.y {= - d.y.set(1) - =} + + reaction(repeat) -> d.y {= d.y.set(1) =} } diff --git a/test/Python/src/Minimal.lf b/test/Python/src/Minimal.lf index 62c985ae2b..63b089c41c 100644 --- a/test/Python/src/Minimal.lf +++ b/test/Python/src/Minimal.lf @@ -1,7 +1,6 @@ -// This is a smoke test of a minimal reactor. -target Python; +# This is a smoke test of a minimal reactor. +target Python + main reactor Minimal { - reaction(startup) {= - print("Hello World.") - =} + reaction(startup) {= print("Hello World.") =} } diff --git a/test/Python/src/MovingAverage.lf b/test/Python/src/MovingAverage.lf index b507eb846d..6add156db6 100644 --- a/test/Python/src/MovingAverage.lf +++ b/test/Python/src/MovingAverage.lf @@ -1,27 +1,30 @@ -// Demonstration of a state variable that is a list. -// The MovingAverage reactor computes the moving average of the last -// four inputs and produces that as output. The source is a counting -// sequence. -target Python { - timeout: 1 sec, - fast: true -}; +# Demonstration of a state variable that is a list. The MovingAverage reactor +# computes the moving average of the last four inputs and produces that as +# output. The source is a counting sequence. +target Python { timeout: 1 sec, fast: true } + import TestDouble from "lib/Test.lf" reactor MASource { - output out; - state count(0); - timer clock(0, 200 msec); + output out + + timer clock(0, 200 msec) + + state count(0) + reaction(clock) -> out {= out.set(self.count) self.count +=1 =} } + reactor MovingAverageImpl { - state delay_line(0.0, 0.0, 0.0); - state index(0); - input m_in; - output out; + input m_in + + output out + + state delay_line(0.0, 0.0, 0.0) + state index(0) reaction(m_in) -> out {= # Calculate the output. @@ -41,9 +44,10 @@ reactor MovingAverageImpl { } main reactor MovingAverage { - s = new MASource(); - m = new MovingAverageImpl(); - p = new TestDouble(expected=(0.0, 0.25, 0.75, 1.5, 2.5, 3.5)); - s.out -> m.m_in; - m.out -> p.t_in; + s = new MASource() + m = new MovingAverageImpl() + p = new TestDouble(expected = (0.0, 0.25, 0.75, 1.5, 2.5, 3.5)) + + s.out -> m.m_in + m.out -> p.t_in } diff --git a/test/Python/src/MultipleContained.lf b/test/Python/src/MultipleContained.lf index fdf42e54ed..1927da2941 100644 --- a/test/Python/src/MultipleContained.lf +++ b/test/Python/src/MultipleContained.lf @@ -1,14 +1,17 @@ -// Test that a reaction can react to and send two multiple -// ports of a contained reactor. -target Python; +# Test that a reaction can react to and send two multiple ports of a contained +# reactor. +target Python + reactor Contained { - output trigger; - state count(0); - input in1; - input in2; - reaction(startup) -> trigger {= - trigger.set(42) - =} + input in1 + input in2 + + output trigger + + state count(0) + + reaction(startup) -> trigger {= trigger.set(42) =} + reaction(in1) {= print("in1 received ", in1.value); if in1.value != 42: @@ -16,6 +19,7 @@ reactor Contained { exit(1) self.count += 1 =} + reaction(in2) {= print("in2 received ", in2.value) if in2.value != 42: @@ -23,14 +27,17 @@ reactor Contained { exit(1) self.count += 1 =} + reaction(shutdown) {= if self.count != 2: sys.stderr.write("FAILED: Should have received two inputs.\n") exit(1) =} } + main reactor MultipleContained { - c = new Contained(); + c = new Contained() + reaction(c.trigger) -> c.in1, c.in2 {= c.in1.set(c.trigger.value) c.in2.set(c.trigger.value) diff --git a/test/Python/src/NativeListsAndTimes.lf b/test/Python/src/NativeListsAndTimes.lf index 6fd6a8bfd3..1b18a01c43 100644 --- a/test/Python/src/NativeListsAndTimes.lf +++ b/test/Python/src/NativeListsAndTimes.lf @@ -1,26 +1,28 @@ -target Python; +target Python -// This test passes if it is successfully compiled into valid target code. +# This test passes if it is successfully compiled into valid target code. +main reactor( + x(0), + y(0), # Units are missing but not required + z(1 msec), # Type is missing but not required + p(1, 2, 3, 4), # List of integers + q(1 msec, 2 msec, 3 msec), # list of time values + r({= 0 =}), # Zero-valued target code also is a valid time + g(1 msec, 2 msec) # List of time values +) { + timer tick(0) # Units missing but not required + timer tock(1 sec) # Implicit type time + timer toe(z) # Implicit type time + + state s(y) # Reference to explicitly typed time parameter + state t(z) # Reference to implicitly typed time parameter + state v # Uninitialized boolean state variable + state w # Uninitialized time state variable + state baz(p) # Implicit type int[] + state period(z) # Implicit type time + state bar(1 msec, 2 msec, 3 msec) # list of time values + state notype(1, 2, 3, 4) -main reactor(x(0), - y(0), // Units are missing but not required - z(1 msec), // Type is missing but not required - p(1, 2, 3, 4), // List of integers - q(1 msec, 2 msec, 3 msec), // list of time values - r({=0=}), // Zero-valued target code also is a valid time - g(1 msec, 2 msec) // List of time values - ) { - state s(y); // Reference to explicitly typed time parameter - state t(z); // Reference to implicitly typed time parameter - state v; // Uninitialized boolean state variable - state w; // Uninitialized time state variable - timer tick(0); // Units missing but not required - timer tock(1 sec); // Implicit type time - timer toe(z); // Implicit type time - state baz(p); // Implicit type int[] - state period(z); // Implicit type time - state bar(1 msec, 2 msec, 3 msec); // list of time values - state notype(1, 2, 3, 4); reaction(tick) {= # Target code =} diff --git a/test/Python/src/ParameterizedState.lf b/test/Python/src/ParameterizedState.lf index 87b285e5aa..3511c8d2f5 100644 --- a/test/Python/src/ParameterizedState.lf +++ b/test/Python/src/ParameterizedState.lf @@ -1,12 +1,11 @@ -target Python; +target Python reactor Foo(bar(42)) { - state baz(bar); + state baz(bar) - reaction (startup) {= - print("Baz: ", self.baz) - =} + reaction(startup) {= print("Baz: ", self.baz) =} } + main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/Python/src/PeriodicDesugared.lf b/test/Python/src/PeriodicDesugared.lf index 4228544db9..cd7776e4c1 100644 --- a/test/Python/src/PeriodicDesugared.lf +++ b/test/Python/src/PeriodicDesugared.lf @@ -1,13 +1,8 @@ -target Python { - fast: true, - timeout: 1 sec -}; +target Python { fast: true, timeout: 1 sec } -main reactor( - offset(0), - period(500 msec)) { - logical action init(offset); - logical action recur(period); +main reactor(offset(0), period(500 msec)) { + logical action init(offset) + logical action recur(period) reaction(startup) -> init, recur {= if self.offset == 0: diff --git a/test/Python/src/PingPong.lf b/test/Python/src/PingPong.lf index dba29d7f47..6198d2a45f 100644 --- a/test/Python/src/PingPong.lf +++ b/test/Python/src/PingPong.lf @@ -1,53 +1,61 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * Ping introduces a microstep delay using a logical action - * to break the causality loop. + * Ping introduces a microstep delay using a logical action to break the + * causality loop. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec + * Unthreaded: 97 msec Threaded: 265 msec * - * There is no parallelism in this application, so it does not benefit from being - * being threaded, just some additional overhead. + * There is no parallelism in this application, so it does not benefit from + * being being threaded, just some additional overhead. * * These measurements are total execution time, including startup and shutdown. - * These are about an order of magnitude faster than anything reported in the paper. + * These are about an order of magnitude faster than anything reported in the + * paper. * * @author Edward A. Lee */ -target Python { - fast: true -}; +target Python { fast: true } + reactor Ping(count(10)) { - input receive; - output send; - state pingsLeft(count); - logical action serve; - reaction (startup, serve) -> send {= + input receive + + output send + + logical action serve + + state pingsLeft(count) + + reaction(startup, serve) -> send {= send.set(self.pingsLeft) self.pingsLeft -= 1 =} - reaction (receive) -> serve {= + + reaction(receive) -> serve {= if self.pingsLeft > 0: serve.schedule(0) else: request_stop() =} } + reactor Pong(expected(10)) { - input receive; - output send; - state count(0); + input receive + + output send + + state count(0) + reaction(receive) -> send {= self.count += 1 send.set(receive.value) =} + reaction(shutdown) {= if self.count != self.expected: sys.stderr.write( @@ -62,8 +70,9 @@ reactor Pong(expected(10)) { } main reactor PingPong { - ping = new Ping(); - pong = new Pong(); - ping.send -> pong.receive; - pong.send -> ping.receive; + ping = new Ping() + pong = new Pong() + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/Python/src/Pipeline.lf b/test/Python/src/Pipeline.lf index 760f1eb5d1..5d318880f9 100644 --- a/test/Python/src/Pipeline.lf +++ b/test/Python/src/Pipeline.lf @@ -1,12 +1,11 @@ -target Python { - timeout: 2 sec -}; +target Python { timeout: 2 sec } reactor TakeTime { - input _in; - output out; - reaction(_in) -> out {= + input _in + + output out + reaction(_in) -> out {= offset = 0 for i in range(10000): offset+=1 @@ -16,9 +15,11 @@ reactor TakeTime { } reactor Print { - input _in; - state count(0); - state received(0); + input _in + + state count(0) + state received(0) + reaction(_in) {= self.received += 1 print("Received: {:d} at logical time {:d}".format(_in.value, lf.time.logical_elapsed())) @@ -27,6 +28,7 @@ reactor Print { exit(1) self.count+=1 =} + reaction(shutdown) {= if self.received == 0: sys.stderr.write("ERROR: Final reactor received no data.\n") @@ -35,22 +37,23 @@ reactor Print { } main reactor Pipeline { - timer t(0, 200 msec); - state count(0); + timer t(0, 200 msec) + + c1 = new TakeTime() + c2 = new TakeTime() + c3 = new TakeTime() + c4 = new TakeTime() + p = new Print() - c1 = new TakeTime(); - c2 = new TakeTime(); - c3 = new TakeTime(); - c4 = new TakeTime(); - p = new Print(); + c1.out -> c2._in after 200 msec + c2.out -> c3._in after 200 msec + c3.out -> c4._in after 200 msec + c4.out -> p._in + + state count(0) reaction(t) -> c1._in {= c1._in.set(self.count) self.count += 1 =} - - c1.out -> c2._in after 200 msec; - c2.out -> c3._in after 200 msec; - c3.out -> c4._in after 200 msec; - c4.out -> p._in; } diff --git a/test/Python/src/Preamble.lf b/test/Python/src/Preamble.lf index 7e95efa3ca..00ec7e538d 100644 --- a/test/Python/src/Preamble.lf +++ b/test/Python/src/Preamble.lf @@ -1,16 +1,16 @@ -// Preambles are put inside the Python reactor class -// Therefore, accessing them requires the use of self. -target Python { - timeout: 2 sec, - fast: true -}; +# Preambles are put inside the Python reactor class Therefore, accessing them +# requires the use of self. +target Python { timeout: 2 sec, fast: true } + main reactor Preamble { preamble {= import platform def add_42(self, i): return i + 42 =} - timer t; + + timer t + reaction(t) {= s = "42"; i = int(s) diff --git a/test/Python/src/ReadOutputOfContainedReactor.lf b/test/Python/src/ReadOutputOfContainedReactor.lf index c2f49112f3..c1a249961d 100644 --- a/test/Python/src/ReadOutputOfContainedReactor.lf +++ b/test/Python/src/ReadOutputOfContainedReactor.lf @@ -1,16 +1,18 @@ -// Test reacting to and reading outputs from a contained -// reactor in various permutations. +# Test reacting to and reading outputs from a contained reactor in various +# permutations. +target Python -target Python; reactor Contained { - output out; - reaction(startup) -> out {= - out.set(42) - =} + output out + + reaction(startup) -> out {= out.set(42) =} } + main reactor ReadOutputOfContainedReactor { - c = new Contained(); - state count(0); + c = new Contained() + + state count(0) + reaction(startup) c.out {= print("Startup reaction reading output of contained reactor: ", c.out.value) if c.out.value != 42: @@ -18,6 +20,7 @@ main reactor ReadOutputOfContainedReactor { exit(2) self.count += 1 =} + reaction(c.out) {= print("Reading output of contained reactor:", c.out.value) if c.out.value != 42: @@ -25,6 +28,7 @@ main reactor ReadOutputOfContainedReactor { exit(3) self.count += 1 =} + reaction(startup, c.out) {= print("Alternate triggering reading output of contained reactor: ", c.out.value) if c.out.value != 42: @@ -32,6 +36,7 @@ main reactor ReadOutputOfContainedReactor { exit(4) self.count += 1 =} + reaction(shutdown) {= if self.count != 3: print("FAILURE: One of the reactions failed to trigger.\n") diff --git a/test/Python/src/Schedule.lf b/test/Python/src/Schedule.lf index 05f555bbb7..976a9768fb 100644 --- a/test/Python/src/Schedule.lf +++ b/test/Python/src/Schedule.lf @@ -1,11 +1,13 @@ -// Example from Schedule section of the C Reactor Target wiki page. -target Python; +# Example from Schedule section of the C Reactor Target wiki page. +target Python + reactor Schedule2 { - input x; - logical action a; - reaction(x) -> a {= - a.schedule(MSEC(200)) - =} + input x + + logical action a + + reaction(x) -> a {= a.schedule(MSEC(200)) =} + reaction(a) {= elapsed_time = lf.time.logical_elapsed() print("Action triggered at logical time {:d} nsec after start.".format(elapsed_time)) @@ -14,10 +16,11 @@ reactor Schedule2 { exit(1) =} } + main reactor { - a = new Schedule2(); - timer t; - reaction(t) -> a.x {= - a.x.set(1) - =} + timer t + + a = new Schedule2() + + reaction(t) -> a.x {= a.x.set(1) =} } diff --git a/test/Python/src/ScheduleLogicalAction.lf b/test/Python/src/ScheduleLogicalAction.lf index 8b5b90237f..5da1e42e32 100644 --- a/test/Python/src/ScheduleLogicalAction.lf +++ b/test/Python/src/ScheduleLogicalAction.lf @@ -1,25 +1,28 @@ -// This checks that a logical action is scheduled the specified -// logical time after the current logical time. -target Python { - fast: true, - timeout: 3 sec -}; +# This checks that a logical action is scheduled the specified logical time +# after the current logical time. +target Python { fast: true, timeout: 3 sec } + reactor foo { - input x; - output y; - logical action a; + input x + + output y + + logical action a + reaction(x) -> y, a {= y.set(2*x.value) # The following uses physical time, incorrectly. a.schedule(MSEC(500)) =} - reaction(a) -> y {= - y.set(-42) - =} + + reaction(a) -> y {= y.set(-42) =} } + reactor print { - state expected_time(0); - input x; + input x + + state expected_time(0) + reaction(x) {= elapsed_time = lf.time.logical_elapsed() print("Result is ", x.value) @@ -31,12 +34,14 @@ reactor print { self.expected_time += MSEC(500) =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42) - =} - f.y -> p.x; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x + + reaction(t) -> f.x {= f.x.set(42) =} } diff --git a/test/Python/src/ScheduleValue.lf b/test/Python/src/ScheduleValue.lf index e51431954c..a8f97e6ff3 100644 --- a/test/Python/src/ScheduleValue.lf +++ b/test/Python/src/ScheduleValue.lf @@ -1,13 +1,14 @@ /** Test of schedule_value. */ -target Python { - timeout: 3 sec -}; +target Python { timeout: 3 sec } + main reactor ScheduleValue { - logical action a; + logical action a + reaction(startup) -> a {= value = "Hello" a.schedule(0, value) =} + reaction(a) {= print("Received: ", a.value) if a.value != "Hello": diff --git a/test/Python/src/SelfLoop.lf b/test/Python/src/SelfLoop.lf index 903641372d..e5f8497455 100644 --- a/test/Python/src/SelfLoop.lf +++ b/test/Python/src/SelfLoop.lf @@ -1,16 +1,19 @@ -target Python { - timeout: 1 sec, - fast: true -}; +target Python { timeout: 1 sec, fast: true } + reactor Self { - input x; - output y; - logical action a; - state expected(43); + input x + + output y + + logical action a + + state expected(43) + reaction(a) -> y {= print("a = ", a.value) y.set(a.value + 1) =} + reaction(x) -> a {= print("x = ", x.value) if x.value != self.expected: @@ -19,16 +22,18 @@ reactor Self { self.expected += 1 a.schedule(MSEC(100), x.value) =} - reaction(startup) -> a {= - a.schedule(0, 42) - =} + + reaction(startup) -> a {= a.schedule(0, 42) =} + reaction(shutdown) {= if self.expected <= 43: sys.stderr.write("Received no data.\n") exit(2) =} } + main reactor SelfLoop { - u = new Self(); - u.y -> u.x; + u = new Self() + + u.y -> u.x } diff --git a/test/Python/src/SendingInside.lf b/test/Python/src/SendingInside.lf index 2951b4b6e6..fd400260f3 100644 --- a/test/Python/src/SendingInside.lf +++ b/test/Python/src/SendingInside.lf @@ -1,12 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. -target Python { - timeout: 10 sec, - fast: true -}; +# This tests a reactor that contains another reactor and also has its own +# reaction that routes inputs to the contained reactor. +target Python { timeout: 10 sec, fast: true } + reactor Printer { - input x; - state count(1); + input x + + state count(1) + reaction(x) {= print("Inside reactor received: ", x.value) if x.value != self.count: @@ -15,10 +15,14 @@ reactor Printer { self.count += 1 =} } + main reactor SendingInside { - state count(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count(0) + reaction(t) -> p.x {= self.count += 1 p.x.set(self.count) diff --git a/test/Python/src/SendingInside2.lf b/test/Python/src/SendingInside2.lf index 67efc98fc0..24aaa95c93 100644 --- a/test/Python/src/SendingInside2.lf +++ b/test/Python/src/SendingInside2.lf @@ -1,6 +1,8 @@ -target Python; +target Python + reactor Printer { - input x; + input x + reaction(x) {= print("Inside reactor received: ", x.value) if x.value != 1: @@ -8,10 +10,11 @@ reactor Printer { exit(1) =} } + main reactor SendingInside2 { - timer t; - p = new Printer(); - reaction(t) -> p.x {= - p.x.set(1) - =} + timer t + + p = new Printer() + + reaction(t) -> p.x {= p.x.set(1) =} } diff --git a/test/Python/src/SetArray.lf b/test/Python/src/SetArray.lf index e07ed0aba7..f2fb5d7bec 100644 --- a/test/Python/src/SetArray.lf +++ b/test/Python/src/SetArray.lf @@ -1,16 +1,17 @@ -// This tests passing lists as port values -// This tests the use of the "polymorphic" delay reactor on a struct. -// It delays by a logical time any pointer datatype. -target Python; +# This tests passing lists as port values This tests the use of the +# "polymorphic" delay reactor on a struct. It delays by a logical time any +# pointer datatype. +target Python + reactor Source { - output out; - reaction(startup) -> out {= - out.set([0,1,2]) - =} + output out + + reaction(startup) -> out {= out.set([0,1,2]) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input _in + reaction(_in) {= print("Recieved ", _in.value) if _in.value != [self.scale*count for count in range(len(_in.value))]: @@ -18,8 +19,10 @@ reactor Print(scale(1)) { exit(1) =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/SimpleDeadline.lf b/test/Python/src/SimpleDeadline.lf index e82def7afe..2e82fae06f 100644 --- a/test/Python/src/SimpleDeadline.lf +++ b/test/Python/src/SimpleDeadline.lf @@ -1,10 +1,13 @@ -// Test local deadline, where a deadline is associated with a reaction -// definition. This test triggers a reaction exactly once with a -// deadline violation. -target Python; +# Test local deadline, where a deadline is associated with a reaction +# definition. This test triggers a reaction exactly once with a deadline +# violation. +target Python + reactor Deadline(threshold(100 msec)) { - input x; - output deadlineViolation; + input x + + output deadlineViolation + reaction(x) -> deadlineViolation {= sys.stderr.write("ERROR: Deadline violation was not detected!\n") exit(1) @@ -13,21 +16,26 @@ reactor Deadline(threshold(100 msec)) { deadlineViolation.set(True) =} } + reactor Print { - input _in; + input _in + reaction(_in) {= if _in.value is True: print("Output successfully produced by deadline handler.") =} } + main reactor SimpleDeadline { - timer start; - d = new Deadline(threshold = 10 msec); - p = new Print(); - d.deadlineViolation -> p._in; - preamble {= - import time - =} + preamble {= import time =} + + timer start + + d = new Deadline(threshold = 10 msec) + p = new Print() + + d.deadlineViolation -> p._in + reaction(start) -> d.x {= self.time.sleep(0.02) d.x.set(42) diff --git a/test/Python/src/SimpleImport.lf b/test/Python/src/SimpleImport.lf index 89a141676a..1183070e24 100644 --- a/test/Python/src/SimpleImport.lf +++ b/test/Python/src/SimpleImport.lf @@ -1,7 +1,8 @@ -target Python; -import HelloWorld2 from "HelloWorld.lf"; +target Python + +import HelloWorld2 from "HelloWorld.lf" main reactor SimpleImport { - a = new HelloWorld2(); - b = new HelloWorld2(); + a = new HelloWorld2() + b = new HelloWorld2() } diff --git a/test/Python/src/SlowingClock.lf b/test/Python/src/SlowingClock.lf index 903289ca02..1f24fdd7a5 100644 --- a/test/Python/src/SlowingClock.lf +++ b/test/Python/src/SlowingClock.lf @@ -1,20 +1,18 @@ -/** Output events at logical times 100, 300, 600, and 1000 msec - * after the start time. - * This uses a logical action with a minimum delay of - * 100 msec and additional delays provided as arguments - * to the schedule() function. +/** + * Output events at logical times 100, 300, 600, and 1000 msec after the start + * time. This uses a logical action with a minimum delay of 100 msec and + * additional delays provided as arguments to the schedule() function. */ -target Python { - timeout: 1 sec, - fast: true -}; +target Python { timeout: 1 sec, fast: true } + main reactor SlowingClock { - logical action a(100 msec); - state interval(100 msec); - state expected_time(100 msec); - reaction(startup) -> a {= - a.schedule(0) - =} + logical action a(100 msec) + + state interval(100 msec) + state expected_time(100 msec) + + reaction(startup) -> a {= a.schedule(0) =} + reaction(a) -> a {= elapsed_logical_time = lf.time.logical_elapsed() print("Logical time since start: {:d} nsec.\n".format(elapsed_logical_time)) @@ -26,6 +24,7 @@ main reactor SlowingClock { self.expected_time += MSEC(100) + self.interval self.interval += MSEC(100) =} + reaction(shutdown) {= if self.expected_time != MSEC(1500): sys.stderr.write("ERROR: Expected the next expected time to be: 1500000000 nsec.\n") diff --git a/test/Python/src/SlowingClockPhysical.lf b/test/Python/src/SlowingClockPhysical.lf index 5db5120b92..994dfb9d9d 100644 --- a/test/Python/src/SlowingClockPhysical.lf +++ b/test/Python/src/SlowingClockPhysical.lf @@ -1,25 +1,27 @@ -/** Output events at physical times at least 100, 300, and 600 - * msec after the start time. - * This uses a physical action with a minimum interarrival time of - * 100 msec. The reactor increases the interarrival time with each - * invocation of the schedule() function. - * The timestamps of the events will be exact because the physical - * time at which schedule() is called is always way smaller than - * the time of the last invocation (or start time) plus the minimum - * interarrival time. Hence, the minimum interarrival time always - * determines the time of the next event. +/** + * Output events at physical times at least 100, 300, and 600 msec after the + * start time. This uses a physical action with a minimum interarrival time of + * 100 msec. The reactor increases the interarrival time with each invocation of + * the schedule() function. The timestamps of the events will be exact because + * the physical time at which schedule() is called is always way smaller than + * the time of the last invocation (or start time) plus the minimum interarrival + * time. Hence, the minimum interarrival time always determines the time of the + * next event. */ -target Python { - timeout: 1500 msec -}; +target Python { timeout: 1500 msec } + main reactor SlowingClockPhysical { - physical action a(100 msec, 100 msec); // first offset and minimum interarrival time. - state interval(100 msec); - state expected_time(100 msec); + # first offset and minimum interarrival time. + physical action a(100 msec, 100 msec) + + state interval(100 msec) + state expected_time(100 msec) + reaction(startup) -> a {= self.expected_time = MSEC(100) a.schedule(0) =} + reaction(a) -> a {= elapsed_logical_time = lf.time.logical_elapsed() print("Logical time since start: {:d} nsec.".format(elapsed_logical_time)) @@ -31,6 +33,7 @@ main reactor SlowingClockPhysical { a.schedule(self.interval) print("Scheduling next to occur after: {:d} nsec.".format(self.interval)) =} + reaction(shutdown) {= if self.expected_time < MSEC(500): sys.stderr.write("ERROR: Expected the next expected time to be at least: 500000000 nsec.\n"); diff --git a/test/Python/src/StartupOutFromInside.lf b/test/Python/src/StartupOutFromInside.lf index 3dc35b4dfc..e539f6b63e 100644 --- a/test/Python/src/StartupOutFromInside.lf +++ b/test/Python/src/StartupOutFromInside.lf @@ -1,14 +1,14 @@ -target Python; +target Python reactor Bar { - output out; - reaction(startup) -> out {= - out.set(42) - =} + output out + + reaction(startup) -> out {= out.set(42) =} } main reactor StartupOutFromInside { - bar = new Bar(); + bar = new Bar() + reaction(startup) bar.out {= print("Output from bar: ", bar.out.value) if bar.out.value != 42: diff --git a/test/Python/src/Stride.lf b/test/Python/src/Stride.lf index cac64a4304..e7db640b6b 100644 --- a/test/Python/src/Stride.lf +++ b/test/Python/src/Stride.lf @@ -1,21 +1,25 @@ -// This example illustrates state variables and parameters on the wiki. -// For this test, success is just compiling and running. -target Python { - timeout: 2 sec, - fast: true -}; +# This example illustrates state variables and parameters on the wiki. For this +# test, success is just compiling and running. +target Python { timeout: 2 sec, fast: true } + reactor Count(stride(1)) { - state count(1); - output y; - timer t(0, 100 msec); + output y + + timer t(0, 100 msec) + + state count(1) + reaction(t) -> y {= y.set(self.count) self.count += self.stride =} } + reactor Display { - input x; - state expected(1); // for testing. + input x + + state expected(1) # for testing. + reaction(x) {= print("Received: ", x.value) if x.value != self.expected: @@ -23,8 +27,10 @@ reactor Display { self.expected += 2 =} } + main reactor Stride { - c = new Count(stride = 2); - d = new Display(); - c.y -> d.x; + c = new Count(stride = 2) + d = new Display() + + c.y -> d.x } diff --git a/test/Python/src/StructAsState.lf b/test/Python/src/StructAsState.lf index 06e40465c5..f8fece3c94 100644 --- a/test/Python/src/StructAsState.lf +++ b/test/Python/src/StructAsState.lf @@ -1,5 +1,7 @@ -// Check that a state variable can have a statically initialized struct as a value. -target Python; +# Check that a state variable can have a statically initialized struct as a +# value. +target Python + main reactor StructAsState { preamble {= class hello: @@ -7,7 +9,9 @@ main reactor StructAsState { self.name = name self.value = value =} - state s ({=self.hello("Earth", 42) =}); + + state s({= self.hello("Earth", 42) =}) + reaction(startup) {= print("State s.name=\"{:s}\", value={:d}.".format(self.s.name, self.s.value)) if self.s.value != 42: diff --git a/test/Python/src/StructAsType.lf b/test/Python/src/StructAsType.lf index 1f6645e672..a673adee44 100644 --- a/test/Python/src/StructAsType.lf +++ b/test/Python/src/StructAsType.lf @@ -1,20 +1,19 @@ -target Python {files: include/hello.py}; +target Python { files: include/hello.py } -preamble {= -import hello -=} +preamble {= import hello =} reactor Source { - output out; + output out reaction(startup) -> out {= temp = hello.hello("Earth", 42) out.set(temp) =} } -// expected parameter is for testing. -reactor Print(expected(42)) { - input _in; + +reactor Print(expected(42)) { # expected parameter is for testing. + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}\n".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -22,8 +21,10 @@ reactor Print(expected(42)) { exit(1) =} } + main reactor StructAsType { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/StructAsTypeDirect.lf b/test/Python/src/StructAsTypeDirect.lf index 490ca61a6b..bbd6218e4f 100644 --- a/test/Python/src/StructAsTypeDirect.lf +++ b/test/Python/src/StructAsTypeDirect.lf @@ -1,11 +1,10 @@ -target Python {files: include/hello.py}; +target Python { files: include/hello.py } -preamble {= -import hello -=} +preamble {= import hello =} reactor Source { - output out; + output out + reaction(startup) -> out {= out_value = out.value out_value = hello.hello() @@ -14,9 +13,10 @@ reactor Source { out.set(out_value) =} } -// expected parameter is for testing. -reactor Print(expected(42)) { - input _in; + +reactor Print(expected(42)) { # expected parameter is for testing. + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -24,8 +24,10 @@ reactor Print(expected(42)) { exit(1) =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/StructParallel.lf b/test/Python/src/StructParallel.lf index 194f4c8b11..acac67d4c0 100644 --- a/test/Python/src/StructParallel.lf +++ b/test/Python/src/StructParallel.lf @@ -1,14 +1,14 @@ -// Source allocates a class object and then sends it to two reactors, -// each of which want to modify it. -target Python {files: ["include/hello.py"]}; -import Source from "StructScale.lf"; +# Source allocates a class object and then sends it to two reactors, each of +# which want to modify it. +target Python { files: ["include/hello.py"] } -preamble {= -import hello -=} +import Source from "StructScale.lf" + +preamble {= import hello =} reactor Check(expected(42)) { - input _in; + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -18,10 +18,12 @@ reactor Check(expected(42)) { } reactor Print(scale(2)) { - // Mutable keyword indicates that this reactor wants a writable copy of the input. - mutable input _in; + # Mutable keyword indicates that this reactor wants a writable copy of the + # input. + mutable input _in + + output out - output out; reaction(_in) -> out {= print(_in.value.value) _in.value.value *= self.scale; @@ -29,15 +31,15 @@ reactor Print(scale(2)) { =} } - main reactor StructParallel { - s = new Source(); - c1 = new Print(); - c2 = new Print(scale = 3); - p1 = new Check(expected = 84); - p2 = new Check(expected = 126); - s.out -> c1._in; - s.out -> c2._in; - c1.out -> p1._in; - c2.out -> p2._in; + s = new Source() + c1 = new Print() + c2 = new Print(scale = 3) + p1 = new Check(expected = 84) + p2 = new Check(expected = 126) + + s.out -> c1._in + s.out -> c2._in + c1.out -> p1._in + c2.out -> p2._in } diff --git a/test/Python/src/StructPrint.lf b/test/Python/src/StructPrint.lf index 3fdb642abe..7ec1396e35 100644 --- a/test/Python/src/StructPrint.lf +++ b/test/Python/src/StructPrint.lf @@ -1,21 +1,18 @@ -// Source produces a dynamically allocated class object, which it passes -// to Print. Reference counting ensures that the struct is freed. -target Python {files: ["include/hello.py"]}; +# Source produces a dynamically allocated class object, which it passes to +# Print. Reference counting ensures that the struct is freed. +target Python { files: ["include/hello.py"] } -preamble {= -import hello -=} +preamble {= import hello =} reactor Print { - output out; - reaction(startup) -> out {= - out.set(hello.hello("Earth", 42)) - =} + output out + + reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} } -// expected parameter is for testing. -reactor Check(expected(42)) { - input _in; +reactor Check(expected(42)) { # expected parameter is for testing. + input _in + reaction(_in) {= print("Received: name = {:s}, value = {:d}\n".format(_in.value.name, _in.value.value)) if _in.value.value != self.expected: @@ -25,7 +22,8 @@ reactor Check(expected(42)) { } main reactor { - s = new Print(); - p = new Check(); - s.out -> p._in; + s = new Print() + p = new Check() + + s.out -> p._in } diff --git a/test/Python/src/StructScale.lf b/test/Python/src/StructScale.lf index 283a8129f1..ff86e8fc65 100644 --- a/test/Python/src/StructScale.lf +++ b/test/Python/src/StructScale.lf @@ -1,23 +1,17 @@ -// Source produces a dynamically allocated class object, which it passes -// to Scale. Scale modifies it and passes it to Print. -target Python {files: ["include/hello.py"]}; +# Source produces a dynamically allocated class object, which it passes to +# Scale. Scale modifies it and passes it to Print. +target Python { files: ["include/hello.py"] } -preamble {= -import hello -=} +preamble {= import hello =} reactor Source { - output out; - reaction(startup) -> out {= - out.set(hello.hello("Earth", 42)) - =} -} - -// expected parameter is for testing. -reactor TestInput(expected(42)) { + output out + reaction(startup) -> out {= out.set(hello.hello("Earth", 42)) =} +} - input _in; +reactor TestInput(expected(42)) { # expected parameter is for testing. + input _in reaction(_in) {= print("Received: name = {:s}, value = {:d}\n".format(_in.value.name, _in.value.value)) @@ -28,10 +22,12 @@ reactor TestInput(expected(42)) { } reactor Print(scale(2)) { - // Mutable keyword indicates that this reactor wants a writable copy of the input. - mutable input _in; + # Mutable keyword indicates that this reactor wants a writable copy of the + # input. + mutable input _in + + output out - output out; reaction(_in) -> out {= _in.value.value *= self.scale; out.set(_in.value) @@ -39,9 +35,10 @@ reactor Print(scale(2)) { } main reactor StructScale { - s = new Source(); - c = new Print(); - p = new TestInput(expected=84); - s.out -> c._in; - c.out -> p._in; + s = new Source() + c = new Print() + p = new TestInput(expected = 84) + + s.out -> c._in + c.out -> p._in } diff --git a/test/Python/src/SubclassesAndStartup.lf b/test/Python/src/SubclassesAndStartup.lf index f99923ae3e..9dae1495be 100644 --- a/test/Python/src/SubclassesAndStartup.lf +++ b/test/Python/src/SubclassesAndStartup.lf @@ -1,11 +1,13 @@ -target Python; +target Python reactor Super { - state count(0); - reaction (startup) {= + state count(0) + + reaction(startup) {= print("{:s}(Super) started".format(self.name)) self.count += 1 =} + reaction(shutdown) {= if self.count == 0: sys.stderr.write("No startup reaction was invoked!\n") @@ -14,7 +16,7 @@ reactor Super { } reactor SubA(name("SubA")) extends Super { - reaction (startup) {= + reaction(startup) {= print("{:s} started".format(self.name)) if self.count == 0: sys.stderr.write("Base class startup reaction was not invoked!\n") @@ -23,7 +25,7 @@ reactor SubA(name("SubA")) extends Super { } reactor SubB(name("SubB")) extends Super { - reaction (startup) {= + reaction(startup) {= print("{:s} started".format(self.name)) if self.count == 0: sys.stderr.write("Base class startup reaction was not invoked!\n") @@ -32,6 +34,6 @@ reactor SubB(name("SubB")) extends Super { } main reactor SubclassesAndStartup { - a = new SubA(); - b = new SubB(); + a = new SubA() + b = new SubB() } diff --git a/test/Python/src/TestForPreviousOutput.lf b/test/Python/src/TestForPreviousOutput.lf index 149c62b992..40fdda2095 100644 --- a/test/Python/src/TestForPreviousOutput.lf +++ b/test/Python/src/TestForPreviousOutput.lf @@ -1,11 +1,11 @@ -// This tests the mechanism for testing whether a previous reaction has -// produced a given output. The output should always be 42. -target Python; +# This tests the mechanism for testing whether a previous reaction has produced +# a given output. The output should always be 42. +target Python + reactor Source { - output out; - preamble {= - import random - =} + preamble {= import random =} + + output out reaction(startup) -> out {= # Set a seed for random number generation based on the current time. @@ -14,6 +14,7 @@ reactor Source { if self.random.choice([0,1]) == 1: out.set(21) =} + reaction(startup) -> out {= if out.is_present: out.set(2 * out.value) @@ -21,8 +22,10 @@ reactor Source { out.set(42) =} } + reactor Sink { - input _in; + input _in + reaction(_in) {= print("Received ", _in.value) if _in.value != 42: @@ -30,8 +33,10 @@ reactor Sink { exit(1) =} } + main reactor TestForPreviousOutput { - s = new Source(); - d = new Sink(); - s.out -> d._in; + s = new Source() + d = new Sink() + + s.out -> d._in } diff --git a/test/Python/src/TimeLimit.lf b/test/Python/src/TimeLimit.lf index 5d457cb8fe..3ccd147047 100644 --- a/test/Python/src/TimeLimit.lf +++ b/test/Python/src/TimeLimit.lf @@ -1,28 +1,31 @@ -// Test that the stop function can be used to internally impose a -// a time limit. -// This is also used to test performance (number of reactions per second). -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt or getting the wrong data. -// On a 2.6 GHz Intel Core i7 running MacOS Mojave, using a single core, -// this executes 10,000,000 cycles (two reactions in each cycle) in 0.74 seconds, -// for over 27 million reactions per second. -// This translates to 37 nanoseconds per reaction invocation. -target Python { - fast: true -}; +# Test that the stop function can be used to internally impose a a time limit. +# This is also used to test performance (number of reactions per second). +# Correct output for this 1, 2, 3, 4. Failure for this test is failing to halt +# or getting the wrong data. On a 2.6 GHz Intel Core i7 running MacOS Mojave, +# using a single core, this executes 10,000,000 cycles (two reactions in each +# cycle) in 0.74 seconds, for over 27 million reactions per second. This +# translates to 37 nanoseconds per reaction invocation. +target Python { fast: true } + reactor Clock(offset(0), period(1 sec)) { - output y; - timer t(offset, period); - state count(0); + output y + + timer t(offset, period) + + state count(0) + reaction(t) -> y {= self.count += 1 # print("Reacting at time ", lf.time.logical_elapsed()) y.set(self.count) =} } + reactor Destination { - input x; - state s(1); + input x + + state s(1) + reaction(x) {= # print(x.value) if x.value != self.s: @@ -30,6 +33,7 @@ reactor Destination { exit(1) self.s += 1 =} + reaction(shutdown) {= print("**** shutdown reaction invoked.") if self.s != 10000002: @@ -38,12 +42,14 @@ reactor Destination { print(f"Approx. time per reaction: {lf.time.physical_elapsed()/(self.s+1):.1f}ns") =} } + main reactor TimeLimit(period(1 usec)) { - timer stop(10 secs); - reaction(stop) {= - request_stop() - =} - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x + + reaction(stop) {= request_stop() =} } diff --git a/test/Python/src/TimeState.lf b/test/Python/src/TimeState.lf index a00c0e5095..c12318400b 100644 --- a/test/Python/src/TimeState.lf +++ b/test/Python/src/TimeState.lf @@ -1,13 +1,11 @@ -target Python; +target Python reactor Foo(bar(42)) { - state baz(500 msec); + state baz(500 msec) - reaction (startup) {= - print("Baz: ", self.baz) - =} + reaction(startup) {= print("Baz: ", self.baz) =} } main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/Python/src/Timers.lf b/test/Python/src/Timers.lf index 3b4b8c0d32..3346fc0ccc 100644 --- a/test/Python/src/Timers.lf +++ b/test/Python/src/Timers.lf @@ -1,19 +1,16 @@ -/** - * Test whether timers with different periods are triggered correctly. - */ -target Python { - timeout: 2 sec -}; +/** Test whether timers with different periods are triggered correctly. */ +target Python { timeout: 2 sec } + main reactor { - timer t(0, 1 sec); - timer t2(0, 2 sec); - state counter(0); - reaction(t2) {= - self.counter += 2 - =} - reaction(t) {= - self.counter -= 1 - =} + timer t(0, 1 sec) + timer t2(0, 2 sec) + + state counter(0) + + reaction(t2) {= self.counter += 2 =} + + reaction(t) {= self.counter -= 1 =} + reaction(shutdown) {= if self.counter != 1: sys.stderr.write("Error: Expected {:d} and got {:d}.\n".format(1, self.counter)) diff --git a/test/Python/src/TriggerDownstreamOnlyIfPresent.lf b/test/Python/src/TriggerDownstreamOnlyIfPresent.lf index b30a8986ba..f36d000cdd 100644 --- a/test/Python/src/TriggerDownstreamOnlyIfPresent.lf +++ b/test/Python/src/TriggerDownstreamOnlyIfPresent.lf @@ -1,15 +1,17 @@ /** - * This test checks that a downstream reaction is triggered only if its trigger is present. + * This test checks that a downstream reaction is triggered only if its trigger + * is present. */ -target Python { - timeout: 1 sec, - fast: true -}; +target Python { timeout: 1 sec, fast: true } + reactor Source { - output a; - output b; - state count(0); - timer t(0, 200 msec); + output a + output b + + timer t(0, 200 msec) + + state count(0) + reaction(t) -> a, b {= if (self.count % 2) == 0: a.set(self.count) @@ -17,14 +19,17 @@ reactor Source { b.set(self.count) =} } + reactor Destination { - input a; - input b; + input a + input b + reaction(a) {= if a.is_present is not True: sys.stderr.write("Reaction to a triggered even though all inputs are absent!\n") exit(1) =} + reaction(b) {= if b.is_present is not True: sys.stderr.write("Reaction to b triggered even though all inputs are absent!\n") @@ -33,8 +38,9 @@ reactor Destination { } main reactor TriggerDownstreamOnlyIfPresent { - s = new[2] Source(); - d = new[2] Destination(); - s.a -> d.a; - s.b -> d.b; + s = new[2] Source() + d = new[2] Destination() + + s.a -> d.a + s.b -> d.b } diff --git a/test/Python/src/TriggerDownstreamOnlyIfPresent2.lf b/test/Python/src/TriggerDownstreamOnlyIfPresent2.lf index b2c9210e41..16ed7509a8 100644 --- a/test/Python/src/TriggerDownstreamOnlyIfPresent2.lf +++ b/test/Python/src/TriggerDownstreamOnlyIfPresent2.lf @@ -1,14 +1,16 @@ /** - * This test checks that a downstream reaction is triggered only if its trigger is present. + * This test checks that a downstream reaction is triggered only if its trigger + * is present. */ -target Python { - timeout: 1 sec, - fast: true -}; +target Python { timeout: 1 sec, fast: true } + reactor Source { - output[2] out; - state count(0); - timer t(0, 200 msec); + output[2] out + + timer t(0, 200 msec) + + state count(0) + reaction(t) -> out {= if (self.count % 2) == 0: self.count += 1 @@ -17,20 +19,22 @@ reactor Source { out[1].set(self.count) =} } + reactor Destination { - input _in; + input _in + reaction(_in) {= if _in.is_present is not True: sys.stderr.write("Reaction to input of triggered even though all inputs are absent!\n") exit(1) =} - reaction(shutdown) {= - print("SUCCESS.") - =} + + reaction(shutdown) {= print("SUCCESS.") =} } main reactor TriggerDownstreamOnlyIfPresent2 { - s = new Source(); - d = new[2] Destination(); - s.out -> d._in; + s = new Source() + d = new[2] Destination() + + s.out -> d._in } diff --git a/test/Python/src/UnconnectedInput.lf b/test/Python/src/UnconnectedInput.lf index e08ec57a2a..a7ce61b18d 100644 --- a/test/Python/src/UnconnectedInput.lf +++ b/test/Python/src/UnconnectedInput.lf @@ -1,21 +1,25 @@ -// Test unconnected input. -target Python { - timeout: 5 sec, - fast: true -}; +# Test unconnected input. +target Python { timeout: 5 sec, fast: true } + reactor Source { - output out; - timer t(0, 1 sec); - state s(1); + output out + + timer t(0, 1 sec) + + state s(1) + reaction(t) -> out {= out.set(self.s) self.s += 1 =} } + reactor Add { - input in1; - input in2; - output out; + input in1 + input in2 + + output out + reaction(in1, in2) -> out {= result = 0 if in1.is_present: @@ -25,9 +29,12 @@ reactor Add { out.set(result) =} } + reactor Print { - input _in; - state expected(1); + input _in + + state expected(1) + reaction(_in) {= print("Received: ", _in.value) if _in.value != self.expected: @@ -37,10 +44,12 @@ reactor Print { self.expected +=1 =} } + main reactor UnconnectedInput { - source = new Source(); - add = new Add(); - print = new Print(); - source.out -> add.in2; - add.out -> print._in; + source = new Source() + add = new Add() + print = new Print() + + source.out -> add.in2 + add.out -> print._in } diff --git a/test/Python/src/Wcet.lf b/test/Python/src/Wcet.lf index 7ee84f1bee..5017f07149 100644 --- a/test/Python/src/Wcet.lf +++ b/test/Python/src/Wcet.lf @@ -1,18 +1,24 @@ -// Setup for WCET analysis of Worker -target Python; +# Setup for WCET analysis of Worker +target Python + reactor Source { - output out1; - output out2; - timer t; + output out1 + output out2 + + timer t + reaction(t) -> out1, out2 {= out1.set(5) out2.set(10) =} } + reactor Work { - input in1; - input in2; - output out; + input in1 + input in2 + + output out + reaction(in1, in2) -> out {= ret = 0 if in1.value > 10: @@ -22,19 +28,19 @@ reactor Work { out.set(ret) =} } + reactor Print { - input p_in; - reaction(p_in) {= - print("Received: ", p_in.value) - =} + input p_in + + reaction(p_in) {= print("Received: ", p_in.value) =} } main reactor Wcet { - source = new Source(); - work = new Work(); - print = new Print(); + source = new Source() + work = new Work() + print = new Print() - source.out1 -> work.in1; - source.out2 -> work.in2; - work.out -> print.p_in; + source.out1 -> work.in1 + source.out2 -> work.in2 + work.out -> print.p_in } diff --git a/test/Python/src/concurrent/AsyncCallback.lf b/test/Python/src/concurrent/AsyncCallback.lf index dcf9925d7c..69bd305e91 100644 --- a/test/Python/src/concurrent/AsyncCallback.lf +++ b/test/Python/src/concurrent/AsyncCallback.lf @@ -1,14 +1,11 @@ /** - * Test asynchronous callbacks that trigger a physical action. - * This test periodically creates a concurrent Python thread that - * schedule a physical action twice. + * Test asynchronous callbacks that trigger a physical action. This test + * periodically creates a concurrent Python thread that schedule a physical + * action twice. */ -target Python { - timeout: 2 sec -}; +target Python { timeout: 2 sec } main reactor AsyncCallback { - preamble {= # Note that preamble code is generated inside the reactor class in Python import time @@ -30,13 +27,15 @@ main reactor AsyncCallback { self.callback(a) return None =} - timer t(0, 200 msec); - state threads({=list()=}); - state expected_time(100 msec); - state toggle(false); - physical action a(100 msec); - state i(0); + timer t(0, 200 msec) + + physical action a(100 msec) + + state threads({= list() =}) + state expected_time(100 msec) + state toggle(false) + state i(0) reaction(t) -> a {= # start new thread, provide callback diff --git a/test/Python/src/concurrent/AsyncCallbackNoTimer.lf b/test/Python/src/concurrent/AsyncCallbackNoTimer.lf index 83b1933d39..ad9b79b473 100644 --- a/test/Python/src/concurrent/AsyncCallbackNoTimer.lf +++ b/test/Python/src/concurrent/AsyncCallbackNoTimer.lf @@ -1,20 +1,15 @@ /** - * Test asynchronous callbacks that trigger a physical action. - * This test creates a concurrent Python thread that schedule a - * physical action twice. + * Test asynchronous callbacks that trigger a physical action. This test creates + * a concurrent Python thread that schedule a physical action twice. * - * There are no timers in this test to drive the logical time forward. - * This is important in the Python target since the user Python threads - * should be allowed to execute independently of the underlying C core - * runtime, without the C runtime polling the Python context with a - * reaction to a timer. + * There are no timers in this test to drive the logical time forward. This is + * important in the Python target since the user Python threads should be + * allowed to execute independently of the underlying C core runtime, without + * the C runtime polling the Python context with a reaction to a timer. */ -target Python { - timeout: 2 sec -}; +target Python { timeout: 2 sec } main reactor { - preamble {= # Note that preamble code is generated inside the reactor class in Python import time @@ -35,15 +30,14 @@ main reactor { self.time.sleep(0.1) self.callback(a) return None - =} - state threads({=list()=}); - state expected_time(100 msec); - state toggle(false); + physical action a(100 msec) - physical action a(100 msec); - state i(0); + state threads({= list() =}) + state expected_time(100 msec) + state toggle(false) + state i(0) reaction(startup) -> a {= # start new thread, provide callback diff --git a/test/Python/src/docker/FilesPropertyContainerized.lf b/test/Python/src/docker/FilesPropertyContainerized.lf index 7a62a4e4e1..d67479e478 100644 --- a/test/Python/src/docker/FilesPropertyContainerized.lf +++ b/test/Python/src/docker/FilesPropertyContainerized.lf @@ -1,7 +1,4 @@ -target Python { - files: "../include/hello.py", - docker: true -}; +target Python { files: "../include/hello.py", docker: true } preamble {= try: @@ -17,12 +14,12 @@ main reactor { except: request_stop() =} - state passed(false); - timer t(1 msec); - reaction(t) {= - self.passed = True - =} + timer t(1 msec) + + state passed(false) + + reaction(t) {= self.passed = True =} reaction(shutdown) {= if not self.passed: diff --git a/test/Python/src/docker/HelloWorldContainerized.lf b/test/Python/src/docker/HelloWorldContainerized.lf index 20de3fe77e..760e5addfb 100644 --- a/test/Python/src/docker/HelloWorldContainerized.lf +++ b/test/Python/src/docker/HelloWorldContainerized.lf @@ -1,9 +1,7 @@ -target Python { - docker: true -}; +target Python { docker: true } import HelloWorld2 from "../HelloWorld.lf" main reactor { - a = new HelloWorld2(); + a = new HelloWorld2() } diff --git a/test/Python/src/docker/PingPongContainerized.lf b/test/Python/src/docker/PingPongContainerized.lf index 3f2a6a8c06..f8cf684fab 100644 --- a/test/Python/src/docker/PingPongContainerized.lf +++ b/test/Python/src/docker/PingPongContainerized.lf @@ -1,38 +1,34 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * Ping introduces a microstep delay using a logical action - * to break the causality loop. + * Ping introduces a microstep delay using a logical action to break the + * causality loop. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec + * Unthreaded: 97 msec Threaded: 265 msec * - * There is no parallelism in this application, so it does not benefit from being - * being threaded, just some additional overhead. + * There is no parallelism in this application, so it does not benefit from + * being being threaded, just some additional overhead. * * These measurements are total execution time, including startup and shutdown. - * These are about an order of magnitude faster than anything reported in the paper. + * These are about an order of magnitude faster than anything reported in the + * paper. * * @author Edward A. Lee */ -target Python { - fast: true, - docker: true -}; +target Python { fast: true, docker: true } import Ping from "../PingPong.lf" import Pong from "../PingPong.lf" - main reactor PingPongContainerized { - ping = new Ping(); - pong = new Pong(); - ping.send -> pong.receive; - pong.send -> ping.receive; + ping = new Ping() + pong = new Pong() + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/Python/src/docker/federated/DistributedCountContainerized.lf b/test/Python/src/docker/federated/DistributedCountContainerized.lf index 812ee15594..c29880e724 100644 --- a/test/Python/src/docker/federated/DistributedCountContainerized.lf +++ b/test/Python/src/docker/federated/DistributedCountContainerized.lf @@ -1,21 +1,23 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee */ target Python { timeout: 5 sec, logging: DEBUG, coordination: centralized, docker: true -}; +} -import Count from "../../lib/Count.lf"; +import Count from "../../lib/Count.lf" import Print from "../../federated/DistributedCount.lf" federated reactor DistributedCountContainerized(offset(200 msec)) at rti { - c = new Count(); - p = new Print(); - c.out -> p.in_ after offset; + c = new Count() + p = new Print() + + c.out -> p.in_ after offset } diff --git a/test/Python/src/docker/federated/DistributedDoublePortContainerized.lf b/test/Python/src/docker/federated/DistributedDoublePortContainerized.lf index f45e86d67f..89c45d1026 100644 --- a/test/Python/src/docker/federated/DistributedDoublePortContainerized.lf +++ b/test/Python/src/docker/federated/DistributedDoublePortContainerized.lf @@ -1,9 +1,7 @@ /** - * Test the case for when two upstream federates - * send messages to a downstream federte on two - * different ports. One message should carry a - * microstep delay relative to the other - * message. + * Test the case for when two upstream federates send messages to a downstream + * federte on two different ports. One message should carry a microstep delay + * relative to the other message. * * @author Soroush Bateni */ @@ -12,16 +10,17 @@ target Python { logging: DEBUG, coordination: centralized, docker: true -}; +} -import Count from "../../lib/Count.lf"; -import CountMicrostep from "../../federated/DistributedDoublePort.lf"; -import Print from "../../federated/DistributedDoublePort.lf"; +import Count from "../../lib/Count.lf" +import CountMicrostep from "../../federated/DistributedDoublePort.lf" +import Print from "../../federated/DistributedDoublePort.lf" federated reactor DistributedDoublePortContainerized at rti { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.out -> p.in_; // Indicating a 'logical' connection. - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.out -> p.in_ # Indicating a 'logical' connection. + cm.out -> p.in2 } diff --git a/test/Python/src/docker/federated/DistributedMultiportContainerized.lf b/test/Python/src/docker/federated/DistributedMultiportContainerized.lf index e70898ed77..c2723ce6b2 100644 --- a/test/Python/src/docker/federated/DistributedMultiportContainerized.lf +++ b/test/Python/src/docker/federated/DistributedMultiportContainerized.lf @@ -1,14 +1,11 @@ -// Check multiport connections between federates. -target Python { - timeout: 1 sec, - coordination: centralized, - docker: true -}; +# Check multiport connections between federates. +target Python { timeout: 1 sec, coordination: centralized, docker: true } -import Source, Destination from "../../federated/DistributedMultiport.lf"; +import Source, Destination from "../../federated/DistributedMultiport.lf" federated reactor DistributedMultiportContainerized at rti { - s = new Source(); - d = new Destination(); - s.out -> d.in_; + s = new Source() + d = new Destination() + + s.out -> d.in_ } diff --git a/test/Python/src/docker/federated/DistributedSendClassContainerized.lf b/test/Python/src/docker/federated/DistributedSendClassContainerized.lf index 0d5101784a..a060a421de 100644 --- a/test/Python/src/docker/federated/DistributedSendClassContainerized.lf +++ b/test/Python/src/docker/federated/DistributedSendClassContainerized.lf @@ -1,12 +1,10 @@ -target Python { - coordination: centralized, - docker: true -}; +target Python { coordination: centralized, docker: true } -import A, B from "../../federated/DistributedSendClass.lf"; +import A, B from "../../federated/DistributedSendClass.lf" federated reactor at rti { - a = new A(); - b = new B(); - b.o -> a.o; + a = new A() + b = new B() + + b.o -> a.o } diff --git a/test/Python/src/docker/federated/DistributedStopDecentralizedContainerized.lf b/test/Python/src/docker/federated/DistributedStopDecentralizedContainerized.lf index 40d550b83d..f94cc0edd7 100644 --- a/test/Python/src/docker/federated/DistributedStopDecentralizedContainerized.lf +++ b/test/Python/src/docker/federated/DistributedStopDecentralizedContainerized.lf @@ -1,17 +1,16 @@ /** - * Test for request_stop() in federated execution with decentralized coordination. + * Test for request_stop() in federated execution with decentralized + * coordination. * * @author Soroush Bateni */ -target Python { - coordination: decentralized, - docker: true -}; +target Python { coordination: decentralized, docker: true } import Sender, Receiver from "../../federated/DistributedStop.lf" federated reactor DistributedStopDecentralizedContainerized at rti { - sender = new Sender(); - receiver = new Receiver(); - sender.out -> receiver.in_; + sender = new Sender() + receiver = new Receiver() + + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/BroadcastFeedback.lf b/test/Python/src/federated/BroadcastFeedback.lf index 935a9bf03f..b66616968e 100644 --- a/test/Python/src/federated/BroadcastFeedback.lf +++ b/test/Python/src/federated/BroadcastFeedback.lf @@ -1,29 +1,32 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target Python { - timeout: 1 sec -}; +target Python { timeout: 1 sec } + reactor SenderAndReceiver { - output out; - input[2] inp; - state received(False); + input[2] inp + + output out + + state received(False) + + reaction(startup) -> out {= out.set(42) =} - reaction(startup) -> out {= - out.set(42) - =} reaction(inp) {= if inp[0].is_present and inp[1].is_present and inp[0].value == 42 and inp[1].value == 42: print("SUCCESS") self.received = True =} + reaction(shutdown) {= if not self.received: print("Failed to receive broadcast") sys.exit(1) =} } + federated reactor { - s = new[2] SenderAndReceiver(); - (s.out)+ -> s.inp; + s = new[2] SenderAndReceiver() + + (s.out)+ -> s.inp } diff --git a/test/Python/src/federated/BroadcastFeedbackWithHierarchy.lf b/test/Python/src/federated/BroadcastFeedbackWithHierarchy.lf index 999a607830..5ba40ff006 100644 --- a/test/Python/src/federated/BroadcastFeedbackWithHierarchy.lf +++ b/test/Python/src/federated/BroadcastFeedbackWithHierarchy.lf @@ -1,40 +1,44 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target Python { - timeout: 1 sec -}; +target Python { timeout: 1 sec } + reactor SenderAndReceiver { - output out; - input[2] in_; - state received(False); + input[2] in_ - reaction(startup) -> out {= - out.set(42) - =} + output out + + r = new Receiver() - r = new Receiver(); - in_ -> r.in_; + in_ -> r.in_ + + state received(False) + + reaction(startup) -> out {= out.set(42) =} } + reactor Receiver { - preamble {= - import sys - =} - input[2] in_; - state received(False); + preamble {= import sys =} + + input[2] in_ + + state received(False) reaction(in_) {= if in_[0].is_present and in_[1].is_present and in_[0].value == 42 and in_[1].value == 42: print("SUCCESS") self.received = True =} + reaction(shutdown) {= if not self.received: print("Failed to receive broadcast") self.sys.exit(1) =} } + federated reactor { - s = new[2] SenderAndReceiver(); - (s.out)+ -> s.in_; + s = new[2] SenderAndReceiver() + + (s.out)+ -> s.in_ } diff --git a/test/Python/src/federated/ChainWithDelay.lf b/test/Python/src/federated/ChainWithDelay.lf index 604259f446..ed267b33fc 100644 --- a/test/Python/src/federated/ChainWithDelay.lf +++ b/test/Python/src/federated/ChainWithDelay.lf @@ -3,17 +3,17 @@ * * @author Edward A. Lee */ -target Python { - timeout: 3 msec -} -import Count from "../lib/Count.lf"; -import InternalDelay from "../lib/InternalDelay.lf"; -import TestCount from "../lib/TestCount.lf"; +target Python { timeout: 3 msec } + +import Count from "../lib/Count.lf" +import InternalDelay from "../lib/InternalDelay.lf" +import TestCount from "../lib/TestCount.lf" federated reactor { - c = new Count(period = 1 msec); - i = new InternalDelay(delay = 500 usec); - t = new TestCount(num_inputs = 3); - c.out -> i.in_; - i.out -> t.in_; + c = new Count(period = 1 msec) + i = new InternalDelay(delay = 500 usec) + t = new TestCount(num_inputs = 3) + + c.out -> i.in_ + i.out -> t.in_ } diff --git a/test/Python/src/federated/CycleDetection.lf b/test/Python/src/federated/CycleDetection.lf index 4e4fd20998..815000a4f8 100644 --- a/test/Python/src/federated/CycleDetection.lf +++ b/test/Python/src/federated/CycleDetection.lf @@ -3,16 +3,16 @@ * introduce a cycle or not. The failure for this test is not being compiled. * @author Edward A. Lee */ -target Python; +target Python reactor CAReplica { - input local_update; - input remote_update; - input query; + input local_update + input remote_update + input query - state balance(0); + output response - output response; + state balance(0) reaction(local_update, remote_update) {= if local_update.is_present: @@ -21,20 +21,18 @@ reactor CAReplica { self.balance += remote_update.value =} - reaction(query) -> response {= - response.set(self.balance) - =} + reaction(query) -> response {= response.set(self.balance) =} } + reactor UserInput { - preamble {= - import sys - =} - input balance; - output deposit; + preamble {= import sys =} + + input balance + + output deposit + + reaction(startup) -> deposit {= deposit.set(100) =} - reaction(startup) -> deposit {= - deposit.set(100) - =} reaction(balance) {= if balance.value != 200: self.sys.stderr.write("Did not receive the expected balance. Expected: 200. Got: {}.\n".format(balance.value)) @@ -43,21 +41,19 @@ reactor UserInput { request_stop() =} - reaction(shutdown) {= - print("Test passed!") - =} + reaction(shutdown) {= print("Test passed!") =} } federated reactor { - u1 = new UserInput(); - r1 = new CAReplica(); - u2 = new UserInput(); - r2 = new CAReplica(); - (u1.deposit)+ -> r1.query, r1.local_update; - r1.response -> u1.balance; - u1.deposit -> r2.remote_update; - - (u2.deposit)+ -> r2.query, r2.local_update; - r2.response -> u2.balance; - u2.deposit -> r1.remote_update; + u1 = new UserInput() + r1 = new CAReplica() + u2 = new UserInput() + r2 = new CAReplica() + + (u1.deposit)+ -> r1.query, r1.local_update + r1.response -> u1.balance + u1.deposit -> r2.remote_update + (u2.deposit)+ -> r2.query, r2.local_update + r2.response -> u2.balance + u2.deposit -> r1.remote_update } diff --git a/test/Python/src/federated/DecentralizedP2PComm.lf b/test/Python/src/federated/DecentralizedP2PComm.lf index 2a8ec8b565..dcaba65983 100644 --- a/test/Python/src/federated/DecentralizedP2PComm.lf +++ b/test/Python/src/federated/DecentralizedP2PComm.lf @@ -6,30 +6,35 @@ target Python { } reactor Platform(start(0), expected_start(0), stp_offset_param(0)) { - preamble {= - import sys - =} - input in_; - output out; - timer t(0, 100 msec); - state count(start); - state expected(expected_start); + preamble {= import sys =} + + input in_ + + output out + + timer t(0, 100 msec) + + state count(start) + state expected(expected_start) + reaction(t) -> out {= out.set(self.count) self.count += 1 =} + reaction(in_) {= print("Received {}.".format(in_.value)) if in_.value != self.expected: self.sys.stderr.write("Expected {} but got {}.\n".format(self.expected_start, in_.value)) self.sys.exit(1) self.expected += 1 - =} STP (stp_offset_param) {= + =} STP(stp_offset_param){= print("Received {} late.".format(in_.value)) current_tag = get_current_tag() self.expected += 1 self.sys.stderr.write("STP offset was violated by ({}, {}).".format(current_tag.time - in_.intended_tag.time, current_tag.microstep - in_.intended_tag.microstep)) =} + reaction(shutdown) {= print("Shutdown invoked.") if self.expected == self.expected_start: @@ -37,9 +42,11 @@ reactor Platform(start(0), expected_start(0), stp_offset_param(0)) { self.sys.exit(1) =} } + federated reactor DecentralizedP2PComm { - a = new Platform(expected_start = 100, stp_offset_param = 10 msec); - b = new Platform(start = 100, stp_offset_param = 10 msec); - a.out -> b.in_; - b.out -> a.in_; + a = new Platform(expected_start = 100, stp_offset_param = 10 msec) + b = new Platform(start = 100, stp_offset_param = 10 msec) + + a.out -> b.in_ + b.out -> a.in_ } diff --git a/test/Python/src/federated/DecentralizedP2PUnbalancedTimeout.lf b/test/Python/src/federated/DecentralizedP2PUnbalancedTimeout.lf index 1e359bdd97..f18a31b8e6 100644 --- a/test/Python/src/federated/DecentralizedP2PUnbalancedTimeout.lf +++ b/test/Python/src/federated/DecentralizedP2PUnbalancedTimeout.lf @@ -1,41 +1,39 @@ /** - * Test a source-destination scenario where the source falls behind real-time, and reaches the - * timeout much later than the destination. In this test, the destination closes the connection - * early, causing the transmission to fail. Warnings will be printed about lost messages. + * Test a source-destination scenario where the source falls behind real-time, + * and reaches the timeout much later than the destination. In this test, the + * destination closes the connection early, causing the transmission to fail. + * Warnings will be printed about lost messages. * * The test fails if the federation does not exit. */ -target Python { - timeout: 1 msec, - coordination: decentralized -} - -// reason for failing: get_current_tag() not supported by the python target +target Python { timeout: 1 msec, coordination: decentralized } +# reason for failing: get_current_tag() not supported by the python target reactor Clock(offset(0), period(1 sec)) { - output y; - timer t(offset, period); - state count(0); + output y + + timer t(offset, period) + + state count(0) + reaction(t) -> y {= self.count += 1 print("Sending {}.".format(self.count)) y.set(self.count) =} - reaction(shutdown) {= - print("SUCCESS: the source exited successfully.") - =} + + reaction(shutdown) {= print("SUCCESS: the source exited successfully.") =} } + reactor Destination { - preamble {= - import sys - =} - input x; - state s(1); - state startup_logical_time; + preamble {= import sys =} - reaction(startup) {= - self.startup_logical_time = lf.time.logical() - =} + input x + + state s(1) + state startup_logical_time + + reaction(startup) {= self.startup_logical_time = lf.time.logical() =} reaction(x) {= print("Received {}".format(x.value)) @@ -52,8 +50,10 @@ reactor Destination { print("Approx. time per reaction: {}ns".format(lf.time.physical_elapsed()//(self.s+1))) =} } -federated reactor (period(10 usec)) { - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; + +federated reactor(period(10 usec)) { + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x } diff --git a/test/Python/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf b/test/Python/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf index fd5d7e6f42..acb8d2efd3 100644 --- a/test/Python/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf +++ b/test/Python/src/federated/DecentralizedP2PUnbalancedTimeoutPhysical.lf @@ -1,47 +1,52 @@ /** - * Test a source-destination scenario where the source falls behind real-time, and reaches the - * timeout much later than the destination. In this test, the destination closes the connection - * early, causing the transmission to fail. Warnings will be printed. + * Test a source-destination scenario where the source falls behind real-time, + * and reaches the timeout much later than the destination. In this test, the + * destination closes the connection early, causing the transmission to fail. + * Warnings will be printed. * - * The test fails if the federation does not exit amenably. - * This variant has a physical connection between source and destination. + * The test fails if the federation does not exit amenably. This variant has a + * physical connection between source and destination. */ -target Python { - timeout: 1 msec, - coordination: decentralized -} +target Python { timeout: 1 msec, coordination: decentralized } reactor Clock(offset(0), period(1 sec)) { - output y; - timer t(offset, period); - state count(0); + output y + + timer t(offset, period) + + state count(0) + reaction(t) -> y {= self.count += 1 y.set(self.count) =} - reaction(shutdown) {= - print("SUCCESS: the source exited successfully.") - =} + + reaction(shutdown) {= print("SUCCESS: the source exited successfully.") =} } + reactor Destination { - preamble {= - import sys - =} + preamble {= import sys =} + input x + state s(1) + reaction(x) {= if x.value != self.s: self.sys.stderr.write("Expected {} and got {}.".format(self.s, x.value)) self.sys.exit(1) self.s += 1 =} + reaction(shutdown) {= print("**** shutdown reaction invoked.") print("Approx. time per reaction: {}ns".format(lf.time.physical_elapsed()//(self.s+1))) =} } -federated reactor (period(10 usec)) { - c = new Clock(period = period); - d = new Destination(); - c.y ~> d.x; + +federated reactor(period(10 usec)) { + c = new Clock(period = period) + d = new Destination() + + c.y ~> d.x } diff --git a/test/Python/src/federated/DistributedBank.lf b/test/Python/src/federated/DistributedBank.lf index 8beda9ca85..8fbc2e2901 100644 --- a/test/Python/src/federated/DistributedBank.lf +++ b/test/Python/src/federated/DistributedBank.lf @@ -1,19 +1,18 @@ -// Check bank of federates. -target Python { - timeout: 1 sec, - coordination: centralized -}; +# Check bank of federates. +target Python { timeout: 1 sec, coordination: centralized } reactor Node { - preamble {= - import sys - =} - timer t(0, 100 msec); + preamble {= import sys =} + + timer t(0, 100 msec) + state count(0) + reaction(t) {= print("Hello world {}.".format(self.count)) self.count += 1 =} + reaction(shutdown) {= if self.count == 0: self.sys.stderr.write("Timer reactions did not execute.\n") @@ -22,5 +21,5 @@ reactor Node { } federated reactor DistributedBank { - n = new[2] Node(); + n = new[2] Node() } diff --git a/test/Python/src/federated/DistributedBankToMultiport.lf b/test/Python/src/federated/DistributedBankToMultiport.lf index 0c6f8a0128..e8c8dc154b 100644 --- a/test/Python/src/federated/DistributedBankToMultiport.lf +++ b/test/Python/src/federated/DistributedBankToMultiport.lf @@ -1,16 +1,15 @@ -// Check multiport to bank connections between federates. -target Python { - timeout: 3 sec -}; +# Check multiport to bank connections between federates. +target Python { timeout: 3 sec } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Destination { - preamble {= - import sys - =} - input[2] in_; - state count(1); + preamble {= import sys =} + + input[2] in_ + + state count(1) + reaction(in_) {= for i in range(len(in_)): print("Received {}.".format(in_[i].value)) @@ -19,6 +18,7 @@ reactor Destination { self.sys.exit(1) self.count += 1 =} + reaction(shutdown) {= if self.count == 0: self.sys.stderr.write("No data received.\n") @@ -27,7 +27,8 @@ reactor Destination { } federated reactor { - s = new[2] Count(); - d = new Destination(); - s.out -> d.in_; + s = new[2] Count() + d = new Destination() + + s.out -> d.in_ } diff --git a/test/Python/src/federated/DistributedCount.lf b/test/Python/src/federated/DistributedCount.lf index bbc8500c59..3c9a5cab9e 100644 --- a/test/Python/src/federated/DistributedCount.lf +++ b/test/Python/src/federated/DistributedCount.lf @@ -1,23 +1,21 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee */ -target Python { - timeout: 5 sec, - logging: DEBUG, - coordination: centralized -}; +target Python { timeout: 5 sec, logging: DEBUG, coordination: centralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - preamble {= - import sys - =} - input in_; - state c(1); + preamble {= import sys =} + + input in_ + + state c(1) + reaction(in_) {= elapsed_time = lf.time.logical_elapsed() print("At time {}, received {}".format(elapsed_time, in_.value)) @@ -29,6 +27,7 @@ reactor Print { self.sys.exit(1) self.c += 1 =} + reaction(shutdown) {= if self.c != 6: print("Expected to receive 5 items.") @@ -37,7 +36,8 @@ reactor Print { } federated reactor DistributedCount(offset(200 msec)) { - c = new Count(); - p = new Print(); - c.out -> p.in_ after offset; + c = new Count() + p = new Print() + + c.out -> p.in_ after offset } diff --git a/test/Python/src/federated/DistributedCountDecentralized.lf b/test/Python/src/federated/DistributedCountDecentralized.lf index 2d8b1c6a29..f32c5ef1f5 100644 --- a/test/Python/src/federated/DistributedCountDecentralized.lf +++ b/test/Python/src/federated/DistributedCountDecentralized.lf @@ -1,25 +1,22 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee */ +# reason for failing: in_.intended_tag are not supported in python target +target Python { timeout: 5 sec, coordination: decentralized } -// reason for failing: in_.intended_tag are not supported in python target - -target Python { - timeout: 5 sec, - coordination: decentralized -}; - -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - preamble {= - import sys - =} + preamble {= import sys =} + input in_ + state c(1) + reaction(in_) {= print(f"At tag ({lf.time.logical_elapsed()}, {lf.tag().microstep}), received {in_.value}. " f"The original intended tag of the message was ({in_.intended_tag.time-lf.time.start()}, {in_.intended_tag.microstep}).") @@ -31,6 +28,7 @@ reactor Print { self.sys.exit(3) self.c += 1 =} + reaction(shutdown) {= if self.c != 6: self.sys.stderr.write("Expected to receive 5 items.\n") @@ -40,8 +38,9 @@ reactor Print { } federated reactor DistributedCountDecentralized { - c = new Count(); - p = new Print(); - c.out -> p.in_ after 200 msec; // Indicating a 'logical' connection - // with a large enough delay. + c = new Count() + p = new Print() + + # Indicating a 'logical' connection with a large enough delay. + c.out -> p.in_ after 200 msec } diff --git a/test/Python/src/federated/DistributedCountDecentralizedLate.lf b/test/Python/src/federated/DistributedCountDecentralizedLate.lf index f6cdd4639f..c896d5b9b1 100644 --- a/test/Python/src/federated/DistributedCountDecentralizedLate.lf +++ b/test/Python/src/federated/DistributedCountDecentralizedLate.lf @@ -1,29 +1,27 @@ /** -* Test a form of a distributed deterministic system -* where a federate that receives timestamped messages has a timer in addition to the messages -* as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. -* @author Edward A. Lee -* @author Soroush Bateni -*/ -target Python { - timeout: 4900 msec, - coordination: decentralized -}; + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. + * @author Edward A. Lee + * @author Soroush Bateni + */ +target Python { timeout: 4900 msec, coordination: decentralized } -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor Print { - preamble {= - import sys - =} - input in_ // STP () - // STP(in, 30 msec); - state success(0) + preamble {= import sys =} + + input in_ # STP () + + timer t(0, 10 usec) # Force a timer to be invoke periodically + + state success(0) # STP(in, 30 msec); state success_stp_violation(0) - timer t(0, 10 usec) // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. + # to ensure logical time will advance in the absence of incoming messages. state c(0) + reaction(in_) {= current_tag = lf.tag() print("At tag ({}, {}) received {}. Intended tag is ({}, {}).".format( @@ -37,7 +35,7 @@ reactor Print { if (lf.tag() == Tag(SEC(1), 0)): self.success += 1 # Message was on-time self.c += 1 - =} STP (0) {= + =} STP(0){= current_tag = lf.tag() print("At tag ({}, {}), message has violated the STP offset by ({}, {}).".format( current_tag.time - lf.time.start(), current_tag.microstep, @@ -48,6 +46,7 @@ reactor Print { self.success_stp_violation += 1 self.c += 1 =} + reaction(t) {= # Do nothing. =} @@ -62,7 +61,8 @@ reactor Print { } federated reactor { - c = new Count(); - p = new Print(); - c.out -> p.in_; // Indicating a 'logical' connection. + c = new Count() + p = new Print() + + c.out -> p.in_ # Indicating a 'logical' connection. } diff --git a/test/Python/src/federated/DistributedCountDecentralizedLateDownstream.lf b/test/Python/src/federated/DistributedCountDecentralizedLateDownstream.lf index a1e8335cdd..ad85e5815d 100644 --- a/test/Python/src/federated/DistributedCountDecentralizedLateDownstream.lf +++ b/test/Python/src/federated/DistributedCountDecentralizedLateDownstream.lf @@ -1,39 +1,40 @@ -/** - * Test a form of a distributed deterministic system - * where a federate that receives timestamped messages has a timer in addition to the messages - * as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. - * In addition, this test shows that the STP violation is passed down the hierarchy until it is handled. - * - * An STP violation occurs if when a message with intended tag g1 arrives - * on a port p after the receiving federate has progressed far enough that - * it cannot process an event with tag g1 on the port p. - * This test has a fast timer (10 usec period) in the receiving federate - * so that the receiving federate is continually advancing its current tag, - * and hence an STP violation is more likely to occur. - * Furthermore, this test sets the STP threshold to 0, which makes the - * violation extremely likely to occur. It could still not occur, however, - * if the message arrives between ticks of the 10 usec timer. - * +/** + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. In addition, this test shows that the STP violation is + * passed down the hierarchy until it is handled. + * + * An STP violation occurs if when a message with intended tag g1 arrives on a + * port p after the receiving federate has progressed far enough that it cannot + * process an event with tag g1 on the port p. This test has a fast timer (10 + * usec period) in the receiving federate so that the receiving federate is + * continually advancing its current tag, and hence an STP violation is more + * likely to occur. Furthermore, this test sets the STP threshold to 0, which + * makes the violation extremely likely to occur. It could still not occur, + * however, if the message arrives between ticks of the 10 usec timer. + * * @author Edward A. Lee * @author Soroush Bateni */ - - target Python { - timeout: 1900 msec, // 9 msec headroom for the last (probably tardy) message to arrive. + # 9 msec headroom for the last (probably tardy) message to arrive. + timeout: 1900 msec, coordination: decentralized -}; +} -import Count from "../lib/Count.lf"; +import Count from "../lib/Count.lf" reactor ImportantActuator { - input inp; - state success(0); // Count messages that arrive without STP violation. - state success_stp_violation(0); - timer t(0, 10 usec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c(0); + input inp + + timer t(0, 10 usec) # Force a timer to be invoke periodically + + state success(0) # Count messages that arrive without STP violation. + state success_stp_violation(0) + # to ensure logical time will advance in the absence of incoming messages. + state c(0) + reaction(inp) {= current_tag = lf.tag() print(f"ImportantActuator: At tag ({lf.tag().time}, {lf.tag().microstep}) received {inp.value}. " @@ -41,23 +42,24 @@ reactor ImportantActuator { if lf.tag() == Tag((SEC(1) * self.c) + + lf.time.start(), 0): self.success += 1 # Message was on-time else: - self.sys.stderr.write("Normal reaction was invoked, but current tag doesn't match expected tag.") + self.sys.stderr.write("Normal reaction was invoked, but current tag doesn't match expected tag.") self.sys.exit(1) self.c += 1 - =} STP (0) {= + =} STP(0){= current_tag = lf.tag() print(f"ImportantActuator: At tag ({lf.time.logical_elapsed()}, {lf.tag().microstep}), message has violated the STP offset " f"by ({lf.tag().time - inp.intended_tag.time}, {lf.tag().microstep - inp.intended_tag.microstep}).") self.success_stp_violation += 1 self.c += 1 =} + reaction(t) {= # Do nothing. =} - + reaction(shutdown) {= if (self.success + self.success_stp_violation) != 2: - self.sys.stderr.write("Failed to detect STP violation in messages.") + self.sys.stderr.write("Failed to detect STP violation in messages.") self.sys.exit(1) else: print(f"Successfully detected STP violations ({self.success_stp_violation} violations, {self.success} on-time).") @@ -65,35 +67,39 @@ reactor ImportantActuator { } reactor Print { - input inp; + input inp + reaction(inp) {= - current_tag = lf.tag(); + current_tag = lf.tag(); print(f"Print reactor: at tag ({lf.time.logical_elapsed()}, lf.tag().microstep) received {inp.value}. " f"Intended tag is ({inp.intended_tag.time - lf.time.start()}, {inp.intended_tag.microstep}).") =} - } reactor Receiver { - input inp; - timer t(0, 10 msec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c(0); - p = new Print(); - a = new ImportantActuator(); + input inp + + timer t(0, 10 msec) # Force a timer to be invoke periodically + + p = new Print() + a = new ImportantActuator() + + # to ensure logical time will advance in the absence of incoming messages. + state c(0) + reaction(inp) -> p.inp, a.inp {= p.inp.set(inp.value + 1) a.inp.set(inp.value + 1) =} - + reaction(t) {= # Do nothing. =} } - + federated reactor { - c = new Count(period = 1 sec); - r = new Receiver(); - c.out -> r.inp; // Indicating a 'logical' connection. + c = new Count(period = 1 sec) + r = new Receiver() + + c.out -> r.inp # Indicating a 'logical' connection. } diff --git a/test/Python/src/federated/DistributedCountDecentralizedLateHierarchy.lf b/test/Python/src/federated/DistributedCountDecentralizedLateHierarchy.lf index 4ece12954c..b3fc170c56 100644 --- a/test/Python/src/federated/DistributedCountDecentralizedLateHierarchy.lf +++ b/test/Python/src/federated/DistributedCountDecentralizedLateHierarchy.lf @@ -1,41 +1,41 @@ -/** - * Test a form of a distributed deterministic system - * where a federate that receives timestamped messages has a timer in addition to the messages - * as triggers. Therefore, careful coordination of the advancement of time using Ptides is needed. - * In addition, this test shows that the STP violation of the reaction - * is passed down the hierarchy until it is handled. - * +/** + * Test a form of a distributed deterministic system where a federate that + * receives timestamped messages has a timer in addition to the messages as + * triggers. Therefore, careful coordination of the advancement of time using + * Ptides is needed. In addition, this test shows that the STP violation of the + * reaction is passed down the hierarchy until it is handled. + * * @author Edward A. Lee * @author Soroush Bateni */ - -target Python { - timeout: 4900 msec, - coordination: decentralized -}; - -import Count from "../lib/Count.lf"; +target Python { timeout: 4900 msec, coordination: decentralized } +import Count from "../lib/Count.lf" import ImportantActuator, Print from "DistributedCountDecentralizedLateDownstream.lf" reactor Receiver { - input inp; - timer t(0, 10 msec); // Force a timer to be invoke periodically - // to ensure logical time will advance in the - // absence of incoming messages. - state c(0); - p = new Print(); - a = new ImportantActuator(); - inp -> p.inp; - inp -> a.inp; - + input inp + + # Force a timer to be invoked periodically to ensure logical time will + # advance in the absence of incoming messages. + timer t(0, 10 msec) + + p = new Print() + a = new ImportantActuator() + + inp -> p.inp + inp -> a.inp + + state c(0) + reaction(t) {= # Do nothing. =} } federated reactor { - c = new Count(); - r = new Receiver(); - c.out -> r.inp; // Indicating a 'logical' connection. + c = new Count() + r = new Receiver() + + c.out -> r.inp # Indicating a 'logical' connection. } diff --git a/test/Python/src/federated/DistributedCountPhysical.lf b/test/Python/src/federated/DistributedCountPhysical.lf index 8c0d384e1d..6c1810af5c 100644 --- a/test/Python/src/federated/DistributedCountPhysical.lf +++ b/test/Python/src/federated/DistributedCountPhysical.lf @@ -1,31 +1,34 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages only over connections - * that are marked 'physical' (using the ~> arrow). - * Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages only over connections that are + * marked 'physical' (using the ~> arrow). Therefore, no additional coordination + * of the advancement of time (HLA or Ptides) is needed. * * @author Edward A. Lee * @author Soroush Bateni */ -target Python { - timeout: 1 sec -}; +target Python { timeout: 1 sec } + reactor Count { - timer t(200 msec, 1 sec); - state s(0); - output out; + output out + + timer t(200 msec, 1 sec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s += 1; =} } + reactor Print { - preamble {= - import sys - =} - input in_; - state c(0); + preamble {= import sys =} + + input in_ + + state c(0) + reaction(in_) {= elapsed_time = lf.time.logical_elapsed() print("At time {}, received {}.".format(elapsed_time, in_.value)) @@ -37,6 +40,7 @@ reactor Print { self.sys.exit(3) self.c += 1 =} + reaction(shutdown) {= if (self.c != 1): self.sys.stderr.write("ERROR: Expected to receive 1 item. Received {}.\n".format(self.c)) @@ -44,8 +48,10 @@ reactor Print { print("SUCCESS: Successfully received 1 item."); =} } + federated reactor at localhost { - c = new Count(); - p = new Print(); - c.out ~> p.in_; // Indicating a 'physical' connection. + c = new Count() + p = new Print() + + c.out ~> p.in_ # Indicating a 'physical' connection. } diff --git a/test/Python/src/federated/DistributedCountPhysicalAfterDelay.lf b/test/Python/src/federated/DistributedCountPhysicalAfterDelay.lf index 712515de24..1132ecfda6 100644 --- a/test/Python/src/federated/DistributedCountPhysicalAfterDelay.lf +++ b/test/Python/src/federated/DistributedCountPhysicalAfterDelay.lf @@ -1,31 +1,34 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages only over connections - * that are marked 'physical' (using the ~> arrow). - * Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages only over connections that are + * marked 'physical' (using the ~> arrow). Therefore, no additional coordination + * of the advancement of time (HLA or Ptides) is needed. * * @author Edward A. Lee * @author Soroush Bateni */ -target Python { - timeout: 1 sec -}; +target Python { timeout: 1 sec } + reactor Count { - timer t(200 msec, 1 sec); - state s(0); - output out; + output out + + timer t(200 msec, 1 sec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s += 1; =} } + reactor Print { - preamble {= - import sys - =} - input in_; - state c(0); + preamble {= import sys =} + + input in_ + + state c(0) + reaction(in_) {= elapsed_time = lf.time.logical_elapsed() print("At time {}, received {}.".format(elapsed_time, in_.value)) @@ -37,6 +40,7 @@ reactor Print { self.sys.exit(3) self.c += 1 =} + reaction(shutdown) {= if (self.c != 1): self.sys.stderr.write("ERROR: Expected to receive 1 item. Received {}.\n".format(self.c)) @@ -44,8 +48,10 @@ reactor Print { print("SUCCESS: Successfully received 1 item."); =} } + federated reactor at localhost { - c = new Count(); - p = new Print(); - c.out ~> p.in_ after 400 msec; // Indicating a 'physical' connection. + c = new Count() + p = new Print() + + c.out ~> p.in_ after 400 msec # Indicating a 'physical' connection. } diff --git a/test/Python/src/federated/DistributedCountPhysicalDecentralized.lf b/test/Python/src/federated/DistributedCountPhysicalDecentralized.lf index f78bc68366..847af85b80 100644 --- a/test/Python/src/federated/DistributedCountPhysicalDecentralized.lf +++ b/test/Python/src/federated/DistributedCountPhysicalDecentralized.lf @@ -1,33 +1,34 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages only over connections - * that are marked 'physical' (using the ~> arrow). - * Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages only over connections that are + * marked 'physical' (using the ~> arrow). Therefore, no additional coordination + * of the advancement of time (HLA or Ptides) is needed. * * @author Edward A. Lee * @author Soroush Bateni */ -target Python { - timeout: 1 sec, - coordination: decentralized -}; +target Python { timeout: 1 sec, coordination: decentralized } reactor Count { - timer t(200 msec, 1 sec); - state s(0); - output out; + output out + + timer t(200 msec, 1 sec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s += 1 =} } + reactor Print { - preamble {= - import sys - =} - input in_; - state c(0); + preamble {= import sys =} + + input in_ + + state c(0) + reaction(in_) {= elapsed_time = lf.time.logical_elapsed() print("At time {}, received {}.".format(elapsed_time, in_.value)) @@ -39,6 +40,7 @@ reactor Print { self.sys.exit(3) self.c += 1 =} + reaction(shutdown) {= if self.c != 1: self.sys.stderr.write("ERROR: Expected to receive 1 item. Received {}.\n".format(self.c)) @@ -46,8 +48,10 @@ reactor Print { print("SUCCESS: Successfully received 1 item.") =} } + federated reactor at localhost { - c = new Count(); - p = new Print(); - c.out ~> p.in_; // Indicating a 'physical' connection. + c = new Count() + p = new Print() + + c.out ~> p.in_ # Indicating a 'physical' connection. } diff --git a/test/Python/src/federated/DistributedDoublePort.lf b/test/Python/src/federated/DistributedDoublePort.lf index 0834edf343..f48a040893 100644 --- a/test/Python/src/federated/DistributedDoublePort.lf +++ b/test/Python/src/federated/DistributedDoublePort.lf @@ -1,43 +1,37 @@ /** - * Test the case for when two upstream federates - * send messages to a downstream federte on two - * different ports. One message should carry a - * microstep delay relative to the other - * message. + * Test the case for when two upstream federates send messages to a downstream + * federte on two different ports. One message should carry a microstep delay + * relative to the other message. * * @author Soroush Bateni */ +target Python { timeout: 900 msec, logging: DEBUG, coordination: centralized } +import Count from "../lib/Count.lf" -target Python { - timeout: 900 msec, - logging: DEBUG, - coordination: centralized -}; +reactor CountMicrostep { + output out -import Count from "../lib/Count.lf"; + timer t(0, 1 sec) + + logical action act + + state count(1) -reactor CountMicrostep { - state count(1); - output out; - logical action act; - timer t(0, 1 sec); reaction(t) -> act {= act.schedule(0, self.count) self.count += 1 =} - reaction(act) -> out {= - out.set(act.value) - =} + reaction(act) -> out {= out.set(act.value) =} } reactor Print { - preamble {= - import sys - =} - input in_; - input in2; + preamble {= import sys =} + + input in_ + input in2 + reaction(in_, in2) {= elapsed_time = lf.time.logical_elapsed() print("At tag ({}, {}), received in_ = {} and in2 = {}.".format(elapsed_time, get_microstep(), in_.value, in2.value)) @@ -52,9 +46,10 @@ reactor Print { } federated reactor DistributedDoublePort { - c = new Count(); - cm = new CountMicrostep(); - p = new Print(); - c.out -> p.in_; // Indicating a 'logical' connection. - cm.out -> p.in2; + c = new Count() + cm = new CountMicrostep() + p = new Print() + + c.out -> p.in_ # Indicating a 'logical' connection. + cm.out -> p.in2 } diff --git a/test/Python/src/federated/DistributedLoopedAction.lf b/test/Python/src/federated/DistributedLoopedAction.lf index 864a84786a..e9f604b2ab 100644 --- a/test/Python/src/federated/DistributedLoopedAction.lf +++ b/test/Python/src/federated/DistributedLoopedAction.lf @@ -1,28 +1,26 @@ /** - * Test a sender-receiver network system that - * relies on microsteps being taken into account. + * Test a sender-receiver network system that relies on microsteps being taken + * into account. * * @author Soroush Bateni */ - -target Python { - timeout: 1 sec -}; +target Python { timeout: 1 sec } import Sender from "../lib/LoopedActionSender.lf" reactor Receiver(take_a_break_after(10), break_interval(400 msec)) { - preamble {= - import sys - =} - input in_; - state received_messages(0); - state total_received_messages(0); - state breaks(0); - timer t(0, 1 msec); // This will impact the performance - // but forces the logical time to advance - // Comment this line for a more sensible - // log output. + preamble {= import sys =} + + input in_ + + # This will impact the performance but forces the logical time to advance + # Comment this line for a more sensible log output. + timer t(0, 1 msec) + + state received_messages(0) + state total_received_messages(0) + state breaks(0) + reaction(in_) {= print("At tag ({}, {}) received value {}.".format( lf.time.logical_elapsed(), @@ -58,10 +56,9 @@ reactor Receiver(take_a_break_after(10), break_interval(400 msec)) { =} } - federated reactor DistributedLoopedAction { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedLoopedPhysicalAction.lf b/test/Python/src/federated/DistributedLoopedPhysicalAction.lf index 8268fa29b3..1e9dbc8f66 100644 --- a/test/Python/src/federated/DistributedLoopedPhysicalAction.lf +++ b/test/Python/src/federated/DistributedLoopedPhysicalAction.lf @@ -1,25 +1,23 @@ /** - * Test a sender-receiver network system that - * is similar to DistributedLoopedAction, but it uses a physical - * action rather than a logical action. - * This also demonstrates the advance-message-interval coordination option. - * This specifies the time period between Time Advance Notice (TAN) messages - * sent to the RTI (a form of null message that must be sent because of the - * physical action). The presence of this option also silences a warning + * Test a sender-receiver network system that is similar to + * DistributedLoopedAction, but it uses a physical action rather than a logical + * action. This also demonstrates the advance-message-interval coordination + * option. This specifies the time period between Time Advance Notice (TAN) + * messages sent to the RTI (a form of null message that must be sent because of + * the physical action). The presence of this option also silences a warning * about having a physical action that triggers an output. * * @author Soroush Bateni */ - -target Python { - timeout: 1 sec, - keepalive: true -}; +target Python { timeout: 1 sec, keepalive: true } reactor Sender(take_a_break_after(10), break_interval(550 msec)) { - output out; - physical action act; - state sent_messages(0); + output out + + physical action act + + state sent_messages(0) + reaction(startup, act) -> act, out {= # Send a message on out out.set(self.sent_messages) @@ -34,21 +32,20 @@ reactor Sender(take_a_break_after(10), break_interval(550 msec)) { } reactor Receiver(take_a_break_after(10), break_interval(550 msec)) { - preamble {= - import sys - =} - input in_; - state received_messages(0); - state total_received_messages(0); - state breaks(0); - timer t(0, 1 msec); // This will impact the performance - // but forces the logical time to advance - // Comment this line for a more sensible - // log output. - state base_logical_time; - reaction(startup) {= - self.base_logical_time = lf.time.logical() - =} + preamble {= import sys =} + + input in_ + + # This will impact the performance but forces the logical time to advance + # Comment this line for a more sensible log output. + timer t(0, 1 msec) + + state received_messages(0) + state total_received_messages(0) + state breaks(0) + state base_logical_time + + reaction(startup) {= self.base_logical_time = lf.time.logical() =} reaction(in_) {= current_tag = get_current_tag() @@ -82,8 +79,8 @@ reactor Receiver(take_a_break_after(10), break_interval(550 msec)) { } federated reactor DistributedLoopedPhysicalAction { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedLoopedPhysicalActionDecentralized.lf b/test/Python/src/federated/DistributedLoopedPhysicalActionDecentralized.lf index a3789858fd..653a5f383f 100644 --- a/test/Python/src/federated/DistributedLoopedPhysicalActionDecentralized.lf +++ b/test/Python/src/federated/DistributedLoopedPhysicalActionDecentralized.lf @@ -1,21 +1,16 @@ /** - * Test a sender-receiver network system that - * relies on microsteps being taken into account. + * Test a sender-receiver network system that relies on microsteps being taken + * into account. * * @author Soroush Bateni */ - - -target Python { - timeout: 1 sec, - coordination: decentralized -}; +target Python { timeout: 1 sec, coordination: decentralized } import Sender, Receiver from "DistributedLoopedPhysicalAction.lf" federated reactor { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedMultiport.lf b/test/Python/src/federated/DistributedMultiport.lf index 33087190f4..3da728c060 100644 --- a/test/Python/src/federated/DistributedMultiport.lf +++ b/test/Python/src/federated/DistributedMultiport.lf @@ -1,13 +1,13 @@ -// Check multiport connections between federates. -target Python { - timeout: 1 sec, - coordination: centralized -}; +# Check multiport connections between federates. +target Python { timeout: 1 sec, coordination: centralized } reactor Source { - output[4] out; - timer t(0, 100 msec); - state count(0); + output[4] out + + timer t(0, 100 msec) + + state count(0) + reaction(t) -> out {= for i in range(len(out)): out[i].set(self.count) @@ -16,11 +16,12 @@ reactor Source { } reactor Destination { - preamble {= - import sys - =} - input[4] in_; - state count(0); + preamble {= import sys =} + + input[4] in_ + + state count(0) + reaction(in_) {= for i in range(len(in_)): if in_[i].is_present: @@ -30,6 +31,7 @@ reactor Destination { self.sys.exit(1) self.count += 1 =} + reaction(shutdown) {= if self.count == 0: self.sys.stderr.write("No data received.") @@ -38,7 +40,8 @@ reactor Destination { } federated reactor DistributedMultiport { - s = new Source(); - d = new Destination(); - s.out -> d.in_; + s = new Source() + d = new Destination() + + s.out -> d.in_ } diff --git a/test/Python/src/federated/DistributedMultiportToBank.lf b/test/Python/src/federated/DistributedMultiportToBank.lf index 345e6c351f..1fbde938a0 100644 --- a/test/Python/src/federated/DistributedMultiportToBank.lf +++ b/test/Python/src/federated/DistributedMultiportToBank.lf @@ -1,12 +1,13 @@ -// Check multiport to bank connections between federates. -target Python { - timeout: 1 sec -}; +# Check multiport to bank connections between federates. +target Python { timeout: 1 sec } reactor Source { - output[2] out; - timer t(0, 100 msec); - state count(0); + output[2] out + + timer t(0, 100 msec) + + state count(0) + reaction(t) -> out {= for i in range(len(out)): out[i].set(self.count) @@ -15,11 +16,12 @@ reactor Source { } reactor Destination { - preamble {= - import sys - =} - input in_; - state count(0); + preamble {= import sys =} + + input in_ + + state count(0) + reaction(in_) {= print("Received {}.".format(in_.value)) if self.count != in_.value: @@ -27,6 +29,7 @@ reactor Destination { self.sys.exit(1) self.count += 1 =} + reaction(shutdown) {= if self.count == 0: self.sys.stderr.write("No data received.") @@ -35,7 +38,8 @@ reactor Destination { } federated reactor DistributedMultiportToBank { - s = new Source(); - d = new[2] Destination(); - s.out -> d.in_; + s = new Source() + d = new[2] Destination() + + s.out -> d.in_ } diff --git a/test/Python/src/federated/DistributedMultiportToken.lf b/test/Python/src/federated/DistributedMultiportToken.lf index fca194f4a3..b4ddc72f34 100644 --- a/test/Python/src/federated/DistributedMultiportToken.lf +++ b/test/Python/src/federated/DistributedMultiportToken.lf @@ -1,14 +1,14 @@ -// Check multiport connections between federates where the message is -// carried by a Token (in this case, with an array of char). -target Python { - timeout: 1 sec, - coordination: centralized -}; +# Check multiport connections between federates where the message is carried by +# a Token (in this case, with an array of char). +target Python { timeout: 1 sec, coordination: centralized } reactor Source { - output[4] out; - timer t(0, 200 msec); - state count(0); + output[4] out + + timer t(0, 200 msec) + + state count(0) + reaction(t) -> out {= for i in range(len(out)): self.count += 1 @@ -22,7 +22,8 @@ reactor Source { } reactor Destination { - input[4] in_; + input[4] in_ + reaction(in_) {= for i in range(len(in_)): if in_[i].is_present: @@ -31,7 +32,8 @@ reactor Destination { } federated reactor DistributedMultiportToken { - s = new Source(); - d = new Destination(); - s.out -> d.in_; + s = new Source() + d = new Destination() + + s.out -> d.in_ } diff --git a/test/Python/src/federated/DistributedNoReact.lf b/test/Python/src/federated/DistributedNoReact.lf index a3dec19ce6..ce7a593b0d 100644 --- a/test/Python/src/federated/DistributedNoReact.lf +++ b/test/Python/src/federated/DistributedNoReact.lf @@ -1,4 +1,4 @@ -target Python { timeout: 2 sec }; +target Python { timeout: 2 sec } preamble {= class C: @@ -12,13 +12,13 @@ reactor A { reactor B { output o - reaction(startup) -> o {= - o.set(C()) - =} + + reaction(startup) -> o {= o.set(C()) =} } federated reactor { - a = new A(); - b = new B(); - b.o -> a.o; + a = new A() + b = new B() + + b.o -> a.o } diff --git a/test/Python/src/federated/DistributedSendClass.lf b/test/Python/src/federated/DistributedSendClass.lf index d8b7f7ae82..d182f29cdf 100644 --- a/test/Python/src/federated/DistributedSendClass.lf +++ b/test/Python/src/federated/DistributedSendClass.lf @@ -1,4 +1,4 @@ -target Python; +target Python preamble {= class C: @@ -8,20 +8,19 @@ preamble {= reactor A { input o - reaction(o) {= - request_stop() - =} + + reaction(o) {= request_stop() =} } reactor B { output o - reaction(startup) -> o {= - o.set(C()) - =} + + reaction(startup) -> o {= o.set(C()) =} } federated reactor { - a = new A(); - b = new B(); - b.o -> a.o; + a = new A() + b = new B() + + b.o -> a.o } diff --git a/test/Python/src/federated/DistributedStop.lf b/test/Python/src/federated/DistributedStop.lf index 0027ddb4de..8d385e5b12 100644 --- a/test/Python/src/federated/DistributedStop.lf +++ b/test/Python/src/federated/DistributedStop.lf @@ -3,18 +3,19 @@ * * @author Soroush Bateni */ +target Python -target Python; - -preamble {= - import sys -=} +preamble {= import sys =} reactor Sender { - output out; - timer t(0, 1 usec); - logical action act; - state reaction_invoked_correctly(False); + output out + + timer t(0, 1 usec) + + logical action act + + state reaction_invoked_correctly(False) + reaction(t, act) -> out, act {= print("Sending 42 at ({}, {}).".format( lf.time.logical_elapsed(), @@ -61,11 +62,13 @@ reactor Sender { =} } -reactor Receiver ( - stp_offset(10 msec) // Used in the decentralized variant of the test +reactor Receiver( + stp_offset(10 msec) # Used in the decentralized variant of the test ) { - input in_; + input in_ + state reaction_invoked_correctly(False) + reaction(in_) {= print("Received {} at ({}, {}).".format( in_.value, @@ -106,8 +109,8 @@ reactor Receiver ( } federated reactor DistributedStop { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedStopDecentralized.lf b/test/Python/src/federated/DistributedStopDecentralized.lf index 7ac3f1723f..5adfac4976 100644 --- a/test/Python/src/federated/DistributedStopDecentralized.lf +++ b/test/Python/src/federated/DistributedStopDecentralized.lf @@ -1,20 +1,18 @@ /** - * Test for request_stop() in federated execution with decentralized coordination. + * Test for request_stop() in federated execution with decentralized + * coordination. * * @author Soroush Bateni */ - -// reason for failing: get_microstep() and lf.tag_compare() are not not supported in python target - -target Python { - coordination: decentralized -}; +# reason for failing: get_microstep() and lf.tag_compare() are not not supported +# in python target +target Python { coordination: decentralized } import Sender, Receiver from "DistributedStop.lf" federated reactor DistributedStopDecentralized { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedStopZero.lf b/test/Python/src/federated/DistributedStopZero.lf index ce72ed15d4..e4a764e0ce 100644 --- a/test/Python/src/federated/DistributedStopZero.lf +++ b/test/Python/src/federated/DistributedStopZero.lf @@ -4,24 +4,22 @@ * * @author Soroush Bateni */ +# reason for failing: get_microstep() and lf.tag_compare() are not not supported +# in python target +target Python -// reason for failing: get_microstep() and lf.tag_compare() are not not supported in python target +preamble {= import sys =} -target Python; +reactor Sender { + output out -preamble {= - import sys -=} + timer t(0, 1 usec) -reactor Sender { - output out; - timer t(0, 1 usec); - state startup_logical_time; + state startup_logical_time - reaction(startup) {= - self.startup_logical_time = lf.time.logical() - =} - reaction(t) -> out{= + reaction(startup) {= self.startup_logical_time = lf.time.logical() =} + + reaction(t) -> out {= print("Sending 42 at ({}, {}).".format( lf.time.logical_elapsed(), get_microstep())) @@ -48,12 +46,12 @@ reactor Sender { } reactor Receiver { - input in_; - state startup_logical_time; + input in_ + + state startup_logical_time + + reaction(startup) {= self.startup_logical_time = lf.time.logical() =} - reaction(startup) {= - self.startup_logical_time = lf.time.logical() - =} reaction(in_) {= print("Received {} at ({}, {}).\n".format( in_.value, @@ -84,8 +82,8 @@ reactor Receiver { } federated reactor { - sender = new Sender(); - receiver = new Receiver(); + sender = new Sender() + receiver = new Receiver() - sender.out -> receiver.in_; + sender.out -> receiver.in_ } diff --git a/test/Python/src/federated/DistributedStructAsType.lf b/test/Python/src/federated/DistributedStructAsType.lf index 5477dd9642..5cac6cd02c 100644 --- a/test/Python/src/federated/DistributedStructAsType.lf +++ b/test/Python/src/federated/DistributedStructAsType.lf @@ -1,13 +1,12 @@ -target Python {files: ../include/hello.py, timeout: 2 secs}; +target Python { files: ../include/hello.py, timeout: 2 secs } import Source, Print from "../StructAsType.lf" -preamble {= - import hello -=} +preamble {= import hello =} federated reactor { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/federated/DistributedStructAsTypeDirect.lf b/test/Python/src/federated/DistributedStructAsTypeDirect.lf index 33b338b836..51ca3f132b 100644 --- a/test/Python/src/federated/DistributedStructAsTypeDirect.lf +++ b/test/Python/src/federated/DistributedStructAsTypeDirect.lf @@ -1,13 +1,12 @@ -target Python {files: ../include/hello.py, timeout: 2 secs}; +target Python { files: ../include/hello.py, timeout: 2 secs } import Source, Print from "../StructAsTypeDirect.lf" -preamble {= - import hello -=} +preamble {= import hello =} federated reactor { - s = new Source(); - p = new Print(); - s.out -> p._in; + s = new Source() + p = new Print() + + s.out -> p._in } diff --git a/test/Python/src/federated/DistributedStructParallel.lf b/test/Python/src/federated/DistributedStructParallel.lf index e5d7e0ff49..a2a2bd1c49 100644 --- a/test/Python/src/federated/DistributedStructParallel.lf +++ b/test/Python/src/federated/DistributedStructParallel.lf @@ -1,21 +1,21 @@ -// Source allocates a class object and then sends it to two reactors, -// each of which want to modify it. -target Python {files: ["../include/hello.py"], timeout: 2 secs}; -import Source from "../StructScale.lf"; +# Source allocates a class object and then sends it to two reactors, each of +# which want to modify it. +target Python { files: ["../include/hello.py"], timeout: 2 secs } + +import Source from "../StructScale.lf" import Check, Print from "../StructParallel.lf" -preamble {= -import hello -=} +preamble {= import hello =} federated reactor { - s = new Source(); - c1 = new Print(); - c2 = new Print(scale = 3); - p1 = new Check(expected = 84); - p2 = new Check(expected = 126); - s.out -> c1._in; - s.out -> c2._in; - c1.out -> p1._in; - c2.out -> p2._in; + s = new Source() + c1 = new Print() + c2 = new Print(scale = 3) + p1 = new Check(expected = 84) + p2 = new Check(expected = 126) + + s.out -> c1._in + s.out -> c2._in + c1.out -> p1._in + c2.out -> p2._in } diff --git a/test/Python/src/federated/DistributedStructPrint.lf b/test/Python/src/federated/DistributedStructPrint.lf index 7d6129302a..d9a68d26c2 100644 --- a/test/Python/src/federated/DistributedStructPrint.lf +++ b/test/Python/src/federated/DistributedStructPrint.lf @@ -1,14 +1,14 @@ -// Source produces a dynamically allocated class object, which it passes -// to Print. Reference counting ensures that the struct is freed. -target Python {files: ["../include/hello.py"], timeout: 2 sec}; +# Source produces a dynamically allocated class object, which it passes to +# Print. Reference counting ensures that the struct is freed. +target Python { files: ["../include/hello.py"], timeout: 2 sec } + import Print, Check from "../StructPrint.lf" -preamble {= -import hello -=} +preamble {= import hello =} federated reactor { - s = new Print(); - p = new Check(); - s.out -> p._in; + s = new Print() + p = new Check() + + s.out -> p._in } diff --git a/test/Python/src/federated/DistributedStructScale.lf b/test/Python/src/federated/DistributedStructScale.lf index 749fda06c0..0eda2a6586 100644 --- a/test/Python/src/federated/DistributedStructScale.lf +++ b/test/Python/src/federated/DistributedStructScale.lf @@ -1,16 +1,16 @@ -// Source produces a dynamically allocated class object, which it passes -// to Scale. Scale modifies it and passes it to Print. -target Python {files: ["../include/hello.py"], timeout: 2 sec}; +# Source produces a dynamically allocated class object, which it passes to +# Scale. Scale modifies it and passes it to Print. +target Python { files: ["../include/hello.py"], timeout: 2 sec } + import Source, TestInput, Print from "../StructScale.lf" -preamble {= -import hello -=} +preamble {= import hello =} + +federated reactor { + s = new Source() + c = new Print() + p = new TestInput(expected = 84) -federated reactor { - s = new Source(); - c = new Print(); - p = new TestInput(expected=84); - s.out -> c._in; - c.out -> p._in; + s.out -> c._in + c.out -> p._in } diff --git a/test/Python/src/federated/HelloDistributed.lf b/test/Python/src/federated/HelloDistributed.lf index d9f5a3ce21..4d11d95ab8 100644 --- a/test/Python/src/federated/HelloDistributed.lf +++ b/test/Python/src/federated/HelloDistributed.lf @@ -1,25 +1,29 @@ -/** Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee +/** + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee */ -target Python; +target Python reactor Source { - output out; + output out + reaction(startup) -> out {= print("Sending 'Hello World!' message from source federate."); out.set("Hello World!") request_stop() =} } + reactor Destination { - input _in; - state received(false); - reaction(startup) {= - print("Destination started.") - =} + input _in + + state received(false) + + reaction(startup) {= print("Destination started.") =} + reaction(_in) {= print(f"At logical time {lf.time.logical_elapsed()}, destination received {_in.value}") if _in.value != "Hello World!": @@ -27,6 +31,7 @@ reactor Destination { exit(1) self.received = True =} + reaction(shutdown) {= print("Shutdown invoked.") if self.received is not True: @@ -36,10 +41,11 @@ reactor Destination { } federated reactor HelloDistributed at localhost { -// reaction(startup) {= -// print("Printing something in top-level federated reactor.") -// =} - s = new Source(); // Reactor s is in federate Source - d = new Destination(); // Reactor d is in federate Destination - s.out -> d._in; // This version preserves the timestamp. + # reaction(startup) {= print("Printing something in top-level federated + # reactor.") + # =} Reactor s is in federate Source + s = new Source() + d = new Destination() # Reactor d is in federate Destination + + s.out -> d._in # This version preserves the timestamp. } diff --git a/test/Python/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf b/test/Python/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf index 9d27354baf..3625bfcd4e 100644 --- a/test/Python/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf +++ b/test/Python/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf @@ -1,27 +1,29 @@ /** - * This tests that the precedence order of reaction invocation is kept - * in the hierarchy of reactors when a feedback loop is present in centralized coordination. - * + * This tests that the precedence order of reaction invocation is kept in the + * hierarchy of reactors when a feedback loop is present in centralized + * coordination. + * * @author Edward A. Lee * @author Soroush Bateni */ target Python { coordination: centralized, - coordination-options: {advance-message-interval: 100 msec}, + coordination-options: { advance-message-interval: 100 msec }, timeout: 5 sec } -reactor Contained (incr(1)) { - timer t(0, 1 sec); - input inp; - state count(0); - state received_count(0); - reaction(t) {= - self.count += self.incr - =} - reaction(inp) {= - self.received_count = self.count - =} +reactor Contained(incr(1)) { + input inp + + timer t(0, 1 sec) + + state count(0) + state received_count(0) + + reaction(t) {= self.count += self.incr =} + + reaction(inp) {= self.received_count = self.count =} + reaction(t) {= if self.received_count != self.count: self.sys.stderr.write("reaction(t) was invoked before reaction(in). Precedence order was not kept.") @@ -30,23 +32,29 @@ reactor Contained (incr(1)) { } reactor Looper(incr(1), delay(0 msec)) { - input inp; - output out; - state count(0); - timer t(0, 1 sec); - - c = new Contained(incr = incr); - + input inp + + output out + + timer t(0, 1 sec) + + c = new Contained(incr = incr) + + inp -> c.inp + + state count(0) + reaction(t) -> out {= - print(f"Sending network output {self.count}") + print(f"Sending network output {self.count}") out.set(self.count) self.count += self.incr =} + reaction(inp) {= time_lag = lf.time.physical() - lf.time.logical() print(f"Received {inp.value}. Logical time is behind physical time by {time_lag:,} nsec.") =} - inp->c.inp; + reaction(shutdown) {= print("******* Shutdown invoked.") if self.count != 6 * self.incr: @@ -54,9 +62,11 @@ reactor Looper(incr(1), delay(0 msec)) { self.sys.exit(1) =} } -federated reactor (delay(0)) { - left = new Looper(); - right = new Looper(incr = -1); - left.out -> right.inp; - right.out -> left.inp; + +federated reactor(delay(0)) { + left = new Looper() + right = new Looper(incr = -1) + + left.out -> right.inp + right.out -> left.inp } diff --git a/test/Python/src/federated/ParallelDestinations.lf b/test/Python/src/federated/ParallelDestinations.lf index 9dec420180..b963add5d8 100644 --- a/test/Python/src/federated/ParallelDestinations.lf +++ b/test/Python/src/federated/ParallelDestinations.lf @@ -1,25 +1,22 @@ -/** - * Test parallel connections for federated execution. - */ -target Python { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target Python { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Source { - output[2] out; - c1 = new Count(); - c2 = new Count(); + output[2] out + + c1 = new Count() + c2 = new Count() - c1.out, c2.out -> out; + c1.out, c2.out -> out } federated reactor { - s = new Source(); - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); + s = new Source() + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) - s.out -> t1.in_, t2.in_; + s.out -> t1.in_, t2.in_ } diff --git a/test/Python/src/federated/ParallelSources.lf b/test/Python/src/federated/ParallelSources.lf index 3a81927f87..32d8a288fe 100644 --- a/test/Python/src/federated/ParallelSources.lf +++ b/test/Python/src/federated/ParallelSources.lf @@ -1,26 +1,22 @@ -/** - * Test parallel connections for federated execution. - */ -target Python { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target Python { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Destination { - input[2] in_; + input[2] in_ - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) - in_ -> t1.in_, t2.in_; + in_ -> t1.in_, t2.in_ } federated reactor { - c1 = new Count(); - c2 = new Count(); - d = new Destination(); + c1 = new Count() + c2 = new Count() + d = new Destination() - c1.out, c2.out -> d.in_; + c1.out, c2.out -> d.in_ } diff --git a/test/Python/src/federated/ParallelSourcesMultiport.lf b/test/Python/src/federated/ParallelSourcesMultiport.lf index ba84a3ef9b..90d617db62 100644 --- a/test/Python/src/federated/ParallelSourcesMultiport.lf +++ b/test/Python/src/federated/ParallelSourcesMultiport.lf @@ -1,36 +1,33 @@ -/** - * Test parallel connections for federated execution. - */ -target Python { - timeout: 2 sec -} +/** Test parallel connections for federated execution. */ +target Python { timeout: 2 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Source { - output[2] out; - c1 = new Count(); - c2 = new Count(); + output[2] out + + c1 = new Count() + c2 = new Count() - c1.out, c2.out -> out; + c1.out, c2.out -> out } reactor Destination1 { - input[3] in_; + input[3] in_ - t1 = new TestCount(num_inputs = 3); - t2 = new TestCount(num_inputs = 3); - t3 = new TestCount(num_inputs = 3); + t1 = new TestCount(num_inputs = 3) + t2 = new TestCount(num_inputs = 3) + t3 = new TestCount(num_inputs = 3) - in_ -> t1.in_, t2.in_, t3.in_; + in_ -> t1.in_, t2.in_, t3.in_ } federated reactor { - s1 = new Source(); - s2 = new Source(); - d1 = new Destination1(); - t4 = new TestCount(num_inputs = 3); + s1 = new Source() + s2 = new Source() + d1 = new Destination1() + t4 = new TestCount(num_inputs = 3) - s1.out, s2.out -> d1.in_, t4.in_; + s1.out, s2.out -> d1.in_, t4.in_ } diff --git a/test/Python/src/federated/PhysicalSTP.lf b/test/Python/src/federated/PhysicalSTP.lf index ded6e82fae..8668fcb8f6 100644 --- a/test/Python/src/federated/PhysicalSTP.lf +++ b/test/Python/src/federated/PhysicalSTP.lf @@ -1,21 +1,18 @@ /** - * This is a test that detects STP violations according to the - * physical time of message arrival. + * This is a test that detects STP violations according to the physical time of + * message arrival. */ +target Python { timeout: 1900 msec, coordination: decentralized } -target Python { - timeout: 1900 msec, - coordination: decentralized -}; +import Count from "../lib/Count.lf" -import Count from "../lib/Count.lf"; +reactor Print(STP_offset(0)) { + preamble {= import sys =} + + input in_ + + state c(1) -reactor Print (STP_offset(0)) { - preamble {= - import sys - =} - input in_; - state c(1); reaction(in_) {= elapsed_time = lf.time.logical_elapsed() print("At time {}, received {}".format(elapsed_time, in_.value)) @@ -30,12 +27,13 @@ reactor Print (STP_offset(0)) { else: self.sys.stderr.write("Message arrived {} early.\n".format(STP_discrepency)) self.sys.exit(1) - =} STP (STP_offset) {= + =} STP(STP_offset){= # This STP handler should never be invoked because the only source of event # for Print is the Count reactor. self.sys.stderr.write("Logical STP violation was detected. Only physical STP violations are possible.\n") self.sys.exit(1) =} + reaction(shutdown) {= if self.c != 3: self.sys.stderr.write("Expected to receive 2 items but got {}.\n".format(self.c)) @@ -44,8 +42,8 @@ reactor Print (STP_offset(0)) { } federated reactor { - c = new Count(offset = 1 msec, period = 1 sec); - p = new Print(STP_offset = 1 usec); + c = new Count(offset = 1 msec, period = 1 sec) + p = new Print(STP_offset = 1 usec) - c.out -> p.in_; + c.out -> p.in_ } diff --git a/test/Python/src/federated/PingPongDistributed.lf b/test/Python/src/federated/PingPongDistributed.lf index e8f9771296..4529017d29 100644 --- a/test/Python/src/federated/PingPongDistributed.lf +++ b/test/Python/src/federated/PingPongDistributed.lf @@ -1,54 +1,58 @@ /** - * Basic benchmark from the Savina benchmark suite that is - * intended to measure message-passing overhead. - * This is based on https://www.scala-lang.org/old/node/54 - * See https://shamsimam.github.io/papers/2014-agere-savina.pdf. + * Basic benchmark from the Savina benchmark suite that is intended to measure + * message-passing overhead. This is based on + * https://www.scala-lang.org/old/node/54 See + * https://shamsimam.github.io/papers/2014-agere-savina.pdf. * - * This is a distributed version, where Ping and Pong run in - * separate programs and can be run on different machines. + * This is a distributed version, where Ping and Pong run in separate programs + * and can be run on different machines. * - * To get a sense, some (informal) results for 1,000,000 ping-pongs - * on my Mac: + * To get a sense, some (informal) results for 1,000,000 ping-pongs on my Mac: * - * Unthreaded: 97 msec - * Threaded: 265 msec - * Distributed: 53 seconds + * Unthreaded: 97 msec Threaded: 265 msec Distributed: 53 seconds * - * There is no parallelism in this application, so it does not benefit from being - * being distributed. + * There is no parallelism in this application, so it does not benefit from + * being being distributed. * - * These measurements are total execution time, including startup and shutdown, of - * all three programs. + * These measurements are total execution time, including startup and shutdown, + * of all three programs. * * @author Edward A. Lee */ -target Python; +target Python reactor Ping(count(10)) { - input receive; - output send; - state pingsLeft(count); - logical action serve; - reaction (startup, serve) -> send {= + input receive + + output send + + logical action serve + + state pingsLeft(count) + + reaction(startup, serve) -> send {= print("At logical time {}, Ping sending {}.\n".format(lf.time.logical_elapsed(), self.pingsLeft)) send.set(self.pingsLeft) self.pingsLeft -= 1 =} - reaction (receive) -> serve {= + + reaction(receive) -> serve {= if self.pingsLeft > 0: serve.schedule(0) else: request_stop() =} } + reactor Pong(expected(10)) { - preamble {= - import sys - =} + preamble {= import sys =} + + input receive + + output send + + state count(0) - input receive; - output send; - state count(0); reaction(receive) -> send {= self.count += 1 print("At logical time {}, Pong received {}.\n".format(lf.time.logical_elapsed(), receive.value)) @@ -56,6 +60,7 @@ reactor Pong(expected(10)) { if self.count == self.expected: request_stop() =} + reaction(shutdown) {= if self.count != self.expected: print("Pong expected to receive {} inputs, but it received {}.\n".format(self.expected, self.count), file=self.sys.stderr) @@ -63,9 +68,11 @@ reactor Pong(expected(10)) { print("Pong received {} pings.\n".format(self.count)) =} } -federated reactor (count(10)) { - ping = new Ping(count = count); - pong = new Pong(expected = count); - ping.send ~> pong.receive; - pong.send ~> ping.receive; + +federated reactor(count(10)) { + ping = new Ping(count = count) + pong = new Pong(expected = count) + + ping.send ~> pong.receive + pong.send ~> ping.receive } diff --git a/test/Python/src/federated/StopAtShutdown.lf b/test/Python/src/federated/StopAtShutdown.lf index a6464a6f69..6a0d719b12 100644 --- a/test/Python/src/federated/StopAtShutdown.lf +++ b/test/Python/src/federated/StopAtShutdown.lf @@ -1,43 +1,35 @@ /** - * Check that request_stop() doesn't cause - * any issues at the shutdown tag. + * Check that request_stop() doesn't cause any issues at the shutdown tag. * * Original bug discovered by Steven Wong * * @author Steven Wong */ -target Python { - timeout: 2 sec -} +target Python { timeout: 2 sec } reactor A { - input in_; - reaction(startup) {= - print("Hello World!") - =} - - reaction(in_) {= - print("Got it") - =} - - reaction(shutdown) {= - request_stop() - =} + input in_ + + reaction(startup) {= print("Hello World!") =} + + reaction(in_) {= print("Got it") =} + + reaction(shutdown) {= request_stop() =} } reactor B { - output out; - timer t(1 sec); - reaction(t) -> out {= - out.set(1) - =} - reaction(shutdown) {= - request_stop() - =} + output out + + timer t(1 sec) + + reaction(t) -> out {= out.set(1) =} + + reaction(shutdown) {= request_stop() =} } federated reactor { - a = new A(); - b = new B(); - b.out -> a.in_; + a = new A() + b = new B() + + b.out -> a.in_ } diff --git a/test/Python/src/lib/Count.lf b/test/Python/src/lib/Count.lf index 0f7d310fe3..4def8c579a 100644 --- a/test/Python/src/lib/Count.lf +++ b/test/Python/src/lib/Count.lf @@ -1,8 +1,12 @@ -target Python; +target Python + reactor Count(offset(0), period(1 sec)) { - state count(1); - output out; - timer t(offset, period); + output out + + timer t(offset, period) + + state count(1) + reaction(t) -> out {= out.set(self.count) self.count += 1 diff --git a/test/Python/src/lib/Imported.lf b/test/Python/src/lib/Imported.lf index 6507a9a395..f9f2bdc9af 100644 --- a/test/Python/src/lib/Imported.lf +++ b/test/Python/src/lib/Imported.lf @@ -1,11 +1,13 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; +# This is used by the test for the ability to import a reactor definition that +# itself imports a reactor definition. +target Python + import ImportedAgain from "./ImportedAgain.lf" + reactor Imported { - input x; - a = new ImportedAgain(); - reaction(x) -> a.x {= - a.x.set(x.value) - =} + input x + + a = new ImportedAgain() + + reaction(x) -> a.x {= a.x.set(x.value) =} } diff --git a/test/Python/src/lib/ImportedAgain.lf b/test/Python/src/lib/ImportedAgain.lf index 6070ab384d..cb877da53c 100644 --- a/test/Python/src/lib/ImportedAgain.lf +++ b/test/Python/src/lib/ImportedAgain.lf @@ -1,10 +1,10 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; -//import Imported from "Imported.lf" -reactor ImportedAgain { - //y = new Imported(); // FIXME: Address this bug - input x; +# This is used by the test for the ability to import a reactor definition that +# itself imports a reactor definition. +target Python + +reactor ImportedAgain { # import Imported from "Imported.lf" + input x # y = new Imported(); // FIXME: Address this bug + reaction(x) {= print("Received: " + str(x.value)) if (x.value != 42): diff --git a/test/Python/src/lib/ImportedComposition.lf b/test/Python/src/lib/ImportedComposition.lf index 3324ce3db8..015c508ced 100644 --- a/test/Python/src/lib/ImportedComposition.lf +++ b/test/Python/src/lib/ImportedComposition.lf @@ -1,19 +1,24 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Python; +# This is used by the test for the ability to import a reactor definition that +# itself imports a reactor definition. +target Python + reactor Gain { - input x; - output y; - reaction(x) -> y {= - y.set(x.value * 2) - =} + input x + + output y + + reaction(x) -> y {= y.set(x.value * 2) =} } + reactor ImportedComposition { - input x; - output y; - g1 = new Gain(); - g2 = new Gain(); - x -> g1.x after 10 msec; - g1.y -> g2.x after 30 msec; - g2.y -> y after 15 msec; + input x + + output y + + g1 = new Gain() + g2 = new Gain() + + x -> g1.x after 10 msec + g1.y -> g2.x after 30 msec + g2.y -> y after 15 msec } diff --git a/test/Python/src/lib/InternalDelay.lf b/test/Python/src/lib/InternalDelay.lf index ab5d47c0e9..b5f4536cdb 100644 --- a/test/Python/src/lib/InternalDelay.lf +++ b/test/Python/src/lib/InternalDelay.lf @@ -1,14 +1,13 @@ -target Python; -reactor InternalDelay ( - delay(10 msec) -) { - input in_; - output out; - logical action d; - reaction(in_) -> d {= - d.schedule(self.delay, in_.value) - =} - reaction(d) -> out {= - out.set(d.value) - =} +target Python + +reactor InternalDelay(delay(10 msec)) { + input in_ + + output out + + logical action d + + reaction(in_) -> d {= d.schedule(self.delay, in_.value) =} + + reaction(d) -> out {= out.set(d.value) =} } diff --git a/test/Python/src/lib/LoopedActionSender.lf b/test/Python/src/lib/LoopedActionSender.lf index af60d13743..bd802360b4 100644 --- a/test/Python/src/lib/LoopedActionSender.lf +++ b/test/Python/src/lib/LoopedActionSender.lf @@ -1,21 +1,23 @@ /** - * A sender reactor that outputs integers - * in superdense time. + * A sender reactor that outputs integers in superdense time. * * @author Soroush Bateni */ -target Python; +target Python /** - * @param take_a_break_after: Indicates how many messages are sent - * in consecutive superdense time - * @param break_interval: Determines how long the reactor should take - * a break after sending take_a_break_after messages. + * @param take_a_break_after: Indicates how many messages are sent in + * consecutive superdense time + * @param break_interval: Determines how long the reactor should take a break + * after sending take_a_break_after messages. */ reactor Sender(take_a_break_after(10), break_interval(400 msec)) { - output out; - logical action act; - state sent_messages(0); + output out + + logical action act + + state sent_messages(0) + reaction(startup, act) -> act, out {= # Send a message on out out.set(self.sent_messages) diff --git a/test/Python/src/lib/Test.lf b/test/Python/src/lib/Test.lf index 6f121519a2..32d3fd2ccb 100644 --- a/test/Python/src/lib/Test.lf +++ b/test/Python/src/lib/Test.lf @@ -1,8 +1,10 @@ -target Python; +target Python reactor TestDouble(expected(1.0, 1.0, 1.0, 1.0)) { - input t_in; - state count(0); + input t_in + + state count(0) + reaction(t_in) {= print("Received: ", t_in.value) if t_in.value != self.expected[self.count]: diff --git a/test/Python/src/lib/TestCount.lf b/test/Python/src/lib/TestCount.lf index 824fc45b64..a3a5fd83cf 100644 --- a/test/Python/src/lib/TestCount.lf +++ b/test/Python/src/lib/TestCount.lf @@ -7,14 +7,16 @@ * @param stride The increment for the inputs. Default is 1. * @param num_inputs The number of inputs expected. Default is 1. */ -target Python; +target Python + reactor TestCount(start(1), stride(1), num_inputs(1)) { - preamble {= - import sys - =} - state count(start); - state inputs_received(0); - input in_; + preamble {= import sys =} + + input in_ + + state count(start) + state inputs_received(0) + reaction(in_) {= print("Received {}.".format(in_.value)) if in_.value != self.count: @@ -23,6 +25,7 @@ reactor TestCount(start(1), stride(1), num_inputs(1)) { self.count += self.stride; self.inputs_received += 1; =} + reaction(shutdown) {= print("Shutdown invoked.") if self.inputs_received != self.num_inputs: diff --git a/test/Python/src/lib/TestCountMultiport.lf b/test/Python/src/lib/TestCountMultiport.lf index f3769b52c6..7cacb54204 100644 --- a/test/Python/src/lib/TestCountMultiport.lf +++ b/test/Python/src/lib/TestCountMultiport.lf @@ -1,22 +1,24 @@ /** * Test that a counting sequence of inputs starts with the specified start * parameter value, increments by the specified stride, and receives the - * specified number of inputs. This version has a multiport input, and - * each input is expected to be present and incremented over the previous - * input. + * specified number of inputs. This version has a multiport input, and each + * input is expected to be present and incremented over the previous input. * * @param start The starting value for the expected inputs. Default is 1. * @param stride The increment for the inputs. Default is 1. - * @param num_inputs The number of inputs expected on each channel. Default is 1. + * @param num_inputs The number of inputs expected on each channel. Default is + * 1. */ -target Python; +target Python + reactor TestCountMultiport(start(1), stride(1), num_inputs(1), width(2)) { - preamble {= - import sys - =} - state count(start); - state inputs_received(0); - input[width] inp; + preamble {= import sys =} + + input[width] inp + + state count(start) + state inputs_received(0) + reaction(inp) {= for i in range(in_width): if not inp[i].is_present: @@ -29,6 +31,7 @@ reactor TestCountMultiport(start(1), stride(1), num_inputs(1), width(2)) { self.count += self.stride self.inputs_received += 1 =} + reaction(shutdown) {= print("Shutdown invoked.") if self.inputs_received != self.num_inputs: diff --git a/test/Python/src/modal_models/util/TraceTesting.lf b/test/Python/src/modal_models/util/TraceTesting.lf index f64a282eab..1014ac3c8d 100644 --- a/test/Python/src/modal_models/util/TraceTesting.lf +++ b/test/Python/src/modal_models/util/TraceTesting.lf @@ -1,19 +1,15 @@ -/* - * Utility reactor to record and test execution traces. - */ +/** Utility reactor to record and test execution traces. */ target Python -reactor TraceTesting(events_size(0), trace({=[]=}), training(False)) { - input [events_size]events +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) {= - self.last_reaction_time = lf.time.logical() - =} + reaction(startup) {= self.last_reaction_time = lf.time.logical() =} reaction(events) {= # Time passed since last reaction diff --git a/test/Python/src/multiport/BankIndexInitializer.lf b/test/Python/src/multiport/BankIndexInitializer.lf index 408d364722..8bfcd7fe5f 100644 --- a/test/Python/src/multiport/BankIndexInitializer.lf +++ b/test/Python/src/multiport/BankIndexInitializer.lf @@ -1,25 +1,20 @@ -// Test bank of reactors to multiport input with id parameter in the bank. -target Python; - -preamble {= - table = [4, 3, 2, 1] -=} - -reactor Source( - bank_index(0), - value(0) -) { - output out; - reaction (startup) -> out {= - out.set(self.value) - =} +# Test bank of reactors to multiport input with id parameter in the bank. +target Python + +preamble {= table = [4, 3, 2, 1] =} + +reactor Source(bank_index(0), value(0)) { + output out + + reaction(startup) -> out {= out.set(self.value) =} } reactor Sink(width(4)) { - input[width] _in; - state received(false); + input[width] _in - reaction (_in) {= + state received(false) + + reaction(_in) {= for (idx, port) in enumerate(_in): if port.is_present is True: print("Received on channel {:d}: {:d}".format(idx, port.value)) @@ -28,14 +23,17 @@ reactor Sink(width(4)) { sys.stderr.write("ERROR: expected {:d}\n".format(4 - idx)) exit(1) =} + reaction(shutdown) {= if self.received is False: sys.stderr.write("ERROR: Sink received no data\n") exit(1) =} } + main reactor(width(4)) { - source = new[width] Source(value = {= table[bank_index] =}); - sink = new Sink(width = width); - source.out -> sink._in; + source = new[width] Source(value = {= table[bank_index] =}) + sink = new Sink(width = width) + + source.out -> sink._in } diff --git a/test/Python/src/multiport/BankReactionsInContainer.lf b/test/Python/src/multiport/BankReactionsInContainer.lf index 2e0454934e..49ad783514 100644 --- a/test/Python/src/multiport/BankReactionsInContainer.lf +++ b/test/Python/src/multiport/BankReactionsInContainer.lf @@ -1,13 +1,14 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target Python { - timeout: 1 sec, -}; -reactor R (bank_index(0)) { - output[2] out; - input[2] inp; - state received(false); +target Python { timeout: 1 sec } + +reactor R(bank_index(0)) { + input[2] inp + + output[2] out + + state received(false) reaction(startup) -> out {= for (i, p) in enumerate(out): @@ -25,6 +26,7 @@ reactor R (bank_index(0)) { sys.stderr.write(f"ERROR: Expected {self.bank_index * 2 + i}.\n") exit(1) =} + reaction(shutdown) {= print("Inner shutdown invoked.") if self.received is not True: @@ -32,9 +34,11 @@ reactor R (bank_index(0)) { exit(1) =} } + main reactor { - s = new[2] R(); - state received(false); + s = new[2] R() + + state received(false) reaction(startup) -> s.inp {= count = 0 @@ -44,6 +48,7 @@ main reactor { p.set(count) count+=1 =} + reaction(s.out) {= for i in range(len(s)): for (j, p) in enumerate(s[i].out): @@ -54,6 +59,7 @@ main reactor { sys.stderr.write(f"ERROR: Expected {i*2+j}.\n") exit(1) =} + reaction(shutdown) {= print("Outer shutdown invoked.") if self.received is not True: diff --git a/test/Python/src/multiport/BankToBank.lf b/test/Python/src/multiport/BankToBank.lf index 1b6b453903..8633107bc7 100644 --- a/test/Python/src/multiport/BankToBank.lf +++ b/test/Python/src/multiport/BankToBank.lf @@ -1,24 +1,24 @@ -// Check bank of reactors sending to bank of reactors. -target Python { - timeout: 2 sec, - fast: true -}; -reactor Source( - bank_index(0) -) { - timer t(0, 200 msec); - output out; - state s(0); +# Check bank of reactors sending to bank of reactors. +target Python { timeout: 2 sec, fast: true } + +reactor Source(bank_index(0)) { + output out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s += self.bank_index =} } -reactor Destination( - bank_index(0) -) { - state s(0); - input _in; + +reactor Destination(bank_index(0)) { + input _in + + state s(0) + reaction(_in) {= print("Destination " + str(self.bank_index) + " received: " + str(_in.value)) if (_in.value != self.s): @@ -26,6 +26,7 @@ reactor Destination( exit(1) self.s += self.bank_index =} + reaction(shutdown) {= if self.s == 0 and self.bank_index != 0: sys.stderr.write("ERROR: Destination " + self.bank_index + " received no input!") @@ -35,7 +36,8 @@ reactor Destination( } main reactor BankToBank(width(4)) { - a = new[width] Source(); - b = new[width] Destination(); - a.out -> b._in; + a = new[width] Source() + b = new[width] Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/BankToBankMultiport.lf b/test/Python/src/multiport/BankToBankMultiport.lf index 4d7f45cc38..7eb5e22590 100644 --- a/test/Python/src/multiport/BankToBankMultiport.lf +++ b/test/Python/src/multiport/BankToBankMultiport.lf @@ -1,21 +1,25 @@ -// Check bank of reactors sending to bank of reactors with multiports. -target Python { - timeout: 2 sec, - fast: true -}; +# Check bank of reactors sending to bank of reactors with multiports. +target Python { timeout: 2 sec, fast: true } + reactor Source(width(1)) { - timer t(0, 200 msec); - output[width] out; - state s(0); + output[width] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set(self.s) self.s += 1 =} } + reactor Destination(width(1)) { - state s(6); - input[width] _in; + input[width] _in + + state s(6) + reaction(_in) {= sm = 0 for port in _in: @@ -29,6 +33,7 @@ reactor Destination(width(1)) { self.s += 16 =} + reaction(shutdown) {= if self.s <= 6: sys.stderr.write("ERROR: Destination received no input!\n") @@ -37,8 +42,10 @@ reactor Destination(width(1)) { print("Success.") =} } + main reactor BankToBankMultiport(bank_width(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b._in; + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b._in } diff --git a/test/Python/src/multiport/BankToBankMultiportAfter.lf b/test/Python/src/multiport/BankToBankMultiportAfter.lf index 406b34a03d..e6d2e2cfef 100644 --- a/test/Python/src/multiport/BankToBankMultiportAfter.lf +++ b/test/Python/src/multiport/BankToBankMultiportAfter.lf @@ -1,11 +1,11 @@ -// Check bank of reactors sending to bank of reactors with multiports. -target Python { - timeout: 2 sec, - fast: true -}; +# Check bank of reactors sending to bank of reactors with multiports. +target Python { timeout: 2 sec, fast: true } + import Source, Destination from "BankToBankMultiport.lf" + main reactor BankToBankMultiportAfter(bank_width(4)) { - a = new[bank_width] Source(width = 4); - b = new[bank_width] Destination(width = 4); - a.out -> b._in after 200 msec; + a = new[bank_width] Source(width = 4) + b = new[bank_width] Destination(width = 4) + + a.out -> b._in after 200 msec } diff --git a/test/Python/src/multiport/BankToMultiport.lf b/test/Python/src/multiport/BankToMultiport.lf index 0ba57d744d..99d7e41133 100644 --- a/test/Python/src/multiport/BankToMultiport.lf +++ b/test/Python/src/multiport/BankToMultiport.lf @@ -1,20 +1,18 @@ -// Test bank of reactors to multiport input with id parameter in the bank. -target Python; - -reactor Source( - bank_index(0) -) { - output out; - reaction (startup) -> out {= - out.set(self.bank_index) - =} +# Test bank of reactors to multiport input with id parameter in the bank. +target Python + +reactor Source(bank_index(0)) { + output out + + reaction(startup) -> out {= out.set(self.bank_index) =} } reactor Sink(width(4)) { - input[width] _in; - state received(false); + input[width] _in + + state received(false) - reaction (_in) {= + reaction(_in) {= for (idx, port) in enumerate(_in): if port.is_present is True: print("Received on channel {:d}: {:d}".format(idx, port.value)) @@ -23,14 +21,17 @@ reactor Sink(width(4)) { sys.stderr.write("ERROR: expected {:d}\n".format(idx)) exit(1) =} + reaction(shutdown) {= if self.received is False: sys.stderr.write("ERROR: Sink received no data\n") exit(1) =} } + main reactor BankToMultiport(width(5)) { - source = new[width] Source(); - sink = new Sink(width = width); - source.out -> sink._in; + source = new[width] Source() + sink = new Sink(width = width) + + source.out -> sink._in } diff --git a/test/Python/src/multiport/Broadcast.lf b/test/Python/src/multiport/Broadcast.lf index 6a0b434bca..e336266221 100644 --- a/test/Python/src/multiport/Broadcast.lf +++ b/test/Python/src/multiport/Broadcast.lf @@ -1,19 +1,16 @@ -target Python { - timeout: 2 sec, - fast: true -}; +target Python { timeout: 2 sec, fast: true } reactor Source(value(42)) { output out - reaction(startup) -> out {= - out.set(self.value) - =} + reaction(startup) -> out {= out.set(self.value) =} } reactor Destination(bank_index(0), delay(0)) { input _in + state received(false) + reaction(_in) {= print(f"Destination {self.bank_index} received {_in.value}.") if (_in.value != 42): @@ -25,6 +22,7 @@ reactor Destination(bank_index(0), delay(0)) { exit(2) self.received = True =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write(f"ERROR: Destination {self.bank_index} received no input!\n") @@ -34,7 +32,8 @@ reactor Destination(bank_index(0), delay(0)) { } main reactor { - a = new Source(); - b = new[4] Destination(); - (a.out)+ -> b._in; + a = new Source() + b = new[4] Destination() + + (a.out)+ -> b._in } diff --git a/test/Python/src/multiport/BroadcastAfter.lf b/test/Python/src/multiport/BroadcastAfter.lf index 4f6b86a10d..f26871a5cf 100644 --- a/test/Python/src/multiport/BroadcastAfter.lf +++ b/test/Python/src/multiport/BroadcastAfter.lf @@ -1,12 +1,10 @@ -target Python { - timeout: 2 sec, - fast: true -}; +target Python { timeout: 2 sec, fast: true } import Source, Destination from "Broadcast.lf" main reactor { - a = new Source(); - b = new[4] Destination(delay = 1 sec); - (a.out)+ -> b._in after 1 sec; + a = new Source() + b = new[4] Destination(delay = 1 sec) + + (a.out)+ -> b._in after 1 sec } diff --git a/test/Python/src/multiport/BroadcastMultipleAfter.lf b/test/Python/src/multiport/BroadcastMultipleAfter.lf index 17f7053398..8226edf41f 100644 --- a/test/Python/src/multiport/BroadcastMultipleAfter.lf +++ b/test/Python/src/multiport/BroadcastMultipleAfter.lf @@ -1,13 +1,12 @@ -target Python { - timeout: 2 sec, - fast: true -}; +target Python { timeout: 2 sec, fast: true } import Source from "Broadcast.lf" reactor Destination(bank_index(0), delay(0)) { input _in + state received(false) + reaction(_in) {= print(f"Destination {self.bank_index} received {_in.value}.") expected = (self.bank_index % 3) + 1 @@ -20,6 +19,7 @@ reactor Destination(bank_index(0), delay(0)) { exit(2) self.received = True =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write(f"ERROR: Destination {self.bank_index} received no input!\n") @@ -29,9 +29,10 @@ reactor Destination(bank_index(0), delay(0)) { } main reactor { - a1 = new Source(value=1); - a2 = new Source(value=2); - a3 = new Source(value=3); - b = new[9] Destination(delay = 1 sec); - (a1.out, a2.out, a3.out)+ -> b._in after 1 sec; + a1 = new Source(value = 1) + a2 = new Source(value = 2) + a3 = new Source(value = 3) + b = new[9] Destination(delay = 1 sec) + + (a1.out, a2.out, a3.out)+ -> b._in after 1 sec } diff --git a/test/Python/src/multiport/MultiportFromBank.lf b/test/Python/src/multiport/MultiportFromBank.lf index 73176f2112..639f726687 100644 --- a/test/Python/src/multiport/MultiportFromBank.lf +++ b/test/Python/src/multiport/MultiportFromBank.lf @@ -1,21 +1,20 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Python { - timeout: 2 sec, - fast: true -}; -reactor Source( - check_override(0), - bank_index(0) -) { - output out; +# Check multiport output to bank of recipients. Here, the bank is smaller than +# the width of the sending port. +target Python { timeout: 2 sec, fast: true } + +reactor Source(check_override(0), bank_index(0)) { + output out + reaction(startup) -> out {= out.set(self.bank_index * self.check_override) =} } + reactor Destination { - input[3] _in; - state received(0); + input[3] _in + + state received(0) + reaction(_in) {= for (idx, port) in enumerate(_in): print("Destination channel " + str(idx) + " received " + str(port.value)) @@ -25,6 +24,7 @@ reactor Destination { self.received = True =} + reaction(shutdown) {= if self.received is False: sys.stderr.write("ERROR: Destination received no input!\n") @@ -35,7 +35,8 @@ reactor Destination { } main reactor MultiportFromBank { - a = new[3] Source(check_override = 1); - b = new Destination(); - a.out -> b._in; + a = new[3] Source(check_override = 1) + b = new Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportFromBankHierarchy.lf b/test/Python/src/multiport/MultiportFromBankHierarchy.lf index 1fbe80d721..49c836884f 100644 --- a/test/Python/src/multiport/MultiportFromBankHierarchy.lf +++ b/test/Python/src/multiport/MultiportFromBankHierarchy.lf @@ -1,25 +1,26 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to bank of recipients. Here, the bank is smaller than +# the width of the sending port. +target Python { timeout: 2 sec, fast: true } + import Destination from "MultiportFromBank.lf" -reactor Source( - bank_index(0) -) { - output out; - reaction(startup) -> out {= - out.set(self.bank_index) - =} + +reactor Source(bank_index(0)) { + output out + + reaction(startup) -> out {= out.set(self.bank_index) =} } + reactor Container { - output[3] out; - s = new[3] Source(); - s.out -> out; + output[3] out + + s = new[3] Source() + + s.out -> out } + main reactor MultiportFromBankHierarchy { - a = new Container(); - b = new Destination(); - a.out -> b._in; + a = new Container() + b = new Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportFromBankHierarchyAfter.lf b/test/Python/src/multiport/MultiportFromBankHierarchyAfter.lf index d3657bbae5..cc1b1f133c 100644 --- a/test/Python/src/multiport/MultiportFromBankHierarchyAfter.lf +++ b/test/Python/src/multiport/MultiportFromBankHierarchyAfter.lf @@ -1,13 +1,13 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to bank of recipients. Here, the bank is smaller than +# the width of the sending port. +target Python { timeout: 2 sec, fast: true } + import Container from "MultiportFromBankHierarchy.lf" import Destination from "MultiportFromBank.lf" + main reactor MultiportFromBankHierarchyAfter { - a = new Container(); - b = new Destination(); - a.out -> b._in after 1 sec; + a = new Container() + b = new Destination() + + a.out -> b._in after 1 sec } diff --git a/test/Python/src/multiport/MultiportFromHierarchy.lf b/test/Python/src/multiport/MultiportFromHierarchy.lf index 6c839e98bd..84d8b2c60f 100644 --- a/test/Python/src/multiport/MultiportFromHierarchy.lf +++ b/test/Python/src/multiport/MultiportFromHierarchy.lf @@ -1,21 +1,26 @@ -// Check multiport output to multiport input, where the former is a hierarchical reactor. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input, where the former is a hierarchical +# reactor. +target Python { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out; - state s(0); + output[4] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set(self.s) self.s = self.s + 1 =} } + reactor Destination { - state s(6); - input[4] _in; + input[4] _in + + state s(6) + reaction(_in) {= sm = 0 for port in _in: @@ -27,6 +32,7 @@ reactor Destination { exit(1) self.s += 16 =} + reaction(shutdown) {= if self.s <= 6: sys.stderr.write("ERROR: Destination received no input!\n") @@ -34,20 +40,26 @@ reactor Destination { print("Success.") =} } + reactor Container { - output[4] out; - src = new InsideContainer(); - src.out -> out; + output[4] out + + src = new InsideContainer() + + src.out -> out } reactor InsideContainer { - output[4] out; - src = new Source(); - src.out -> out; + output[4] out + + src = new Source() + + src.out -> out } -main reactor MultiportFromHierarchy { - a = new Container(); - b = new Destination(); - a.out -> b._in; +main reactor MultiportFromHierarchy { + a = new Container() + b = new Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportFromReaction.lf b/test/Python/src/multiport/MultiportFromReaction.lf index bda0dce645..3cc1eca334 100644 --- a/test/Python/src/multiport/MultiportFromReaction.lf +++ b/test/Python/src/multiport/MultiportFromReaction.lf @@ -1,11 +1,11 @@ -// Check reaction to multiport input of a contained reactor. -target Python { - timeout: 2 sec, - fast: true -}; +# Check reaction to multiport input of a contained reactor. +target Python { timeout: 2 sec, fast: true } + reactor Destination(width(1)) { - state s(6); - input[width] _in; + input[width] _in + + state s(6) + reaction(_in) {= sm = 0; for port in _in: @@ -18,6 +18,7 @@ reactor Destination(width(1)) { self.s += 16 =} + reaction(shutdown) {= if self.s <= 6: sys.stderr.write("ERROR: Destination received no input!\n") @@ -25,10 +26,14 @@ reactor Destination(width(1)) { print("Success.") =} } + main reactor MultiportFromReaction { - timer t(0, 200 msec); - state s(0); - b = new Destination(width = 4); + timer t(0, 200 msec) + + b = new Destination(width = 4) + + state s(0) + reaction(t) -> b._in {= for (idx, port) in enumerate(b._in): print("Before SET, b.in[{:d}].is_present has value {:d}".format(idx, port.is_present)) diff --git a/test/Python/src/multiport/MultiportIn.lf b/test/Python/src/multiport/MultiportIn.lf index 31fd2c71e4..4c05ddabf5 100644 --- a/test/Python/src/multiport/MultiportIn.lf +++ b/test/Python/src/multiport/MultiportIn.lf @@ -1,29 +1,33 @@ -// This is a version fo the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target Python { - timeout: 2 sec, - fast: true -}; +# This is a version fo the Threaded test that uses a multiport input at the +# destination. Its purpose is to test multiport inputs. +target Python { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out; - state s(0); + output out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s+=1 =} } + reactor Computation { - input _in; - output out; - reaction(_in) -> out {= - out.set(_in.value) - =} + input _in + + output out + + reaction(_in) -> out {= out.set(_in.value) =} } + reactor Destination { - state s(0); - input[4] _in; + input[4] _in + + state s(0) + reaction(_in) {= sum = 0 for port in _in: @@ -36,6 +40,7 @@ reactor Destination { self.s += 4 =} + reaction(shutdown) {= if self.s == 0: sys.stderr.write("ERROR: Destination received no input!") @@ -46,15 +51,16 @@ reactor Destination { } main reactor MultiportIn { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1._in; - a.out -> t2._in; - a.out -> t3._in; - a.out -> t4._in; - t1.out, t2.out, t3.out, t4.out -> b._in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1._in + a.out -> t2._in + a.out -> t3._in + a.out -> t4._in + t1.out, t2.out, t3.out, t4.out -> b._in } diff --git a/test/Python/src/multiport/MultiportInParameterized.lf b/test/Python/src/multiport/MultiportInParameterized.lf index 253dcbd99e..57106d1beb 100644 --- a/test/Python/src/multiport/MultiportInParameterized.lf +++ b/test/Python/src/multiport/MultiportInParameterized.lf @@ -1,29 +1,33 @@ -// This is a version of the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target Python { - timeout: 2 sec, - fast: true -}; +# This is a version of the Threaded test that uses a multiport input at the +# destination. Its purpose is to test multiport inputs. +target Python { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out; - state s(0); + output out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= out.set(self.s) self.s += 1 =} } + reactor Computation { - input _in; - output out; - reaction(_in) -> out {= - out.set(_in.value) - =} + input _in + + output out + + reaction(_in) -> out {= out.set(_in.value) =} } + reactor Destination(width(1)) { - state s(0); - input[width] _in; + input[width] _in + + state s(0) + reaction(_in) {= sm = 0 for port in _in: @@ -34,6 +38,7 @@ reactor Destination(width(1)) { exit(1) self.s += 4 =} + reaction(shutdown) {= if self.s == 0: sys.stderr.write("ERROR: Destination received no input!\n") @@ -43,20 +48,18 @@ reactor Destination(width(1)) { } main reactor MultiportInParameterized { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(width = 4); - a.out -> t1._in; - a.out -> t2._in; - a.out -> t3._in; - a.out -> t4._in; - t1.out, t2.out, t3.out, t4.out -> b._in; - // I.e.: - // t1.out -> b._in[0]; - // t2.out -> b._in[1]; - // t3.out -> b._in[2]; - // dt4.out -> b._in[3]; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination(width = 4) + + a.out -> t1._in + a.out -> t2._in + a.out -> t3._in + a.out -> t4._in + # I.e.: t1.out -> b._in[0]; t2.out -> b._in[1]; t3.out -> b._in[2]; dt4.out + # -> b._in[3]; + t1.out, t2.out, t3.out, t4.out -> b._in } diff --git a/test/Python/src/multiport/MultiportMutableInput.lf b/test/Python/src/multiport/MultiportMutableInput.lf index 0b3ff9bab7..5e7910aca9 100644 --- a/test/Python/src/multiport/MultiportMutableInput.lf +++ b/test/Python/src/multiport/MultiportMutableInput.lf @@ -1,18 +1,20 @@ -// Source produces a ints on a multiport, which it passes -// to Scale. Scale requests a writable copy. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target Python; +# Source produces a ints on a multiport, which it passes to Scale. Scale +# requests a writable copy. It modifies it and passes it to Print. It gets freed +# after Print is done with it. +target Python + reactor Source { - output[2] out; + output[2] out + reaction(startup) -> out {= out[0].set(21) out[1].set(42) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input[2] _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input[2] _in + reaction(_in) {= expected = 42 for (idx, port) in enumerate(_in): @@ -25,8 +27,10 @@ reactor Print(scale(1)) { } reactor Scale(scale(2)) { - mutable input[2] _in; - output[2] out; + mutable input[2] _in + + output[2] out + reaction(_in) -> out {= for (idx, port) in enumerate(_in): # Modify the input, allowed because mutable. @@ -34,10 +38,12 @@ reactor Scale(scale(2)) { out[idx].set(port.value) =} } + main reactor MultiportMutableInput { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c._in; - c.out -> p._in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c._in + c.out -> p._in } diff --git a/test/Python/src/multiport/MultiportMutableInputArray.lf b/test/Python/src/multiport/MultiportMutableInputArray.lf index 45e618ec9f..cfd507b572 100644 --- a/test/Python/src/multiport/MultiportMutableInputArray.lf +++ b/test/Python/src/multiport/MultiportMutableInputArray.lf @@ -1,19 +1,21 @@ -// Source produces a list on a multiport, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original list. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target Python; +# Source produces a list on a multiport, which it passes to Scale. Scale +# requests a writable copy, which, instead of copying, it just gets ownership of +# the original list. It modifies it and passes it to Print. It gets freed after +# Print is done with it. +target Python + reactor Source { - output[2] out; + output[2] out + reaction(startup) -> out {= out[0].set([0,1,2]) out[1].set([3,4,5]) =} } -// The scale parameter is just for testing. -reactor Print(scale(1)) { - input[2] _in; + +reactor Print(scale(1)) { # The scale parameter is just for testing. + input[2] _in + reaction(_in) {= for (idx, port) in enumerate(_in): print("Received on channel ", port.value) @@ -24,8 +26,10 @@ reactor Print(scale(1)) { } reactor Scale(scale(2)) { - mutable input[2] _in; - output[2] out; + mutable input[2] _in + + output[2] out + reaction(_in) -> out {= for (idx, port) in enumerate(_in): if port.is_present: @@ -35,9 +39,10 @@ reactor Scale(scale(2)) { } main reactor MultiportMutableInputArray { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c._in; - c.out -> p._in; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c._in + c.out -> p._in } diff --git a/test/Python/src/multiport/MultiportOut.lf b/test/Python/src/multiport/MultiportOut.lf index 14ab11a3d8..c20554a616 100644 --- a/test/Python/src/multiport/MultiportOut.lf +++ b/test/Python/src/multiport/MultiportOut.lf @@ -1,12 +1,13 @@ -// Check multiport capabilities on Outputs. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport capabilities on Outputs. +target Python { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out; - state s(0); + output[4] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set(self.s) @@ -14,16 +15,20 @@ reactor Source { self.s+=1 =} } + reactor Computation { - input _in; - output out; - reaction(_in) -> out {= - out.set(_in.value) - =} + input _in + + output out + + reaction(_in) -> out {= out.set(_in.value) =} } + reactor Destination { - state s(0); - input[4] _in; + input[4] _in + + state s(0) + reaction(_in) {= sum = 0 for port in _in: @@ -37,6 +42,7 @@ reactor Destination { self.s += 4 =} + reaction(shutdown) {= if self.s == 0: sys.stderr.write("ERROR: Destination received no input!") @@ -47,12 +53,13 @@ reactor Destination { } main reactor MultiportOut { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1._in, t2._in, t3._in, t4._in; - t1.out, t2.out, t3.out, t4.out -> b._in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1._in, t2._in, t3._in, t4._in + t1.out, t2.out, t3.out, t4.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToBank.lf b/test/Python/src/multiport/MultiportToBank.lf index 8a6327d9d4..58b328e5dd 100644 --- a/test/Python/src/multiport/MultiportToBank.lf +++ b/test/Python/src/multiport/MultiportToBank.lf @@ -1,20 +1,20 @@ -// Check multiport output to bank of recipients. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to bank of recipients. +target Python { timeout: 2 sec, fast: true } + reactor Source { - output[3] out; + output[3] out + reaction(startup) -> out {= for (idx, port) in enumerate(out): port.set(idx) =} } -reactor Destination( - bank_index(0) -) { - input _in; - state received(0); + +reactor Destination(bank_index(0)) { + input _in + + state received(0) + reaction(_in) {= print("Destination " + str(self.bank_index) + " received " + str(_in.value)) if self.bank_index != _in.value: @@ -22,6 +22,7 @@ reactor Destination( exit(1) self.received = True =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write("ERROR: Destination " + str(self.bank_index) + " received no input!\n") @@ -31,7 +32,8 @@ reactor Destination( } main reactor MultiportToBank { - a = new Source(); - b = new[3] Destination(); - a.out -> b._in; + a = new Source() + b = new[3] Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToBankAfter.lf b/test/Python/src/multiport/MultiportToBankAfter.lf index 576d5f5743..ea032d0ec0 100644 --- a/test/Python/src/multiport/MultiportToBankAfter.lf +++ b/test/Python/src/multiport/MultiportToBankAfter.lf @@ -1,14 +1,14 @@ -// Check multiport output to bank of recipients where the width of the bank is inferred. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to bank of recipients where the width of the bank is +# inferred. +target Python { timeout: 2 sec, fast: true } + import Source from "MultiportToBank.lf" -reactor Destination( - bank_index(0) -) { - input _in; - state received(false); + +reactor Destination(bank_index(0)) { + input _in + + state received(false) + reaction(_in) {= print("Destination {:d} received {:d}.".format(self.bank_index, _in.value)) if self.bank_index != _in.value: @@ -19,6 +19,7 @@ reactor Destination( exit(2) self.received = True =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write("ERROR: Destination {:d} received no input!\n".format(self.bank_index)) @@ -28,7 +29,8 @@ reactor Destination( } main reactor MultiportToBankAfter { - a = new Source(); - b = new[3] Destination(); - a.out -> b._in after 1 sec; // Width of the bank of delays will be inferred. + a = new Source() + b = new[3] Destination() + + a.out -> b._in after 1 sec # Width of the bank of delays will be inferred. } diff --git a/test/Python/src/multiport/MultiportToBankHierarchy.lf b/test/Python/src/multiport/MultiportToBankHierarchy.lf index af3b2bd9cf..ecc186525f 100644 --- a/test/Python/src/multiport/MultiportToBankHierarchy.lf +++ b/test/Python/src/multiport/MultiportToBankHierarchy.lf @@ -1,15 +1,14 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to bank of recipients. Here, the bank is smaller than +# the width of the sending port. +target Python { timeout: 2 sec, fast: true } + import Source from "MultiportToBank.lf" -reactor Destination( - bank_index(0) -) { - input _in; - state received(false); + +reactor Destination(bank_index(0)) { + input _in + + state received(false) + reaction(_in) {= print("Destination {:d} received {:d}.\n".format(self.bank_index, _in.value)) if self.bank_index != _in.value: @@ -17,6 +16,7 @@ reactor Destination( exit(1) self.received = True =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write("ERROR: Destination {:d} received no input!\n".format(self.bank_index)) @@ -24,14 +24,18 @@ reactor Destination( print("Success.") =} } + reactor Container { - input[3] _in; - c = new[3] Destination(); - _in -> c._in; + input[3] _in + + c = new[3] Destination() + + _in -> c._in } main reactor MultiportToBankHierarchy { - a = new Source(); - b = new Container(); - a.out -> b._in; + a = new Source() + b = new Container() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToHierarchy.lf b/test/Python/src/multiport/MultiportToHierarchy.lf index 981513dc13..445e1b9921 100644 --- a/test/Python/src/multiport/MultiportToHierarchy.lf +++ b/test/Python/src/multiport/MultiportToHierarchy.lf @@ -1,22 +1,27 @@ -// Check multiport output to multiport input, where the latter is a hierarchical reactor. -// Note that the destination reactor has width wider than the sender, so one input is dangling. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input, where the latter is a hierarchical +# reactor. Note that the destination reactor has width wider than the sender, so +# one input is dangling. +target Python { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[4] out; - state s(0); + output[4] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set(self.s) self.s += 1 =} } + reactor Destination(width(4)) { - state s(6); - input[width] _in; + input[width] _in + + state s(6) + reaction(_in) {= sm = 0 for port in _in: @@ -28,6 +33,7 @@ reactor Destination(width(4)) { exit(1) self.s += 16 =} + reaction(shutdown) {= if self.s <= 6: sys.stderr.write("ERROR: Destination received no input!\n") @@ -35,14 +41,18 @@ reactor Destination(width(4)) { print("Success.") =} } + reactor Container(width(4)) { - input[width] _in; - dst = new Destination(); - _in -> dst._in; + input[width] _in + + dst = new Destination() + + _in -> dst._in } -main reactor MultiportToHierarchy { - a = new Source(); - b = new Container(); - a.out -> b._in; +main reactor MultiportToHierarchy { + a = new Source() + b = new Container() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToMultiport.lf b/test/Python/src/multiport/MultiportToMultiport.lf index 7ab864f4e4..5b5b8c7a9d 100644 --- a/test/Python/src/multiport/MultiportToMultiport.lf +++ b/test/Python/src/multiport/MultiportToMultiport.lf @@ -1,13 +1,15 @@ -// Check multiport output to multiport input. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input. +target Python { timeout: 2 sec, fast: true } + import Destination from "MultiportToHierarchy.lf" + reactor Source(width(1)) { - timer t(0, 200 msec); - output[width] out; - state s(0); + output[width] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for i in range(len(out)): print("Before SET, out[{:d}]->is_present has value %d".format(i), out[i].is_present) @@ -17,8 +19,10 @@ reactor Source(width(1)) { print("AFTER set, out[{:d}]->value has value ".format(i), out[i].value) =} } + main reactor MultiportToMultiport { - a = new Source(width = 4); - b = new Destination(width = 4); - a.out -> b._in; + a = new Source(width = 4) + b = new Destination(width = 4) + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToMultiport2.lf b/test/Python/src/multiport/MultiportToMultiport2.lf index 18008842dd..7d0bb85b3d 100644 --- a/test/Python/src/multiport/MultiportToMultiport2.lf +++ b/test/Python/src/multiport/MultiportToMultiport2.lf @@ -1,18 +1,19 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target Python; +# Test multiport to multiport connections. See also MultiportToMultiport. +target Python reactor Source(width(2)) { - output[width] out; - reaction (startup) -> out {= + output[width] out + + reaction(startup) -> out {= for (idx, port) in enumerate(out): port.set(idx) =} } reactor Destination(width(2)) { - input[width] _in; - reaction (_in) {= + input[width] _in + + reaction(_in) {= for (idx, port) in enumerate(_in): if port.is_present: print("Received on channel {:d}: ".format(idx), port.value) @@ -25,8 +26,9 @@ reactor Destination(width(2)) { } main reactor MultiportToMultiport2 { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b._in; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToMultiport2After.lf b/test/Python/src/multiport/MultiportToMultiport2After.lf index 9732d7c284..16003394f9 100644 --- a/test/Python/src/multiport/MultiportToMultiport2After.lf +++ b/test/Python/src/multiport/MultiportToMultiport2After.lf @@ -1,11 +1,12 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target Python; +# Test multiport to multiport connections. See also MultiportToMultiport. +target Python import Source from "MultiportToMultiport2.lf" + reactor Destination(width(2)) { - input[width] _in; - reaction (_in) {= + input[width] _in + + reaction(_in) {= for (idx, port) in enumerate(_in): if port.is_present: print("Received on channel {:d}: ".format(idx), port.value) @@ -21,8 +22,9 @@ reactor Destination(width(2)) { } main reactor MultiportToMultiport2After { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b._in after 1 sec; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b._in after 1 sec } diff --git a/test/Python/src/multiport/MultiportToMultiportArray.lf b/test/Python/src/multiport/MultiportToMultiportArray.lf index 86ea005f97..a718d8ea2e 100644 --- a/test/Python/src/multiport/MultiportToMultiportArray.lf +++ b/test/Python/src/multiport/MultiportToMultiportArray.lf @@ -1,13 +1,14 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input. Destination port is wider than +# sending port. +target Python { timeout: 2 sec, fast: true } + reactor Source { - timer t(0, 200 msec); - output[2] out; - state s(0); + output[2] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set([self.s, self.s + 1, self.s + 2]) @@ -16,8 +17,10 @@ reactor Source { } reactor Destination { - state s(15); - input[2] _in; + input[2] _in + + state s(15) + reaction(_in) {= sm = 0 for port in _in: @@ -31,6 +34,7 @@ reactor Destination { self.s += 36 =} + reaction(shutdown) {= if self.s <= 15: sys.stderr.write("ERROR: Destination received no input!\n") @@ -40,7 +44,8 @@ reactor Destination { } main reactor MultiportToMultiportArray { - a = new Source(); - b = new Destination(); - a.out -> b._in; + a = new Source() + b = new Destination() + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToMultiportParameter.lf b/test/Python/src/multiport/MultiportToMultiportParameter.lf index b71df08616..e56e39ec2d 100644 --- a/test/Python/src/multiport/MultiportToMultiportParameter.lf +++ b/test/Python/src/multiport/MultiportToMultiportParameter.lf @@ -1,12 +1,12 @@ -// Check multiport output to multiport input. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input. +target Python { timeout: 2 sec, fast: true } + import Source from "MultiportToMultiport.lf" import Destination from "MultiportToHierarchy.lf" -main reactor MultiportToMultiportParameter (width(4)) { - a = new Source(width = width); - b = new Destination(width = width); - a.out -> b._in; + +main reactor MultiportToMultiportParameter(width(4)) { + a = new Source(width = width) + b = new Destination(width = width) + + a.out -> b._in } diff --git a/test/Python/src/multiport/MultiportToPort.lf b/test/Python/src/multiport/MultiportToPort.lf index 50e98e9124..4cb53dbef9 100644 --- a/test/Python/src/multiport/MultiportToPort.lf +++ b/test/Python/src/multiport/MultiportToPort.lf @@ -1,20 +1,22 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target Python { - timeout: 2 sec, - fast: true -}; +# Check multiport output to multiport input. Destination port is wider than +# sending port. +target Python { timeout: 2 sec, fast: true } + reactor Source { - output[2] out; + output[2] out + reaction(startup) -> out {= for (idx, port) in enumerate(out): print("Source sending ", idx) port.set(idx) =} } + reactor Destination(expected(0)) { - input _in; - state received(false); + input _in + + state received(false) + reaction(_in) {= print("Received: ", _in.value) self.received = True @@ -22,6 +24,7 @@ reactor Destination(expected(0)) { sys.stderr.write("ERROR: Expected {:d}.\n".format(self.expected)) exit(1) =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write("ERROR: Destination received no input!\n") @@ -31,8 +34,9 @@ reactor Destination(expected(0)) { } main reactor MultiportToPort { - a = new Source(); - b1 = new Destination(); - b2 = new Destination(expected = 1); - a.out -> b1._in, b2._in; + a = new Source() + b1 = new Destination() + b2 = new Destination(expected = 1) + + a.out -> b1._in, b2._in } diff --git a/test/Python/src/multiport/MultiportToReaction.lf b/test/Python/src/multiport/MultiportToReaction.lf index 51430a4a96..7f575eeae9 100644 --- a/test/Python/src/multiport/MultiportToReaction.lf +++ b/test/Python/src/multiport/MultiportToReaction.lf @@ -1,20 +1,25 @@ -// Check reaction to multiport output of a contained reactor. -target Python { - timeout: 2 sec, - fast: true -}; +# Check reaction to multiport output of a contained reactor. +target Python { timeout: 2 sec, fast: true } + reactor Source(width(1)) { - timer t(0, 200 msec); - state s(0); - output[width] out; + output[width] out + + timer t(0, 200 msec) + + state s(0) + reaction(t) -> out {= for port in out: port.set(self.s) self.s += 1 =} } + main reactor { - state s(6); + b = new Source(width = 4) + + state s(6) + reaction(b.out) {= sm = 0 for port in b.out: @@ -26,11 +31,11 @@ main reactor { exit(1) self.s += 16 =} + reaction(shutdown) {= if self.s <= 6: sys.stderr.write("ERROR: Destination received no input!\n") exit(1) print("Success.") =} - b = new Source(width = 4); } diff --git a/test/Python/src/multiport/NestedBanks.lf b/test/Python/src/multiport/NestedBanks.lf index 055477e59e..c842cdcce0 100644 --- a/test/Python/src/multiport/NestedBanks.lf +++ b/test/Python/src/multiport/NestedBanks.lf @@ -2,36 +2,47 @@ * Test of nested banks with multiports. * @author Edward A. Lee */ -target Python; +target Python + main reactor { - a = new[2] A(); - c = new[3] C(); - d = new D(); - e = new E(); + a = new[2] A() + c = new[3] C() + d = new D() + e = new E() - (a.x)+ -> c.z, d.u, e.t; + (a.x)+ -> c.z, d.u, e.t } + reactor A(bank_index(0)) { - output[4] x; - b = new[2] B(a_bank_index = bank_index); - b.y -> x; + output[4] x + + b = new[2] B(a_bank_index = bank_index) + + b.y -> x } + reactor B(a_bank_index(0), bank_index(0)) { - output[2] y; + output[2] y + reaction(startup) -> y {= base = self.a_bank_index * 4 + self.bank_index * 2 y[0].set(base) y[1].set(base + 1) =} } + reactor C(bank_index(0)) { - input[2] z; - f = new F(c_bank_index = bank_index); - g = new G(c_bank_index = bank_index); - z -> f.w, g.s; + input[2] z + + f = new F(c_bank_index = bank_index) + g = new G(c_bank_index = bank_index) + + z -> f.w, g.s } + reactor D { - input[2] u; + input[2] u + reaction(u) {= for (i, p) in enumerate(u): print(f"d.u[{i}] received {p.value}.") @@ -40,15 +51,19 @@ reactor D { exit(1) =} } + reactor E { - input[8] t; + input[8] t + reaction(t) {= for (i, p) in enumerate(t): print(f"e.t[{i}] received {p.value}.") =} } + reactor F(c_bank_index(0)) { - input w; + input w + reaction(w) {= print(f"c[{self.c_bank_index}].f.w received {w.value}.") if w.value != self.c_bank_index * 2: @@ -56,12 +71,14 @@ reactor F(c_bank_index(0)) { exit(1) =} } + reactor G(c_bank_index(0)) { - input s; + input s + reaction(s) {= - print(f"c[{self.c_bank_index}].g.s received {s.value}.") - if s.value != (self.c_bank_index * 2 + 1): - sys.stderr.write(f"ERROR: Expected {self.c_bank_index * 2 + 1} but received {s.value}.\n") - exit(1) + print(f"c[{self.c_bank_index}].g.s received {s.value}.") + if s.value != (self.c_bank_index * 2 + 1): + sys.stderr.write(f"ERROR: Expected {self.c_bank_index * 2 + 1} but received {s.value}.\n") + exit(1) =} } diff --git a/test/Python/src/multiport/NestedInterleavedBanks.lf b/test/Python/src/multiport/NestedInterleavedBanks.lf index f38376cb0e..021528401b 100644 --- a/test/Python/src/multiport/NestedInterleavedBanks.lf +++ b/test/Python/src/multiport/NestedInterleavedBanks.lf @@ -2,22 +2,29 @@ * Test nested banks with interleaving. * @author Edward A. Lee */ -target Python; +target Python + reactor A(bank_index(0), outer_bank_index(0)) { - output[2] p; + output[2] p + reaction(startup) -> p {= for i, port in enumerate(p): port.set(self.outer_bank_index * 4 + self.bank_index * 2 + i + 1) print(f"A sending {port.value}.") =} } + reactor B(bank_index(0)) { - output[4] q; - a = new[2] A(outer_bank_index = bank_index); - interleaved(a.p) -> q; + output[4] q + + a = new[2] A(outer_bank_index = bank_index) + + interleaved (a.p) -> q } + reactor C { - input[8] i; + input[8] i + reaction(i) {= expected = [1, 3, 2, 4, 5, 7, 6, 8] for j, port in enumerate(i): @@ -27,8 +34,10 @@ reactor C { exit(1) =} } + main reactor { - b = new[2] B(); - c = new C(); - b.q -> c.i; + b = new[2] B() + c = new C() + + b.q -> c.i } diff --git a/test/Python/src/multiport/PipelineAfter.lf b/test/Python/src/multiport/PipelineAfter.lf index 1bf8b65bdd..77a4aee606 100644 --- a/test/Python/src/multiport/PipelineAfter.lf +++ b/test/Python/src/multiport/PipelineAfter.lf @@ -1,26 +1,23 @@ -target Python; +target Python reactor Source { - output out; + output out - reaction (startup) -> out {= - out.set(40) - =} + reaction(startup) -> out {= out.set(40) =} } reactor Compute { - input inp; - output out; + input inp - reaction (inp) -> out {= - out.set(inp.value + 2) - =} + output out + + reaction(inp) -> out {= out.set(inp.value + 2) =} } reactor Sink { - input inp; + input inp - reaction (inp) {= + reaction(inp) {= print(f"Received {inp.value}") if inp.value != 42: sys.stderr.write("ERROR: expected 42!\n") @@ -29,13 +26,12 @@ reactor Sink { sys.stderr.write("ERROR: Expected to receive input after one second.\n") exit(2) =} - } main reactor { - source = new Source(); - compute = new Compute(); - sink = new Sink(); + source = new Source() + compute = new Compute() + sink = new Sink() - source.out, compute.out -> compute.inp, sink.inp after 500 msec; + source.out, compute.out -> compute.inp, sink.inp after 500 msec } diff --git a/test/Python/src/multiport/ReactionsToNested.lf b/test/Python/src/multiport/ReactionsToNested.lf index 8a5d4e6c45..3de41bde23 100644 --- a/test/Python/src/multiport/ReactionsToNested.lf +++ b/test/Python/src/multiport/ReactionsToNested.lf @@ -1,11 +1,12 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target Python { - timeout: 1 sec -}; +# This test connects a simple counting source to tester that checks against its +# own count. +target Python { timeout: 1 sec } + reactor T(expected(0)) { - input z; - state received(false); + input z + + state received(false) + reaction(z) {= print(f"T received {z.value}.") self.received = True @@ -13,6 +14,7 @@ reactor T(expected(0)) { sys.stderr.write(f"ERROR: Expected {self.response}") exit(1) =} + reaction(shutdown) {= if self.received is not True: sys.stderr.write(f"ERROR: No input received.") @@ -21,18 +23,18 @@ reactor T(expected(0)) { } reactor D { - input[2] y; - t1 = new T(expected = 42); - t2 = new T(expected = 43); - y -> t1.z, t2.z; + input[2] y + + t1 = new T(expected = 42) + t2 = new T(expected = 43) + + y -> t1.z, t2.z } main reactor { - d = new D(); - reaction(startup) -> d.y {= - d.y[0].set(42) - =} - reaction(startup) -> d.y {= - d.y[1].set(43) - =} + d = new D() + + reaction(startup) -> d.y {= d.y[0].set(42) =} + + reaction(startup) -> d.y {= d.y[1].set(43) =} } diff --git a/test/Python/src/serialization/PersonProtocolBuffers.lf b/test/Python/src/serialization/PersonProtocolBuffers.lf index 76a979c2c8..bbda8e7292 100644 --- a/test/Python/src/serialization/PersonProtocolBuffers.lf +++ b/test/Python/src/serialization/PersonProtocolBuffers.lf @@ -1,26 +1,25 @@ -/** This example demonstrates a very simple use of protocol buffers - * within a reactor. It encodes and decodes a very simple protocol - * buffer definition in Person.proto. This reactor is heavily - * based on the examples at https://github.com/protobuf-c/protobuf-c/wiki/Examples. - * This example just packs and unpacks a message. +/** + * This example demonstrates a very simple use of protocol buffers within a + * reactor. It encodes and decodes a very simple protocol buffer definition in + * Person.proto. This reactor is heavily based on the examples at + * https://github.com/protobuf-c/protobuf-c/wiki/Examples. This example just + * packs and unpacks a message. * - * To run this example first install the protocol buffers compiler - * from https://github.com/protocolbuffers/protobuf. It is also - * available from homebrew on a Mac via + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from + * homebrew on a Mac via * - * $ brew install protobuf + * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that - * if possible. Next, install the Google APIs for Python + * Building protobuf from source is slow, so avoid doing that if possible. Next, + * install the Google APIs for Python * - * $ pip3 install --upgrade google-api-python-client + * $ pip3 install --upgrade google-api-python-client * - * The code generator assumes - * that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. + * The code generator assumes that executables are installed within the PATH. On + * a Mac, this is typically at /usr/local/bin. */ - -target Python {protobufs: Person.proto}; +target Python { protobufs: Person.proto } main reactor { reaction(startup) {= diff --git a/test/Python/src/serialization/ProtoNoPacking.lf b/test/Python/src/serialization/ProtoNoPacking.lf index a7798105c8..fe5d6835bc 100644 --- a/test/Python/src/serialization/ProtoNoPacking.lf +++ b/test/Python/src/serialization/ProtoNoPacking.lf @@ -1,27 +1,28 @@ -/** This example creates a Protocol Buffer message and passes it to - * another reactor without packing and unpacking. This demonstrates - * that local communication, within one shared-memory machine, need - * not incur the overhead of packing and unpacking. +/** + * This example creates a Protocol Buffer message and passes it to another + * reactor without packing and unpacking. This demonstrates that local + * communication, within one shared-memory machine, need not incur the overhead + * of packing and unpacking. * - * To run this example first install the protocol buffers compiler - * from https://github.com/protocolbuffers/protobuf. It is also - * available from homebrew on a Mac via + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from + * homebrew on a Mac via * - * $ brew install protobuf + * $ brew install protobuf * - * Building protobuf from source is slow, so avoid doing that - * if possible. Next, install the Google APIs for Python + * Building protobuf from source is slow, so avoid doing that if possible. Next, + * install the Google APIs for Python * - * $ pip3 install --upgrade google-api-python-client + * $ pip3 install --upgrade google-api-python-client * - * The code generator assumes - * that executables are installed within the PATH. On a Mac, this is - * typically at /usr/local/bin. + * The code generator assumes that executables are installed within the PATH. On + * a Mac, this is typically at /usr/local/bin. */ -target Python {protobufs: ProtoHelloWorld.proto}; +target Python { protobufs: ProtoHelloWorld.proto } reactor SourceProto { - output out; + output out + reaction(startup) -> out {= message = ProtoHelloWorld.ProtoHelloWorld() message.name = "Hello World" @@ -31,14 +32,16 @@ reactor SourceProto { } reactor SinkProto { - input _in; + input _in + reaction(_in) {= print("Received: name='{:s}', number={:d}.".format(_in.value.name, _in.value.number)) =} } main reactor ProtoNoPacking { - s = new SourceProto(); - d = new SinkProto(); - s.out -> d._in; + s = new SourceProto() + d = new SinkProto() + + s.out -> d._in } diff --git a/test/Python/src/target/AfterNoTypes.lf b/test/Python/src/target/AfterNoTypes.lf index 649ccc62f6..37bca7f813 100644 --- a/test/Python/src/target/AfterNoTypes.lf +++ b/test/Python/src/target/AfterNoTypes.lf @@ -1,21 +1,21 @@ -// This test demonstrates that after can be used on connections -// with ports that have no types. The test passes if the compile is succeeded -target Python { - fast: false, - timeout: 3 sec -}; +# This test demonstrates that after can be used on connections with ports that +# have no types. The test passes if the compile is succeeded +target Python { fast: false, timeout: 3 sec } reactor Foo { - input x; - output y; - reaction(x) -> y {= - y.set(2*x.value); - =} + input x + + output y + + reaction(x) -> y {= y.set(2*x.value); =} } + reactor Print { - state expected_time(10 msec); - state received(0); - input x; + input x + + state expected_time(10 msec) + state received(0) + reaction(x) {= self.received+=1 elapsed_time = lf.time.logical_elapsed() @@ -31,18 +31,21 @@ reactor Print { exit(2) self.expected_time += SEC(1) =} + reaction(shutdown) {= if (self.received == 0): sys.stderr.write("ERROR: Final reactor received no data.\n") exit(3) =} } + main reactor { - f = new Foo(); - p = new Print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x.set(42) - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new Foo() + p = new Print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= f.x.set(42) =} } From 3075a0680b6a9bc375e2476dc7005e7b070503e0 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 00:06:38 -0700 Subject: [PATCH 091/130] [formatting] Repair regex. --- org.lflang/src/org/lflang/ast/FormattingUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index cffa844a82..690162e72d 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -27,7 +27,7 @@ public class FormattingUtils { /** Match a multiline comment. */ private static final Pattern MULTILINE_COMMENT = Pattern.compile( - "\\s*/\\*\\v?(\\V*\\v+)+\\V*" + "\\s*/\\*\\v?(\\V*\\v+)*\\V*" ); /** The number of spaces to prepend to a line per indentation level. */ From c23dd5d659f4ab6356b7bfdec71bbeb8e0569930 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 14:02:29 -0700 Subject: [PATCH 092/130] [formatting] Format Rust tests. --- test/Rust/src/ActionDelay.lf | 10 +-- test/Rust/src/ActionImplicitDelay.lf | 11 ++- test/Rust/src/ActionIsPresent.lf | 10 +-- test/Rust/src/ActionIsPresentDouble.lf | 7 +- test/Rust/src/ActionScheduleMicrostep.lf | 7 +- test/Rust/src/ActionValues.lf | 11 +-- test/Rust/src/ActionValuesCleanup.lf | 6 +- .../src/CompositionInitializationOrder.lf | 27 +++---- test/Rust/src/CompositionWithPorts.lf | 21 +++--- test/Rust/src/CtorParamDefault.lf | 9 +-- test/Rust/src/CtorParamMixed.lf | 13 ++-- test/Rust/src/CtorParamSimple.lf | 9 +-- test/Rust/src/DependencyOnChildPort.lf | 25 ++++--- test/Rust/src/DependencyUseAccessible.lf | 42 ++++++----- test/Rust/src/DependencyUseNonTrigger.lf | 19 ++--- test/Rust/src/DependencyUseOnLogicalAction.lf | 15 ++-- test/Rust/src/FloatLiteral.lf | 7 +- test/Rust/src/Import.lf | 19 ++--- test/Rust/src/ImportPreambleItem.lf | 18 ++--- test/Rust/src/MainReactorParam.lf | 13 ++-- test/Rust/src/Minimal.lf | 7 +- test/Rust/src/MovingAverage.lf | 54 ++++++++------ test/Rust/src/NativeListsAndTimes.lf | 71 ++++++++++--------- .../src/PhysicalActionKeepaliveIsSmart.lf | 11 ++- .../PhysicalActionWakesSleepingScheduler.lf | 29 ++++---- test/Rust/src/PhysicalActionWithKeepalive.lf | 8 +-- test/Rust/src/PortConnectionInSelfInChild.lf | 23 +++--- test/Rust/src/PortConnectionInSelfOutSelf.lf | 39 +++++----- .../Rust/src/PortConnectionOutChildOutSelf.lf | 32 +++++---- test/Rust/src/PortRefCleanup.lf | 19 ++--- test/Rust/src/PortValueCleanup.lf | 23 +++--- test/Rust/src/Preamble.lf | 8 +-- test/Rust/src/ReactionLabels.lf | 15 ++-- test/Rust/src/ReservedKeywords.lf | 29 ++++---- test/Rust/src/SingleFileGeneration.lf | 22 +++--- test/Rust/src/StateDefaultValue.lf | 10 ++- test/Rust/src/StateInitializerVisibility.lf | 10 +-- test/Rust/src/Stop.lf | 37 +++++----- test/Rust/src/StopAsync.lf | 3 +- test/Rust/src/StopCleanup.lf | 17 +++-- test/Rust/src/StopDuringStartup.lf | 6 +- test/Rust/src/StopIdempotence.lf | 10 +-- test/Rust/src/StopNoEvent.lf | 11 +-- test/Rust/src/StopTimeout.lf | 10 +-- test/Rust/src/StopTimeoutExact.lf | 15 ++-- test/Rust/src/StopTopology.lf | 12 ++-- test/Rust/src/StructAsState.lf | 23 +++--- test/Rust/src/StructAsType.lf | 27 +++---- test/Rust/src/TimeState.lf | 9 +-- test/Rust/src/TimerDefaults.lf | 9 ++- test/Rust/src/TimerIsPresent.lf | 17 ++--- test/Rust/src/TimerPeriodic.lf | 11 +-- test/Rust/src/Timers.lf | 26 +++---- test/Rust/src/TypeVarLengthList.lf | 25 ++++--- test/Rust/src/concurrent/Workers.lf | 3 +- test/Rust/src/generics/CtorParamGeneric.lf | 17 ++--- .../Rust/src/generics/CtorParamGenericInst.lf | 36 +++++----- test/Rust/src/generics/GenericReactor.lf | 22 +++--- test/Rust/src/lib/Imported.lf | 19 ++--- test/Rust/src/lib/ImportedAgain.lf | 10 +-- test/Rust/src/lib/SomethingWithAPreamble.lf | 9 +-- .../src/multiport/ConnectionToSelfBank.lf | 19 ++--- .../multiport/ConnectionToSelfMultiport.lf | 16 +++-- test/Rust/src/multiport/CycledLhs_SelfLoop.lf | 29 ++++---- test/Rust/src/multiport/CycledLhs_Single.lf | 64 ++++++++--------- test/Rust/src/multiport/FullyConnected.lf | 21 +++--- .../multiport/FullyConnectedAddressable.lf | 29 ++++---- test/Rust/src/multiport/MultiportFromBank.lf | 26 +++---- .../src/multiport/MultiportFromHierarchy.lf | 51 ++++++++----- test/Rust/src/multiport/MultiportIn.lf | 56 ++++++++------- test/Rust/src/multiport/MultiportOut.lf | 46 +++++++----- test/Rust/src/multiport/MultiportToBank.lf | 21 +++--- .../src/multiport/MultiportToBankHierarchy.lf | 30 ++++---- .../src/multiport/MultiportToMultiport.lf | 17 ++--- .../src/multiport/MultiportToMultiport2.lf | 24 ++++--- .../src/target/BuildProfileDefaultIsDev.lf | 7 +- test/Rust/src/target/BuildProfileRelease.lf | 9 +-- test/Rust/src/target/CargoDependency.lf | 20 +++--- .../src/target/CargoDependencyOnRuntime.lf | 19 +++-- test/Rust/src/target/CliFeature.lf | 12 +--- test/Rust/src/target/ModuleDependency.lf | 16 ++--- .../target/ModuleDependencyWithDirModule.lf | 6 +- 82 files changed, 839 insertions(+), 792 deletions(-) diff --git a/test/Rust/src/ActionDelay.lf b/test/Rust/src/ActionDelay.lf index eaa87d700a..d33b4070a4 100644 --- a/test/Rust/src/ActionDelay.lf +++ b/test/Rust/src/ActionDelay.lf @@ -1,10 +1,11 @@ // Test logical action with delay. -target Rust; +target Rust main reactor ActionDelay { - logical action act0; - logical action act1(100 msec); - state count: u32(0); + logical action act0 + logical action act1(100 msec) + + state count: u32(0) reaction(startup) -> act0, act1 {= ctx.schedule(act0, after!(100 ms)); @@ -25,5 +26,4 @@ main reactor ActionDelay { assert_eq!(2, self.count); println!("SUCCESS") =} - } diff --git a/test/Rust/src/ActionImplicitDelay.lf b/test/Rust/src/ActionImplicitDelay.lf index 1d78a11a11..caa556b50a 100644 --- a/test/Rust/src/ActionImplicitDelay.lf +++ b/test/Rust/src/ActionImplicitDelay.lf @@ -1,13 +1,12 @@ // Test logical action with delay. -target Rust; +target Rust main reactor ActionImplicitDelay { - logical action act(40 msec); - state count: u64(1); + logical action act(40 msec) - reaction(startup) -> act {= - ctx.schedule(act, Asap); - =} + state count: u64(1) + + reaction(startup) -> act {= ctx.schedule(act, Asap); =} reaction(act) -> act {= assert_tag_is!(ctx, T0 + (40 * self.count) ms); diff --git a/test/Rust/src/ActionIsPresent.lf b/test/Rust/src/ActionIsPresent.lf index a21985f83b..326e47964a 100644 --- a/test/Rust/src/ActionIsPresent.lf +++ b/test/Rust/src/ActionIsPresent.lf @@ -1,10 +1,11 @@ // Tests the is_present variable for actions. -target Rust; +target Rust main reactor ActionIsPresent { - logical action a; - state success: bool(false); - state tried: bool(false); + logical action a + + state success: bool(false) + state tried: bool(false) reaction(startup, a) -> a {= if !ctx.is_present(a) { @@ -21,6 +22,7 @@ main reactor ActionIsPresent { self.success = true; } =} + reaction(shutdown) {= assert!(self.success, "What happened!?"); println!("success"); diff --git a/test/Rust/src/ActionIsPresentDouble.lf b/test/Rust/src/ActionIsPresentDouble.lf index b11dce93b6..361378a6bc 100644 --- a/test/Rust/src/ActionIsPresentDouble.lf +++ b/test/Rust/src/ActionIsPresentDouble.lf @@ -1,9 +1,9 @@ // Test logical action with delay. -target Rust; +target Rust main reactor ActionIsPresentDouble { - logical action act0; - logical action act1(100 msec); + logical action act0 + logical action act1(100 msec) reaction(startup) -> act0, act1 {= ctx.schedule(act0, after!(100 ms)); @@ -18,5 +18,4 @@ main reactor ActionIsPresentDouble { println!("success"); } =} - } diff --git a/test/Rust/src/ActionScheduleMicrostep.lf b/test/Rust/src/ActionScheduleMicrostep.lf index 55b56ffc9f..4038814c9e 100644 --- a/test/Rust/src/ActionScheduleMicrostep.lf +++ b/test/Rust/src/ActionScheduleMicrostep.lf @@ -1,9 +1,10 @@ // Test logical action with delay. -target Rust; +target Rust main reactor ActionScheduleMicrostep { - logical action act; - state count: u32(1); + logical action act + + state count: u32(1) reaction(startup) -> act {= assert_tag_is!(ctx, T0); diff --git a/test/Rust/src/ActionValues.lf b/test/Rust/src/ActionValues.lf index d4711dc594..ee91a75f7d 100644 --- a/test/Rust/src/ActionValues.lf +++ b/test/Rust/src/ActionValues.lf @@ -1,10 +1,11 @@ // Test logical action with delay. -target Rust; +target Rust main reactor ActionValues { - state r1done: bool(false); - state r2done: bool(false); - logical action act(100 msec): i32; + logical action act(100 msec): i32 + + state r1done: bool(false) + state r2done: bool(false) reaction(startup) -> act {= ctx.schedule_with_v(act, Some(100), Asap); // scheduled in 100 ms @@ -25,7 +26,7 @@ main reactor ActionValues { } =} - reaction (shutdown) {= + reaction(shutdown) {= assert!(self.r1done && self.r2done); println!("Success") =} diff --git a/test/Rust/src/ActionValuesCleanup.lf b/test/Rust/src/ActionValuesCleanup.lf index 3c2f88e01f..a6f2f4f02e 100644 --- a/test/Rust/src/ActionValuesCleanup.lf +++ b/test/Rust/src/ActionValuesCleanup.lf @@ -1,5 +1,5 @@ // Test that scheduling actions drops the previous value if any -target Rust; +target Rust main reactor ActionValuesCleanup { preamble {= @@ -19,9 +19,9 @@ main reactor ActionValuesCleanup { } =} + logical action act: FooDrop - logical action act: FooDrop; - state count: u32(0); + state count: u32(0) reaction(startup) -> act {= ctx.schedule_with_v(act, Some(FooDrop { }), Asap) diff --git a/test/Rust/src/CompositionInitializationOrder.lf b/test/Rust/src/CompositionInitializationOrder.lf index fb5ec56451..4c2a428f10 100644 --- a/test/Rust/src/CompositionInitializationOrder.lf +++ b/test/Rust/src/CompositionInitializationOrder.lf @@ -1,23 +1,18 @@ -// This test asserts the relative execution order of startup -// reactions within a composite reactor. - - -target Rust; +// This test asserts the relative execution order of startup reactions within a +// composite reactor. +target Rust main reactor CompositionInitializationOrder { - c1 = new Component1(); - c2 = new Component2(); - reaction(startup) {= - println!("parent woke up"); - =} + c1 = new Component1() + c2 = new Component2() + + reaction(startup) {= println!("parent woke up"); =} } + reactor Component2 { - reaction(startup) {= - println!("c2 woke up"); - =} + reaction(startup) {= println!("c2 woke up"); =} } + reactor Component1 { - reaction(startup) {= - println!("c1 woke up"); - =} + reaction(startup) {= println!("c1 woke up"); =} } diff --git a/test/Rust/src/CompositionWithPorts.lf b/test/Rust/src/CompositionWithPorts.lf index a81b651aa2..90e33db180 100644 --- a/test/Rust/src/CompositionWithPorts.lf +++ b/test/Rust/src/CompositionWithPorts.lf @@ -1,12 +1,14 @@ -target Rust; +target Rust + reactor Source { - output out: i32; - reaction(startup) -> out {= - ctx.set(&mut out, 76600) - =} + output out: i32 + + reaction(startup) -> out {= ctx.set(&mut out, 76600) =} } + reactor Sink { - input inport: i32; + input inport: i32 + reaction(inport) {= if let Some(value) = ctx.get(inport) { println!("received {}", value); @@ -16,9 +18,10 @@ reactor Sink { } =} } + main reactor CompositionWithPorts { - source = new Source(); - sink = new Sink(); + source = new Source() + sink = new Sink() - source.out -> sink.inport; + source.out -> sink.inport } diff --git a/test/Rust/src/CtorParamDefault.lf b/test/Rust/src/CtorParamDefault.lf index 6b3c7894a6..2a4f4b8074 100644 --- a/test/Rust/src/CtorParamDefault.lf +++ b/test/Rust/src/CtorParamDefault.lf @@ -1,13 +1,14 @@ -target Rust; +target Rust -reactor Print(value:i32(42)) { - state v: i32(value); +reactor Print(value: i32(42)) { + state v: i32(value) reaction(startup) {= assert_eq!(42, self.v); println!("success"); =} } + main reactor CtorParamDefault { - p = new Print(); + p = new Print() } diff --git a/test/Rust/src/CtorParamMixed.lf b/test/Rust/src/CtorParamMixed.lf index a6c80f7c2c..cb8536fe0a 100644 --- a/test/Rust/src/CtorParamMixed.lf +++ b/test/Rust/src/CtorParamMixed.lf @@ -1,13 +1,13 @@ -target Rust; +target Rust reactor Print( value: i32(42), - name: String({="xxx".into()=}), + name: String({= "xxx".into() =}), other: bool(false) ) { - state value(value); - state name(name); - state other(other); + state value(value) + state name(name) + state other(other) reaction(startup) {= assert_eq!(42, self.value); @@ -16,6 +16,7 @@ reactor Print( println!("success"); =} } + main reactor CtorParamMixed { - p = new Print(other=true, name={="x2hr".into()=}); + p = new Print(other = true, name = {= "x2hr".into() =}) } diff --git a/test/Rust/src/CtorParamSimple.lf b/test/Rust/src/CtorParamSimple.lf index 94af3c7f7a..8594adde3d 100644 --- a/test/Rust/src/CtorParamSimple.lf +++ b/test/Rust/src/CtorParamSimple.lf @@ -1,13 +1,14 @@ -target Rust; +target Rust -reactor Print(value:i32(42)) { - state v: i32(value); +reactor Print(value: i32(42)) { + state v: i32(value) reaction(startup) {= assert_eq!(self.v, 23); println!("success"); =} } + main reactor CtorParamSimple { - p = new Print(value=23); + p = new Print(value = 23) } diff --git a/test/Rust/src/DependencyOnChildPort.lf b/test/Rust/src/DependencyOnChildPort.lf index ac5f53e276..ae87302511 100644 --- a/test/Rust/src/DependencyOnChildPort.lf +++ b/test/Rust/src/DependencyOnChildPort.lf @@ -1,24 +1,27 @@ -/* Test that reactions can depend on ports of input child. */ - -target Rust; +/** Test that reactions can depend on ports of input child. */ +target Rust reactor Box { - input inp: u32; - output out: u32; + input inp: u32 + + output out: u32 - inp -> out; + inp -> out } main reactor { - state done: bool(false); + box0 = new Box() + box1 = new Box() - box0 = new Box(); - box1 = new Box(); + box0.out -> box1.inp - box0.out -> box1.inp; + state done: bool(false) reaction(startup) -> box0.inp {= ctx.set(box0__inp, 444); =} - reaction(box1.out) {= assert!(ctx.get_elapsed_logical_time().is_zero()); self.done = true; =} + + reaction(box1.out) {= + assert!(ctx.get_elapsed_logical_time().is_zero()); self.done = true; + =} reaction(shutdown) {= assert!(self.done, "reaction was not executed"); diff --git a/test/Rust/src/DependencyUseAccessible.lf b/test/Rust/src/DependencyUseAccessible.lf index 8abe778c45..03dac73d12 100644 --- a/test/Rust/src/DependencyUseAccessible.lf +++ b/test/Rust/src/DependencyUseAccessible.lf @@ -1,21 +1,26 @@ -/* Test that use-dependencies may be absent within a reaction. */ -target Rust; +/** Test that use-dependencies may be absent within a reaction. */ +target Rust reactor Source { - output clock: u32; - output o1: u32; - output o2: u32; - timer t1(35 msec); - timer t2(70 msec); - reaction(startup) -> clock {= ctx.set(clock, 0); =} - reaction(t1) -> clock, o1 {= ctx.set(clock, 1); ctx.set(o1, 10) =} - reaction(t2) -> clock, o2 {= ctx.set(clock, 2); =} // has a dependency but doesn't use it + output clock: u32 + output o1: u32 + output o2: u32 + + timer t1(35 msec) + timer t2(70 msec) + + reaction(startup) -> clock {= ctx.set(clock, 0); =} + + reaction(t1) -> clock, o1 {= ctx.set(clock, 1); ctx.set(o1, 10) =} + + // has a dependency but doesn't use it + reaction(t2) -> clock, o2 {= ctx.set(clock, 2); =} } reactor Sink { - input clock: u32; - input in1: u32; - input in2: u32; + input clock: u32 + input in1: u32 + input in2: u32 reaction(clock) in1, in2 {= match ctx.get(clock) { @@ -33,11 +38,10 @@ reactor Sink { } main reactor { - source = new Source(); - sink = new Sink(); - - source.clock -> sink.clock; + source = new Source() + sink = new Sink() - source.o1 -> sink.in1; - source.o2 -> sink.in2; + source.clock -> sink.clock + source.o1 -> sink.in1 + source.o2 -> sink.in2 } diff --git a/test/Rust/src/DependencyUseNonTrigger.lf b/test/Rust/src/DependencyUseNonTrigger.lf index 458b7e6cee..53496d6896 100644 --- a/test/Rust/src/DependencyUseNonTrigger.lf +++ b/test/Rust/src/DependencyUseNonTrigger.lf @@ -1,14 +1,15 @@ -/* Test that use-dependencies do not trigger reactions. */ -target Rust; +/** Test that use-dependencies do not trigger reactions. */ +target Rust reactor Source { - output clock: u32; - reaction(startup) -> clock {= ctx.set(clock, 0); =} + output clock: u32 + + reaction(startup) -> clock {= ctx.set(clock, 0); =} } reactor Sink { - input clock: u32; - input bogus: u32; + input clock: u32 + input bogus: u32 reaction(bogus) clock {= panic!("Should not be executed") =} @@ -16,8 +17,8 @@ reactor Sink { } main reactor { - source = new Source(); - sink = new Sink(); + source = new Source() + sink = new Sink() - source.clock -> sink.clock; + source.clock -> sink.clock } diff --git a/test/Rust/src/DependencyUseOnLogicalAction.lf b/test/Rust/src/DependencyUseOnLogicalAction.lf index 838ada37ad..9949eea606 100644 --- a/test/Rust/src/DependencyUseOnLogicalAction.lf +++ b/test/Rust/src/DependencyUseOnLogicalAction.lf @@ -1,16 +1,13 @@ -/* Test that use-dependencies may be declared on logical actions and timers. */ -target Rust { - timeout: 10 msec -}; +/** Test that use-dependencies may be declared on logical actions and timers. */ +target Rust { timeout: 10 msec } main reactor { - logical action clock: u32; + timer t(0, 2 msec) - logical action a; + logical action clock: u32 + logical action a - timer t(0, 2msec); - - state tick: u32(0); + state tick: u32(0) reaction(startup) -> clock, a {= ctx.schedule(a, after!(3 ms)); // out of order on purpose diff --git a/test/Rust/src/FloatLiteral.lf b/test/Rust/src/FloatLiteral.lf index 7efc0f2e33..645581c844 100644 --- a/test/Rust/src/FloatLiteral.lf +++ b/test/Rust/src/FloatLiteral.lf @@ -1,11 +1,12 @@ -target Rust; -// This test verifies that floating-point literals are handled -// correctly. +target Rust + +// This test verifies that floating-point literals are handled correctly. main reactor { state N: f64(6.0221409e+23) state charge: f64(-1.6021766E-19) state minus_epsilon: f64(-.01e0) state expected: f64(.964853323188E5) + reaction(startup) {= let F = - self.N * self.charge; println!("The Faraday constant is roughly {}.", F); diff --git a/test/Rust/src/Import.lf b/test/Rust/src/Import.lf index bb6489debc..ee3b871fa4 100644 --- a/test/Rust/src/Import.lf +++ b/test/Rust/src/Import.lf @@ -1,12 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Rust; -import Imported from "lib/Imported.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target Rust + +import Imported from "lib/Imported.lf" main reactor Import { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - ctx.set(a__x, 42); - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= ctx.set(a__x, 42); =} } diff --git a/test/Rust/src/ImportPreambleItem.lf b/test/Rust/src/ImportPreambleItem.lf index 7c1d263eca..e532f74c70 100644 --- a/test/Rust/src/ImportPreambleItem.lf +++ b/test/Rust/src/ImportPreambleItem.lf @@ -1,11 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target Rust; -import SomethingWithAPreamble from "lib/SomethingWithAPreamble.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target Rust + +import SomethingWithAPreamble from "lib/SomethingWithAPreamble.lf" main reactor { - r = new SomethingWithAPreamble(); - reaction(startup) -> r.a {= - ctx.set(r__a, super::something_with_a_preamble::some_fun()); - =} + r = new SomethingWithAPreamble() + + reaction(startup) -> r.a {= + ctx.set(r__a, super::something_with_a_preamble::some_fun()); + =} } diff --git a/test/Rust/src/MainReactorParam.lf b/test/Rust/src/MainReactorParam.lf index 81863cd68d..36a78d7699 100644 --- a/test/Rust/src/MainReactorParam.lf +++ b/test/Rust/src/MainReactorParam.lf @@ -1,9 +1,8 @@ -target Rust; -main reactor (one: u64(1152921504606846976), two: u64({= 1 << 60 =})) { - state one(one); - state two(two); +target Rust - reaction(startup) {= - assert_eq!(self.one, self.two); - =} +main reactor(one: u64(1152921504606846976), two: u64({= 1 << 60 =})) { + state one(one) + state two(two) + + reaction(startup) {= assert_eq!(self.one, self.two); =} } diff --git a/test/Rust/src/Minimal.lf b/test/Rust/src/Minimal.lf index 6e21b84e1e..77c7c791f6 100644 --- a/test/Rust/src/Minimal.lf +++ b/test/Rust/src/Minimal.lf @@ -1,7 +1,6 @@ // This is a smoke test of a minimal reactor. -target Rust; +target Rust + main reactor Minimal { - reaction(startup) {= - println!("Hello World."); - =} + reaction(startup) {= println!("Hello World."); =} } diff --git a/test/Rust/src/MovingAverage.lf b/test/Rust/src/MovingAverage.lf index 1bbb4af673..700bc287ce 100644 --- a/test/Rust/src/MovingAverage.lf +++ b/test/Rust/src/MovingAverage.lf @@ -1,24 +1,29 @@ -// Demonstration of a state variable that is a fixed size list. -// The MovingAverage reactor computes the moving average of the last -// four inputs and produces that as output. The source is a counting -// sequence. -target Rust { - timeout: 50 msec, -}; +// Demonstration of a state variable that is a fixed size list. The +// MovingAverage reactor computes the moving average of the last four inputs and +// produces that as output. The source is a counting sequence. +target Rust { timeout: 50 msec } + reactor Source { - output out: f64; - state count: u32(0); - timer clock(0, 10 msec); + output out: f64 + + timer clock(0, 10 msec) + + state count: u32(0) + reaction(clock) -> out {= ctx.set(out, self.count.into()); self.count += 1; =} } + reactor MovingAverageImpl { - state delay_line: f64[4] (0.0, 0.0, 0.0, 0.0);// fixme inaccessible ({=[0.0 ; 4]=}); - state index: usize(0); - input in_: f64; - output out: f64; + input in_: f64 + + output out: f64 + + // fixme inaccessible ({=[0.0 ; 4]=}); + state delay_line: f64[4](0.0, 0.0, 0.0, 0.0) + state index: usize(0) reaction(in_) -> out {= let in_ = ctx.get(in_).unwrap(); @@ -31,33 +36,36 @@ reactor MovingAverageImpl { // Calculate the output. let sum: f64 = self.delay_line.iter().sum(); ctx.set(out, sum / 4.0); - =} } reactor Print { - input in_: f64; - state count: usize(0); - preamble {= const EXPECTED: [ f64 ; 6 ] = [0.0, 0.25, 0.75, 1.5, 2.5, 3.5]; =} + input in_: f64 + + state count: usize(0) + reaction(in_) {= let in_ = ctx.get(in_).unwrap(); println!("Received {}", in_); assert_eq!(in_, EXPECTED[self.count]); self.count += 1; =} + reaction(shutdown) {= assert_eq!(self.count, 6); println!("Success."); =} } + main reactor MovingAverage { - s = new Source(); - m = new MovingAverageImpl(); - p = new Print(); - s.out -> m.in_; - m.out -> p.in_; + s = new Source() + m = new MovingAverageImpl() + p = new Print() + + s.out -> m.in_ + m.out -> p.in_ } diff --git a/test/Rust/src/NativeListsAndTimes.lf b/test/Rust/src/NativeListsAndTimes.lf index 31281c0ae9..3ce834ddc5 100644 --- a/test/Rust/src/NativeListsAndTimes.lf +++ b/test/Rust/src/NativeListsAndTimes.lf @@ -1,46 +1,47 @@ -target Rust; +target Rust // This test passes if it is successfully compiled into valid target code. +reactor Foo( + x: i32(0), + y: time(0), // Units are missing but not required + z(1 msec), // Type is missing but not required + p: i32[](1, 2, 3, 4), // List of integers + p2: i32[]({= vec![1] =}), // List of integers with single element + // todo // p2: i32[](1), // List of integers with single element p3: + // i32[](), // Empty list of integers List of time values + q: Vec(1 msec, 2 msec, 3 msec), + g: time[](1 msec, 2 msec) // List of time values +) { + timer tick(0) // Units missing but not required + timer tock(1 sec) // Implicit type time + timer toe(z) // Implicit type time -reactor Foo(x: i32(0), - y: time(0), // Units are missing but not required - z(1 msec), // Type is missing but not required - p: i32[](1, 2, 3, 4), // List of integers - p2: i32[]({= vec![1] =}), // List of integers with single element + state s: time(y) // Reference to explicitly typed time parameter + state t: time(z) // Reference to implicitly typed time parameter + state v: bool // Uninitialized boolean state variable + state w: time // Uninitialized time state variable + /** + * fixme following should be equivalent: + * - state baz(p); + * - state baz: i32[4](p); + * - state baz: i32[4]({=p=}); + * + * because the initializer is the same modulo fat braces + */ + // state baz(p); // Implicit type i32[] fixme this interplays badly with + // syntax for array init Implicit type time + state period(z) + state times: Vec>(q, g) // a list of lists - // todo // p2: i32[](1), // List of integers with single element - // p3: i32[](), // Empty list of integers - q: Vec (1 msec, 2 msec, 3 msec), // List of time values - g: time[](1 msec, 2 msec) // List of time values - ) { - state s: time(y); // Reference to explicitly typed time parameter - state t: time(z); // Reference to implicitly typed time parameter - state v: bool; // Uninitialized boolean state variable - state w: time; // Uninitialized time state variable - timer tick(0); // Units missing but not required - timer tock(1 sec); // Implicit type time - timer toe(z); // Implicit type time - // fixme following should be equivalent: - // state baz(p); - // state baz: i32[4](p); - // state baz: i32[4]({=p=}); - // because the initializer is the same modulo fat braces - - // state baz(p); // Implicit type i32[] fixme this interplays badly with syntax for array init - state period(z); // Implicit type time - state times: Vec>(q, g); // a list of lists + /** + * reactor Foo (p: i32[](1, 2)) { state baz(p); // Implicit type i32[] state + * baz({=p=}); // Implicit type i32[] } + */ reaction(tick) {= // Target code =} - /* - reactor Foo (p: i32[](1, 2)) { - state baz(p); // Implicit type i32[] - state baz({=p=}); // Implicit type i32[] - } - - */ } main reactor NativeListsAndTimes { - foo = new Foo(); + foo = new Foo() } diff --git a/test/Rust/src/PhysicalActionKeepaliveIsSmart.lf b/test/Rust/src/PhysicalActionKeepaliveIsSmart.lf index 759d657f47..477e4d5694 100644 --- a/test/Rust/src/PhysicalActionKeepaliveIsSmart.lf +++ b/test/Rust/src/PhysicalActionKeepaliveIsSmart.lf @@ -1,12 +1,9 @@ -// Tests that the scheduler ends up shutting down if there are -// no live Sender that can send messages back to the scheduler. -target Rust { - keepalive: true -}; +// Tests that the scheduler ends up shutting down if there are no live Sender +// that can send messages back to the scheduler. +target Rust { keepalive: true } main reactor { - - physical action act: u32; + physical action act: u32 reaction(startup) -> act {= std::thread::spawn(|| { diff --git a/test/Rust/src/PhysicalActionWakesSleepingScheduler.lf b/test/Rust/src/PhysicalActionWakesSleepingScheduler.lf index b3c47827cd..5a6bc278f1 100644 --- a/test/Rust/src/PhysicalActionWakesSleepingScheduler.lf +++ b/test/Rust/src/PhysicalActionWakesSleepingScheduler.lf @@ -1,19 +1,20 @@ -// Tests that, given a logical event scheduled far away in -// the future (which puts the scheduler to sleep), and a -// physical action being triggered asynchronously during -// that sleep time, the scheduler wakes up and processes the -// physical action before the logical action. - -// This test is unfortunately not very reliable, as the sleeping -// thread may wake up very late depending on the platform and the weather. -// The test has already failed in CI on macos, because the -// action was triggered at (T0+135ms), that is, 115ms later -// than the expected wake up time (T0+20ms). -target Rust; +/** + * Tests that, given a logical event scheduled far away in the future (which + * puts the scheduler to sleep), and a physical action being triggered + * asynchronously during that sleep time, the scheduler wakes up and processes + * the physical action before the logical action. + * + * This test is unfortunately not very reliable, as the sleeping thread may wake + * up very late depending on the platform and the weather. The test has already + * failed in CI on macos, because the action was triggered at (T0+135ms), that + * is, 115ms later than the expected wake up time (T0+20ms). + */ +target Rust main reactor { - timer t(250 msec); // this is unused but important - physical action act: u32; + timer t(250 msec) // this is unused but important + + physical action act: u32 reaction(startup) -> act {= let act = act.clone(); diff --git a/test/Rust/src/PhysicalActionWithKeepalive.lf b/test/Rust/src/PhysicalActionWithKeepalive.lf index 19a51be75e..e1c11742dd 100644 --- a/test/Rust/src/PhysicalActionWithKeepalive.lf +++ b/test/Rust/src/PhysicalActionWithKeepalive.lf @@ -1,11 +1,7 @@ -target Rust { - - keepalive: true -}; +target Rust { keepalive: true } main reactor { - - physical action act: u32; + physical action act: u32 reaction(startup) -> act {= let act = act.clone(); diff --git a/test/Rust/src/PortConnectionInSelfInChild.lf b/test/Rust/src/PortConnectionInSelfInChild.lf index 3a27ce5934..d00c290eff 100644 --- a/test/Rust/src/PortConnectionInSelfInChild.lf +++ b/test/Rust/src/PortConnectionInSelfInChild.lf @@ -1,9 +1,10 @@ // Tests a port connection between (input of self -> input of child) -target Rust; +target Rust reactor Child { - input inp: i32; - state done: bool(false); + input inp: i32 + + state done: bool(false) reaction(inp) {= assert_eq!(ctx.get(inp), Some(76600)); @@ -15,16 +16,20 @@ reactor Child { println!("Success") =} } + reactor Parent { - input inp: i32; - child = new Child(); - inp -> child.inp; + input inp: i32 + + child = new Child() + + inp -> child.inp } + main reactor { - parent = new Parent(); + parent = new Parent() reaction(startup) -> parent.inp {= - ctx.set(parent__inp, 76600); - println!("out := 76600") + ctx.set(parent__inp, 76600); + println!("out := 76600") =} } diff --git a/test/Rust/src/PortConnectionInSelfOutSelf.lf b/test/Rust/src/PortConnectionInSelfOutSelf.lf index 548315992a..31eaf9d0c6 100644 --- a/test/Rust/src/PortConnectionInSelfOutSelf.lf +++ b/test/Rust/src/PortConnectionInSelfOutSelf.lf @@ -1,37 +1,42 @@ // Tests a port connection between (input of self -> input of child) -target Rust; +target Rust reactor Source { - output out: i32; + output out: i32 + reaction(startup) -> out {= - ctx.set(out, 76600); - println!("out := 76600") + ctx.set(out, 76600); + println!("out := 76600") =} } + reactor TestCase { - input inp: i32; - output out: i32; - inp -> out; + input inp: i32 + + output out: i32 + + inp -> out } + reactor Sink { - input inp: i32; - state done: bool(false); + input inp: i32 + + state done: bool(false) + reaction(inp) {= assert_eq!(ctx.get(inp), Some(76600)); println!("Success"); self.done = true; =} - reaction(shutdown) {= - assert!(self.done, "reaction was not executed") - =} + reaction(shutdown) {= assert!(self.done, "reaction was not executed") =} } main reactor { - source = new Source(); - middle = new TestCase(); - sink = new Sink(); + source = new Source() + middle = new TestCase() + sink = new Sink() - source.out -> middle.inp; - middle.out -> sink.inp; + source.out -> middle.inp + middle.out -> sink.inp } diff --git a/test/Rust/src/PortConnectionOutChildOutSelf.lf b/test/Rust/src/PortConnectionOutChildOutSelf.lf index 4993c58c08..24d8b76f81 100644 --- a/test/Rust/src/PortConnectionOutChildOutSelf.lf +++ b/test/Rust/src/PortConnectionOutChildOutSelf.lf @@ -1,37 +1,41 @@ // Tests a port connection between (input of self -> input of child) -target Rust; +target Rust reactor Child { - output out: i32; + output out: i32 + reaction(startup) -> out {= ctx.set(out, 76600); println!("out := 76600") =} } + reactor Parent { - output out: i32; + output out: i32 - child = new Child(); - child.out -> out; + child = new Child() + + child.out -> out } + reactor Sink { - input inp: i32; - state done: bool(false); + input inp: i32 + + state done: bool(false) + reaction(inp) {= assert_eq!(ctx.get(inp), Some(76600)); println!("Success"); self.done = true; =} - reaction(shutdown) {= - assert!(self.done, "reaction was not executed") - =} + reaction(shutdown) {= assert!(self.done, "reaction was not executed") =} } main reactor { - parent = new Parent(); + parent = new Parent() - state done: bool(false); + state done: bool(false) reaction(parent.out) {= assert_eq!(ctx.get(parent__out), Some(76600)); @@ -39,7 +43,5 @@ main reactor { self.done = true; =} - reaction(shutdown) {= - assert!(self.done, "reaction was not executed") - =} + reaction(shutdown) {= assert!(self.done, "reaction was not executed") =} } diff --git a/test/Rust/src/PortRefCleanup.lf b/test/Rust/src/PortRefCleanup.lf index 061dbe2715..700ec847b3 100644 --- a/test/Rust/src/PortRefCleanup.lf +++ b/test/Rust/src/PortRefCleanup.lf @@ -1,21 +1,22 @@ // Tests that a port value is cleaned up after a tag -target Rust; +target Rust reactor Box { - input inp: u32; - output out: u32; + input inp: u32 - inp -> out; + output out: u32 + + inp -> out } main reactor { - boxr = new Box(); + timer t1(0) + timer t2(15 msec) - timer t1(0); - timer t2(15msec); + boxr = new Box() - state reaction_num: u32(0); - state done: bool(false); + state reaction_num: u32(0) + state done: bool(false) reaction(t1) -> boxr.inp {= ctx.set(boxr__inp, 150); diff --git a/test/Rust/src/PortValueCleanup.lf b/test/Rust/src/PortValueCleanup.lf index c02826e4c4..c29b87f121 100644 --- a/test/Rust/src/PortValueCleanup.lf +++ b/test/Rust/src/PortValueCleanup.lf @@ -1,20 +1,19 @@ // Tests that a port value is cleaned up after a tag -target Rust; +target Rust reactor Source { - output out: u32; + output out: u32 - reaction(startup) -> out {= - ctx.set(out, 150); - =} + reaction(startup) -> out {= ctx.set(out, 150); =} } reactor Sink { - timer t2(15 msec); + input in: u32 + + timer t2(15 msec) - input in: u32; - state reaction_num: u32(0); - state done: bool(false); + state reaction_num: u32(0) + state done: bool(false) reaction(in, t2) {= if self.reaction_num == 0 { @@ -34,8 +33,8 @@ reactor Sink { } main reactor { - source = new Source(); - sink = new Sink(); + source = new Source() + sink = new Sink() - source.out -> sink.in; + source.out -> sink.in } diff --git a/test/Rust/src/Preamble.lf b/test/Rust/src/Preamble.lf index 34f2cda35d..c8c186491d 100644 --- a/test/Rust/src/Preamble.lf +++ b/test/Rust/src/Preamble.lf @@ -1,11 +1,11 @@ -target Rust; +target Rust + main reactor Preamble { preamble {= fn add_42(i: i32) -> i32 { return i + 42; } =} - reaction(startup) {= - println!("42 plus 42 is {}.\n", add_42(42)); - =} + + reaction(startup) {= println!("42 plus 42 is {}.\n", add_42(42)); =} } diff --git a/test/Rust/src/ReactionLabels.lf b/test/Rust/src/ReactionLabels.lf index df87b8bd56..c696ab85c2 100644 --- a/test/Rust/src/ReactionLabels.lf +++ b/test/Rust/src/ReactionLabels.lf @@ -1,10 +1,9 @@ -// There was a bug whereby reaction labels mess up generated code. -// Labels are used as debug info by the runtime. -target Rust; +// There was a bug whereby reaction labels mess up generated code. Labels are +// used as debug info by the runtime. +target Rust + main reactor { - timer t(0); - // @label foo - reaction(t) {= - println!("success"); - =} + timer t(0) + + reaction(t) {= println!("success"); =} // @label foo } diff --git a/test/Rust/src/ReservedKeywords.lf b/test/Rust/src/ReservedKeywords.lf index 6b5d7fe2e2..444b075578 100644 --- a/test/Rust/src/ReservedKeywords.lf +++ b/test/Rust/src/ReservedKeywords.lf @@ -1,13 +1,15 @@ -// Tests that rust keywords may be used as identifiers in LF and are properly escaped by the emitter -target Rust; +// Tests that rust keywords may be used as identifiers in LF and are properly +// escaped by the emitter +target Rust reactor box { - input in: u32; - output struct: u32; + input in: u32 - in -> struct; + output struct: u32 - state foo: bool(true); // not escaped + in -> struct + + state foo: bool(true) // not escaped reaction(in) {= ctx.get(r#in); @@ -15,16 +17,11 @@ reactor box { } main reactor ReservedKeywords(struct: u32(0)) { - box = new box(); - - timer t1(0); - timer t2(15msec); - - // not in types, this wouldn't be useful. - // state reaction_num: struct(0); + timer t1(0) + timer t2(15 msec) - reaction(box.struct, t2) {= - - =} + box = new box() + // not in types, this wouldn't be useful. state reaction_num: struct(0); + reaction(box.struct, t2) {= =} } diff --git a/test/Rust/src/SingleFileGeneration.lf b/test/Rust/src/SingleFileGeneration.lf index caa399f3a6..ec2828eba4 100644 --- a/test/Rust/src/SingleFileGeneration.lf +++ b/test/Rust/src/SingleFileGeneration.lf @@ -1,16 +1,15 @@ // The same as CompositionWithPorts.lf, but as a single file project -target Rust { - single-file-project: true -}; +target Rust { single-file-project: true } reactor Source { - output out: i32; - reaction(startup) -> out {= - ctx.set(out, 76600) - =} + output out: i32 + + reaction(startup) -> out {= ctx.set(out, 76600) =} } + reactor Sink { - input inport: i32; + input inport: i32 + reaction(inport) {= if let Some(value) = ctx.get(inport) { println!("received {}", value); @@ -20,9 +19,10 @@ reactor Sink { } =} } + main reactor { - source = new Source(); - sink = new Sink(); + source = new Source() + sink = new Sink() - source.out -> sink.inport; + source.out -> sink.inport } diff --git a/test/Rust/src/StateDefaultValue.lf b/test/Rust/src/StateDefaultValue.lf index 1149561146..a9eeb1d457 100644 --- a/test/Rust/src/StateDefaultValue.lf +++ b/test/Rust/src/StateDefaultValue.lf @@ -1,16 +1,14 @@ -target Rust; +target Rust main reactor { - // missing initializers are taken to mean "initialize to Default::default()" - state foo_default: u32; - state vec_default: Vec; - state option: Option>; + state foo_default: u32 + state vec_default: Vec + state option: Option> reaction(startup) {= assert_eq!(self.foo_default, 0); assert_eq!(self.vec_default, vec![]); assert_eq!(self.option, None); =} - } diff --git a/test/Rust/src/StateInitializerVisibility.lf b/test/Rust/src/StateInitializerVisibility.lf index d7a12e1de3..cef728ccfa 100644 --- a/test/Rust/src/StateInitializerVisibility.lf +++ b/test/Rust/src/StateInitializerVisibility.lf @@ -1,10 +1,10 @@ -// Tests that state vars are accessible within initializers -// of other state vars declared further down. +// Tests that state vars are accessible within initializers of other state vars +// declared further down. +target Rust -target Rust; main reactor { - state foo: u32(123); - state x: u32({= *&foo =}); + state foo: u32(123) + state x: u32({= *&foo =}) reaction(startup) {= assert_eq!(self.x, self.foo); diff --git a/test/Rust/src/Stop.lf b/test/Rust/src/Stop.lf index 858d8151b2..8f89205da1 100644 --- a/test/Rust/src/Stop.lf +++ b/test/Rust/src/Stop.lf @@ -1,25 +1,24 @@ -/* +/** * A test for the request_stop() functionality in Lingua Franca. * * @author Soroush Bateni */ -target Rust { - timeout: 11 msec, -}; +target Rust { timeout: 11 msec } /** - * @param take_a_break_after: Indicates how many messages are sent - * in consecutive superdense time - * @param break_interval: Determines how long the reactor should take - * a break after sending take_a_break_after messages. + * @param take_a_break_after: Indicates how many messages are sent in + * consecutive superdense time + * @param break_interval: Determines how long the reactor should take a break + * after sending take_a_break_after messages. */ reactor Sender(take_a_break_after: u32(10), break_interval: time(400 msec)) { - output out: u32; - logical action act; - state sent_messages: u32(0); + output out: u32 + + logical action act - state take_a_break_after(take_a_break_after); - state break_interval(break_interval); + state sent_messages: u32(0) + state take_a_break_after(take_a_break_after) + state break_interval(break_interval) reaction(startup, act) -> act, out {= // Send a message on out @@ -39,8 +38,10 @@ reactor Sender(take_a_break_after: u32(10), break_interval: time(400 msec)) { } reactor Consumer { - input in_: u32; - state reaction_invoked_correctly: bool(false); + input in_: u32 + + state reaction_invoked_correctly: bool(false) + reaction(in_) {= let current_tag = ctx.get_tag(); @@ -78,8 +79,8 @@ reactor Consumer { } main reactor Stop { - consumer = new Consumer(); - producer = new Sender(break_interval = 1 msec); + consumer = new Consumer() + producer = new Sender(break_interval = 1 msec) - producer.out -> consumer.in_; + producer.out -> consumer.in_ } diff --git a/test/Rust/src/StopAsync.lf b/test/Rust/src/StopAsync.lf index 0c459c1200..6f54ceecde 100644 --- a/test/Rust/src/StopAsync.lf +++ b/test/Rust/src/StopAsync.lf @@ -1,7 +1,6 @@ -target Rust; +target Rust main reactor { - reaction(startup) {= ctx.spawn_physical_thread(|ctx| { std::thread::sleep(delay!(140 msec)); diff --git a/test/Rust/src/StopCleanup.lf b/test/Rust/src/StopCleanup.lf index 02a5a2a0fd..5bb89fffc2 100644 --- a/test/Rust/src/StopCleanup.lf +++ b/test/Rust/src/StopCleanup.lf @@ -1,10 +1,9 @@ -/* Tests that ports are cleaned up before the shutdown wave executes. */ - -target Rust { -}; +/** Tests that ports are cleaned up before the shutdown wave executes. */ +target Rust reactor Sender { - output out: u32; + output out: u32 + reaction(startup) -> out {= assert_tag_is!(ctx, (T0, 0)); ctx.set(out, 43); @@ -13,7 +12,7 @@ reactor Sender { } reactor Consumer { - input in_: u32; + input in_: u32 reaction(shutdown) in_ {= assert!(ctx.get(in_).is_none(), "Port should have been cleaned up before shutdown"); @@ -23,8 +22,8 @@ reactor Consumer { } main reactor StopCleanup { - consumer = new Consumer(); - producer = new Sender(); + consumer = new Consumer() + producer = new Sender() - producer.out -> consumer.in_; + producer.out -> consumer.in_ } diff --git a/test/Rust/src/StopDuringStartup.lf b/test/Rust/src/StopDuringStartup.lf index f2e98639bd..a49cdcf243 100644 --- a/test/Rust/src/StopDuringStartup.lf +++ b/test/Rust/src/StopDuringStartup.lf @@ -1,11 +1,7 @@ // tests that a request_stop called during startup is acted upon. - -target Rust { - timeout: 30 msec, -}; +target Rust { timeout: 30 msec } main reactor { - reaction(startup) {= ctx.request_stop(Asap); // requested for (T0, 1) assert_tag_is!(ctx, T0); diff --git a/test/Rust/src/StopIdempotence.lf b/test/Rust/src/StopIdempotence.lf index df29f1982d..4033889bc1 100644 --- a/test/Rust/src/StopIdempotence.lf +++ b/test/Rust/src/StopIdempotence.lf @@ -1,12 +1,8 @@ -/* Tests that ports are cleaned up before the shutdown wave executes. */ - - target Rust { - timeout: 30 msec, - - }; +/** Tests that ports are cleaned up before the shutdown wave executes. */ +target Rust { timeout: 30 msec } main reactor StopIdempotence { - state count: u32(0); + state count: u32(0) reaction(startup) {= ctx.request_stop(Asap); // requested for (T0, 1) diff --git a/test/Rust/src/StopNoEvent.lf b/test/Rust/src/StopNoEvent.lf index 86c36c690e..ae84b0bfbd 100644 --- a/test/Rust/src/StopNoEvent.lf +++ b/test/Rust/src/StopNoEvent.lf @@ -1,8 +1,9 @@ -/* Tests that `shutdown` is triggered even if the program exits because of an empty event queue. */ -target Rust; +/** + * Tests that `shutdown` is triggered even if the program exits because of an + * empty event queue. + */ +target Rust main reactor StopNoEvent { - reaction(shutdown) {= - println!("success"); - =} + reaction(shutdown) {= println!("success"); =} } diff --git a/test/Rust/src/StopTimeout.lf b/test/Rust/src/StopTimeout.lf index fd66bae3b0..c2733d0a11 100644 --- a/test/Rust/src/StopTimeout.lf +++ b/test/Rust/src/StopTimeout.lf @@ -1,8 +1,8 @@ -/* Tests that `shutdown` is triggered even if the program exits because of timeout target property. */ - - target Rust { - timeout: 30 msec, - }; +/** + * Tests that `shutdown` is triggered even if the program exits because of + * timeout target property. + */ +target Rust { timeout: 30 msec } main reactor StopTimeout { reaction(shutdown) {= diff --git a/test/Rust/src/StopTimeoutExact.lf b/test/Rust/src/StopTimeoutExact.lf index 8e201e4d5e..e00f087ae2 100644 --- a/test/Rust/src/StopTimeoutExact.lf +++ b/test/Rust/src/StopTimeoutExact.lf @@ -1,16 +1,13 @@ -/* - * Tests that when a timeout coincides with a scheduled event, - * all scheduled reactions are properly executed (in addition to the shutdown ones). +/** + * Tests that when a timeout coincides with a scheduled event, all scheduled + * reactions are properly executed (in addition to the shutdown ones). */ -target Rust { - timeout: 50 msec, -}; +target Rust { timeout: 50 msec } main reactor StopTimeoutExact { - // the fifth triggering will coincide with the timeout - timer t(0, 10 msec); + timer t(0, 10 msec) // the fifth triggering will coincide with the timeout - state reacted_on_shutdown: bool(false); + state reacted_on_shutdown: bool(false) reaction(t) {= if ctx.get_tag() == tag!(T0 + 50 ms) { diff --git a/test/Rust/src/StopTopology.lf b/test/Rust/src/StopTopology.lf index 825fee843f..20e394a3ee 100644 --- a/test/Rust/src/StopTopology.lf +++ b/test/Rust/src/StopTopology.lf @@ -1,12 +1,10 @@ -/* Tests that shutdown wave occurs in topological order like a normal wave. */ - -target Rust { - timeout: 30 msec -}; +/** Tests that shutdown wave occurs in topological order like a normal wave. */ +target Rust { timeout: 30 msec } main reactor StopTopology { - timer end(30 msec); // collides with timeout - state count: u32; + timer end(30 msec) // collides with timeout + + state count: u32 reaction(end) {= assert_eq!(self.count, 0); diff --git a/test/Rust/src/StructAsState.lf b/test/Rust/src/StructAsState.lf index c253547872..c5e529524d 100644 --- a/test/Rust/src/StructAsState.lf +++ b/test/Rust/src/StructAsState.lf @@ -1,6 +1,7 @@ -// Check that a state variable can have a statically initialized struct as a value. -// Check how preambles work -target Rust; +// Check that a state variable can have a statically initialized struct as a +// value. Check how preambles work +target Rust + main reactor StructAsState { preamble {= struct Hello { @@ -8,12 +9,16 @@ main reactor StructAsState { value: i32, } =} - // notice this uses parentheses - // todo - // state s: Hello(name= "Earth".into(), value= 42); - // state s: Hello(name: "Earth".into(), value: 42); - // state s: Hello { name: "Earth".into(), value: 42 }; - state s: Hello ({= Hello { name: "Earth".into(), value: 42 } =}); + + /** + * notice this uses parentheses + * + * todo + * * state s: Hello(name= "Earth".into(), value= 42); + * * state s: Hello(name: "Earth".into(), value: 42); + * * state s: Hello { name: "Earth".into(), value: 42 }; + */ + state s: Hello({= Hello { name: "Earth".into(), value: 42 } =}) reaction(startup) {= println!("State s.name=\"{}\", s.value={}.", self.s.name, self.s.value); diff --git a/test/Rust/src/StructAsType.lf b/test/Rust/src/StructAsType.lf index bb8acc17e5..0ee29c1a04 100644 --- a/test/Rust/src/StructAsType.lf +++ b/test/Rust/src/StructAsType.lf @@ -1,10 +1,7 @@ -// Source produces a struct directly, rather than a pointer to -// a struct. -target Rust; +// Source produces a struct directly, rather than a pointer to a struct. +target Rust reactor Source { - output out: Hello; - preamble {= pub struct Hello { pub name: String, @@ -12,16 +9,20 @@ reactor Source { } =} + output out: Hello + reaction(startup) -> out {= // Create the struct on the stack and then copy // it to the output ctx.set(out, Hello { name: "Earth".into(), value: 42 }) =} } -// expected parameter is for testing. -reactor Print(expected:i32(42)) { - input inp: {= super::source::Hello =}; - state expected:i32(expected); + +reactor Print(expected: i32(42)) { // expected parameter is for testing. + input inp: {= super::source::Hello =} + + state expected: i32(expected) + reaction(inp) {= ctx.use_ref_opt(inp, |hello| { println!("Received: name=\"{}\", value={}.", hello.name, hello.value); @@ -31,8 +32,10 @@ reactor Print(expected:i32(42)) { }); =} } + main reactor StructAsType { - s = new Source(); - p = new Print(); - s.out -> p.inp; + s = new Source() + p = new Print() + + s.out -> p.inp } diff --git a/test/Rust/src/TimeState.lf b/test/Rust/src/TimeState.lf index 3eef66d06e..d077be8920 100644 --- a/test/Rust/src/TimeState.lf +++ b/test/Rust/src/TimeState.lf @@ -1,13 +1,14 @@ -target Rust; +target Rust reactor Foo { - state baz: time(500 msec); + state baz: time(500 msec) - reaction (startup) {= + reaction(startup) {= assert_eq!(500, self.baz.as_millis()); + println!("success"); =} } main reactor TimeState { - a = new Foo(); + a = new Foo() } diff --git a/test/Rust/src/TimerDefaults.lf b/test/Rust/src/TimerDefaults.lf index e08a2051c5..9d6a291184 100644 --- a/test/Rust/src/TimerDefaults.lf +++ b/test/Rust/src/TimerDefaults.lf @@ -1,7 +1,10 @@ -target Rust; +target Rust + main reactor TimerDefaults { - state i: i32(0); - timer t; + timer t + + state i: i32(0) + reaction(t) {= assert_tag_is!(ctx, T0); println!("Tick {} after {} ms", self.i, ctx.get_elapsed_physical_time().as_millis()); diff --git a/test/Rust/src/TimerIsPresent.lf b/test/Rust/src/TimerIsPresent.lf index 7efb0bbf84..363a07fba2 100644 --- a/test/Rust/src/TimerIsPresent.lf +++ b/test/Rust/src/TimerIsPresent.lf @@ -1,17 +1,13 @@ // Tests the is_present function for timers. -target Rust { - timeout: 7 msec, - -}; +target Rust { timeout: 7 msec } main reactor { + timer a(0, 5 msec) + timer b(1 msec, 5 msec) + timer c(1 msec) - timer a(0, 5 msec); - timer b(1 msec, 5 msec); - timer c(1 msec); - - state success: bool(false); - state tick: u32(0); + state success: bool(false) + state tick: u32(0) reaction(startup, a, b, c) {= match self.tick { @@ -46,6 +42,7 @@ main reactor { } self.tick += 1; =} + reaction(shutdown) {= assert!(self.success); println!("success"); diff --git a/test/Rust/src/TimerPeriodic.lf b/test/Rust/src/TimerPeriodic.lf index 375cea45e4..7980745cda 100644 --- a/test/Rust/src/TimerPeriodic.lf +++ b/test/Rust/src/TimerPeriodic.lf @@ -1,10 +1,11 @@ target Rust { - timeout: 15 msec, - // fast: true -}; + timeout: 15 msec // fast: true +} + main reactor TimerPeriodic { - state i: i32(0); - timer t2(0, 3 msec); + timer t2(0, 3 msec) + + state i: i32(0) reaction(t2) {= println!("Tick {} at {}", self.i, ctx.get_tag()); diff --git a/test/Rust/src/Timers.lf b/test/Rust/src/Timers.lf index 1fa66dda49..5d1739c1d3 100644 --- a/test/Rust/src/Timers.lf +++ b/test/Rust/src/Timers.lf @@ -1,20 +1,16 @@ -/** - * Test whether timers with different periods are triggered correctly. - */ -target Rust { - timeout: 2 sec -}; +/** Test whether timers with different periods are triggered correctly. */ +target Rust { timeout: 2 sec } + main reactor Timers { - timer t(0, 1 sec); - timer t2(0, 2 sec); - state counter: i32(0); + timer t(0, 1 sec) + timer t2(0, 2 sec) + + state counter: i32(0) + + reaction(t2) {= self.counter += 2; =} + + reaction(t) {= self.counter -= 1; =} - reaction(t2) {= - self.counter += 2; - =} - reaction(t) {= - self.counter -= 1; - =} reaction(shutdown) {= assert_eq!(1, self.counter); println!("SUCCESS.") diff --git a/test/Rust/src/TypeVarLengthList.lf b/test/Rust/src/TypeVarLengthList.lf index 35cb813280..b0ca2eec34 100644 --- a/test/Rust/src/TypeVarLengthList.lf +++ b/test/Rust/src/TypeVarLengthList.lf @@ -1,15 +1,14 @@ -target Rust; - -// this thing must compile -// needs to be modified when https://github.com/lf-lang/lingua-franca/discussions/492 is implemented +target Rust + +// this thing must compile needs to be modified when +// https://github.com/lf-lang/lingua-franca/discussions/492 is implemented +/** + * The following state declarations should be supported: + * * state l2: i32[](1); // generates l2: 1 // doesn't compile... + * * state l3: i32[](); // doesn't parse... + * * state l1: Vec(1, 2); // does not compile... + */ main reactor TypeVarLengthList { - state l0: i32[]({= Vec::new() =}); // generates l0: Vec::new() - state l1: i32[](1, 2); // generates l1: vec![1, 2] - // state l2: i32[](1); // generates l2: 1 // doesn't compile... - // state l3: i32[](); // doesn't parse... - - - - // state l1: Vec(1, 2); // does not compile... - + state l0: i32[]({= Vec::new() =}) // generates l0: Vec::new() + state l1: i32[](1, 2) // generates l1: vec![1, 2] } diff --git a/test/Rust/src/concurrent/Workers.lf b/test/Rust/src/concurrent/Workers.lf index dfa83be2e5..8a2574008d 100644 --- a/test/Rust/src/concurrent/Workers.lf +++ b/test/Rust/src/concurrent/Workers.lf @@ -1,4 +1,5 @@ -target Rust { workers: 16 }; +target Rust { workers: 16 } + main reactor { reaction(startup) {= if (ctx.num_workers() != 16) { diff --git a/test/Rust/src/generics/CtorParamGeneric.lf b/test/Rust/src/generics/CtorParamGeneric.lf index e8d668ddfe..c716ee88b2 100644 --- a/test/Rust/src/generics/CtorParamGeneric.lf +++ b/test/Rust/src/generics/CtorParamGeneric.lf @@ -1,10 +1,12 @@ // tests that ctor parameters may refer to type parameters. +target Rust -target Rust; +reactor Generic<{= T: Default + Eq + Sync + std::fmt::Debug =}>( + value: T({= Default::default() =}) +) { + input in: T -reactor Generic<{= T: Default + Eq + Sync + std::fmt::Debug =}>(value: T({= Default::default() =})) { - input in: T; - state v: T(value); + state v: T(value) reaction(in) {= ctx.use_ref_opt(r#in, |i| { @@ -13,10 +15,9 @@ reactor Generic<{= T: Default + Eq + Sync + std::fmt::Debug =}>(value: T({= Defa }); =} } + main reactor { - p = new Generic(value=23); + p = new Generic(value = 23) - reaction(startup) -> p.in {= - ctx.set(p__in, 23); - =} + reaction(startup) -> p.in {= ctx.set(p__in, 23); =} } diff --git a/test/Rust/src/generics/CtorParamGenericInst.lf b/test/Rust/src/generics/CtorParamGenericInst.lf index 6a4765c693..211e845169 100644 --- a/test/Rust/src/generics/CtorParamGenericInst.lf +++ b/test/Rust/src/generics/CtorParamGenericInst.lf @@ -1,13 +1,15 @@ -// this one is deeper than CtorParamGeneric, it illustrates -// the use of ctor parameters within the argument list of a -// further child instance. +// this one is deeper than CtorParamGeneric, it illustrates the use of ctor +// parameters within the argument list of a further child instance. +target Rust -target Rust; +reactor Generic2< + {= T: Default + Eq + Sync + std::fmt::Debug + Send + 'static =} +>( + value: T({= Default::default() =}) +) { + input in: T - -reactor Generic2<{= T: Default + Eq + Sync + std::fmt::Debug + Send + 'static =}>(value: T({= Default::default() =})) { - input in: T; - state v: T(value); + state v: T(value) reaction(in) {= ctx.use_ref_opt(r#in, |i| { @@ -17,18 +19,20 @@ reactor Generic2<{= T: Default + Eq + Sync + std::fmt::Debug + Send + 'static =} =} } -reactor Generic<{= T: Default + Eq + Sync + std::fmt::Debug + Copy + Send + 'static =}>(value: T({= Default::default() =})) { - input in: T; +reactor Generic< + {= T: Default + Eq + Sync + std::fmt::Debug + Copy + Send + 'static =} +>( + value: T({= Default::default() =}) +) { + input in: T - inner = new Generic2(value = value); + inner = new Generic2(value = value) - in -> inner.in; + in -> inner.in } main reactor { - p = new Generic(value=23); + p = new Generic(value = 23) - reaction(startup) -> p.in {= - ctx.set(p__in, 23); - =} + reaction(startup) -> p.in {= ctx.set(p__in, 23); =} } diff --git a/test/Rust/src/generics/GenericReactor.lf b/test/Rust/src/generics/GenericReactor.lf index efce59d63e..e625f1f5f6 100644 --- a/test/Rust/src/generics/GenericReactor.lf +++ b/test/Rust/src/generics/GenericReactor.lf @@ -1,23 +1,27 @@ // Tests a port connection between (input of self -> input of child) -target Rust; +target Rust reactor Box<{= T: Sync =}> { - input inp: T; - output out: T; + input inp: T - inp -> out; + output out: T + + inp -> out } main reactor { - state done: bool(false); + box0 = new Box() + box1 = new Box() - box0 = new Box(); - box1 = new Box(); + box0.out -> box1.inp - box0.out -> box1.inp; + state done: bool(false) reaction(startup) -> box0.inp {= ctx.set(box0__inp, 444); =} - reaction(box1.out) {= assert!(ctx.get_elapsed_logical_time().is_zero()); self.done = true; =} + + reaction(box1.out) {= + assert!(ctx.get_elapsed_logical_time().is_zero()); self.done = true; + =} reaction(shutdown) {= assert!(self.done, "reaction was not executed"); diff --git a/test/Rust/src/lib/Imported.lf b/test/Rust/src/lib/Imported.lf index 9fb3de78b4..ebfd3d4d64 100644 --- a/test/Rust/src/lib/Imported.lf +++ b/test/Rust/src/lib/Imported.lf @@ -1,12 +1,13 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Rust; -import ImportedAgain from "ImportedAgain.lf"; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target Rust + +import ImportedAgain from "ImportedAgain.lf" reactor Imported { - input x: u32; - a = new ImportedAgain(); - reaction(x) -> a.x {= - ctx.set(a__x, ctx.get(x).unwrap()); - =} + input x: u32 + + a = new ImportedAgain() + + reaction(x) -> a.x {= ctx.set(a__x, ctx.get(x).unwrap()); =} } diff --git a/test/Rust/src/lib/ImportedAgain.lf b/test/Rust/src/lib/ImportedAgain.lf index 5391c0bfb6..7e61e9a575 100644 --- a/test/Rust/src/lib/ImportedAgain.lf +++ b/test/Rust/src/lib/ImportedAgain.lf @@ -1,8 +1,10 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Rust; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target Rust + reactor ImportedAgain { - input x: u32; + input x: u32 + reaction(x) {= assert_eq!(Some(42), ctx.get(x)); println!("success"); diff --git a/test/Rust/src/lib/SomethingWithAPreamble.lf b/test/Rust/src/lib/SomethingWithAPreamble.lf index 6d0e1c52d3..8161b2429b 100644 --- a/test/Rust/src/lib/SomethingWithAPreamble.lf +++ b/test/Rust/src/lib/SomethingWithAPreamble.lf @@ -1,12 +1,13 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target Rust; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target Rust reactor SomethingWithAPreamble { - input a: u32; preamble {= pub fn some_fun() -> u32 { 4 } =} + + input a: u32 } diff --git a/test/Rust/src/multiport/ConnectionToSelfBank.lf b/test/Rust/src/multiport/ConnectionToSelfBank.lf index 12048756de..a8b3c93c74 100644 --- a/test/Rust/src/multiport/ConnectionToSelfBank.lf +++ b/test/Rust/src/multiport/ConnectionToSelfBank.lf @@ -1,16 +1,16 @@ -target Rust; +target Rust reactor Node(bank_index: usize(0), num_nodes: usize(4)) { input[num_nodes] in: usize + output out: usize - state bank_index(bank_index); - state num_nodes(num_nodes); - reaction (startup) -> out {= - ctx.set(out, self.bank_index); - =} + state bank_index(bank_index) + state num_nodes(num_nodes) - reaction (in) {= + reaction(startup) -> out {= ctx.set(out, self.bank_index); =} + + reaction(in) {= let count = r#in.into_iter().filter(|p| ctx.is_present(p)).count(); assert_eq!(count, self.num_nodes); println!("success") @@ -18,6 +18,7 @@ reactor Node(bank_index: usize(0), num_nodes: usize(4)) { } main reactor(num_nodes: usize(4)) { - nodes = new[num_nodes] Node(num_nodes=num_nodes); - (nodes.out)+ -> nodes.in; + nodes = new[num_nodes] Node(num_nodes = num_nodes) + + (nodes.out)+ -> nodes.in } diff --git a/test/Rust/src/multiport/ConnectionToSelfMultiport.lf b/test/Rust/src/multiport/ConnectionToSelfMultiport.lf index ab4b55d212..78b003dadd 100644 --- a/test/Rust/src/multiport/ConnectionToSelfMultiport.lf +++ b/test/Rust/src/multiport/ConnectionToSelfMultiport.lf @@ -1,18 +1,20 @@ // test a connection from a multiport to another multiport of the same reactor -target Rust; +target Rust reactor Node(num_nodes: usize(4)) { input[num_nodes] in: usize + output[num_nodes] out: usize - state num_nodes(num_nodes); - reaction (startup) -> out {= + state num_nodes(num_nodes) + + reaction(startup) -> out {= for (i, out) in out.into_iter().enumerate() { ctx.set(out, i) } =} - reaction (in) {= + reaction(in) {= let count = r#in.into_iter().filter(|p| ctx.is_present(p)).count(); assert_eq!(count, self.num_nodes); println!("success") @@ -20,7 +22,7 @@ reactor Node(num_nodes: usize(4)) { } main reactor(num_nodes: usize(4)) { - nodes = new Node(num_nodes=num_nodes); - // todo: (nodes.out)+ -> nodes.in; - nodes.out -> nodes.in; + nodes = new Node(num_nodes = num_nodes) + + nodes.out -> nodes.in // todo: (nodes.out)+ -> nodes.in; } diff --git a/test/Rust/src/multiport/CycledLhs_SelfLoop.lf b/test/Rust/src/multiport/CycledLhs_SelfLoop.lf index 95eaf2cda3..9cebea3721 100644 --- a/test/Rust/src/multiport/CycledLhs_SelfLoop.lf +++ b/test/Rust/src/multiport/CycledLhs_SelfLoop.lf @@ -1,23 +1,21 @@ -// test a cycled connection which has ports of the same reactor on the LHS and rhs -// (single port)+ -> multiport - -target Rust { - timeout: 16 usec, -}; +// test a cycled connection which has ports of the same reactor on the LHS and +// RHS. (single port)+ -> multiport +target Rust { timeout: 16 usec } reactor Test { - output out: u32; - input[2] in: u32; - logical action act: u32; - state last: u32(1); + input[2] in: u32 + + output out: u32 + + logical action act: u32 + + state last: u32(1) reaction(startup) -> act {= ctx.schedule_with_v(act, Some(1), after!(1 us)); =} - reaction(act) -> out {= - ctx.set_opt(out, ctx.get(act)); - =} + reaction(act) -> out {= ctx.set_opt(out, ctx.get(act)); =} reaction(in) -> act {= let sum: u32 = r#in.into_iter().map(|p| ctx.get(&p).unwrap()).sum(); @@ -34,6 +32,7 @@ reactor Test { } main reactor { - t = new Test(); - (t.out)+ -> t.in; + t = new Test() + + (t.out)+ -> t.in } diff --git a/test/Rust/src/multiport/CycledLhs_Single.lf b/test/Rust/src/multiport/CycledLhs_Single.lf index 3ab94497e7..15a3b5c7a9 100644 --- a/test/Rust/src/multiport/CycledLhs_Single.lf +++ b/test/Rust/src/multiport/CycledLhs_Single.lf @@ -1,15 +1,15 @@ -// test a cycled connection which has ports of the same reactor on the LHS and rhs -// (multiport)+ -> multiport - -target Rust { - timeout: 16 usec, -}; +// test a cycled connection which has ports of the same reactor on the LHS and +// RHS. (multiport)+ -> multiport +target Rust { timeout: 16 usec } reactor Test { - output[2] out: u32; - input[4] in: u32; - logical action act: {= (u32, u32) =}; - state last: u32(1); + input[4] in: u32 + + output[2] out: u32 + + logical action act: {= (u32, u32) =} + + state last: u32(1) reaction(startup) -> act {= ctx.schedule_with_v(act, Some((0, 1)), after!(1 us)); @@ -41,28 +41,26 @@ reactor Test { =} } +// Fibonacci numbers: +// * 0 + 1 = 1 +// * 1 + 1 = 2 +// * 1 + 2 = 3 +// * 2 + 3 = 5 +// * 3 + 5 = 8 +// * 5 + 8 = 13 +// * 8 + 13 = 21 +// * 13 + 21 = 34 +// * 21 + 34 = 55 +// * 34 + 55 = 89 +// * 55 + 89 = 144 +// * 89 + 144 = 233 +// * 144 + 233 = 377 +// * 233 + 377 = 610 +// * 377 + 610 = 987 +// * 610 + 987 = 1597 +// * 987 + 1597 = 2584 main reactor { - t = new Test(); - (t.out)+ -> t.in; -} - -/* -0 + 1 = 1 -1 + 1 = 2 -1 + 2 = 3 -2 + 3 = 5 -3 + 5 = 8 -5 + 8 = 13 -8 + 13 = 21 -13 + 21 = 34 -21 + 34 = 55 -34 + 55 = 89 -55 + 89 = 144 -89 + 144 = 233 -144 + 233 = 377 -233 + 377 = 610 -377 + 610 = 987 -610 + 987 = 1597 -987 + 1597 = 2584 + t = new Test() - */ + (t.out)+ -> t.in +} diff --git a/test/Rust/src/multiport/FullyConnected.lf b/test/Rust/src/multiport/FullyConnected.lf index a0a2e3223f..402a85ab96 100644 --- a/test/Rust/src/multiport/FullyConnected.lf +++ b/test/Rust/src/multiport/FullyConnected.lf @@ -1,20 +1,20 @@ // test iterated connection on the left -target Rust; +target Rust reactor Left(bank_index: usize(0)) { output out: usize - state bank_index(bank_index); - reaction (startup) -> out {= - ctx.set(out, self.bank_index); - =} + state bank_index(bank_index) + + reaction(startup) -> out {= ctx.set(out, self.bank_index); =} } reactor Right(bank_index: usize(0), num_nodes: usize(4)) { input[num_nodes] in: usize - state num_nodes(num_nodes); - reaction (in) {= + state num_nodes(num_nodes) + + reaction(in) {= let count = r#in.into_iter().filter(|p| ctx.is_present(p)).count(); assert_eq!(count, self.num_nodes); println!("success") @@ -22,7 +22,8 @@ reactor Right(bank_index: usize(0), num_nodes: usize(4)) { } main reactor(num_nodes: usize(4)) { - left = new[num_nodes] Left(); - right = new[num_nodes] Right(num_nodes=num_nodes); - (left.out)+ -> right.in; + left = new[num_nodes] Left() + right = new[num_nodes] Right(num_nodes = num_nodes) + + (left.out)+ -> right.in } diff --git a/test/Rust/src/multiport/FullyConnectedAddressable.lf b/test/Rust/src/multiport/FullyConnectedAddressable.lf index 1da11f65cb..79de2438cb 100644 --- a/test/Rust/src/multiport/FullyConnectedAddressable.lf +++ b/test/Rust/src/multiport/FullyConnectedAddressable.lf @@ -1,23 +1,22 @@ // In this pattern, each node can send direct messages to individual other nodes - -target Rust; +target Rust reactor Node(bank_index: usize(0), num_nodes: usize(4)) { - state bank_index(bank_index); - state num_nodes(num_nodes); + input[num_nodes] inpt: usize - input[num_nodes] inpt: usize; - output[num_nodes] out: usize; + output[num_nodes] out: usize - state received: bool(false); + state bank_index(bank_index) + state num_nodes(num_nodes) + state received: bool(false) - reaction (startup) -> out{= + reaction(startup) -> out {= println!("Hello from node {}!", self.bank_index); // send my ID only to my right neighbour ctx.set(out.get((self.bank_index + 1) % self.num_nodes), self.bank_index); =} - reaction (inpt) {= + reaction(inpt) {= print!("Node {} received messages from ", self.bank_index); self.received = true; let mut count = 0; @@ -35,9 +34,9 @@ reactor Node(bank_index: usize(0), num_nodes: usize(4)) { if count != 1 || result != expected { panic!("ERROR: received an unexpected message!"); } - =} - reaction (shutdown) {= + + reaction(shutdown) {= if !self.received { panic!("Error: received no input!"); } @@ -45,9 +44,9 @@ reactor Node(bank_index: usize(0), num_nodes: usize(4)) { } main reactor(num_nodes: usize(4)) { - nodes1 = new[num_nodes] Node(num_nodes=num_nodes); - nodes1.out -> interleaved(nodes1.inpt); + nodes1 = new[num_nodes] Node(num_nodes = num_nodes) + nodes2 = new[num_nodes] Node(num_nodes = num_nodes) - nodes2 = new[num_nodes] Node(num_nodes=num_nodes); - interleaved(nodes2.out) -> nodes2.inpt; + nodes1.out -> interleaved (nodes1.inpt) + interleaved (nodes2.out) -> nodes2.inpt } diff --git a/test/Rust/src/multiport/MultiportFromBank.lf b/test/Rust/src/multiport/MultiportFromBank.lf index 25d55a5678..fe67388d90 100644 --- a/test/Rust/src/multiport/MultiportFromBank.lf +++ b/test/Rust/src/multiport/MultiportFromBank.lf @@ -1,16 +1,17 @@ // Check bank output to multiport input. -target Rust { - timeout: 2 sec, -}; +target Rust { timeout: 2 sec } + reactor Source(bank_index: usize(0)) { - output out: usize; - state bank_index(bank_index); - reaction(startup) -> out {= - ctx.set(out, self.bank_index); - =} + output out: usize + + state bank_index(bank_index) + + reaction(startup) -> out {= ctx.set(out, self.bank_index); =} } + reactor Destination(port_width: usize(2)) { - input[port_width] in: usize; + input[port_width] in: usize + reaction(in) {= for (i, port) in r#in.into_iter().enumerate() { assert_eq!(Some(i), ctx.get(&port), "Failed for input in[{}]", i); @@ -20,7 +21,8 @@ reactor Destination(port_width: usize(2)) { } main reactor { - a = new[4] Source(); - b = new Destination(port_width = 4); - a.out -> b.in; + a = new[4] Source() + b = new Destination(port_width = 4) + + a.out -> b.in } diff --git a/test/Rust/src/multiport/MultiportFromHierarchy.lf b/test/Rust/src/multiport/MultiportFromHierarchy.lf index b4a48da6fe..1a075f3139 100644 --- a/test/Rust/src/multiport/MultiportFromHierarchy.lf +++ b/test/Rust/src/multiport/MultiportFromHierarchy.lf @@ -1,11 +1,14 @@ -// Check multiport output to multiport input, where the former is a hierarchical reactor. -target Rust { - timeout: 2 sec, -}; +// Check multiport output to multiport input, where the former is a hierarchical +// reactor. +target Rust { timeout: 2 sec } + reactor Source { - timer t(0, 200 msec); - output[4] out: u32; - state s: u32(0); + output[4] out: u32 + + timer t(0, 200 msec) + + state s: u32(0) + reaction(t) -> out {= for mut chan in out { ctx.set(&mut chan, self.s); @@ -13,34 +16,44 @@ reactor Source { } =} } + reactor Destination { - state s: u32(6); - input[4] in: u32; + input[4] in: u32 + + state s: u32(6) + reaction(in) {= let sum: u32 = r#in.into_iter().map(|p| ctx.get(&p).unwrap()).sum(); println!("Sum of received: {}", sum); assert_eq!(sum, self.s); self.s += 16; =} + reaction(shutdown) {= assert!(self.s > 6, "Destination received no input!"); println!("Success"); =} } + reactor Container { - output[4] out: u32; - src = new InsideContainer(); - src.out -> out; + output[4] out: u32 + + src = new InsideContainer() + + src.out -> out } reactor InsideContainer { - output[4] out: u32; - src = new Source(); - src.out -> out; + output[4] out: u32 + + src = new Source() + + src.out -> out } -main reactor MultiportFromHierarchy { - a = new Container(); - b = new Destination(); - a.out -> b.in; +main reactor MultiportFromHierarchy { + a = new Container() + b = new Destination() + + a.out -> b.in } diff --git a/test/Rust/src/multiport/MultiportIn.lf b/test/Rust/src/multiport/MultiportIn.lf index 8b72e81d99..ab71d66d66 100644 --- a/test/Rust/src/multiport/MultiportIn.lf +++ b/test/Rust/src/multiport/MultiportIn.lf @@ -1,35 +1,42 @@ -// This is a version fo the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target Rust { - timeout: 2 sec, - fast: true -}; +// This is a version fo the Threaded test that uses a multiport input at the +// destination. Its purpose is to test multiport inputs. +target Rust { timeout: 2 sec, fast: true } reactor Source { - timer t(0, 200 msec); - output out: u32; - state s: u32(0); + output out: u32 + + timer t(0, 200 msec) + + state s: u32(0) + reaction(t) -> out {= ctx.set(out, self.s); self.s += 1; =} } + reactor Computation { - input in: u32; - output out: u32; + input in: u32 + + output out: u32 + reaction(in) -> out {= ctx.set(out, ctx.get(r#in).unwrap()); =} } + reactor Destination { - state s: u32(0); - input[4] in: u32; + input[4] in: u32 + + state s: u32(0) + reaction(in) {= let sum: u32 = r#in.into_iter().map(|p| ctx.get(&p).unwrap()).sum(); println!("Sum of received: {}", sum); assert_eq!(sum, self.s); self.s += 4; =} + reaction(shutdown) {= assert_ne!(0, self.s); println!("Success"); @@ -37,15 +44,16 @@ reactor Destination { } main reactor MultiportIn { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in; - a.out -> t2.in; - a.out -> t3.in; - a.out -> t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in + a.out -> t2.in + a.out -> t3.in + a.out -> t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/Rust/src/multiport/MultiportOut.lf b/test/Rust/src/multiport/MultiportOut.lf index 255f1c67e2..fa6ac48a37 100644 --- a/test/Rust/src/multiport/MultiportOut.lf +++ b/test/Rust/src/multiport/MultiportOut.lf @@ -1,11 +1,13 @@ // Check multiport capabilities on Outputs. -target Rust { - timeout: 2 sec, -}; +target Rust { timeout: 2 sec } + reactor Source { - timer t(0, 200 msec); - output[4] out: u32; - state s: u32(0); + output[4] out: u32 + + timer t(0, 200 msec) + + state s: u32(0) + reaction(t) -> out {= for i in 0..out.len() { ctx.set(out.get(i), self.s); @@ -13,9 +15,12 @@ reactor Source { self.s += 1; =} } + reactor Computation { - input in: u32; - output out: u32; + input in: u32 + + output out: u32 + reaction(in) -> out {= // No need to sleep for this test. // struct timespec sleep_time = {(time_t) 0, (long)200000000}; @@ -24,9 +29,12 @@ reactor Computation { ctx.set(out, ctx.get(r#in).unwrap()); =} } + reactor Destination { - state s: u32(0); - input[4] in: u32; + input[4] in: u32 + + state s: u32(0) + reaction(in) {= let mut sum = 0; for channel in r#in { @@ -38,6 +46,7 @@ reactor Destination { assert_eq!(sum, self.s); self.s += 4; =} + reaction(shutdown) {= assert_ne!(0, self.s); println!("Success"); @@ -45,12 +54,13 @@ reactor Destination { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.in, t2.in, t3.in, t4.in; - t1.out, t2.out, t3.out, t4.out -> b.in; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.in, t2.in, t3.in, t4.in + t1.out, t2.out, t3.out, t4.out -> b.in } diff --git a/test/Rust/src/multiport/MultiportToBank.lf b/test/Rust/src/multiport/MultiportToBank.lf index a148b2a96a..a460c7e2e3 100644 --- a/test/Rust/src/multiport/MultiportToBank.lf +++ b/test/Rust/src/multiport/MultiportToBank.lf @@ -1,10 +1,10 @@ // Check multiport output to bank of recipients. -target Rust; +target Rust reactor Source { - output[4] out: usize; + output[4] out: usize - reaction (startup) -> out {= + reaction(startup) -> out {= for (i, out) in out.into_iter().enumerate() { ctx.set(out, i) } @@ -12,12 +12,12 @@ reactor Source { } reactor Sink(bank_index: usize(0)) { - input in: usize; - state bank_index(bank_index); + input in: usize - state asserts_done: u32(0); + state bank_index(bank_index) + state asserts_done: u32(0) - reaction (in) {= + reaction(in) {= assert_eq!(ctx.get(r#in), Some(self.bank_index)); self.asserts_done += 1; =} @@ -29,7 +29,8 @@ reactor Sink(bank_index: usize(0)) { } main reactor MultiportToBank { - source = new Source(); - sink = new[4] Sink(); - source.out -> sink.in; + source = new Source() + sink = new[4] Sink() + + source.out -> sink.in } diff --git a/test/Rust/src/multiport/MultiportToBankHierarchy.lf b/test/Rust/src/multiport/MultiportToBankHierarchy.lf index bf705b85b2..27d1324d0b 100644 --- a/test/Rust/src/multiport/MultiportToBankHierarchy.lf +++ b/test/Rust/src/multiport/MultiportToBankHierarchy.lf @@ -1,9 +1,9 @@ // Check multiport output to bank of recipients within a hierarchy. -target Rust { - timeout: 2 sec, -}; +target Rust { timeout: 2 sec } + reactor Source { - output[3] out: usize; + output[3] out: usize + reaction(startup) -> out {= for (i, out) in out.into_iter().enumerate() { ctx.set(out, i) @@ -12,15 +12,16 @@ reactor Source { } reactor Destination(bank_index: usize(0)) { - input in: usize; + input in: usize - state bank_index(bank_index); - state asserts_done: u32(0); + state bank_index(bank_index) + state asserts_done: u32(0) reaction(in) {= assert_eq!(ctx.get(r#in), Some(self.bank_index)); self.asserts_done += 1; =} + reaction(shutdown) {= assert_eq!(self.asserts_done, 1, "should have been triggered once (per instance)"); println!("success {}/3", self.bank_index) @@ -28,13 +29,16 @@ reactor Destination(bank_index: usize(0)) { } reactor Container { - input[3] in: usize; - c = new[3] Destination(); - in -> c.in; + input[3] in: usize + + c = new[3] Destination() + + in -> c.in } main reactor MultiportToBankHierarchy { - a = new Source(); - b = new Container(); - a.out -> b.in; + a = new Source() + b = new Container() + + a.out -> b.in } diff --git a/test/Rust/src/multiport/MultiportToMultiport.lf b/test/Rust/src/multiport/MultiportToMultiport.lf index 23c50f1700..3c12c462c6 100644 --- a/test/Rust/src/multiport/MultiportToMultiport.lf +++ b/test/Rust/src/multiport/MultiportToMultiport.lf @@ -1,10 +1,10 @@ // test a connection multiport to multiport (same width) -target Rust; +target Rust reactor Source { - output[4] out: usize; + output[4] out: usize - reaction (startup) -> out {= + reaction(startup) -> out {= for (i, out) in out.into_iter().enumerate() { ctx.set(out, i) } @@ -12,9 +12,9 @@ reactor Source { } reactor Sink { - input[4] in: usize; + input[4] in: usize - reaction (in) {= + reaction(in) {= for (i, port) in r#in.into_iter().enumerate() { assert_eq!(Some(i), ctx.get(&port), "Failed for input in[{}]", i); } @@ -23,7 +23,8 @@ reactor Sink { } main reactor MultiportToMultiport { - source = new Source(); - sink = new Sink(); - source.out -> sink.in; + source = new Source() + sink = new Sink() + + source.out -> sink.in } diff --git a/test/Rust/src/multiport/MultiportToMultiport2.lf b/test/Rust/src/multiport/MultiportToMultiport2.lf index 8e420f56d1..7df3262903 100644 --- a/test/Rust/src/multiport/MultiportToMultiport2.lf +++ b/test/Rust/src/multiport/MultiportToMultiport2.lf @@ -1,9 +1,11 @@ -// test a sparse connection between multiports (some channels are left disconnected) -target Rust; +// test a sparse connection between multiports (some channels are left +// disconnected) +target Rust reactor Source(width: usize(2)) { - output[width] out: usize; - reaction (startup) -> out {= + output[width] out: usize + + reaction(startup) -> out {= for (i, out) in out.into_iter().enumerate() { ctx.set(out, i) } @@ -11,8 +13,9 @@ reactor Source(width: usize(2)) { } reactor Destination(width: usize(2)) { - input[width] in: usize; - reaction (in) {= + input[width] in: usize + + reaction(in) {= for (i, port) in r#in.into_iter().enumerate() { if let Some(v) = ctx.get(&port) { // NOTE: For testing purposes, this assumes the specific @@ -25,8 +28,9 @@ reactor Destination(width: usize(2)) { } main reactor MultiportToMultiport2 { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.in; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.in } diff --git a/test/Rust/src/target/BuildProfileDefaultIsDev.lf b/test/Rust/src/target/BuildProfileDefaultIsDev.lf index fe48c162a6..b27f66a2d0 100644 --- a/test/Rust/src/target/BuildProfileDefaultIsDev.lf +++ b/test/Rust/src/target/BuildProfileDefaultIsDev.lf @@ -1,7 +1,6 @@ -// Tests that the default build profile is dev. -// A proxy for checking this is to check that debug assertions are enabled. - -target Rust; +// Tests that the default build profile is dev. A proxy for checking this is to +// check that debug assertions are enabled. +target Rust main reactor { reaction(startup) {= diff --git a/test/Rust/src/target/BuildProfileRelease.lf b/test/Rust/src/target/BuildProfileRelease.lf index c82022c44e..3117bfcfb7 100644 --- a/test/Rust/src/target/BuildProfileRelease.lf +++ b/test/Rust/src/target/BuildProfileRelease.lf @@ -1,9 +1,6 @@ -// Tests that the we can enable the release profile -// A proxy for checking this is to check that debug assertions are disabled. - -target Rust { - build-type: "Release", -}; +// Tests that the we can enable the release profile. A proxy for checking this +// is to check that debug assertions are disabled. +target Rust { build-type: "Release" } main reactor { reaction(startup) {= diff --git a/test/Rust/src/target/CargoDependency.lf b/test/Rust/src/target/CargoDependency.lf index cdba261ea8..243c0cb0d2 100644 --- a/test/Rust/src/target/CargoDependency.lf +++ b/test/Rust/src/target/CargoDependency.lf @@ -1,17 +1,13 @@ -// This tests the ability to depend on crates with carg -// if this compiles it's fine -target Rust { - cargo-dependencies: { - rand: "0.8", - regex: { - version: "1", - }, - } -}; +/** + * This tests the ability to depend on crates with carg + * + * if this compiles it's fine + */ +target Rust { cargo-dependencies: { rand: "0.8", regex: { version: "1" } } } main reactor { - reaction(startup) {= + reaction(startup) {= use rand::rngs::StdRng; use regex::*; - =} + =} } diff --git a/test/Rust/src/target/CargoDependencyOnRuntime.lf b/test/Rust/src/target/CargoDependencyOnRuntime.lf index dedba415ae..6a652ec4f4 100644 --- a/test/Rust/src/target/CargoDependencyOnRuntime.lf +++ b/test/Rust/src/target/CargoDependencyOnRuntime.lf @@ -1,15 +1,12 @@ -// This tests the ability to depend on crates with carg -// if this compiles it's fine +/** + * This tests the ability to depend on crates with carg + * + * if this compiles it's fine + */ target Rust { - cargo-dependencies: { - reactor_rt: { - features: ["parallel-runtime"] - }, - } -}; + cargo-dependencies: { reactor_rt: { features: ["parallel-runtime"] } } +} main reactor { - reaction(startup) {= - println!("success") - =} + reaction(startup) {= println!("success") =} } diff --git a/test/Rust/src/target/CliFeature.lf b/test/Rust/src/target/CliFeature.lf index 96228bf9b4..7f5ee84132 100644 --- a/test/Rust/src/target/CliFeature.lf +++ b/test/Rust/src/target/CliFeature.lf @@ -1,12 +1,6 @@ -target Rust { - build-type: Release, - cargo-features: ["cli"] -}; +target Rust { build-type: Release, cargo-features: ["cli"] } // todo allow test framework to pass CLI arguments. - -main reactor CliFeature(size: u32(4), t: time(4 sec)){ - reaction(startup) {= - println!("success"); - =} +main reactor CliFeature(size: u32(4), t: time(4 sec)) { + reaction(startup) {= println!("success"); =} } diff --git a/test/Rust/src/target/ModuleDependency.lf b/test/Rust/src/target/ModuleDependency.lf index d5565d6e85..2753be5ca5 100644 --- a/test/Rust/src/target/ModuleDependency.lf +++ b/test/Rust/src/target/ModuleDependency.lf @@ -1,14 +1,12 @@ // Test that we can include modules into main -target Rust { - rust-include: "some_module.rs", -}; +target Rust { rust-include: "some_module.rs" } main reactor { - timer t(0); + timer t(0) - reaction(t) {= - use crate::some_module::*; - assert_eq!("hihihi", from_some_module()); - println!("success"); - =} + reaction(t) {= + use crate::some_module::*; + assert_eq!("hihihi", from_some_module()); + println!("success"); + =} } diff --git a/test/Rust/src/target/ModuleDependencyWithDirModule.lf b/test/Rust/src/target/ModuleDependencyWithDirModule.lf index 78583930e7..4e25afaf87 100644 --- a/test/Rust/src/target/ModuleDependencyWithDirModule.lf +++ b/test/Rust/src/target/ModuleDependencyWithDirModule.lf @@ -1,10 +1,8 @@ // The same as CompositionWithPorts.lf, but as a single file project -target Rust { - rust-include: "testmod", -}; +target Rust { rust-include: "testmod" } main reactor { - timer t(0); + timer t(0) reaction(t) {= use crate::testmod::*; From c9d197fc41204131dc1ba192a4e5c80d03c9b76a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 14:41:27 -0700 Subject: [PATCH 093/130] [formatting] Format TypeScript tests. --- .../src/org/lflang/ast/FormattingUtils.java | 3 +- test/TypeScript/src/ActionDelay.lf | 39 +++++----- test/TypeScript/src/ActionWithNoReaction.lf | 41 ++++++----- test/TypeScript/src/After.lf | 43 ++++++----- test/TypeScript/src/ArrayAsParameter.lf | 32 +++++--- test/TypeScript/src/ArrayAsType.lf | 24 +++--- test/TypeScript/src/ArrayPrint.lf | 26 ++++--- test/TypeScript/src/ArrayScale.lf | 34 +++++---- test/TypeScript/src/Composition.lf | 33 +++++---- test/TypeScript/src/CompositionAfter.lf | 37 ++++++---- test/TypeScript/src/CountTest.lf | 22 +++--- test/TypeScript/src/DanglingOutput.lf | 28 ++++--- test/TypeScript/src/Deadline.lf | 41 ++++++----- test/TypeScript/src/DeadlineHandledAbove.lf | 30 +++++--- test/TypeScript/src/DelayInt.lf | 46 +++++++----- test/TypeScript/src/DelayedAction.lf | 18 ++--- test/TypeScript/src/DelayedReaction.lf | 23 +++--- test/TypeScript/src/Determinism.lf | 47 ++++++------ test/TypeScript/src/DoubleInvocation.lf | 59 ++++++++------- test/TypeScript/src/DoubleReaction.lf | 42 ++++++----- test/TypeScript/src/DoubleTrigger.lf | 19 ++--- test/TypeScript/src/FloatLiteral.lf | 15 ++-- test/TypeScript/src/Gain.lf | 73 ++++++++++--------- test/TypeScript/src/GetTime.lf | 14 ++-- test/TypeScript/src/Hello.lf | 48 +++++++----- test/TypeScript/src/HelloWorld.lf | 13 ++-- test/TypeScript/src/Hierarchy.lf | 54 +++++++++----- test/TypeScript/src/Hierarchy2.lf | 72 ++++++++++-------- test/TypeScript/src/Import.lf | 22 +++--- test/TypeScript/src/Microsteps.lf | 23 +++--- test/TypeScript/src/Minimal.lf | 10 +-- test/TypeScript/src/MovingAverage.lf | 53 ++++++++------ test/TypeScript/src/MultipleContained.lf | 25 ++++--- test/TypeScript/src/NativeListsAndTimes.lf | 41 ++++++----- test/TypeScript/src/ParameterizedState.lf | 14 ++-- test/TypeScript/src/PeriodicDesugared.lf | 14 ++-- test/TypeScript/src/Preamble.lf | 9 ++- .../src/ReadOutputOfContainedReactor.lf | 24 +++--- test/TypeScript/src/Schedule.lf | 28 ++++--- test/TypeScript/src/ScheduleLogicalAction.lf | 47 ++++++------ test/TypeScript/src/SendingInside.lf | 25 ++++--- test/TypeScript/src/SendingInside2.lf | 17 +++-- test/TypeScript/src/SendsPointerTest.lf | 26 ++++--- test/TypeScript/src/SimpleDeadline.lf | 35 ++++++--- test/TypeScript/src/SimpleImport.lf | 9 ++- test/TypeScript/src/SlowingClock.lf | 20 ++--- test/TypeScript/src/SlowingClockPhysical.lf | 34 +++++---- test/TypeScript/src/Stride.lf | 37 +++++----- test/TypeScript/src/StructAsState.lf | 9 +-- test/TypeScript/src/StructAsType.lf | 27 ++++--- test/TypeScript/src/StructAsTypeDirect.lf | 29 +++++--- test/TypeScript/src/StructPrint.lf | 28 ++++--- test/TypeScript/src/StructScale.lf | 37 ++++++---- test/TypeScript/src/TestForPreviousOutput.lf | 23 ++++-- test/TypeScript/src/TimeLimit.lf | 48 ++++++------ test/TypeScript/src/TimeState.lf | 12 ++- test/TypeScript/src/Wcet.lf | 40 +++++----- .../src/concurrent/AsyncCallback.lf | 18 ++--- .../src/docker/HelloWorldContainerized.lf | 6 +- .../src/federated/ChainWithDelay.lf | 24 +++--- .../src/federated/HelloDistributed.lf | 39 +++++----- .../src/federated/PingPongDistributed.lf | 51 +++++++------ .../src/federated/StopAtShutdown.lf | 46 +++++------- .../src/federated/TopLevelArtifacts.lf | 60 +++++++-------- test/TypeScript/src/lib/Count.lf | 19 ++--- test/TypeScript/src/lib/Imported.lf | 22 +++--- test/TypeScript/src/lib/ImportedAgain.lf | 12 +-- test/TypeScript/src/lib/InternalDelay.lf | 29 ++++---- test/TypeScript/src/lib/TestCount.lf | 14 ++-- .../TypeScript/src/multiport/BankMulticast.lf | 35 +++++---- .../src/multiport/BankMultiportToReaction.lf | 24 +++--- .../src/multiport/BankReactionsInContainer.lf | 22 ++++-- .../src/multiport/BankSelfBroadcast.lf | 31 ++++---- test/TypeScript/src/multiport/BankToBank.lf | 31 +++++--- .../src/multiport/BankToBankMultiport.lf | 36 +++++---- .../src/multiport/BankToBankMultiportAfter.lf | 36 +++++---- .../src/multiport/BankToMultiport.lf | 26 ++++--- .../src/multiport/BankToReaction.lf | 11 ++- test/TypeScript/src/multiport/Broadcast.lf | 19 +++-- .../src/multiport/BroadcastAfter.lf | 24 +++--- .../src/multiport/BroadcastMultipleAfter.lf | 30 ++++---- .../src/multiport/FullyConnected.lf | 26 ++++--- .../src/multiport/MultiportFromBank.lf | 35 +++++---- .../multiport/MultiportFromBankHierarchy.lf | 27 ++++--- .../MultiportFromBankHierarchyAfter.lf | 16 ++-- .../src/multiport/MultiportFromHierarchy.lf | 59 +++++++++------ .../src/multiport/MultiportFromReaction.lf | 26 ++++--- test/TypeScript/src/multiport/MultiportIn.lf | 59 ++++++++------- .../src/multiport/MultiportInParameterized.lf | 68 +++++++++-------- .../src/multiport/MultiportMutableInput.lf | 40 +++++----- .../multiport/MultiportMutableInputArray.lf | 40 +++++----- test/TypeScript/src/multiport/MultiportOut.lf | 46 +++++++----- .../src/multiport/MultiportToBank.lf | 17 +++-- .../src/multiport/MultiportToBankAfter.lf | 30 +++++--- .../src/multiport/MultiportToBankDouble.lf | 37 ++++++---- .../src/multiport/MultiportToBankHierarchy.lf | 36 +++++---- .../src/multiport/MultiportToHierarchy.lf | 51 ++++++++----- .../src/multiport/MultiportToMultiport.lf | 23 +++--- .../src/multiport/MultiportToMultiport2.lf | 28 +++---- .../multiport/MultiportToMultiport2After.lf | 28 +++---- .../multiport/MultiportToMultiportArray.lf | 32 ++++---- .../MultiportToMultiportParameter.lf | 36 +++++---- .../src/multiport/MultiportToPort.lf | 31 ++++---- .../src/multiport/MultiportToReaction.lf | 24 +++--- test/TypeScript/src/multiport/NestedBanks.lf | 59 +++++++++------ .../TypeScript/src/multiport/PipelineAfter.lf | 30 ++++---- .../src/multiport/ReactionToContainedBank.lf | 16 ++-- .../src/multiport/ReactionsToNested.lf | 40 +++++----- .../src/serialization/ProtoNoPacking.lf | 38 +++++----- test/TypeScript/src/target/AfterNoTypes.lf | 34 +++++---- 110 files changed, 1924 insertions(+), 1515 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 690162e72d..4cdbcaa994 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -102,7 +102,8 @@ static String lineWrapComments( StringBuilder current = new StringBuilder(); for (String comment : comments) { if (comment.stripLeading().startsWith("/*")) { - ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); + ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)) + .append("\n"); current.setLength(0); ret.append(lineWrapComment(comment, width, singleLineCommentPrefix)).append("\n"); } else { diff --git a/test/TypeScript/src/ActionDelay.lf b/test/TypeScript/src/ActionDelay.lf index 29f7d687f6..354f09b31c 100644 --- a/test/TypeScript/src/ActionDelay.lf +++ b/test/TypeScript/src/ActionDelay.lf @@ -1,30 +1,32 @@ // Test logical action with delay. -target TypeScript; +target TypeScript reactor GeneratedDelay { - input y_in:number; - output y_out:number; - state y_state:number(0); - logical action act(100 msec); + input y_in: number + + output y_out: number + + logical action act(100 msec) + + state y_state: number(0) reaction(y_in) -> act {= y_state = y_in as number; actions.act.schedule(0, null); =} - reaction(act) -> y_out {= - y_out = y_state; - =} + reaction(act) -> y_out {= y_out = y_state; =} } reactor Source { - output out:number; - reaction(startup) -> out {= - out = 1; - =} + output out: number + + reaction(startup) -> out {= out = 1; =} } + reactor Sink { - input x:number; + input x: number + reaction(x) {= const elapsed_logical = util.getElapsedLogicalTime(); const logical = util.getCurrentLogicalTime(); @@ -38,11 +40,12 @@ reactor Sink { } =} } + main reactor ActionDelay { - source = new Source(); - sink = new Sink(); - g = new GeneratedDelay(); + source = new Source() + sink = new Sink() + g = new GeneratedDelay() - source.out -> g.y_in; - g.y_out -> sink.x; + source.out -> g.y_in + g.y_out -> sink.x } diff --git a/test/TypeScript/src/ActionWithNoReaction.lf b/test/TypeScript/src/ActionWithNoReaction.lf index 8da716146d..9bd0a2bbc3 100644 --- a/test/TypeScript/src/ActionWithNoReaction.lf +++ b/test/TypeScript/src/ActionWithNoReaction.lf @@ -1,33 +1,38 @@ -// This checks that action can be created even if there is no reaction. -// This test passes merely by compiling and executing without a segfault. -// Its other functionality is tested by other tests. -target TypeScript { - fast: true, - timeout: 3 sec -}; +// This checks that action can be created even if there is no reaction. This +// test passes merely by compiling and executing without a segfault. Its other +// functionality is tested by other tests. +target TypeScript { fast: true, timeout: 3 sec } + reactor foo { - input x:number; - output y:number; - logical action a; + input x: number + + output y: number + + logical action a + reaction(x) -> y, a {= y = 2 * (x as number); actions.a.schedule(TimeValue.msec(500), null) =} } + reactor print { - input x:number; + input x: number + reaction(x) {= console.log("Result is " + (x as number)); console.log("Current logical time is " + util.getElapsedLogicalTime()); console.log("Current physical time is: " + util.getElapsedPhysicalTime()); =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x = 42; - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= f.x = 42; =} } diff --git a/test/TypeScript/src/After.lf b/test/TypeScript/src/After.lf index 0cc0d9fcd0..c4e581e8de 100644 --- a/test/TypeScript/src/After.lf +++ b/test/TypeScript/src/After.lf @@ -1,19 +1,20 @@ -// This checks that the after keyword adjusts logical time, not -// using physical time. -target TypeScript { - fast: true, - timeout: 3 sec -}; +// This checks that the after keyword adjusts logical time, not using physical +// time. +target TypeScript { fast: true, timeout: 3 sec } + reactor Foo { - input x:number; - output y:number; - reaction(x) -> y {= - y = 2 * (x as number); - =} + input x: number + + output y: number + + reaction(x) -> y {= y = 2 * (x as number); =} } + reactor Print { - state expected_time:time(10 msec); - input x:number; + input x: number + + state expected_time: time(10 msec) + reaction(x) {= let elapsed_time = util.getElapsedLogicalTime(); console.log("Result is " + x); @@ -25,12 +26,14 @@ reactor Print { expected_time = expected_time.add(TimeValue.sec(1)); =} } + main reactor { - f = new Foo(); - p = new Print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x = 42; - =} - f.y -> p.x after 10 msec; + timer t(0, 1 sec) + + f = new Foo() + p = new Print() + + f.y -> p.x after 10 msec + + reaction(t) -> f.x {= f.x = 42; =} } diff --git a/test/TypeScript/src/ArrayAsParameter.lf b/test/TypeScript/src/ArrayAsParameter.lf index c4e349addb..9a8cf96d8f 100644 --- a/test/TypeScript/src/ArrayAsParameter.lf +++ b/test/TypeScript/src/ArrayAsParameter.lf @@ -1,10 +1,13 @@ -// Source has an array as a parameter, the elements of which it passes -// to Print. -target TypeScript; -reactor Source(sequence:{=Array=}({= [0, 1, 2] =})) { - output out:number; - state count:number(0); - logical action next; +// Source has an array as a parameter, the elements of which it passes to Print. +target TypeScript + +reactor Source(sequence: {= Array =}({= [0, 1, 2] =})) { + output out: number + + logical action next + + state count: number(0) + reaction(startup, next) -> out, next {= out = sequence[count]; count++; @@ -13,9 +16,12 @@ reactor Source(sequence:{=Array=}({= [0, 1, 2] =})) { } =} } + reactor Print { - input x:number; - state count:number(1); + input x: number + + state count: number(1) + reaction(x) {= console.log("Received: " + x + "."); if (x != count) { @@ -24,8 +30,10 @@ reactor Print { count++; =} } + main reactor ArrayAsParameter { - s = new Source(sequence={= [1, 2, 3, 4] =}); - p = new Print(); - s.out -> p.x; + s = new Source(sequence = {= [1, 2, 3, 4] =}) + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/ArrayAsType.lf b/test/TypeScript/src/ArrayAsType.lf index 41f6f99c81..00da6fccf9 100644 --- a/test/TypeScript/src/ArrayAsType.lf +++ b/test/TypeScript/src/ArrayAsType.lf @@ -1,10 +1,11 @@ -// In TypeScript this test is almost exactly the same as ArrayAsType. +// In TypeScript this test is almost exactly the same as ArrayAsType. Source +// produces a statically allocated array, which it passes to Print. The +// destination references the array directly. +target TypeScript -// Source produces a statically allocated array, which it passes -// to Print. The destination references the array directly. -target TypeScript; reactor Source { - output out:{=Array=}; + output out: {= Array =} + reaction(startup) -> out {= let toSend = []; toSend[0] = 0; @@ -14,9 +15,9 @@ reactor Source { =} } -// The scale parameter is just for testing. -reactor Print(scale:number(1)) { - input x:{=Array=}; +reactor Print(scale: number(1)) { // The scale parameter is just for testing. + input x: {= Array =} + reaction(x) {= let count = 0; // For testing. let failed = false; // For testing. @@ -41,7 +42,8 @@ reactor Print(scale:number(1)) { } main reactor ArrayAsType { - s = new Source(); - p = new Print(); - s.out -> p.x; + s = new Source() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/ArrayPrint.lf b/test/TypeScript/src/ArrayPrint.lf index 68299e2c8d..ff8096ff99 100644 --- a/test/TypeScript/src/ArrayPrint.lf +++ b/test/TypeScript/src/ArrayPrint.lf @@ -1,10 +1,11 @@ -// In TypeScript this test is almost exactly the same as ArrayAsType. +// In TypeScript this test is almost exactly the same as ArrayAsType. Source +// produces a dynamically allocated array, which it passes to Print. Reference +// counting ensures that the array is freed. +target TypeScript -// Source produces a dynamically allocated array, which it passes -// to Print. Reference counting ensures that the array is freed. -target TypeScript; reactor Source { - output out:{=Array=}; + output out: {= Array =} + reaction(startup) -> out {= let toSend = new Array(); toSend[0] = 0; @@ -13,9 +14,10 @@ reactor Source { out = toSend; =} } -// The scale parameter is just for testing. -reactor Print(scale:number(1)) { - input x:{=Array=}; + +reactor Print(scale: number(1)) { // The scale parameter is just for testing. + input x: {= Array =} + reaction(x) {= let count = 0; // For testing. let failed = false; // For testing. @@ -38,8 +40,10 @@ reactor Print(scale:number(1)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.x; + s = new Source() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/ArrayScale.lf b/test/TypeScript/src/ArrayScale.lf index 5f549fdae5..75c8019a8e 100644 --- a/test/TypeScript/src/ArrayScale.lf +++ b/test/TypeScript/src/ArrayScale.lf @@ -1,14 +1,16 @@ -// Source produces a dynamically allocated array, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target TypeScript; -import Source, Print from "ArrayPrint.lf"; +// Source produces a dynamically allocated array, which it passes to Scale. +// Scale requests a writable copy, which, instead of copying, it just gets +// ownership of the original array. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target TypeScript + +import Source, Print from "ArrayPrint.lf" + +reactor Scale(scale: number(2)) { + mutable input x: {= Array =} + + output out: {= Array =} -reactor Scale(scale:number(2)) { - mutable input x:{=Array=}; - output out:{=Array=}; reaction(x) -> out {= x = x as Array; for(let i = 0; i < x.length; i++) { @@ -17,10 +19,12 @@ reactor Scale(scale:number(2)) { out = x; =} } + main reactor ArrayScale { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.x; - c.out -> p.x; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.x + c.out -> p.x } diff --git a/test/TypeScript/src/Composition.lf b/test/TypeScript/src/Composition.lf index e68b978168..10a75a9903 100644 --- a/test/TypeScript/src/Composition.lf +++ b/test/TypeScript/src/Composition.lf @@ -1,12 +1,14 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target TypeScript { - timeout : 5 sec -}; -reactor Source(period:time(2 sec)) { - output y:number; - timer t(1 sec, period); - state count:number(0); +// This test connects a simple counting source to tester that checks against its +// own count. +target TypeScript { timeout: 5 sec } + +reactor Source(period: time(2 sec)) { + output y: number + + timer t(1 sec, period) + + state count: number(0) + reaction(t) -> y {= count++; y = count; @@ -14,8 +16,10 @@ reactor Source(period:time(2 sec)) { } reactor Test { - input x:number; - state count:number(0); + input x: number + + state count: number(0) + reaction(x) {= count++; console.log("Received " + x); @@ -24,9 +28,10 @@ reactor Test { } =} } + main reactor Composition { - s = new Source(); + s = new Source() + d = new Test() - d = new Test(); - s.y -> d.x; + s.y -> d.x } diff --git a/test/TypeScript/src/CompositionAfter.lf b/test/TypeScript/src/CompositionAfter.lf index e774d9d69b..f9766ca746 100644 --- a/test/TypeScript/src/CompositionAfter.lf +++ b/test/TypeScript/src/CompositionAfter.lf @@ -1,13 +1,14 @@ -// This test connects a simple counting source -// that checks against its own count. -target TypeScript { - fast: true, - timeout: 10 sec -}; -reactor Source(period:time(2 sec)) { - output y:number; - timer t(1 sec, period); - state count:number(0); +// This test connects a simple counting source that checks against its own +// count. +target TypeScript { fast: true, timeout: 10 sec } + +reactor Source(period: time(2 sec)) { + output y: number + + timer t(1 sec, period) + + state count: number(0) + reaction(t) -> y {= count++; y = count; @@ -15,8 +16,10 @@ reactor Source(period:time(2 sec)) { } reactor Test { - input x:number; - state count:number(0); + input x: number + + state count: number(0) + reaction(x) {= count++; console.log("Received " + x); @@ -25,8 +28,10 @@ reactor Test { } =} } -main reactor (delay:time(5 sec)) { - s = new Source(); - d = new Test(); - s.y -> d.x after delay; + +main reactor(delay: time(5 sec)) { + s = new Source() + d = new Test() + + s.y -> d.x after delay } diff --git a/test/TypeScript/src/CountTest.lf b/test/TypeScript/src/CountTest.lf index 664b870a97..b3179d42a9 100644 --- a/test/TypeScript/src/CountTest.lf +++ b/test/TypeScript/src/CountTest.lf @@ -1,12 +1,12 @@ -target TypeScript{ - timeout : 3 sec -}; +target TypeScript { timeout: 3 sec } + +import Count from "lib/Count.lf" -import Count from -"lib/Count.lf"; reactor Test { - input c:number; - state i:number(0); + input c: number + + state i: number(0) + reaction(c) {= console.log("Received " + c); i++; @@ -15,8 +15,10 @@ reactor Test { } =} } + main reactor CountTest { - count = new Count(); - test = new Test(); - count.out -> test.c; + count = new Count() + test = new Test() + + count.out -> test.c } diff --git a/test/TypeScript/src/DanglingOutput.lf b/test/TypeScript/src/DanglingOutput.lf index f348e7d230..c86bc365eb 100644 --- a/test/TypeScript/src/DanglingOutput.lf +++ b/test/TypeScript/src/DanglingOutput.lf @@ -1,17 +1,20 @@ // This tests that an output that is not connected to anything does not result -// in a compilation error. Passing the test is just compiling and running. -target TypeScript; +// in a compilation error. Passing the test is just compiling and running. +target TypeScript + reactor Source { - output out:number; - timer t; - reaction(t) -> out {= - out = 1; - =} + output out: number + + timer t + + reaction(t) -> out {= out = 1; =} } reactor Gain { - input x:number; - output out:number; + input x: number + + output out: number + reaction(x) -> out {= console.log("Received " + x); out = (x as number) * 2; @@ -19,7 +22,8 @@ reactor Gain { } main reactor DanglingOutput { - source = new Source(); - container = new Gain(); - source.out -> container.x; + source = new Source() + container = new Gain() + + source.out -> container.x } diff --git a/test/TypeScript/src/Deadline.lf b/test/TypeScript/src/Deadline.lf index 7cee366801..d5a2b86491 100644 --- a/test/TypeScript/src/Deadline.lf +++ b/test/TypeScript/src/Deadline.lf @@ -1,16 +1,15 @@ -// This example illustrates local deadline handling. -// Even numbers are sent by the Source immediately, whereas odd numbers -// are sent after a big enough delay to violate the deadline. -target TypeScript{ - timeout : 4 sec -}; - -//run = "bin/Deadline -timeout 4 sec" - -reactor Source(period:time(2 sec)) { - output y:number; - timer t(0, period); - state count:number(0); +// This example illustrates local deadline handling. Even numbers are sent by +// the Source immediately, whereas odd numbers are sent after a big enough delay +// to violate the deadline. +target TypeScript { timeout: 4 sec } + +reactor Source(period: time(2 sec)) { // run = "bin/Deadline -timeout 4 sec" + output y: number + + timer t(0, period) + + state count: number(0) + reaction(t) -> y {= if (2 * Math.floor(count / 2) != count){ // The count variable is odd. @@ -26,9 +25,11 @@ reactor Source(period:time(2 sec)) { =} } -reactor Destination(timeout:time(1 sec)) { - input x:number; - state count:number(0); +reactor Destination(timeout: time(1 sec)) { + input x: number + + state count: number(0) + reaction(x) {= console.log("Destination receives: " + x); if (2 * Math.floor(count / 2) != count) { @@ -45,8 +46,10 @@ reactor Destination(timeout:time(1 sec)) { count++; =} } + main reactor Deadline { - s = new Source(); - d = new Destination(timeout = 200 msec); - s.y -> d.x; + s = new Source() + d = new Destination(timeout = 200 msec) + + s.y -> d.x } diff --git a/test/TypeScript/src/DeadlineHandledAbove.lf b/test/TypeScript/src/DeadlineHandledAbove.lf index 585b7affe1..ffb127eda3 100644 --- a/test/TypeScript/src/DeadlineHandledAbove.lf +++ b/test/TypeScript/src/DeadlineHandledAbove.lf @@ -1,33 +1,41 @@ -// Test a deadline where the deadline violation produces -// an output and the container reacts to that output. -target TypeScript{ - timeout : 2 sec -}; -reactor Deadline(threshold:time(100 msec)) { - input x:number; - output deadline_violation:boolean; +// Test a deadline where the deadline violation produces an output and the +// container reacts to that output. +target TypeScript { timeout: 2 sec } + +reactor Deadline(threshold: time(100 msec)) { + input x: number + + output deadline_violation: boolean + reaction(x) -> deadline_violation {= util.requestErrorStop("ERROR: Deadline violation was not detected!") - =} deadline(threshold) {= + =} deadline( + threshold + ) {= console.log("Deadline violation detected."); deadline_violation = true; =} } + main reactor DeadlineHandledAbove { - state violation_detected:boolean(false); - d = new Deadline(threshold = 10 msec); + d = new Deadline(threshold = 10 msec) + + state violation_detected: boolean(false) + reaction(startup) -> d.x {= // Busy wait 20 msec to cause a deadline violation. let initialElapsedTime = util.getElapsedPhysicalTime(); while (util.getElapsedPhysicalTime().isEarlierThan(initialElapsedTime.add(TimeValue.msec(20)))); d.x = 42; =} + reaction(d.deadline_violation) {= if (d.deadline_violation) { console.log("Output successfully produced by deadline miss handler."); violation_detected = true; } =} + reaction(shutdown) {= if ( violation_detected) { console.log("SUCCESS. Test passes."); diff --git a/test/TypeScript/src/DelayInt.lf b/test/TypeScript/src/DelayInt.lf index 682938bbe5..39c938ae90 100644 --- a/test/TypeScript/src/DelayInt.lf +++ b/test/TypeScript/src/DelayInt.lf @@ -1,27 +1,34 @@ -// This tests actions with payloads by delaying an input by a fixed amount. -// This is a start at handling dynamic memory allocation for such actions. -target TypeScript; -reactor Delay(delay:time(100 msec)) { - input x:number; - output out:number; - logical action a:number; - reaction(x) -> a {= - actions.a.schedule( delay, x as number); - =} +// This tests actions with payloads by delaying an input by a fixed amount. This +// is a start at handling dynamic memory allocation for such actions. +target TypeScript + +reactor Delay(delay: time(100 msec)) { + input x: number + + output out: number + + logical action a: number + + reaction(x) -> a {= actions.a.schedule( delay, x as number); =} + reaction(a) -> out {= if (a !== null){ out = a as number } =} } + reactor Test { - input x:number; - state start_time:time(0); - state received_value:boolean(false); + input x: number + + state start_time: time(0) + state received_value: boolean(false) + reaction(startup) {= // Record the logical time at the start. start_time = util.getCurrentLogicalTime(); =} + reaction(x) {= console.log("Received: " + x); received_value = true; @@ -36,6 +43,7 @@ reactor Test { util.requestErrorStop("ERROR: Expected input value to be 42. It was " + x) } =} + reaction(shutdown) {= console.log("Checking that communication occurred."); if (!received_value) { @@ -45,10 +53,10 @@ reactor Test { } main reactor DelayInt { - d = new Delay(); - t = new Test(); - d.out -> t.x; - reaction(startup) -> d.x {= - d.x = 42; - =} + d = new Delay() + t = new Test() + + d.out -> t.x + + reaction(startup) -> d.x {= d.x = 42; =} } diff --git a/test/TypeScript/src/DelayedAction.lf b/test/TypeScript/src/DelayedAction.lf index 41278c86b9..3933af12ee 100644 --- a/test/TypeScript/src/DelayedAction.lf +++ b/test/TypeScript/src/DelayedAction.lf @@ -1,13 +1,13 @@ -target TypeScript{ - timeout : 5 sec -}; +target TypeScript { timeout: 5 sec } + main reactor DelayedAction { - timer t(0, 1 sec); - logical action a; - state count:number(0); - reaction(t) -> a {= - actions.a.schedule(TimeValue.msec(100), null); - =} + timer t(0, 1 sec) + + logical action a + + state count: number(0) + + reaction(t) -> a {= actions.a.schedule(TimeValue.msec(100), null); =} reaction(a) {= let elapsedLogical = util.getElapsedLogicalTime(); diff --git a/test/TypeScript/src/DelayedReaction.lf b/test/TypeScript/src/DelayedReaction.lf index 81302fcf23..7f78b3489e 100644 --- a/test/TypeScript/src/DelayedReaction.lf +++ b/test/TypeScript/src/DelayedReaction.lf @@ -1,16 +1,17 @@ // Test delay made on a connection. -target TypeScript; +target TypeScript reactor Source { - output out:number; - timer t; - reaction(t) -> out {= - out = 1; - =} + output out: number + + timer t + + reaction(t) -> out {= out = 1; =} } reactor Sink { - input x:number; + input x: number + reaction(x) {= let elapsed = util.getElapsedLogicalTime(); console.log("Nanoseconds since start: " + elapsed); @@ -19,8 +20,10 @@ reactor Sink { } =} } + main reactor DelayedReaction { - source = new Source(); - sink = new Sink(); - source.out -> sink.x after 100 msec; + source = new Source() + sink = new Sink() + + source.out -> sink.x after 100 msec } diff --git a/test/TypeScript/src/Determinism.lf b/test/TypeScript/src/Determinism.lf index 79d77cc7a1..0a9815531c 100644 --- a/test/TypeScript/src/Determinism.lf +++ b/test/TypeScript/src/Determinism.lf @@ -1,14 +1,17 @@ -target TypeScript; +target TypeScript + reactor Source { - output y:number; - timer t; - reaction(t) -> y {= - y = 1; - =} + output y: number + + timer t + + reaction(t) -> y {= y = 1; =} } + reactor Destination { - input x:number; - input y:number; + input x: number + input y: number + reaction(x, y) {= let sum = 0; if (x !== undefined) { @@ -23,21 +26,23 @@ reactor Destination { } =} } + reactor Pass { - input x:number; - output y:number; - reaction(x) -> y {= - y = x as number; - =} + input x: number + + output y: number + + reaction(x) -> y {= y = x as number; =} } main reactor Determinism { - s = new Source(); - d = new Destination(); - p1 = new Pass(); - p2 = new Pass(); - s.y -> d.y; - s.y -> p1.x; - p1.y -> p2.x; - p2.y -> d.x; + s = new Source() + d = new Destination() + p1 = new Pass() + p2 = new Pass() + + s.y -> d.y + s.y -> p1.x + p1.y -> p2.x + p2.y -> d.x } diff --git a/test/TypeScript/src/DoubleInvocation.lf b/test/TypeScript/src/DoubleInvocation.lf index e9e7ec010c..26abd43bad 100644 --- a/test/TypeScript/src/DoubleInvocation.lf +++ b/test/TypeScript/src/DoubleInvocation.lf @@ -1,37 +1,38 @@ -// This illustrates a very strange bug that showed up -// and has now been fixed. This test ensures it does -// not reappear. -// At logical time zero, the two Print reactors used to be -// fired twice each at the same logical time. -// They should only be fired once. -// This behavior was oddly eliminated by either of the following -// actions, neither of which should affect this behavior: +// This illustrates a very strange bug that showed up and has now been fixed. +// This test ensures it does not reappear. At logical time zero, the two Print +// reactors used to be fired twice each at the same logical time. They should +// only be fired once. This behavior was oddly eliminated by either of the +// following actions, neither of which should affect this behavior: // * Removing the startup reaction in Print. // * Sending only position, not velocity from Ball. +target TypeScript { timeout: 5 sec, fast: true } -target TypeScript { - timeout: 5 sec, - fast: true -}; reactor Ball { - output position:number; - output velocity:number; - state p:number(200); - timer trigger(0, 1 sec); + output position: number + output velocity: number + + timer trigger(0, 1 sec) + + state p: number(200) + reaction(trigger) -> position, velocity {= position = p; velocity = -1; p -= 1; =} } + reactor Print { - input velocity:number; - input position:number; - state previous:number(-1); - reaction (startup) {= + input velocity: number + input position: number + + state previous: number(-1) + + reaction(startup) {= console.log("####### Print startup"); =} - reaction (position, velocity) {= + + reaction(position, velocity) {= if (position) { console.log("Position: " + position); } @@ -40,12 +41,14 @@ reactor Print { } =} } + main reactor DoubleInvocation { - b1 = new Ball(); - p = new Print(); - plot = new Print(); - b1.position -> p.position; - b1.velocity -> p.velocity; - b1.position -> plot.position; - b1.velocity -> plot.velocity; + b1 = new Ball() + p = new Print() + plot = new Print() + + b1.position -> p.position + b1.velocity -> p.velocity + b1.position -> plot.position + b1.velocity -> plot.velocity } diff --git a/test/TypeScript/src/DoubleReaction.lf b/test/TypeScript/src/DoubleReaction.lf index 970001a05b..01aa438c4e 100644 --- a/test/TypeScript/src/DoubleReaction.lf +++ b/test/TypeScript/src/DoubleReaction.lf @@ -1,14 +1,14 @@ -// Test that two simultaneous inputs that trigger a reaction -// trigger it only once. -// Correct output for this 2, 4, 6, 8, etc. -target TypeScript { - timeout: 10 sec, - fast: true -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:number; - timer t(offset, period); - state count:number(0); +// Test that two simultaneous inputs that trigger a reaction trigger it only +// once. Correct output for this 2, 4, 6, 8, etc. +target TypeScript { timeout: 10 sec, fast: true } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: number + + timer t(offset, period) + + state count: number(0) + reaction(t) -> y {= count++; y = count; @@ -16,9 +16,11 @@ reactor Clock(offset:time(0), period:time(1 sec)) { } reactor Destination { - input x:number; - input w:number; - state s:number(2); + input x: number + input w: number + + state s: number(2) + reaction(x, w) {= let sum = 0; if (x) { @@ -34,10 +36,12 @@ reactor Destination { s += 2; =} } + main reactor DoubleReaction { - c1 = new Clock(); - c2 = new Clock(); - d = new Destination(); - c1.y -> d.x; - c2.y -> d.w; + c1 = new Clock() + c2 = new Clock() + d = new Destination() + + c1.y -> d.x + c2.y -> d.w } diff --git a/test/TypeScript/src/DoubleTrigger.lf b/test/TypeScript/src/DoubleTrigger.lf index fe1f9c1d45..1bdbc45d01 100644 --- a/test/TypeScript/src/DoubleTrigger.lf +++ b/test/TypeScript/src/DoubleTrigger.lf @@ -1,19 +1,20 @@ -// Test that two simultaneous triggers don't cause -// a reaction to execute twice at the same tag. -target TypeScript { - fast: true, - timeout: 1 sec -}; +// Test that two simultaneous triggers don't cause a reaction to execute twice +// at the same tag. +target TypeScript { fast: true, timeout: 1 sec } + main reactor DoubleTrigger { - timer t1; - timer t2; - state s:number(0); + timer t1 + timer t2 + + state s: number(0) + reaction(t1, t2) {= s++; if (s > 1) { util.requestErrorStop("FAILURE: Reaction got triggered twice.") } =} + reaction(shutdown) {= if (s != 1) { util.reportError("FAILURE: Reaction was never triggered."); diff --git a/test/TypeScript/src/FloatLiteral.lf b/test/TypeScript/src/FloatLiteral.lf index 161529a105..1d3e688deb 100644 --- a/test/TypeScript/src/FloatLiteral.lf +++ b/test/TypeScript/src/FloatLiteral.lf @@ -1,11 +1,12 @@ -target TypeScript; -// This test verifies that floating-point literals are handled -// correctly. +target TypeScript + +// This test verifies that floating-point literals are handled correctly. main reactor { - state N:number(6.0221409e+23) - state charge:number(-1.6021766E-19) - state minus_epsilon:number(-.01e0) - state expected:number(.964853323188E5) + state N: number(6.0221409e+23) + state charge: number(-1.6021766E-19) + state minus_epsilon: number(-.01e0) + state expected: number(.964853323188E5) + reaction(startup) {= const F: number = - N * charge; if (Math.abs(F - expected) < Math.abs(minus_epsilon)) { diff --git a/test/TypeScript/src/Gain.lf b/test/TypeScript/src/Gain.lf index d646207d51..15aa662f7f 100644 --- a/test/TypeScript/src/Gain.lf +++ b/test/TypeScript/src/Gain.lf @@ -1,36 +1,41 @@ // Example in the Wiki. +target TypeScript - target TypeScript; - reactor Scale(scale:number(2)) { - input x:number; - output y:number; - reaction(x) -> y {= - y = (x as number) * scale; - =} - } - reactor Test { - input x:number; - state received_value:boolean(false); - reaction(x) {= - console.log("Received " + x + "."); - received_value = true; - if ((x as number) != 2) { - util.requestErrorStop("ERROR: Expected 2!"); - } - =} - reaction(shutdown) {= - if (!received_value){ - util.reportError("ERROR: No value received by Test reactor!"); - } else { - console.log("Test passes"); - } - =} - } - main reactor Gain { - g = new Scale(); - d = new Test(); - g.y -> d.x; - reaction(startup) -> g.x {= - g.x = 1; - =} - } +reactor Scale(scale: number(2)) { + input x: number + + output y: number + + reaction(x) -> y {= y = (x as number) * scale; =} +} + +reactor Test { + input x: number + + state received_value: boolean(false) + + reaction(x) {= + console.log("Received " + x + "."); + received_value = true; + if ((x as number) != 2) { + util.requestErrorStop("ERROR: Expected 2!"); + } + =} + + reaction(shutdown) {= + if (!received_value){ + util.reportError("ERROR: No value received by Test reactor!"); + } else { + console.log("Test passes"); + } + =} +} + +main reactor Gain { + g = new Scale() + d = new Test() + + g.y -> d.x + + reaction(startup) -> g.x {= g.x = 1; =} +} diff --git a/test/TypeScript/src/GetTime.lf b/test/TypeScript/src/GetTime.lf index b2d24fec3b..2fee5dfc20 100644 --- a/test/TypeScript/src/GetTime.lf +++ b/test/TypeScript/src/GetTime.lf @@ -1,12 +1,14 @@ -// This file includes code documented on the Wiki. -// For this test, success is just compiling and running. +// This file includes code documented on the Wiki. For this test, success is +// just compiling and running. target TypeScript { + // FIXME the C version of this test is fast, but in TS it's illegal to + // subtract TimeValues and get a negative result fast: true timeout: 2 sec -// FIXME the C version of this test is fast, but in TS it's illegal to subtract TimeValues and get a negative result -// fast: true -}; +} + main reactor GetTime { - timer t(0, 1 sec); + timer t(0, 1 sec) + reaction(t) {= let logical = util.getCurrentLogicalTime(); console.log("Logical time is " + logical); diff --git a/test/TypeScript/src/Hello.lf b/test/TypeScript/src/Hello.lf index bbd15d36a1..8ad00d431c 100644 --- a/test/TypeScript/src/Hello.lf +++ b/test/TypeScript/src/Hello.lf @@ -1,17 +1,18 @@ -// This test checks that logical time is incremented an appropriate -// amount as a result of an invocation of the schedule() function at -// runtime. It also performs various smoke tests of timing aligned -// reactions. The first instance has a period of 4 seconds, the second -// of 2 seconds, and the third (composite) or 1 second. -target TypeScript { - timeout: 10 sec, - fast: true -}; -reactor Reschedule(period:time(2 secs), message:string("Hello TypeScript")) { - state count:number(0); - state previous_time:time(0); - timer t(1 secs, period); - logical action a; +// This test checks that logical time is incremented an appropriate amount as a +// result of an invocation of the schedule() function at runtime. It also +// performs various smoke tests of timing aligned reactions. The first instance +// has a period of 4 seconds, the second of 2 seconds, and the third (composite) +// or 1 second. +target TypeScript { timeout: 10 sec, fast: true } + +reactor Reschedule(period: time(2 sec), message: string("Hello TypeScript")) { + timer t(1 sec, period) + + logical action a + + state count: number(0) + state previous_time: time(0) + reaction(t) -> a {= console.log(message); actions.a.schedule(TimeValue.msec(200), null); @@ -19,6 +20,7 @@ reactor Reschedule(period:time(2 secs), message:string("Hello TypeScript")) { previous_time = util.getCurrentLogicalTime(); console.log("Current time is " + previous_time); =} + reaction(a) {= count++; console.log("***** action " + count + " at time " + util.getCurrentLogicalTime()); @@ -33,11 +35,19 @@ reactor Reschedule(period:time(2 secs), message:string("Hello TypeScript")) { } =} } -reactor Inside(period:time(1 sec), message:string("Composite default message.")) { - third_instance = new Reschedule(period = period, message = message); + +reactor Inside( + period: time(1 sec), + message: string("Composite default message.") +) { + third_instance = new Reschedule(period = period, message = message) } + main reactor Hello { - first_instance = new Reschedule(period = 4 sec, message = "Hello from first_instance."); - second_instance = new Reschedule(message = "Hello from second_instance."); - composite_instance = new Inside(message = "Hello from composite_instance."); + first_instance = new Reschedule( + period = 4 sec, + message = "Hello from first_instance." + ) + second_instance = new Reschedule(message = "Hello from second_instance.") + composite_instance = new Inside(message = "Hello from composite_instance.") } diff --git a/test/TypeScript/src/HelloWorld.lf b/test/TypeScript/src/HelloWorld.lf index 2959362396..85d560e3a7 100644 --- a/test/TypeScript/src/HelloWorld.lf +++ b/test/TypeScript/src/HelloWorld.lf @@ -1,10 +1,11 @@ -target TypeScript; +target TypeScript + reactor HelloWorldInside { - timer t; - reaction(t) {= - console.log("Hello World."); - =} + timer t + + reaction(t) {= console.log("Hello World."); =} } + main reactor HelloWorld { - a = new HelloWorldInside(); + a = new HelloWorldInside() } diff --git a/test/TypeScript/src/Hierarchy.lf b/test/TypeScript/src/Hierarchy.lf index 7af676436e..53c0af560d 100644 --- a/test/TypeScript/src/Hierarchy.lf +++ b/test/TypeScript/src/Hierarchy.lf @@ -1,23 +1,31 @@ // Test data transport across hierarchy. -target TypeScript; +target TypeScript + reactor Source { - output out:number; - timer t; + output out: number + + timer t + reaction(t) -> out {= console.log("Producing from source"); out = 1; =} } + reactor Gain { - input x:number; - output out:number; + input x: number + + output out: number + reaction(x) -> out {= console.log("Gain received " + x); out = (x as number) * 2; =} } + reactor Print { - input x:number; + input x: number + reaction(x) {= x = x as number; console.log("Received: " + x); @@ -26,21 +34,27 @@ reactor Print { } =} } + reactor GainContainer { - input x:number; - output out:number; - output out2:number; - gain = new Gain(); - x -> gain.x; - gain.out -> out; - gain.out -> out2; + input x: number + + output out: number + output out2: number + + gain = new Gain() + + x -> gain.x + gain.out -> out + gain.out -> out2 } + main reactor Hierarchy { - source = new Source(); - container = new GainContainer(); - print = new Print(); - print2 = new Print(); - source.out -> container.x; - container.out -> print.x; - container.out -> print2.x; + source = new Source() + container = new GainContainer() + print = new Print() + print2 = new Print() + + source.out -> container.x + container.out -> print.x + container.out -> print2.x } diff --git a/test/TypeScript/src/Hierarchy2.lf b/test/TypeScript/src/Hierarchy2.lf index 9abd0016d1..2c6052a685 100644 --- a/test/TypeScript/src/Hierarchy2.lf +++ b/test/TypeScript/src/Hierarchy2.lf @@ -1,28 +1,33 @@ // Test data transport across hierarchy. -target TypeScript { - timeout: 5 sec, - fast: true -}; +target TypeScript { timeout: 5 sec, fast: true } + reactor Source { - output out:number; - timer t(0, 1 sec); - reaction(t) -> out {= - out = 1; - =} + output out: number + + timer t(0, 1 sec) + + reaction(t) -> out {= out = 1; =} } + reactor Count { - output out:number; - timer t(0, 1 sec); - state i:number(0); + output out: number + + timer t(0, 1 sec) + + state i: number(0) + reaction(t) -> out {= i++; out = i; =} } + reactor Add { - input in1:number; - input in2:number; - output out:number; + input in1: number + input in2: number + + output out: number + reaction(in1, in2) -> out {= let result = 0; if (in1) result += in1; @@ -30,9 +35,12 @@ reactor Add { out = result; =} } + reactor Print { - input x:number; - state expected:number(2); + input x: number + + state expected: number(2) + reaction(x) {= x = x as number; if (x != expected) { @@ -41,19 +49,25 @@ reactor Print { expected++; =} } + reactor AddCount { - input x:number; - output out:number; - count = new Count(); - add = new Add(); - x -> add.in1; - count.out -> add.in2; - add.out -> out; + input x: number + + output out: number + + count = new Count() + add = new Add() + + x -> add.in1 + count.out -> add.in2 + add.out -> out } + main reactor Hierarchy2 { - source = new Source(); - addCount = new AddCount(); - print = new Print(); - source.out -> addCount.x; - addCount.out -> print.x; + source = new Source() + addCount = new AddCount() + print = new Print() + + source.out -> addCount.x + addCount.out -> print.x } diff --git a/test/TypeScript/src/Import.lf b/test/TypeScript/src/Import.lf index 858239ba56..4810c2d4ab 100644 --- a/test/TypeScript/src/Import.lf +++ b/test/TypeScript/src/Import.lf @@ -1,13 +1,13 @@ -// This tests the ability to import a reactor definition -// that itself imports a reactor definition. -target TypeScript{ - timeout : 2 sec -}; -import Imported from "lib/Imported.lf"; +// This tests the ability to import a reactor definition that itself imports a +// reactor definition. +target TypeScript { timeout: 2 sec } + +import Imported from "lib/Imported.lf" + main reactor Import { - timer t; - a = new Imported(); - reaction(t) -> a.x {= - a.x = 42; - =} + timer t + + a = new Imported() + + reaction(t) -> a.x {= a.x = 42; =} } diff --git a/test/TypeScript/src/Microsteps.lf b/test/TypeScript/src/Microsteps.lf index fda8da8424..ff4c8e40c7 100644 --- a/test/TypeScript/src/Microsteps.lf +++ b/test/TypeScript/src/Microsteps.lf @@ -1,7 +1,9 @@ -target TypeScript; +target TypeScript + reactor Destination { - input x:number; - input y:number; + input x: number + input y: number + reaction(x, y) {= let elapsed = util.getElapsedLogicalTime(); console.log("Time since start: " + elapsed); @@ -22,15 +24,18 @@ reactor Destination { } =} } + main reactor Microsteps { - timer start; - logical action repeat; - d = new Destination(); + timer start + + logical action repeat + + d = new Destination() + reaction(start) -> d.x, repeat {= d.x = 1; actions.repeat.schedule(0, null); =} - reaction(repeat) -> d.y {= - d.y = 1; - =} + + reaction(repeat) -> d.y {= d.y = 1; =} } diff --git a/test/TypeScript/src/Minimal.lf b/test/TypeScript/src/Minimal.lf index cf11d685c1..737ec70336 100644 --- a/test/TypeScript/src/Minimal.lf +++ b/test/TypeScript/src/Minimal.lf @@ -1,8 +1,8 @@ // This is a smoke test of a minimal reactor. -target TypeScript; +target TypeScript + main reactor Minimal { - timer t; - reaction(t) {= - console.log("Hello World."); - =} + timer t + + reaction(t) {= console.log("Hello World."); =} } diff --git a/test/TypeScript/src/MovingAverage.lf b/test/TypeScript/src/MovingAverage.lf index cfab964927..6019e9a667 100644 --- a/test/TypeScript/src/MovingAverage.lf +++ b/test/TypeScript/src/MovingAverage.lf @@ -1,25 +1,29 @@ -// Demonstration of a state variable that is an array. -// The MovingAverage reactor computes the moving average of the last -// four inputs and produces that as output. The source is a counting -// sequence. -target TypeScript { - timeout: 1 sec, - fast: true -}; +// Demonstration of a state variable that is an array. The MovingAverage reactor +// computes the moving average of the last four inputs and produces that as +// output. The source is a counting sequence. +target TypeScript { timeout: 1 sec, fast: true } + reactor Source { - output out:number; - state count:number(0); - timer clock(0, 200 msec); + output out: number + + timer clock(0, 200 msec) + + state count: number(0) + reaction(clock) -> out {= out = count; count++; =} } + reactor MovingAverageImpl { - state delay_line:{=Array=}({= [0.0, 0.0, 0.0] =}); - state index:number(0); - input x:number; - output out:number; + input x: number + + output out: number + + state delay_line: {= Array =}({= [0.0, 0.0, 0.0] =}) + state index: number(0) + reaction(x) -> out {= x = x as number; // Calculate the output. @@ -39,9 +43,12 @@ reactor MovingAverageImpl { } =} } + reactor Print { - input x:number; - state count:number(0); + input x: number + + state count: number(0) + reaction(x) {= x = x as number; console.log("Received: " + x); @@ -52,10 +59,12 @@ reactor Print { count++; =} } + main reactor MovingAverage { - s = new Source(); - m = new MovingAverageImpl(); - p = new Print(); - s.out -> m.x; - m.out -> p.x; + s = new Source() + m = new MovingAverageImpl() + p = new Print() + + s.out -> m.x + m.out -> p.x } diff --git a/test/TypeScript/src/MultipleContained.lf b/test/TypeScript/src/MultipleContained.lf index 4bdf56fe3f..c9bd2fae09 100644 --- a/test/TypeScript/src/MultipleContained.lf +++ b/test/TypeScript/src/MultipleContained.lf @@ -1,13 +1,15 @@ -// Test that a reaction can react to and send two multiple -// ports of a contained reactor. -target TypeScript; +// Test that a reaction can react to and send two multiple ports of a contained +// reactor. +target TypeScript + reactor Contained { - output trigger:number; - input in1:number; - input in2:number; - reaction(startup) -> trigger {= - trigger = 42; - =} + input in1: number + input in2: number + + output trigger: number + + reaction(startup) -> trigger {= trigger = 42; =} + reaction(in1) {= in1 = in1 as number; console.log("in1 received " + in1); @@ -15,6 +17,7 @@ reactor Contained { util.requestErrorStop("FAILED: Expected 42.") } =} + reaction(in2) {= in2 = in2 as number; console.log("in2 received " + in2); @@ -23,8 +26,10 @@ reactor Contained { } =} } + main reactor MultipleContained { - c = new Contained(); + c = new Contained() + reaction(c.trigger) -> c.in1, c.in2 {= c.trigger = c.trigger as number; c.in1 = c.trigger; diff --git a/test/TypeScript/src/NativeListsAndTimes.lf b/test/TypeScript/src/NativeListsAndTimes.lf index 5e27a379b7..093289f7ff 100644 --- a/test/TypeScript/src/NativeListsAndTimes.lf +++ b/test/TypeScript/src/NativeListsAndTimes.lf @@ -1,24 +1,27 @@ -target TypeScript; +target TypeScript + // This test passes if it is successfully compiled into valid target code. -main reactor (x:number(0), - y:time(0), // Units are missing but not required - z(1 msec), // Type is missing but not required - p:number[](1, 2, 3, 4), // List of integers - q:TimeValue[](1 msec, 2 msec, 3 msec), // list of time values - r:time({=0=}), // Zero-valued target code also is a valid time - g:time[](1 msec, 2 msec) // List of time values - ) { - state s:time(y); // Reference to explicitly typed time parameter - state t:time(z); // Reference to implicitly typed time parameter - state v:boolean; // Uninitialized boolean state variable - state w:time; // Uninitialized time state variable - timer tick(0); // Units missing but not required - timer tock(1 sec); // Implicit type time - timer toe(z); // Implicit type time - state baz(p); // Implicit type int[] - state period(z); // Implicit type time +main reactor( + x: number(0), + y: time(0), // Units are missing but not required + z(1 msec), // Type is missing but not required + p: number[](1, 2, 3, 4), // List of integers + q: TimeValue[](1 msec, 2 msec, 3 msec), // list of time values + r: time({= 0 =}), // Zero-valued target code also is a valid time + g: time[](1 msec, 2 msec) // List of time values +) { + timer tick(0) // Units missing but not required + timer tock(1 sec) // Implicit type time + timer toe(z) // Implicit type time + + state s: time(y) // Reference to explicitly typed time parameter + state t: time(z) // Reference to implicitly typed time parameter + state v: boolean // Uninitialized boolean state variable + state w: time // Uninitialized time state variable + state baz(p) // Implicit type int[] + state period(z) // Implicit type time + reaction(tick) {= // Target code =} - } diff --git a/test/TypeScript/src/ParameterizedState.lf b/test/TypeScript/src/ParameterizedState.lf index 81a9bad4b6..d2ea34da12 100644 --- a/test/TypeScript/src/ParameterizedState.lf +++ b/test/TypeScript/src/ParameterizedState.lf @@ -1,11 +1,11 @@ -target TypeScript; +target TypeScript -reactor Foo(bar:number(42)) { - state baz(bar); - reaction (startup) {= - console.log("Baz: " + baz); - =} +reactor Foo(bar: number(42)) { + state baz(bar) + + reaction(startup) {= console.log("Baz: " + baz); =} } + main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/TypeScript/src/PeriodicDesugared.lf b/test/TypeScript/src/PeriodicDesugared.lf index 97b7e0df58..633aae4b7f 100644 --- a/test/TypeScript/src/PeriodicDesugared.lf +++ b/test/TypeScript/src/PeriodicDesugared.lf @@ -1,10 +1,10 @@ -target TypeScript; -main reactor ( - offset:time(0), - period:time(500 msec)) { - logical action init(offset); - logical action recur(period); - state count:number(0); +target TypeScript + +main reactor(offset: time(0), period: time(500 msec)) { + logical action init(offset) + logical action recur(period) + + state count: number(0) reaction(startup) -> init, recur {= if (offset.isZero()) { diff --git a/test/TypeScript/src/Preamble.lf b/test/TypeScript/src/Preamble.lf index a398ab0e29..96a0a18364 100644 --- a/test/TypeScript/src/Preamble.lf +++ b/test/TypeScript/src/Preamble.lf @@ -1,13 +1,14 @@ -target TypeScript{ - timeout : 2 sec -}; +target TypeScript { timeout: 2 sec } + main reactor Preamble { preamble {= function add42( i:number) { return i + 42; } =} - timer t; + + timer t + reaction(t) {= let s = "42"; let radix = 10; diff --git a/test/TypeScript/src/ReadOutputOfContainedReactor.lf b/test/TypeScript/src/ReadOutputOfContainedReactor.lf index 80a6b4311e..ea3f25fd44 100644 --- a/test/TypeScript/src/ReadOutputOfContainedReactor.lf +++ b/test/TypeScript/src/ReadOutputOfContainedReactor.lf @@ -1,15 +1,18 @@ -// Test reacting to and reading outputs from a contained -// reactor in various permutations. -target TypeScript; +// Test reacting to and reading outputs from a contained reactor in various +// permutations. +target TypeScript + reactor Contained { - output out:number; - reaction(startup) -> out {= - out = 42; - =} + output out: number + + reaction(startup) -> out {= out = 42; =} } + main reactor ReadOutputOfContainedReactor { - c = new Contained(); - state count:number(0); + c = new Contained() + + state count: number(0) + reaction(startup) c.out {= console.log("Startup reaction reading output of contained reactor: " + c.out); if (c.out != 42) { @@ -17,6 +20,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(c.out) {= console.log("Reading output of contained reactor: " + c.out); if (c.out != 42) { @@ -24,6 +28,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(startup, c.out) {= console.log("Alternate triggering reading output of contained reactor: " + c.out); if (c.out != 42) { @@ -31,6 +36,7 @@ main reactor ReadOutputOfContainedReactor { } count++; =} + reaction(shutdown) {= if (count != 3) { console.log("Count is: " + count) diff --git a/test/TypeScript/src/Schedule.lf b/test/TypeScript/src/Schedule.lf index 010a163313..d313bbecb5 100644 --- a/test/TypeScript/src/Schedule.lf +++ b/test/TypeScript/src/Schedule.lf @@ -1,11 +1,14 @@ -// TypeScript translated example from Schedule section of the C Reactor Target wiki page. -target TypeScript; +// TypeScript translated example from Schedule section of the C Reactor Target +// wiki page. +target TypeScript + reactor ScheduleLogicalAction { - input x:number; - logical action a; - reaction(x) -> a {= - actions.a.schedule(TimeValue.msec(200), null) - =} + input x: number + + logical action a + + reaction(x) -> a {= actions.a.schedule(TimeValue.msec(200), null) =} + reaction(a) {= let elapsedTime = util.getElapsedLogicalTime(); console.log("Action triggered at logical time " + elapsedTime + " (sec, nsec) after start."); @@ -16,10 +19,11 @@ reactor ScheduleLogicalAction { } =} } + main reactor { - a = new ScheduleLogicalAction(); - timer t; - reaction(t) -> a.x {= - a.x = 1; - =} + timer t + + a = new ScheduleLogicalAction() + + reaction(t) -> a.x {= a.x = 1; =} } diff --git a/test/TypeScript/src/ScheduleLogicalAction.lf b/test/TypeScript/src/ScheduleLogicalAction.lf index c6351deeb0..672ffcf539 100644 --- a/test/TypeScript/src/ScheduleLogicalAction.lf +++ b/test/TypeScript/src/ScheduleLogicalAction.lf @@ -1,26 +1,29 @@ -// This checks that a logical action is scheduled the specified -// logical time after the current logical time. -target TypeScript { - fast: true, - timeout: 3 sec -}; +// This checks that a logical action is scheduled the specified logical time +// after the current logical time. +target TypeScript { fast: true, timeout: 3 sec } + reactor foo { - input x:number; - output y:number; - logical action a; + input x: number + + output y: number + + logical action a + reaction(x) -> y, a {= x = x as number; y = 2 * x; // The following uses physical time, incorrectly. actions.a.schedule(TimeValue.msec(500), null); =} - reaction(a) -> y {= - y = -42; - =} + + reaction(a) -> y {= y = -42; =} } + reactor print { - state expected_time:time(0); - input x:number; + input x: number + + state expected_time: time(0) + reaction(x) {= let elapsed_time = util.getElapsedLogicalTime(); console.log("Result is " + x); @@ -32,12 +35,14 @@ reactor print { expected_time = expected_time.add(TimeValue.msec(500)); =} } + main reactor { - f = new foo(); - p = new print(); - timer t(0, 1 sec); - reaction(t) -> f.x {= - f.x = 42; - =} - f.y -> p.x; + timer t(0, 1 sec) + + f = new foo() + p = new print() + + f.y -> p.x + + reaction(t) -> f.x {= f.x = 42; =} } diff --git a/test/TypeScript/src/SendingInside.lf b/test/TypeScript/src/SendingInside.lf index 5ddb809d6c..f71d4dcd50 100644 --- a/test/TypeScript/src/SendingInside.lf +++ b/test/TypeScript/src/SendingInside.lf @@ -1,13 +1,12 @@ -// This tests a reactor that contains another reactor and also -// has its own reaction that routes inputs to the contained reactor. +// This tests a reactor that contains another reactor and also has its own +// reaction that routes inputs to the contained reactor. +target TypeScript { timeout: 10 sec, fast: true } -target TypeScript{ - timeout : 10 sec, - fast: true -}; reactor Printer { - input x:number; - state count:number(1); + input x: number + + state count: number(1) + reaction(x) {= console.log("Inside reactor received: " + x); if ((x as number) != count) { @@ -16,10 +15,14 @@ reactor Printer { count++; =} } + main reactor SendingInside { - state count:number(0); - timer t(0, 1 sec); - p = new Printer(); + timer t(0, 1 sec) + + p = new Printer() + + state count: number(0) + reaction(t) -> p.x {= count++; p.x = count; diff --git a/test/TypeScript/src/SendingInside2.lf b/test/TypeScript/src/SendingInside2.lf index e8075b6ecc..de2abee8b4 100644 --- a/test/TypeScript/src/SendingInside2.lf +++ b/test/TypeScript/src/SendingInside2.lf @@ -1,6 +1,8 @@ -target TypeScript; +target TypeScript + reactor Printer { - input x:number; + input x: number + reaction(x) {= console.log("Inside reactor received:" + x ); if (x != 1) { @@ -8,10 +10,11 @@ reactor Printer { } =} } + main reactor SendingInside2 { - timer t; - p = new Printer(); - reaction(t) -> p.x {= - p.x = 1; - =} + timer t + + p = new Printer() + + reaction(t) -> p.x {= p.x = 1; =} } diff --git a/test/TypeScript/src/SendsPointerTest.lf b/test/TypeScript/src/SendsPointerTest.lf index 1582f37919..bf4f418f04 100644 --- a/test/TypeScript/src/SendsPointerTest.lf +++ b/test/TypeScript/src/SendsPointerTest.lf @@ -1,16 +1,20 @@ -// Source produces a dynamically allocated object, which it passes -// to Print. Reference counting ensures that the struct is freed. -target TypeScript; -reactor SendsPointer { - output out:{= {value: number} =}; +// Source produces a dynamically allocated object, which it passes to Print. +// Reference counting ensures that the struct is freed. +target TypeScript + +reactor SendsPointer { + output out: {= {value: number} =} + reaction(startup) -> out {= let my_object = { value: 42 }; out = my_object; =} } + // expected parameter is for testing. -reactor Print(expected:{= {value: number} =}({={ value: 42 }=})) { - input x:{= {value: number} =}; +reactor Print(expected: {= {value: number} =}({= { value: 42 } =})) { + input x: {= {value: number} =} + reaction(x) {= x = x as {value: number}; console.log("Received: " + JSON.stringify(x)); @@ -19,8 +23,10 @@ reactor Print(expected:{= {value: number} =}({={ value: 42 }=})) { } =} } + main reactor SendsPointerTest { - s = new SendsPointer(); - p = new Print(); - s.out -> p.x; + s = new SendsPointer() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/SimpleDeadline.lf b/test/TypeScript/src/SimpleDeadline.lf index 53b987fa2a..6791e5b478 100644 --- a/test/TypeScript/src/SimpleDeadline.lf +++ b/test/TypeScript/src/SimpleDeadline.lf @@ -1,30 +1,41 @@ // Test local deadline, where a deadline is associated with a reaction -// definition. This test triggers a reaction exactly once with a -// deadline violation. -target TypeScript; -reactor Deadline(threshold:time(100 msec)) { - input x:number; - output deadlineViolation:boolean; +// definition. This test triggers a reaction exactly once with a deadline +// violation. +target TypeScript + +reactor Deadline(threshold: time(100 msec)) { + input x: number + + output deadlineViolation: boolean + reaction(x) -> deadlineViolation {= util.requestErrorStop("ERROR: Deadline violation was not detected!") - =} deadline(threshold) {= + =} deadline( + threshold + ) {= console.log("Deadline violation detected."); deadlineViolation = true; =} } + reactor Print { - input x:boolean; + input x: boolean + reaction(x) {= if (x) { console.log("Output successfully produced by deadline handler."); } =} } + main reactor SimpleDeadline { - timer start; - d = new Deadline(threshold = 10 msec); - p = new Print(); - d.deadlineViolation -> p.x; + timer start + + d = new Deadline(threshold = 10 msec) + p = new Print() + + d.deadlineViolation -> p.x + reaction(start) -> d.x {= let sleep_time = TimeValue.msec(20); let startTime = util.getCurrentPhysicalTime(); diff --git a/test/TypeScript/src/SimpleImport.lf b/test/TypeScript/src/SimpleImport.lf index 48afaddace..364c2f2ab3 100644 --- a/test/TypeScript/src/SimpleImport.lf +++ b/test/TypeScript/src/SimpleImport.lf @@ -1,7 +1,8 @@ -target TypeScript; -import HelloWorldInside from "HelloWorld.lf"; +target TypeScript + +import HelloWorldInside from "HelloWorld.lf" main reactor SimpleImport { - a = new HelloWorldInside(); - b = new HelloWorldInside(); + a = new HelloWorldInside() + b = new HelloWorldInside() } diff --git a/test/TypeScript/src/SlowingClock.lf b/test/TypeScript/src/SlowingClock.lf index 3d88749bb1..d566995756 100644 --- a/test/TypeScript/src/SlowingClock.lf +++ b/test/TypeScript/src/SlowingClock.lf @@ -1,14 +1,13 @@ -target TypeScript { - timeout: 5 sec, - fast: true -}; +target TypeScript { timeout: 5 sec, fast: true } + main reactor SlowingClock { - logical action a(100 msec); - state interval:time(100 msec); - state expected_time:time(100 msec); - reaction(startup) -> a {= - actions.a.schedule(0, null); - =} + logical action a(100 msec) + + state interval: time(100 msec) + state expected_time: time(100 msec) + + reaction(startup) -> a {= actions.a.schedule(0, null); =} + reaction(a) -> a {= let elapsed_logical_time : TimeValue = util.getElapsedLogicalTime(); console.log("Logical time since start: " + elapsed_logical_time); @@ -20,6 +19,7 @@ main reactor SlowingClock { expected_time = expected_time.add(interval); interval = interval.add(TimeValue.msec(100)); =} + reaction(shutdown) {= if (!expected_time.isEqualTo(TimeValue.msec(5500))) { util.requestErrorStop("ERROR: Expected the next expected time to be: " + TimeValue.msec(5500) + "It was: " + expected_time) diff --git a/test/TypeScript/src/SlowingClockPhysical.lf b/test/TypeScript/src/SlowingClockPhysical.lf index 234944f7ec..1d87059d87 100644 --- a/test/TypeScript/src/SlowingClockPhysical.lf +++ b/test/TypeScript/src/SlowingClockPhysical.lf @@ -1,25 +1,26 @@ -/** Output events at physical times at least 100, 300, and 600 - * msec after the start time. - * This uses a physical action with a minimum interarrival time of - * 100 msec. The reactor increases the interarrival time with each - * invocation of the schedule() function. - * The timestamps of the events will be exact because the physical - * time at which schedule() is called is always way smaller than - * the time of the last invocation (or start time) plus the minimum - * interarrival time. Hence, the minimum interarrival time always - * determines the time of the next event. +/** + * Output events at physical times at least 100, 300, and 600 msec after the + * start time. This uses a physical action with a minimum interarrival time of + * 100 msec. The reactor increases the interarrival time with each invocation of + * the schedule() function. The timestamps of the events will be exact because + * the physical time at which schedule() is called is always way smaller than + * the time of the last invocation (or start time) plus the minimum interarrival + * time. Hence, the minimum interarrival time always determines the time of the + * next event. */ -target TypeScript { - timeout: 1 sec -}; +target TypeScript { timeout: 1 sec } + main reactor SlowingClockPhysical { - physical action a(100 msec); - state interval:time(100 msec); - state expected_time:time(100 msec); + physical action a(100 msec) + + state interval: time(100 msec) + state expected_time: time(100 msec) + reaction(startup) -> a {= expected_time = TimeValue.msec(100); actions.a.schedule(0, null); =} + reaction(a) -> a {= let elapsed_logical_time = util.getElapsedLogicalTime(); console.log("Logical time since start: " + elapsed_logical_time); @@ -30,6 +31,7 @@ main reactor SlowingClockPhysical { expected_time = (TimeValue.msec(100)).add(interval); actions.a.schedule(interval, null); =} + reaction(shutdown) {= if (expected_time.isEarlierThan(TimeValue.msec(500))) { util.requestErrorStop("ERROR: Expected the next expected time to be at least: 500 msec. It was: " + expected_time) diff --git a/test/TypeScript/src/Stride.lf b/test/TypeScript/src/Stride.lf index 2a4840e898..5c3c6c4797 100644 --- a/test/TypeScript/src/Stride.lf +++ b/test/TypeScript/src/Stride.lf @@ -1,26 +1,29 @@ -// This example illustrates state variables and parameters on the wiki. -// For this test, success is just compiling and running. -target TypeScript{ - timeout: 2 sec, - fast: true -}; -reactor Count(stride:number(1)) { - state count:number(0); - output y:number; - timer t(0, 100 msec); +// This example illustrates state variables and parameters on the wiki. For this +// test, success is just compiling and running. +target TypeScript { timeout: 2 sec, fast: true } + +reactor Count(stride: number(1)) { + output y: number + + timer t(0, 100 msec) + + state count: number(0) + reaction(t) -> y {= y = count; count = count + stride; =} } + reactor Display { - input x:number; - reaction(x) {= - console.log("Received: " + x); - =} + input x: number + + reaction(x) {= console.log("Received: " + x); =} } + main reactor Stride { - c = new Count(stride = 2); - d = new Display(); - c.y -> d.x; + c = new Count(stride = 2) + d = new Display() + + c.y -> d.x } diff --git a/test/TypeScript/src/StructAsState.lf b/test/TypeScript/src/StructAsState.lf index da823f5fef..9ad77f33c0 100644 --- a/test/TypeScript/src/StructAsState.lf +++ b/test/TypeScript/src/StructAsState.lf @@ -2,16 +2,13 @@ target TypeScript; main reactor StructAsState { preamble {= - type hello_t = { + type hello_t = { name: string ; value: number; - } + }; =} state s:hello_t({= {name: "Earth", value: 42}=}); reaction(startup) {= - console.log("State s.name=" + s.name + ", s.value=" + s.value); - if (s.value != 42) { - util.requestErrorStop("FAILED: Expected 42."); - } + console.log("State s.name=" + s.name + ", s.value=" + s.value) =} } diff --git a/test/TypeScript/src/StructAsType.lf b/test/TypeScript/src/StructAsType.lf index 055b92d6ba..a46f1ef623 100644 --- a/test/TypeScript/src/StructAsType.lf +++ b/test/TypeScript/src/StructAsType.lf @@ -1,14 +1,16 @@ -// Source produces a struct directly, rather than a pointer to -// a struct. -target TypeScript; +// Source produces a struct directly, rather than a pointer to a struct. +target TypeScript + reactor Source { preamble {= type hello_t = { name: string ; value: number; - } + }; =} - output out:hello_t; + + output out: hello_t + reaction(startup) -> out {= // Create the struct on the stack and then copy // it to the output as follows: @@ -16,9 +18,10 @@ reactor Source { out = temp; =} } -// expected parameter is for testing. -reactor Print(expected:number(42)) { - input x:hello_t; + +reactor Print(expected: number(42)) { // expected parameter is for testing. + input x: hello_t + reaction(x) {= x = x as hello_t; console.log("Received: name = " + x.name + ", value = " + x.value); @@ -27,8 +30,10 @@ reactor Print(expected:number(42)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.x; + s = new Source() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/StructAsTypeDirect.lf b/test/TypeScript/src/StructAsTypeDirect.lf index 3ff45ded04..d777d6f4a4 100644 --- a/test/TypeScript/src/StructAsTypeDirect.lf +++ b/test/TypeScript/src/StructAsTypeDirect.lf @@ -1,14 +1,16 @@ -// Source produces a struct directly, rather than a pointer to -// a struct. -target TypeScript; +// Source produces a struct directly, rather than a pointer to a struct. +target TypeScript + reactor Source { -preamble {= + preamble {= type hello_t = { name: string ; value: number; - } + }; =} - output out:hello_t; + + output out: hello_t + reaction(startup) -> out {= let temp: hello_t = {name: "", value: 0}; temp.name = "Earth"; @@ -16,9 +18,10 @@ preamble {= out = temp; =} } -// expected parameter is for testing. -reactor Print(expected:number(42)) { - input x:hello_t; + +reactor Print(expected: number(42)) { // expected parameter is for testing. + input x: hello_t + reaction(x) {= x = x as hello_t; console.log("Received: name = " + x.name + ", value = " + x.value); @@ -27,8 +30,10 @@ reactor Print(expected:number(42)) { } =} } + main reactor { - s = new Source(); - p = new Print(); - s.out -> p.x; + s = new Source() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/StructPrint.lf b/test/TypeScript/src/StructPrint.lf index e22597da88..ec7051f58a 100644 --- a/test/TypeScript/src/StructPrint.lf +++ b/test/TypeScript/src/StructPrint.lf @@ -1,22 +1,26 @@ -// Source produces a dynamically allocated struct, which it passes -// to Print. Reference counting ensures that the struct is freed. -target TypeScript; +// Source produces a dynamically allocated struct, which it passes to Print. +// Reference counting ensures that the struct is freed. +target TypeScript + reactor Source { preamble {= type hello_t = { name: string ; value: number; - } + }; =} - output out:hello_t; + + output out: hello_t + reaction(startup) -> out {= let temp: hello_t = {name: "Earth", value: 42} out = temp; =} } -// expected parameter is for testing. -reactor Print(expected:number(42)) { - input x:hello_t; + +reactor Print(expected: number(42)) { // expected parameter is for testing. + input x: hello_t + reaction(x) {= x = x as hello_t; console.log("Received: name = " + x.name + ", value = " + x.value); @@ -25,8 +29,10 @@ reactor Print(expected:number(42)) { } =} } + main reactor StructPrint { - s = new Source(); - p = new Print(); - s.out -> p.x; + s = new Source() + p = new Print() + + s.out -> p.x } diff --git a/test/TypeScript/src/StructScale.lf b/test/TypeScript/src/StructScale.lf index d5614239c8..7ddfc118ce 100644 --- a/test/TypeScript/src/StructScale.lf +++ b/test/TypeScript/src/StructScale.lf @@ -1,25 +1,30 @@ -// Source produces a dynamically allocated struct, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original struct. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target TypeScript; -import Print, Source from "StructPrint.lf"; +// Source produces a dynamically allocated struct, which it passes to Scale. +// Scale requests a writable copy, which, instead of copying, it just gets +// ownership of the original struct. It modifies it and passes it to Print. It +// gets freed after Print is done with it. +target TypeScript + +import Print, Source from "StructPrint.lf" + +reactor Scale(scale: number(2)) { + // Mutable keyword indicates that this reactor wants a writable copy of the + // input. + mutable input x: hello_t + + output out: hello_t -reactor Scale(scale:number(2)) { - // Mutable keyword indicates that this reactor wants a writable copy of the input. - mutable input x:hello_t; - output out:hello_t; reaction(x) -> out {= x = x as hello_t x.value *= scale; out = x; =} } + main reactor StructScale { - s = new Source(); - c = new Scale(); - p = new Print(expected=84); - s.out -> c.x; - c.out -> p.x; + s = new Source() + c = new Scale() + p = new Print(expected = 84) + + s.out -> c.x + c.out -> p.x } diff --git a/test/TypeScript/src/TestForPreviousOutput.lf b/test/TypeScript/src/TestForPreviousOutput.lf index 33ecdd3675..9a949ff586 100644 --- a/test/TypeScript/src/TestForPreviousOutput.lf +++ b/test/TypeScript/src/TestForPreviousOutput.lf @@ -1,8 +1,10 @@ -// This tests the mechanism for testing whether a previous reaction has -// produced a given output. The output should always be 42. -target TypeScript; +// This tests the mechanism for testing whether a previous reaction has produced +// a given output. The output should always be 42. +target TypeScript + reactor Source { - output out:number; + output out: number + reaction(startup) -> out {= // Note: Math.random can't be seeded // Randomly produce an output or not. @@ -10,6 +12,7 @@ reactor Source { out = 21; } =} + reaction(startup) -> out {= let previous_output = out; if (previous_output) { @@ -19,8 +22,10 @@ reactor Source { } =} } + reactor Sink { - input x:number; + input x: number + reaction(x) {= x = x as number; console.log("Received " + x); @@ -29,8 +34,10 @@ reactor Sink { } =} } + main reactor TestForPreviousOutput { - s = new Source(); - d = new Sink(); - s.out -> d.x; + s = new Source() + d = new Sink() + + s.out -> d.x } diff --git a/test/TypeScript/src/TimeLimit.lf b/test/TypeScript/src/TimeLimit.lf index 7a0bdac0f2..52b2449f8d 100644 --- a/test/TypeScript/src/TimeLimit.lf +++ b/test/TypeScript/src/TimeLimit.lf @@ -1,25 +1,27 @@ -// Test that the stop function can be used to internally impose a -// a time limit. +// Test that the stop function can be used to internally impose a a time limit. // This is also used to test performance (number of reactions per second). -// Correct output for this 1, 2, 3, 4. -// Failure for this test is failing to halt or getting the wrong data. - -target TypeScript { - fast: true, - logging: INFO -}; -reactor Clock(offset:time(0), period:time(1 sec)) { - output y:number; - timer t(offset, period); - state count:number(0); +// Correct output for this 1, 2, 3, 4. Failure for this test is failing to halt +// or getting the wrong data. +target TypeScript { fast: true, logging: INFO } + +reactor Clock(offset: time(0), period: time(1 sec)) { + output y: number + + timer t(offset, period) + + state count: number(0) + reaction(t) -> y {= count++; y = count; =} } + reactor Destination { - input x:number; - state s:number(1); + input x: number + + state s: number(1) + reaction(x) {= if (x != s) { util.requestErrorStop("Error: Expected " + s + " and got " + x + ".") @@ -28,13 +30,13 @@ reactor Destination { =} } -main reactor TimeLimit(period:time(1 msec)) { // usecs take a little too long - timer stop(10 secs); - reaction(stop) {= - util.requestStop() - =} +main reactor TimeLimit(period: time(1 msec)) { // usecs take a little too long + timer stop(10 sec) + + c = new Clock(period = period) + d = new Destination() + + c.y -> d.x - c = new Clock(period = period); - d = new Destination(); - c.y -> d.x; + reaction(stop) {= util.requestStop() =} } diff --git a/test/TypeScript/src/TimeState.lf b/test/TypeScript/src/TimeState.lf index d55cbff534..95d21f8f52 100644 --- a/test/TypeScript/src/TimeState.lf +++ b/test/TypeScript/src/TimeState.lf @@ -1,13 +1,11 @@ -target TypeScript; +target TypeScript -reactor Foo(bar:number(42)) { - state baz:time(500 msec); +reactor Foo(bar: number(42)) { + state baz: time(500 msec) - reaction (startup) {= - console.log("Baz: " + baz); - =} + reaction(startup) {= console.log("Baz: " + baz); =} } main reactor { - a = new Foo(); + a = new Foo() } diff --git a/test/TypeScript/src/Wcet.lf b/test/TypeScript/src/Wcet.lf index 3fcb3ef172..74dcde9cb6 100644 --- a/test/TypeScript/src/Wcet.lf +++ b/test/TypeScript/src/Wcet.lf @@ -1,18 +1,24 @@ // Setup for WCET analysis of Worker -target TypeScript; +target TypeScript + reactor Source { - output out1:number; - output out2:number; - timer t; + output out1: number + output out2: number + + timer t + reaction(t) -> out1, out2 {= out1 = 5; out2 = 10; =} } + reactor Work { - input in1:number; - input in2:number; - output out:number; + input in1: number + input in2: number + + output out: number + reaction(in1, in2) -> out {= let ret:number; if ((in1 as number) > 10) { @@ -23,19 +29,19 @@ reactor Work { out = ret; =} } + reactor Print { - input x:number; - reaction(x) {= - console.log("Received: " + x); - =} + input x: number + + reaction(x) {= console.log("Received: " + x); =} } main reactor Wcet { - source = new Source(); - work = new Work(); - print = new Print(); + source = new Source() + work = new Work() + print = new Print() - source.out1 -> work.in1; - source.out2 -> work.in2; - work.out -> print.x; + source.out1 -> work.in1 + source.out2 -> work.in2 + work.out -> print.x } diff --git a/test/TypeScript/src/concurrent/AsyncCallback.lf b/test/TypeScript/src/concurrent/AsyncCallback.lf index 09a7754551..b2b32cb0a2 100644 --- a/test/TypeScript/src/concurrent/AsyncCallback.lf +++ b/test/TypeScript/src/concurrent/AsyncCallback.lf @@ -1,12 +1,10 @@ // Test asynchronous callbacks that trigger a physical action. - target TypeScript { timeout: 2 sec, - keepalive: true // Not really needed here because there is a timer. -}; + keepalive: true // Not really needed here because there is a timer. +} main reactor AsyncCallback { - preamble {= function callback(a : Sched) { // Schedule twice. If the action is not physical, these should @@ -18,12 +16,14 @@ main reactor AsyncCallback { a.schedule(0, null); } =} - timer t(0, 200 msec); - state expected_time:time(100 msec); - state toggle:boolean(false); - physical action a(100 msec):number; - state i:number(0); + timer t(0, 200 msec) + + physical action a(100 msec): number + + state expected_time: time(100 msec) + state toggle: boolean(false) + state i: number(0) reaction(t) -> a {= // set a timeout for the callback diff --git a/test/TypeScript/src/docker/HelloWorldContainerized.lf b/test/TypeScript/src/docker/HelloWorldContainerized.lf index 831a3afd18..50ca1dcd8d 100644 --- a/test/TypeScript/src/docker/HelloWorldContainerized.lf +++ b/test/TypeScript/src/docker/HelloWorldContainerized.lf @@ -1,9 +1,7 @@ -target TypeScript { - docker: true -}; +target TypeScript { docker: true } import HelloWorldInside from "../HelloWorld.lf" main reactor HelloWorldContainerized { - a = new HelloWorldInside(); + a = new HelloWorldInside() } diff --git a/test/TypeScript/src/federated/ChainWithDelay.lf b/test/TypeScript/src/federated/ChainWithDelay.lf index 0c774a841e..58691727fc 100644 --- a/test/TypeScript/src/federated/ChainWithDelay.lf +++ b/test/TypeScript/src/federated/ChainWithDelay.lf @@ -1,20 +1,20 @@ /** * Demonstration that monotonic NET hypothesis is invalid. - * + * * @author Edward A. Lee * @author Youri Su */ - target TypeScript { - timeout: 3 msec -} -import Count from "../lib/Count.lf"; -import InternalDelay from "../lib/InternalDelay.lf"; -import TestCount from "../lib/TestCount.lf"; +target TypeScript { timeout: 3 msec } + +import Count from "../lib/Count.lf" +import InternalDelay from "../lib/InternalDelay.lf" +import TestCount from "../lib/TestCount.lf" federated reactor { - c = new Count(period = 1 msec); - i = new InternalDelay(delay = 500 usec); - t = new TestCount(numInputs = 3); - c.out -> i.inp; - i.out -> t.inp; + c = new Count(period = 1 msec) + i = new InternalDelay(delay = 500 usec) + t = new TestCount(numInputs = 3) + + c.out -> i.inp + i.out -> t.inp } diff --git a/test/TypeScript/src/federated/HelloDistributed.lf b/test/TypeScript/src/federated/HelloDistributed.lf index 61dcb84731..2795b5acc2 100644 --- a/test/TypeScript/src/federated/HelloDistributed.lf +++ b/test/TypeScript/src/federated/HelloDistributed.lf @@ -1,17 +1,16 @@ /** - * Test a particularly simple form of a distributed deterministic system - * where a federation that receives timestamped messages has only those - * messages as triggers. Therefore, no additional coordination of the - * advancement of time (HLA or Ptides) is needed. - * @author Edward A. Lee - * @author Hokeun Kim + * Test a particularly simple form of a distributed deterministic system where a + * federation that receives timestamped messages has only those messages as + * triggers. Therefore, no additional coordination of the advancement of time + * (HLA or Ptides) is needed. + * @author Edward A. Lee + * @author Hokeun Kim */ -target TypeScript { - timeout: 2 secs -}; +target TypeScript { timeout: 2 secs } reactor Source { - output out:string; + output out: string + reaction(startup) -> out {= console.log("Sending 'Hello World!' message from source federate."); out = "Hello World!"; @@ -20,11 +19,12 @@ reactor Source { } reactor Destination { - input inp:string; - state received:boolean(false); - reaction(startup) {= - console.log("Destination started."); - =} + input inp: string + + state received: boolean(false) + + reaction(startup) {= console.log("Destination started."); =} + reaction(inp) {= console.log(`At logical time ${util.getElapsedLogicalTime()}, destination received: $inp`); if (inp !== "Hello World!") { @@ -32,6 +32,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= console.log("Shutdown invoked."); if (!received) { @@ -41,10 +42,12 @@ reactor Destination { } federated reactor HelloDistributed at localhost { + s = new Source() // Reactor s is in federate Source + d = new Destination() // Reactor d is in federate Destination + + s.out -> d.inp // This version preserves the timestamp. + reaction(startup) {= console.log("Printing something in top-level federated reactor."); =} - s = new Source(); // Reactor s is in federate Source - d = new Destination(); // Reactor d is in federate Destination - s.out -> d.inp; // This version preserves the timestamp. } diff --git a/test/TypeScript/src/federated/PingPongDistributed.lf b/test/TypeScript/src/federated/PingPongDistributed.lf index e10c0ff8c2..923bb72b06 100644 --- a/test/TypeScript/src/federated/PingPongDistributed.lf +++ b/test/TypeScript/src/federated/PingPongDistributed.lf @@ -1,20 +1,22 @@ -/** -* This checks communication between federates -*/ - -target TypeScript; - -reactor Ping(count:number(10)) { - input receive:number; - output send:number; - state pingsLeft:number(count); - logical action serve; - reaction (startup, serve) -> send {= +/** This checks communication between federates */ +target TypeScript + +reactor Ping(count: number(10)) { + input receive: number + + output send: number + + logical action serve + + state pingsLeft: number(count) + + reaction(startup, serve) -> send {= console.log(`At lo${util.getElapsedLogicalTime()}, Ping sending ${pingsLeft}`); send = pingsLeft; pingsLeft = pingsLeft - 1; =} - reaction (receive) -> serve {= + + reaction(receive) -> serve {= if(pingsLeft > 0){ actions.serve.schedule(0, null); } @@ -24,10 +26,13 @@ reactor Ping(count:number(10)) { =} } -reactor Pong(expected:number(10)) { - input receive:number; - output send:number; - state count:number(0); +reactor Pong(expected: number(10)) { + input receive: number + + output send: number + + state count: number(0) + reaction(receive) -> send {= count += 1; console.log(`At logical time ${util.getElapsedLogicalTime()}, Pong received ${receive}`) @@ -36,6 +41,7 @@ reactor Pong(expected:number(10)) { util.requestStop(); } =} + reaction(shutdown) {= if (count != expected){ util.requestErrorStop(`Pong expected to receive ${expected} inputs, but it received ${count}`); @@ -44,9 +50,10 @@ reactor Pong(expected:number(10)) { =} } -federated reactor PingPongDistributed(count: number(10)){ - ping = new Ping(count=count); - pong = new Pong(expected=count); - ping.send -> pong.receive; - pong.send -> ping.receive; +federated reactor PingPongDistributed(count: number(10)) { + ping = new Ping(count = count) + pong = new Pong(expected = count) + + ping.send -> pong.receive + pong.send -> ping.receive } diff --git a/test/TypeScript/src/federated/StopAtShutdown.lf b/test/TypeScript/src/federated/StopAtShutdown.lf index 9d9b092487..5f874bfea6 100644 --- a/test/TypeScript/src/federated/StopAtShutdown.lf +++ b/test/TypeScript/src/federated/StopAtShutdown.lf @@ -1,39 +1,33 @@ /** - * Check that request_stop() doesn't cause - * any issues at the shutdown tag. + * Check that request_stop() doesn't cause any issues at the shutdown tag. * * Original bug discovered by Steven Wong */ -target TypeScript { - timeout: 2 sec -} +target TypeScript { timeout: 2 sec } reactor A { - input inp:number; - reaction(startup) {= - console.log("Hello World!"); - =} - reaction(inp) {= - console.log("Got it"); - =} - reaction(shutdown) {= - util.requestStop(); - =} + input inp: number + + reaction(startup) {= console.log("Hello World!"); =} + + reaction(inp) {= console.log("Got it"); =} + + reaction(shutdown) {= util.requestStop(); =} } reactor B { - output out:number; - timer t(1 sec); - reaction(t) -> out {= - out = 1; - =} - reaction(shutdown) {= - util.requestStop(); - =} + output out: number + + timer t(1 sec) + + reaction(t) -> out {= out = 1; =} + + reaction(shutdown) {= util.requestStop(); =} } federated reactor { - a = new A(); - b = new B(); - b.out -> a.inp; + a = new A() + b = new B() + + b.out -> a.inp } diff --git a/test/TypeScript/src/federated/TopLevelArtifacts.lf b/test/TypeScript/src/federated/TopLevelArtifacts.lf index 188fdc3246..cf54b0aaaf 100644 --- a/test/TypeScript/src/federated/TopLevelArtifacts.lf +++ b/test/TypeScript/src/federated/TopLevelArtifacts.lf @@ -1,40 +1,40 @@ /** - * Test whether top-level reactions, actions, and ports are handled appropriately. - * + * Test whether top-level reactions, actions, and ports are handled + * appropriately. + * * Currently, these artifacts are replicated on all federates. - * - * @note This just tests for the correctness of the code generation. These top-level - * artifacts might be disallowed in the future. + * + * @note This just tests for the correctness of the code generation. These + * top-level artifacts might be disallowed in the future. * @author Youri Su */ - - target TypeScript { - timeout: 1 msec -}; - - import Count from "../lib/Count.lf"; - import TestCount from "../lib/TestCount.lf"; - - federated reactor { - state successes:number(0); - logical action act; - reaction (startup) {= - successes++; - =} - timer t(0, 1 sec); - reaction (t) -> act {= +target TypeScript { timeout: 1 msec } + +import Count from "../lib/Count.lf" +import TestCount from "../lib/TestCount.lf" + +federated reactor { + timer t(0, 1 sec) + + logical action act + + c = new Count() + tc = new TestCount() + + c.out -> tc.inp + + state successes: number(0) + + reaction(startup) {= successes++; =} + + reaction(t) -> act {= successes++; actions.act.schedule(0, null); =} - reaction (act) {= - successes++; - =} - - c = new Count(); - tc = new TestCount(); - c.out -> tc.inp; - - reaction (shutdown) {= + + reaction(act) {= successes++; =} + + reaction(shutdown) {= if (successes != 3) { util.requestErrorStop(`Failed to properly execute top-level reactions`); } diff --git a/test/TypeScript/src/lib/Count.lf b/test/TypeScript/src/lib/Count.lf index b7b698f4a3..a2a6d85ccc 100644 --- a/test/TypeScript/src/lib/Count.lf +++ b/test/TypeScript/src/lib/Count.lf @@ -1,10 +1,11 @@ -target TypeScript; - -reactor Count(offset:time(0), period:time(1 sec)) { - output out:number; - timer t(offset, period); - state count:number(1); - reaction(t) -> out {= - out = count++; - =} +target TypeScript + +reactor Count(offset: time(0), period: time(1 sec)) { + output out: number + + timer t(offset, period) + + state count: number(1) + + reaction(t) -> out {= out = count++; =} } diff --git a/test/TypeScript/src/lib/Imported.lf b/test/TypeScript/src/lib/Imported.lf index 47c665fff6..1739ec1509 100644 --- a/test/TypeScript/src/lib/Imported.lf +++ b/test/TypeScript/src/lib/Imported.lf @@ -1,13 +1,13 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target TypeScript{ - timeout : 2 sec -}; -import ImportedAgain from "ImportedAgain.lf"; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target TypeScript { timeout: 2 sec } + +import ImportedAgain from "ImportedAgain.lf" + reactor Imported { - input x:number; - a = new ImportedAgain(); - reaction(x) -> a.x {= - a.x = (x as number); - =} + input x: number + + a = new ImportedAgain() + + reaction(x) -> a.x {= a.x = (x as number); =} } diff --git a/test/TypeScript/src/lib/ImportedAgain.lf b/test/TypeScript/src/lib/ImportedAgain.lf index 68eec84e7b..e30dc2ac70 100644 --- a/test/TypeScript/src/lib/ImportedAgain.lf +++ b/test/TypeScript/src/lib/ImportedAgain.lf @@ -1,10 +1,10 @@ -// This is used by the test for the ability to import a reactor definition -// that itself imports a reactor definition. -target TypeScript{ - timeout : 2 sec -}; +// This is used by the test for the ability to import a reactor definition that +// itself imports a reactor definition. +target TypeScript { timeout: 2 sec } + reactor ImportedAgain { - input x:number; + input x: number + reaction(x) {= console.log("Received: " + x); if ((x as number) != 42) { diff --git a/test/TypeScript/src/lib/InternalDelay.lf b/test/TypeScript/src/lib/InternalDelay.lf index 63ca3a9969..74fdf40bdb 100644 --- a/test/TypeScript/src/lib/InternalDelay.lf +++ b/test/TypeScript/src/lib/InternalDelay.lf @@ -1,17 +1,14 @@ -/** - * @author Youri Su - */ -target TypeScript; -reactor InternalDelay ( - delay:TimeValue(10 msec) -) { - input inp:number; - output out:number; - logical action d:number; - reaction(inp) -> d {= - actions.d.schedule(delay, inp as number); - =} - reaction(d) -> out {= - out = d; - =} +/** @author Youri Su */ +target TypeScript + +reactor InternalDelay(delay: TimeValue(10 msec)) { + input inp: number + + output out: number + + logical action d: number + + reaction(inp) -> d {= actions.d.schedule(delay, inp as number); =} + + reaction(d) -> out {= out = d; =} } diff --git a/test/TypeScript/src/lib/TestCount.lf b/test/TypeScript/src/lib/TestCount.lf index b7e8399f8f..e327122dd3 100644 --- a/test/TypeScript/src/lib/TestCount.lf +++ b/test/TypeScript/src/lib/TestCount.lf @@ -7,11 +7,14 @@ * @param stride The increment for the inputs. Default is 1. * @param numInputs The number of inputs expected. Default is 1. */ -target TypeScript; -reactor TestCount(start:number(1), stride:number(1), numInputs:number(1)) { - state count:number(start); - state inputsReceived:number(0); - input inp:number; +target TypeScript + +reactor TestCount(start: number(1), stride: number(1), numInputs: number(1)) { + input inp: number + + state count: number(start) + state inputsReceived: number(0) + reaction(inp) {= console.log("Received " + inp + "."); if (inp != count) { @@ -20,6 +23,7 @@ reactor TestCount(start:number(1), stride:number(1), numInputs:number(1)) { count += stride; inputsReceived++; =} + reaction(shutdown) {= console.log("Shutdown invoked."); if (inputsReceived != numInputs) { diff --git a/test/TypeScript/src/multiport/BankMulticast.lf b/test/TypeScript/src/multiport/BankMulticast.lf index 155e569c8d..f760d72daa 100644 --- a/test/TypeScript/src/multiport/BankMulticast.lf +++ b/test/TypeScript/src/multiport/BankMulticast.lf @@ -1,37 +1,36 @@ /** - * This tests that a contained bank can send not only to a local connection, but also - * multicast via the container's output port. + * This tests that a contained bank can send not only to a local connection, but + * also multicast via the container's output port. */ -target TypeScript { - timeout: 3 sec -} +target TypeScript { timeout: 3 sec } import Count from "../lib/Count.lf" import TestCount from "../lib/TestCount.lf" reactor Foo { - input inp:number; - output out:number; + input inp: number + + output out: number - c = new Count(); - c.out -> out; + c = new Count() + d = new TestCount(numInputs = 4) - d = new TestCount(numInputs = 4); - inp -> d.inp; + c.out -> out + inp -> d.inp } reactor Bar { - output[4] out:number; + output[4] out: number - foo = new[4] Foo(); + foo = new[4] Foo() - foo.out -> foo.inp; - foo.out -> out; + foo.out -> foo.inp + foo.out -> out } main reactor { - bar = new Bar(); + bar = new Bar() + d = new[4] TestCount(numInputs = 4) - d = new[4] TestCount(numInputs = 4); - bar.out -> d.inp; + bar.out -> d.inp } diff --git a/test/TypeScript/src/multiport/BankMultiportToReaction.lf b/test/TypeScript/src/multiport/BankMultiportToReaction.lf index b9b4637609..99d94af907 100644 --- a/test/TypeScript/src/multiport/BankMultiportToReaction.lf +++ b/test/TypeScript/src/multiport/BankMultiportToReaction.lf @@ -1,20 +1,21 @@ -target TypeScript { - timeout: 5 sec -}; -import Count from "../lib/Count.lf"; +target TypeScript { timeout: 5 sec } + +import Count from "../lib/Count.lf" reactor DoubleCount { - output[2] out:number; - c1 = new Count(); - c2 = new Count(); - c1.out, c2.out -> out; + output[2] out: number + + c1 = new Count() + c2 = new Count() + + c1.out, c2.out -> out } main reactor { - state count:number(1); - state received:boolean(false); + s = new[2] DoubleCount() - s = new[2] DoubleCount(); + state count: number(1) + state received: boolean(false) reaction(s.out) {= for (let i = 0; i < s.length; i++) { @@ -30,6 +31,7 @@ main reactor { } count++; =} + reaction(shutdown) {= if (!received) { util.reportError("No inputs present."); diff --git a/test/TypeScript/src/multiport/BankReactionsInContainer.lf b/test/TypeScript/src/multiport/BankReactionsInContainer.lf index 193d94d961..1e2b45680b 100644 --- a/test/TypeScript/src/multiport/BankReactionsInContainer.lf +++ b/test/TypeScript/src/multiport/BankReactionsInContainer.lf @@ -1,13 +1,14 @@ /** * This tests an output that is broadcast back to a multiport input of a bank. */ -target TypeScript { - timeout: 1 sec -}; +target TypeScript { timeout: 1 sec } + reactor R { - output[2] out:number; - input[2] inp:number; - state received:boolean(false); + input[2] inp: number + + output[2] out: number + + state received: boolean(false) reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { @@ -29,6 +30,7 @@ reactor R { } } =} + reaction(shutdown) {= console.log("Inner shutdown invoked."); if (!received) { @@ -36,9 +38,11 @@ reactor R { } =} } + main reactor { - s = new[2] R(); - state received:boolean(false); + s = new[2] R() + + state received: boolean(false) reaction(startup) -> s.inp {= let count = 0; @@ -49,6 +53,7 @@ main reactor { } } =} + reaction(s.out) {= for (let j = 0; j < s.length; j++) { for (let i = 0; i < s[j].out.length; i++) { @@ -62,6 +67,7 @@ main reactor { } } =} + reaction(shutdown) {= console.log("Outer shutdown invoked."); if (!received) { diff --git a/test/TypeScript/src/multiport/BankSelfBroadcast.lf b/test/TypeScript/src/multiport/BankSelfBroadcast.lf index 2b93008501..09f9642a98 100644 --- a/test/TypeScript/src/multiport/BankSelfBroadcast.lf +++ b/test/TypeScript/src/multiport/BankSelfBroadcast.lf @@ -1,21 +1,23 @@ /** - * Test a bank of reactors that broadcast a single output - * back to a multiport input of the same reactors in the bank - * so that each reactor in the bank receives the output - * produced by itself and each other reactor. + * Test a bank of reactors that broadcast a single output back to a multiport + * input of the same reactors in the bank so that each reactor in the bank + * receives the output produced by itself and each other reactor. * * @author Edward A. Lee * @author Christian Menard * @author Hokeun Kim */ -target TypeScript; +target TypeScript + reactor A { - input[4] inp:number; - output out:number; - state received:boolean(false); - reaction(startup) -> out {= - out = this.getBankIndex(); - =} + input[4] inp: number + + output out: number + + state received: boolean(false) + + reaction(startup) -> out {= out = this.getBankIndex(); =} + reaction(inp) {= for (let i = 0; i < inp.length; i++) { if (inp[i] !== undefined) { @@ -31,13 +33,16 @@ reactor A { } } =} + reaction(shutdown) {= if (!received) { util.requestErrorStop("ERROR: No inputs received."); } =} } + main reactor { - a = new[4] A(); - (a.out)+ -> a.inp; + a = new[4] A() + + (a.out)+ -> a.inp } diff --git a/test/TypeScript/src/multiport/BankToBank.lf b/test/TypeScript/src/multiport/BankToBank.lf index 5661085066..612b5a049d 100644 --- a/test/TypeScript/src/multiport/BankToBank.lf +++ b/test/TypeScript/src/multiport/BankToBank.lf @@ -1,19 +1,24 @@ // Check bank of reactors sending to bank of reactors. -target TypeScript { - timeout: 2 sec -}; +target TypeScript { timeout: 2 sec } + reactor Source { - timer t(0, 200 msec); - output out:number; - state s:number(0); + output out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= out = s; s += this.getBankIndex(); =} } + reactor Destination { - state s:number(0); - input inp:number; + input inp: number + + state s: number(0) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received: " + inp); if (inp != s) { @@ -21,6 +26,7 @@ reactor Destination { } s += this.getBankIndex(); =} + reaction(shutdown) {= if (s == 0 && this.getBankIndex() != 0) { util.requestErrorStop("ERROR: Destination " + this.getBankIndex() + " received no input!"); @@ -29,9 +35,10 @@ reactor Destination { =} } -main reactor BankToBank(width:number(4)) { +main reactor BankToBank(width: number(4)) { // FIXME: Should set the width to "width" rather than "4". - a = new[4] Source(); - b = new[4] Destination(); - a.out -> b.inp; + a = new[4] Source() + b = new[4] Destination() + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/BankToBankMultiport.lf b/test/TypeScript/src/multiport/BankToBankMultiport.lf index 10274e5855..b8230eb1e2 100644 --- a/test/TypeScript/src/multiport/BankToBankMultiport.lf +++ b/test/TypeScript/src/multiport/BankToBankMultiport.lf @@ -1,20 +1,25 @@ // Check bank of reactors sending to bank of reactors with multiports. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(1)) { - timer t(0, 200 msec); - output[width] out:number; - state s:number(0); +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(1)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < out.length; i++) { out[i] = s++; } =} } -reactor Destination(width:number(1)) { - state s:number(6); - input[width] inp:number; + +reactor Destination(width: number(1)) { + input[width] inp: number + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -27,6 +32,7 @@ reactor Destination(width:number(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); @@ -34,8 +40,10 @@ reactor Destination(width:number(1)) { console.log("Success."); =} } -main reactor BankToBankMultiport(bankWidth:number(4)) { - a = new[bankWidth] Source(width = 4); - b = new[bankWidth] Destination(width = 4); - a.out -> b.inp; + +main reactor BankToBankMultiport(bankWidth: number(4)) { + a = new[bankWidth] Source(width = 4) + b = new[bankWidth] Destination(width = 4) + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/BankToBankMultiportAfter.lf b/test/TypeScript/src/multiport/BankToBankMultiportAfter.lf index e7321fce11..2377af9d7e 100644 --- a/test/TypeScript/src/multiport/BankToBankMultiportAfter.lf +++ b/test/TypeScript/src/multiport/BankToBankMultiportAfter.lf @@ -1,20 +1,25 @@ // Check bank of reactors sending to bank of reactors with multiports. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(1)) { - timer t(0, 200 msec); - output[width] out:number; - state s:number(0); +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(1)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < out.length; i++) { out[i] = s++; } =} } -reactor Destination(width:number(1)) { - state s:number(6); - input[width] inp:number; + +reactor Destination(width: number(1)) { + input[width] inp: number + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -27,6 +32,7 @@ reactor Destination(width:number(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); @@ -34,8 +40,10 @@ reactor Destination(width:number(1)) { console.log("Success."); =} } -main reactor (bankWidth:number(4)) { - a = new[bankWidth] Source(width = 4); - b = new[bankWidth] Destination(width = 4); - a.out -> b.inp after 200 msec; + +main reactor(bankWidth: number(4)) { + a = new[bankWidth] Source(width = 4) + b = new[bankWidth] Destination(width = 4) + + a.out -> b.inp after 200 msec } diff --git a/test/TypeScript/src/multiport/BankToMultiport.lf b/test/TypeScript/src/multiport/BankToMultiport.lf index bb12cf2d43..bf7b46e5d1 100644 --- a/test/TypeScript/src/multiport/BankToMultiport.lf +++ b/test/TypeScript/src/multiport/BankToMultiport.lf @@ -1,18 +1,18 @@ // Test bank of reactors to multiport input with id parameter in the bank. -target TypeScript; +target TypeScript + reactor Source { - output out:number; + output out: number - reaction (startup) -> out {= - out = this.getBankIndex(); - =} + reaction(startup) -> out {= out = this.getBankIndex(); =} } reactor Sink { - input[4] inp:number; - state received:boolean(false); + input[4] inp: number + + state received: boolean(false) - reaction (inp) {= + reaction(inp) {= for (let i = 0; i < inp.length; i++) { received = true; console.log("Received " + inp[i]); @@ -21,7 +21,8 @@ reactor Sink { } } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { util.requestErrorStop("Error: received no input!"); } @@ -29,7 +30,8 @@ reactor Sink { } main reactor BankToMultiport { - source = new[4] Source(); - sink = new Sink(); - source.out -> sink.inp; + source = new[4] Source() + sink = new Sink() + + source.out -> sink.inp } diff --git a/test/TypeScript/src/multiport/BankToReaction.lf b/test/TypeScript/src/multiport/BankToReaction.lf index 087fe4d01b..a756e7eb2e 100644 --- a/test/TypeScript/src/multiport/BankToReaction.lf +++ b/test/TypeScript/src/multiport/BankToReaction.lf @@ -1,12 +1,11 @@ -target TypeScript { - timeout: 5 sec -}; -import Count from "../lib/Count.lf"; +target TypeScript { timeout: 5 sec } + +import Count from "../lib/Count.lf" main reactor { - state count:number(1); + s = new[2] Count() - s = new[2] Count(); + state count: number(1) reaction(s.out) {= for (let i = 0; i < s.length; i++) { diff --git a/test/TypeScript/src/multiport/Broadcast.lf b/test/TypeScript/src/multiport/Broadcast.lf index a2a3dfe151..28e14eea13 100644 --- a/test/TypeScript/src/multiport/Broadcast.lf +++ b/test/TypeScript/src/multiport/Broadcast.lf @@ -1,17 +1,15 @@ -target TypeScript; +target TypeScript reactor Source { - output out:number; + output out: number - reaction (startup) -> out {= - out = 42; - =} + reaction(startup) -> out {= out = 42; =} } reactor Sink { - input inp:number; + input inp: number - reaction (inp) {= + reaction(inp) {= console.log("Received " + inp); if (inp != 42) { util.requestErrorStop("Error: expected " + 42); @@ -20,7 +18,8 @@ reactor Sink { } main reactor { - source = new Source(); - sink = new[4] Sink(); - (source.out)+ -> sink.inp; + source = new Source() + sink = new[4] Sink() + + (source.out)+ -> sink.inp } diff --git a/test/TypeScript/src/multiport/BroadcastAfter.lf b/test/TypeScript/src/multiport/BroadcastAfter.lf index 2c2052a327..ec2985cdeb 100644 --- a/test/TypeScript/src/multiport/BroadcastAfter.lf +++ b/test/TypeScript/src/multiport/BroadcastAfter.lf @@ -1,18 +1,16 @@ -target TypeScript { - timeout: 2 sec -}; +target TypeScript { timeout: 2 sec } reactor Source { - output out:number; + output out: number - reaction(startup) -> out {= - out = 42; - =} + reaction(startup) -> out {= out = 42; =} } reactor Destination { - input inp:number; - state received:boolean(false); + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received " + inp + "."); if (inp != 42) { @@ -24,6 +22,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { util.reportError("ERROR: Destination " + this.getBankIndex() + " received no input!"); @@ -33,7 +32,8 @@ reactor Destination { } main reactor { - a = new Source(); - b = new[4] Destination(); - (a.out)+ -> b.inp after 1 sec; + a = new Source() + b = new[4] Destination() + + (a.out)+ -> b.inp after 1 sec } diff --git a/test/TypeScript/src/multiport/BroadcastMultipleAfter.lf b/test/TypeScript/src/multiport/BroadcastMultipleAfter.lf index 47157195fa..149bca35de 100644 --- a/test/TypeScript/src/multiport/BroadcastMultipleAfter.lf +++ b/test/TypeScript/src/multiport/BroadcastMultipleAfter.lf @@ -1,18 +1,16 @@ -target TypeScript { - timeout: 2 sec -}; +target TypeScript { timeout: 2 sec } -reactor Source(value:number(42)) { - output out:number; +reactor Source(value: number(42)) { + output out: number - reaction(startup) -> out {= - out = value; - =} + reaction(startup) -> out {= out = value; =} } reactor Destination { - input inp:number; - state received:boolean(false); + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received " + inp + "."); let expected = (this.getBankIndex() % 3) + 1; @@ -25,6 +23,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { util.requestErrorStop("ERROR: Destination " + this.getBankIndex() + " received no input!"); @@ -34,9 +33,10 @@ reactor Destination { } main reactor { - a1 = new Source(value=1); - a2 = new Source(value=2); - a3 = new Source(value=3); - b = new[9] Destination(); - (a1.out, a2.out, a3.out)+ -> b.inp after 1 sec; + a1 = new Source(value = 1) + a2 = new Source(value = 2) + a3 = new Source(value = 3) + b = new[9] Destination() + + (a1.out, a2.out, a3.out)+ -> b.inp after 1 sec } diff --git a/test/TypeScript/src/multiport/FullyConnected.lf b/test/TypeScript/src/multiport/FullyConnected.lf index 80fb68b83b..49af916dc9 100644 --- a/test/TypeScript/src/multiport/FullyConnected.lf +++ b/test/TypeScript/src/multiport/FullyConnected.lf @@ -1,20 +1,19 @@ -target TypeScript; +target TypeScript -reactor Node( - numNodes: number(4) -) { - input[numNodes] inp: number; - output out: number; +reactor Node(numNodes: number(4)) { + input[numNodes] inp: number - state received: boolean(false); + output out: number - reaction (startup) -> out{= + state received: boolean(false) + + reaction(startup) -> out {= console.log("Hello from node " + this.getBankIndex() + "!"); // broadcast my ID to everyone out = this.getBankIndex(); =} - reaction (inp) {= + reaction(inp) {= console.log("Node " + this.getBankIndex() + " received messages from "); let count = 0; for (let i = 0; i < inp.length; i++) { @@ -30,13 +29,16 @@ reactor Node( util.requestErrorStop("Received fewer messages than expected!"); } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { util.reportError("Received no input!"); } =} } + main reactor(numNodes: number(4)) { - nodes = new[numNodes] Node(numNodes=numNodes); - (nodes.out)+ -> nodes.inp; + nodes = new[numNodes] Node(numNodes = numNodes) + + (nodes.out)+ -> nodes.inp } diff --git a/test/TypeScript/src/multiport/MultiportFromBank.lf b/test/TypeScript/src/multiport/MultiportFromBank.lf index a360bb41ba..fe6a809110 100644 --- a/test/TypeScript/src/multiport/MultiportFromBank.lf +++ b/test/TypeScript/src/multiport/MultiportFromBank.lf @@ -1,17 +1,18 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target TypeScript { timeout: 2 sec } + reactor Source { - output out:number; - reaction(startup) -> out {= - out = this.getBankIndex(); - =} + output out: number + + reaction(startup) -> out {= out = this.getBankIndex(); =} } -reactor Destination(portWidth:number(3)) { - input[portWidth] inp:number; - state received:boolean(false); + +reactor Destination(portWidth: number(3)) { + input[portWidth] inp: number + + state received: boolean(false) + reaction(inp) {= for (let i = 0; i < inp.length; i++) { console.log("Destination channel " + i + " received " + inp[i]); @@ -21,6 +22,7 @@ reactor Destination(portWidth:number(3)) { } received = true; =} + reaction(shutdown) {= if (!received) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -29,8 +31,9 @@ reactor Destination(portWidth:number(3)) { =} } -main reactor (width:number(4)) { - a = new[width] Source(); - b = new Destination(portWidth = width); - a.out -> b.inp; +main reactor(width: number(4)) { + a = new[width] Source() + b = new Destination(portWidth = width) + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportFromBankHierarchy.lf b/test/TypeScript/src/multiport/MultiportFromBankHierarchy.lf index a74709081e..18cfdc1874 100644 --- a/test/TypeScript/src/multiport/MultiportFromBankHierarchy.lf +++ b/test/TypeScript/src/multiport/MultiportFromBankHierarchy.lf @@ -1,17 +1,20 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target TypeScript { timeout: 2 sec } + import Source, Destination from "MultiportFromBank.lf" -reactor Container(portWidth:number(3)) { - output[portWidth] out:number; - s = new[portWidth] Source(); - s.out -> out; + +reactor Container(portWidth: number(3)) { + output[portWidth] out: number + + s = new[portWidth] Source() + + s.out -> out } main reactor { - a = new Container(); - b = new Destination(); - a.out -> b.inp; + a = new Container() + b = new Destination() + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportFromBankHierarchyAfter.lf b/test/TypeScript/src/multiport/MultiportFromBankHierarchyAfter.lf index ca8aa9baaa..3f34fd6dec 100644 --- a/test/TypeScript/src/multiport/MultiportFromBankHierarchyAfter.lf +++ b/test/TypeScript/src/multiport/MultiportFromBankHierarchyAfter.lf @@ -1,13 +1,13 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target TypeScript { timeout: 2 sec } + import Destination from "MultiportFromBank.lf" import Container from "MultiportFromBankHierarchy.lf" main reactor MultiportFromBankHierarchyAfter { - a = new Container(portWidth = 4); - b = new Destination(portWidth = 4); - a.out -> b.inp after 1 sec; + a = new Container(portWidth = 4) + b = new Destination(portWidth = 4) + + a.out -> b.inp after 1 sec } diff --git a/test/TypeScript/src/multiport/MultiportFromHierarchy.lf b/test/TypeScript/src/multiport/MultiportFromHierarchy.lf index c2466edce9..3a8f473852 100644 --- a/test/TypeScript/src/multiport/MultiportFromHierarchy.lf +++ b/test/TypeScript/src/multiport/MultiportFromHierarchy.lf @@ -1,20 +1,26 @@ -// Check multiport output to multiport input, where the former is a hierarchical reactor. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(3)) { - timer t(0, 200 msec); - output[width] out:number; - state s:number(0); +// Check multiport output to multiport input, where the former is a hierarchical +// reactor. +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(3)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < out.length; i++) { out[i] = s++; } =} } -reactor Destination(width:number(3)) { - state s:number(6); - input[width] inp:number; + +reactor Destination(width: number(3)) { + input[width] inp: number + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -27,6 +33,7 @@ reactor Destination(width:number(3)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); @@ -34,20 +41,26 @@ reactor Destination(width:number(3)) { console.log("Success."); =} } -reactor Container(width:number(3)) { - output[width] out:number; - src = new InsideContainer(width = width); - src.out -> out; + +reactor Container(width: number(3)) { + output[width] out: number + + src = new InsideContainer(width = width) + + src.out -> out } -reactor InsideContainer(width:number(3)) { - output[width] out:number; - src = new Source(width = width); - src.out -> out; +reactor InsideContainer(width: number(3)) { + output[width] out: number + + src = new Source(width = width) + + src.out -> out } -main reactor MultiportFromHierarchy(width:number(4)) { - a = new Container(width = width); - b = new Destination(width = width); - a.out -> b.inp; +main reactor MultiportFromHierarchy(width: number(4)) { + a = new Container(width = width) + b = new Destination(width = width) + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportFromReaction.lf b/test/TypeScript/src/multiport/MultiportFromReaction.lf index ec2d74eb3e..f4aea41fff 100644 --- a/test/TypeScript/src/multiport/MultiportFromReaction.lf +++ b/test/TypeScript/src/multiport/MultiportFromReaction.lf @@ -1,10 +1,11 @@ // Check reaction to multiport input of a contained reactor. -target TypeScript { - timeout: 2 sec -}; -reactor Destination(width:number(1)) { - state s:number(6); - input[width] inp:number; +target TypeScript { timeout: 2 sec } + +reactor Destination(width: number(1)) { + input[width] inp: number + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -17,6 +18,7 @@ reactor Destination(width:number(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); @@ -24,9 +26,14 @@ reactor Destination(width:number(1)) { console.log("Success."); =} } -main reactor MultiportFromReaction(width:number(4)) { - timer t(0, 200 msec); - state s:number(0); + +main reactor MultiportFromReaction(width: number(4)) { + timer t(0, 200 msec) + + b = new Destination(width = width) + + state s: number(0) + reaction(t) -> b.inp {= for (let i = 0; i < b.inp.length; i++) { console.log("Before SET, b.inp[" + i + "] !== undefined has value " + b.inp[i] !== undefined); @@ -35,5 +42,4 @@ main reactor MultiportFromReaction(width:number(4)) { console.log("AFTER set, b.inp[" + i + "] has value " + b.inp[i]); } =} - b = new Destination(width = width); } diff --git a/test/TypeScript/src/multiport/MultiportIn.lf b/test/TypeScript/src/multiport/MultiportIn.lf index 50d3dd8153..f3190a4b75 100644 --- a/test/TypeScript/src/multiport/MultiportIn.lf +++ b/test/TypeScript/src/multiport/MultiportIn.lf @@ -1,27 +1,30 @@ // This is a version of the test that uses a multiport input at the destination. // Its purpose is to test multiport inputs. -target TypeScript { - timeout: 2 sec -}; +target TypeScript { timeout: 2 sec } reactor Source { - timer t(0, 200 msec); - output out:number; - state s:number(0); - reaction(t) -> out {= - out = s++; - =} + output out: number + + timer t(0, 200 msec) + + state s: number(0) + + reaction(t) -> out {= out = s++; =} } + reactor Computation { - input inp:number; - output out:number; - reaction(inp) -> out {= - out = inp; - =} + input inp: number + + output out: number + + reaction(inp) -> out {= out = inp; =} } + reactor Destination { - state s:number(0); - input[4] inp:number; + input[4] inp: number + + state s: number(0) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -38,6 +41,7 @@ reactor Destination { } s += 4; =} + reaction(shutdown) {= if (s == 0) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -47,15 +51,16 @@ reactor Destination { } main reactor MultiportIn { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.inp; - a.out -> t2.inp; - a.out -> t3.inp; - a.out -> t4.inp; - t1.out, t2.out, t3.out, t4.out -> b.inp; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.inp + a.out -> t2.inp + a.out -> t3.inp + a.out -> t4.inp + t1.out, t2.out, t3.out, t4.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportInParameterized.lf b/test/TypeScript/src/multiport/MultiportInParameterized.lf index f0ddfc3c5f..fe4f3b9dda 100644 --- a/test/TypeScript/src/multiport/MultiportInParameterized.lf +++ b/test/TypeScript/src/multiport/MultiportInParameterized.lf @@ -1,28 +1,33 @@ -// This is a version of the Threaded test that uses a multiport input at the destination. -// Its purpose is to test multiport inputs. -target TypeScript { - timeout: 2 sec -}; +// This is a version of the Threaded test that uses a multiport input at the +// destination. Its purpose is to test multiport inputs. +target TypeScript { timeout: 2 sec } reactor Source { - timer t(0, 200 msec); - output out:number; - state s:number(0); + output out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= out = s; s++; =} } + reactor Computation { - input inp:number; - output out:number; - reaction(inp) -> out {= - out = inp; - =} + input inp: number + + output out: number + + reaction(inp) -> out {= out = inp; =} } -reactor Destination(width:number(1)) { - state s:number(0); - input[width] inp:number; + +reactor Destination(width: number(1)) { + input[width] inp: number + + state s: number(0) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -37,6 +42,7 @@ reactor Destination(width:number(1)) { } s += 4; =} + reaction(shutdown) {= if (s == 0) { util.reportError("ERROR: Destination received no input!"); @@ -46,20 +52,18 @@ reactor Destination(width:number(1)) { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(width = 4); - a.out -> t1.inp; - a.out -> t2.inp; - a.out -> t3.inp; - a.out -> t4.inp; - t1.out, t2.out, t3.out, t4.out -> b.inp; - // I.e.: - // t1.out -> b.inp[0]; - // t2.out -> b.inp[1]; - // t3.out -> b.inp[2]; - // dt4.out -> b.inp[3]; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination(width = 4) + + a.out -> t1.inp + a.out -> t2.inp + a.out -> t3.inp + a.out -> t4.inp + // I.e.: t1.out -> b.inp[0]; t2.out -> b.inp[1]; t3.out -> b.inp[2]; dt4.out + // -> b.inp[3]; + t1.out, t2.out, t3.out, t4.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportMutableInput.lf b/test/TypeScript/src/multiport/MultiportMutableInput.lf index 387df2e24d..60aecd04ed 100644 --- a/test/TypeScript/src/multiport/MultiportMutableInput.lf +++ b/test/TypeScript/src/multiport/MultiportMutableInput.lf @@ -1,18 +1,20 @@ -// Source produces a ints on a multiport, which it passes -// to Scale. Scale requests a writable copy. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target TypeScript; +// Source produces a ints on a multiport, which it passes to Scale. Scale +// requests a writable copy. It modifies it and passes it to Print. It gets +// freed after Print is done with it. +target TypeScript + reactor Source { - output[2] out:number; + output[2] out: number + reaction(startup) -> out {= out[0] = 21; out[1] = 42; =} } -// The scale parameter is just for testing. -reactor Print(scale:number(1)) { - input[2] inp:number; + +reactor Print(scale: number(1)) { // The scale parameter is just for testing. + input[2] inp: number + reaction(inp) {= let expected = 42; for (let j = 0; j < 2; j++) { @@ -25,9 +27,11 @@ reactor Print(scale:number(1)) { =} } -reactor Scale(scale:number(2)) { - mutable input[2] inp:number; - output[2] out:number; +reactor Scale(scale: number(2)) { + mutable input[2] inp: number + + output[2] out: number + reaction(inp) -> out {= for (let j = 0; j < 2; j++) { // Modify the input, allowed because mutable. @@ -36,10 +40,12 @@ reactor Scale(scale:number(2)) { } =} } + main reactor { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.inp; - c.out -> p.inp; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.inp + c.out -> p.inp } diff --git a/test/TypeScript/src/multiport/MultiportMutableInputArray.lf b/test/TypeScript/src/multiport/MultiportMutableInputArray.lf index c6e74464ed..0b8f48e386 100644 --- a/test/TypeScript/src/multiport/MultiportMutableInputArray.lf +++ b/test/TypeScript/src/multiport/MultiportMutableInputArray.lf @@ -1,12 +1,12 @@ -// Source produces a dynamically allocated arrays on a multiport, which it passes -// to Scale. Scale requests a writable copy, which, instead of -// copying, it just gets ownership of the original array. -// It modifies it and passes it to Print. It gets freed after -// Print is done with it. -target TypeScript; +// Source produces a dynamically allocated arrays on a multiport, which it +// passes to Scale. Scale requests a writable copy, which, instead of copying, +// it just gets ownership of the original array. It modifies it and passes it to +// Print. It gets freed after Print is done with it. +target TypeScript reactor Source { - output[2] out:{=Array=}; + output[2] out: {= Array =} + reaction(startup) -> out {= // Dynamically allocate an output array of length 3. out[0] = new Array(3); @@ -25,9 +25,10 @@ reactor Source { out[1][2] = 5; =} } -// The scale parameter is just for testing. -reactor Print(scale:number(1)) { - input[2] inp:{=Array=}; + +reactor Print(scale: number(1)) { // The scale parameter is just for testing. + input[2] inp: {= Array =} + reaction(inp) {= let count = 0; // For testing. let failed = false; // For testing. @@ -54,9 +55,11 @@ reactor Print(scale:number(1)) { =} } -reactor Scale(scale:number(2)) { - mutable input[2] inp:{=Array=}; - output[2] out:{=Array=}; +reactor Scale(scale: number(2)) { + mutable input[2] inp: {= Array =} + + output[2] out: {= Array =} + reaction(inp) -> out {= for (let j = 0; j < inp.length; j++) { if (inp[j] === undefined) { @@ -71,9 +74,10 @@ reactor Scale(scale:number(2)) { } main reactor { - s = new Source(); - c = new Scale(); - p = new Print(scale=2); - s.out -> c.inp; - c.out -> p.inp; + s = new Source() + c = new Scale() + p = new Print(scale = 2) + + s.out -> c.inp + c.out -> p.inp } diff --git a/test/TypeScript/src/multiport/MultiportOut.lf b/test/TypeScript/src/multiport/MultiportOut.lf index 67c698adb8..7aa79d0c53 100644 --- a/test/TypeScript/src/multiport/MultiportOut.lf +++ b/test/TypeScript/src/multiport/MultiportOut.lf @@ -1,11 +1,13 @@ // Check multiport capabilities on Outputs. -target TypeScript { - timeout: 2 sec, -}; +target TypeScript { timeout: 2 sec } + reactor Source { - timer t(0, 200 msec); - output[4] out:number; - state s:number(0); + output[4] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < 4; i++) { out[i] = s; @@ -13,17 +15,23 @@ reactor Source { s++; =} } + reactor Computation { - input inp:number; - output out:number; + input inp: number + + output out: number + reaction(inp) -> out {= // No need to sleep for this test. out = inp; =} } + reactor Destination { - state s:number(0); - input[4] inp:number; + input[4] inp: number + + state s: number(0) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -36,6 +44,7 @@ reactor Destination { } s += 4; =} + reaction(shutdown) {= if (s == 0) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -45,12 +54,13 @@ reactor Destination { } main reactor { - a = new Source(); - t1 = new Computation(); - t2 = new Computation(); - t3 = new Computation(); - t4 = new Computation(); - b = new Destination(); - a.out -> t1.inp, t2.inp, t3.inp, t4.inp; - t1.out, t2.out, t3.out, t4.out -> b.inp; + a = new Source() + t1 = new Computation() + t2 = new Computation() + t3 = new Computation() + t4 = new Computation() + b = new Destination() + + a.out -> t1.inp, t2.inp, t3.inp, t4.inp + t1.out, t2.out, t3.out, t4.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToBank.lf b/test/TypeScript/src/multiport/MultiportToBank.lf index 381154ed24..67ea72e385 100644 --- a/test/TypeScript/src/multiport/MultiportToBank.lf +++ b/test/TypeScript/src/multiport/MultiportToBank.lf @@ -1,9 +1,9 @@ -target TypeScript; +target TypeScript reactor Source { - output[4] out:number; + output[4] out: number - reaction (startup) -> out {= + reaction(startup) -> out {= for (let i = 0 ; i < out.length; i++) { out[i] = i; } @@ -11,9 +11,9 @@ reactor Source { } reactor Sink { - input inp:number; + input inp: number - reaction (inp) {= + reaction(inp) {= console.log("Received " + inp); if (inp != this.getBankIndex()) { util.requestErrorStop("Error: expected " + this.getBankIndex()); @@ -22,7 +22,8 @@ reactor Sink { } main reactor MultiportToBank { - source = new Source(); - sink = new[4] Sink(); - source.out -> sink.inp; + source = new Source() + sink = new[4] Sink() + + source.out -> sink.inp } diff --git a/test/TypeScript/src/multiport/MultiportToBankAfter.lf b/test/TypeScript/src/multiport/MultiportToBankAfter.lf index abe2ef1a37..a0a2ec7ddf 100644 --- a/test/TypeScript/src/multiport/MultiportToBankAfter.lf +++ b/test/TypeScript/src/multiport/MultiportToBankAfter.lf @@ -1,18 +1,22 @@ -// Check multiport output to bank of recipients where the width of the bank is inferred. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(2)) { - output[width] out:number; +// Check multiport output to bank of recipients where the width of the bank is +// inferred. +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(2)) { + output[width] out: number + reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { out[i] = i; } =} } + reactor Destination { - input inp:number; - state received:boolean(false); + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received " + inp + "."); if (this.getBankIndex() != inp) { @@ -25,6 +29,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { util.reportError("ERROR: Destination " + this.getBankIndex() + " received no input!", ); @@ -33,8 +38,9 @@ reactor Destination { =} } -main reactor(width:number(3)) { - a = new Source(width = width); - b = new[width] Destination(); - a.out -> b.inp after 1 sec; // Width of the bank of delays will be inferred. +main reactor(width: number(3)) { + a = new Source(width = width) + b = new[width] Destination() + + a.out -> b.inp after 1 sec // Width of the bank of delays will be inferred. } diff --git a/test/TypeScript/src/multiport/MultiportToBankDouble.lf b/test/TypeScript/src/multiport/MultiportToBankDouble.lf index 41b44f7294..200db51890 100644 --- a/test/TypeScript/src/multiport/MultiportToBankDouble.lf +++ b/test/TypeScript/src/multiport/MultiportToBankDouble.lf @@ -1,26 +1,33 @@ -// Check multiport output to bank of recipients where the source -// has two reactions that write to the output. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to bank of recipients where the source has two +// reactions that write to the output. +target TypeScript { timeout: 2 sec } + reactor Source { - output[3] out:number; // Connected to a bank of Destination reactors + output[3] out: number // Connected to a bank of Destination reactors + reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { out[i] = i; } =} - // Test also that multiple appearances of the same effect port - // do not result in multiple allocations of memory for the port. - reaction(startup) -> out {= // Contents of the reactions does not matter (either could be empty) + + // Test also that multiple appearances of the same effect port do not result + // in multiple allocations of memory for the port. + reaction(startup) -> + out + {= // Contents of the reactions does not matter (either could be empty) + // Contents of the reactions does not matter (either could be empty) for (let i = 0; i < out.length; i++) { out[i] = i * 2; } =} } + reactor Destination { - input inp:number; - state received:boolean(false); + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received " + inp + "."); if (this.getBankIndex() * 2 != inp) { @@ -28,6 +35,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { util.reportError("ERROR: Destination " + this.getBankIndex() + " received no input!"); @@ -37,7 +45,8 @@ reactor Destination { } main reactor { - a = new Source(); - b = new[3] Destination(); - a.out -> b.inp; + a = new Source() + b = new[3] Destination() + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToBankHierarchy.lf b/test/TypeScript/src/multiport/MultiportToBankHierarchy.lf index b97a3ee682..fd65d7e0c7 100644 --- a/test/TypeScript/src/multiport/MultiportToBankHierarchy.lf +++ b/test/TypeScript/src/multiport/MultiportToBankHierarchy.lf @@ -1,19 +1,22 @@ -// Check multiport output to bank of recipients. -// Here, the bank is smaller than the width of the sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to bank of recipients. Here, the bank is smaller than +// the width of the sending port. +target TypeScript { timeout: 2 sec } + reactor Source { - output[3] out:number; + output[3] out: number + reaction(startup) -> out {= for(let i = 0; i < out.length; i++) { out[i] = i; } =} } + reactor Destination { - input inp:number; - state received:boolean(false); + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Destination " + this.getBankIndex() + " received " + inp + "."); if (this.getBankIndex() != inp) { @@ -21,6 +24,7 @@ reactor Destination { } received = true; =} + reaction(shutdown) {= if (!received) { util.reportError("ERROR: Destination " + this.getBankIndex() + " received no input!"); @@ -28,14 +32,18 @@ reactor Destination { console.log("Success."); =} } + reactor Container { - input[3] inp:number; - c = new[3] Destination(); - inp -> c.inp; + input[3] inp: number + + c = new[3] Destination() + + inp -> c.inp } main reactor MultiportToBankHierarchy { - a = new Source(); - b = new Container(); - a.out -> b.inp; + a = new Source() + b = new Container() + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToHierarchy.lf b/test/TypeScript/src/multiport/MultiportToHierarchy.lf index 051524fe12..17ceacaa93 100644 --- a/test/TypeScript/src/multiport/MultiportToHierarchy.lf +++ b/test/TypeScript/src/multiport/MultiportToHierarchy.lf @@ -1,21 +1,27 @@ -// Check multiport output to multiport input, where the latter is a hierarchical reactor. -// Note that the destination reactor has width wider than the sender, so one input is dangling. -target TypeScript { - timeout: 2 sec, -}; -reactor Source(width:number(4)) { - timer t(0, 200 msec); - output[width] out:number; - state s:number(0); +// Check multiport output to multiport input, where the latter is a hierarchical +// reactor. Note that the destination reactor has width wider than the sender, +// so one input is dangling. +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(4)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < 4; i++) { out[i] = s++; } =} } -reactor Destination(width:number(4)) { - state s:number(6); - input[width] inp:number; + +reactor Destination(width: number(4)) { + input[width] inp: number + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -28,6 +34,7 @@ reactor Destination(width:number(4)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -35,14 +42,18 @@ reactor Destination(width:number(4)) { console.log("Success."); =} } -reactor Container(width:number(4)) { - input[width] inp:number; - dst = new Destination(); - inp -> dst.inp; + +reactor Container(width: number(4)) { + input[width] inp: number + + dst = new Destination() + + inp -> dst.inp } -main reactor MultiportToHierarchy(width:number(4)) { - a = new Source(width=width); - b = new Container(width=width); - a.out -> b.inp; +main reactor MultiportToHierarchy(width: number(4)) { + a = new Source(width = width) + b = new Container(width = width) + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToMultiport.lf b/test/TypeScript/src/multiport/MultiportToMultiport.lf index 054e0bdb48..a99270d2e8 100644 --- a/test/TypeScript/src/multiport/MultiportToMultiport.lf +++ b/test/TypeScript/src/multiport/MultiportToMultiport.lf @@ -1,9 +1,9 @@ -target TypeScript; +target TypeScript reactor Source { - output[4] out:number; + output[4] out: number - reaction (startup) -> out {= + reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { out[i] = i; } @@ -11,10 +11,11 @@ reactor Source { } reactor Sink { - input[4] inp:number; - state received:boolean(false); + input[4] inp: number - reaction (inp) {= + state received: boolean(false) + + reaction(inp) {= for (let i = 0; i < inp.length; i++) { console.log("Received " + inp[i]); received = true; @@ -23,7 +24,8 @@ reactor Sink { } } =} - reaction (shutdown) {= + + reaction(shutdown) {= if (!received) { util.requestErrorStop("ERROR: No data received!!"); } @@ -32,7 +34,8 @@ reactor Sink { } main reactor MultiportToMultiport { - source = new Source(); - sink = new Sink(); - source.out -> sink.inp; + source = new Source() + sink = new Sink() + + source.out -> sink.inp } diff --git a/test/TypeScript/src/multiport/MultiportToMultiport2.lf b/test/TypeScript/src/multiport/MultiportToMultiport2.lf index 239d510a00..30f3521d89 100644 --- a/test/TypeScript/src/multiport/MultiportToMultiport2.lf +++ b/test/TypeScript/src/multiport/MultiportToMultiport2.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target TypeScript; +// Test multiport to multiport connections. See also MultiportToMultiport. +target TypeScript -reactor Source(width:number(2)) { - output[width] out:number; - reaction (startup) -> out {= +reactor Source(width: number(2)) { + output[width] out: number + + reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { out[i] = i; } =} } -reactor Destination(width:number(2)) { - input[width] inp:number; - reaction (inp) {= +reactor Destination(width: number(2)) { + input[width] inp: number + + reaction(inp) {= for (let i = 0; i < inp.length; i++) { console.log("Received on channel " + i + ": " + inp[i]); // NOTE: For testing purposes, this assumes the specific @@ -26,8 +27,9 @@ reactor Destination(width:number(2)) { } main reactor MultiportToMultiport2 { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.inp; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToMultiport2After.lf b/test/TypeScript/src/multiport/MultiportToMultiport2After.lf index 208c1686eb..e8260a8b71 100644 --- a/test/TypeScript/src/multiport/MultiportToMultiport2After.lf +++ b/test/TypeScript/src/multiport/MultiportToMultiport2After.lf @@ -1,19 +1,20 @@ -// Test multiport to multiport connections. -// See also MultiportToMultiport. -target TypeScript; +// Test multiport to multiport connections. See also MultiportToMultiport. +target TypeScript -reactor Source(width:number(2)) { - output[width] out:number; - reaction (startup) -> out {= +reactor Source(width: number(2)) { + output[width] out: number + + reaction(startup) -> out {= for (let i = 0; i < out.length; i++) { out[i] = i; } =} } -reactor Destination(width:number(2)) { - input[width] inp:number; - reaction (inp) {= +reactor Destination(width: number(2)) { + input[width] inp: number + + reaction(inp) {= for (let i = 0; i < inp.length; i++) { if (inp[i] !== undefined) { let value = inp[i]; @@ -33,8 +34,9 @@ reactor Destination(width:number(2)) { } main reactor { - a1 = new Source(width = 3); - a2 = new Source(width = 2); - b = new Destination(width = 5); - a1.out, a2.out -> b.inp after 1 sec; + a1 = new Source(width = 3) + a2 = new Source(width = 2) + b = new Destination(width = 5) + + a1.out, a2.out -> b.inp after 1 sec } diff --git a/test/TypeScript/src/multiport/MultiportToMultiportArray.lf b/test/TypeScript/src/multiport/MultiportToMultiportArray.lf index 72e9467457..808bf5c1ac 100644 --- a/test/TypeScript/src/multiport/MultiportToMultiportArray.lf +++ b/test/TypeScript/src/multiport/MultiportToMultiportArray.lf @@ -1,12 +1,14 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target TypeScript { timeout: 2 sec } + reactor Source { - timer t(0, 200 msec); - output[2] out:{=Array=}; - state s:number(0); + output[2] out: {= Array =} + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for(let i = 0; i < 2; i++) { // Dynamically allocate a new output array @@ -22,8 +24,10 @@ reactor Source { } reactor Destination { - state s:number(15); - input[2] inp:{=Array=}; + input[2] inp: {= Array =} + + state s: number(15) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -40,6 +44,7 @@ reactor Destination { } s += 36; =} + reaction(shutdown) {= if (s <= 15) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -49,7 +54,8 @@ reactor Destination { } main reactor MultiportToMultiportArray { - a = new Source(); - b = new Destination(); - a.out -> b.inp; + a = new Source() + b = new Destination() + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToMultiportParameter.lf b/test/TypeScript/src/multiport/MultiportToMultiportParameter.lf index df67a3f57c..4d293fe686 100644 --- a/test/TypeScript/src/multiport/MultiportToMultiportParameter.lf +++ b/test/TypeScript/src/multiport/MultiportToMultiportParameter.lf @@ -1,20 +1,25 @@ // Check multiport output to multiport input. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(1)) { - timer t(0, 200 msec); - output[width] out:number; - state s:number(0); +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(1)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= for (let i = 0; i < out.length; i++) { out[i] = s++; } =} } -reactor Destination(width:number(1)) { - state s:number(6); - input[width] inp:number; // Width is one larger than that of the source. + +reactor Destination(width: number(1)) { + input[width] inp: number // Width is one larger than that of the source. + + state s: number(6) + reaction(inp) {= let sum = 0; for (let i = 0; i < inp.length; i++) { @@ -26,6 +31,7 @@ reactor Destination(width:number(1)) { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); @@ -33,8 +39,10 @@ reactor Destination(width:number(1)) { console.log("Success."); =} } -main reactor (width:number(4)) { - a = new Source(width = width); - b = new Destination(width = width); - a.out -> b.inp; + +main reactor(width: number(4)) { + a = new Source(width = width) + b = new Destination(width = width) + + a.out -> b.inp } diff --git a/test/TypeScript/src/multiport/MultiportToPort.lf b/test/TypeScript/src/multiport/MultiportToPort.lf index 987167667c..d0aa6f2ee4 100644 --- a/test/TypeScript/src/multiport/MultiportToPort.lf +++ b/test/TypeScript/src/multiport/MultiportToPort.lf @@ -1,10 +1,10 @@ -// Check multiport output to multiport input. -// Destination port is wider than sending port. -target TypeScript { - timeout: 2 sec -}; +// Check multiport output to multiport input. Destination port is wider than +// sending port. +target TypeScript { timeout: 2 sec } + reactor Source { - output[2] out:number; + output[2] out: number + reaction(startup) -> out {= for(let i = 0; i < out.length; i++) { console.log("Source sending " + i); @@ -12,9 +12,12 @@ reactor Source { } =} } -reactor Destination(expected:number(0)) { - input inp:number; - state received:boolean(false); + +reactor Destination(expected: number(0)) { + input inp: number + + state received: boolean(false) + reaction(inp) {= console.log("Received " + inp); received = true; @@ -22,6 +25,7 @@ reactor Destination(expected:number(0)) { util.requestErrorStop("FAILURE: Expected " + expected); } =} + reaction(shutdown) {= if (!received) { util.requestErrorStop("ERROR: Destination received no input!"); @@ -31,8 +35,9 @@ reactor Destination(expected:number(0)) { } main reactor MultiportToPort { - a = new Source(); - b1 = new Destination(); - b2 = new Destination(expected = 1); - a.out -> b1.inp, b2.inp; + a = new Source() + b1 = new Destination() + b2 = new Destination(expected = 1) + + a.out -> b1.inp, b2.inp } diff --git a/test/TypeScript/src/multiport/MultiportToReaction.lf b/test/TypeScript/src/multiport/MultiportToReaction.lf index bcee23009c..dc0855e170 100644 --- a/test/TypeScript/src/multiport/MultiportToReaction.lf +++ b/test/TypeScript/src/multiport/MultiportToReaction.lf @@ -1,11 +1,13 @@ // Check reaction to multiport output of a contained reactor. -target TypeScript { - timeout: 2 sec -}; -reactor Source(width:number(1)) { - timer t(0, 200 msec); - state s:number(0); - output[width] out:number; +target TypeScript { timeout: 2 sec } + +reactor Source(width: number(1)) { + output[width] out: number + + timer t(0, 200 msec) + + state s: number(0) + reaction(t) -> out {= console.log("Sending."); for (let i = 0; i < out.length; i++) { @@ -13,8 +15,12 @@ reactor Source(width:number(1)) { } =} } + main reactor MultiportToReaction { - state s:number(6); + b = new Source(width = 4) + + state s: number(6) + reaction(b.out) {= let sum = 0; for (let i = 0; i < b.out.length; i++) { @@ -27,11 +33,11 @@ main reactor MultiportToReaction { } s += 16; =} + reaction(shutdown) {= if (s <= 6) { util.reportError("ERROR: Destination received no input!"); } console.log("Success."); =} - b = new Source(width = 4); } diff --git a/test/TypeScript/src/multiport/NestedBanks.lf b/test/TypeScript/src/multiport/NestedBanks.lf index f8940c9d8a..3f23e2a270 100644 --- a/test/TypeScript/src/multiport/NestedBanks.lf +++ b/test/TypeScript/src/multiport/NestedBanks.lf @@ -3,36 +3,47 @@ * @author Edward A. Lee * @author Hokeun Kim */ -target TypeScript; +target TypeScript + main reactor { - a = new[2] A(); - c = new[3] C(); - d = new D(); - e = new E(); + a = new[2] A() + c = new[3] C() + d = new D() + e = new E() - (a.x)+ -> c.z, d.u, e.t; + (a.x)+ -> c.z, d.u, e.t } + reactor A { - output[4] x:number; - b = new[2] B(aBankIndex = {=this.getBankIndex()=}); - b.y -> x; + output[4] x: number + + b = new[2] B(aBankIndex = {= this.getBankIndex() =}) + + b.y -> x } -reactor B(aBankIndex:number(0)) { - output[2] y:number; + +reactor B(aBankIndex: number(0)) { + output[2] y: number + reaction(startup) -> y {= let base = aBankIndex * 4 + this.getBankIndex() * 2; y[0] = base; y[1] = base + 1; =} } + reactor C { - input[2] z:number; - f = new F(cBankIndex = {=this.getBankIndex()=}); - g = new G(cBankIndex = {=this.getBankIndex()=}); - z -> f.w, g.s; + input[2] z: number + + f = new F(cBankIndex = {= this.getBankIndex() =}) + g = new G(cBankIndex = {= this.getBankIndex() =}) + + z -> f.w, g.s } + reactor D { - input[2] u:number; + input[2] u: number + reaction(u) {= for (let i = 0; i < u.length; i++) { console.log("d.u[" + i + "] received " + u[i] + "."); @@ -42,16 +53,20 @@ reactor D { } =} } + reactor E { - input[8] t:number; + input[8] t: number + reaction(t) {= for (let i = 0; i < t.length; i++) { console.log("e.t[" + i + "] received " + t[i] + "."); } =} } -reactor F(cBankIndex:number(0)) { - input w:number; + +reactor F(cBankIndex: number(0)) { + input w: number + reaction(w) {= console.log("c[" + cBankIndex + "].f.w received " + w + "."); if (w != cBankIndex * 2) { @@ -59,8 +74,10 @@ reactor F(cBankIndex:number(0)) { } =} } -reactor G(cBankIndex:number(0)) { - input s:number; + +reactor G(cBankIndex: number(0)) { + input s: number + reaction(s) {= console.log("c[" + cBankIndex + "].g.s received " + s + "."); if (s != cBankIndex * 2 + 1) { diff --git a/test/TypeScript/src/multiport/PipelineAfter.lf b/test/TypeScript/src/multiport/PipelineAfter.lf index d759895190..6cce7d7a12 100644 --- a/test/TypeScript/src/multiport/PipelineAfter.lf +++ b/test/TypeScript/src/multiport/PipelineAfter.lf @@ -1,26 +1,23 @@ -target TypeScript; +target TypeScript reactor Source { - output out:number; + output out: number - reaction (startup) -> out {= - out = 40; - =} + reaction(startup) -> out {= out = 40; =} } reactor Compute { - input inp:number; - output out:number; + input inp: number - reaction (inp) -> out {= - out = (inp as number) + 2; - =} + output out: number + + reaction(inp) -> out {= out = (inp as number) + 2; =} } reactor Sink { - input inp:number; + input inp: number - reaction (inp) {= + reaction(inp) {= console.log("Received " + inp); if (inp != 42) { util.requestErrorStop("ERROR: expected 42!"); @@ -29,13 +26,12 @@ reactor Sink { util.requestErrorStop("ERROR: Expected to receive input after one second."); } =} - } main reactor { - source = new Source(); - compute = new Compute(); - sink = new Sink(); + source = new Source() + compute = new Compute() + sink = new Sink() - source.out, compute.out -> compute.inp, sink.inp after 500 msec; + source.out, compute.out -> compute.inp, sink.inp after 500 msec } diff --git a/test/TypeScript/src/multiport/ReactionToContainedBank.lf b/test/TypeScript/src/multiport/ReactionToContainedBank.lf index 8d7a151498..509acc9392 100644 --- a/test/TypeScript/src/multiport/ReactionToContainedBank.lf +++ b/test/TypeScript/src/multiport/ReactionToContainedBank.lf @@ -1,14 +1,14 @@ // Test reaction sending messages to a contained bank of reactors. -target TypeScript { - timeout: 1 sec -}; -import TestCount from "../lib/TestCount.lf"; +target TypeScript { timeout: 1 sec } -main reactor ReactionToContainedBank(width:number(2)) { - timer t(0, 100 msec); - state count:number(1); +import TestCount from "../lib/TestCount.lf" - test = new[width] TestCount(numInputs = 11); +main reactor ReactionToContainedBank(width: number(2)) { + timer t(0, 100 msec) + + test = new[width] TestCount(numInputs = 11) + + state count: number(1) reaction(t) -> test.inp {= for (let i = 0; i < width; i++) { diff --git a/test/TypeScript/src/multiport/ReactionsToNested.lf b/test/TypeScript/src/multiport/ReactionsToNested.lf index cef6d0a268..a25787ad65 100644 --- a/test/TypeScript/src/multiport/ReactionsToNested.lf +++ b/test/TypeScript/src/multiport/ReactionsToNested.lf @@ -1,11 +1,12 @@ -// This test connects a simple counting source to tester -// that checks against its own count. -target TypeScript { - timeout: 1 sec -}; -reactor T(expected:number(0)) { - input z:number; - state received:boolean(false); +// This test connects a simple counting source to tester that checks against its +// own count. +target TypeScript { timeout: 1 sec } + +reactor T(expected: number(0)) { + input z: number + + state received: boolean(false) + reaction(z) {= console.log("T received " + z); received = true; @@ -13,6 +14,7 @@ reactor T(expected:number(0)) { util.requestErrorStop("Expected " + expected); } =} + reaction(shutdown) {= if (!received) { util.reportError("No input received"); @@ -21,18 +23,18 @@ reactor T(expected:number(0)) { } reactor D { - input[2] y:number; - t1 = new T(expected = 42); - t2 = new T(expected = 43); - y -> t1.z, t2.z; + input[2] y: number + + t1 = new T(expected = 42) + t2 = new T(expected = 43) + + y -> t1.z, t2.z } main reactor { - d = new D(); - reaction(startup) -> d.y {= - d.y[0] = 42; - =} - reaction(startup) -> d.y {= - d.y[1] = 43; - =} + d = new D() + + reaction(startup) -> d.y {= d.y[0] = 42; =} + + reaction(startup) -> d.y {= d.y[1] = 43; =} } diff --git a/test/TypeScript/src/serialization/ProtoNoPacking.lf b/test/TypeScript/src/serialization/ProtoNoPacking.lf index b5ea7bb1a0..0b181a4f67 100644 --- a/test/TypeScript/src/serialization/ProtoNoPacking.lf +++ b/test/TypeScript/src/serialization/ProtoNoPacking.lf @@ -1,24 +1,22 @@ -/** This example creates a Protocol Buffer message and passes it to - * another reactor without packing and unpacking. This demonstrates - * that local communication, within one shared-memory machine, need - * not incur the overhead of packing and unpacking. +/** + * This example creates a Protocol Buffer message and passes it to another + * reactor without packing and unpacking. This demonstrates that local + * communication, within one shared-memory machine, need not incur the overhead + * of packing and unpacking. * - * To run this example first install the protocol buffers compiler - * from https://github.com/protocolbuffers/protobuf. It is also - * available from homebrew on a Mac via + * To run this example first install the protocol buffers compiler from + * https://github.com/protocolbuffers/protobuf. It is also available from + * homebrew on a Mac via * - * $ brew install protobuf - * - * Building protobuf from source is slow, so avoid doing that - * if possible. + * $ brew install protobuf * + * Building protobuf from source is slow, so avoid doing that if possible. */ -target TypeScript { - protobufs: ProtoHelloWorld.proto -}; +target TypeScript { protobufs: ProtoHelloWorld.proto } reactor SourceProto { - output out:ProtoHelloWorld.ProtoHelloWorld; + output out: ProtoHelloWorld.ProtoHelloWorld + reaction(startup) -> out {= // The contents of a compiled proto file are imported in // TypeScript as "import * as <.protoFileName>". So the constructor @@ -32,7 +30,8 @@ reactor SourceProto { } reactor SinkProto { - input x:ProtoHelloWorld.ProtoHelloWorld; + input x: ProtoHelloWorld.ProtoHelloWorld + reaction(x) {= if (x !== undefined) { console.log(`Received: name=${x.getName()}, number=${x.getNumber()}.`) @@ -41,7 +40,8 @@ reactor SinkProto { } main reactor ProtoNoPacking { - s = new SourceProto(); - d = new SinkProto(); - s.out -> d.x; + s = new SourceProto() + d = new SinkProto() + + s.out -> d.x } diff --git a/test/TypeScript/src/target/AfterNoTypes.lf b/test/TypeScript/src/target/AfterNoTypes.lf index 6f637cd486..66edbb75e3 100644 --- a/test/TypeScript/src/target/AfterNoTypes.lf +++ b/test/TypeScript/src/target/AfterNoTypes.lf @@ -1,30 +1,36 @@ -// This test demonstrates that after can be used on connections -// with ports that have no types. -target TypeScript { - fast: false, - timeout: 3 sec -}; +// This test demonstrates that after can be used on connections with ports that +// have no types. +target TypeScript { fast: false, timeout: 3 sec } reactor Foo { - input x; - output y; + input x + + output y + reaction(x) -> y {= // Do something =} } + reactor Print { - state expected_time:time(10 msec); - input x; + input x + + state expected_time: time(10 msec) + reaction(x) {= // Do something =} } + main reactor { - f = new Foo(); - p = new Print(); - timer t(0, 1 sec); + timer t(0, 1 sec) + + f = new Foo() + p = new Print() + + f.y -> p.x after 10 msec + reaction(t) -> f.x {= // Do something =} - f.y -> p.x after 10 msec; } From ad1e196d6829054a5afa07b6ab1cab33c6e6da1a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 14:41:51 -0700 Subject: [PATCH 094/130] [formatting] Clean up stray whitespace. This problem appeared when there were multiple comments appearing in sequence. --- .../src/org/lflang/ast/FormattingUtils.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 4cdbcaa994..412d41df87 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -102,19 +102,18 @@ static String lineWrapComments( StringBuilder current = new StringBuilder(); for (String comment : comments) { if (comment.stripLeading().startsWith("/*")) { - ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)) - .append("\n"); + if (!ret.isEmpty() && !current.isEmpty()) ret.append("\n"); + ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); current.setLength(0); - ret.append(lineWrapComment(comment, width, singleLineCommentPrefix)).append("\n"); + if (!ret.isEmpty()) ret.append("\n"); + ret.append(lineWrapComment(comment.strip(), width, singleLineCommentPrefix)); } else { - current.append(comment).append("\n"); + if (!current.isEmpty()) current.append("\n"); + current.append(comment.strip()); } } - if (!current.isEmpty()) { - ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); - } else if (!ret.isEmpty()) { - ret.deleteCharAt(ret.length() - 1); // Delete final newline - } + if (!ret.isEmpty() && !current.isEmpty()) ret.append("\n"); + ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); return ret.toString(); } static String lineWrapComment(String comment, int width, String singleLineCommentPrefix) { From 1da71239699e7b86ee659a0fe67ecc14e8fd63ff Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 16:12:50 -0700 Subject: [PATCH 095/130] [formatting] Comment code; use Linux-style EOL. --- org.lflang/src/org/lflang/ASTUtils.java | 3 - .../src/org/lflang/ast/FormattingUtils.java | 53 ++++++--- .../src/org/lflang/ast/MalleableString.java | 105 ++++++++++++++++-- org.lflang/src/org/lflang/ast/ToLf.java | 49 +++++--- .../src/org/lflang/generator/CodeBuilder.java | 2 +- .../src/org/lflang/generator/Position.java | 2 +- 6 files changed, 167 insertions(+), 47 deletions(-) diff --git a/org.lflang/src/org/lflang/ASTUtils.java b/org.lflang/src/org/lflang/ASTUtils.java index 588afa17b3..1398ac385f 100644 --- a/org.lflang/src/org/lflang/ASTUtils.java +++ b/org.lflang/src/org/lflang/ASTUtils.java @@ -1210,9 +1210,6 @@ public static boolean isOfTimeType(Parameter param) { return t.isTime && !t.isList; } - - - /** * Given a parameter, return its initial value. * The initial value is a list of instances of Expressions. diff --git a/org.lflang/src/org/lflang/ast/FormattingUtils.java b/org.lflang/src/org/lflang/ast/FormattingUtils.java index 412d41df87..73c6218b46 100644 --- a/org.lflang/src/org/lflang/ast/FormattingUtils.java +++ b/org.lflang/src/org/lflang/ast/FormattingUtils.java @@ -65,6 +65,10 @@ public static String render(EObject object, int lineLength) { + "\n" + optimizedRendering.rendering(); } + /** + * Return the prefix that the formatter should use to mark the start of a + * single-line comment. + */ private static String getSingleLineCommentPrefix(EObject object) { if (object instanceof Model model) { var targetDecl = ASTUtils.targetDecl(model); @@ -81,6 +85,9 @@ private static String getSingleLineCommentPrefix(EObject object) { */ public static String render(EObject object) { return render(object, DEFAULT_LINE_LENGTH); } + /** + * Return the number of characters appearing in columns exceeding {@code lineLength}. + */ private static ToLongFunction countCharactersViolatingLineLength(int lineLength) { return s -> s.lines().mapToInt(it -> Math.max(0, it.length() - lineLength)).sum(); } @@ -91,7 +98,8 @@ private static long countNewlines(String s) { /** * Break lines at spaces so that each line is no more than {@code width} - * columns long, if possible. Normalize whitespace. + * columns long, if possible. Normalize whitespace. Merge consecutive + * single-line comments. */ static String lineWrapComments( List comments, @@ -116,15 +124,16 @@ static String lineWrapComments( ret.append(lineWrapComment(current.toString(), width, singleLineCommentPrefix)); return ret.toString(); } - static String lineWrapComment(String comment, int width, String singleLineCommentPrefix) { + /** Wrap lines. Do not merge lines that start with weird characters. */ + private static String lineWrapComment(String comment, int width, String singleLineCommentPrefix) { width = Math.max(width, MINIMUM_COMMENT_WIDTH_IN_COLUMNS); List> paragraphs = Arrays.stream( comment.strip() .replaceAll("^/?((\\*|//|#)\\s*)+", "") .replaceAll("\\s*\\*/$", "") - .replaceAll("(?<=" + System.lineSeparator() + ")\\h*(\\*|//|#)\\h*", "") - .split(String.format("(%n\\s*){2,}")) - ).map(s -> Arrays.stream(s.split("((\r\n?)|\n)\\s*(?=[@#$%^&*\\-+=:;<>/])"))) + .replaceAll("(?<=(\\r\\n|\\r|\\n))\\h*(\\*|//|#)\\h*", "") + .split("(\n\\s*){2,}") + ).map(s -> Arrays.stream(s.split("(\\r\\n|\\r|\\n)\\h*(?=[@#$%^&*\\-+=:;<>/])"))) .map(stream -> stream.map(s -> s.replaceAll("\\s+", " "))) .map(Stream::toList) .toList(); @@ -134,12 +143,18 @@ static String lineWrapComment(String comment, int width, String singleLineCommen ) { return String.format("/** %s */", paragraphs.get(0).get(0)); } - return String.format("/**%n%s%n */", lineWrapComment(paragraphs, width, " * ")); + return String.format("/**\n%s\n */", lineWrapComment(paragraphs, width, " * ")); } return lineWrapComment(paragraphs, width, singleLineCommentPrefix + " "); } - static String lineWrapComment( + /** + * Wrap lines. + * @param paragraphs A list of lists of subparagraphs. + * @param width The preferred maximum number of columns per line. + * @param linePrefix A string to prepend to each line of comment. + */ + private static String lineWrapComment( List> paragraphs, int width, String linePrefix @@ -151,11 +166,12 @@ static String lineWrapComment( return paragraphs.stream() .map(paragraph -> wrapLines(paragraph, widthAfterPrefix) .map(s -> (linePrefix + s.stripLeading()).stripTrailing()) - .collect(Collectors.joining(System.lineSeparator())) - ).collect(Collectors.joining(String.format("%n%s%n", linePrefix.stripTrailing()))); + .collect(Collectors.joining("\n")) + ).collect(Collectors.joining(String.format("\n%s\n", linePrefix.stripTrailing()))); } - static Stream wrapLines(List subparagraphs, int width) { + /** Wrap a given paragraph. */ + private static Stream wrapLines(List subparagraphs, int width) { var ret = new ArrayList(); for (String s : subparagraphs) { int numCharactersProcessed = 0; @@ -187,7 +203,9 @@ static Stream wrapLines(List subparagraphs, int width) { * appear on their own line. * @param keepCommentsOnSameLine Whether to make a best-effort attempt to * keep the comment on the same line as the associated string. - * + * @param singleLineCommentPrefix The prefix that marks the start of a + * single-line comment. + * @return Whether the comment placement succeeded. */ static boolean placeComment( List comment, @@ -201,25 +219,26 @@ static boolean placeComment( String wrapped = FormattingUtils.lineWrapComments(comment, width, singleLineCommentPrefix); if (keepCommentsOnSameLine && wrapped.lines().count() == 1 && !wrapped.startsWith("/**")) { for (int j = i; j < components.size(); j++) { - if (components.get(j).contains(System.lineSeparator())) { + if (components.get(j).contains("\n")) { components.set(j, components.get(j).replaceFirst( - System.lineSeparator(), - String.format(" %s%n", wrapped) + "\n", + String.format(" %s\n", wrapped) )); return true; } } } for (int j = i - 1; j >= 0; j--) { - if (components.get(j).endsWith(System.lineSeparator())) { - components.set(j, String.format("%s%s%n", components.get(j), wrapped)); + if (components.get(j).endsWith("\n")) { + components.set(j, String.format("%s%s\n", components.get(j), wrapped)); return true; } } return false; } + /** Normalize end-of-line sequences to the Linux style. */ static String normalizeEol(String s) { - return s.replaceAll("(\\r\\n?)|\\n", System.lineSeparator()); + return s.replaceAll("(\\r\\n?)|\\n", "\n"); } } diff --git a/org.lflang/src/org/lflang/ast/MalleableString.java b/org.lflang/src/org/lflang/ast/MalleableString.java index bd880fd43e..a0374e53ca 100644 --- a/org.lflang/src/org/lflang/ast/MalleableString.java +++ b/org.lflang/src/org/lflang/ast/MalleableString.java @@ -20,10 +20,23 @@ public abstract class MalleableString { protected List comments = new ArrayList<>(); + /** Return this, indented by one more level. */ public MalleableString indent() { return new Indented(this); } + /** + * Change the state of this such that the badness of the supplied render + * result is minimized. + * @param providedRender A supplier of render results that should be + * optimized. + * @param badness A badness computer for render results. + * @param width The number of columns permitted for this, excluding + * indentation applied to the whole of this. + * @param indentation The number of spaces used per level of indentation. + * @param singleLineCommentPrefix The prefix that marks the start of a + * single-line comment. + */ public abstract void findBestRepresentation( Supplier providedRender, ToLongFunction badness, @@ -32,23 +45,41 @@ public abstract void findBestRepresentation( String singleLineCommentPrefix ); + /** Return whether any representation of this contains text. */ public abstract boolean isEmpty(); + /** Associate comments with this. */ public MalleableString addComments(Stream comments) { comments.filter(s -> !s.isBlank()).map(String::strip).forEach(this.comments::add); return this; } + /** + * Render this using {@code indentation} spaces per indentation level and + * {@code singleLineCommentMarker} to mark the beginnings of single-line comments. + */ public abstract RenderResult render(int indentation, String singleLineCommentMarker); + /** + * Return an object that can be represented as any one of the given + * alternatives. + */ public static MalleableString anyOf(MalleableString... possibilities) { return new Fork(possibilities); } + /** + * Return an object that can be represented as any one of the given + * alternatives. + */ public static MalleableString anyOf(String... possibilities) { return new Leaf(possibilities); } + /** + * Return an object that can be represented as any one of the given + * alternatives. + */ public static MalleableString anyOf(Object... possibilities) { return new Leaf(objectArrayToString(possibilities)); } @@ -61,14 +92,26 @@ private static String[] objectArrayToString(Object[] objects) { return ret; } + /** + * Build a {@code MalleableString} in a manner analogous to the way we build + * {@code String}s. + */ public static final class Builder { private final List components = new ArrayList<>(); + /** + * Append something that can be represented as any of the given + * possibilities. + */ public Builder append(MalleableString... possibilities) { return insert(Function.identity(), Fork::new, possibilities, components::add); } + /** + * Prepend something that can be represented as any of the given + * possibilities. + */ public Builder prepend(MalleableString... possibilities) { return insert( Function.identity(), @@ -78,19 +121,35 @@ public Builder prepend(MalleableString... possibilities) { ); } + /** + * Append something that can be represented as any of the given + * possibilities. + */ public Builder append(String... content) { return insert(Leaf::new, Leaf::new, content, components::add); } + /** + * Append something that can be represented as any of the given + * possibilities. + */ @SuppressWarnings("UnusedReturnValue") public Builder append(Object... content) { return append(objectArrayToString(content)); } + /** + * Append something that can be represented as any of the given + * possibilities. + */ public MalleableString get() { return new Sequence(ImmutableList.copyOf(components)); } + /** + * Append something that can be represented as any of the given + * possibilities. + */ private Builder insert( Function toMalleableString, Function multiplePossibilitiesRepresenter, @@ -107,6 +166,9 @@ private Builder insert( } } + /** + * Join {@code MalleableString}s together using the given separator. + */ public static final class Joiner implements Collector< MalleableString, Builder, @@ -116,10 +178,20 @@ public static final class Joiner implements Collector< private final Function prependPrefix; private final Function appendSuffix; + /** Join strings using {@code separator}. */ + public Joiner(String separator) { + this(MalleableString.anyOf(separator)); + } + + /** Join strings using {@code separator}. */ public Joiner(MalleableString separator) { this(separator, MalleableString.anyOf(""), MalleableString.anyOf("")); } + /** + * Join strings using {@code separator} and delimit the result with + * {@code prefix} and {@code suffix}. + */ public Joiner(MalleableString separator, MalleableString prefix, MalleableString suffix) { this.appendSeparator = builder -> builder.components.isEmpty() ? builder : builder.append(separator); @@ -127,10 +199,10 @@ public Joiner(MalleableString separator, MalleableString prefix, MalleableString this.appendSuffix = builder -> builder.append(suffix); } - public Joiner(String separator) { - this(MalleableString.anyOf(separator)); - } - + /** + * Join strings using {@code separator} and delimit the result with + * {@code prefix} and {@code suffix}. + */ public Joiner(String separator, String prefix, String suffix) { this( MalleableString.anyOf(separator), @@ -169,6 +241,7 @@ public Set characteristics() { } } + /** The result of rendering a {@code MalleableString}. */ public record RenderResult( Stream unplacedComments, String rendering, @@ -183,6 +256,7 @@ private RenderResult with(Stream moreUnplacedComments) { } } + /** Represent a list of items that should be rendered in sequence. */ private static final class Sequence extends MalleableString { private final ImmutableList components; @@ -271,6 +345,7 @@ public boolean isEmpty() { } } + /** Represent an indented version of another {@code MalleableString}. */ private static final class Indented extends MalleableString { private final MalleableString nested; @@ -320,9 +395,9 @@ public RenderResult render(int indentation, String singleLineCommentPrefix) { this.comments.stream(), ( renderedComments.isBlank() ? result.rendering - : renderedComments + System.lineSeparator() + result.rendering + : renderedComments + "\n" + result.rendering ).replaceAll( - "(?<=" + System.lineSeparator() + "|^)(?=\\h*\\S)", + "(?<=\n|^)(?=\\h*\\S)", " ".repeat(indentation) ), result.levelsOfCommentDisplacement() @@ -330,7 +405,11 @@ public RenderResult render(int indentation, String singleLineCommentPrefix) { } } - private abstract static class MalleableStringImpl extends MalleableString { + /** + * Represent a {@code MalleableString} that admits multiple possible + * representations. + */ + private abstract static class MalleableStringWithAlternatives extends MalleableString { protected abstract List getPossibilities(); private T bestPossibility; @@ -364,6 +443,7 @@ public void findBestRepresentation( } } + /** Return the best representation of this. */ protected T getChosenPossibility() { if (getPossibilities().isEmpty()) { throw new IllegalStateException( @@ -375,7 +455,11 @@ protected T getChosenPossibility() { } } - private static final class Fork extends MalleableStringImpl { + /** + * A {@code Fork} can be represented by multiple possible + * {@code MalleableString}s. + */ + private static final class Fork extends MalleableStringWithAlternatives { private final ImmutableList possibilities; private Fork(MalleableString[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); @@ -396,7 +480,10 @@ public RenderResult render(int indentation, String singleLineCommentPrefix) { } } - private static final class Leaf extends MalleableStringImpl { + /** + * A {@code Leaf} can be represented by multiple possible {@code String}s. + */ + private static final class Leaf extends MalleableStringWithAlternatives { private final ImmutableList possibilities; private Leaf(String[] possibilities) { this.possibilities = ImmutableList.copyOf(possibilities); diff --git a/org.lflang/src/org/lflang/ast/ToLf.java b/org.lflang/src/org/lflang/ast/ToLf.java index e67d6d2614..ef64472028 100644 --- a/org.lflang/src/org/lflang/ast/ToLf.java +++ b/org.lflang/src/org/lflang/ast/ToLf.java @@ -117,6 +117,10 @@ public MalleableString doSwitch(EObject eObject) { ).addComments(followingComments); } + /** + * Return all comments contained by ancestors of {@code node} that belong to + * said ancestors. + */ private static Set getAncestorComments(INode node) { Set ancestorComments = new HashSet<>(); for ( @@ -131,6 +135,10 @@ private static Set getAncestorComments(INode node) { return ancestorComments; } + /** + * Return the next composite sibling of {@code node}, as given by sequential + * application of {@code getNextSibling}. + */ static ICompositeNode getNextCompositeSibling( INode node, Function getNextSibling @@ -145,6 +153,10 @@ static ICompositeNode getNextCompositeSibling( return null; } + /** + * Return the siblings following {@code node} up to (and not including) the + * next non-leaf sibling. + */ private static Stream getFollowingNonCompositeSiblings(ICompositeNode node) { INode sibling = node; List ret = new ArrayList<>(); @@ -157,6 +169,11 @@ private static Stream getFollowingNonCompositeSiblings(ICompositeNode nod return ret.stream(); } + /** + * Return comments that follow {@code node} in the source code and that + * either satisfy {@code filter} or that cannot belong to any following + * sibling of {@code node}. + */ private static Stream getFollowingComments( ICompositeNode node, Predicate filter @@ -198,7 +215,7 @@ private static List getContainedComments(INode node) { public MalleableString caseCode(Code code) { String content = ToText.instance.doSwitch(code).lines() .map(String::stripTrailing) - .collect(Collectors.joining(System.lineSeparator())); + .collect(Collectors.joining("\n")); MalleableString singleLineRepresentation = MalleableString.anyOf( String.format("{= %s =}", content.strip()) ); @@ -295,16 +312,16 @@ public MalleableString caseModel(Model object) { // (preambles+=Preamble)* // (reactors+=Reactor)+ Builder msb = new Builder(); - msb.append(doSwitch(object.getTarget())).append(System.lineSeparator().repeat(2)); - object.getImports().forEach(i -> msb.append(doSwitch(i)).append(System.lineSeparator())); - if (!object.getImports().isEmpty()) msb.append(System.lineSeparator()); + msb.append(doSwitch(object.getTarget())).append("\n".repeat(2)); + object.getImports().forEach(i -> msb.append(doSwitch(i)).append("\n")); + if (!object.getImports().isEmpty()) msb.append("\n"); object.getPreambles().forEach( - p -> msb.append(doSwitch(p)).append(System.lineSeparator().repeat(2)) + p -> msb.append(doSwitch(p)).append("\n".repeat(2)) ); msb.append( object.getReactors().stream().map(this::doSwitch) - .collect(new Joiner(System.lineSeparator().repeat(2))) - ).append(System.lineSeparator()); + .collect(new Joiner("\n".repeat(2))) + ).append("\n"); return msb.get(); } @@ -390,7 +407,7 @@ public MalleableString caseReactor(Reactor object) { ); msb.append(smallFeatures); if (!smallFeatures.isEmpty() && !bigFeatures.isEmpty()) { - msb.append(System.lineSeparator().repeat(1)); + msb.append("\n".repeat(1)); } msb.append(bigFeatures); msb.append("}"); @@ -412,7 +429,7 @@ private MalleableString reactorHeader(Reactor object) { msb.append( MalleableString.anyOf(" extends "), new Builder() - .append(System.lineSeparator()) + .append("\n") .append( MalleableString.anyOf("extends ").indent().indent() ) @@ -684,7 +701,7 @@ public MalleableString caseConnection(Connection object) { } msb.append( "", - MalleableString.anyOf(System.lineSeparator()).indent() + MalleableString.anyOf("\n").indent() ); msb.append(object.isPhysical() ? " ~> " : " ->"); msb.append(minimallyDelimitedList(object.getRightPorts())); @@ -931,11 +948,11 @@ private MalleableString list( return MalleableString.anyOf( rigid, new Builder() - .append(prefix.stripTrailing() + System.lineSeparator()) + .append(prefix.stripTrailing() + "\n") .append(list( - separator.strip() + System.lineSeparator(), + separator.strip() + "\n", "", - System.lineSeparator(), + "\n", nothingIfEmpty, true, items @@ -972,16 +989,16 @@ private MalleableString indentedStatements( return statementListList.stream() .filter(list -> !list.isEmpty()) .map(statementList -> list( - System.lineSeparator().repeat(1 + extraSeparation), + "\n".repeat(1 + extraSeparation), "", - System.lineSeparator(), + "\n", true, true, statementList ) ).collect( new Joiner( - System.lineSeparator().repeat(1 + extraSeparation), + "\n".repeat(1 + extraSeparation), "", "" ) diff --git a/org.lflang/src/org/lflang/generator/CodeBuilder.java b/org.lflang/src/org/lflang/generator/CodeBuilder.java index ba7717c53c..d6abcddb31 100644 --- a/org.lflang/src/org/lflang/generator/CodeBuilder.java +++ b/org.lflang/src/org/lflang/generator/CodeBuilder.java @@ -97,7 +97,7 @@ public void pr(String format, Object... args) { */ public void pr(CharSequence text) { for (String line : (Iterable) () -> text.toString().lines().iterator()) { - code.append(indentation).append(line).append(System.lineSeparator()); + code.append(indentation).append(line).append("\n"); } } diff --git a/org.lflang/src/org/lflang/generator/Position.java b/org.lflang/src/org/lflang/generator/Position.java index 9923785f2d..e26e25a27a 100644 --- a/org.lflang/src/org/lflang/generator/Position.java +++ b/org.lflang/src/org/lflang/generator/Position.java @@ -148,7 +148,7 @@ public int getZeroBasedColumn() { * caused by {@code text} */ public Position plus(String text) { - text += System.lineSeparator(); // Turn line separators into line terminators. + text += "\n"; // Turn line separators into line terminators. String[] lines = text.lines().toArray(String[]::new); if (lines.length == 0) return this; // OK not to copy because Positions are immutable int lastLineLength = lines[lines.length - 1].length(); From 0670e13c98ed88246382b30f1cb4a703b68fe28a Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 16:24:00 -0700 Subject: [PATCH 096/130] [tests] Repair test that wrongly fails LSP tests. --- test/Python/src/ManualDelayedReaction.lf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Python/src/ManualDelayedReaction.lf b/test/Python/src/ManualDelayedReaction.lf index d70f5c9157..1cdb70f2fe 100644 --- a/test/Python/src/ManualDelayedReaction.lf +++ b/test/Python/src/ManualDelayedReaction.lf @@ -28,7 +28,7 @@ reactor Source { timer t - reaction(t) -> out {= out.set(1) =} # reaction(t) -> out after 100 msec {= + reaction(t) -> out {= out.set(1) =} # reaction(t) -> out after 100 msec } reactor Sink { From c0ea3b29cf7ffa60ecc3335b120ef39c33030a72 Mon Sep 17 00:00:00 2001 From: Peter Donovan Date: Fri, 8 Jul 2022 23:49:45 -0700 Subject: [PATCH 097/130] [formatting] Format modal models tests. --- .idea/codeStyles/Project.xml | 16 +- org.lflang/src/org/lflang/ast/ToLf.java | 30 ++- org.lflang/src/org/lflang/ast/ToText.java | 2 +- .../src/org/lflang/util/StringUtil.java | 15 +- test/C/src/modal_models/ConvertCaseTest.lf | 171 +++++++++++------- test/C/src/modal_models/Count3Modes.lf | 30 ++- test/C/src/modal_models/ModalActions.lf | 59 +++--- test/C/src/modal_models/ModalAfter.lf | 82 ++++----- test/C/src/modal_models/ModalCycleBreaker.lf | 56 +++--- .../src/modal_models/ModalNestedReactions.lf | 43 ++--- .../src/modal_models/ModalStartupShutdown.lf | 101 +++++------ test/C/src/modal_models/ModalStateReset.lf | 66 +++---- .../C/src/modal_models/ModalStateResetAuto.lf | 72 ++++---- test/C/src/modal_models/ModalTimers.lf | 44 ++--- .../MultipleOutputFeeder_2Connections.lf | 64 +++---- ...ultipleOutputFeeder_ReactionConnections.lf | 63 +++---- test/C/src/modal_models/util/TraceTesting.lf | 27 +-- .../src/modal_models/ConvertCaseTest.lf | 87 ++++----- test/Python/src/modal_models/Count3Modes.lf | 38 ++-- test/Python/src/modal_models/ModalActions.lf | 71 ++++---- test/Python/src/modal_models/ModalAfter.lf | 82 ++++----- .../src/modal_models/ModalCycleBreaker.lf | 66 +++---- .../src/modal_models/ModalStartupShutdown.lf | 81 ++++----- .../src/modal_models/ModalStateReset.lf | 40 ++-- test/Python/src/modal_models/ModalTimers.lf | 32 ++-- .../MultipleOutputFeeder_2Connections.lf | 48 ++--- ...ultipleOutputFeeder_ReactionConnections.lf | 47 ++--- 27 files changed, 712 insertions(+), 821 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 5a907b1337..055d81ffee 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -24,7 +24,6 @@