Skip to content

Commit 34cbb8b

Browse files
authored
Merge pull request #12 from PRETgroup/network-functions
Network functions
2 parents b785a1a + b6a92cd commit 34cbb8b

12 files changed

Lines changed: 262 additions & 197 deletions

File tree

specs/HAML.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Hybrid Automata Modelling Language (HAML)
22

3-
#### Version: 0.1.5
3+
#### Version: 0.1.6
44

55
## Introduction
66

@@ -158,6 +158,7 @@ A Network can instantiate further networks inside of it, to create a hierarchica
158158
| definitions | Map[String, [Network](#network) \| [Automata](#automata)] | **Required.** A set of definitions of Hybrid Networks or Hybrid Automata that can be instantiated. |
159159
| instances | Map[String, [Instance](#instance) \| String] | **Required.** A set of instances of previously defined Hybrid Networks or Hybrid Automata. |
160160
| mappings | Map[String, [Formula](#formula)] | A set of mappings that determine the value of each output of this network, or input of each Instance. |
161+
| functions | Map[String, [Function](#function)] | A set of functions that exist inside this Hybrid Network. |
161162
162163
163164
#### Example
@@ -742,6 +743,7 @@ codegenConfig:
742743

743744
| Version | Date | Notes |
744745
|---|---|---|
746+
| 0.1.6 | 2020-09-14 | Added support for functions inside Networks |
745747
| 0.1.5 | 2020-06-08 | Added support for loops in custom functions, including `for` and `break` statements |
746748
| 0.1.4 | 2020-02-25 | Added support for more functions: `Power`, `Natural Log`, `Floor`, `Ceil` |
747749
| 0.1.3 | 2019-04-26 | Added support for trigonometric functions and constants |

src/main/kotlin/me/nallen/modularcodegeneration/codegen/CodeGenManager.kt

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -122,21 +122,19 @@ object CodeGenManager {
122122
val functionTypes = LinkedHashMap<String, VariableType?>()
123123
val functionArguments = LinkedHashMap<String, List<VariableType>>()
124124

125-
if(item is HybridAutomata) {
126-
// We need to parametrise every function
127-
for(function in item.functions) {
128-
// All variables that are either inputs, or parameters, end up the same - they get set externally.
129-
val inputs = ArrayList(function.inputs)
130-
inputs.addAll(item.variables.filter {it.locality == Locality.PARAMETER}.map { VariableDeclaration(it.name, it.type, ParseTreeLocality.EXTERNAL_INPUT, it.defaultValue) })
131-
132-
// So now we collect all internal variables given we know about the external inputs and parameters
133-
function.logic.collectVariables(inputs, functionTypes, functionArguments)
134-
135-
// Get the return type, and keep track of it too
136-
function.returnType = function.logic.getReturnType(functionTypes)
137-
functionTypes[function.name] = function.returnType
138-
functionArguments[function.name] = function.inputs.map { it.type }
139-
}
125+
// We need to parametrise every function
126+
for(function in item.functions) {
127+
// All variables that are either inputs, or parameters, end up the same - they get set externally.
128+
val inputs = ArrayList(function.inputs)
129+
inputs.addAll(item.variables.filter {it.locality == Locality.PARAMETER}.map { VariableDeclaration(it.name, it.type, ParseTreeLocality.EXTERNAL_INPUT, it.defaultValue) })
130+
131+
// So now we collect all internal variables given we know about the external inputs and parameters
132+
function.logic.collectVariables(inputs, functionTypes, functionArguments)
133+
134+
// Get the return type, and keep track of it too
135+
function.returnType = function.logic.getReturnType(functionTypes)
136+
functionTypes[function.name] = function.returnType
137+
functionArguments[function.name] = function.inputs.map { it.type }
140138
}
141139

142140
// Now for the new automata, we want to set the value for each parameter

src/main/kotlin/me/nallen/modularcodegeneration/codegen/c/CFileGenerator.kt

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,9 @@ object CFileGenerator {
6060
result.appendln("#include \"${Utils.createFileName(item.name)}.h\"")
6161
result.appendln()
6262

63-
// If this is an Automata, then we also want to add the custom functions
64-
if(item is HybridAutomata) {
65-
//Generate the code for any custom functions, if any
66-
if(item.functions.size > 0)
67-
result.appendln(generateCustomFunctions(item))
68-
}
63+
//Generate the code for any custom functions, if any
64+
if(item.functions.size > 0)
65+
result.appendln(generateCustomFunctions(item))
6966

7067
// If we're supporting run time parametrisation then we want to generate the default parametrisation function
7168
if(config.parametrisationMethod == ParametrisationMethod.RUN_TIME)
@@ -85,7 +82,7 @@ object CFileGenerator {
8582
* Generates a string that captures all custom functions defined in this automata, including both the method
8683
* signatures and the method bodies
8784
*/
88-
private fun generateCustomFunctions(automata: HybridAutomata): String {
85+
private fun generateCustomFunctions(item: HybridItem): String {
8986
val result = StringBuilder()
9087

9188
// Iterate over every function in the automaton

src/main/kotlin/me/nallen/modularcodegeneration/codegen/vhdl/AutomataGenerator.kt

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import me.nallen.modularcodegeneration.hybridautomata.Locality
77
import me.nallen.modularcodegeneration.parsetree.*
88
import me.nallen.modularcodegeneration.parsetree.Variable
99
import me.nallen.modularcodegeneration.codegen.vhdl.Utils.VariableObject
10+
import me.nallen.modularcodegeneration.codegen.vhdl.Utils.CustomFunctionObject
1011
import kotlin.collections.ArrayList
1112
import kotlin.collections.HashMap
1213

@@ -268,26 +269,6 @@ object AutomataGenerator {
268269
var initialLocation: String = ""
269270
)
270271

271-
/**
272-
* A class which stores information about custom functions that need to be declared
273-
*/
274-
data class CustomFunctionObject(
275-
// The name of the funtion
276-
var name: String,
277-
278-
// The return type of the function
279-
var returnType: String,
280-
281-
// A list of any inputs that are required when the function is called
282-
var inputs: MutableList<VariableObject> = ArrayList(),
283-
284-
// A list of internal variables of the function
285-
var variables: MutableList<VariableObject> = ArrayList(),
286-
287-
// The logic (body) of the function
288-
var logic: MutableList<String> = ArrayList()
289-
)
290-
291272
/**
292273
* A class which contains all information about a single location of the automaton
293274
*/

src/main/kotlin/me/nallen/modularcodegeneration/codegen/vhdl/NetworkGenerator.kt

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ package me.nallen.modularcodegeneration.codegen.vhdl
33
import com.hubspot.jinjava.Jinjava
44
import me.nallen.modularcodegeneration.codegen.Configuration
55
import me.nallen.modularcodegeneration.codegen.vhdl.Utils.VariableObject
6+
import me.nallen.modularcodegeneration.codegen.vhdl.Utils.CustomFunctionObject
67
import me.nallen.modularcodegeneration.hybridautomata.HybridAutomata
78
import me.nallen.modularcodegeneration.hybridautomata.HybridNetwork
89
import me.nallen.modularcodegeneration.hybridautomata.Locality
910
import me.nallen.modularcodegeneration.hybridautomata.Variable
1011
import me.nallen.modularcodegeneration.parsetree.And
1112
import me.nallen.modularcodegeneration.parsetree.ParseTreeItem
1213
import me.nallen.modularcodegeneration.parsetree.VariableType
14+
import me.nallen.modularcodegeneration.parsetree.Variable as ParseTreeVariable
1315
import java.util.*
1416
import kotlin.collections.ArrayList
1517
import kotlin.collections.HashMap
@@ -57,6 +59,54 @@ object NetworkGenerator {
5759
rootItem.variables.add(variableObject)
5860
}
5961

62+
// Now it's time to create all the functions that we need
63+
val functionParams = HashMap<String, ArrayList<ParseTreeItem>>()
64+
65+
// Iterate through every function we want to declare
66+
for(func in item.functions) {
67+
// Create a function object
68+
val functionObject = CustomFunctionObject(
69+
Utils.createFunctionName(func.name),
70+
Utils.generateBasicVHDLType(func.returnType)
71+
)
72+
73+
// We keep track of (extra) parameters that are needed for each function call. This will basically just be
74+
// parameters that are fed into this automaton
75+
functionParams[func.name] = ArrayList()
76+
77+
// Iterate over every input to the function
78+
for(input in func.inputs) {
79+
// And then we want to add that to the function object
80+
functionObject.inputs.add(VariableObject.create(me.nallen.modularcodegeneration.hybridautomata.Variable(input.name, input.type, Locality.EXTERNAL_INPUT, input.defaultValue)))
81+
}
82+
83+
// We also need to find all of the internal variables that we need, this is any internal variable which
84+
// isn't a parameter
85+
for(internal in func.logic.variables.filter {it.locality == ParseTreeLocality.INTERNAL}) {
86+
// And then we can add internal variables
87+
functionObject.variables.add(VariableObject.create(me.nallen.modularcodegeneration.hybridautomata.Variable(internal.name, internal.type, Locality.INTERNAL, internal.defaultValue)))
88+
}
89+
90+
// If we are doing run-time parametrisation then we also need to deal with parameters
91+
if(config.runTimeParametrisation) {
92+
// We want to go through each parameter that is used in this function
93+
for(internal in func.logic.variables.filter {it.locality == ParseTreeLocality.EXTERNAL_INPUT}
94+
.filter {item.variables.any { search -> search.locality == Locality.PARAMETER && search.name == it.name }}) {
95+
// Add it as an external input
96+
functionObject.inputs.add(VariableObject.create(me.nallen.modularcodegeneration.hybridautomata.Variable(internal.name, internal.type, Locality.EXTERNAL_INPUT, internal.defaultValue)))
97+
98+
// And keep track of the extra parameter that needs to be added to functions
99+
functionParams[func.name]!!.add(ParseTreeVariable(internal.name))
100+
}
101+
}
102+
103+
// Now we want to generate the internal logic for the function
104+
functionObject.logic.addAll(Utils.generateCodeForProgram(func.logic).split("\n"))
105+
106+
// And record the function so that we can add it to the end file
107+
rootItem.customFunctions.add(functionObject)
108+
}
109+
60110
// Depending on the parametrisation method, we'll do things slightly differently
61111
if(config.compileTimeParametrisation) {
62112
// We only want to generate each definition once (because generics), so keep track of them
@@ -398,14 +448,14 @@ object NetworkGenerator {
398448
// If it's a local signal, then we want to check signalNameMap
399449
rootItem.mappings.add(MappingObject(
400450
Utils.createVariableName(signalNameMap[destination.variable] ?: destination.variable),
401-
Utils.generateCodeForParseTreeItem(value, Utils.PrefixData("", signalNameMap))
451+
Utils.generateCodeForParseTreeItem(value, Utils.PrefixData("", signalNameMap, functionParams))
402452
))
403453
}
404454
else {
405455
// Otherwise we use the automata name
406456
rootItem.mappings.add(MappingObject(
407457
Utils.createVariableName(destination.automata, destination.variable),
408-
Utils.generateCodeForParseTreeItem(value, Utils.PrefixData("", signalNameMap))
458+
Utils.generateCodeForParseTreeItem(value, Utils.PrefixData("", signalNameMap, functionParams))
409459
))
410460
}
411461
}
@@ -462,6 +512,9 @@ object NetworkGenerator {
462512
// The Mappings between variables that need to be done once per tick
463513
var mappings: MutableList<MappingObject> = ArrayList(),
464514

515+
// A list of custom functions that need to be declared for the operation
516+
var customFunctions: MutableList<CustomFunctionObject> = ArrayList(),
517+
465518
// If run-time parametrisation is being done then this will be a list of run-time processes to be
466519
// declared which will do all of the execution for each instantiate of each type
467520
var runtimeMappingProcesses: MutableList<RuntimeMappingProcessObject> = ArrayList(),

src/main/kotlin/me/nallen/modularcodegeneration/codegen/vhdl/Utils.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,4 +499,24 @@ object Utils {
499499
}
500500
}
501501
}
502+
503+
/**
504+
* A class which stores information about custom functions that need to be declared
505+
*/
506+
data class CustomFunctionObject(
507+
// The name of the funtion
508+
var name: String,
509+
510+
// The return type of the function
511+
var returnType: String,
512+
513+
// A list of any inputs that are required when the function is called
514+
var inputs: MutableList<VariableObject> = ArrayList(),
515+
516+
// A list of internal variables of the function
517+
var variables: MutableList<VariableObject> = ArrayList(),
518+
519+
// The logic (body) of the function
520+
var logic: MutableList<String> = ArrayList()
521+
)
502522
}

src/main/kotlin/me/nallen/modularcodegeneration/description/haml/Exporter.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ private fun createNetwork(network: HybridNetwork): Network {
9898

9999
definition.loadMappings(network.ioMapping)
100100

101+
definition.loadFunctions(network.functions)
102+
101103
return definition
102104
}
103105

@@ -219,9 +221,9 @@ private fun createTransitionDefinition(edge: HybridEdge): Transition {
219221
}
220222

221223
/**
222-
* Loads the functions from a Hybrid Automata into an Automata DefinitionItem
224+
* Loads the functions from a Hybrid Item into a DefinitionItem
223225
*/
224-
private fun Automata.loadFunctions(functions: List<HybridFunction>) {
226+
private fun DefinitionItem.loadFunctions(functions: List<HybridFunction>) {
225227
if(functions.isNotEmpty() && this.functions == null)
226228
this.functions = LinkedHashMap()
227229

src/main/kotlin/me/nallen/modularcodegeneration/description/haml/Importer.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,6 @@ private fun createHybridAutomata(name: String, definition: Automata): HybridAuto
143143
// Load the common features
144144
automata.loadData(name, definition)
145145

146-
// And then any custom functions that it may contain
147-
automata.loadFunctions(definition.functions)
148-
149146
// Add the locations (transitions are within locations)
150147
automata.loadLocations(definition.locations)
151148

@@ -194,6 +191,9 @@ private fun HybridItem.loadData(name: String, definition: DefinitionItem) {
194191

195192
// And all parameters
196193
this.loadVariables(definition.parameters, Locality.PARAMETER)
194+
195+
// And then any custom functions that it may contain
196+
this.loadFunctions(definition.functions)
197197
}
198198

199199
/**
@@ -314,9 +314,9 @@ private fun HybridAutomata.loadInitialisation(init: Initialisation?) {
314314
}
315315

316316
/**
317-
* Imports a set of HAML Function definitions into the given HybridAutomata instantiate
317+
* Imports a set of HAML Function definitions into the given HybridItem instantiate
318318
*/
319-
private fun HybridAutomata.loadFunctions(functions: Map<String, Function>?) {
319+
private fun HybridItem.loadFunctions(functions: Map<String, Function>?) {
320320
// We need to keep track of functions we know about and their return types
321321
val existingFunctionTypes = LinkedHashMap<String, ParseTreeVariableType?>()
322322
val existingFunctionArguments = LinkedHashMap<String, List<ParseTreeVariableType>>()

src/main/kotlin/me/nallen/modularcodegeneration/description/haml/Schema.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ class Automata: DefinitionItem() {
4444
// The locations that exist inside this Hybrid Automata
4545
var locations: LinkedHashMap<String, Location>? = null
4646

47-
// A set of functions that exist inside this Hybrid Automata
48-
var functions: LinkedHashMap<String, Function>? = null
49-
5047
// Sets the initialisation options for the Hybrid Automata (location, variable states, etc.)
5148
var initialisation: Initialisation? = null
5249
}
@@ -61,9 +58,12 @@ sealed class DefinitionItem {
6158
// The variables that this Hybrid Item emits as outputs
6259
var outputs: LinkedHashMap<String, VariableDefinition>? = null
6360

64-
// The parameters that are available for configuration of this Hybrid Automata
61+
// The parameters that are available for configuration of this Hybrid Item
6562
var parameters: LinkedHashMap<String, VariableDefinition>? = null
6663

64+
// A set of functions that exist inside this Hybrid Item
65+
var functions: LinkedHashMap<String, Function>? = null
66+
6767
companion object Factory {
6868
// Method for creating from a String (used in JSON parsing)
6969
@JsonCreator @JvmStatic

0 commit comments

Comments
 (0)