@sdeverywhere/cli 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/README.md CHANGED
@@ -97,7 +97,10 @@ sde bundle [--config sde.config.js] [--verbose]
97
97
  sde generate --list {model}
98
98
  ```
99
99
 
100
- #### Preprocess a model to remove macros and tabbed arrays to removals.txt
100
+ #### Preprocess a model to remove macros and tabbed arrays
101
+
102
+ _NOTE:_ For most users it is not necessary to run the preprocessor manually
103
+ because the transpiler runs the preprocessor automatically prior to parsing.
101
104
 
102
105
  ```
103
106
  sde generate --preprocess {model}
@@ -204,21 +207,6 @@ There is an example in the `directdata` sample model.
204
207
  }
205
208
  ```
206
209
 
207
- #### Specify equations to remove from the model
208
-
209
- When SDEverywhere cannot handle a certain Vensim construct yet, you will need to remove equations that use the construct from the model, convert it by hand into something that SDEverywhere can handle, and then insert it back into the model.
210
- To have the preprocessor remove equations from the model into a `removals.txt` file, specify substrings to match in the equation in the `removalKeys` section.
211
- Macros and `TABBED ARRAY` equations are already automatically removed by the preprocessor.
212
-
213
- For instance, you could key on the variable name in the equation definition.
214
-
215
- ```json
216
- "removalKeys": [
217
- "varname1 =",
218
- "varname2 ="
219
- ]
220
- ```
221
-
222
210
  #### Generating, compiling, running, and testing the C code
223
211
 
224
212
  To generate C code using the `--spec` argument, enter the following command:
@@ -260,15 +248,6 @@ That is, the values are separated by spaces, and each pair has an index number,
260
248
  The zero-based index maps into a static array of input variable pointers held in the function.
261
249
  These are used to set the value directly into the static `double` variable in the generated code.
262
250
 
263
- #### Inserting a file into the model
264
-
265
- Some constructs like macros are not supported by SDEverywhere.
266
- They are removed from the model by the preprocessor into the `removals.txt` file.
267
- You can edit these constructs into a form that SDEverywhere supports and insert them back into the model.
268
- Create a file called `mdl-edits.txt` in the model directory with the constructs to insert.
269
- For instance, manually expand macros and place them into the `mdl-edits.txt` file.
270
- The preprocessor will read this file and insert its contents unchanged into the beginning of the model.
271
-
272
251
  ## License
273
252
 
274
253
  SDEverywhere is distributed under the MIT license. See `LICENSE` for more details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sdeverywhere/cli",
3
- "version": "0.7.27",
3
+ "version": "0.7.28",
4
4
  "description": "Contains the `sde` command line interface for the SDEverywhere tool suite.",
5
5
  "type": "module",
6
6
  "files": [
@@ -11,8 +11,8 @@
11
11
  "sde": "src/main.js"
12
12
  },
13
13
  "dependencies": {
14
- "@sdeverywhere/build": "^0.3.6",
15
- "@sdeverywhere/compile": "^0.7.20",
14
+ "@sdeverywhere/build": "^0.3.7",
15
+ "@sdeverywhere/compile": "^0.7.21",
16
16
  "bufx": "^1.0.5",
17
17
  "byline": "^5.0.0",
18
18
  "ramda": "^0.27.0",
package/src/sde-build.js CHANGED
@@ -43,7 +43,8 @@ export let build = async (model, opts) => {
43
43
  }
44
44
  } catch (e) {
45
45
  // Exit with a non-zero error code if any step failed
46
- console.error(`ERROR: ${e.message}\n`)
46
+ console.error(e)
47
+ console.error()
47
48
  process.exit(1)
48
49
  }
49
50
  }
package/src/sde-causes.js CHANGED
@@ -1,4 +1,6 @@
1
- import { generateCode, parseModel, preprocessModel } from '@sdeverywhere/compile'
1
+ import { readFileSync } from 'fs'
2
+
3
+ import { parseAndGenerate } from '@sdeverywhere/compile'
2
4
 
3
5
  import { modelPathProps, parseSpec } from './utils.js'
4
6
 
@@ -14,22 +16,13 @@ let builder = {
14
16
  let handler = argv => {
15
17
  causes(argv.model, argv.c_varname, argv)
16
18
  }
17
- let causes = (model, varname, opts) => {
19
+ let causes = async (model, varname, opts) => {
18
20
  // Get the model name and directory from the model argument.
19
- let { modelDirname, modelPathname } = modelPathProps(model)
20
- let extData = new Map()
21
- let directData = new Map()
21
+ let { modelDirname, modelPathname, modelName } = modelPathProps(model)
22
22
  let spec = parseSpec(opts.spec)
23
- // Preprocess model text into parser input.
24
- // TODO: The legacy `parseModel` function previously required the `preprocessModel`
25
- // step to be performed first, but the new `parseModel` runs the preprocessor
26
- // implicitly, so we can remove this step (and can simplify this code to use
27
- // `parseAndGenerate` instead)
28
- let input = preprocessModel(modelPathname, spec)
29
23
  // Parse the model to get variable and subscript information.
30
- let parsedModel = parseModel(input, modelDirname)
31
- let operations = ['printRefGraph']
32
- generateCode(parsedModel, { spec, operations, extData, directData, modelDirname, varname })
24
+ let input = readFileSync(modelPathname, 'utf8')
25
+ await parseAndGenerate(input, spec, ['printRefGraph'], modelDirname, modelName, '', varname)
33
26
  }
34
27
  export default {
35
28
  command,
@@ -1,8 +1,9 @@
1
+ import { readFileSync } from 'fs'
1
2
  import path from 'path'
2
3
 
3
4
  import B from 'bufx'
4
5
 
5
- import { preprocessModel } from '@sdeverywhere/compile'
6
+ import { preprocessVensimModel } from '@sdeverywhere/compile'
6
7
 
7
8
  import { buildDir, modelPathProps } from './utils.js'
8
9
 
@@ -44,16 +45,23 @@ const flatten = async (outFile, inFiles, opts) => {
44
45
  // Get the path and short name of the input mdl file
45
46
  const inModelProps = modelPathProps(inFile)
46
47
 
47
- // Preprocess the mdl file and extract the equations
48
- const decls = []
49
- preprocessModel(inModelProps.modelPathname, undefined, 'runnable', false, decls)
48
+ // Read the mdl file content
49
+ const mdlContent = readFileSync(inModelProps.modelPathname, 'utf8')
50
50
 
51
- // Associate each declaration with the name of the model from which it came
52
- for (const decl of decls) {
53
- decl.sourceModelName = inModelProps.modelName
51
+ // Preprocess the mdl file and extract the equations and subscript range definitions
52
+ const { defs } = preprocessVensimModel(mdlContent)
53
+
54
+ for (const def of defs) {
55
+ // Associate each definition with the name of the model from which it came
56
+ def.sourceModelName = inModelProps.modelName
57
+
58
+ // The object contains the preprocessed definition in a `def` property; copy this
59
+ // to a `processedDecl` property for clarity (since the existing code used that
60
+ // property name).
61
+ def.processedDecl = def.def
54
62
  }
55
63
 
56
- fileDecls[inModelProps.modelName] = decls
64
+ fileDecls[inModelProps.modelName] = defs
57
65
  }
58
66
 
59
67
  // Collapse so that we have only one equation or declaration per key.
@@ -176,9 +184,8 @@ const flatten = async (outFile, inFiles, opts) => {
176
184
  B.open('pp')
177
185
  const ENCODING = '{UTF-8}'
178
186
  B.emitLine(ENCODING, 'pp')
179
- B.emitLine('', 'pp')
180
187
  for (const decl of sorted) {
181
- B.emitLine(`${decl.processedDecl}\n`, 'pp')
188
+ B.emitLine(`\n${decl.processedDecl}`, 'pp')
182
189
  }
183
190
 
184
191
  // Write the flattened mdl file to the build directory
@@ -1,7 +1,8 @@
1
1
  import path from 'path'
2
+ import { readFileSync } from 'fs'
2
3
  import B from 'bufx'
3
4
 
4
- import { parseAndGenerate, preprocessModel } from '@sdeverywhere/compile'
5
+ import { parseAndGenerate, preprocessVensimModel } from '@sdeverywhere/compile'
5
6
 
6
7
  import { buildDir, modelPathProps, parseSpec } from './utils.js'
7
8
 
@@ -28,11 +29,6 @@ export let builder = {
28
29
  type: 'boolean',
29
30
  alias: 'p'
30
31
  },
31
- analysis: {
32
- describe: 'write a nonexecutable preprocessed model for analysis',
33
- type: 'boolean',
34
- alias: 'a'
35
- },
36
32
  spec: {
37
33
  describe: 'pathname of the I/O specification JSON file',
38
34
  type: 'string',
@@ -64,16 +60,13 @@ export let generate = async (model, opts) => {
64
60
  let { modelDirname, modelName, modelPathname } = modelPathProps(model)
65
61
  // Ensure the build directory exists.
66
62
  let buildDirname = buildDir(opts.builddir, modelDirname)
67
- // Preprocess model text into parser input. Stop now if that's all we're doing.
68
63
  let spec = parseSpec(opts.spec)
69
- // Produce a runnable model with the "runnable" and "preprocess" options.
70
- let profile = opts.analysis ? 'analysis' : 'runnable'
71
- // Write the preprocessed model and removals if the option is "analysis" or "preprocess".
72
- let writeFiles = opts.analysis || opts.preprocess
73
- let input = preprocessModel(modelPathname, spec, profile, writeFiles)
74
- if (writeFiles) {
64
+ let mdlContent = readFileSync(modelPathname, 'utf8')
65
+ if (opts.preprocess) {
66
+ // Only run the preprocessor.
67
+ let preprocessed = preprocessModel(mdlContent)
75
68
  let outputPathname = path.join(buildDirname, `${modelName}.mdl`)
76
- B.write(input, outputPathname)
69
+ B.write(preprocessed, outputPathname)
77
70
  process.exit(0)
78
71
  }
79
72
  // Parse the model and generate code. If no operation is specified, the code generator will
@@ -94,7 +87,7 @@ export let generate = async (model, opts) => {
94
87
  if (opts.refidtest) {
95
88
  operations.push('printRefIdTest')
96
89
  }
97
- await parseAndGenerate(input, spec, operations, modelDirname, modelName, buildDirname)
90
+ await parseAndGenerate(mdlContent, spec, operations, modelDirname, modelName, buildDirname)
98
91
  }
99
92
 
100
93
  export default {
@@ -104,3 +97,29 @@ export default {
104
97
  handler,
105
98
  generate
106
99
  }
100
+
101
+ /**
102
+ * Read and preprocess the given Vensim model content.
103
+ *
104
+ * @param {string} mdlContent The mdl content.
105
+ * @return {string} The preprocessed mdl text.
106
+ */
107
+ function preprocessModel(mdlContent) {
108
+ // Run the preprocessor
109
+ const { defs } = preprocessVensimModel(mdlContent)
110
+
111
+ // Sort the definitions alphabetically by key. This mainly exists for compatibility
112
+ // with the legacy `sde generate --preprocess` command, which was changed in #55 to
113
+ // sort definitions alphabetically.
114
+ defs.sort((a, b) => {
115
+ return a.key < b.key ? -1 : a.key > b.key ? 1 : 0
116
+ })
117
+
118
+ // Join the preprocessed definitions into a single string
119
+ let text = '{UTF-8}\n'
120
+ for (const def of defs) {
121
+ text += `\n${def.def}\n`
122
+ }
123
+
124
+ return text
125
+ }
package/src/sde-names.js CHANGED
@@ -1,4 +1,6 @@
1
- import { parseAndGenerate, preprocessModel, printNames } from '@sdeverywhere/compile'
1
+ import { readFileSync } from 'fs'
2
+
3
+ import { parseAndGenerate, printNames } from '@sdeverywhere/compile'
2
4
 
3
5
  import { modelPathProps, parseSpec } from './utils.js'
4
6
 
@@ -26,9 +28,8 @@ let names = async (model, namesPathname, opts) => {
26
28
  // Get the model name and directory from the model argument.
27
29
  let { modelDirname, modelPathname, modelName } = modelPathProps(model)
28
30
  let spec = parseSpec(opts.spec)
29
- // Preprocess model text into parser input.
30
- let input = preprocessModel(modelPathname, spec)
31
31
  // Parse the model to get variable and subscript information.
32
+ let input = readFileSync(modelPathname, 'utf8')
32
33
  await parseAndGenerate(input, spec, ['convertNames'], modelDirname, modelName, '')
33
34
  // Read each variable name from the names file and convert it.
34
35
  printNames(namesPathname, opts.toc ? 'to-c' : 'to-vensim')
package/src/sde-test.js CHANGED
@@ -66,7 +66,8 @@ export let test = async (model, opts) => {
66
66
  }
67
67
  } catch (e) {
68
68
  // Exit with a non-zero error code if any step failed
69
- console.error(`ERROR: ${e.message}\n`)
69
+ console.error(e)
70
+ console.error()
70
71
  process.exit(1)
71
72
  }
72
73
  }