@sdeverywhere/parse 0.1.0 → 0.1.2

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/dist/index.d.cts CHANGED
@@ -1,3 +1,35 @@
1
+ /**
2
+ * Format a model variable or subscript/dimension name into a valid C identifier (with
3
+ * special characters converted to underscore).
4
+ *
5
+ * Note that this should only be called with an individual variable base name (e.g.,
6
+ * 'Variable name') or a subscript/dimension name (e.g., 'DimA'). In the case where
7
+ * you have a full variable name that includes subscripts/dimensions (e.g.,
8
+ * 'Variable name[DimA,B2]'), use `canonicalVarId` to convert the base variable name
9
+ * and subscript/dimension parts to canonical form indepdendently.
10
+ *
11
+ * @param {string} name The name of the variable in the source model, e.g., "Variable name".
12
+ * @returns {string} The C identifier for the given name, e.g., "_variable_name".
13
+ */
14
+ declare function canonicalId(name: string): string;
15
+ /**
16
+ * Format a (subscripted or non-subscripted) model variable name into a canonical identifier,
17
+ * (with special characters converted to underscore, and subscript/dimension parts separated
18
+ * by commas).
19
+ *
20
+ * @param {string} name The name of the variable in the source model, e.g., "Variable name[DimA, B2]".
21
+ * @returns {string} The canonical identifier for the given name, e.g., "_variable_name[_dima,_b2]".
22
+ */
23
+ declare function canonicalVarId(name: string): string;
24
+ /**
25
+ * Format a model function name into a valid C identifier (with special characters
26
+ * converted to underscore, and the ID converted to uppercase).
27
+ *
28
+ * @param {string} name The name of the variable in the source model, e.g., "FUNCTION name".
29
+ * @returns {string} The C identifier for the given name, e.g., "_FUNCTION_NAME".
30
+ */
31
+ declare function canonicalFunctionId(name: string): string;
32
+
1
33
  /** The original name of a dimension, as it appears in the model. */
2
34
  type DimName = string;
3
35
  /** The canonical identifier of a dimension, as it appears in generated code. */
@@ -442,4 +474,88 @@ declare function parseVensimEquation(input: string): Equation;
442
474
  */
443
475
  declare function parseVensimModel(input: string, context?: VensimParseContext, sort?: boolean): Model;
444
476
 
