@sdeverywhere/compile 0.7.27 → 0.7.28
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 +2 -2
- package/src/generate/gen-expr.js +87 -37
- package/src/index.js +9 -1
- package/src/model/model.js +79 -5
- package/src/model/read-equation-fn-delay.js +6 -4
- package/src/model/read-equation-fn-smooth.js +7 -5
- package/src/model/read-equation-fn-trend.js +1 -1
- package/src/model/read-equations.js +541 -234
- package/src/parse-and-generate.js +35 -23
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdeverywhere/compile",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.28",
|
|
4
4
|
"description": "The core Vensim to C compiler for the SDEverywhere tool suite.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@sdeverywhere/parse": "^0.1.
|
|
8
|
+
"@sdeverywhere/parse": "^0.1.3",
|
|
9
9
|
"byline": "^5.0.0",
|
|
10
10
|
"csv-parse": "^5.3.3",
|
|
11
11
|
"ramda": "^0.27.0",
|
package/src/generate/gen-expr.js
CHANGED
|
@@ -162,8 +162,28 @@ export function generateExpr(expr, ctx) {
|
|
|
162
162
|
* @return {string} The generated C/JS code.
|
|
163
163
|
*/
|
|
164
164
|
function generateFunctionCall(callExpr, ctx) {
|
|
165
|
-
|
|
165
|
+
function generateSimpleFunctionCall(fnId) {
|
|
166
|
+
const args = callExpr.args.map(argExpr => generateExpr(argExpr, ctx))
|
|
167
|
+
if (ctx.outFormat === 'js' && fnId === '_IF_THEN_ELSE') {
|
|
168
|
+
// When generating conditional expressions for JS target, since we can't rely on macros like we do for C,
|
|
169
|
+
// it is better to translate it into a ternary instead of relying on a built-in function (since the latter
|
|
170
|
+
// would require always evaluating both branches, while the former can be more optimized by the interpreter)
|
|
171
|
+
return `((${args[0]}) ? (${args[1]}) : (${args[2]}))`
|
|
172
|
+
} else {
|
|
173
|
+
// For simple functions, emit a C/JS function call with a generated C/JS expression for each argument
|
|
174
|
+
return `${fnRef(fnId, ctx)}(${args.join(', ')})`
|
|
175
|
+
}
|
|
176
|
+
}
|
|
166
177
|
|
|
178
|
+
function generateLookupFunctionCall(fnId) {
|
|
179
|
+
// For LOOKUP* functions, the first argument must be a reference to the lookup variable. Emit
|
|
180
|
+
// a C/JS function call with a generated C/JS expression for each remaining argument.
|
|
181
|
+
const cVarRef = ctx.cVarRef(callExpr.args[0])
|
|
182
|
+
const cArgs = callExpr.args.slice(1).map(arg => generateExpr(arg, ctx))
|
|
183
|
+
return `${fnRef(fnId, ctx)}(${cVarRef}, ${cArgs.join(', ')})`
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const fnId = callExpr.fnId
|
|
167
187
|
switch (fnId) {
|
|
168
188
|
//
|
|
169
189
|
//
|
|
@@ -174,46 +194,54 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
174
194
|
//
|
|
175
195
|
//
|
|
176
196
|
|
|
197
|
+
// Simple functions that are common to Vensim and XMILE/Stella
|
|
177
198
|
case '_ABS':
|
|
178
199
|
case '_ARCCOS':
|
|
179
200
|
case '_ARCSIN':
|
|
180
201
|
case '_ARCTAN':
|
|
181
202
|
case '_COS':
|
|
182
203
|
case '_EXP':
|
|
183
|
-
case '_GAMMA_LN':
|
|
184
204
|
case '_IF_THEN_ELSE':
|
|
185
|
-
case '_INTEGER':
|
|
186
205
|
case '_LN':
|
|
187
206
|
case '_MAX':
|
|
188
207
|
case '_MIN':
|
|
189
|
-
case '_MODULO':
|
|
190
|
-
case '_POW':
|
|
191
|
-
case '_POWER':
|
|
192
|
-
case '_PULSE':
|
|
193
|
-
case '_PULSE_TRAIN':
|
|
194
|
-
case '_QUANTUM':
|
|
195
208
|
case '_RAMP':
|
|
196
209
|
case '_SIN':
|
|
197
210
|
case '_SQRT':
|
|
198
211
|
case '_STEP':
|
|
199
212
|
case '_TAN':
|
|
213
|
+
return generateSimpleFunctionCall(fnId)
|
|
214
|
+
|
|
215
|
+
// Simple functions supported by Vensim only
|
|
216
|
+
case '_GAMMA_LN':
|
|
217
|
+
case '_INTEGER':
|
|
218
|
+
case '_MODULO':
|
|
219
|
+
case '_POW':
|
|
220
|
+
case '_POWER':
|
|
221
|
+
case '_PULSE_TRAIN':
|
|
222
|
+
case '_PULSE':
|
|
223
|
+
case '_QUANTUM':
|
|
200
224
|
case '_WITH_LOOKUP':
|
|
201
225
|
case '_XIDZ':
|
|
202
|
-
case '_ZIDZ':
|
|
203
|
-
const args = callExpr.args.map(argExpr => generateExpr(argExpr, ctx))
|
|
226
|
+
case '_ZIDZ':
|
|
204
227
|
if (ctx.outFormat === 'js' && fnId === '_GAMMA_LN') {
|
|
205
228
|
throw new Error(`${callExpr.fnName} function not yet implemented for JS code gen`)
|
|
206
229
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
230
|
+
return generateSimpleFunctionCall(fnId)
|
|
231
|
+
|
|
232
|
+
// Simple functions supported by XMILE/Stella only
|
|
233
|
+
case '_INT':
|
|
234
|
+
// XMILE/Stella uses `INT`, but it is the same as the Vensim `INTEGER` function,
|
|
235
|
+
// which is the name used in the runtime function implementation
|
|
236
|
+
return generateSimpleFunctionCall('_INTEGER')
|
|
237
|
+
case '_MOD':
|
|
238
|
+
// XMILE/Stella uses `MOD`, but it is the same as the Vensim `MODULO` function,
|
|
239
|
+
// which is the name used in the runtime function implementation
|
|
240
|
+
return generateSimpleFunctionCall('_MODULO')
|
|
241
|
+
case '_SAFEDIV':
|
|
242
|
+
// XMILE/Stella uses `SAFEDIV`, but it is the same as the Vensim `ZIDZ` function,
|
|
243
|
+
// which is the name used in the runtime function implementation
|
|
244
|
+
return generateSimpleFunctionCall('_ZIDZ')
|
|
217
245
|
|
|
218
246
|
//
|
|
219
247
|
//
|
|
@@ -225,17 +253,12 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
225
253
|
//
|
|
226
254
|
//
|
|
227
255
|
|
|
256
|
+
// Lookup functions supported by Vensim only
|
|
228
257
|
case '_GET_DATA_BETWEEN_TIMES':
|
|
229
258
|
case '_LOOKUP_BACKWARD':
|
|
230
259
|
case '_LOOKUP_FORWARD':
|
|
231
|
-
case '_LOOKUP_INVERT':
|
|
232
|
-
|
|
233
|
-
// a C/JS function call with a generated C/JS expression for each remaining argument.
|
|
234
|
-
const cVarRef = ctx.cVarRef(callExpr.args[0])
|
|
235
|
-
const cArgs = callExpr.args.slice(1).map(arg => generateExpr(arg, ctx))
|
|
236
|
-
return `${fnRef(fnId, ctx)}(${cVarRef}, ${cArgs.join(', ')})`
|
|
237
|
-
}
|
|
238
|
-
|
|
260
|
+
case '_LOOKUP_INVERT':
|
|
261
|
+
return generateLookupFunctionCall(fnId)
|
|
239
262
|
case '_GAME': {
|
|
240
263
|
// For the GAME function, emit a C/JS function call that has the synthesized game inputs lookup
|
|
241
264
|
// as the first argument, followed by the default value argument from the function call
|
|
@@ -244,6 +267,16 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
244
267
|
return `${fnRef(fnId, ctx)}(${cLookupArg}, ${cDefaultArg})`
|
|
245
268
|
}
|
|
246
269
|
|
|
270
|
+
// Lookup functions supported by XMILE/Stella only
|
|
271
|
+
case '_LOOKUP':
|
|
272
|
+
// XMILE/Stella has an explicit `LOOKUP` function while Vensim uses `x(y)` syntax, but
|
|
273
|
+
// underneath both are implemented at runtime by the `LOOKUP` function
|
|
274
|
+
return generateLookupFunctionCall('_LOOKUP')
|
|
275
|
+
case '_LOOKUPINV':
|
|
276
|
+
// XMILE/Stella uses `LOOKUPINV`, but it is the same as the Vensim `LOOKUP INVERT` function,
|
|
277
|
+
// which is the name used in the runtime function implementation
|
|
278
|
+
return generateLookupFunctionCall('_LOOKUP_INVERT')
|
|
279
|
+
|
|
247
280
|
//
|
|
248
281
|
//
|
|
249
282
|
// Level functions
|
|
@@ -251,12 +284,16 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
251
284
|
//
|
|
252
285
|
|
|
253
286
|
case '_ACTIVE_INITIAL':
|
|
287
|
+
case '_DELAY':
|
|
254
288
|
case '_DELAY_FIXED':
|
|
255
289
|
case '_DEPRECIATE_STRAIGHTLINE':
|
|
256
290
|
case '_SAMPLE_IF_TRUE':
|
|
257
291
|
case '_INTEG':
|
|
258
292
|
// Split level functions into init and eval expressions
|
|
259
|
-
if (
|
|
293
|
+
if (
|
|
294
|
+
ctx.outFormat === 'js' &&
|
|
295
|
+
(fnId === '_DELAY' || fnId === '_DELAY_FIXED' || fnId === '_DEPRECIATE_STRAIGHTLINE')
|
|
296
|
+
) {
|
|
260
297
|
throw new Error(`${callExpr.fnName} function not yet implemented for JS code gen`)
|
|
261
298
|
}
|
|
262
299
|
if (ctx.mode.startsWith('init')) {
|
|
@@ -311,7 +348,12 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
311
348
|
case '_SMOOTH':
|
|
312
349
|
case '_SMOOTHI':
|
|
313
350
|
case '_SMOOTH3':
|
|
314
|
-
case '_SMOOTH3I':
|
|
351
|
+
case '_SMOOTH3I':
|
|
352
|
+
case '_SMTH1':
|
|
353
|
+
case '_SMTH3': {
|
|
354
|
+
// Note that Vensim uses `SMOOTH[I]` and `SMOOTH3[I]` while XMILE uses `SMTH1` and
|
|
355
|
+
// `SMTH3`, but otherwise they have been translated the same way during the read
|
|
356
|
+
// equations phase
|
|
315
357
|
const smoothVar = Model.varWithRefId(ctx.variable.smoothVarRefId)
|
|
316
358
|
return ctx.cVarRef(smoothVar.parsedEqn.lhs.varDef)
|
|
317
359
|
}
|
|
@@ -345,11 +387,13 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
345
387
|
}
|
|
346
388
|
return generateAllocateAvailableCall(callExpr, ctx)
|
|
347
389
|
|
|
348
|
-
case '_ELMCOUNT':
|
|
349
|
-
|
|
390
|
+
case '_ELMCOUNT':
|
|
391
|
+
case '_SIZE': {
|
|
392
|
+
// Emit the size of the dimension in place of the dimension name. Note that Vensim uses
|
|
393
|
+
// `ELMCOUNT` while XMILE uses `SIZE`, but otherwise they are the same.
|
|
350
394
|
const dimArg = callExpr.args[0]
|
|
351
395
|
if (dimArg.kind !== 'variable-ref') {
|
|
352
|
-
throw new Error(
|
|
396
|
+
throw new Error(`Argument for ${callExpr.fnName} must be a dimension name`)
|
|
353
397
|
}
|
|
354
398
|
const dimId = dimArg.varId
|
|
355
399
|
return `${sub(dimId).size}`
|
|
@@ -362,7 +406,9 @@ function generateFunctionCall(callExpr, ctx) {
|
|
|
362
406
|
throw new Error(`Unexpected function '${fnId}' in code gen for '${ctx.variable.modelLHS}'`)
|
|
363
407
|
|
|
364
408
|
case '_INITIAL':
|
|
365
|
-
|
|
409
|
+
case '_INIT':
|
|
410
|
+
// Note that Vensim uses `INITIAL` while XMILE uses `INIT`, but otherwise they are the same.
|
|
411
|
+
// In init mode, only emit the initial expression without the INITIAL function call.
|
|
366
412
|
if (ctx.mode.startsWith('init')) {
|
|
367
413
|
return generateExpr(callExpr.args[0], ctx)
|
|
368
414
|
} else {
|
|
@@ -423,6 +469,7 @@ function generateLevelInit(callExpr, ctx) {
|
|
|
423
469
|
case '_INTEG':
|
|
424
470
|
initialArgIndex = 1
|
|
425
471
|
break
|
|
472
|
+
case '_DELAY':
|
|
426
473
|
case '_DELAY_FIXED': {
|
|
427
474
|
// Emit the code that initializes the `FixedDelay` support struct
|
|
428
475
|
const fixedDelay = ctx.cVarRefWithLhsSubscripts(ctx.variable.fixedDelayVarName)
|
|
@@ -474,12 +521,15 @@ function generateLevelEval(callExpr, ctx) {
|
|
|
474
521
|
// For ACTIVE INITIAL, emit the first arg without a function call
|
|
475
522
|
return generateExpr(callExpr.args[0], ctx)
|
|
476
523
|
|
|
524
|
+
case '_DELAY':
|
|
477
525
|
case '_DELAY_FIXED': {
|
|
478
|
-
//
|
|
526
|
+
// Stella's DELAY function is behaviorally equivalent to Vensim's DELAY FIXED function, so
|
|
527
|
+
// they use the same `_DELAY_FIXED` runtime function. For these, emit the first arg
|
|
528
|
+
// followed by the FixedDelay support var.
|
|
479
529
|
const args = []
|
|
480
530
|
args.push(generateExpr(callExpr.args[0], ctx))
|
|
481
531
|
args.push(ctx.cVarRefWithLhsSubscripts(ctx.variable.fixedDelayVarName))
|
|
482
|
-
return
|
|
532
|
+
return `${fnRef('_DELAY_FIXED', ctx)}(${args.join(', ')})`
|
|
483
533
|
}
|
|
484
534
|
|
|
485
535
|
case '_DEPRECIATE_STRAIGHTLINE': {
|
package/src/index.js
CHANGED
|
@@ -35,7 +35,15 @@ export function parseInlineVensimModel(mdlContent /*: string*/, modelDir /*?: st
|
|
|
35
35
|
// the preprocess step, and in the case of the new parser (which implicitly runs the
|
|
36
36
|
// preprocess step), don't sort the definitions. This makes it easier to do apples
|
|
37
37
|
// to apples comparisons on the outputs from the two parser implementations.
|
|
38
|
-
return parseModel(mdlContent, modelDir, { sort: false })
|
|
38
|
+
return parseModel(mdlContent, 'vensim', modelDir, { sort: false })
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @hidden This is not yet part of the public API; it is exposed only for use
|
|
43
|
+
* in the experimental playground app.
|
|
44
|
+
*/
|
|
45
|
+
export function parseInlineXmileModel(mdlContent /*: string*/, modelDir /*?: string*/) /*: ParsedModel*/ {
|
|
46
|
+
return parseModel(mdlContent, 'xmile', modelDir)
|
|
39
47
|
}
|
|
40
48
|
|
|
41
49
|
/**
|
package/src/model/model.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as R from 'ramda'
|
|
2
2
|
|
|
3
|
+
import { canonicalVarId, toPrettyString } from '@sdeverywhere/parse'
|
|
4
|
+
|
|
3
5
|
import B from '../_shared/bufx.js'
|
|
4
|
-
import {
|
|
6
|
+
import { decanonicalize, isIterable, strlist, vlog, vsort } from '../_shared/helpers.js'
|
|
5
7
|
import {
|
|
6
8
|
addIndex,
|
|
7
9
|
allAliases,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
import { cName } from '../_shared/var-names.js'
|
|
16
18
|
|
|
17
19
|
import { expandVar } from './expand-var-instances.js'
|
|
18
|
-
import { readEquation } from './read-equations.js'
|
|
20
|
+
import { readEquation, resolveXmileDimensionWildcards } from './read-equations.js'
|
|
19
21
|
import { readDimensionDefs } from './read-subscripts.js'
|
|
20
22
|
import { readVariables } from './read-variables.js'
|
|
21
23
|
import { reduceVariables } from './reduce-variables.js'
|
|
@@ -92,10 +94,80 @@ function read(parsedModel, spec, extData, directData, modelDirname, opts) {
|
|
|
92
94
|
timeVar.varName = '_time'
|
|
93
95
|
vars.push(timeVar)
|
|
94
96
|
|
|
97
|
+
// Helper function to define a control variable for XMILE models
|
|
98
|
+
function defineXmileControlVar(varName, varId, rhsValue) {
|
|
99
|
+
let rhsExpr
|
|
100
|
+
if (typeof rhsValue === 'number') {
|
|
101
|
+
rhsExpr = {
|
|
102
|
+
kind: 'number',
|
|
103
|
+
value: rhsValue,
|
|
104
|
+
text: rhsValue.toString()
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
rhsExpr = {
|
|
108
|
+
kind: 'variable-ref',
|
|
109
|
+
varName: rhsValue,
|
|
110
|
+
varId: canonicalVarId(rhsValue)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const v = new Variable()
|
|
114
|
+
v.modelLHS = varName
|
|
115
|
+
v.varName = varId
|
|
116
|
+
v.parsedEqn = {
|
|
117
|
+
lhs: {
|
|
118
|
+
varDef: {
|
|
119
|
+
varName,
|
|
120
|
+
varId
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
rhs: {
|
|
124
|
+
kind: 'expr',
|
|
125
|
+
expr: rhsExpr
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
v.modelFormula = toPrettyString(rhsExpr, { compact: true })
|
|
129
|
+
v.includeInOutput = false
|
|
130
|
+
vars.push(v)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (parsedModel.kind === 'xmile') {
|
|
134
|
+
// XXX: Unlike Vensim models, XMILE models do not include the control parameters as
|
|
135
|
+
// normal model equations; instead, they are defined in the `<sim_specs>` element.
|
|
136
|
+
// In addition, XMILE allows these values to be accessed in equations (e.g., `<start>`
|
|
137
|
+
// can be accessed as `STARTTIME`, `<stop>` as `STOPTIME`, and `<dt>` as `DT`).
|
|
138
|
+
// For compatibility with the existing runtime code (which expects these variables
|
|
139
|
+
// to be defined using the Vensim names), we will synthesize variables using the
|
|
140
|
+
// Vensim names (e.g., `INITIAL TIME`) and also synthesize variables that derive
|
|
141
|
+
// from these using the XMILE names (e.g., `STARTTIME`).
|
|
142
|
+
defineXmileControlVar('INITIAL TIME', '_initial_time', parsedModel.root.simulationSpec.startTime)
|
|
143
|
+
defineXmileControlVar('FINAL TIME', '_final_time', parsedModel.root.simulationSpec.endTime)
|
|
144
|
+
defineXmileControlVar('TIME STEP', '_time_step', parsedModel.root.simulationSpec.timeStep)
|
|
145
|
+
defineXmileControlVar('STARTTIME', '_starttime', 'INITIAL TIME')
|
|
146
|
+
defineXmileControlVar('STOPTIME', '_stoptime', 'FINAL TIME')
|
|
147
|
+
defineXmileControlVar('DT', '_dt', 'TIME STEP')
|
|
148
|
+
// XXX: For now, also include a `SAVEPER` variable that is the same as `TIME STEP` (is there
|
|
149
|
+
// an equivalent of this in XMILE?)
|
|
150
|
+
defineXmileControlVar('SAVEPER', '_saveper', 'TIME STEP')
|
|
151
|
+
}
|
|
152
|
+
|
|
95
153
|
// Add the variables to the `Model`
|
|
96
154
|
vars.forEach(addVariable)
|
|
97
155
|
if (opts?.stopAfterReadVariables) return
|
|
98
156
|
|
|
157
|
+
if (parsedModel.kind === 'xmile') {
|
|
158
|
+
// XXX: In the case of XMILE, we need to resolve any wildcards used in dimension
|
|
159
|
+
// position in the RHS of the equation
|
|
160
|
+
for (const variable of vars) {
|
|
161
|
+
if (variable.parsedEqn?.rhs?.kind === 'expr') {
|
|
162
|
+
const updatedEqn = resolveXmileDimensionWildcards(variable)
|
|
163
|
+
if (updatedEqn) {
|
|
164
|
+
variable.parsedEqn = updatedEqn
|
|
165
|
+
variable.modelFormula = toPrettyString(updatedEqn.rhs.expr, { compact: true })
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
99
171
|
if (spec) {
|
|
100
172
|
// If the spec file contains `input/outputVarNames`, convert the full Vensim variable
|
|
101
173
|
// names to C names first so that later phases only need to work with canonical names
|
|
@@ -268,7 +340,7 @@ function resolveDimensions(dimensionFamilies) {
|
|
|
268
340
|
}
|
|
269
341
|
}
|
|
270
342
|
|
|
271
|
-
function analyze(
|
|
343
|
+
function analyze(modelKind, inputVars, opts) {
|
|
272
344
|
// Analyze the RHS of each equation in stages after all the variables are read.
|
|
273
345
|
// Find non-apply-to-all vars that are defined with more than one equation.
|
|
274
346
|
findNonAtoAVars()
|
|
@@ -284,7 +356,9 @@ function analyze(parsedModelKind, inputVars, opts) {
|
|
|
284
356
|
if (opts?.stopAfterReduceVariables === true) return
|
|
285
357
|
|
|
286
358
|
// Read the RHS to list the refIds of vars that are referenced and set the var type.
|
|
287
|
-
variables.forEach(
|
|
359
|
+
variables.forEach(v => {
|
|
360
|
+
readEquation(v, modelKind)
|
|
361
|
+
})
|
|
288
362
|
}
|
|
289
363
|
|
|
290
364
|
function checkSpecVars(spec) {
|
|
@@ -1221,7 +1295,7 @@ function jsonList() {
|
|
|
1221
1295
|
|
|
1222
1296
|
const varInstances = expandVar(v)
|
|
1223
1297
|
for (const { varName, subscriptIndices } of varInstances) {
|
|
1224
|
-
const varId =
|
|
1298
|
+
const varId = canonicalVarId(varName)
|
|
1225
1299
|
const varItem = {
|
|
1226
1300
|
varId,
|
|
1227
1301
|
varName,
|
|
@@ -16,10 +16,12 @@ import Model from './model.js'
|
|
|
16
16
|
/**
|
|
17
17
|
* Generate level and aux variables that implement one of the following `DELAY` function
|
|
18
18
|
* call variants:
|
|
19
|
-
* - DELAY1
|
|
20
|
-
* - DELAY1I
|
|
21
|
-
* - DELAY3
|
|
22
|
-
* - DELAY3I
|
|
19
|
+
* - DELAY1 (Vensim)
|
|
20
|
+
* - DELAY1I (Vensim)
|
|
21
|
+
* - DELAY3 (Vensim)
|
|
22
|
+
* - DELAY3I (Vensim)
|
|
23
|
+
* - DELAY1 (Stella)
|
|
24
|
+
* - DELAY3 (Stella)
|
|
23
25
|
*
|
|
24
26
|
* TODO: Docs
|
|
25
27
|
*
|
|
@@ -15,10 +15,12 @@ import Model from './model.js'
|
|
|
15
15
|
/**
|
|
16
16
|
* Generate level and aux variables that implement one of the following `SMOOTH` function
|
|
17
17
|
* call variants:
|
|
18
|
-
* - SMOOTH
|
|
19
|
-
* - SMOOTHI
|
|
20
|
-
* - SMOOTH3
|
|
21
|
-
* - SMOOTH3I
|
|
18
|
+
* - SMOOTH (Vensim)
|
|
19
|
+
* - SMOOTHI (Vensim)
|
|
20
|
+
* - SMOOTH3 (Vensim)
|
|
21
|
+
* - SMOOTH3I (Vensim)
|
|
22
|
+
* - SMTH1 (Stella)
|
|
23
|
+
* - SMTH3 (Stella)
|
|
22
24
|
*
|
|
23
25
|
* TODO: Docs
|
|
24
26
|
*
|
|
@@ -43,7 +45,7 @@ export function generateSmoothVariables(v, callExpr, context) {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const fnId = callExpr.fnId
|
|
46
|
-
if (fnId === '_SMOOTH' || fnId === '_SMOOTHI') {
|
|
48
|
+
if (fnId === '_SMOOTH' || fnId === '_SMOOTHI' || fnId === '_SMTH1') {
|
|
47
49
|
// Generate 1 level variable that will replace the `SMOOTH[I]` function call
|
|
48
50
|
const level = generateSmoothLevel(v, context, argInput, argDelay, argInit, 1)
|
|
49
51
|
// For `SMOOTH[I]`, the smoothVarRefId is the level var's refId
|
|
@@ -3,7 +3,7 @@ import { toPrettyString } from '@sdeverywhere/parse'
|
|
|
3
3
|
import { canonicalName, newAuxVarName, newLevelVarName } from '../_shared/helpers.js'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Generate two level variables and one aux that implement an `
|
|
6
|
+
* Generate two level variables and one aux that implement an `TREND` function call.
|
|
7
7
|
*
|
|
8
8
|
* TODO: Docs
|
|
9
9
|
*
|