194 lines
4.0 KiB
Go
194 lines
4.0 KiB
Go
package lua
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
VarArgHasArg uint8 = 1
|
|
VarArgIsVarArg uint8 = 2
|
|
VarArgNeedsArg uint8 = 4
|
|
)
|
|
|
|
type DbgLocalInfo struct {
|
|
Name string
|
|
StartPc int
|
|
EndPc int
|
|
}
|
|
|
|
type DbgCall struct {
|
|
Name string
|
|
Pc int
|
|
}
|
|
|
|
type FunctionProto struct {
|
|
SourceName string
|
|
LineDefined int
|
|
LastLineDefined int
|
|
NumUpvalues uint8
|
|
NumParameters uint8
|
|
IsVarArg uint8
|
|
NumUsedRegisters uint8
|
|
Code []uint32
|
|
Constants []LValue
|
|
FunctionPrototypes []*FunctionProto
|
|
|
|
DbgSourcePositions []int
|
|
DbgLocals []*DbgLocalInfo
|
|
DbgCalls []DbgCall
|
|
DbgUpvalues []string
|
|
|
|
stringConstants []string
|
|
}
|
|
|
|
/* Upvalue {{{ */
|
|
|
|
type Upvalue struct {
|
|
next *Upvalue
|
|
reg *registry
|
|
index int
|
|
value LValue
|
|
closed bool
|
|
}
|
|
|
|
func (uv *Upvalue) Value() LValue {
|
|
//if uv.IsClosed() {
|
|
if uv.closed || uv.reg == nil {
|
|
return uv.value
|
|
}
|
|
//return uv.reg.Get(uv.index)
|
|
return uv.reg.array[uv.index]
|
|
}
|
|
|
|
func (uv *Upvalue) SetValue(value LValue) {
|
|
if uv.IsClosed() {
|
|
uv.value = value
|
|
} else {
|
|
uv.reg.Set(uv.index, value)
|
|
}
|
|
}
|
|
|
|
func (uv *Upvalue) Close() {
|
|
value := uv.Value()
|
|
uv.closed = true
|
|
uv.value = value
|
|
}
|
|
|
|
func (uv *Upvalue) IsClosed() bool {
|
|
return uv.closed || uv.reg == nil
|
|
}
|
|
|
|
func UpvalueIndex(i int) int {
|
|
return GlobalsIndex - i
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* FunctionProto {{{ */
|
|
|
|
func newFunctionProto(name string) *FunctionProto {
|
|
return &FunctionProto{
|
|
SourceName: name,
|
|
LineDefined: 0,
|
|
LastLineDefined: 0,
|
|
NumUpvalues: 0,
|
|
NumParameters: 0,
|
|
IsVarArg: 0,
|
|
NumUsedRegisters: 2,
|
|
Code: make([]uint32, 0, 128),
|
|
Constants: make([]LValue, 0, 32),
|
|
FunctionPrototypes: make([]*FunctionProto, 0, 16),
|
|
|
|
DbgSourcePositions: make([]int, 0, 128),
|
|
DbgLocals: make([]*DbgLocalInfo, 0, 16),
|
|
DbgCalls: make([]DbgCall, 0, 128),
|
|
DbgUpvalues: make([]string, 0, 16),
|
|
|
|
stringConstants: make([]string, 0, 32),
|
|
}
|
|
}
|
|
|
|
func (fp *FunctionProto) String() string {
|
|
return fp.str(1, 0)
|
|
}
|
|
|
|
func (fp *FunctionProto) str(level int, count int) string {
|
|
indent := strings.Repeat(" ", level-1)
|
|
buf := []string{}
|
|
buf = append(buf, fmt.Sprintf("%v; function [%v] definition (level %v)\n",
|
|
indent, count, level))
|
|
buf = append(buf, fmt.Sprintf("%v; %v upvalues, %v params, %v stacks\n",
|
|
indent, fp.NumUpvalues, fp.NumParameters, fp.NumUsedRegisters))
|
|
for reg, linfo := range fp.DbgLocals {
|
|
buf = append(buf, fmt.Sprintf("%v.local %v ; %v\n", indent, linfo.Name, reg))
|
|
}
|
|
for reg, upvalue := range fp.DbgUpvalues {
|
|
buf = append(buf, fmt.Sprintf("%v.upvalue %v ; %v\n", indent, upvalue, reg))
|
|
}
|
|
for reg, conzt := range fp.Constants {
|
|
buf = append(buf, fmt.Sprintf("%v.const %v ; %v\n", indent, conzt.String(), reg))
|
|
}
|
|
buf = append(buf, "\n")
|
|
|
|
protono := 0
|
|
for no, code := range fp.Code {
|
|
inst := opGetOpCode(code)
|
|
if inst == OP_CLOSURE {
|
|
buf = append(buf, "\n")
|
|
buf = append(buf, fp.FunctionPrototypes[protono].str(level+1, protono))
|
|
buf = append(buf, "\n")
|
|
protono++
|
|
}
|
|
buf = append(buf, fmt.Sprintf("%v[%03d] %v (line:%v)\n",
|
|
indent, no+1, opToString(code), fp.DbgSourcePositions[no]))
|
|
|
|
}
|
|
buf = append(buf, fmt.Sprintf("%v; end of function\n", indent))
|
|
return strings.Join(buf, "")
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* LFunction {{{ */
|
|
|
|
func newLFunctionL(proto *FunctionProto, env *LTable, nupvalue int) *LFunction {
|
|
return &LFunction{
|
|
IsG: false,
|
|
Env: env,
|
|
|
|
Proto: proto,
|
|
GFunction: nil,
|
|
Upvalues: make([]*Upvalue, nupvalue),
|
|
}
|
|
}
|
|
|
|
func newLFunctionG(gfunc LGFunction, env *LTable, nupvalue int) *LFunction {
|
|
return &LFunction{
|
|
IsG: true,
|
|
Env: env,
|
|
|
|
Proto: nil,
|
|
GFunction: gfunc,
|
|
Upvalues: make([]*Upvalue, nupvalue),
|
|
}
|
|
}
|
|
|
|
func (fn *LFunction) LocalName(regno, pc int) (string, bool) {
|
|
if fn.IsG {
|
|
return "", false
|
|
}
|
|
p := fn.Proto
|
|
for i := 0; i < len(p.DbgLocals) && p.DbgLocals[i].StartPc < pc; i++ {
|
|
if pc < p.DbgLocals[i].EndPc {
|
|
regno--
|
|
if regno == 0 {
|
|
return p.DbgLocals[i].Name, true
|
|
}
|
|
}
|
|
}
|
|
return "", false
|
|
}
|
|
|
|
/* }}} */
|