Walks two ASTs in parallel. The two trees must have identical structure. Args: node: Union[ast.AST, Iterable[ast.AST]] other: Union[ast.AST, Iterable[ast.AST]] Yields: Tuple[ast.AST, ast.AST] Raises: ValueError: if the two trees don't have identical structure.
(node, other)
| 260 | |
| 261 | |
| 262 | def parallel_walk(node, other): |
| 263 | """Walks two ASTs in parallel. |
| 264 | |
| 265 | The two trees must have identical structure. |
| 266 | |
| 267 | Args: |
| 268 | node: Union[ast.AST, Iterable[ast.AST]] |
| 269 | other: Union[ast.AST, Iterable[ast.AST]] |
| 270 | Yields: |
| 271 | Tuple[ast.AST, ast.AST] |
| 272 | Raises: |
| 273 | ValueError: if the two trees don't have identical structure. |
| 274 | """ |
| 275 | if isinstance(node, (list, tuple)): |
| 276 | node_stack = list(node) |
| 277 | else: |
| 278 | node_stack = [node] |
| 279 | |
| 280 | if isinstance(other, (list, tuple)): |
| 281 | other_stack = list(other) |
| 282 | else: |
| 283 | other_stack = [other] |
| 284 | |
| 285 | while node_stack and other_stack: |
| 286 | assert len(node_stack) == len(other_stack) |
| 287 | n = node_stack.pop() |
| 288 | o = other_stack.pop() |
| 289 | |
| 290 | if ((not isinstance(n, (ast.AST, gast.AST, str)) and n is not None) or |
| 291 | (not isinstance(o, (ast.AST, gast.AST, str)) and n is not None) or |
| 292 | n.__class__.__name__ != o.__class__.__name__): |
| 293 | raise ValueError('inconsistent nodes: {} ({}) and {} ({})'.format( |
| 294 | n, n.__class__.__name__, o, o.__class__.__name__)) |
| 295 | |
| 296 | yield n, o |
| 297 | |
| 298 | if isinstance(n, str): |
| 299 | assert isinstance(o, str), 'The check above should have ensured this' |
| 300 | continue |
| 301 | if n is None: |
| 302 | assert o is None, 'The check above should have ensured this' |
| 303 | continue |
| 304 | |
| 305 | for f in n._fields: |
| 306 | n_child = getattr(n, f, None) |
| 307 | o_child = getattr(o, f, None) |
| 308 | if f.startswith('__') or n_child is None or o_child is None: |
| 309 | continue |
| 310 | |
| 311 | if isinstance(n_child, (list, tuple)): |
| 312 | if (not isinstance(o_child, (list, tuple)) or |
| 313 | len(n_child) != len(o_child)): |
| 314 | raise ValueError( |
| 315 | 'inconsistent values for field {}: {} and {}'.format( |
| 316 | f, n_child, o_child)) |
| 317 | node_stack.extend(n_child) |
| 318 | other_stack.extend(o_child) |
| 319 |