Skip to content

Commit

Permalink
Merge pull request #8 from axone-protocol/feat/vm-hooks
Browse files Browse the repository at this point in the history
Add support for hooks in bytecode execution
  • Loading branch information
ccamel authored Sep 24, 2024
2 parents ea00e9b + c6a535a commit 53584b2
Show file tree
Hide file tree
Showing 6 changed files with 308 additions and 155 deletions.
41 changes: 21 additions & 20 deletions engine/builtin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ import (
"context"
"errors"
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
orderedmap "github.com/wk8/go-ordered-map/v2"
"io"
"math"
"os"
Expand All @@ -16,6 +13,10 @@ import (
"strings"
"testing"
"unicode/utf8"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
orderedmap "github.com/wk8/go-ordered-map/v2"
)

type procedurePair orderedmap.Pair[procedureIndicator, procedure]
Expand Down Expand Up @@ -2709,8 +2710,8 @@ func TestAssertz(t *testing.T) {
args: []Term{NewAtom("a")},
},
bytecode: bytecode{
{opcode: opGetConst, operand: NewAtom("a")},
{opcode: opExit},
{opcode: OpGetConst, operand: NewAtom("a")},
{opcode: OpExit},
},
},
{
Expand All @@ -2723,8 +2724,8 @@ func TestAssertz(t *testing.T) {
args: []Term{NewAtom("b")},
},
bytecode: bytecode{
{opcode: opGetConst, operand: NewAtom("b")},
{opcode: opExit},
{opcode: OpGetConst, operand: NewAtom("b")},
{opcode: OpExit},
},
},
}}, vm.procedures.GetPair(procedureIndicator{
Expand Down Expand Up @@ -2839,8 +2840,8 @@ func TestAsserta(t *testing.T) {
args: []Term{NewAtom("b")},
},
bytecode: bytecode{
{opcode: opGetConst, operand: NewAtom("b")},
{opcode: opExit},
{opcode: OpGetConst, operand: NewAtom("b")},
{opcode: OpExit},
},
},
{
Expand All @@ -2850,8 +2851,8 @@ func TestAsserta(t *testing.T) {
args: []Term{NewAtom("a")},
},
bytecode: bytecode{
{opcode: opGetConst, operand: NewAtom("a")},
{opcode: opExit},
{opcode: OpGetConst, operand: NewAtom("a")},
{opcode: OpExit},
},
},
}}, vm.procedures.GetPair(procedureIndicator{name: NewAtom("foo"), arity: 1}).Value)
Expand Down Expand Up @@ -2902,11 +2903,11 @@ func TestAsserta(t *testing.T) {
},
},
bytecode: bytecode{
{opcode: opEnter},
{opcode: opPutConst, operand: NewAtom("a")},
{opcode: opCall, operand: procedureIndicator{name: NewAtom("p"), arity: 1}},
{opcode: opCut},
{opcode: opExit},
{opcode: OpEnter},
{opcode: OpPutConst, operand: NewAtom("a")},
{opcode: OpCall, operand: procedureIndicator{name: NewAtom("p"), arity: 1}},
{opcode: OpCut},
{opcode: OpExit},
},
},
{
Expand All @@ -2922,10 +2923,10 @@ func TestAsserta(t *testing.T) {
},
},
bytecode: bytecode{
{opcode: opEnter},
{opcode: opPutConst, operand: NewAtom("b")},
{opcode: opCall, operand: procedureIndicator{name: NewAtom("p"), arity: 1}},
{opcode: opExit},
{opcode: OpEnter},
{opcode: OpPutConst, operand: NewAtom("b")},
{opcode: OpCall, operand: procedureIndicator{name: NewAtom("p"), arity: 1}},
{opcode: OpExit},
},
},
}}, vm.procedures.GetPair(procedureIndicator{name: NewAtom("foo"), arity: 0}).Value)
Expand Down
46 changes: 23 additions & 23 deletions engine/clause.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func compileClause(head Term, body Term, env *Env) (clause, error) {
return c, typeError(validTypeCallable, body, env)
}
}
c.bytecode = append(c.bytecode, instruction{opcode: opExit})
c.bytecode = append(c.bytecode, instruction{opcode: OpExit})
return c, nil
}

Expand All @@ -88,7 +88,7 @@ func (c *clause) compileHead(head Term, env *Env) {
}

