From de1a3e23035982f5db98fae95311f678f9f5824c Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 22 Feb 2022 01:34:06 +0000 Subject: [PATCH 1/3] port generatorBase to java --- ...GeneratorBase.xtend => GeneratorBase.java} | 770 +++++++++--------- 1 file changed, 394 insertions(+), 376 deletions(-) rename org.lflang/src/org/lflang/generator/{GeneratorBase.xtend => GeneratorBase.java} (63%) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend b/org.lflang/src/org/lflang/generator/GeneratorBase.java similarity index 63% rename from org.lflang/src/org/lflang/generator/GeneratorBase.xtend rename to org.lflang/src/org/lflang/generator/GeneratorBase.java index 849e11169b..0e3bb1a183 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.xtend +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -22,52 +22,64 @@ * (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.generator - -import java.io.File -import java.nio.file.Files -import java.nio.file.Paths -import java.util.ArrayList -import java.util.HashSet -import java.util.LinkedHashMap -import java.util.LinkedHashSet -import java.util.List -import java.util.Map -import java.util.Set -import java.util.regex.Pattern -import java.util.stream.Collectors -import org.eclipse.core.resources.IMarker -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.util.CancelIndicator -import org.lflang.ASTUtils -import org.lflang.ErrorReporter -import org.lflang.FileConfig -import org.lflang.InferredType -import org.lflang.MainConflictChecker -import org.lflang.Target -import org.lflang.TargetConfig -import org.lflang.TargetConfig.Mode -import org.lflang.TargetProperty.CoordinationType -import org.lflang.TimeUnit -import org.lflang.TimeValue -import org.lflang.federated.FedASTUtils -import org.lflang.federated.FederateInstance -import org.lflang.federated.serialization.SupportedSerializers -import org.lflang.graph.InstantiationGraph -import org.lflang.lf.Action -import org.lflang.lf.Delay -import org.lflang.lf.Instantiation -import org.lflang.lf.LfFactory -import org.lflang.lf.Model -import org.lflang.lf.Parameter -import org.lflang.lf.Reaction -import org.lflang.lf.Reactor -import org.lflang.lf.Time -import org.lflang.lf.Value -import org.lflang.lf.VarRef - -import static extension org.lflang.ASTUtils.* -import org.lflang.validation.AbstractLFValidator +package org.lflang.generator; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.google.common.base.Objects; +import com.google.common.collect.Iterables; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.util.CancelIndicator; +import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.IterableExtensions; +import org.eclipse.xtext.xbase.lib.IteratorExtensions; +import org.eclipse.xtext.xbase.lib.Pair; +import org.lflang.ASTUtils; +import org.lflang.ErrorReporter; +import org.lflang.FileConfig; +import org.lflang.InferredType; +import org.lflang.MainConflictChecker; +import org.lflang.Target; +import org.lflang.TargetConfig; +import org.lflang.TargetConfig.Mode; +import org.lflang.TargetProperty.CoordinationType; +import org.lflang.TimeUnit; +import org.lflang.TimeValue; +import org.lflang.federated.FedASTUtils; +import org.lflang.federated.FederateInstance; +import org.lflang.federated.serialization.SupportedSerializers; +import org.lflang.graph.InstantiationGraph; +import org.lflang.lf.Action; +import org.lflang.lf.Connection; +import org.lflang.lf.Delay; +import org.lflang.lf.Instantiation; +import org.lflang.lf.LfFactory; +import org.lflang.lf.Model; +import org.lflang.lf.Parameter; +import org.lflang.lf.Reaction; +import org.lflang.lf.Reactor; +import org.lflang.lf.Time; +import org.lflang.lf.Value; +import org.lflang.lf.VarRef; +import org.lflang.util.LFCommand; +import org.lflang.validation.AbstractLFValidator; /** * Generator base class for specifying core functionality @@ -79,7 +91,7 @@ * @author{Matt Weber } * @author{Soroush Bateni } */ -abstract class GeneratorBase extends AbstractLFValidator { +public abstract class GeneratorBase extends AbstractLFValidator { //////////////////////////////////////////// //// Public fields. @@ -87,15 +99,15 @@ abstract class GeneratorBase extends AbstractLFValidator { /** * Constant that specifies how to name generated delay reactors. */ - public static val GEN_DELAY_CLASS_NAME = "_lf_GenDelay" + public static String GEN_DELAY_CLASS_NAME = "_lf_GenDelay"; /** * The main (top-level) reactor instance. */ - public ReactorInstance main + public ReactorInstance main; /** A error reporter for reporting any errors or warnings during the code generation */ - public ErrorReporter errorReporter + public ErrorReporter errorReporter; //////////////////////////////////////////// //// Protected fields. @@ -103,31 +115,32 @@ abstract class GeneratorBase extends AbstractLFValidator { /** * The current target configuration. */ - protected var TargetConfig targetConfig = new TargetConfig() - def TargetConfig getTargetConfig() { return this.targetConfig;} + protected TargetConfig targetConfig = new TargetConfig(); + + public TargetConfig getTargetConfig() { return this.targetConfig;} /** * The current file configuration. */ - protected var FileConfig fileConfig + protected FileConfig fileConfig; /** * A factory for compiler commands. */ - protected var GeneratorCommandFactory commandFactory + protected GeneratorCommandFactory commandFactory; /** * Collection of generated delay classes. */ - val delayClasses = new LinkedHashSet() + private LinkedHashSet delayClasses = new LinkedHashSet<>(); /** * Definition of the main (top-level) reactor. * This is an automatically generated AST node for the top-level * reactor. */ - protected Instantiation mainDef - def getMainDef() { return mainDef; } + protected Instantiation mainDef; + public Instantiation getMainDef() { return mainDef; } /** * A list of Reactor definitions in the main resource, including non-main @@ -135,12 +148,12 @@ abstract class GeneratorBase extends AbstractLFValidator { * such a way that each reactor is preceded by any reactor that it instantiates * using a command like `foo = new Foo();` */ - protected var List reactors = new ArrayList + protected List reactors = new ArrayList<>(); /** * The set of resources referenced reactor classes reside in. */ - protected var Set resources = newLinkedHashSet + protected Set resources = new LinkedHashSet<>(); /** * Graph that tracks dependencies between instantiations. @@ -151,7 +164,7 @@ abstract class GeneratorBase extends AbstractLFValidator { * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any * reactor is preceded in the list by reactors that it instantiates. */ - protected var InstantiationGraph instantiationGraph + protected InstantiationGraph instantiationGraph; /** * The set of unordered reactions. An unordered reaction is one that does @@ -164,23 +177,23 @@ abstract class GeneratorBase extends AbstractLFValidator { * state of the containing reactor. To make a reaction unordered, when * the Reaction instance is created, add that instance to this set. */ - protected var Set unorderedReactions = null + protected Set unorderedReactions = null; /** * Map from reactions to bank indices */ - protected var Map reactionBankIndices = null + protected Map reactionBankIndices = null; /** * Keep a unique list of enabled serializers */ - public var HashSet enabledSerializers = new HashSet(); + public HashSet enabledSerializers = new HashSet<>(); /** * Indicates whether or not the current Lingua Franca program * contains a federation. */ - public var boolean isFederated = false + public boolean isFederated = false; // ////////////////////////////////////////// // // Target properties, if they are included. @@ -188,36 +201,36 @@ abstract class GeneratorBase extends AbstractLFValidator { * A list of federate instances or a list with a single empty string * if there are no federates specified. FIXME: Why put a single empty string there? It should be just empty... */ - public var List federates = new ArrayList + public List federates = new ArrayList<>(); /** * A map from federate IDs to federate instances. */ - protected var Map federateByID = new LinkedHashMap() + protected Map federateByID = new LinkedHashMap<>(); /** * A map from instantiations to the federate instances for that instantiation. * If the instantiation has a width, there may be more than one federate instance. */ - protected var Map> federatesByInstantiation + protected Map> federatesByInstantiation; /** * The federation RTI properties, which defaults to 'localhost: 15045'. */ - protected val federationRTIProperties = newLinkedHashMap( - 'host' -> 'localhost', - 'port' -> 0 // Indicator to use the default port, typically 15045. - ) + protected LinkedHashMap federationRTIProperties = CollectionLiterals.newLinkedHashMap( + Pair.of("host", "localhost"), + Pair.of("port", 0) // Indicator to use the default port, typically 15045. + ); /** * Contents of $LF_CLASSPATH, if it was set. */ - protected String classpathLF + protected String classpathLF; /** * The name of the top-level reactor. */ - protected var String topLevelName; // FIXME: remove and use fileConfig.name instead + protected String topLevelName; // FIXME: remove and use fileConfig.name instead // ////////////////////////////////////////// // // Private fields. @@ -225,11 +238,11 @@ abstract class GeneratorBase extends AbstractLFValidator { /** * Create a new GeneratorBase object. */ - new(FileConfig fileConfig, ErrorReporter errorReporter) { - this.fileConfig = fileConfig - this.topLevelName = fileConfig.name - this.errorReporter = errorReporter - this.commandFactory = new GeneratorCommandFactory(errorReporter, fileConfig) + public GeneratorBase(FileConfig fileConfig, ErrorReporter errorReporter) { + this.fileConfig = fileConfig; + this.topLevelName = fileConfig.name; + this.errorReporter = errorReporter; + this.commandFactory = new GeneratorCommandFactory(errorReporter, fileConfig); } // ////////////////////////////////////////// @@ -239,33 +252,35 @@ abstract class GeneratorBase extends AbstractLFValidator { * Store the given reactor in the collection of generated delay classes * and insert it in the AST under the top-level reactors node. */ - def void addDelayClass(Reactor generatedDelay) { + public void addDelayClass(Reactor generatedDelay) { // Record this class, so it can be reused. - this.delayClasses.add(generatedDelay) + delayClasses.add(generatedDelay); // And hook it into the AST. - (fileConfig.resource.allContents.findFirst[it|it instanceof Model] as Model).reactors.add(generatedDelay) + EObject node = IteratorExtensions.findFirst(fileConfig.resource.getAllContents(), Model.class::isInstance); + ((Model) node).getReactors().add(generatedDelay); } /** * Return the generated delay reactor that corresponds to the given class * name if it had been created already, `null` otherwise. */ - def Reactor findDelayClass(String className) { - return this.delayClasses.findFirst[it|it.name.equals(className)] + public Reactor findDelayClass(String className) { + return IterableExtensions.findFirst(delayClasses, it -> it.getName().equals(className)); } /** * If there is a main or federated reactor, then create a synthetic Instantiation * for that top-level reactor and set the field mainDef to refer to it. */ - private def createMainInstantiation() { + private void createMainInstantiation() { // Find the main reactor and create an AST node for its instantiation. - for (reactor : fileConfig.resource.allContents.toIterable.filter(Reactor)) { - if (reactor.isMain || reactor.isFederated) { + Iterable nodes = IteratorExtensions.toIterable(fileConfig.resource.getAllContents()); + for (Reactor reactor : Iterables.filter(nodes, Reactor.class)) { + if (reactor.isMain() || reactor.isFederated()) { // Creating an definition for the main reactor because there isn't one. - this.mainDef = LfFactory.eINSTANCE.createInstantiation() - this.mainDef.setName(reactor.name) - this.mainDef.setReactorClass(reactor) + this.mainDef = LfFactory.eINSTANCE.createInstantiation(); + this.mainDef.setName(reactor.getName()); + this.mainDef.setReactorClass(reactor); } } } @@ -282,41 +297,41 @@ private def createMainInstantiation() { * @param context Context relating to invocation of the code generator. * In stand alone mode, this object is also used to relay CLI arguments. */ - def void doGenerate(Resource resource, LFGeneratorContext context) { + public void doGenerate(Resource resource, LFGeneratorContext context) throws IOException { JavaGeneratorUtils.setTargetConfig( context, JavaGeneratorUtils.findTarget(fileConfig.resource), targetConfig, errorReporter - ) + ); - fileConfig.cleanIfNeeded() + fileConfig.cleanIfNeeded(); - printInfo() + printInfo(); // Clear any IDE markers that may have been created by a previous build. // Markers mark problems in the Eclipse IDE when running in integrated mode. if (errorReporter instanceof EclipseErrorReporter) { - errorReporter.clearMarkers() + ((EclipseErrorReporter) errorReporter).clearMarkers(); } - ASTUtils.setMainName(fileConfig.resource, fileConfig.name) + ASTUtils.setMainName(fileConfig.resource, fileConfig.name); - createMainInstantiation() + createMainInstantiation(); // Check if there are any conflicting main reactors elsewhere in the package. - if (context.mode == Mode.STANDALONE && mainDef !== null) { + if (Objects.equal(context.getMode(), TargetConfig.Mode.STANDALONE) && mainDef != null) { for (String conflict : new MainConflictChecker(fileConfig).conflicts) { - errorReporter.reportError(this.mainDef.reactorClass, "Conflicting main reactor in " + conflict); + errorReporter.reportError(this.mainDef.getReactorClass(), "Conflicting main reactor in " + conflict); } } // Configure the command factory commandFactory.setVerbose(); - if (context.mode == Mode.STANDALONE && context.getArgs().containsKey("quiet")) { + if (Objects.equal(context.getMode(), TargetConfig.Mode.STANDALONE) && context.getArgs().containsKey("quiet")) { commandFactory.setQuiet(); } // This must be done before desugaring delays below. - analyzeFederates(context) + analyzeFederates(context); // Process target files. Copy each of them into the src-gen dir. // FIXME: Should we do this here? I think the Cpp target doesn't support @@ -327,28 +342,28 @@ def void doGenerate(Resource resource, LFGeneratorContext context) { // Collect reactors and create an instantiation graph. // These are needed to figure out which resources we need // to validate, which happens in setResources(). - setReactorsAndInstantiationGraph() + setReactorsAndInstantiationGraph(); - JavaGeneratorUtils.validate(context, fileConfig, instantiationGraph, errorReporter) - val allResources = JavaGeneratorUtils.getResources(reactors) + JavaGeneratorUtils.validate(context, fileConfig, instantiationGraph, errorReporter); + List allResources = JavaGeneratorUtils.getResources(reactors); resources.addAll(allResources.stream() // FIXME: This filter reproduces the behavior of the method it replaces. But why must it be so complicated? Why are we worried about weird corner cases like this? - .filter [it | it != fileConfig.resource || (mainDef !== null && it === mainDef.reactorClass.eResource)] - .map [it | JavaGeneratorUtils.getLFResource(it, fileConfig.getSrcGenBasePath(), context, errorReporter)] + .filter(it -> !Objects.equal(it, fileConfig.resource) || mainDef != null && it == mainDef.getReactorClass().eResource()) + .map(it -> JavaGeneratorUtils.getLFResource(it, fileConfig.getSrcGenBasePath(), context, errorReporter)) .collect(Collectors.toList()) - ) - JavaGeneratorUtils.accommodatePhysicalActionsIfPresent(allResources, target, targetConfig, errorReporter); + ); + JavaGeneratorUtils.accommodatePhysicalActionsIfPresent(allResources, getTarget(), targetConfig, errorReporter); // FIXME: Should the GeneratorBase pull in `files` from imported // resources? // Reroute connections that have delays associated with them via // generated delay reactors. - transformDelays() + transformDelays(); // Invoke these functions a second time because transformations // may have introduced new reactors! - setReactorsAndInstantiationGraph() + setReactorsAndInstantiationGraph(); - enableSupportForSerializationIfApplicable(context.cancelIndicator); + enableSupportForSerializationIfApplicable(context.getCancelIndicator()); } /** @@ -359,22 +374,23 @@ def void doGenerate(Resource resource, LFGeneratorContext context) { * Hence, after this method returns, `this.reactors` will be a list of Reactors such that any * reactor is preceded in the list by reactors that it instantiates. */ - protected def setReactorsAndInstantiationGraph() { + protected void setReactorsAndInstantiationGraph() { // Build the instantiation graph . - this.instantiationGraph = new InstantiationGraph(fileConfig.resource, false) + instantiationGraph = new InstantiationGraph(fileConfig.resource, false); // Topologically sort the reactors such that all of a reactor's instantiation dependencies occur earlier in // the sorted list of reactors. This helps the code generator output code in the correct order. // For example if `reactor Foo {bar = new Bar()}` then the definition of `Bar` has to be generated before // the definition of `Foo`. - this.reactors = this.instantiationGraph.nodesInTopologicalOrder + reactors = instantiationGraph.nodesInTopologicalOrder(); // If there is no main reactor or if all reactors in the file need to be validated, then make sure the reactors // list includes even reactors that are not instantiated anywhere. - if (mainDef === null || fileConfig.context.mode == Mode.LSP_MEDIUM) { - for (r : fileConfig.resource.allContents.toIterable.filter(Reactor)) { - if (!this.reactors.contains(r)) { - this.reactors.add(r); + if (mainDef == null || Objects.equal(fileConfig.context.getMode(), TargetConfig.Mode.LSP_MEDIUM)) { + Iterable nodes = IteratorExtensions.toIterable(fileConfig.resource.getAllContents()); + for (Reactor r : IterableExtensions.filter(nodes, Reactor.class)) { + if (!reactors.contains(r)) { + reactors.add(r); } } } @@ -383,9 +399,9 @@ protected def setReactorsAndInstantiationGraph() { /** * For each involved resource, replace connections with delays with generated delay reactors. */ - private def transformDelays() { - for (r : this.resources) { - r.eResource.insertGeneratedDelays(this) + private void transformDelays() { + for (LFResource r : resources) { + ASTUtils.insertGeneratedDelays(r.eResource, this); } } @@ -396,21 +412,21 @@ private def transformDelays() { * @param targetConfig The targetConfig to read the `files` from. * @param fileConfig The fileConfig used to make the copy and resolve paths. */ - protected def copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { + protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) throws IOException { // Make sure the target directory exists. - val targetDir = this.fileConfig.getSrcGenPath - Files.createDirectories(targetDir) + Path targetDir = fileConfig.getSrcGenPath(); + Files.createDirectories(targetDir); - for (filename : targetConfig.fileNames) { - val relativeFileName = fileConfig.copyFileOrResource( + for (String filename : targetConfig.fileNames) { + String relativeFileName = fileConfig.copyFileOrResource( filename, - fileConfig.srcFile.parent, + fileConfig.srcFile.getParent(), targetDir); - if (relativeFileName.isNullOrEmpty) { + if (relativeFileName == null || relativeFileName.isEmpty()) { errorReporter.reportError( "Failed to find file " + filename + " specified in the" + " files target property." - ) + ); } else { this.targetConfig.filesNamesWithoutPath.add( relativeFileName @@ -424,14 +440,14 @@ protected def copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { * This will return true if any of the reportError methods was called. * @return True if errors occurred. */ - def errorsOccurred() { + public boolean errorsOccurred() { return errorReporter.getErrorsOccurred(); } /* * Return the TargetTypes instance associated with this. */ - abstract def TargetTypes getTargetTypes(); + public abstract TargetTypes getTargetTypes(); /** * Generate code for the body of a reaction that takes an input and @@ -439,7 +455,7 @@ def errorsOccurred() { * @param the action to schedule * @param the port to read from */ - abstract def String generateDelayBody(Action action, VarRef port); + public abstract String generateDelayBody(Action action, VarRef port); /** * Generate code for the body of a reaction that is triggered by the @@ -447,13 +463,13 @@ def errorsOccurred() { * @param the action that triggers the reaction * @param the port to write to */ - abstract def String generateForwardBody(Action action, VarRef port); + public abstract String generateForwardBody(Action action, VarRef port); /** * Generate code for the generic type to be used in the class definition * of a generated delay reactor. */ - abstract def String generateDelayGeneric(); + public abstract String generateDelayGeneric(); /** * Return true if the reaction is unordered. An unordered reaction is one @@ -467,12 +483,8 @@ def errorsOccurred() { * the Reaction instance is created, add that instance to this set. * @return True if the reaction has been marked unordered. */ - def isUnordered(Reaction reaction) { - if (unorderedReactions !== null) { - unorderedReactions.contains(reaction) - } else { - false - } + public boolean isUnordered(Reaction reaction) { + return unorderedReactions != null ? unorderedReactions.contains(reaction) : false; } /** @@ -487,11 +499,11 @@ def isUnordered(Reaction reaction) { * instance is created, add that instance to this set. * @param reaction The reaction to make unordered. */ - def makeUnordered(Reaction reaction) { - if (unorderedReactions === null) { - unorderedReactions = new LinkedHashSet() + public void makeUnordered(Reaction reaction) { + if (unorderedReactions == null) { + unorderedReactions = new LinkedHashSet(); } - unorderedReactions.add(reaction) + unorderedReactions.add(reaction); } /** @@ -503,13 +515,14 @@ def makeUnordered(Reaction reaction) { * @param The reaction. * @param bankIndex The bank index, or -1 if there is no bank. */ - def setReactionBankIndex(Reaction reaction, int bankIndex) { - if (bankIndex >= 0) { - if (reactionBankIndices === null) { - reactionBankIndices = new LinkedHashMap() - } - reactionBankIndices.put(reaction, bankIndex) + public void setReactionBankIndex(Reaction reaction, int bankIndex) { + if (bankIndex < 0) { + return; } + if (reactionBankIndices == null) { + reactionBankIndices = new LinkedHashMap(); + } + reactionBankIndices.put(reaction, bankIndex); } /** @@ -518,10 +531,10 @@ def setReactionBankIndex(Reaction reaction, int bankIndex) { * @param The reaction. * @return The reaction bank index, if one has been set, and -1 otherwise. */ - def int getReactionBankIndex(Reaction reaction) { - if (reactionBankIndices === null) return -1 - if (reactionBankIndices.get(reaction) === null) return -1 - return reactionBankIndices.get(reaction) + public int getReactionBankIndex(Reaction reaction) { + if (reactionBankIndices == null) return -1; + if (reactionBankIndices.get(reaction) == null) return -1; + return reactionBankIndices.get(reaction); } /** @@ -535,20 +548,20 @@ def int getReactionBankIndex(Reaction reaction) { * @param time A TimeValue that represents a time. * @return A string, such as "MSEC(100)" for 100 milliseconds. */ - def String timeInTargetLanguage(TimeValue time) { - if (time !== null) { - if (time.unit !== null) { - return time.unit.cMacroName + '(' + time.magnitude + ')' + public String timeInTargetLanguage(TimeValue time) { + if (time != null) { + if (time.unit != null) { + return cMacroName(time.unit) + "(" + time.getMagnitude() + ")"; } else { - return time.magnitude.toString() + return Long.valueOf(time.getMagnitude()).toString(); } } - return "0" // FIXME: do this or throw exception? + return "0"; // FIXME: do this or throw exception? } // note that this is moved out by #544 - final def String cMacroName(TimeUnit unit) { - return unit.canonicalName.toUpperCase + public final String cMacroName(TimeUnit unit) { + return unit.getCanonicalName().toUpperCase(); } /** @@ -563,38 +576,38 @@ final def String cMacroName(TimeUnit unit) { * * LF_BIN_DIRECTORY: The directory into which to put binaries. * */ - protected def runBuildCommand() { - var commands = new ArrayList - for (cmd : targetConfig.buildCommands) { - val tokens = newArrayList(cmd.split("\\s+")) - if (tokens.size > 0) { - val buildCommand = commandFactory.createCommand( - tokens.head, - tokens.tail.toList, + protected void runBuildCommand() { + List commands = new ArrayList<>(); + for (String cmd : targetConfig.buildCommands) { + List tokens = CollectionLiterals.newArrayList(cmd.split("\\s+")); + if (tokens.size() > 0) { + LFCommand buildCommand = commandFactory.createCommand( + IterableExtensions.head(tokens), + IterableExtensions.toList(IterableExtensions.tail(tokens)), this.fileConfig.srcPath - ) + ); // If the build command could not be found, abort. // An error has already been reported in createCommand. - if (buildCommand === null) { - return + if (buildCommand == null) { + return; } - commands.add(buildCommand) + commands.add(buildCommand); } } - for (cmd : commands) { + for (LFCommand cmd : commands) { // execute the command - val returnCode = cmd.run() + int returnCode = cmd.run(); - if (returnCode != 0 && fileConfig.context.mode === Mode.STANDALONE) { - errorReporter.reportError('''Build command "«targetConfig.buildCommands»" returns error code «returnCode»''') - return + if (returnCode != 0 && fileConfig.context.getMode() == Mode.STANDALONE) { + errorReporter.reportError("Build command \""+String.join("", targetConfig.buildCommands)+"\" returns error code "+returnCode); + return; } // For warnings (vs. errors), the return code is 0. // But we still want to mark the IDE. - if (cmd.errors.toString.length > 0 && fileConfig.context.mode !== Mode.STANDALONE) { - reportCommandErrors(cmd.errors.toString()) - return + if (cmd.getErrors().toString().length() > 0 && fileConfig.context.getMode() != Mode.STANDALONE) { + reportCommandErrors(cmd.getErrors().toString()); + return; } } } @@ -618,7 +631,7 @@ protected def runBuildCommand() { * @param isPhysical Indicates whether or not the connection is physical * @param serializer The serializer used on the connection. */ - def String generateNetworkReceiverBody( + public String generateNetworkReceiverBody( Action action, VarRef sendingPort, VarRef receivingPort, @@ -631,7 +644,7 @@ def String generateNetworkReceiverBody( boolean isPhysical, SupportedSerializers serializer ) { - throw new UnsupportedOperationException("This target does not support network connections between federates.") + throw new UnsupportedOperationException("This target does not support network connections between federates."); } /** @@ -650,7 +663,7 @@ def String generateNetworkReceiverBody( * @throws UnsupportedOperationException If the target does not support this operation. * @param serializer The serializer used on the connection. */ - def String generateNetworkSenderBody( + public String generateNetworkSenderBody( VarRef sendingPort, VarRef receivingPort, int receivingPortID, @@ -663,7 +676,7 @@ def String generateNetworkSenderBody( Delay delay, SupportedSerializers serializer ) { - throw new UnsupportedOperationException("This target does not support network connections between federates.") + throw new UnsupportedOperationException("This target does not support network connections between federates."); } /** @@ -674,11 +687,11 @@ def String generateNetworkSenderBody( * @param maxSTP The maximum value of STP is assigned to reactions (if any) * that have port as their trigger or source */ - def String generateNetworkInputControlReactionBody( + public String generateNetworkInputControlReactionBody( int receivingPortID, TimeValue maxSTP ) { - throw new UnsupportedOperationException("This target does not support network connections between federates.") + throw new UnsupportedOperationException("This target does not support network connections between federates."); } /** @@ -692,7 +705,7 @@ def String generateNetworkInputControlReactionBody( * @param sendingChannelIndex The channel if a multiport * @param delay The delay value imposed on the connection using after */ - def String generateNetworkOutputControlReactionBody( + public String generateNetworkOutputControlReactionBody( VarRef port, int portID, int receivingFederateID, @@ -700,18 +713,18 @@ def String generateNetworkOutputControlReactionBody( int sendingChannelIndex, Delay delay ) { - throw new UnsupportedOperationException("This target does not support network connections between federates.") + throw new UnsupportedOperationException("This target does not support network connections between federates."); } /** * Add necessary code to the source and necessary build support to * enable the requested serializations in 'enabledSerializations' */ - def void enableSupportForSerializationIfApplicable(CancelIndicator cancelIndicator) { - if (!enabledSerializers.isNullOrEmpty()) { + public void enableSupportForSerializationIfApplicable(CancelIndicator cancelIndicator) { + if (!IterableExtensions.isNullOrEmpty(enabledSerializers)) { throw new UnsupportedOperationException( "Serialization is target-specific "+ - " and is not implemented for the "+target.toString+" target." + " and is not implemented for the "+getTarget().toString()+" target." ); } } @@ -720,16 +733,16 @@ def void enableSupportForSerializationIfApplicable(CancelIndicator cancelIndicat * Returns true if the program is federated and uses the decentralized * coordination mechanism. */ - def isFederatedAndDecentralized() { - return isFederated && targetConfig.coordination === CoordinationType.DECENTRALIZED + public boolean isFederatedAndDecentralized() { + return isFederated && targetConfig.coordination == CoordinationType.DECENTRALIZED; } /** * Returns true if the program is federated and uses the centralized * coordination mechanism. */ - def isFederatedAndCentralized() { - return isFederated && targetConfig.coordination === CoordinationType.CENTRALIZED + public boolean isFederatedAndCentralized() { + return isFederated && targetConfig.coordination == CoordinationType.CENTRALIZED; } /** @@ -738,21 +751,23 @@ def isFederatedAndCentralized() { * @param The name of the docker file. * @param The name of the federate. */ - def writeDockerFile(File dockerComposeDir, String dockerFileName, String federateName) { - throw new UnsupportedOperationException("This target does not support docker file generation.") + public void writeDockerFile(File dockerComposeDir, String dockerFileName, String federateName) { + throw new UnsupportedOperationException("This target does not support docker file generation."); } /** * Parsed error message from a compiler is returned here. */ - static class ErrorFileAndLine { - public var filepath = null as String - public var line = "1" - public var character = "0" - public var message = "" - public var isError = true // false for a warning. - override String toString() { + public static class ErrorFileAndLine { + public String filepath = null; + public String line = "1"; + public String character = "0"; + public String message = ""; + public boolean isError = true; // false for a warning. + + @Override + public String toString() { return (isError ? "Error" : "Non-error") + " at " + line + ":" + character + " of file " + filepath + ": " + message; } } @@ -771,8 +786,8 @@ override String toString() { * "0" if there is none), and the message (or an empty string if there * is none). */ - protected def parseCommandOutput(String line) { - return null as ErrorFileAndLine + protected ErrorFileAndLine parseCommandOutput(String line) { + return null; } /** @@ -784,90 +799,90 @@ protected def parseCommandOutput(String line) { * * @param stderr The output on standard error of executing a command. */ - def reportCommandErrors(String stderr) { + public void reportCommandErrors(String stderr) { // NOTE: If the VS Code branch passes code review, then this function, // parseCommandOutput, and ErrorFileAndLine will be deleted soon after. // First, split the message into lines. - val lines = stderr.split("\\r?\\n") - var message = new StringBuilder() - var lineNumber = null as Integer - var path = fileConfig.srcFile + String[] lines = stderr.split("\\r?\\n"); + StringBuilder message = new StringBuilder(); + Integer lineNumber = null; + Path path = fileConfig.srcFile; // In case errors occur within an imported file, record the original path. - val originalPath = path; + Path originalPath = path; - var severity = IMarker.SEVERITY_ERROR - for (line : lines) { - val parsed = parseCommandOutput(line) - if (parsed !== null) { + int severity = IMarker.SEVERITY_ERROR; + for (String line : lines) { + ErrorFileAndLine parsed = parseCommandOutput(line); + if (parsed != null) { // Found a new line number designator. // If there is a previously accumulated message, report it. - if (message.length > 0) { + if (message.length() > 0) { if (severity == IMarker.SEVERITY_ERROR) - errorReporter.reportError(path, lineNumber, message.toString()) + errorReporter.reportError(path, lineNumber, message.toString()); else - errorReporter.reportWarning(path, lineNumber, message.toString()) + errorReporter.reportWarning(path, lineNumber, message.toString()); - if (originalPath.toFile != path.toFile) { + if (!Objects.equal(originalPath.toFile(), path.toFile())) { // Report an error also in the top-level resource. // FIXME: It should be possible to descend through the import // statements to find which one matches and mark all the // import statements down the chain. But what a pain! if (severity == IMarker.SEVERITY_ERROR) { - errorReporter.reportError(originalPath, 1, "Error in imported file: " + path) + errorReporter.reportError(originalPath, 1, "Error in imported file: " + path); } else { - errorReporter.reportWarning(originalPath, 1, "Warning in imported file: " + path) + errorReporter.reportWarning(originalPath, 1, "Warning in imported file: " + path); } } } if (parsed.isError) { - severity = IMarker.SEVERITY_ERROR + severity = IMarker.SEVERITY_ERROR; } else { - severity = IMarker.SEVERITY_WARNING + severity = IMarker.SEVERITY_WARNING; } // Start accumulating a new message. - message = new StringBuilder() + message = new StringBuilder(); // Append the message on the line number designator line. - message.append(parsed.message) + message.append(parsed.message); // Set the new line number. try { - lineNumber = Integer.decode(parsed.line) + lineNumber = Integer.decode(parsed.line); } catch (Exception ex) { // Set the line number unknown. - lineNumber = null + lineNumber = null; } // FIXME: Ignoring the position within the line. // Determine the path within which the error occurred. - path = Paths.get(parsed.filepath) + path = Paths.get(parsed.filepath); } else { // No line designator. - if (message.length > 0) { - message.append("\n") + if (message.length() > 0) { + message.append("\n"); } else { - if (!line.toLowerCase.contains('error:')) { - severity = IMarker.SEVERITY_WARNING + if (!line.toLowerCase().contains("error:")) { + severity = IMarker.SEVERITY_WARNING; } } message.append(line); } } - if (message.length > 0) { + if (message.length() > 0) { if (severity == IMarker.SEVERITY_ERROR) { - errorReporter.reportError(path, lineNumber, message.toString()) + errorReporter.reportError(path, lineNumber, message.toString()); } else { - errorReporter.reportWarning(path, lineNumber, message.toString()) + errorReporter.reportWarning(path, lineNumber, message.toString()); } - if (originalPath.toFile != path.toFile) { + if (originalPath.toFile() != path.toFile()) { // Report an error also in the top-level resource. // FIXME: It should be possible to descend through the import // statements to find which one matches and mark all the // import statements down the chain. But what a pain! if (severity == IMarker.SEVERITY_ERROR) { - errorReporter.reportError(originalPath, 1, "Error in imported file: " + path) + errorReporter.reportError(originalPath, 1, "Error in imported file: " + path); } else { - errorReporter.reportWarning(originalPath, 1, "Warning in imported file: " + path) + errorReporter.reportWarning(originalPath, 1, "Warning in imported file: " + path); } } } @@ -879,8 +894,8 @@ def reportCommandErrors(String stderr) { * @param param The parameter to generate code for * @return Parameter reference in target code */ - protected def String getTargetReference(Parameter param) { - return param.name + protected String getTargetReference(Parameter param) { + return param.getName(); } // ////////////////////////////////////////////////// @@ -896,24 +911,27 @@ protected def String getTargetReference(Parameter param) { * @param instance The reactor instance to remove these ports from if any. * Can be null. */ - protected def void removeRemoteFederateConnectionPorts(ReactorInstance instance) { - if (isFederated) { - for (federate: federates) { - // Remove disconnected network triggers from the AST - federate.removeRemoteFederateConnectionPorts(); - if (instance !== null) { - // If passed a reactor instance, also purge the disconnected network triggers - // from the reactor instance graph - for (reaction: federate.networkReactions) { - val networkReaction = instance.lookupReactionInstance(reaction) - if (networkReaction !== null) { - for (port: federate.remoteNetworkReactionTriggers) { - val disconnectedPortInstance = instance.lookupPortInstance(port); - if (disconnectedPortInstance !== null) { - networkReaction.removePortInstance(disconnectedPortInstance); - } - } - } + protected void removeRemoteFederateConnectionPorts(ReactorInstance instance) { + if (!isFederated) { + return; + } + for (FederateInstance federate : federates) { + // Remove disconnected network triggers from the AST + federate.removeRemoteFederateConnectionPorts(); + if (instance == null) { + continue; + } + // If passed a reactor instance, also purge the disconnected network triggers + // from the reactor instance graph + for (Reaction reaction : federate.networkReactions) { + ReactionInstance networkReaction = instance.lookupReactionInstance(reaction); + if (networkReaction == null) { + continue; + } + for (VarRef port : federate.remoteNetworkReactionTriggers) { + PortInstance disconnectedPortInstance = instance.lookupPortInstance(port); + if (disconnectedPortInstance != null) { + networkReaction.removePortInstance(disconnectedPortInstance); } } } @@ -923,29 +941,29 @@ protected def void removeRemoteFederateConnectionPorts(ReactorInstance instance) /** * Set the RTI hostname, port and username if given as compiler arguments */ - private def setFederationRTIProperties(LFGeneratorContext context) { - val rtiAddr = context.args.getProperty("rti").toString() - val pattern = Pattern.compile("([a-zA-Z0-9]+@)?([a-zA-Z0-9]+\\.?[a-z]{2,}|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):?([0-9]+)?") - val matcher = pattern.matcher(rtiAddr) + private void setFederationRTIProperties(LFGeneratorContext context) { + String rtiAddr = context.getArgs().getProperty("rti").toString(); + Pattern pattern = Pattern.compile("([a-zA-Z0-9]+@)?([a-zA-Z0-9]+\\.?[a-z]{2,}|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):?([0-9]+)?"); + Matcher matcher = pattern.matcher(rtiAddr); if (!matcher.find()) { return; } // the user match group contains a trailing "@" which needs to be removed. - val userWithAt = matcher.group(1) - val user = userWithAt === null ? null : userWithAt.substring(0, userWithAt.length() - 1) - val host = matcher.group(2) - val port = matcher.group(3) + String userWithAt = matcher.group(1); + String user = userWithAt == null ? null : userWithAt.substring(0, userWithAt.length() - 1); + String host = matcher.group(2); + String port = matcher.group(3); - if (host !== null) { - federationRTIProperties.put("host", host) + if (host != null) { + federationRTIProperties.put("host", host); } - if (port !== null) { - federationRTIProperties.put("port", port) + if (port != null) { + federationRTIProperties.put("port", port); } - if (user !== null) { - federationRTIProperties.put("user", user) + if (user != null) { + federationRTIProperties.put("user", user); } } @@ -967,85 +985,85 @@ private def setFederationRTIProperties(LFGeneratorContext context) { * information between federates. See the C target * for a reference implementation. */ - private def analyzeFederates(LFGeneratorContext context) { + private void analyzeFederates(LFGeneratorContext context) { // Next, if there actually are federates, analyze the topology // interconnecting them and replace the connections between them // with an action and two reactions. - val mainReactor = this.mainDef?.reactorClass.toDefinition + Reactor mainReactor = mainDef != null ? ASTUtils.toDefinition(mainDef.getReactorClass()) : null; - if (this.mainDef === null || !mainReactor.isFederated) { + if (mainDef == null || !mainReactor.isFederated()) { // The program is not federated. // Ensure federates is never empty. - var federateInstance = new FederateInstance(null, 0, 0, this, errorReporter) - federates.add(federateInstance) - federateByID.put(0, federateInstance) + FederateInstance federateInstance = new FederateInstance(null, 0, 0, this, errorReporter); + federates.add(federateInstance); + federateByID.put(0, federateInstance); } else { // The Lingua Franca program is federated - isFederated = true + isFederated = true; // If the "--rti" flag is given to the compiler, use the argument from the flag. - if (context.args.containsKey("rti")) { - setFederationRTIProperties(context) - } else if (mainReactor.host !== null) { + if (context.getArgs().containsKey("rti")) { + setFederationRTIProperties(context); + } else if (mainReactor.getHost() != null) { // Get the host information, if specified. // If not specified, this defaults to 'localhost' - if (mainReactor.host.addr !== null) { - federationRTIProperties.put("host", mainReactor.host.addr) + if (mainReactor.getHost().getAddr() != null) { + federationRTIProperties.put("host", mainReactor.getHost().getAddr()); } // Get the port information, if specified. // If not specified, this defaults to 14045 - if (mainReactor.host.port !== 0) { - federationRTIProperties.put("port", mainReactor.host.port) + if (mainReactor.getHost().getPort() != 0) { + federationRTIProperties.put("port", mainReactor.getHost().getPort()); } // Get the user information, if specified. - if (mainReactor.host.user !== null) { - federationRTIProperties.put("user", mainReactor.host.user) + if (mainReactor.getHost().getUser() != null) { + federationRTIProperties.put("user", mainReactor.getHost().getUser()); } } // Since federates are always within the main (federated) reactor, // create a list containing just that one containing instantiation. // This will be used to look up parameter values. - val mainReactorContext = new ArrayList(); + List mainReactorContext = new ArrayList<>(); mainReactorContext.add(mainDef); // Create a FederateInstance for each top-level reactor. - for (instantiation : mainReactor.allInstantiations) { - var bankWidth = ASTUtils.width(instantiation.widthSpec, mainReactorContext); + for (Instantiation instantiation : ASTUtils.allInstantiations(mainReactor)) { + int bankWidth = ASTUtils.width(instantiation.getWidthSpec(), mainReactorContext); if (bankWidth < 0) { errorReporter.reportError(instantiation, "Cannot determine bank width! Assuming width of 1."); // Continue with a bank width of 1. bankWidth = 1; } // Create one federate instance for each instance in a bank of reactors. - val federateInstances = new ArrayList(bankWidth); - for (var i = 0; i < bankWidth; i++) { + List federateInstances = new ArrayList<>(bankWidth); + for (int i = 0; i < bankWidth; i++) { // Assign an integer ID to the federate. - var federateID = federates.size - var federateInstance = new FederateInstance(instantiation, federateID, i, this, errorReporter) + int federateID = federates.size(); + FederateInstance federateInstance = new FederateInstance(instantiation, federateID, i, this, errorReporter); federateInstance.bankIndex = i; - federates.add(federateInstance) - federateInstances.add(federateInstance) - federateByID.put(federateID, federateInstance) + federates.add(federateInstance); + federateInstances.add(federateInstance); + federateByID.put(federateID, federateInstance); - if (instantiation.host !== null) { - federateInstance.host = instantiation.host.addr + if (instantiation.getHost() != null) { + federateInstance.host = instantiation.getHost().getAddr(); // The following could be 0. - federateInstance.port = instantiation.host.port + federateInstance.port = instantiation.getHost().getPort(); // The following could be null. - federateInstance.user = instantiation.host.user + federateInstance.user = instantiation.getHost().getUser(); /* FIXME: The at keyword should support a directory component. - * federateInstance.dir = instantiation.host.dir + * federateInstance.dir = instantiation.getHost().dir */ - if (federateInstance.host !== null && - federateInstance.host != 'localhost' && - federateInstance.host != '0.0.0.0' + if (federateInstance.host != null && + federateInstance.host != "localhost" && + federateInstance.host != "0.0.0.0" ) { federateInstance.isRemote = true; } } } - if (federatesByInstantiation === null) { + if (federatesByInstantiation == null) { federatesByInstantiation = new LinkedHashMap>(); } federatesByInstantiation.put(instantiation, federateInstances); @@ -1054,7 +1072,7 @@ private def analyzeFederates(LFGeneratorContext context) { // In a federated execution, we need keepalive to be true, // otherwise a federate could exit simply because it hasn't received // any messages. - targetConfig.keepalive = true + targetConfig.keepalive = true; // Analyze the connection topology of federates. // First, find all the connections between federates. @@ -1062,10 +1080,10 @@ private def analyzeFederates(LFGeneratorContext context) { // AST with an action (which inherits the delay) and two reactions. // The action will be physical for physical connections and logical // for logical connections. - replaceFederateConnectionsWithActions() + replaceFederateConnectionsWithActions(); // Remove the connections at the top level - mainReactor.connections.clear() + mainReactor.getConnections().clear(); } } @@ -1073,8 +1091,8 @@ private def analyzeFederates(LFGeneratorContext context) { * Replace connections between federates in the AST with actions that * handle sending and receiving data. */ - private def replaceFederateConnectionsWithActions() { - val mainReactor = this.mainDef?.reactorClass.toDefinition + private void replaceFederateConnectionsWithActions() { + Reactor mainReactor = mainDef != null ? ASTUtils.toDefinition(mainDef.getReactorClass()) : null; // Each connection in the AST may represent more than one connection between // federate instances because of banks and multiports. We need to generate communication @@ -1082,11 +1100,11 @@ private def replaceFederateConnectionsWithActions() { // to duplicate the rather complicated logic in that class. We specify a depth of 1, // so it only creates the reactors immediately within the top level, not reactors // that those contain. - val mainInstance = new ReactorInstance(mainReactor, errorReporter, 1) + ReactorInstance mainInstance = new ReactorInstance(mainReactor, errorReporter, 1); - for (child : mainInstance.children) { - for (output : child.outputs) { - replaceConnectionFromFederate(output, child, mainInstance) + for (ReactorInstance child : mainInstance.children) { + for (PortInstance output : child.outputs) { + replaceConnectionFromFederate(output, child, mainInstance); } } } @@ -1098,68 +1116,68 @@ private def replaceFederateConnectionsWithActions() { * @param federateReactor The reactor instance for that federate. * @param mainInstance The main reactor instance. */ - private def void replaceConnectionFromFederate( + private void replaceConnectionFromFederate( PortInstance output, ReactorInstance federateReactor, ReactorInstance mainInstance ) { - for (srcRange : output.dependentPorts) { + for (SendRange srcRange : output.dependentPorts) { for (RuntimeRange dstRange : srcRange.destinations) { - var srcID = srcRange.startMR(); - val dstID = dstRange.startMR(); - var dstCount = 0; - var srcCount = 0; + MixedRadixInt srcID = srcRange.startMR(); + MixedRadixInt dstID = dstRange.startMR(); + int dstCount = 0; + int srcCount = 0; while (dstCount++ < dstRange.width) { - val srcChannel = srcID.digits.get(0); - val srcBank = srcID.get(1); - val dstChannel = dstID.digits.get(0); - val dstBank = dstID.get(1); + int srcChannel = srcID.getDigits().get(0); + int srcBank = srcID.get(1); + int dstChannel = dstID.getDigits().get(0); + int dstBank = dstID.get(1); - val srcFederate = federatesByInstantiation.get( + FederateInstance srcFederate = federatesByInstantiation.get( srcRange.instance.parent.definition ).get(srcBank); - val dstFederate = federatesByInstantiation.get( + FederateInstance dstFederate = federatesByInstantiation.get( dstRange.instance.parent.definition ).get(dstBank); - val connection = srcRange.connection; + Connection connection = srcRange.connection; - if (connection === null) { + if (connection == null) { // This should not happen. errorReporter.reportError(output.definition, - "Unexpected error. Cannot find output connection for port") + "Unexpected error. Cannot find output connection for port"); } else { - if (srcFederate !== dstFederate - && !connection.physical - && targetConfig.coordination !== CoordinationType.DECENTRALIZED) { + if (srcFederate != dstFederate + && !connection.isPhysical() + && targetConfig.coordination != CoordinationType.DECENTRALIZED) { // Map the delays on connections between federates. // First see if the cache has been created. - var dependsOnDelays = dstFederate.dependsOn.get(srcFederate) - if (dependsOnDelays === null) { + Set dependsOnDelays = dstFederate.dependsOn.get(srcFederate); + if (dependsOnDelays == null) { // If not, create it. - dependsOnDelays = new LinkedHashSet() - dstFederate.dependsOn.put(srcFederate, dependsOnDelays) + dependsOnDelays = new LinkedHashSet(); + dstFederate.dependsOn.put(srcFederate, dependsOnDelays); } // Put the delay on the cache. - if (connection.delay !== null) { - dependsOnDelays.add(connection.delay) + if (connection.getDelay() != null) { + dependsOnDelays.add(connection.getDelay()); } else { // To indicate that at least one connection has no delay, add a null entry. - dependsOnDelays.add(null) + dependsOnDelays.add(null); } // Map the connections between federates. - var sendsToDelays = srcFederate.sendsTo.get(dstFederate) - if (sendsToDelays === null) { - sendsToDelays = new LinkedHashSet() - srcFederate.sendsTo.put(dstFederate, sendsToDelays) + Set sendsToDelays = srcFederate.sendsTo.get(dstFederate); + if (sendsToDelays == null) { + sendsToDelays = new LinkedHashSet(); + srcFederate.sendsTo.put(dstFederate, sendsToDelays); } - if (connection.delay !== null) { - sendsToDelays.add(connection.delay) + if (connection.getDelay() != null) { + sendsToDelays.add(connection.getDelay()); } else { // To indicate that at least one connection has no delay, add a null entry. - sendsToDelays.add(null) + sendsToDelays.add(null); } } @@ -1192,11 +1210,11 @@ private def void replaceConnectionFromFederate( * Print to stdout information about what source file is being generated, * what mode the generator is in, and where the generated sources are to be put. */ - def printInfo() { - println("Generating code for: " + fileConfig.resource.getURI.toString) - println('******** mode: ' + fileConfig.context.mode) - println('******** source file: ' + fileConfig.srcFile) // FIXME: redundant - println('******** generated sources: ' + fileConfig.getSrcGenPath) + public void printInfo() { + System.out.println("Generating code for: " + fileConfig.resource.getURI().toString()); + System.out.println("******** mode: " + fileConfig.context.getMode()); + System.out.println("******** source file: " + fileConfig.srcFile); // FIXME: redundant + System.out.println("******** generated sources: " + fileConfig.getSrcGenPath()); } /** @@ -1210,17 +1228,17 @@ def printInfo() { * side of the connection. This gives the code generator the information needed to infer the correct width at * runtime. */ - def boolean generateAfterDelaysWithVariableWidth() { return true } + public boolean generateAfterDelaysWithVariableWidth() { return true; } /** * Get the buffer type used for network messages */ - def String getNetworkBufferType() '''''' + public String getNetworkBufferType() { return ""; } /** * Return the Targets enum for the current target */ - abstract def Target getTarget() + public abstract Target getTarget(); /** * Get textual representation of a time in the target language. @@ -1228,9 +1246,9 @@ abstract def Target getTarget() * @param t A time AST node * @return A time string in the target language */ - protected def getTargetTime(Time t) { - val value = new TimeValue(t.interval, TimeUnit.fromName(t.unit)) - return value.timeInTargetLanguage + protected String getTargetTime(Time t) { + TimeValue value = new TimeValue(t.getInterval(), TimeUnit.fromName(t.getUnit())); + return timeInTargetLanguage(value); } /** @@ -1241,11 +1259,11 @@ protected def getTargetTime(Time t) { * @param v A time AST node * @return A time string in the target language */ - protected def getTargetValue(Value v) { - if (v.time !== null) { - return v.time.targetTime + protected String getTargetValue(Value v) { + if (v.getTime() != null) { + return getTargetTime(v.getTime()); } - return v.toText + return ASTUtils.toText(v); } /** @@ -1256,21 +1274,21 @@ protected def getTargetValue(Value v) { * @param v A time AST node * @return A time string in the target language */ - protected def getTargetTime(Value v) { - if (v.time !== null) { - return v.time.targetTime - } else if (v.isZero) { - val value = TimeValue.ZERO - return value.timeInTargetLanguage + protected String getTargetTime(Value v) { + if (v.getTime() != null) { + return getTargetTime(v.getTime()); + } else if (ASTUtils.isZero(v)) { + TimeValue value = TimeValue.ZERO; + return timeInTargetLanguage(value); } - return v.toText + return ASTUtils.toText(v); } - protected def getTargetTime(Delay d) { - if (d.parameter !== null) { - return d.toText + protected String getTargetTime(Delay d) { + if (d.getParameter() != null) { + return ASTUtils.toText(d); } else { - return d.time.targetTime + return getTargetTime(d.getTime()); } } } From 025300ecf2831405d0363238fbb8fa619846e447 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 22 Feb 2022 01:46:59 +0000 Subject: [PATCH 2/3] fix unhandled IO Exception error --- .../src/org/lflang/generator/GeneratorBase.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/GeneratorBase.java b/org.lflang/src/org/lflang/generator/GeneratorBase.java index 0e3bb1a183..fb5c9a3021 100644 --- a/org.lflang/src/org/lflang/generator/GeneratorBase.java +++ b/org.lflang/src/org/lflang/generator/GeneratorBase.java @@ -48,6 +48,7 @@ import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.xtext.util.CancelIndicator; import org.eclipse.xtext.xbase.lib.CollectionLiterals; +import org.eclipse.xtext.xbase.lib.Exceptions; import org.eclipse.xtext.xbase.lib.IterableExtensions; import org.eclipse.xtext.xbase.lib.IteratorExtensions; import org.eclipse.xtext.xbase.lib.Pair; @@ -297,7 +298,7 @@ private void createMainInstantiation() { * @param context Context relating to invocation of the code generator. * In stand alone mode, this object is also used to relay CLI arguments. */ - public void doGenerate(Resource resource, LFGeneratorContext context) throws IOException { + public void doGenerate(Resource resource, LFGeneratorContext context) { JavaGeneratorUtils.setTargetConfig( context, JavaGeneratorUtils.findTarget(fileConfig.resource), targetConfig, errorReporter @@ -412,10 +413,14 @@ private void transformDelays() { * @param targetConfig The targetConfig to read the `files` from. * @param fileConfig The fileConfig used to make the copy and resolve paths. */ - protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) throws IOException { + protected void copyUserFiles(TargetConfig targetConfig, FileConfig fileConfig) { // Make sure the target directory exists. Path targetDir = fileConfig.getSrcGenPath(); - Files.createDirectories(targetDir); + try { + Files.createDirectories(targetDir); + } catch (IOException e) { + Exceptions.sneakyThrow(e); + } for (String filename : targetConfig.fileNames) { String relativeFileName = fileConfig.copyFileOrResource( From a71034ef7226df98d80b1f7947b3165ada7ccb97 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 25 Feb 2022 23:20:43 +0000 Subject: [PATCH 3/3] bug fix --- .../src/org/lflang/generator/python/PythonGenerator.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java index 20960e1c47..85d6496111 100644 --- a/org.lflang/src/org/lflang/generator/python/PythonGenerator.java +++ b/org.lflang/src/org/lflang/generator/python/PythonGenerator.java @@ -190,11 +190,10 @@ public Target getTarget() { // ////////////////////////////////////////// // // Public methods @Override - public String printInfo() { + public void printInfo() { System.out.println("Generating code for: " + fileConfig.resource.getURI().toString()); System.out.println("******** Mode: " + fileConfig.context.getMode()); System.out.println("******** Generated sources: " + fileConfig.getSrcGenPath()); - return null; } @Override