github.com/suixinio/gopher-lua@v0.0.0-20230314172526-3c6bff009a9a/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 /* }}} */