@sdeverywhere/compile 0.7.6 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generate/code-gen.js +41 -4
- package/src/model/model.js +109 -2
- package/src/parse-and-generate.js +3 -1
package/package.json
CHANGED
package/src/generate/code-gen.js
CHANGED
|
@@ -163,7 +163,17 @@ const char* getHeader() {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
void storeOutputData() {
|
|
166
|
-
${
|
|
166
|
+
${specOutputSection(outputVars)}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
void storeOutput(size_t varIndex, size_t subIndex0, size_t subIndex1, size_t subIndex2) {
|
|
170
|
+
#if SDE_USE_OUTPUT_INDICES
|
|
171
|
+
switch (varIndex) {
|
|
172
|
+
${fullOutputSection(Model.varIndexInfo())}
|
|
173
|
+
default:
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
#endif
|
|
167
177
|
}
|
|
168
178
|
`
|
|
169
179
|
}
|
|
@@ -250,11 +260,16 @@ ${postStep}
|
|
|
250
260
|
}
|
|
251
261
|
function internalVarsSection() {
|
|
252
262
|
// Declare internal variables to run the model.
|
|
263
|
+
let decls
|
|
253
264
|
if (outputAllVars) {
|
|
254
|
-
|
|
265
|
+
decls = `const int numOutputs = ${expandedVarNames().length};`
|
|
255
266
|
} else {
|
|
256
|
-
|
|
267
|
+
decls = `const int numOutputs = ${spec.outputVars.length};`
|
|
257
268
|
}
|
|
269
|
+
decls += `\n#define SDE_USE_OUTPUT_INDICES 0`
|
|
270
|
+
decls += `\n#define SDE_MAX_OUTPUT_INDICES 1000`
|
|
271
|
+
decls += `\nconst int maxOutputIndices = SDE_USE_OUTPUT_INDICES ? SDE_MAX_OUTPUT_INDICES : 0;`
|
|
272
|
+
return decls
|
|
258
273
|
}
|
|
259
274
|
function arrayDimensionsSection() {
|
|
260
275
|
// Emit a declaration for each array dimension's index numbers.
|
|
@@ -312,12 +327,34 @@ ${postStep}
|
|
|
312
327
|
//
|
|
313
328
|
// Input/output section helpers
|
|
314
329
|
//
|
|
315
|
-
function
|
|
330
|
+
function specOutputSection(varNames) {
|
|
316
331
|
// Emit output calls using varNames in C format.
|
|
317
332
|
let code = R.map(varName => ` outputVar(${varName});`)
|
|
318
333
|
let section = R.pipe(code, lines)
|
|
319
334
|
return section(varNames)
|
|
320
335
|
}
|
|
336
|
+
function fullOutputSection(varIndexInfo) {
|
|
337
|
+
// Emit output calls for all variables.
|
|
338
|
+
const code = R.map(info => {
|
|
339
|
+
let varAccess = info.varName
|
|
340
|
+
if (info.subscriptCount > 0) {
|
|
341
|
+
varAccess += '[subIndex0]'
|
|
342
|
+
}
|
|
343
|
+
if (info.subscriptCount > 1) {
|
|
344
|
+
varAccess += '[subIndex1]'
|
|
345
|
+
}
|
|
346
|
+
if (info.subscriptCount > 2) {
|
|
347
|
+
varAccess += '[subIndex2]'
|
|
348
|
+
}
|
|
349
|
+
let c = ''
|
|
350
|
+
c += ` case ${info.varIndex}:\n`
|
|
351
|
+
c += ` outputVar(${varAccess});\n`
|
|
352
|
+
c += ` break;`
|
|
353
|
+
return c
|
|
354
|
+
})
|
|
355
|
+
const section = R.pipe(code, lines)
|
|
356
|
+
return section(varIndexInfo)
|
|
357
|
+
}
|
|
321
358
|
function inputsFromStringImpl() {
|
|
322
359
|
// If there was an I/O spec file, then emit code to parse input variables.
|
|
323
360
|
// The user can replace this with a parser for a different serialization format.
|
package/src/model/model.js
CHANGED
|
@@ -330,8 +330,14 @@ function removeUnusedVariables(spec) {
|
|
|
330
330
|
if (!referencedRefIds.has(refId)) {
|
|
331
331
|
referencedRefIds.add(refId)
|
|
332
332
|
const refVar = varWithRefId(refId)
|
|
333
|
-
|
|
334
|
-
|
|
333
|
+
if (refVar) {
|
|
334
|
+
recordUsedVariable(refVar)
|
|
335
|
+
recordRefsOfVariable(refVar)
|
|
336
|
+
} else {
|
|
337
|
+
console.error(`No var found for ${refId}`)
|
|
338
|
+
console.error(v)
|
|
339
|
+
process.exit(1)
|
|
340
|
+
}
|
|
335
341
|
}
|
|
336
342
|
}
|
|
337
343
|
}
|
|
@@ -1010,6 +1016,105 @@ function printDepsGraph(graph, varType) {
|
|
|
1010
1016
|
console.error(`${dep[0]} → ${dep[1]}`)
|
|
1011
1017
|
}
|
|
1012
1018
|
}
|
|
1019
|
+
|
|
1020
|
+
function allListedVars() {
|
|
1021
|
+
// Put variables into the order that they are evaluated by SDE in the generated model
|
|
1022
|
+
let vars = []
|
|
1023
|
+
vars.push(...constVars())
|
|
1024
|
+
vars.push(...lookupVars())
|
|
1025
|
+
vars.push(...dataVars())
|
|
1026
|
+
vars.push(varWithName('_time'))
|
|
1027
|
+
vars.push(...initVars())
|
|
1028
|
+
vars.push(...auxVars())
|
|
1029
|
+
// TODO: Also levelVars not covered by initVars?
|
|
1030
|
+
|
|
1031
|
+
// Filter out data/lookup variables and variables that are generated/used internally
|
|
1032
|
+
const isInternal = v => {
|
|
1033
|
+
return v.refId.startsWith('__level') || v.refId.startsWith('__aux')
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
return R.filter(v => !isInternal(v), vars)
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
function filteredListedVars() {
|
|
1040
|
+
// Extract a subset of the available info for each variable and sort all variables
|
|
1041
|
+
// according to the order that they are evaluated by SDE in the generated model
|
|
1042
|
+
return R.map(v => filterVar(v), allListedVars())
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
function varIndexInfoMap() {
|
|
1046
|
+
// Return a map containing information for each listed variable:
|
|
1047
|
+
// varName
|
|
1048
|
+
// varIndex
|
|
1049
|
+
// subscriptCount
|
|
1050
|
+
|
|
1051
|
+
// Get the filtered variables in the order that they are evaluated by SDE in the
|
|
1052
|
+
// generated model
|
|
1053
|
+
const sortedVars = filteredListedVars()
|
|
1054
|
+
|
|
1055
|
+
// Get the set of unique variable names, and assign a 1-based index
|
|
1056
|
+
// to each; this matches the index number used in `storeOutput()`
|
|
1057
|
+
// in the generated C code
|
|
1058
|
+
const infoMap = new Map()
|
|
1059
|
+
let varIndex = 1
|
|
1060
|
+
for (const v of sortedVars) {
|
|
1061
|
+
if (v.varType === 'data' || v.varType === 'lookup') {
|
|
1062
|
+
// Omit the index for data and lookup variables; at this time, the data for these
|
|
1063
|
+
// cannot be output like for other types of variables
|
|
1064
|
+
continue
|
|
1065
|
+
}
|
|
1066
|
+
const varName = v.varName
|
|
1067
|
+
if (!infoMap.get(varName)) {
|
|
1068
|
+
infoMap.set(varName, {
|
|
1069
|
+
varName,
|
|
1070
|
+
varIndex,
|
|
1071
|
+
subscriptCount: v.families ? v.families.length : 0
|
|
1072
|
+
})
|
|
1073
|
+
varIndex++
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return infoMap
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function varIndexInfo() {
|
|
1081
|
+
// Return an array, sorted by `varName`, containing information for each
|
|
1082
|
+
// listed variable:
|
|
1083
|
+
// varName
|
|
1084
|
+
// varIndex
|
|
1085
|
+
// subscriptCount
|
|
1086
|
+
return Array.from(varIndexInfoMap().values())
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
function jsonList() {
|
|
1090
|
+
// Return a stringified JSON object containing variable and subscript information
|
|
1091
|
+
// for the model.
|
|
1092
|
+
|
|
1093
|
+
// Get the set of available subscripts
|
|
1094
|
+
const allDims = [...allDimensions()]
|
|
1095
|
+
const sortedDims = allDims.sort((a, b) => a.name.localeCompare(b.name))
|
|
1096
|
+
|
|
1097
|
+
// Extract a subset of the available info for each variable and put them in eval order
|
|
1098
|
+
const sortedVars = filteredListedVars()
|
|
1099
|
+
|
|
1100
|
+
// Assign a 1-based index for each variable that has data that can be accessed.
|
|
1101
|
+
// This matches the index number used in `storeOutput()` in the generated C code.
|
|
1102
|
+
const infoMap = varIndexInfoMap()
|
|
1103
|
+
for (const v of sortedVars) {
|
|
1104
|
+
const varInfo = infoMap.get(v.varName)
|
|
1105
|
+
if (varInfo) {
|
|
1106
|
+
v.varIndex = varInfo.varIndex
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// Convert to JSON
|
|
1111
|
+
const obj = {
|
|
1112
|
+
dimensions: sortedDims,
|
|
1113
|
+
variables: sortedVars
|
|
1114
|
+
}
|
|
1115
|
+
return JSON.stringify(obj, null, 2)
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1013
1118
|
export default {
|
|
1014
1119
|
addConstantExpr,
|
|
1015
1120
|
addEquation,
|
|
@@ -1026,6 +1131,7 @@ export default {
|
|
|
1026
1131
|
initVars,
|
|
1027
1132
|
isInputVar,
|
|
1028
1133
|
isNonAtoAName,
|
|
1134
|
+
jsonList,
|
|
1029
1135
|
levelVars,
|
|
1030
1136
|
lookupVars,
|
|
1031
1137
|
printRefGraph,
|
|
@@ -1036,6 +1142,7 @@ export default {
|
|
|
1036
1142
|
refIdsWithName,
|
|
1037
1143
|
splitRefId,
|
|
1038
1144
|
variables,
|
|
1145
|
+
varIndexInfo,
|
|
1039
1146
|
varNames,
|
|
1040
1147
|
varsWithName,
|
|
1041
1148
|
varWithName,
|
|
@@ -17,7 +17,7 @@ import { generateCode } from './generate/code-gen.js'
|
|
|
17
17
|
*
|
|
18
18
|
* - If `operation` is 'generateC', the generated C code will be written to `buildDir`.
|
|
19
19
|
* - If `operation` is 'printVarList', variables and subscripts will be written to
|
|
20
|
-
* txt and
|
|
20
|
+
* txt, yaml, and json files under `buildDir`.
|
|
21
21
|
* - If `operation` is 'printRefIdTest', reference identifiers will be printed to the console.
|
|
22
22
|
* - If `operation` is 'convertNames', no output will be generated, but the results of model
|
|
23
23
|
* analysis will be available.
|
|
@@ -85,6 +85,8 @@ export async function parseAndGenerate(input, spec, operation, modelDirname, mod
|
|
|
85
85
|
writeOutput(`${modelName}_vars.yaml`, Model.yamlVarList())
|
|
86
86
|
// Write subscripts to a YAML file.
|
|
87
87
|
writeOutput(`${modelName}_subs.yaml`, yamlSubsList())
|
|
88
|
+
// Write variables and subscripts to a JSON file.
|
|
89
|
+
writeOutput(`${modelName}.json`, Model.jsonList())
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
return code
|