@sdeverywhere/compile 0.7.17 → 0.7.19

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.
@@ -1,202 +0,0 @@
1
- import { ModelLexer, ModelVisitor } from 'antlr4-vensim'
2
-
3
- import { canonicalName } from '../_shared/helpers.js'
4
- import { createParser } from '../parse/parser.js'
5
-
6
- import Model from './model.js'
7
-
8
- /**
9
- * Reads an expression and determines if it resolves to a constant numeric value.
10
- * This depends on having access to the model variables, so this should be used
11
- * only after the `readVariables` process has been completed and the spec file
12
- * has been loaded.
13
- */
14
- export default class ExprReader extends ModelVisitor {
15
- constructor() {
16
- super()
17
- }
18
-
19
- read(exprText) {
20
- let parser = createParser(exprText)
21
- let expr = parser.expr()
22
- expr.accept(this)
23
-
24
- return {
25
- constantValue: this.constantValue
26
- }
27
- }
28
-
29
- // Constants
30
-
31
- visitConst(ctx) {
32
- const constantValue = parseFloat(ctx.Const().getText())
33
- if (!Number.isNaN(constantValue)) {
34
- this.constantValue = constantValue
35
- } else {
36
- this.constantValue = undefined
37
- }
38
- }
39
- visitConstList() {
40
- this.constantValue = undefined
41
- }
42
-
43
- // Function calls and variables
44
-
45
- visitCall() {
46
- // Treat function calls as non-constant (can't easily determine if they
47
- // resolve to a constant)
48
- this.constantValue = undefined
49
- }
50
- visitExprList() {
51
- // Treat function calls as non-constant (can't easily determine if they
52
- // resolve to a constant)
53
- this.constantValue = undefined
54
- }
55
- visitVar(ctx) {
56
- // Determine whether this variable has a constant value
57
- const varName = ctx.Id().getText().trim()
58
- const cName = canonicalName(varName)
59
- const v = Model.varWithName(cName)
60
- const modelFormula = v?.modelFormula?.trim() || ''
61
- const isNumber = modelFormula.match(/^[+-]?\d+(\.\d+)?$/)
62
- const canBeOverridden = Model.isInputVar(cName)
63
- if (v && isNumber && !canBeOverridden) {
64
- const numValue = parseFloat(modelFormula)
65
- if (!Number.isNaN(numValue)) {
66
- this.constantValue = numValue
67
- } else {
68
- this.constantValue = undefined
69
- }
70
- } else {
71
- this.constantValue = undefined
72
- }
73
- }
74
-
75
- // Lookups
76
-
77
- visitLookup() {
78
- this.constantValue = undefined
79
- }
80
- visitLookupCall() {
81
- this.constantValue = undefined
82
- }
83
-
84
- // Unary operators
85
-
86
- visitNegative(ctx) {
87
- super.visitNegative(ctx)
88
- if (this.constantValue !== undefined) {
89
- this.constantValue = -this.constantValue
90
- }
91
- }
92
- visitPositive(ctx) {
93
- super.visitPositive(ctx)
94
- if (this.constantValue !== undefined) {
95
- this.constantValue = +this.constantValue
96
- }
97
- }
98
- visitNot(ctx) {
99
- super.visitNot(ctx)
100
- if (this.constantValue !== undefined) {
101
- this.constantValue = !this.constantValue
102
- }
103
- }
104
-
105
- // Binary operators
106
-
107
- visitBinaryArgs(ctx, combine) {
108
- ctx.expr(0).accept(this)
109
- const constantValue0 = this.constantValue
110
- ctx.expr(1).accept(this)
111
- const constantValue1 = this.constantValue
112
- if (constantValue0 !== undefined && constantValue1 !== undefined) {
113
- this.constantValue = combine(constantValue0, constantValue1)
114
- } else {
115
- this.constantValue = undefined
116
- }
117
- }
118
-
119
- visitPower(ctx) {
120
- this.visitBinaryArgs(ctx, (a, b) => Math.pow(a, b))
121
- }
122
- visitMulDiv(ctx) {
123
- this.visitBinaryArgs(ctx, (a, b) => {
124
- if (ctx.op.type === ModelLexer.Star) {
125
- return a * b
126
- } else {
127
- return a / b
128
- }
129
- })
130
- }
131
- visitAddSub(ctx) {
132
- this.visitBinaryArgs(ctx, (a, b) => {
133
- if (ctx.op.type === ModelLexer.Plus) {
134
- return a + b
135
- } else {
136
- return a - b
137
- }
138
- })
139
- }
140
- visitRelational(ctx) {
141
- this.visitBinaryArgs(ctx, (a, b) => {
142
- if (ctx.op.type === ModelLexer.Less) {
143
- return a < b ? 1 : 0
144
- } else if (ctx.op.type === ModelLexer.Greater) {
145
- return a > b ? 1 : 0
146
- } else if (ctx.op.type === ModelLexer.LessEqual) {
147
- return a <= b ? 1 : 0
148
- } else {
149
- return a >= b ? 1 : 0
150
- }
151
- })
152
- }
153
- visitEquality(ctx) {
154
- this.visitBinaryArgs(ctx, (a, b) => {
155
- if (ctx.op.type === ModelLexer.Equal) {
156
- return a === b ? 1 : 0
157
- } else {
158
- return a !== b ? 1 : 0
159
- }
160
- })
161
- }
162
- visitAnd(ctx) {
163
- // For AND expressions, we don't need both sides to have a constant value; as
164
- // long as one side is known to be false, then the expression resolves to false
165
- ctx.expr(0).accept(this)
166
- const constantValue0 = this.constantValue
167
- ctx.expr(1).accept(this)
168
- const constantValue1 = this.constantValue
169
- if (constantValue0 !== undefined && constantValue1 !== undefined) {
170
- this.constantValue = constantValue0 && constantValue1
171
- } else if (constantValue0 !== undefined && !constantValue0) {
172
- this.constantValue = 0
173
- } else if (constantValue1 !== undefined && !constantValue1) {
174
- this.constantValue = 0
175
- } else {
176
- this.constantValue = undefined
177
- }
178
- }
179
- visitOr(ctx) {
180
- // For OR expressions, we don't need both sides to have a constant value; as
181
- // long as one side is known to be true, then the expression resolves to true
182
- ctx.expr(0).accept(this)
183
- const constantValue0 = this.constantValue
184
- ctx.expr(1).accept(this)
185
- const constantValue1 = this.constantValue
186
- if (constantValue0 !== undefined && constantValue1 !== undefined) {
187
- this.constantValue = constantValue0 || constantValue1
188
- } else if (constantValue0 !== undefined && constantValue0) {
189
- this.constantValue = 1
190
- } else if (constantValue1 !== undefined && constantValue1) {
191
- this.constantValue = 1
192
- } else {
193
- this.constantValue = undefined
194
- }
195
- }
196
-
197
- // Tokens
198
-
199
- visitParens(ctx) {
200
- super.visitParens(ctx)
201
- }
202
- }
@@ -1,143 +0,0 @@
1
- import path from 'path'
2
- import { ModelParser } from 'antlr4-vensim'
3
- import * as R from 'ramda'
4
- import XLSX from 'xlsx'
5
-
6
- import { cFunctionName, matchRegex, readCsv } from '../_shared/helpers.js'
7
- import { Subscript } from '../_shared/subscript.js'
8
- import ModelReader from '../parse/model-reader.js'
9
-
10
- export default class SubscriptRangeReader extends ModelReader {
11
- constructor(modelDirname) {
12
- super()
13
- // The model directory is required when reading data files for GET DIRECT SUBSCRIPT.
14
- this.modelDirname = modelDirname
15
- // Index names from a subscript list or GET DIRECT SUBSCRIPT
16
- this.indNames = []
17
- // Dimension mappings with model names
18
- this.modelMappings = []
19
- }
20
- visitModel(ctx) {
21
- let subscriptRanges = ctx.subscriptRange()
22
- if (subscriptRanges) {
23
- for (let subscriptRange of subscriptRanges) {
24
- subscriptRange.accept(this)
25
- }
26
- }
27
- }
28
- visitSubscriptRange(ctx) {
29
- // When entering a new subscript range definition, reset the properties that will be filled in.
30
- this.indNames = []
31
- this.modelMappings = []
32
- // A subscript alias has two Ids, while a regular subscript range definition has just one.
33
- if (ctx.Id().length === 1) {
34
- // Subscript range definitions have a dimension name.
35
- let modelName = ctx.Id()[0].getText()
36
- // Visit children to fill in the subscript range definition.
37
- super.visitSubscriptRange(ctx)
38
- // Create a new subscript range definition from Vensim-format names.
39
- // The family is provisionally set to the dimension name.
40
- // It will be updated to the maximal dimension if this is a subdimension.
41
- // The mapping value contains dimensions and indices in the toDim.
42
- // It will be expanded and inverted to fromDim indices later.
43
- Subscript(modelName, this.indNames, modelName, this.modelMappings)
44
- } else {
45
- let modelName = ctx.Id()[0].getText()
46
- let modelFamily = ctx.Id()[1].getText()
47
- Subscript(modelName, '', modelFamily, [])
48
- }
49
- }
50
- visitSubscriptList(ctx) {
51
- // Get the subscripts from each subscript index in the list.
52
- for (let child of ctx.children) {
53
- if (child.symbol?.type === ModelParser.Id) {
54
- this.addSubscriptIndex(ctx, child)
55
- }
56
- }
57
- }
58
- visitSubscriptDefList(ctx) {
59
- // Subscript range definitions can have indices and numeric subscript sequences.
60
- for (let child of ctx.children) {
61
- if (child.symbol?.type === ModelParser.Id) {
62
- this.addSubscriptIndex(ctx, child)
63
- } else if (child.ruleIndex === ModelParser.RULE_subscriptSequence) {
64
- this.visitSubscriptSequence(child)
65
- }
66
- }
67
- }
68
- addSubscriptIndex(ctx, child) {
69
- let subscript = child.getText()
70
- if (ctx.parentCtx.ruleIndex === ModelParser.RULE_subscriptRange) {
71
- this.indNames.push(subscript)
72
- } else if (ctx.parentCtx.ruleIndex === ModelParser.RULE_subscriptMapping) {
73
- this.mappingValue.push(subscript)
74
- }
75
- }
76
- visitSubscriptMapping(ctx) {
77
- let toDim = ctx.Id().getText()
78
- // If a subscript list is part of the mapping, mappingValue will be set by visitSubscriptList.
79
- this.mappingValue = []
80
- super.visitSubscriptMapping(ctx)
81
- this.modelMappings.push({ toDim, value: this.mappingValue })
82
- }
83
- visitSubscriptSequence(ctx) {
84
- // Construct index names from the sequence start and end indices.
85
- // This assumes the indices begin with the same string and end with numbers.
86
- let r = /^(.*?)(\d+)$/
87
- let ids = R.map(id => id.getText(), ctx.Id())
88
- let matches = R.map(id => r.exec(id), ids)
89
- if (matches[0][1] === matches[1][1]) {
90
- let prefix = matches[0][1]
91
- let start = parseInt(matches[0][2])
92
- let end = parseInt(matches[1][2])
93
- // TODO get this to work with subscript mappings too
94
- for (let i = start; i <= end; i++) {
95
- this.indNames.push(prefix + i)
96
- }
97
- }
98
- }
99
- visitCall(ctx) {
100
- // A subscript range can have a GET DIRECT SUBSCRIPT call on the RHS.
101
- let fn = cFunctionName(ctx.Id().getText())
102
- if (fn === '_GET_DIRECT_SUBSCRIPT') {
103
- super.visitCall(ctx)
104
- }
105
- }
106
- visitExprList(ctx) {
107
- // We assume the only call that ends up here is GET DIRECT SUBSCRIPT.
108
- let args = R.map(
109
- arg => matchRegex(arg, /'(.*)'/),
110
- R.map(expr => expr.getText(), ctx.expr())
111
- )
112
- let pathname = args[0]
113
- let delimiter = args[1]
114
- let firstCell = args[2]
115
- let lastCell = args[3]
116
- // let prefix = args[4]
117
- // If lastCell is a column letter, scan the column, else scan the row.
118
- let dataAddress = XLSX.utils.decode_cell(firstCell.toUpperCase())
119
- let col = dataAddress.c
120
- let row = dataAddress.r
121
- if (col < 0 || row < 0) {
122
- throw new Error(`Failed to parse 'firstcell' argument for GET DIRECT SUBSCRIPT call: ${firstCell}`)
123
- }
124
- let nextCell
125
- if (isNaN(parseInt(lastCell))) {
126
- nextCell = () => row++
127
- } else {
128
- nextCell = () => col++
129
- }
130
- // Read subscript names from the CSV file at the given position.
131
- let csvPathname = path.resolve(this.modelDirname, pathname)
132
- let data = readCsv(csvPathname, delimiter)
133
- if (data) {
134
- let indexName = data[row][col]
135
- while (indexName != null) {
136
- this.indNames.push(indexName)
137
- nextCell()
138
- indexName = data[row] != null ? data[row][col] : null
139
- }
140
- }
141
- super.visitExprList(ctx)
142
- }
143
- }
@@ -1,40 +0,0 @@
1
- import * as R from 'ramda'
2
-
3
- import { canonicalName } from '../_shared/helpers.js'
4
- import { sub, isIndex, normalizeSubscripts } from '../_shared/subscript.js'
5
- import ModelReader from '../parse/model-reader.js'
6
- import { createParser } from '../parse/parser.js'
7
-
8
- //
9
- // VarNameReader reads a model var name using the parser to get the var name in C format.
10
- // This is used to generate a variable output in the output section.
11
- //
12
- export default class VarNameReader extends ModelReader {
13
- constructor() {
14
- super()
15
- this.varName = ''
16
- }
17
- read(modelVarName) {
18
- // Parse an individual model var name and convert it into a a canonical C var name.
19
- // Parse a single var name, which may include subscripts.
20
- let parser = createParser(modelVarName)
21
- let tree = parser.lhs()
22
- // Generate and return the canonical name.
23
- this.visitLhs(tree)
24
- return this.varName
25
- }
26
- visitLhs(ctx) {
27
- let varName = ctx.Id().getText()
28
- this.varName = canonicalName(varName)
29
- super.visitLhs(ctx)
30
- }
31
- visitSubscriptList(ctx) {
32
- // Get the canonical form of subscripts found in the var name.
33
- let subscripts = R.map(id => canonicalName(id.getText()), ctx.Id())
34
- subscripts = normalizeSubscripts(subscripts)
35
- // If a subscript is an index, convert it to an index number to match Vensim data exports.
36
- this.varName += R.map(subName => {
37
- return isIndex(subName) ? `[${sub(subName).value}]` : `[${subName}]`
38
- }, subscripts).join('')
39
- }
40
- }
@@ -1,172 +0,0 @@
1
- import { ModelParser } from 'antlr4-vensim'
2
- import * as R from 'ramda'
3
-
4
- import { canonicalName, vlog, strlist, cartesianProductOf } from '../_shared/helpers.js'
5
- import {
6
- sub,
7
- isDimension,
8
- isIndex,
9
- normalizeSubscripts,
10
- subscriptsMatch,
11
- isSubdimension
12
- } from '../_shared/subscript.js'
13
- import ModelReader from '../parse/model-reader.js'
14
-
15
- import Model from './model.js'
16
- import Variable from './variable.js'
17
-
18
- // Set true to print extra debugging information to stderr.
19
- const DEBUG_LOG = false
20
- let debugLog = (title, value) => !DEBUG_LOG || vlog(title, value)
21
-
22
- export default class VariableReader extends ModelReader {
23
- constructor(specialSeparationDims, directData) {
24
- super()
25
- // specialSeparationDims are var names that need to be separated because of
26
- // circular references, mapped to the dimension subscript to separate on.
27
- // '{c-variable-name}': '{c-dimension-name}'
28
- this.specialSeparationDims = specialSeparationDims || {}
29
- this.directData = directData || {}
30
- }
31
- visitModel(ctx) {
32
- let equations = ctx.equation()
33
- if (equations) {
34
- for (let equation of equations) {
35
- equation.accept(this)
36
- }
37
- }
38
- }
39
- visitEquation(ctx) {
40
- // Start a new variable defined by this equation.
41
- this.var = new Variable(ctx)
42
- // Allow for an alternate array of variables that are expanded over subdimensions.
43
- this.expandedVars = []
44
- // Fill in the variable by visiting the equation parse context.
45
- super.visitEquation(ctx)
46
- if (R.isEmpty(this.expandedVars)) {
47
- // Add a single variable defined by the equation.
48
- Model.addVariable(this.var)
49
- } else {
50
- // Add variables expanded over indices to the model.
51
- R.forEach(v => Model.addVariable(v), this.expandedVars)
52
- }
53
- }
54
- visitLhs(ctx) {
55
- this.var.varName = canonicalName(ctx.Id().getText())
56
- super.visitLhs(ctx)
57
- // Possibly expand the var on subdimensions.
58
- if (!R.isEmpty(this.var.subscripts)) {
59
- // Expand on LHS subscripts alone.
60
- let expanding = this.subscriptPosToExpand()
61
- this.expandVars(expanding)
62
- }
63
- }
64
- subscriptPosToExpand() {
65
- // Decide whether we need to expand each subscript on the LHS.
66
- // Construct an array of booleans in each subscript position.
67
- let expanding = []
68
- for (let iLhsSub = 0; iLhsSub < this.var.subscripts.length; iLhsSub++) {
69
- let subscript = this.var.subscripts[iLhsSub]
70
- let expand = false
71
- // Expand a subdimension and special separation dims in the LHS.
72
- if (isDimension(subscript)) {
73
- expand = isSubdimension(subscript)
74
- if (!expand) {
75
- let specialSeparationDims = this.specialSeparationDims[this.var.varName] || []
76
- expand = specialSeparationDims.includes(subscript)
77
- }
78
- }
79
- if (!expand) {
80
- // Direct data vars with subscripts are separated because we generate a lookup for each index.
81
- if (
82
- isDimension(subscript) &&
83
- (this.var.modelFormula.includes('GET DIRECT DATA') || this.var.modelFormula.includes('GET DIRECT LOOKUPS'))
84
- ) {
85
- expand = true
86
- }
87
- }
88
- // Also expand on exception subscripts that are indices or subdimensions.
89
- if (!expand) {
90
- for (let exceptSubs of this.var.exceptSubscripts) {
91
- expand = isIndex(exceptSubs[iLhsSub]) || isSubdimension(exceptSubs[iLhsSub])
92
- if (expand) {
93
- break
94
- }
95
- }
96
- }
97
- expanding.push(expand)
98
- }
99
- return expanding
100
- }
101
- expandVars(expanding) {
102
- // Expand the indicated subscripts into variable objects in the expandedVars list.
103
- debugLog(`expanding ${this.var.varName}[${strlist(this.var.subscripts)}] subscripts`, strlist(this.var.subscripts))
104
- let expansion = []
105
- let separationDims = []
106
- // Construct an array with an array at each subscript position. If the subscript is expanded at that position,
107
- // it will become an array of indices. Otherwise, it remains an index or dimension as a single-valued array.
108
- for (let i = 0; i < this.var.subscripts.length; i++) {
109
- let subscript = this.var.subscripts[i]
110
- let value
111
- if (expanding[i]) {
112
- separationDims.push(subscript)
113
- if (isDimension(subscript)) {
114
- value = sub(subscript).value
115
- }
116
- }
117
- expansion.push(value || [subscript])
118
- }
119
- // Generate an array of fully expanded subscripts, which may be indices or dimensions.
120
- let expandedSubs = cartesianProductOf(expansion)
121
- let skipExpansion = subs => {
122
- // Check the subscripts against each set of except subscripts. Skip expansion if one of them matches.
123
- let subsRange = R.range(0, subs.length)
124
- for (let exceptSubscripts of this.var.exceptSubscripts) {
125
- if (subs.length === exceptSubscripts.length) {
126
- if (R.all(i => subscriptsMatch(subs[i], exceptSubscripts[i]), subsRange)) {
127
- return true
128
- }
129
- } else {
130
- console.error(`WARNING: expandedSubs length ≠ exceptSubscripts length in ${this.var.varName}`)
131
- }
132
- }
133
- return false
134
- }
135
- for (let subs of expandedSubs) {
136
- // Skip expansions that match exception subscripts.
137
- if (!skipExpansion(subs)) {
138
- // Add a new variable to the expanded vars.
139
- let v = new Variable(this.var.eqnCtx)
140
- v.varName = this.var.varName
141
- v.subscripts = subs
142
- v.separationDims = separationDims
143
- debugLog(` ${strlist(v.subscripts)}`)
144
- this.expandedVars.push(v)
145
- }
146
- }
147
- }
148
- visitSubscriptList(ctx) {
149
- if (ctx.parentCtx.ruleIndex === ModelParser.RULE_lhs) {
150
- let subscripts = normalizeSubscripts(R.map(id => canonicalName(id.getText()), ctx.Id()))
151
- // Save subscripts in the Variable instance. Subscripts after the first one are exception subscripts.
152
- if (R.isEmpty(this.var.subscripts)) {
153
- this.var.subscripts = subscripts
154
- } else {
155
- this.var.exceptSubscripts.push(subscripts)
156
- }
157
- }
158
- super.visitSubscriptList(ctx)
159
- }
160
- visitConstList(ctx) {
161
- // Expand a subscripted equation with a constant list.
162
- let exprs = ctx.expr()
163
- if (exprs.length > 1) {
164
- let expanding = R.map(subscript => isDimension(subscript), this.var.subscripts)
165
- // If the var was already expanded, do it over to make sure we expand on all subscripts.
166
- if (!R.isEmpty(this.expandedVars)) {
167
- this.expandedVars = []
168
- }
169
- this.expandVars(expanding)
170
- }
171
- }
172
- }
@@ -1,141 +0,0 @@
1
- import { ModelVisitor } from 'antlr4-vensim'
2
-
3
- export default class ModelReader extends ModelVisitor {
4
- constructor() {
5
- super()
6
- // stack of function names and argument indices encountered on the RHS
7
- this.callStack = []
8
- }
9
- currentFunctionName() {
10
- // Return the name of the current function on top of the call stack.
11
- let n = this.callStack.length
12
- return n > 0 ? this.callStack[n - 1].fn : ''
13
- }
14
- setArgIndex(argIndex) {
15
- // Set the argument index in the current function call on top of the call stack.
16
- // This may be set in the exprList visitor and picked up in the var visitor to facilitate special argument handling.
17
- let n = this.callStack.length
18
- if (n > 0) {
19
- this.callStack[n - 1].argIndex = argIndex
20
- }
21
- }
22
- argIndexForFunctionName(name) {
23
- // Search the call stack for the function name. Return the current argument index or undefined if not found.
24
- let argIndex
25
- for (let i = this.callStack.length - 1; i >= 0; i--) {
26
- if (this.callStack[i].fn === name) {
27
- argIndex = this.callStack[i].argIndex
28
- break
29
- }
30
- }
31
- return argIndex
32
- }
33
- visitEquation(ctx) {
34
- ctx.lhs().accept(this)
35
- if (ctx.expr()) {
36
- ctx.expr().accept(this)
37
- } else if (ctx.constList()) {
38
- ctx.constList().accept(this)
39
- } else if (ctx.lookup()) {
40
- ctx.lookup().accept(this)
41
- } else {
42
- this.var.varType = 'data'
43
- }
44
- }
45
- visitLhs(ctx) {
46
- // An LHS may have a subscript list after the var name.
47
- // If it has an EXCEPT clause, it will have one or more other subscript lists there too.
48
- let subscriptLists = ctx.subscriptList()
49
- if (subscriptLists.length > 0) {
50
- for (let i = 0; i < subscriptLists.length; i++) {
51
- subscriptLists[i].accept(this)
52
- }
53
- }
54
- }
55
-
56
- // Function calls and variables
57
-
58
- visitCall(ctx) {
59
- if (ctx.exprList()) {
60
- ctx.exprList().accept(this)
61
- }
62
- }
63
- visitExprList(ctx) {
64
- let exprs = ctx.expr()
65
- // Set the argument index in an instance property so derived classes can determine argument position.
66
- for (let i = 0; i < exprs.length; i++) {
67
- this.setArgIndex(i)
68
- exprs[i].accept(this)
69
- }
70
- }
71
- visitVar(ctx) {
72
- if (ctx.subscriptList()) {
73
- ctx.subscriptList().accept(this)
74
- }
75
- }
76
-
77
- // Lookups
78
-
79
- visitLookup(ctx) {
80
- if (ctx.lookupRange()) {
81
- ctx.lookupRange().accept(this)
82
- }
83
- if (ctx.lookupPointList()) {
84
- ctx.lookupPointList().accept(this)
85
- }
86
- }
87
- visitLookupCall(ctx) {
88
- if (ctx.subscriptList()) {
89
- ctx.subscriptList().accept(this)
90
- }
91
- }
92
-
93
- // Unary operators
94
-
95
- visitNegative(ctx) {
96
- ctx.expr().accept(this)
97
- }
98
- visitPositive(ctx) {
99
- ctx.expr().accept(this)
100
- }
101
- visitNot(ctx) {
102
- ctx.expr().accept(this)
103
- }
104
-
105
- // Binary operators
106
-
107
- visitPower(ctx) {
108
- ctx.expr(0).accept(this)
109
- ctx.expr(1).accept(this)
110
- }
111
- visitMulDiv(ctx) {
112
- ctx.expr(0).accept(this)
113
- ctx.expr(1).accept(this)
114
- }
115
- visitAddSub(ctx) {
116
- ctx.expr(0).accept(this)
117
- ctx.expr(1).accept(this)
118
- }
119
- visitRelational(ctx) {
120
- ctx.expr(0).accept(this)
121
- ctx.expr(1).accept(this)
122
- }
123
- visitEquality(ctx) {
124
- ctx.expr(0).accept(this)
125
- ctx.expr(1).accept(this)
126
- }
127
- visitAnd(ctx) {
128
- ctx.expr(0).accept(this)
129
- ctx.expr(1).accept(this)
130
- }
131
- visitOr(ctx) {
132
- ctx.expr(0).accept(this)
133
- ctx.expr(1).accept(this)
134
- }
135
-
136
- // Tokens
137
-
138
- visitParens(ctx) {
139
- ctx.expr().accept(this)
140
- }
141
- }