| 75 | |
| 76 | |
| 77 | class PyScopedSymbolTable(object): |
| 78 | |
| 79 | class Scope(object): |
| 80 | |
| 81 | def __init__(self, scope_root, parent=None): |
| 82 | assert isinstance(scope_root, Block) and hasattr( |
| 83 | scope_root, 'owner') |
| 84 | self.root = scope_root |
| 85 | self.parent = parent |
| 86 | self._blockID = -1 |
| 87 | self._parentBlocks = deque() |
| 88 | self._symbols = {} |
| 89 | |
| 90 | def beginBlock(self): |
| 91 | self._blockID += 1 |
| 92 | self._parentBlocks.append(self._blockID) |
| 93 | |
| 94 | def endBlock(self): |
| 95 | assert self._parentBlocks |
| 96 | self._parentBlocks.pop() |
| 97 | |
| 98 | def isDefined(self, symbol): |
| 99 | return symbol in self._symbols |
| 100 | |
| 101 | def tryGet(self, symbol): |
| 102 | """Returns the value of the given symbol in this scope, as well as a |
| 103 | boolean indicating whether the value is valid in the current |
| 104 | scope.""" |
| 105 | if not symbol in self._symbols: |
| 106 | return None, False |
| 107 | |
| 108 | # We need to make sure that the symbol is not only defined, |
| 109 | # but also accessible at this location in the MLIR we generate. |
| 110 | # To check for this, the symbol table keeps track of which block |
| 111 | # a symbol is defined in. Because/if some variables are stored |
| 112 | # as values in the symbol table, a value defined in an inner |
| 113 | # block may not be accessible in the outer block (MLIR fails |
| 114 | # with "operand does not dominate this use"). We hence fail |
| 115 | # with a comprehensive error if a symbol is defined according |
| 116 | # to Python scoping rules, but not valid to use at the current |
| 117 | # location in the generated MLIR. |
| 118 | value, sid = self._symbols[symbol] |
| 119 | return value, sid in self._parentBlocks |
| 120 | |
| 121 | def addOrUpdate(self, symbol, value): |
| 122 | assert self._parentBlocks |
| 123 | if hasattr(value, 'owner'): |
| 124 | if value.owner == self.root: |
| 125 | self._symbols[symbol] = (value, 0) |
| 126 | return |
| 127 | if (hasattr(value.owner, 'parent') and |
| 128 | value.owner.parent == self.root.owner): |
| 129 | self._symbols[symbol] = (value, 0) |
| 130 | return |
| 131 | self._symbols[symbol] = (value, self._parentBlocks[-1]) |
| 132 | |
| 133 | @property |
| 134 | def depth(self): |