* Returns an expression of all template guards that apply to this scope, including those of * parent scopes. If no guards have been applied, null is returned.
()
| 328 | * parent scopes. If no guards have been applied, null is returned. |
| 329 | */ |
| 330 | guards(): TcbExpr | null { |
| 331 | let parentGuards: TcbExpr | null = null; |
| 332 | if (this.parent !== null) { |
| 333 | // Start with the guards from the parent scope, if present. |
| 334 | parentGuards = this.parent.guards(); |
| 335 | } |
| 336 | |
| 337 | if (this.guard === null) { |
| 338 | // This scope does not have a guard, so return the parent's guards as is. |
| 339 | return parentGuards; |
| 340 | } else if (parentGuards === null) { |
| 341 | // There's no guards from the parent scope, so this scope's guard represents all available |
| 342 | // guards. |
| 343 | return typeof this.guard === 'string' ? new TcbExpr(this.guard) : this.guard; |
| 344 | } else { |
| 345 | // Both the parent scope and this scope provide a guard, so create a combination of the two. |
| 346 | // It is important that the parent guard is used as left operand, given that it may provide |
| 347 | // narrowing that is required for this scope's guard to be valid. |
| 348 | const guard = typeof this.guard === 'string' ? this.guard : this.guard.print(); |
| 349 | return new TcbExpr(`(${parentGuards.print()}) && (${guard})`); |
| 350 | } |
| 351 | } |
| 352 | |
| 353 | /** Returns whether a template symbol is defined locally within the current scope. */ |
| 354 | isLocal(node: Variable | LetDeclaration | Reference): boolean { |
no test coverage detected