Traverse expression tree with visit function. The visit function is applied to an expression with given args and kwargs. Traverse call returns an expression returned by visit when not None, otherwise return a new normalized expression with traverse-visit sub
(self, visit, *args, **kwargs)
| 657 | raise NotImplementedError(f'substitute method for {self.op}: {self!r}') |
| 658 | |
| 659 | def traverse(self, visit, *args, **kwargs): |
| 660 | """Traverse expression tree with visit function. |
| 661 | |
| 662 | The visit function is applied to an expression with given args |
| 663 | and kwargs. |
| 664 | |
| 665 | Traverse call returns an expression returned by visit when not |
| 666 | None, otherwise return a new normalized expression with |
| 667 | traverse-visit sub-expressions. |
| 668 | """ |
| 669 | result = visit(self, *args, **kwargs) |
| 670 | if result is not None: |
| 671 | return result |
| 672 | |
| 673 | if self.op in (Op.INTEGER, Op.REAL, Op.STRING, Op.SYMBOL): |
| 674 | return self |
| 675 | elif self.op in (Op.COMPLEX, Op.ARRAY, Op.CONCAT, Op.TERNARY): |
| 676 | return normalize(Expr(self.op, tuple( |
| 677 | item.traverse(visit, *args, **kwargs) |
| 678 | for item in self.data))) |
| 679 | elif self.op in (Op.TERMS, Op.FACTORS): |
| 680 | data = {} |
| 681 | for k, v in self.data.items(): |
| 682 | k = k.traverse(visit, *args, **kwargs) |
| 683 | v = (v.traverse(visit, *args, **kwargs) |
| 684 | if isinstance(v, Expr) else v) |
| 685 | if k in data: |
| 686 | v = data[k] + v |
| 687 | data[k] = v |
| 688 | return normalize(Expr(self.op, data)) |
| 689 | elif self.op is Op.APPLY: |
| 690 | obj = self.data[0] |
| 691 | func = (obj.traverse(visit, *args, **kwargs) |
| 692 | if isinstance(obj, Expr) else obj) |
| 693 | operands = tuple(operand.traverse(visit, *args, **kwargs) |
| 694 | for operand in self.data[1]) |
| 695 | kwoperands = {k: v.traverse(visit, *args, **kwargs) |
| 696 | for k, v in self.data[2].items()} |
| 697 | return normalize(Expr(self.op, (func, operands, kwoperands))) |
| 698 | elif self.op is Op.INDEXING: |
| 699 | obj = self.data[0] |
| 700 | obj = (obj.traverse(visit, *args, **kwargs) |
| 701 | if isinstance(obj, Expr) else obj) |
| 702 | indices = tuple(index.traverse(visit, *args, **kwargs) |
| 703 | for index in self.data[1:]) |
| 704 | return normalize(Expr(self.op, (obj,) + indices)) |
| 705 | elif self.op in (Op.REF, Op.DEREF): |
| 706 | return normalize(Expr(self.op, |
| 707 | self.data.traverse(visit, *args, **kwargs))) |
| 708 | elif self.op is Op.RELATIONAL: |
| 709 | rop, left, right = self.data |
| 710 | left = left.traverse(visit, *args, **kwargs) |
| 711 | right = right.traverse(visit, *args, **kwargs) |
| 712 | return normalize(Expr(self.op, (rop, left, right))) |
| 713 | raise NotImplementedError(f'traverse method for {self.op}') |
| 714 | |
| 715 | def contains(self, other): |
| 716 | """Check if self contains other. |