Skip to content

Commit

Permalink
Hashes no longer change for expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
corywalker committed Jul 17, 2017
1 parent ddbc0b2 commit cc5acb4
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 34 deletions.
6 changes: 4 additions & 2 deletions expreduce/builtin_sort.go
Expand Up @@ -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
},
Expand Down
59 changes: 30 additions & 29 deletions expreduce/ex_expression.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
7 changes: 4 additions & 3 deletions 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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
Expand Down

0 comments on commit cc5acb4

Please sign in to comment.