func (c *clause) compileBody(body Term, env *Env) error {
c.bytecode = append(c.bytecode, instruction{opcode: opEnter})
c.bytecode = append(c.bytecode, instruction{opcode: OpEnter})
iter := seqIterator{Seq: body, Env: env}
for iter.Next() {
if err := c.compilePred(iter.Current(), env); err != nil {
Expand All @@ -107,16 +107,16 @@ func (c *clause) compilePred(p Term, env *Env) error {
case Atom:
switch p {
case atomCut:
c.bytecode = append(c.bytecode, instruction{opcode: opCut})
c.bytecode = append(c.bytecode, instruction{opcode: OpCut})
return nil
}
c.bytecode = append(c.bytecode, instruction{opcode: opCall, operand: procedureIndicator{name: p, arity: 0}})
c.bytecode = append(c.bytecode, instruction{opcode: OpCall, operand: procedureIndicator{name: p, arity: 0}})
return nil
case Compound:
for i := 0; i < p.Arity(); i++ {
c.compileBodyArg(p.Arg(i), env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opCall, operand: procedureIndicator{name: p.Functor(), arity: Integer(p.Arity())}})
c.bytecode = append(c.bytecode, instruction{opcode: OpCall, operand: procedureIndicator{name: p.Functor(), arity: Integer(p.Arity())}})
return nil
default:
return errNotCallable
Expand All @@ -126,67 +126,67 @@ func (c *clause) compilePred(p Term, env *Env) error {
func (c *clause) compileHeadArg(a Term, env *Env) {
switch a := env.Resolve(a).(type) {
case Variable:
c.bytecode = append(c.bytecode, instruction{opcode: opGetVar, operand: c.varOffset(a)})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetVar, operand: c.varOffset(a)})
case charList, codeList: // Treat them as if they're atomic.
c.bytecode = append(c.bytecode, instruction{opcode: opGetConst, operand: a})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetConst, operand: a})
case list:
c.bytecode = append(c.bytecode, instruction{opcode: opGetList, operand: Integer(len(a))})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetList, operand: Integer(len(a))})
for _, arg := range a {
c.compileHeadArg(arg, env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
case *partial:
prefix := a.Compound.(list)
c.bytecode = append(c.bytecode, instruction{opcode: opGetPartial, operand: Integer(len(prefix))})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetPartial, operand: Integer(len(prefix))})
c.compileHeadArg(*a.tail, env)
for _, arg := range prefix {
c.compileHeadArg(arg, env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
case Compound:
c.bytecode = append(c.bytecode, instruction{opcode: opGetFunctor, operand: procedureIndicator{name: a.Functor(), arity: Integer(a.Arity())}})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetFunctor, operand: procedureIndicator{name: a.Functor(), arity: Integer(a.Arity())}})
for i := 0; i < a.Arity(); i++ {
c.compileHeadArg(a.Arg(i), env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
default:
c.bytecode = append(c.bytecode, instruction{opcode: opGetConst, operand: a})
c.bytecode = append(c.bytecode, instruction{opcode: OpGetConst, operand: a})
}
}

func (c *clause) compileBodyArg(a Term, env *Env) {
switch a := env.Resolve(a).(type) {
case Variable:
c.bytecode = append(c.bytecode, instruction{opcode: opPutVar, operand: c.varOffset(a)})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutVar, operand: c.varOffset(a)})
case charList, codeList: // Treat them as if they're atomic.
c.bytecode = append(c.bytecode, instruction{opcode: opPutConst, operand: a})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutConst, operand: a})
case list:
c.bytecode = append(c.bytecode, instruction{opcode: opPutList, operand: Integer(len(a))})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutList, operand: Integer(len(a))})
for _, arg := range a {
c.compileBodyArg(arg, env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
case *partial:
var l int
iter := ListIterator{List: a.Compound}
for iter.Next() {
l++
}
c.bytecode = append(c.bytecode, instruction{opcode: opPutPartial, operand: Integer(l)})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutPartial, operand: Integer(l)})
c.compileBodyArg(*a.tail, env)
iter = ListIterator{List: a.Compound}
for iter.Next() {
c.compileBodyArg(iter.Current(), env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
case Compound:
c.bytecode = append(c.bytecode, instruction{opcode: opPutFunctor, operand: procedureIndicator{name: a.Functor(), arity: Integer(a.Arity())}})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutFunctor, operand: procedureIndicator{name: a.Functor(), arity: Integer(a.Arity())}})
for i := 0; i < a.Arity(); i++ {
c.compileBodyArg(a.Arg(i), env)
}
c.bytecode = append(c.bytecode, instruction{opcode: opPop})
c.bytecode = append(c.bytecode, instruction{opcode: OpPop})
default:
c.bytecode = append(c.bytecode, instruction{opcode: opPutConst, operand: a})
c.bytecode = append(c.bytecode, instruction{opcode: OpPutConst, operand: a})
}
}

Expand Down
Loading

0 comments on commit 53584b2

Please sign in to comment.