Skip to content

Commit

Permalink
Refactorings
Browse files Browse the repository at this point in the history
  • Loading branch information
erlingrj committed Jan 15, 2025
1 parent d3173cf commit dd61844
Show file tree
Hide file tree
Showing 24 changed files with 790 additions and 1,012 deletions.
7 changes: 2 additions & 5 deletions lfc/core/src/main/java/org/lflang/generator/LFGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@

import com.google.inject.Inject;
import com.google.inject.Injector;
import java.io.IOException;

import java.nio.file.Path;
import java.util.Arrays;

import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.generator.AbstractGenerator;
import org.eclipse.xtext.generator.IFileSystemAccess2;
import org.eclipse.xtext.generator.IGeneratorContext;
import org.eclipse.xtext.util.RuntimeIOException;
import org.lflang.FileConfig;
import org.lflang.MessageReporter;
import org.lflang.ast.ASTUtils;
import org.lflang.generator.uc.UcFileConfig;
import org.lflang.generator.uc.UcGenerator;
import org.lflang.generator.uc.UcNonFederatedGenerator;
import org.lflang.scoping.LFGlobalScopeProvider;
import org.lflang.target.Target;

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,61 +18,71 @@ import java.time.LocalDateTime
import kotlin.io.path.name
import kotlin.math.max

