Skip to content

Commit

Permalink
Merge pull request #268 from ichiban/renamed-copy-partial
Browse files Browse the repository at this point in the history
efficient renamed copy for partials
  • Loading branch information
ichiban authored Nov 30, 2022
2 parents 5bee541 + 550c0c3 commit 8dff549
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 17 deletions.
11 changes: 9 additions & 2 deletions engine/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,13 @@ func renamedCopy(t Term, copied map[termID]Term, env *Env) Term {
l[i] = renamedCopy(t[i], copied, env)
}
return l
case *partial:
var p partial
copied[id(t)] = &p
p.Compound = renamedCopy(t.Compound, copied, env).(Compound)
tail := renamedCopy(*t.tail, copied, env)
p.tail = &tail
return &p
case Compound:
c := compound{
functor: t.Functor(),
Expand Down Expand Up @@ -2849,9 +2856,9 @@ func Append(vm *VM, xs, ys, zs Term, k Cont, env *Env) *Promise {
for iter.Next() {
}
if err := iter.Err(); err == nil {
return Unify(vm, zs, partial{
return Unify(vm, zs, &partial{
Compound: xs,
tail: ys,
tail: &ys,
}, k, env)
}
}
Expand Down
4 changes: 2 additions & 2 deletions engine/clause.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ func (c *clause) compileArg(a Term, env *Env) {
c.compileArg(arg, env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
case partial:
case *partial:
prefix := a.Compound.(list)
c.bytecode = append(c.bytecode, instruction{opcode: opPartial, operand: c.xrOffset(Integer(len(prefix)))})
c.compileArg(a.tail, env)
c.compileArg(*a.tail, env)
for _, arg := range prefix {
c.compileArg(arg, env)
}
Expand Down
20 changes: 10 additions & 10 deletions engine/compound.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,43 +102,43 @@ func List(ts ...Term) Term {

type partial struct {
Compound
tail Term
tail *Term
}

func (p partial) termID() termID { // The underlying compound might not be comparable.
func (p *partial) termID() termID { // The underlying compound might not be comparable.
type partialID struct {
prefixID, tailID termID
}
return partialID{
prefixID: id(p.Compound),
tailID: id(p.tail),
tailID: p.tail,
}
}

func (p partial) Arg(n int) Term {
func (p *partial) Arg(n int) Term {
t := p.Compound.Arg(n)
if c := p.Compound; c.Functor() == atomDot && c.Arity() == 2 && n == 1 {
if t == atomEmptyList {
t = p.tail
t = *p.tail
} else {
t = partial{Compound: t.(Compound), tail: p.tail}
t = &partial{Compound: t.(Compound), tail: p.tail}
}
}
return t
}

func (p partial) GoString() string {
return fmt.Sprintf(`engine.partial{Compound:%#v, tail:%#v}`, p.Compound, p.tail)
func (p *partial) GoString() string {
return fmt.Sprintf(`engine.partial{Compound:%#v, tail:%#v}`, p.Compound, *p.tail)
}

// PartialList returns a list of ts followed by tail.
func PartialList(tail Term, ts ...Term) Term {
if len(ts) == 0 {
return tail
}
return partial{
return &partial{
Compound: list(ts),
tail: tail,
tail: &tail,
}
}

Expand Down
4 changes: 2 additions & 2 deletions engine/compound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func TestList(t *testing.T) {
}

func TestPartialList(t *testing.T) {
x := NewVariable()
x := Term(NewVariable())

tests := []struct {
title string
Expand All @@ -51,7 +51,7 @@ func TestPartialList(t *testing.T) {
list Term
}{
{title: "empty", rest: x, elems: nil, list: x},
{title: "non-empty", rest: x, elems: []Term{NewAtom("a"), NewAtom("b")}, list: partial{Compound: list{NewAtom("a"), NewAtom("b")}, tail: x}},
{title: "non-empty", rest: x, elems: []Term{NewAtom("a"), NewAtom("b")}, list: &partial{Compound: list{NewAtom("a"), NewAtom("b")}, tail: &x}},
}

for _, tt := range tests {
Expand Down
7 changes: 7 additions & 0 deletions engine/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,13 @@ func simplify(t Term, simplified map[termID]Compound, env *Env) Term {
l[i] = simplify(e, simplified, env)
}
return l
case *partial:
var p partial
simplified[id(t)] = &p
p.Compound = simplify(t.Compound, simplified, env).(Compound)
tail := simplify(*t.tail, simplified, env)
p.tail = &tail
return &p
case Compound:
c := compound{
functor: t.Functor(),
Expand Down
2 changes: 1 addition & 1 deletion engine/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func TestEnv_Simplify(t *testing.T) {
assert.True(t, iter.Next())
assert.Equal(t, NewAtom("b"), iter.Current())
assert.False(t, iter.Next())
suffix, ok := iter.Suffix().(Compound)
suffix, ok := iter.Suffix().(*partial)
assert.True(t, ok)
assert.Equal(t, atomDot, suffix.Functor())
assert.Equal(t, 2, suffix.Arity())
Expand Down

0 comments on commit 8dff549

Please sign in to comment.