* * @param {Scope} scope * @param {Expression | FunctionDeclaration} expression * @param {Set<any>} values
(scope, expression, values)
| 261 | * @param {Set<any>} values |
| 262 | */ |
| 263 | constructor(scope, expression, values) { |
| 264 | current_evaluations.set(expression, this); |
| 265 | |
| 266 | this.values = values; |
| 267 | |
| 268 | switch (expression.type) { |
| 269 | case 'Literal': { |
| 270 | this.values.add(expression.value); |
| 271 | break; |
| 272 | } |
| 273 | |
| 274 | case 'Identifier': { |
| 275 | const binding = scope.get(expression.name); |
| 276 | |
| 277 | if (binding) { |
| 278 | if ( |
| 279 | binding.initial?.type === 'CallExpression' && |
| 280 | get_rune(binding.initial, scope) === '$props.id' |
| 281 | ) { |
| 282 | this.values.add(STRING); |
| 283 | break; |
| 284 | } |
| 285 | |
| 286 | const is_prop = |
| 287 | binding.kind === 'prop' || |
| 288 | binding.kind === 'rest_prop' || |
| 289 | binding.kind === 'bindable_prop'; |
| 290 | |
| 291 | if (binding.initial?.type === 'EachBlock' && binding.initial.index === expression.name) { |
| 292 | this.values.add(NUMBER); |
| 293 | break; |
| 294 | } |
| 295 | |
| 296 | if (binding.initial?.type === 'SnippetBlock') { |
| 297 | this.is_defined = true; |
| 298 | this.is_known = false; |
| 299 | this.values.add(UNKNOWN); |
| 300 | break; |
| 301 | } |
| 302 | |
| 303 | if (!binding.updated && binding.initial !== null && !is_prop) { |
| 304 | binding.scope.evaluate(/** @type {Expression} */ (binding.initial), this.values); |
| 305 | break; |
| 306 | } |
| 307 | } else if (expression.name === 'undefined') { |
| 308 | this.values.add(undefined); |
| 309 | break; |
| 310 | } |
| 311 | |
| 312 | // TODO glean what we can from reassignments |
| 313 | // TODO one day, expose props and imports somehow |
| 314 | |
| 315 | this.values.add(UNKNOWN); |
| 316 | break; |
| 317 | } |
| 318 | |
| 319 | case 'BinaryExpression': { |
| 320 | const a = scope.evaluate(/** @type {Expression} */ (expression.left)); // `left` cannot be `PrivateIdentifier` unless operator is `in` |