github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/cont.go (about)

     1  package runtime
     2  
     3  import (
     4  	"os"
     5  	"syscall"
     6  )
     7  
     8  // Cont is an interface for things that can be run in a Thread.  Implementations
     9  // of Cont a typically an invocation of a Lua function or an invocation of a Go
    10  // function.
    11  type Cont interface {
    12  
    13  	// Push "pushes" a Value to the continuation (arguments before a call, or
    14  	// before resuming a continuation which has been suspended via "yield").  This is to
    15  	// pass arguments to the continuation before calling RunInThread.
    16  	Push(*Runtime, Value)
    17  
    18  	// PushEtc "pushes" varargs to the continutation, this happens e.g. in Lua
    19  	// code when running "f(...)".
    20  	PushEtc(*Runtime, []Value)
    21  
    22  	// RunInThread runs the continuation in the given thread, returning either
    23  	// the next continuation to be run or an error.
    24  	RunInThread(*Thread) (Cont, error)
    25  
    26  	// Next() returns the continuation that follows after this one (could be
    27  	// e.g. the caller).
    28  	Next() Cont
    29  
    30  	// Parent() returns the continuation that initiated this continuation.  It
    31  	// can be the same as Next() but not necessarily.  This is useful for giving
    32  	// meaningful tracebacks, not used by the runtime engine.
    33  	Parent() Cont
    34  
    35  	// DebugInfo() returns debug info for the continuation.  Used for building
    36  	// error messages and tracebacks.
    37  	DebugInfo() *DebugInfo
    38  }
    39  
    40  // Push is a convenience method that pushes a number of values to the
    41  // continuation c.
    42  func (r *Runtime) Push(c Cont, vals ...Value) {
    43  	for _, v := range vals {
    44  		c.Push(r, v)
    45  	}
    46  }
    47  
    48  // Push1 is a convenience method that pushes v to the continuation c.
    49  func (r *Runtime) Push1(c Cont, v Value) {
    50  	c.Push(r, v)
    51  }
    52  
    53  // PushIoError is a convenience method that translates ioErr to a value if
    54  // appropriated and pushes that value to c, else returns an error.  It is useful
    55  // because a number of Go IO errors are considered regular return values by Lua.
    56  func (r *Runtime) PushIoError(c Cont, ioErr error) error {
    57  	// It is not specified in the Lua docs, but the test suite expects an
    58  	// errno as the third value returned in case of an error.  I'm not sure
    59  	// the conversion to syscall.Errno is future-proof though?
    60  
    61  	var err error
    62  	switch tErr := ioErr.(type) {
    63  	case *os.PathError:
    64  		err = tErr.Unwrap()
    65  	case *os.LinkError:
    66  		err = tErr.Unwrap()
    67  	default:
    68  		return ioErr
    69  	}
    70  	r.Push1(c, NilValue)
    71  	r.Push1(c, StringValue(ioErr.Error()))
    72  	if errno, ok := err.(syscall.Errno); ok {
    73  		r.Push1(c, IntValue(int64(errno)))
    74  	}
    75  	return nil
    76  }
    77  
    78  // ProcessIoError is like PushIoError but its signature makes it convenient to
    79  // use in a return statement from a GoFunc implementation.
    80  func (r *Runtime) ProcessIoError(c Cont, ioErr error) (Cont, error) {
    81  	if err := r.PushIoError(c, ioErr); err != nil {
    82  		return nil, err
    83  	}
    84  	return c, nil
    85  }