445
- export { BinaryOp, BinaryOpExpr, DimId, DimName, DimOrSubId, DimOrSubName, DimensionDef, Equation, EquationLhs, EquationRhs, EquationRhsConstList, EquationRhsData, EquationRhsExpr, EquationRhsLookup, Expr, FormatVariableRefFunc, FunctionCall, FunctionId, FunctionName, Keyword, LookupCall, LookupDef, LookupPoint, LookupRange, Model, NumberLiteral, ParensExpr, PrettyOpts, ReduceExprOptions, StringLiteral, SubId, SubName, SubscriptMapping, SubscriptRef, UnaryOp, UnaryOpExpr, VariableDef, VariableId, VariableName, VariableRef, VensimParseContext, debugPrintExpr, parseVensimEquation, parseVensimExpr, parseVensimModel, parseVensimSubscriptRange, prettyPrintExpr, printExprStats, reduceConditionals, reduceExpr, toPrettyString };
477
+ /**
478
+ * A single Vensim definition (either a subscript range definition or an
479
+ * equation definition). This contains the definition's text and metadata
480
+ * that was extracted during preprocessing.
481
+ */
482
+ interface VensimDef {
483
+ /**
484
+ * A simplified key for the LHS of the definition, used for sorting
485
+ * and/or flattening.
486
+ */
487
+ key: string;
488
+ /**
489
+ * The preprocessed equation or subscript range definition (with
490
+ * units and comment replaced with `~~|`).
491
+ */
492
+ def: string;
493
+ /**
494
+ * The kind of definition; either 'eqn' for an equation containing an equals
495
+ * sign, 'dim' for a dimension (subscript range) definition, or 'decl' for
496
+ * all other declarations (e.g., a lookup or data variable definition).
497
+ */
498
+ kind: 'eqn' | 'dim' | 'decl';
499
+ /**
500
+ * The (1-based) line number where the definition begins.
501
+ */
502
+ line: number;
503
+ /**
504
+ * The units text.
505
+ */
506
+ units: string;
507
+ /**
508
+ * The comment text.
509
+ */
510
+ comment: string;
511
+ /**
512
+ * The optional group name, if the definition is contained within a group.
513
+ */
514
+ group?: string;
515
+ }
516
+ /**
517
+ * Result type for the `preprocessVensimModel` function.
518
+ */
519
+ interface PreprocessedVensimModel {
520
+ /**
521
+ * The preprocessed definitions that were preserved.
522
+ */
523
+ defs: VensimDef[];
524
+ /**
525
+ * The macros that were removed by the preprocessor.
526
+ */
527
+ removedMacros: string[];
528
+ /**
529
+ * The text blocks that were removed by the preprocessor. These include
530
+ * unsupported functions (such as `TABBED ARRAY`) and other definitions
531
+ * that were requested for removal.
532
+ */
533
+ removedBlocks: string[];
534
+ }
535
+ /**
536
+ * Process the given Vensim model content so that it can be parsed
537
+ * by `antlr4-vensim`. This will:
538
+ * - strip out group markers
539
+ * - remove macro definitions, which are currently unsupported
540
+ * - remove equations that reference certain unsupported functions
541
+ * (e.g., `TABBED ARRAY`)
542
+ * - remove everything in the private Vensim sketch section
543
+ * - join lines that are separated by a continuation (backslash)
544
+ * - split the input into distinct definitions (equations and
545
+ * subscript ranges)
546
+ *
547
+ * The definitions are further processed to preserve the units and
548
+ * comment text in separate properties, but strips them from the
549
+ * equation string (replaced with `~~`) to make it easier for
550
+ * `antlr4-vensim` to process.
551
+ *
552
+ * @param input The original Vensim mdl file content.
553
+ * @param options The options that control preprocessing.
554
+ * @return A `PreprocessedVensimModel` instance containing the preprocessed
555
+ * Vensim definitions.
556
+ */
557
+ declare function preprocessVensimModel(input: string, options?: {
558
+ removalKeys?: string[];
559
+ }): PreprocessedVensimModel;
560
+
561
+ export { type BinaryOp, type BinaryOpExpr, type DimId, type DimName, type DimOrSubId, type DimOrSubName, type DimensionDef, type Equation, type EquationLhs, type EquationRhs, type EquationRhsConstList, type EquationRhsData, type EquationRhsExpr, type EquationRhsLookup, type Expr, type FormatVariableRefFunc, type FunctionCall, type FunctionId, type FunctionName, type Keyword, type LookupCall, type LookupDef, type LookupPoint, type LookupRange, type Model, type NumberLiteral, type ParensExpr, type PreprocessedVensimModel, type PrettyOpts, type ReduceExprOptions, type StringLiteral, type SubId, type SubName, type SubscriptMapping, type SubscriptRef, type UnaryOp, type UnaryOpExpr, type VariableDef, type VariableId, type VariableName, type VariableRef, type VensimDef, type VensimParseContext, canonicalFunctionId, canonicalId, canonicalVarId, debugPrintExpr, parseVensimEquation, parseVensimExpr, parseVensimModel, parseVensimSubscriptRange, preprocessVensimModel, prettyPrintExpr, printExprStats, reduceConditionals, reduceExpr, toPrettyString };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,35 @@
1
+ /**
2
+ * Format a model variable or subscript/dimension name into a valid C identifier (with
3
+ * special characters converted to underscore).
4
+ *
5
+ * Note that this should only be called with an individual variable base name (e.g.,
6
+ * 'Variable name') or a subscript/dimension name (e.g., 'DimA'). In the case where
7
+ * you have a full variable name that includes subscripts/dimensions (e.g.,
8
+ * 'Variable name[DimA,B2]'), use `canonicalVarId` to convert the base variable name
9
+ * and subscript/dimension parts to canonical form indepdendently.
10
+ *
11
+ * @param {string} name The name of the variable in the source model, e.g., "Variable name".
12
+ * @returns {string} The C identifier for the given name, e.g., "_variable_name".
13
+ */
14
+ declare function canonicalId(name: string): string;
15
+ /**
16
+ * Format a (subscripted or non-subscripted) model variable name into a canonical identifier,
17
+ * (with special characters converted to underscore, and subscript/dimension parts separated
18
+ * by commas).
19
+ *
20
+ * @param {string} name The name of the variable in the source model, e.g., "Variable name[DimA, B2]".
21
+ * @returns {string} The canonical identifier for the given name, e.g., "_variable_name[_dima,_b2]".
22
+ */
23
+ declare function canonicalVarId(name: string): string;
24
+ /**
25
+ * Format a model function name into a valid C identifier (with special characters
26
+ * converted to underscore, and the ID converted to uppercase).
27
+ *
28
+ * @param {string} name The name of the variable in the source model, e.g., "FUNCTION name".
29
+ * @returns {string} The C identifier for the given name, e.g., "_FUNCTION_NAME".
30
+ */
31
+ declare function canonicalFunctionId(name: string): string;
32
+
1
33
  /** The original name of a dimension, as it appears in the model. */
