123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909 |
- package zygo
- import (
- "errors"
- "fmt"
- )
- type Instruction interface {
- InstrString() string
- Execute(env *Zlisp) error
- }
- type JumpInstr struct {
- addpc int
- where string
- }
- var OutOfBounds error = errors.New("jump out of bounds")
- func (j JumpInstr) InstrString() string {
- return fmt.Sprintf("jump %d %s", j.addpc, j.where)
- }
- func (j JumpInstr) Execute(env *Zlisp) error {
- newpc := env.pc + j.addpc
- if newpc < 0 || newpc > env.CurrentFunctionSize() {
- return OutOfBounds
- }
- env.pc = newpc
- return nil
- }
- type GotoInstr struct {
- location int
- }
- func (g GotoInstr) InstrString() string {
- return fmt.Sprintf("goto %d", g.location)
- }
- func (g GotoInstr) Execute(env *Zlisp) error {
- if g.location < 0 || g.location > env.CurrentFunctionSize() {
- return OutOfBounds
- }
- env.pc = g.location
- return nil
- }
- type BranchInstr struct {
- direction bool
- location int
- }
- func (b BranchInstr) InstrString() string {
- var format string
- if b.direction {
- format = "br %d"
- } else {
- format = "brn %d"
- }
- return fmt.Sprintf(format, b.location)
- }
- func (b BranchInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- if b.direction == IsTruthy(expr) {
- return JumpInstr{addpc: b.location}.Execute(env)
- }
- env.pc++
- return nil
- }
- type PushInstr struct {
- expr Sexp
- }
- func (p PushInstr) InstrString() string {
- return "push " + p.expr.SexpString(nil)
- }
- func (p PushInstr) Execute(env *Zlisp) error {
- env.datastack.PushExpr(p.expr)
- env.pc++
- return nil
- }
- type PopInstr int
- func (p PopInstr) InstrString() string {
- return "pop"
- }
- func (p PopInstr) Execute(env *Zlisp) error {
- _, err := env.datastack.PopExpr()
- env.pc++
- return err
- }
- type DupInstr int
- func (d DupInstr) InstrString() string {
- return "dup"
- }
- func (d DupInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.GetExpr(0)
- if err != nil {
- return err
- }
- env.datastack.PushExpr(expr)
- env.pc++
- return nil
- }
- type EnvToStackInstr struct {
- sym *SexpSymbol
- }
- func (g EnvToStackInstr) InstrString() string {
- return fmt.Sprintf("envToStack %s", g.sym.name)
- }
- func (g EnvToStackInstr) Execute(env *Zlisp) error {
- //VPrintf("in EnvToStackInstr\n")
- //defer VPrintf("leaving EnvToStackInstr env.pc =%v\n", env.pc)
- macxpr, isMacro := env.macros[g.sym.number]
- if isMacro {
- if macxpr.orig != nil {
- return fmt.Errorf("'%s' is a macro, with definition: %s\n", g.sym.name, macxpr.orig.SexpString(nil))
- }
- return fmt.Errorf("'%s' is a builtin macro.\n", g.sym.name)
- }
- var expr Sexp
- var err error
- expr, err, _ = env.LexicalLookupSymbol(g.sym, nil)
- if err != nil {
- return err
- }
- env.datastack.PushExpr(expr)
- env.pc++
- return nil
- }
- type PopStackPutEnvInstr struct {
- sym *SexpSymbol
- }
- func (p PopStackPutEnvInstr) InstrString() string {
- return fmt.Sprintf("popStackPutEnv %s", p.sym.name)
- }
- func (p PopStackPutEnvInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- env.pc++
- return env.LexicalBindSymbol(p.sym, expr)
- }
- // Update takes top of datastack and
- // assigns it to sym when sym is found
- // already in the current scope or
- // up the stack. Used
- // to implement (set v 10) when v is
- // not in the local scope.
- //
- type UpdateInstr struct {
- sym *SexpSymbol
- }
- func (p UpdateInstr) InstrString() string {
- return fmt.Sprintf("putup %s", p.sym.name)
- }
- func (p UpdateInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- env.pc++
- if p.sym.isSigil {
- Q("UpdateInstr: ignoring sigil symbol '%s'", p.sym.SexpString(nil))
- return nil
- }
- if p.sym.isDot {
- Q("UpdateInstr: dot symbol '%s' being updated with dotGetSetHelper()",
- p.sym.SexpString(nil))
- _, err := dotGetSetHelper(env, p.sym.name, &expr)
- return err
- }
- // if found up the stack, we will (set) expr
- _, err, _ = env.LexicalLookupSymbol(p.sym, &expr)
- if err != nil {
- // not found up the stack, so treat like (def)
- // instead of (set)
- return env.LexicalBindSymbol(p.sym, expr)
- }
- //return scope.UpdateSymbolInScope(p.sym, expr) // LexicalLookupSymbol now takes a setVal pointer which does this automatically
- return err
- }
- type CallInstr struct {
- sym *SexpSymbol
- nargs int
- }
- func (c CallInstr) InstrString() string {
- return fmt.Sprintf("call %s %d", c.sym.name, c.nargs)
- }
- func (c CallInstr) Execute(env *Zlisp) error {
- f, ok := env.builtins[c.sym.number]
- if ok {
- _, err := env.CallUserFunction(f, c.sym.name, c.nargs)
- return err
- }
- var funcobj, indirectFuncName Sexp
- var err error
- funcobj, err, _ = env.LexicalLookupSymbol(c.sym, nil)
- if err != nil {
- return err
- }
- //P("\n in CallInstr, after looking up c.sym='%s', got funcobj='%v'. datastack is:\n", c.sym.name, funcobj.SexpString(nil))
- //env.datastack.PrintStack()
- switch f := funcobj.(type) {
- case *SexpSymbol:
- // is it a dot-symbol call?
- //P("\n in CallInstr, found symbol\n")
- if c.sym.isDot {
- //P("\n in CallInstr, found symbol, c.sym.isDot is true\n")
- dotSymRef, dotLookupErr := dotGetSetHelper(env, c.sym.name, nil)
- // cannot error out yet, we might be assigning to a new field,
- // not already set.
- if dotLookupErr != nil {
- return dotLookupErr
- }
- // are we a value request (no further args), or a fuction/method call?
- //P("\n in CallInstr, found dot-symbol\n")
- // now always be a function call here, allowing zero-argument calls.
- indirectFuncName = dotSymRef
- } else {
- // not isDot
- // allow symbols to refer to dot-symbols, that then we call
- indirectFuncName, err = dotGetSetHelper(env, f.name, nil)
- if err != nil {
- return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
- c.sym.name, f.name, f.name, err)
- }
- // allow symbols to refer to functions that we then call
- /*
- indirectFuncName, err, _ = env.LexicalLookupSymbol(f, nil)
- if err != nil {
- return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
- c.sym.name, f.name, f.name, err)
- }
- */
- //P("\n in CallInstr, found symbol, c.sym.isDot is false. f of type %T/val = %v. indirectFuncName = '%v'\n", f, f.SexpString(nil), indirectFuncName.SexpString(nil))
- }
- //P("in CallInstr, reached switch on indirectFuncName.(type)")
- switch g := indirectFuncName.(type) {
- case *SexpFunction:
- if !g.user {
- return env.CallFunction(g, c.nargs)
- }
- _, err := env.CallUserFunction(g, f.name, c.nargs)
- return err
- default:
- if err != nil {
- return fmt.Errorf("symbol '%s' refers to '%s' which does not refer to a function.", c.sym.name, f.name)
- }
- }
- case *SexpFunction:
- if !f.user {
- return env.CallFunction(f, c.nargs)
- }
- _, err := env.CallUserFunction(f, c.sym.name, c.nargs)
- return err
- case *RegisteredType:
- if f.Constructor == nil {
- env.pc++
- res, err := baseConstruct(env, f, c.nargs)
- if err != nil {
- return err
- }
- env.datastack.PushExpr(res)
- return nil
- }
- //P("call instruction for RegisteredType!")
- _, err := env.CallUserFunction(f.Constructor, c.sym.name, c.nargs)
- return err
- }
- return fmt.Errorf("%s is not a function", c.sym.name)
- }
- type DispatchInstr struct {
- nargs int
- }
- func (d DispatchInstr) InstrString() string {
- return fmt.Sprintf("dispatch %d", d.nargs)
- }
- func (d DispatchInstr) Execute(env *Zlisp) error {
- funcobj, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- switch f := funcobj.(type) {
- case *SexpFunction:
- if !f.user {
- return env.CallFunction(f, d.nargs)
- }
- _, err := env.CallUserFunction(f, f.name, d.nargs)
- return err
- }
- // allow ([] int64) to express slice of int64.
- switch arr := funcobj.(type) {
- case *SexpArray:
- if len(arr.Val) == 0 {
- _, err := env.CallUserFunction(sxSliceOf, funcobj.SexpString(nil), d.nargs)
- return err
- }
- // call along with the array as an argument so we know the size of the
- // array / matrix / tensor to make. The 2nd argument will be the dimension array.
- env.datastack.PushExpr(arr)
- _, err := env.CallUserFunction(sxArrayOf, funcobj.SexpString(nil), d.nargs+1)
- return err
- }
- return fmt.Errorf("unbalanced parenthesis in the input? : not a function on top of datastack: '%T/%#v'", funcobj, funcobj)
- }
- type ReturnInstr struct {
- err error
- }
- func (r ReturnInstr) Execute(env *Zlisp) error {
- if r.err != nil {
- return r.err
- }
- return env.ReturnFromFunction()
- }
- func (r ReturnInstr) InstrString() string {
- if r.err == nil {
- return "ret"
- }
- return "ret \"" + r.err.Error() + "\""
- }
- type AddScopeInstr struct {
- Name string
- }
- func (a AddScopeInstr) InstrString() string {
- return "add scope " + a.Name
- }
- func (a AddScopeInstr) Execute(env *Zlisp) error {
- sc := env.NewNamedScope(fmt.Sprintf("scope Name: '%s'",
- a.Name))
- env.linearstack.Push(sc)
- env.pc++
- return nil
- }
- type AddFuncScopeInstr struct {
- Name string
- Helper *AddFuncScopeHelper // we need a pointer we can update later once we know MyFunction
- }
- type AddFuncScopeHelper struct {
- MyFunction *SexpFunction
- }
- func (a AddFuncScopeInstr) InstrString() string {
- return "add func scope " + a.Name
- }
- func (a AddFuncScopeInstr) Execute(env *Zlisp) error {
- sc := env.NewNamedScope(fmt.Sprintf("%s at pc=%v",
- env.curfunc.name, env.pc))
- sc.IsFunction = true
- sc.MyFunction = a.Helper.MyFunction
- env.linearstack.Push(sc)
- env.pc++
- return nil
- }
- type RemoveScopeInstr struct{}
- func (a RemoveScopeInstr) InstrString() string {
- return "rem runtime scope"
- }
- func (a RemoveScopeInstr) Execute(env *Zlisp) error {
- env.pc++
- return env.linearstack.PopScope()
- }
- type ExplodeInstr int
- func (e ExplodeInstr) InstrString() string {
- return "explode"
- }
- func (e ExplodeInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- arr, err := ListToArray(expr)
- if err != nil {
- return err
- }
- for _, val := range arr {
- env.datastack.PushExpr(val)
- }
- env.pc++
- return nil
- }
- type SquashInstr int
- func (s SquashInstr) InstrString() string {
- return "squash"
- }
- func (s SquashInstr) Execute(env *Zlisp) error {
- var list Sexp = SexpNull
- for {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- if expr == SexpMarker {
- break
- }
- list = Cons(expr, list)
- }
- env.datastack.PushExpr(list)
- env.pc++
- return nil
- }
- // bind these symbols to the SexpPair list found at
- // datastack top.
- type BindlistInstr struct {
- syms []*SexpSymbol
- }
- func (b BindlistInstr) InstrString() string {
- joined := ""
- for _, s := range b.syms {
- joined += s.name + " "
- }
- return fmt.Sprintf("bindlist %s", joined)
- }
- func (b BindlistInstr) Execute(env *Zlisp) error {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- arr, err := ListToArray(expr)
- if err != nil {
- return err
- }
- nsym := len(b.syms)
- narr := len(arr)
- if narr < nsym {
- return fmt.Errorf("bindlist failing: %d targets but only %d sources", nsym, narr)
- }
- for i, bindThisSym := range b.syms {
- env.LexicalBindSymbol(bindThisSym, arr[i])
- }
- env.pc++
- return nil
- }
- type VectorizeInstr int
- func (s VectorizeInstr) InstrString() string {
- return fmt.Sprintf("vectorize %v", int(s))
- }
- func (s VectorizeInstr) Execute(env *Zlisp) error {
- vec := make([]Sexp, 0)
- env.pc++
- for {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- if expr == SexpMarker {
- break
- }
- vec = append([]Sexp{expr}, vec...)
- }
- env.datastack.PushExpr(&SexpArray{Val: vec, Env: env})
- return nil
- }
- type HashizeInstr struct {
- HashLen int
- TypeName string
- }
- func (s HashizeInstr) InstrString() string {
- return "hashize"
- }
- func (s HashizeInstr) Execute(env *Zlisp) error {
- a := make([]Sexp, 0)
- for {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- if expr == SexpMarker {
- break
- }
- a = append(a, expr)
- }
- hash, err := MakeHash(a, s.TypeName, env)
- if err != nil {
- return err
- }
- env.datastack.PushExpr(hash)
- env.pc++
- return nil
- }
- type LabelInstr struct {
- label string
- }
- func (s LabelInstr) InstrString() string {
- return fmt.Sprintf("label %s", s.label)
- }
- func (s LabelInstr) Execute(env *Zlisp) error {
- env.pc++
- return nil
- }
- type BreakInstr struct {
- loop *Loop
- pos int
- }
- func (s BreakInstr) InstrString() string {
- if s.pos == 0 {
- return fmt.Sprintf("break %s", s.loop.stmtname.name)
- }
- return fmt.Sprintf("break %s (loop is at %d)", s.loop.stmtname.name, s.pos)
- }
- func (s *BreakInstr) Execute(env *Zlisp) error {
- if s.pos == 0 {
- pos, err := env.FindLoop(s.loop)
- if err != nil {
- return err
- }
- s.pos = pos
- }
- env.pc = s.pos + s.loop.breakOffset
- return nil
- }
- type ContinueInstr struct {
- loop *Loop
- pos int
- }
- func (s ContinueInstr) InstrString() string {
- if s.pos == 0 {
- return fmt.Sprintf("continue %s", s.loop.stmtname.name)
- }
- return fmt.Sprintf("continue %s (loop is at pos %d)", s.loop.stmtname.name, s.pos)
- }
- func (s *ContinueInstr) Execute(env *Zlisp) error {
- //VPrintf("\n executing ContinueInstr with loop: '%#v'\n", s.loop)
- if s.pos == 0 {
- pos, err := env.FindLoop(s.loop)
- if err != nil {
- return err
- }
- s.pos = pos
- }
- env.pc = s.pos + s.loop.continueOffset
- //VPrintf("\n more detail ContinueInstr pos=%d, setting pc = %d\n", s.pos, env.pc)
- return nil
- }
- type LoopStartInstr struct {
- loop *Loop
- }
- func (s LoopStartInstr) InstrString() string {
- return fmt.Sprintf("loopstart %s", s.loop.stmtname.name)
- }
- func (s LoopStartInstr) Execute(env *Zlisp) error {
- env.pc++
- return nil
- }
- // stack cleanup discipline instructions let us
- // ensure the stack gets reset to a previous
- // known good level. The sym designates
- // how far down to clean up, in a unique and
- // distinguishable gensym-ed manner.
- // create a stack mark
- type PushStackmarkInstr struct {
- sym *SexpSymbol
- }
- func (s PushStackmarkInstr) InstrString() string {
- return fmt.Sprintf("push-stack-mark %s", s.sym.name)
- }
- func (s PushStackmarkInstr) Execute(env *Zlisp) error {
- env.datastack.PushExpr(&SexpStackmark{sym: s.sym})
- env.pc++
- return nil
- }
- // cleanup until our stackmark, but leave it in place
- type PopUntilStackmarkInstr struct {
- sym *SexpSymbol
- }
- func (s PopUntilStackmarkInstr) InstrString() string {
- return fmt.Sprintf("pop-until-stack-mark %s", s.sym.name)
- }
- func (s PopUntilStackmarkInstr) Execute(env *Zlisp) error {
- env.pc++
- toploop:
- for {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- P("alert: did not find SexpStackmark '%s'", s.sym.name)
- return err
- }
- switch m := expr.(type) {
- case *SexpStackmark:
- if m.sym.number == s.sym.number {
- env.datastack.PushExpr(m)
- break toploop
- }
- }
- }
- return nil
- }
- // erase everything up-to-and-including our mark
- type ClearStackmarkInstr struct {
- sym *SexpSymbol
- }
- func (s ClearStackmarkInstr) InstrString() string {
- return fmt.Sprintf("clear-stack-mark %s", s.sym.name)
- }
- func (s ClearStackmarkInstr) Execute(env *Zlisp) error {
- toploop:
- for {
- expr, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- switch m := expr.(type) {
- case *SexpStackmark:
- if m.sym.number == s.sym.number {
- break toploop
- }
- }
- }
- env.pc++
- return nil
- }
- type DebugInstr struct {
- diagnostic string
- }
- func (g DebugInstr) InstrString() string {
- return fmt.Sprintf("debug %s", g.diagnostic)
- }
- func (g DebugInstr) Execute(env *Zlisp) error {
- switch g.diagnostic {
- case "showScopes":
- err := env.ShowStackStackAndScopeStack()
- if err != nil {
- return err
- }
- default:
- panic(fmt.Errorf("unknown diagnostic %v", g.diagnostic))
- }
- env.pc++
- return nil
- }
- // when a defn or fn executes, capture the creation env.
- type CreateClosureInstr struct {
- sfun *SexpFunction
- }
- func (a CreateClosureInstr) InstrString() string {
- return "create closure " + a.sfun.SexpString(nil)
- }
- func (a CreateClosureInstr) Execute(env *Zlisp) error {
- env.pc++
- cls := NewClosing(a.sfun.name, env)
- myInvok := a.sfun.Copy()
- myInvok.SetClosing(cls)
- if env.curfunc != nil {
- a.sfun.parent = env.curfunc
- myInvok.parent = env.curfunc
- //P("myInvok is copy of a.sfun '%s' with parent = %s", a.sfun.name, myInvok.parent.name)
- }
- ps8 := NewPrintStateWithIndent(8)
- shown, err := myInvok.ShowClosing(env, ps8, fmt.Sprintf("closedOverScopes of '%s'", myInvok.name))
- _ = shown
- if err != nil {
- return err
- }
- //VPrintf("+++ CreateClosure: assign to '%s' the stack:\n\n%s\n\n", myInvok.SexpString(nil), shown)
- top := cls.TopScope()
- //VPrintf("222 CreateClosure: top of NewClosing Scope has addr %p and is\n", top)
- top.Show(env, ps8, fmt.Sprintf("top of NewClosing at %p", top))
- env.datastack.PushExpr(myInvok)
- return nil
- }
- type AssignInstr struct {
- }
- func (a AssignInstr) InstrString() string {
- return "assign stack top to stack top -1"
- }
- func (a AssignInstr) Execute(env *Zlisp) error {
- env.pc++
- rhs, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- lhs, err := env.datastack.PopExpr()
- if err != nil {
- return err
- }
- switch x := lhs.(type) {
- case *SexpSymbol:
- return env.LexicalBindSymbol(x, rhs)
- case Selector:
- Q("AssignInstr: I see lhs is Selector")
- err := x.AssignToSelection(env, rhs)
- return err
- case *SexpArray:
- switch rhsArray := rhs.(type) {
- case *SexpArray:
- //Q("AssignInstr: lhs is SexpArray '%v', *and* rhs is SexpArray ='%v'",
- // x.SexpString(nil), rhsArray.SexpString(nil))
- nRhs := len(rhsArray.Val)
- nLhs := len(x.Val)
- if nRhs != nLhs {
- return fmt.Errorf("assignment count mismatch %v != %v", nLhs, nRhs)
- }
- for i := range x.Val {
- switch sym := x.Val[i].(type) {
- case *SexpSymbol:
- err = env.LexicalBindSymbol(sym, rhsArray.Val[i])
- if err != nil {
- return err
- }
- default:
- return fmt.Errorf("assignment error: left-hand-side element %v needs to be a symbol but"+
- " we found %T", i, x.Val[i])
- }
- }
- return nil
- default:
- return fmt.Errorf("AssignInstr: don't know how to assign rhs %T `%v` to lhs %T `%v`",
- rhs, rhs.SexpString(nil), lhs, lhs.SexpString(nil))
- }
- }
- return fmt.Errorf("AssignInstr: don't know how to assign to lhs %T", lhs)
- }
- // PopScopeTransferToDataStackInstr is used to wrap up a package
- // and put it on the data stack as a value.
- type PopScopeTransferToDataStackInstr struct {
- PackageName string
- }
- func (a PopScopeTransferToDataStackInstr) InstrString() string {
- return "pop scope transfer to data stack as package " + a.PackageName
- }
- func (a PopScopeTransferToDataStackInstr) Execute(env *Zlisp) error {
- env.pc++
- stackClone := env.linearstack.Clone()
- stackClone.IsPackage = true // always/only used for packages.
- stackClone.PackageName = a.PackageName
- //P("PopScopeTransferToDataStackInstr: scope is '%v'", stackClone.SexpString(nil))
- env.linearstack.PopScope()
- env.datastack.PushExpr(stackClone)
- return nil
- }
- type PrepareCallInstr struct {
- sym *SexpSymbol
- nargs int
- }
- func (c PrepareCallInstr) InstrString() string {
- return fmt.Sprintf("pre-call %s %d", c.sym.name, c.nargs)
- }
- func (c PrepareCallInstr) Execute(env *Zlisp) error {
- if err := c.execute(env); err != nil {
- return err
- }
- env.pc++
- return nil
- }
- func (c PrepareCallInstr) execute(env *Zlisp) error {
- _, ok := env.builtins[c.sym.number]
- if ok {
- return nil
- }
- var funcobj, indirectFuncName Sexp
- var err error
- funcobj, err, _ = env.LexicalLookupSymbol(c.sym, nil)
- if err != nil {
- return err
- }
- switch f := funcobj.(type) {
- case *SexpSymbol:
- if c.sym.isDot {
- dotSymRef, dotLookupErr := dotGetSetHelper(env, c.sym.name, nil)
- if dotLookupErr != nil {
- return dotLookupErr
- }
- indirectFuncName = dotSymRef
- } else {
- indirectFuncName, err = dotGetSetHelper(env, f.name, nil)
- if err != nil {
- return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
- c.sym.name, f.name, f.name, err)
- }
- }
- switch g := indirectFuncName.(type) {
- case *SexpFunction:
- if !g.user && g.varargs {
- return env.wrangleOptargs(g.nargs, c.nargs)
- }
- return nil
- }
- case *SexpFunction:
- if !f.user && f.varargs {
- return env.wrangleOptargs(f.nargs, c.nargs)
- }
- }
- return nil
- }
|