Skip to content

Commit

Permalink
feat: preserve Vensim group names during preprocessing and parsing (#418
Browse files Browse the repository at this point in the history
)

Fixes #417
  • Loading branch information
chrispcampbell authored Dec 8, 2023
1 parent ce66990 commit e755be2
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 13 deletions.
11 changes: 7 additions & 4 deletions packages/parse/src/ast/ast-builders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export function dimDef(
familyName: DimName,
dimOrSubNames: SubName[],
subscriptMappings: SubscriptMapping[] = [],
comment = ''
comment = '',
group?: string
): DimensionDef {
return {
dimName,
Expand All @@ -70,7 +71,8 @@ export function dimDef(
familyId: canonicalName(familyName),
subscriptRefs: dimOrSubNames.map(subRef),
subscriptMappings,
comment
comment,
...(group ? { group } : {})
}
}

Expand Down Expand Up @@ -176,7 +178,7 @@ export function varDef(
}
}

export function exprEqn(varDef: VariableDef, expr: Expr, units = '', comment = ''): Equation {
export function exprEqn(varDef: VariableDef, expr: Expr, units = '', comment = '', group?: string): Equation {
return {
lhs: {
varDef
Expand All @@ -186,7 +188,8 @@ export function exprEqn(varDef: VariableDef, expr: Expr, units = '', comment = '
expr
},
units,
comment
comment,
...(group ? { group } : {})
}
}

Expand Down
8 changes: 8 additions & 0 deletions packages/parse/src/ast/ast-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ export interface DimensionDef {
* The optional comment text that accompanies the dimension definition in the model.
*/
comment?: string
/**
* The optional group name, if this dimension definition is contained within a group.
*/
group?: string
}

//
Expand Down Expand Up @@ -375,6 +379,10 @@ export interface Equation {
* The optional comment text that accompanies the equation definition in the model.
*/
comment?: string
/**
* The optional group name, if this equation definition is contained within a group.
*/
group?: string
}

//
Expand Down
41 changes: 41 additions & 0 deletions packages/parse/src/vensim/parse-vensim-model.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,45 @@ x = 1
)
)
})

it('should preserve group names', () => {
const mdl = `\
{UTF-8}
DimA: A1, A2 ~~|
x = 1 ~~|
********************************************************
.Group name 1
********************************************************~
Group comment here.
|
y[DimA] = 1 ~~|
********************************************************
.Group name 2
********************************************************~
Group comment here.
|
DimB: B1, B2 ~~|
z[DimB] = 1 ~~|
\\\\\\---/// Sketch information - do not modify anything except names
V301 Do not put anything below this section - it will be ignored
*XYZ
`
expect(parseVensimModel(mdl)).toEqual(
model(
[dimDef('DimA', 'DimA', ['A1', 'A2']), dimDef('DimB', 'DimB', ['B1', 'B2'], [], '', 'Group name 2')],
[
exprEqn(varDef('x'), num(1)),
exprEqn(varDef('y', ['DimA']), num(1), '', '', 'Group name 1'),
exprEqn(varDef('z', ['DimB']), num(1), '', '', 'Group name 2')
]
)
)
})
})
12 changes: 8 additions & 4 deletions packages/parse/src/vensim/parse-vensim-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,23 @@ export function parseVensimModel(input: string, context?: VensimParseContext, so
}

for (const dimensionDef of parsedModel.dimensions) {
// Fold in the comment string that was extracted during preprocessing
// Fold in the other strings that were extracted during preprocessing
const group = def.group
dimensions.push({
...dimensionDef,
comment: def.comment
comment: def.comment,
...(group ? { group } : {})
})
}

for (const equation of parsedModel.equations) {
// Fold in the units and comment strings that were extracted during preprocessing
// Fold in the other strings that were extracted during preprocessing
const group = def.group
equations.push({
...equation,
units: def.units,
comment: def.comment
comment: def.comment,
...(group ? { group } : {})
})
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/parse/src/vensim/preprocess-vensim.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ $192-192-192,0,Arial|12||0-0-0|0-0-0|0-0-255|-1--1--1|-1--1--1|96,96,5,0
def: 'W[A,B] :EXCEPT: [A1,B1] = 1 ~~|',
line: 23,
units: '',
comment: ''
comment: '',
group: 'Group name'
}
])
})
Expand Down
35 changes: 31 additions & 4 deletions packages/parse/src/vensim/preprocess-vensim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export interface VensimDef {
* The comment text.
*/
comment: string
/**
* The optional group name, if the definition is contained within a group.
*/
group?: string
}

/**
Expand All @@ -46,6 +50,11 @@ interface RawDef {
* The (1-based) line number where the definition begins.
*/
line: number
/**
* The group in which the definition is contained (can be undefined if
* the definition is not inside a group).
*/
group?: string
}

/**
Expand Down Expand Up @@ -96,6 +105,7 @@ function splitDefs(input: string): RawDef[] {
// number of line breaks in that definition
const rawDefs = []
let lineNum = 1
let currentGroup: string
for (let defText of defTexts) {
if (lineNum === 1) {
// Strip the encoding (included in first def)
Expand All @@ -115,11 +125,24 @@ function splitDefs(input: string): RawDef[] {
const leadingLineBreaks = parts[1]?.match(/\r\n|\n|\r/gm)
lineNum += leadingLineBreaks?.length || 0

// Add the def (if it's not a group)
if (!defText.includes('********************************************************')) {
// See if this is a group header
if (defText.includes('********************************************************')) {
// This is a group; save the group name
const groupLines = splitLines(defText).filter(s => s.trim().length > 0)
currentGroup = undefined
if (groupLines.length > 1) {
const groupNameLine = groupLines[1]
const groupNameParts = groupNameLine.match(/^\s*\.(.*)$/)
if (groupNameParts) {
currentGroup = groupNameParts[1]
}
}
} else {
// This is a regular definition; add it
rawDefs.push({
text: defText,
line: lineNum
line: lineNum,
group: currentGroup
})
}

Expand Down Expand Up @@ -304,11 +327,15 @@ function processDef(rawDef: RawDef): VensimDef | undefined {

// TODO: Extract the `:SUPPLEMENTARY:` flags?

// Preserve the group name, if defined
const group = rawDef.group

return {
key,
def,
line: rawDef.line,
units,
comment
comment,
...(group ? { group } : {})
}
}

0 comments on commit e755be2

Please sign in to comment.