2
34
  type DimName = string;
3
35
  /** The canonical identifier of a dimension, as it appears in generated code. */
@@ -442,4 +474,88 @@ declare function parseVensimEquation(input: string): Equation;
442
474
  */
443
475
  declare function parseVensimModel(input: string, context?: VensimParseContext, sort?: boolean): Model;
444
476
 
445
- export { BinaryOp, BinaryOpExpr, DimId, DimName, DimOrSubId, DimOrSubName, DimensionDef, Equation, EquationLhs, EquationRhs, EquationRhsConstList, EquationRhsData, EquationRhsExpr, EquationRhsLookup, Expr, FormatVariableRefFunc, FunctionCall, FunctionId, FunctionName, Keyword, LookupCall, LookupDef, LookupPoint, LookupRange, Model, NumberLiteral, ParensExpr, PrettyOpts, ReduceExprOptions, StringLiteral, SubId, SubName, SubscriptMapping, SubscriptRef, UnaryOp, UnaryOpExpr, VariableDef, VariableId, VariableName, VariableRef, VensimParseContext, debugPrintExpr, parseVensimEquation, parseVensimExpr, parseVensimModel, parseVensimSubscriptRange, prettyPrintExpr, printExprStats, reduceConditionals, reduceExpr, toPrettyString };
477
+ /**
478
+ * A single Vensim definition (either a subscript range definition or an
479
+ * equation definition). This contains the definition's text and metadata
480
+ * that was extracted during preprocessing.
481
+ */
482
+ interface VensimDef {
483
+ /**
484
+ * A simplified key for the LHS of the definition, used for sorting
485
+ * and/or flattening.
486
+ */
487
+ key: string;
488
+ /**
489
+ * The preprocessed equation or subscript range definition (with
490
+ * units and comment replaced with `~~|`).
491
+ */
492
+ def: string;
493
+ /**
494
+ * The kind of definition; either 'eqn' for an equation containing an equals
495
+ * sign, 'dim' for a dimension (subscript range) definition, or 'decl' for
496
+ * all other declarations (e.g., a lookup or data variable definition).
497
+ */
498
+ kind: 'eqn' | 'dim' | 'decl';
499
+ /**
500
+ * The (1-based) line number where the definition begins.
501
+ */
502
+ line: number;
503
+ /**
504
+ * The units text.
505
+ */
506
+ units: string;
507
+ /**
508
+ * The comment text.
509
+ */
510
+ comment: string;
511
+ /**
512
+ * The optional group name, if the definition is contained within a group.
513
+ */
514
+ group?: string;
515
+ }
516
+ /**
517
+ * Result type for the `preprocessVensimModel` function.
518
+ */
519
+ interface PreprocessedVensimModel {
520
+ /**
521
+ * The preprocessed definitions that were preserved.
522
+ */
523
+ defs: VensimDef[];
524
+ /**
525
+ * The macros that were removed by the preprocessor.
526
+ */
527
+ removedMacros: string[];
528
+ /**
529
+ * The text blocks that were removed by the preprocessor. These include
530
+ * unsupported functions (such as `TABBED ARRAY`) and other definitions
531
+ * that were requested for removal.
532
+ */
533
+ removedBlocks: string[];
534
+ }
535
+ /**
536
+ * Process the given Vensim model content so that it can be parsed
537
+ * by `antlr4-vensim`. This will:
538
+ * - strip out group markers
539
+ * - remove macro definitions, which are currently unsupported
540
+ * - remove equations that reference certain unsupported functions
541
+ * (e.g., `TABBED ARRAY`)
542
+ * - remove everything in the private Vensim sketch section
543
+ * - join lines that are separated by a continuation (backslash)
544
+ * - split the input into distinct definitions (equations and
545
+ * subscript ranges)
546
+ *
547
+ * The definitions are further processed to preserve the units and
548
+ * comment text in separate properties, but strips them from the
549
+ * equation string (replaced with `~~`) to make it easier for
550
+ * `antlr4-vensim` to process.
551
+ *
552
+ * @param input The original Vensim mdl file content.
553
+ * @param options The options that control preprocessing.
554
+ * @return A `PreprocessedVensimModel` instance containing the preprocessed
555
+ * Vensim definitions.
556
+ */
557
+ declare function preprocessVensimModel(input: string, options?: {
558
+ removalKeys?: string[];
559
+ }): PreprocessedVensimModel;
560
+
561
+ export { type BinaryOp, type BinaryOpExpr, type DimId, type DimName, type DimOrSubId, type DimOrSubName, type DimensionDef, type Equation, type EquationLhs, type EquationRhs, type EquationRhsConstList, type EquationRhsData, type EquationRhsExpr, type EquationRhsLookup, type Expr, type FormatVariableRefFunc, type FunctionCall, type FunctionId, type FunctionName, type Keyword, type LookupCall, type LookupDef, type LookupPoint, type LookupRange, type Model, type NumberLiteral, type ParensExpr, type PreprocessedVensimModel, type PrettyOpts, type ReduceExprOptions, type StringLiteral, type SubId, type SubName, type SubscriptMapping, type SubscriptRef, type UnaryOp, type UnaryOpExpr, type VariableDef, type VariableId, type VariableName, type VariableRef, type VensimDef, type VensimParseContext, canonicalFunctionId, canonicalId, canonicalVarId, debugPrintExpr, parseVensimEquation, parseVensimExpr, parseVensimModel, parseVensimSubscriptRange, preprocessVensimModel, prettyPrintExpr, printExprStats, reduceConditionals, reduceExpr, toPrettyString };
package/dist/index.js CHANGED
@@ -1,3 +1,26 @@
1
+ // src/_shared/canonical-id.js
2
+ var reTrailingMark = new RegExp("\\s+!$", "g");
3
+ var reWhitespace = new RegExp("(\\s|_)+", "g");
4
+ var reSpecialChars = new RegExp(`['"\\.,\\-\\$&%\\/\\|()]`, "g");
5
+ function canonicalId(name) {
6
+ return "_" + name.trim().replace(reTrailingMark, "!").replace(reWhitespace, "_").replace(reSpecialChars, "_").toLowerCase();
7
+ }
8
+ function canonicalVarId(name) {
9
+ const m = name.match(/([^[]+)(?:\[([^\]]+)\])?/);
10
+ if (!m) {
11
+ throw new Error(`Invalid variable name: ${name}`);
12
+ }
13
+ let id = canonicalId(m[1]);
14
+ if (m[2]) {
15
+ const subscripts = m[2].split(",").map((x) => canonicalId(x));
16
+ id += `[${subscripts.join(",")}]`;
17
+ }
18
+ return id;
19
+ }
20
+ function canonicalFunctionId(name) {
21
+ return canonicalId(name).toUpperCase();
22
+ }
23
+
1
24
  // src/ast/print-expr.ts