class UcCmakeGenerator(private val mainDef: Instantiation, private val targetConfig: TargetConfig, private val fileConfig: FileConfig, private val numEvents: Int, private val numReactions: Int) {
private val S = '$' // a little trick to escape the dollar sign with $S
private val platform = targetConfig.get(PlatformProperty.INSTANCE).platform
private val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() }
private val mainTarget = fileConfig.name
abstract class UcCmakeGenerator(private val targetConfig: TargetConfig, private val fileConfig: UcFileConfig, private val numEvents: Int, private val numReactions: Int) {
protected val S = '$' // a little trick to escape the dollar sign with $S
private val minCmakeVersion = "3.10"
protected val includeFiles = targetConfig.get(CmakeIncludeProperty.INSTANCE)?.map { fileConfig.srcPath.resolve(it).toUnixString() }
protected val platform = targetConfig.get(PlatformProperty.INSTANCE).platform
abstract val mainTarget: String
abstract fun generateCmake(sources: List<Path>): String


fun generateCmake(sources: List<Path>) =
if (platform == PlatformType.Platform.NATIVE) {
generateCmakePosix(sources)
} else {
generateCmakeEmbedded(sources)
}

fun generateCmakeEmbedded(sources: List<Path>) = with(PrependOperator) {
"""
|# This file is generated by LFC. It is meant to be included in
|# an existing CMake project.
|
protected fun generateCmakeCommon(sources: List<Path>, compileDefs: List<String>) = with(PrependOperator) {
""" |
|set(LFC_GEN_SOURCES
${" | "..sources.filterNot{it.name == "lf_main.c"}.joinWithLn { "$S{CMAKE_CURRENT_LIST_DIR}/${it.toUnixString()}"}}
|)
|set(LFC_GEN_COMPILE_DEFS
${" | "..compileDefs.joinWithLn { it }}
|)
|set(LFC_GEN_MAIN "$S{CMAKE_CURRENT_LIST_DIR}/lf_main.c")
|set(REACTOR_UC_PATH $S{CMAKE_CURRENT_LIST_DIR}/reactor-uc)
|set(LFC_GEN_INCLUDE_DIRS $S{CMAKE_CURRENT_LIST_DIR})
|set(REACTION_QUEUE_SIZE ${max(numReactions, 1)} CACHE STRING "Size of the reaction queue")
|set(EVENT_QUEUE_SIZE ${max(numEvents, 1)} CACHE STRING "Size of the event queue")
|
""".trimMargin()
}

fun generateCmakePosix(sources: List<Path>) = with(PrependOperator) {
protected fun generateCmakePosix(sources: List<Path>, compileDefs: List<String>) = with(PrependOperator) {
"""
|cmake_minimum_required(VERSION 3.10)
|cmake_minimum_required(VERSION $minCmakeVersion)
|project(${mainTarget} LANGUAGES C)
|set(PLATFORM POSIX CACHE STRING "Target platform")
|set(REACTION_QUEUE_SIZE ${max(numReactions, 1)} CACHE STRING "Size of the reaction queue")
|set(EVENT_QUEUE_SIZE ${max(numEvents, 1)} CACHE STRING "Size of the event queue")
|set(CMAKE_BUILD_TYPE ${targetConfig.getOrDefault(BuildTypeProperty.INSTANCE)})
|
|set(LF_MAIN_TARGET ${mainTarget})
|set(SOURCES
${" | "..sources.joinWithLn { it.toUnixString() }}
|)
|add_executable($S{LF_MAIN_TARGET} $S{SOURCES})
|set(CMAKE_BUILD_TYPE ${targetConfig.getOrDefault(BuildTypeProperty.INSTANCE)})
|set(PLATFORM POSIX CACHE STRING "Target platform")
${" |"..generateCmakeCommon(sources, compileDefs)}
|add_executable($S{LF_MAIN_TARGET} $S{LFC_GEN_SOURCES} $S{LFC_GEN_MAIN})
|install(TARGETS $S{LF_MAIN_TARGET}
| RUNTIME DESTINATION $S{CMAKE_INSTALL_BINDIR}
| OPTIONAL
|)
|add_compile_definitions(LF_LOG_LEVEL_ALL=${targetConfig.getOrDefault(LoggingProperty.INSTANCE).ordinal})
|
|add_subdirectory(reactor-uc $S{CMAKE_CURRENT_LIST_DIR})
|add_compile_definitions("LF_LOG_LEVEL_ALL=LF_LOG_LEVEL_${targetConfig.getOrDefault(LoggingProperty.INSTANCE).name.uppercase()}")
|add_compile_definitions($S{LFC_GEN_COMPILE_DEFS})
|add_subdirectory($S{REACTOR_UC_PATH})
|target_link_libraries($S{LF_MAIN_TARGET} PRIVATE reactor-uc)
|target_include_directories($S{LF_MAIN_TARGET} PRIVATE $S{CMAKE_CURRENT_LIST_DIR})
${" |"..(includeFiles?.joinWithLn { "include(\"$it\")" } ?: "")}
|target_include_directories($S{LF_MAIN_TARGET} PRIVATE $S{LFC_GEN_INCLUDE_DIRS})
${" |"..(includeFiles?.joinWithLn { "include(\"$it\")" } ?: "")}
""".trimMargin()
}
}

class UcCmakeGeneratorNonFederated(private val mainDef: Instantiation, targetConfig: TargetConfig, fileConfig: UcFileConfig, numEvents: Int, numReactions: Int): UcCmakeGenerator(targetConfig, fileConfig, numEvents, numReactions) {
override val mainTarget = fileConfig.name

override fun generateCmake(sources: List<Path>) =
if (platform == PlatformType.Platform.NATIVE) {
generateCmakePosix(sources, emptyList())
} else {
generateCmakeCommon(sources, emptyList())
}
}

class UcCmakeGeneratorFederated(private val federate: UcFederate, targetConfig: TargetConfig, fileConfig: UcFileConfig, numEvents: Int, numReactions: Int): UcCmakeGenerator(targetConfig, fileConfig, numEvents, numReactions) {
override val mainTarget = federate.codeType

override fun generateCmake(sources: List<Path>) =
if (platform == PlatformType.Platform.NATIVE) {
generateCmakePosix(sources, federate.getCompileDefs())
} else {
generateCmakeCommon(sources, federate.getCompileDefs())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,79 @@ import org.lflang.generator.uc.UcInstanceGenerator.Companion.isAFederate
import org.lflang.generator.uc.UcReactorGenerator.Companion.codeType
import org.lflang.lf.*

/**
* This generator creates code for configuring the connections between reactors. This is perhaps the most complicated
* part of the code-generator. This generator handles both federated and non-federated programs
*/
class UcConnectionGenerator(
private val reactor: Reactor,
private val currentFederate: UcFederate?,
private val allFederates: List<UcFederate>
private val reactor: Reactor, // The reactor to generator connections for
private val currentFederate: UcFederate?, // The federate to generate connections for. If set then `reactor` should be the top-level reactor.
private val allFederates: List<UcFederate> // A list of all the federates in the program. Only used for federated code-gen.
) {

/** A list containing all non-federated gruoped connections within this reactor. */
private val nonFederatedConnections: List<UcGroupedConnection>

/** A list containing all federated connection bundles (each containing grouped connections) within this reactor, that
* has the current federate as a src or dest.
*/
private val federatedConnectionBundles: List<UcFederatedConnectionBundle>

private val isFederated = currentFederate != null

/**
* Given a LF connection and possibly the list of federates of the program. Create all the ConnectionChannels
* found within the LF Connection. This must handle multiports, banks, iterated connections and federated connections.
*/
private fun parseConnectionChannels(conn: Connection, federates: List<UcFederate>): List<UcConnectionChannel> {
val res = mutableListOf<UcConnectionChannel>()
val rhsPorts = conn.rightPorts.map { getChannelQueue(it, federates) }
var rhsPortIndex = 0

var lhsPorts = conn.leftPorts.map { getChannelQueue(it, federates) }
var lhsPortIndex = 0

// Keep parsing out connections until we are out of right-hand-side (rhs) ports
while (rhsPortIndex < rhsPorts.size) {
// First get the current lhs and rhs port and UcGroupedConnection that we are working with
val lhsPort = lhsPorts[lhsPortIndex]
val rhsPort = rhsPorts[rhsPortIndex]
if (rhsPort.channelsLeft() > lhsPort.channelsLeft()) {
val rhsChannelsToAdd = rhsPort.takeChannels(lhsPort.channelsLeft())
val lhsChannelsToAdd = lhsPort.takeRemainingChannels()
lhsChannelsToAdd.zip(rhsChannelsToAdd)
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
lhsPortIndex += 1
} else if (rhsPort.channelsLeft() < lhsPort.channelsLeft()) {
val numRhsChannelsToAdd = rhsPort.channelsLeft()
val rhsChannelsToAdd = rhsPort.takeRemainingChannels()
val lhsChannelsToAdd = lhsPort.takeChannels(numRhsChannelsToAdd)
lhsChannelsToAdd.zip(rhsChannelsToAdd)
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
rhsPortIndex += 1
} else {
lhsPort.takeRemainingChannels().zip(rhsPort.takeRemainingChannels())
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
rhsPortIndex += 1
lhsPortIndex += 1
}

// If we are out of lhs variables, but not rhs, then there should be an iterated connection.
// We handle it by resetting the lhsChannels variable and index and continuing until
// we have been through all rhs channels.
if (lhsPortIndex >= lhsPorts.size && rhsPortIndex < rhsPorts.size) {
assert(conn.isIterated)
lhsPorts = conn.leftPorts.map {getChannelQueue(it, federates)}
lhsPortIndex = 0
}
}
return res
}

/**
* Given a list of ConnectionChannels, group them together. How they are grouepd depends on
* whether we are dealing with federated or non-federated reactors.
*/
private fun groupConnections(channels: List<UcConnectionChannel>): List<UcGroupedConnection> {
val res = mutableListOf<UcGroupedConnection>()
val channels = HashSet(channels)
Expand Down Expand Up @@ -65,68 +128,27 @@ class UcConnectionGenerator(
return res
}

private fun getUcPorts(portVarRefs: List<VarRef>, federates: List<UcFederate>): List<UcPort> {
return portVarRefs.map { c ->
if (c.container?.isAFederate ?: false) {
val federates = allFederates.filter { it.inst == c.container }
UcPort(c, federates)
/** Given a port VarRef, and the list of federates. Create a channel queue. I.e. create
* all the UcChannels and associate them with the correct federates.
*/
private fun getChannelQueue(portVarRef: VarRef, federates: List<UcFederate>): UcChannelQueue {
return if (portVarRef.container?.isAFederate ?: false) {
val federates = allFederates.filter { it.inst == portVarRef.container }
UcChannelQueue(portVarRef, federates)
} else {
UcPort(c, emptyList())
UcChannelQueue(portVarRef, emptyList())
}
}

}

private fun parseConnectionChannels(conn: Connection, federates: List<UcFederate>): List<UcConnectionChannel> {
val res = mutableListOf<UcConnectionChannel>()
val rhsPorts = getUcPorts(conn.rightPorts, federates)
var rhsPortIndex = 0

var lhsPorts = getUcPorts(conn.leftPorts, federates)
var lhsPortIndex = 0

// Keep parsing out connections until we are out of right-hand-side (rhs) ports
while (rhsPortIndex < rhsPorts.size) {
// First get the current lhs and rhs port and UcGroupedConnection that we are working with
val lhsPort = lhsPorts[lhsPortIndex]
val rhsPort = rhsPorts[rhsPortIndex]
if (rhsPort.channelsLeft() > lhsPort.channelsLeft()) {
val rhsChannelsToAdd = rhsPort.takeChannels(lhsPort.channelsLeft())
val lhsChannelsToAdd = lhsPort.takeRemainingChannels()
lhsChannelsToAdd.zip(rhsChannelsToAdd)
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
lhsPortIndex += 1
} else if (rhsPort.channelsLeft() < lhsPort.channelsLeft()) {
val numRhsChannelsToAdd = rhsPort.channelsLeft()
val rhsChannelsToAdd = rhsPort.takeRemainingChannels()
val lhsChannelsToAdd = lhsPort.takeChannels(numRhsChannelsToAdd)
lhsChannelsToAdd.zip(rhsChannelsToAdd)
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
rhsPortIndex += 1
} else {
lhsPort.takeRemainingChannels().zip(rhsPort.takeRemainingChannels())
.forEach { res.add(UcConnectionChannel(it.first, it.second, conn)) }
rhsPortIndex += 1
lhsPortIndex += 1
}

// If we are out of lhs variables, but not rhs, then there should be an iterated connection.
// We handle it by resetting the lhsChannels variable and index and continuing until
// we have been through all rhs channels.
if (lhsPortIndex >= lhsPorts.size && rhsPortIndex < rhsPorts.size) {
assert(conn.isIterated)
lhsPorts = getUcPorts(conn.leftPorts, federates)
lhsPortIndex = 0
}
}
return res
}

companion object {
private val Connection.delayString
get(): String = this.delay.orNever().toCCode()

/** Whether we have initialized the UcFederates with NetworkInterfaces. This is only done once. */
private var federateInterfacesInitialized = false
/** A global list of FederatedConnectionBundles. It is computed once and reused when code-generating */
private var allFederatedConnectionBundles: List<UcFederatedConnectionBundle> = emptyList()

private fun createFederatedConnectionBundles(groupedConnections: List<UcGroupedConnection>) {
Expand Down
Loading

0 comments on commit dd61844

Please sign in to comment.