* Fully evaluates the given expression and returns the resulting value. * May throw a variety of VimErrors if the expression is semantically invalid.
(expression: Expression)
| 165 | * May throw a variety of VimErrors if the expression is semantically invalid. |
| 166 | */ |
| 167 | public evaluate(expression: Expression): Value { |
| 168 | switch (expression.type) { |
| 169 | case 'number': |
| 170 | case 'float': |
| 171 | case 'string': |
| 172 | return expression; |
| 173 | case 'blob': |
| 174 | return blob(expression.data); |
| 175 | case 'list': |
| 176 | return list(expression.items.map((x) => this.evaluate(x))); |
| 177 | case 'dictionary': { |
| 178 | const items = new Map<string, Value>(); |
| 179 | for (const [key, val] of expression.items) { |
| 180 | const keyStr = toString(this.evaluate(key)); |
| 181 | if (items.has(keyStr)) { |
| 182 | throw VimError.DuplicateKeyInDictionary(keyStr); |
| 183 | } else { |
| 184 | items.set(keyStr, this.evaluate(val)); |
| 185 | } |
| 186 | } |
| 187 | return dictionary(items); |
| 188 | } |
| 189 | case 'funcref': |
| 190 | const arglist = expression.arglist |
| 191 | ? list(expression.arglist.items.map((e) => this.evaluate(e))) |
| 192 | : undefined; |
| 193 | const dict = expression.dict |
| 194 | ? dictionary( |
| 195 | new Map( |
| 196 | [...expression.dict.items].map(([k, v]) => [ |
| 197 | toString(this.evaluate(k)), |
| 198 | this.evaluate(v), |
| 199 | ]), |
| 200 | ), |
| 201 | ) |
| 202 | : undefined; |
| 203 | return funcref({ name: expression.name, body: expression.body, arglist, dict }); |
| 204 | case 'variable': |
| 205 | return this.evaluateVariable(expression); |
| 206 | case 'register': |
| 207 | const reg = Register.getSync(expression.name); |
| 208 | if (reg === undefined || reg.text instanceof RecordedState) { |
| 209 | return str(''); // TODO: Handle RecordedState? |
| 210 | } |
| 211 | return str(reg.text); |
| 212 | case 'option': |
| 213 | return str(''); // TODO |
| 214 | case 'env_variable': |
| 215 | return str(process.env[expression.name] ?? ''); |
| 216 | case 'function_call': |
| 217 | return this.evaluateFunctionCall(expression); |
| 218 | case 'index': { |
| 219 | return this.evaluateIndex( |
| 220 | this.evaluate(expression.expression), |
| 221 | this.evaluate(expression.index), |
| 222 | ); |
| 223 | } |
| 224 | case 'slice': { |