2
25
  import { assertNever } from "assert-never";
3
26
  function debugPrintExpr(expr, indent = 0) {
@@ -246,14 +269,6 @@ function fullIdForVarRef(varRef) {
246
269
  // src/ast/reduce-expr.ts
247
270
  import { assertNever as assertNever2 } from "assert-never";
248
271
 
249
- // src/_shared/names.js
250
- function canonicalName(name) {
251
- return "_" + name.trim().replace(/"/g, "_").replace(/\s+!$/g, "!").replace(/\s/g, "_").replace(/,/g, "_").replace(/-/g, "_").replace(/\./g, "_").replace(/\$/g, "_").replace(/'/g, "_").replace(/&/g, "_").replace(/%/g, "_").replace(/\//g, "_").replace(/\|/g, "_").toLowerCase();
252
- }
253
- function cFunctionName(name) {
254
- return canonicalName(name).toUpperCase();
255
- }
256
-
257
272
  // src/ast/ast-builders.ts
258
273
  function num(value, text) {
259
274
  return {
@@ -629,7 +644,7 @@ var SubscriptRangeReader = class extends ModelVisitor {
629
644
  const ids = ctx.Id();
630
645
  if (ids.length === 1) {
631
646
  const dimName = ids[0].getText();
632
- const dimId = canonicalName(dimName);
647
+ const dimId = canonicalId(dimName);
633
648
  super.visitSubscriptRange(ctx);
634
649
  return {
635
650
  dimName,
@@ -639,7 +654,7 @@ var SubscriptRangeReader = class extends ModelVisitor {
639
654
  subscriptRefs: this.subscriptNames.map((subName) => {
640
655
  return {
641
656
  subName,
642
- subId: canonicalName(subName)
657
+ subId: canonicalId(subName)
643
658
  };
644
659
  }),
645
660
  subscriptMappings: this.subscriptMappings,
@@ -647,9 +662,9 @@ var SubscriptRangeReader = class extends ModelVisitor {
647
662
  };
648
663
  } else if (ids.length === 2) {
649
664
  const dimName = ids[0].getText();
650
- const dimId = canonicalName(dimName);
665
+ const dimId = canonicalId(dimName);
651
666
  const familyName = ids[1].getText();
652
- const familyId = canonicalName(familyName);
667
+ const familyId = canonicalId(familyName);
653
668
  return {
654
669
  dimName,
655
670
  dimId,
@@ -689,11 +704,11 @@ var SubscriptRangeReader = class extends ModelVisitor {
689
704
  super.visitSubscriptMapping(ctx);
690
705
  this.subscriptMappings.push({
691
706
  toDimName,
692
- toDimId: canonicalName(toDimName),
707
+ toDimId: canonicalId(toDimName),
693
708
  subscriptRefs: this.mappedSubscriptNames.map((subName) => {
694
709
  return {
695
710
  subName,
696
- subId: canonicalName(subName)
711
+ subId: canonicalId(subName)
697
712
  };
698
713
  })
699
714
  });
@@ -703,7 +718,7 @@ var SubscriptRangeReader = class extends ModelVisitor {
703
718
  }
704
719
  visitCall(ctx) {
705
720
  const fnName = ctx.Id().getText();
706
- const fnId = cFunctionName(fnName);
721
+ const fnId = canonicalFunctionId(fnName);
707
722
  if (fnId === "_GET_DIRECT_SUBSCRIPT") {
708
723
  super.visitCall(ctx);
709
724
  } else {
@@ -799,7 +814,7 @@ var ExprReader = class extends ModelVisitor2 {
799
814
  //
800
815
  visitCall(ctx) {
801
816
  const vensimFnName = ctx.Id().getText();
802
- const fnId = cFunctionName(vensimFnName);
817
+ const fnId = canonicalFunctionId(vensimFnName);
803
818
  this.callStack.push({ fn: fnId, args: [] });
804
819
  super.visitCall(ctx);
805
820
  const callInfo = this.callStack.pop();
@@ -822,14 +837,14 @@ var ExprReader = class extends ModelVisitor2 {
822
837
  }
823
838
  visitVar(ctx) {
824
839
  const vensimVarName = ctx.Id().getText().trim();
825
- const varId = canonicalName(vensimVarName);
840
+ const varId = canonicalId(vensimVarName);
826
841
  this.subscripts = void 0;
827
842
  super.visitVar(ctx);
828
843
  const subscriptNames = this.subscripts;
829
844
  const subscriptRefs = subscriptNames?.map((name) => {
830
845
  return {
831
846
  subName: name,
832
- subId: canonicalName(name)
847
+ subId: canonicalId(name)
833
848
  };
834
849
  });
835
850
  this.subscripts = void 0;
@@ -879,7 +894,7 @@ var ExprReader = class extends ModelVisitor2 {
879
894
  }
880
895
  visitLookupCall(ctx) {
881
896
  const lookupVarName = ctx.Id().getText();
882
- const lookupVarId = canonicalName(lookupVarName);
897
+ const lookupVarId = canonicalId(lookupVarName);
883
898
  if (ctx.subscriptList()) {
884
899
  ctx.subscriptList().accept(this);
885
900
  }
@@ -887,7 +902,7 @@ var ExprReader = class extends ModelVisitor2 {
887
902
  const subscriptRefs = subscriptNames?.map((name) => {
888
903
  return {
889
904
  subName: name,
890
- subId: canonicalName(name)
905
+ subId: canonicalId(name)
891
906
  };
892
907
  });
893
908
  this.subscripts = void 0;
@@ -1084,13 +1099,13 @@ var EquationReader = class extends ModelVisitor3 {
1084
1099
  }
1085
1100
  visitLhs(ctx) {
1086
1101
  const lhsVarName = ctx.Id().getText();
1087
- const lhsVarId = canonicalName(lhsVarName);
1102
+ const lhsVarId = canonicalId(lhsVarName);
1088
1103
  super.visitLhs(ctx);
1089
1104
  const subscriptNames = this.subscripts;
1090
1105
  const subscriptRefs = subscriptNames?.map((name) => {
1091
1106
  return {
1092
1107
  subName: name,
1093
- subId: canonicalName(name)
1108
+ subId: canonicalId(name)
1094
1109
  };
1095
1110
  });
1096
1111
  const exceptSubscriptSets = this.exceptSubscriptSets;
@@ -1098,7 +1113,7 @@ var EquationReader = class extends ModelVisitor3 {
1098
1113
  return subscriptSet.map((name) => {
1099
1114
  return {
1100
1115
  subName: name,
1101
- subId: canonicalName(name)
1116
+ subId: canonicalId(name)
1102
1117
  };
1103
1118
  });
1104
1119
  });
@@ -1178,16 +1193,41 @@ function parseVensimEquation(input) {
1178
1193
 
1179
1194
  // src/vensim/preprocess-vensim.ts
1180
1195
  import split from "split-string";
1181
- function preprocessVensimModel(input) {
1196
+ function preprocessVensimModel(input, options) {
1197
+ const removalKeys = options?.removalKeys;
1198
+ function shouldRemove(text) {
1199
+ if (text.includes("TABBED ARRAY")) {
1200
+ return true;
1201
+ }
1202
+ if (removalKeys) {
1203
+ for (const key of removalKeys) {
1204
+ if (text.includes(key)) {
1205
+ return true;
1206
+ }
1207
+ }
1208
+ }
1209
+ return false;
1210
+ }
1211
+ const macrosResult = removeMacros(input);
1212
+ input = macrosResult.processed;
1182
1213
  const rawDefs = splitDefs(input);
1183
1214
  const vensimDefs = [];
1215
+ const removedBlocks = [];
1184
1216
  for (const rawDef of rawDefs) {
1217
+ if (shouldRemove(rawDef.text)) {
1218
+ removedBlocks.push(rawDef.text.trim() + "|");
1219
+ continue;
1220
+ }
1185
1221
  const vensimDef = processDef(rawDef);
1186
1222
  if (vensimDef) {
1187
1223
  vensimDefs.push(vensimDef);
1188
1224
  }
1189
1225
  }
1190
- return vensimDefs;
1226
+ return {
1227
+ defs: vensimDefs,
1228
+ removedMacros: macrosResult.removed,
1229
+ removedBlocks
1230
+ };
1191
1231
  }
1192
1232
  function splitDefs(input) {
1193
1233
  const defTexts = split(input, { separator: "|", quotes: ['"'], keep: () => true });
@@ -1229,6 +1269,9 @@ function splitDefs(input) {
1229
1269
  function splitLines(input) {
1230
1270
  return input.split(/\r\n|\n|\r/);
1231
1271
  }
1272
+ function splitExceptInQuoted(input, sep) {
1273
+ return split(input, { separator: sep, quotes: ['"'] });
1274
+ }
1232
1275
  function processBackslashes(input) {
1233
1276
  const inputLines = splitLines(input);
1234
1277
  let output = "";
@@ -1274,22 +1317,27 @@ function replaceDelimitedStrings(str, open, close, newStr) {
1274
1317
  function reduceWhitespace(input) {
1275
1318
  return input.replace(/\s\s+/g, " ").trim();
1276
1319
  }
1320
+ var reWhitespace2 = new RegExp("(\\s|_)+", "g");
1277
1321
  function keyForDef(def) {
1278
1322
  let key = def;
1279
1323
  key = key.replace(/:INTERPOLATE:/g, "");
1324
+ let kind;
1280
1325
  if (key.includes("=")) {
1326
+ kind = "eqn";
1281
1327
  key = key.split("=")[0].trim();
1282
1328
  } else if (key.includes(":")) {
1329
+ kind = "dim";
1283
1330
  key = key.split(":")[0].trim();
1284
1331
  } else {
1332
+ kind = "decl";
1285
1333
  }
1334
+ key = splitExceptInQuoted(key, "(")[0];
1286
1335
  key = key.replace(/"/g, "");
1287
- key = key.split("(")[0];
1288
1336
  key = key.trim();
1289
- key = key.replace(/\[\s*/g, "[");
1290
- key = key.replace(/\s*\]/g, "]");
1337
+ key = key.replace(/(?<=\[).*?(?=\])/g, (match) => match.replace(/\s/g, ""));
1338
+ key = key.replace(reWhitespace2, "_");
1291
1339
  key = key.toLowerCase();
1292
- return key;
1340
+ return { key, kind };
1293
1341
  }
1294
1342
  function processDef(rawDef) {
1295
1343
  let input = rawDef.text;
@@ -1307,7 +1355,7 @@ function processDef(rawDef) {
1307
1355
  ${input}`);
1308
1356
  }
1309
1357
  const rawDefText = reduceWhitespace(parts[0]);
1310
- const key = keyForDef(rawDefText);
1358
+ const { key, kind } = keyForDef(rawDefText);
1311
1359
  const def = `${rawDefText} ~~|`;
1312
1360
  const units = reduceWhitespace(parts[1]);
1313
1361
  const comment = reduceWhitespace(parts[2]);
@@ -1315,12 +1363,25 @@ ${input}`);
1315
1363
  return {
1316
1364
  key,
1317
1365
  def,
1366
+ kind,
1318
1367
  line: rawDef.line,
1319
1368
  units,
1320
1369
  comment,
1321
1370
  ...group ? { group } : {}
1322
1371
  };
1323
1372
  }
1373
+ function removeMacros(input) {
1374
+ const removed = [];
1375
+ const processed = input.replace(/:MACRO:.*:END OF MACRO:/gms, (match) => {
1376
+ removed.push(match);
1377
+ const numBreaks = match.split(/\r\n|\n|\r/gms).length - 1;
1378
+ return numBreaks > 0 ? "\n".repeat(numBreaks) : "";
1379
+ });
1380
+ return {
1381
+ processed,
1382
+ removed
1383
+ };
1384
+ }
1324
1385
 
1325
1386
  // src/vensim/impl/model-reader.js
1326
1387
  import { ModelVisitor as ModelVisitor4 } from "antlr4-vensim";
@@ -1379,7 +1440,7 @@ var ModelReader = class extends ModelVisitor4 {
1379
1440
  function parseVensimModel(input, context, sort = false) {
1380
1441
  const dimensions = [];
1381
1442
  const equations = [];
1382
- const defs = preprocessVensimModel(input);
1443
+ const { defs } = preprocessVensimModel(input);
1383
1444
  if (sort) {
1384
1445
  defs.sort((a, b) => {
1385
1446
  return a.key < b.key ? -1 : a.key > b.key ? 1 : 0;
@@ -1431,11 +1492,15 @@ Detail:
1431
1492
  };
1432
1493
  }
1433
1494
  export {
1495
+ canonicalFunctionId,
1496
+ canonicalId,
1497
+ canonicalVarId,
1434
1498
  debugPrintExpr,
1435
1499
  parseVensimEquation,
1436
1500
  parseVensimExpr,
1437
1501
  parseVensimModel,
1438
1502
  parseVensimSubscriptRange,
1503
+ preprocessVensimModel,
1439
1504
  prettyPrintExpr,
1440
1505
  printExprStats,
1441
1506
  reduceConditionals,