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

     1  package runtime
     2  
     3  import "unsafe"
     4  
     5  // Termination is a 'dead-end' continuation: it cannot be run.
     6  type Termination struct {
     7  	parent    Cont
     8  	args      []Value
     9  	pushIndex int
    10  	etc       *[]Value
    11  }
    12  
    13  var _ Cont = (*Termination)(nil)
    14  
    15  // NewTermination returns a new pointer to Termination where the first len(args)
    16  // values will be pushed into args and the remaining ones will be added to etc
    17  // if it is non nil, dropped otherwise.
    18  func NewTermination(parent Cont, args []Value, etc *[]Value) *Termination {
    19  	return &Termination{parent: parent, args: args, etc: etc}
    20  }
    21  
    22  // NewTerminationWith creates a new Termination expecting nArgs args and
    23  // possibly gathering extra args into an etc if hasEtc is true.
    24  func NewTerminationWith(parent Cont, nArgs int, hasEtc bool) *Termination {
    25  	var args []Value
    26  	var etc *[]Value
    27  	if nArgs > 0 {
    28  		args = make([]Value, nArgs)
    29  	}
    30  	if hasEtc {
    31  		etc = new([]Value)
    32  	}
    33  	return NewTermination(parent, args, etc)
    34  }
    35  
    36  // Push implements Cont.Push.  It just accumulates values into
    37  // a slice.
    38  func (c *Termination) Push(r *Runtime, v Value) {
    39  	if c.pushIndex < len(c.args) {
    40  		c.args[c.pushIndex] = v
    41  		c.pushIndex++
    42  	} else if c.etc != nil {
    43  		r.RequireSize(unsafe.Sizeof(Value{}))
    44  		*c.etc = append(*c.etc, v)
    45  	}
    46  }
    47  
    48  // PushEtc implements Cont.PushEtc.
    49  func (c *Termination) PushEtc(r *Runtime, etc []Value) {
    50  	if c.pushIndex < len(c.args) {
    51  		for i, v := range etc {
    52  			c.args[c.pushIndex] = v
    53  			c.pushIndex++
    54  			if c.pushIndex == len(c.args) {
    55  				etc = etc[i+1:]
    56  				goto FillEtc
    57  			}
    58  		}
    59  		return
    60  	}
    61  FillEtc:
    62  	if c.etc == nil {
    63  		return
    64  	}
    65  	r.RequireArrSize(unsafe.Sizeof(Value{}), len(etc))
    66  	*c.etc = append(*c.etc, etc...)
    67  }
    68  
    69  // RunInThread implements Cont.RunInThread. A termination exits
    70  // immediately so it always returns nil.
    71  func (c *Termination) RunInThread(t *Thread) (Cont, error) {
    72  	return nil, nil
    73  }
    74  
    75  // Next implmements Cont.Next.
    76  func (c *Termination) Next() Cont {
    77  	return nil
    78  }
    79  
    80  func (c *Termination) Parent() Cont {
    81  	if c.parent == nil {
    82  		return nil
    83  	}
    84  	return c.parent.Parent()
    85  }
    86  
    87  // DebugInfo implements Cont.DebugInfo.
    88  func (c *Termination) DebugInfo() *DebugInfo {
    89  	if c.parent == nil {
    90  		return nil
    91  	}
    92  	return c.parent.DebugInfo()
    93  }
    94  
    95  // Get returns the n-th arg pushed to the termination.
    96  func (c *Termination) Get(n int) Value {
    97  	if n >= c.pushIndex {
    98  		return NilValue
    99  	}
   100  	return c.args[n]
   101  }
   102  
   103  // Etc returns all the extra args pushed to the termination.
   104  func (c *Termination) Etc() []Value {
   105  	if c.etc == nil {
   106  		return nil
   107  	}
   108  	return *c.etc
   109  }
   110  
   111  // Reset erases all the args pushed to the termination.
   112  func (c *Termination) Reset() {
   113  	c.pushIndex = 0
   114  	if c.etc != nil {
   115  		c.etc = new([]Value)
   116  	}
   117  }