UpdateExpr updates the target expression with the updated content while preserving macro metadata. There are four scenarios during the update to consider: 1. target is not macro, updated is not macro 2. target is macro, updated is not macro 3. target is macro, updated is macro 4. target is not macr
(target, updated ast.Expr)
| 497 | // updated to point to the new updated macro. Otherwise, other macros which pointed to |
| 498 | // the target body must be replaced with copies of the updated expression body. |
| 499 | func (opt *optimizerExprFactory) UpdateExpr(target, updated ast.Expr) { |
| 500 | // Update the expression |
| 501 | target.SetKindCase(updated) |
| 502 | |
| 503 | // Early return if there's no macros present sa the source info reflects the |
| 504 | // macro set from the target and updated expressions. |
| 505 | if len(opt.sourceInfo.MacroCalls()) == 0 { |
| 506 | return |
| 507 | } |
| 508 | // Determine whether the target expression was a macro. |
| 509 | _, targetIsMacro := opt.sourceInfo.GetMacroCall(target.ID()) |
| 510 | |
| 511 | // Determine whether the updated expression was a macro. |
| 512 | updatedMacro, updatedIsMacro := opt.sourceInfo.GetMacroCall(updated.ID()) |
| 513 | |
| 514 | if updatedIsMacro { |
| 515 | // If the updated call was a macro, then updated id maps to target id, |
| 516 | // and the updated macro moves into the target id slot. |
| 517 | opt.sourceInfo.ClearMacroCall(updated.ID()) |
| 518 | opt.sourceInfo.SetMacroCall(target.ID(), updatedMacro) |
| 519 | } else if targetIsMacro { |
| 520 | // Otherwise if the target expr was a macro, but is no longer, clear |
| 521 | // the macro reference. |
| 522 | opt.sourceInfo.ClearMacroCall(target.ID()) |
| 523 | } |
| 524 | |
| 525 | // Punch holes in the updated value where macros references exist. |
| 526 | macroExpr := opt.fac.CopyExpr(target) |
| 527 | macroRefVisitor := ast.NewExprVisitor(func(e ast.Expr) { |
| 528 | if _, exists := opt.sourceInfo.GetMacroCall(e.ID()); exists { |
| 529 | e.SetKindCase(nil) |
| 530 | } |
| 531 | }) |
| 532 | ast.PostOrderVisit(macroExpr, macroRefVisitor) |
| 533 | |
| 534 | // Update any references to the expression within a macro |
| 535 | macroVisitor := ast.NewExprVisitor(func(call ast.Expr) { |
| 536 | // Update the target expression to point to the macro expression which |
| 537 | // will be empty if the updated expression was a macro. |
| 538 | if call.ID() == target.ID() { |
| 539 | call.SetKindCase(opt.fac.CopyExpr(macroExpr)) |
| 540 | } |
| 541 | // Update the macro call expression if it refers to the updated expression |
| 542 | // id which has since been remapped to the target id. |
| 543 | if call.ID() == updated.ID() { |
| 544 | // Either ensure the expression is a macro reference or a populated with |
| 545 | // the relevant sub-expression if the updated expr was not a macro. |
| 546 | if updatedIsMacro { |
| 547 | call.SetKindCase(nil) |
| 548 | } else { |
| 549 | call.SetKindCase(opt.fac.CopyExpr(macroExpr)) |
| 550 | } |
| 551 | // Since SetKindCase does not renumber the id, ensure the references to |
| 552 | // the old 'updated' id are mapped to the target id. |
| 553 | call.RenumberIDs(func(id int64) int64 { |
| 554 | if id == updated.ID() { |
| 555 | return target.ID() |
| 556 | } |