github.com/rhettli/gopher-lua@v0.0.0-20200830072439-712e2f816099/function.go (about)

     1  package lua
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  const (
     9  	VarArgHasArg   uint8 = 1
    10  	VarArgIsVarArg uint8 = 2
    11  	VarArgNeedsArg uint8 = 4
    12  )
    13  
    14  type DbgLocalInfo struct {
    15  	Name    string
    16  	StartPc int
    17  	EndPc   int
    18  }
    19  
    20  type DbgCall struct {
    21  	Name string
    22  	Pc   int
    23  }
    24  
    25  type FunctionProto struct {
    26  	SourceName         string
    27  	LineDefined        int
    28  	LastLineDefined    int
    29  	NumUpvalues        uint8
    30  	NumParameters      uint8
    31  	IsVarArg           uint8
    32  	NumUsedRegisters   uint8
    33  	Code               []uint32
    34  	Constants          []LValue
    35  	FunctionPrototypes []*FunctionProto
    36  
    37  	DbgSourcePositions []int
    38  	DbgLocals          []*DbgLocalInfo
    39  	DbgCalls           []DbgCall
    40  	DbgUpvalues        []string
    41  
    42  	stringConstants []string
    43  }
    44  
    45  /* Upvalue {{{ */
    46  
    47  type Upvalue struct {
    48  	next   *Upvalue
    49  	reg    *registry
    50  	index  int
    51  	value  LValue
    52  	closed bool
    53  }
    54  
    55  func (uv *Upvalue) Value() LValue {
    56  	//if uv.IsClosed() {
    57  	if uv.closed || uv.reg == nil {
    58  		return uv.value
    59  	}
    60  	//return uv.reg.Get(uv.index)
    61  	return uv.reg.array[uv.index]
    62  }
    63  
    64  func (uv *Upvalue) SetValue(value LValue) {
    65  	if uv.IsClosed() {
    66  		uv.value = value
    67  	} else {
    68  		uv.reg.Set(uv.index, value)
    69  	}
    70  }
    71  
    72  func (uv *Upvalue) Close() {
    73  	value := uv.Value()
    74  	uv.closed = true
    75  	uv.value = value
    76  }
    77  
    78  func (uv *Upvalue) IsClosed() bool {
    79  	return uv.closed || uv.reg == nil
    80  }
    81  
    82  func UpvalueIndex(i int) int {
    83  	return GlobalsIndex - i
    84  }
    85  
    86  /* }}} */
    87  
    88  /* FunctionProto {{{ */
    89  
    90  func newFunctionProto(name string) *FunctionProto {
    91  	return &FunctionProto{
    92  		SourceName:         name,
    93  		LineDefined:        0,
    94  		LastLineDefined:    0,
    95  		NumUpvalues:        0,
    96  		NumParameters:      0,
    97  		IsVarArg:           0,
    98  		NumUsedRegisters:   2,
    99  		Code:               make([]uint32, 0, 128),
   100  		Constants:          make([]LValue, 0, 32),
   101  		FunctionPrototypes: make([]*FunctionProto, 0, 16),
   102  
   103  		DbgSourcePositions: make([]int, 0, 128),
   104  		DbgLocals:          make([]*DbgLocalInfo, 0, 16),
   105  		DbgCalls:           make([]DbgCall, 0, 128),
   106  		DbgUpvalues:        make([]string, 0, 16),
   107  
   108  		stringConstants: make([]string, 0, 32),
   109  	}
   110  }
   111  
   112  func (fp *FunctionProto) String() string {
   113  	return fp.str(1, 0)
   114  }
   115  
   116  func (fp *FunctionProto) str(level int, count int) string {
   117  	indent := strings.Repeat("  ", level-1)
   118  	buf := []string{}
   119  	buf = append(buf, fmt.Sprintf("%v; function [%v] definition (level %v)\n",
   120  		indent, count, level))
   121  	buf = append(buf, fmt.Sprintf("%v; %v upvalues, %v params, %v stacks\n",
   122  		indent, fp.NumUpvalues, fp.NumParameters, fp.NumUsedRegisters))
   123  	for reg, linfo := range fp.DbgLocals {
   124  		buf = append(buf, fmt.Sprintf("%v.local %v ; %v\n", indent, linfo.Name, reg))
   125  	}
   126  	for reg, upvalue := range fp.DbgUpvalues {
   127  		buf = append(buf, fmt.Sprintf("%v.upvalue %v ; %v\n", indent, upvalue, reg))
   128  	}
   129  	for reg, conzt := range fp.Constants {
   130  		buf = append(buf, fmt.Sprintf("%v.const %v ; %v\n", indent, conzt.String(), reg))
   131  	}
   132  	buf = append(buf, "\n")
   133  
   134  	protono := 0
   135  	for no, code := range fp.Code {
   136  		inst := opGetOpCode(code)
   137  		if inst == OP_CLOSURE {
   138  			buf = append(buf, "\n")
   139  			buf = append(buf, fp.FunctionPrototypes[protono].str(level+1, protono))
   140  			buf = append(buf, "\n")
   141  			protono++
   142  		}
   143  		buf = append(buf, fmt.Sprintf("%v[%03d] %v (line:%v)\n",
   144  			indent, no+1, opToString(code), fp.DbgSourcePositions[no]))
   145  
   146  	}
   147  	buf = append(buf, fmt.Sprintf("%v; end of function\n", indent))
   148  	return strings.Join(buf, "")
   149  }
   150  
   151  /* }}} */
   152  
   153  /* LFunction {{{ */
   154  
   155  func newLFunctionL(proto *FunctionProto, env *LTable, nupvalue int) *LFunction {
   156  	return &LFunction{
   157  		IsG: false,
   158  		Env: env,
   159  
   160  		Proto:     proto,
   161  		GFunction: nil,
   162  		Upvalues:  make([]*Upvalue, nupvalue),
   163  	}
   164  }
   165  
   166  func newLFunctionG(gfunc LGFunction, env *LTable, nupvalue int) *LFunction {
   167  	return &LFunction{
   168  		IsG: true,
   169  		Env: env,
   170  
   171  		Proto:     nil,
   172  		GFunction: gfunc,
   173  		Upvalues:  make([]*Upvalue, nupvalue),
   174  	}
   175  }
   176  
   177  func (fn *LFunction) LocalName(regno, pc int) (string, bool) {
   178  	if fn.IsG {
   179  		return "", false
   180  	}
   181  	p := fn.Proto
   182  	for i := 0; i < len(p.DbgLocals) && p.DbgLocals[i].StartPc < pc; i++ {
   183  		if pc < p.DbgLocals[i].EndPc {
   184  			regno--
   185  			if regno == 0 {
   186  				return p.DbgLocals[i].Name, true
   187  			}
   188  		}
   189  	}
   190  	return "", false
   191  }
   192  
   193  /* }}} */