From d55cc5e0134bd57040188933b9904d6d18227339 Mon Sep 17 00:00:00 2001 From: Doug Torrance Date: Sat, 20 Jan 2024 17:25:29 -0500 Subject: [PATCH] Refactor augmented assignment so we don't evaluate things twice Evaluate everything immediately but store it as evaluatedCode for later. --- M2/Macaulay2/d/evaluate.d | 44 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/M2/Macaulay2/d/evaluate.d b/M2/Macaulay2/d/evaluate.d index d156d4a4699..52e3a904da4 100644 --- a/M2/Macaulay2/d/evaluate.d +++ b/M2/Macaulay2/d/evaluate.d @@ -1213,50 +1213,52 @@ augmentedAssignmentFun(x:augmentedAssignmentCode):Expr := ( when lookup(x.oper.word, augmentedAssignmentOperatorTable) is null do buildErrorPacket("unknown augmented assignment operator") is s:Symbol do ( - -- first check if user-defined method - -- TODO: when there isn't a user-defined method, we end up evaluating - -- the left-hand side twice. is there any way to avoid this? - left := eval(x.lhs); - when left is e:Error do return Expr(e) else nothing; - meth := lookup(Class(left), Expr(SymbolClosure(globalFrame, x.oper))); + -- evaluate both sides first + left := evaluatedCode(eval(x.lhs), dummyPosition); + when left.expr is e:Error do return Expr(e) else nothing; + right := evaluatedCode(eval(x.rhs), dummyPosition); + when right.expr is e:Error do return Expr(e) else nothing; + -- check if user-defined method exists + meth := lookup(Class(left.expr), + Expr(SymbolClosure(globalFrame, x.oper))); if meth != nullE then ( - right := eval(x.rhs); - when right is e:Error do return Expr(e) - else ( - r := applyEEE(meth, left, right); - when r - is s:SymbolClosure do ( - if s.symbol.word.name === "Default" then nothing - else return r) - else return r)); + r := applyEEE(meth, left.expr, right.expr); + when r + is s:SymbolClosure do ( + if s.symbol.word.name === "Default" then nothing + else return r) + else return r); -- if not, use default behavior when x.lhs is y:globalMemoryReferenceCode do ( - r := s.binary(x.lhs, x.rhs); + r := s.binary(Code(left), Code(right)); when r is e:Error do Expr(e) else globalAssignment(y.frameindex, x.info, r)) is y:localMemoryReferenceCode do ( - r := s.binary(x.lhs, x.rhs); + r := s.binary(Code(left), Code(right)); when r is e:Error do Expr(e) else localAssignment(y.nestingDepth, y.frameindex, r)) is y:threadMemoryReferenceCode do ( - r := s.binary(x.lhs, x.rhs); + r := s.binary(Code(left), Code(right)); when r is e:Error do Expr(e) else globalAssignment(y.frameindex, x.info, r)) is y:binaryCode do ( - r := Code(binaryCode(s.binary, y, x.rhs, dummyPosition)); + r := Code(binaryCode(s.binary, Code(left), Code(right), + dummyPosition)); if y.f == DotS.symbol.binary || y.f == SharpS.symbol.binary then AssignElemFun(y.lhs, y.rhs, r) else InstallValueFun(CodeSequence(Code( globalSymbolClosureCode(x.info, dummyPosition)), y.lhs, y.rhs, r))) is y:adjacentCode do ( - r := Code(binaryCode(s.binary, y, x.rhs, dummyPosition)); + r := Code(binaryCode(s.binary, Code(left), Code(right), + dummyPosition)); InstallValueFun(CodeSequence(Code(globalSymbolClosureCode( AdjacentS.symbol, dummyPosition)), y.lhs, y.rhs, r))) is y:unaryCode do ( - r := Code(binaryCode(s.binary, y, x.rhs, dummyPosition)); + r := Code(binaryCode(s.binary, Code(left), Code(right), + dummyPosition)); UnaryInstallValueFun( Code(globalSymbolClosureCode(x.info, dummyPosition)), y.rhs, r))