From cc5acb4389853022370169c178891b85248ded97 Mon Sep 17 00:00:00 2001 From: cmwslw Date: Sun, 16 Jul 2017 20:24:04 -0700 Subject: [PATCH] Hashes no longer change for expressions. --- expreduce/builtin_sort.go | 6 ++-- expreduce/ex_expression.go | 59 +++++++++++++++++++------------------- expreduce/replace.go | 7 +++-- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/expreduce/builtin_sort.go b/expreduce/builtin_sort.go index a378436..93eaab2 100644 --- a/expreduce/builtin_sort.go +++ b/expreduce/builtin_sort.go @@ -16,8 +16,10 @@ func GetSortDefinitions() (defs []Definition) { exp, ok := this.Parts[1].(*Expression) if ok { - sort.Sort(exp) - return exp + sortedExp := exp.DeepCopy().(*Expression) + sortedExp.cachedHash = 0 + sort.Sort(sortedExp) + return sortedExp } return this }, diff --git a/expreduce/ex_expression.go b/expreduce/ex_expression.go index 1a9a53a..74df022 100644 --- a/expreduce/ex_expression.go +++ b/expreduce/ex_expression.go @@ -71,36 +71,32 @@ func tryReturnValue(e Ex) (Ex, bool) { // Is this causing issues by not creating a copy as we modify? Actually it is // creating copies. -func (this *Expression) mergeSequences(es *EvalState, headStr string, shouldEval bool) { +func (this *Expression) mergeSequences(es *EvalState, headStr string, shouldEval bool) *Expression { // TODO: I should not be attempting to merge the head if it happens to be // a Sequence type. This is very similar to the flatten function. Perhaps // it should be combined. This version is not recursive, and it does not // accept level depths. It is a specific case of Flatten. - origLen := len(this.Parts) - offset := 0 - for i := 0; i < origLen; i++ { - j := i + offset - e := this.Parts[j] + res := NewEmptyExpression() + encounteredSeq := false + for _, e := range(this.Parts) { seq, isseq := HeadAssertion(e, headStr) - if shouldEval { - for j := 1; j < len(seq.Parts); j++ { - seq.Parts[j] = seq.Parts[j].Eval(es) - } - } if isseq { - start := j - end := j + 1 - if j == 0 { - this.Parts = append(seq.Parts[1:], this.Parts[end:]...) - } else if j == len(this.Parts)-1 { - this.Parts = append(this.Parts[:start], seq.Parts[1:]...) - } else { - // All of these deep copies may not be needed. - this.Parts = append(append(this.DeepCopy().(*Expression).Parts[:start], seq.DeepCopy().(*Expression).Parts[1:]...), this.DeepCopy().(*Expression).Parts[end:]...) + encounteredSeq = true + for _, seqPart := range seq.Parts[1:] { + if shouldEval { + res.Parts = append(res.Parts, seqPart.Eval(es)) + } else { + res.Parts = append(res.Parts, seqPart) + } } - offset += len(seq.Parts[1:]) - 1 + } else { + res.Parts = append(res.Parts, e) } } + if encounteredSeq { + return res + } + return this } func (this *Expression) Eval(es *EvalState) Ex { @@ -219,17 +215,19 @@ func (this *Expression) Eval(es *EvalState) Ex { // If any of the parts are Sequence, merge them with parts if headIsSym { if !attrs.SequenceHold { - curr.mergeSequences(es, "Sequence", false) + curr = curr.mergeSequences(es, "Sequence", false) } } else { - curr.mergeSequences(es, "Sequence", false) + curr = curr.mergeSequences(es, "Sequence", false) } - curr.mergeSequences(es, "Evaluate", true) + curr = curr.mergeSequences(es, "Evaluate", true) + // In case curr changed + currEx = curr pureFunction, isPureFunction := HeadAssertion(curr.Parts[0], "Function") if headIsSym { if attrs.Flat { - curr.mergeSequences(es, headSym.Name, false) + curr = curr.mergeSequences(es, headSym.Name, false) } if attrs.Orderless { sort.Sort(curr) @@ -328,11 +326,10 @@ func (this *Expression) ReplaceAll(r *Expression, stopAtHead string, es *EvalSta es.Debugf("Rule r is: %s", r) matchq, matches := IsMatchQ(this, r.Parts[1], EmptyPD(), es) - toreturn := ReplacePD(r.Parts[2].DeepCopy(), es, matches) if matchq { es.Debugf("After MatchQ, rule is: %s", r) es.Debugf("MatchQ succeeded. Returning r.Parts[2]: %s", r.Parts[2]) - return toreturn + return ReplacePD(r.Parts[2].DeepCopy(), es, matches) } thisSym, thisSymOk := this.Parts[0].(*Symbol) @@ -343,14 +340,18 @@ func (this *Expression) ReplaceAll(r *Expression, stopAtHead string, es *EvalSta if thisSym.Name == otherSym.Name { attrs := thisSym.Attrs(&es.defined) if attrs.Flat { - FlatReplace(this, lhsExpr, r.Parts[2], attrs.Orderless, es) + return FlatReplace(this, lhsExpr, r.Parts[2], attrs.Orderless, es) } } } } + maybeChanged := NewEmptyExpression() for i := range this.Parts { - this.Parts[i] = ReplaceAll(this.Parts[i], r, es, EmptyPD(), stopAtHead) + maybeChanged.Parts = append(maybeChanged.Parts, ReplaceAll(this.Parts[i], r, es, EmptyPD(), stopAtHead)) + } + if hashEx(maybeChanged) != hashEx(this) { + return maybeChanged } return this } diff --git a/expreduce/replace.go b/expreduce/replace.go index 4e820fa..08ae7be 100644 --- a/expreduce/replace.go +++ b/expreduce/replace.go @@ -1,7 +1,7 @@ package expreduce // This function assumes e and lhs have the same head and that the head is Flat. -func FlatReplace(e *Expression, lhs *Expression, rhs Ex, orderless bool, es *EvalState) { +func FlatReplace(e *Expression, lhs *Expression, rhs Ex, orderless bool, es *EvalState) Ex { looseLhs := NewExpression([]Ex{}) looseLhs.Parts = append(looseLhs.Parts, lhs.Parts[0]) if !orderless { @@ -35,9 +35,9 @@ func FlatReplace(e *Expression, lhs *Expression, rhs Ex, orderless bool, es *Eva &Symbol{"Expreduce`end"}, }), es, newPd) } - tmpExpr := tmpEx.(*Expression) - e.Parts = tmpExpr.Parts + return tmpEx } + return e } func ReplacePDInternal(e Ex, pm *PDManager) Ex { @@ -52,6 +52,7 @@ func ReplacePDInternal(e Ex, pm *PDManager) Ex { } asExpr, isExpr := e.(*Expression) if isExpr { + asExpr.cachedHash = 0 for i := range asExpr.Parts { asExpr.Parts[i] = ReplacePDInternal(asExpr.Parts[i], pm) }