1package lua
2
3import (
4	"fmt"
5	"strings"
6)
7
8const (
9	VarArgHasArg   uint8 = 1
10	VarArgIsVarArg uint8 = 2
11	VarArgNeedsArg uint8 = 4
12)
13
14type DbgLocalInfo struct {
15	Name    string
16	StartPc int
17	EndPc   int
18}
19
20type DbgCall struct {
21	Name string
22	Pc   int
23}
24
25type 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
47type Upvalue struct {
48	next   *Upvalue
49	reg    *registry
50	index  int
51	value  LValue
52	closed bool
53}
54
55func (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
64func (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
72func (uv *Upvalue) Close() {
73	value := uv.Value()
74	uv.closed = true
75	uv.value = value
76}
77
78func (uv *Upvalue) IsClosed() bool {
79	return uv.closed || uv.reg == nil
80}
81
82func UpvalueIndex(i int) int {
83	return GlobalsIndex - i
84}
85
86/* }}} */
87
88/* FunctionProto {{{ */
89
90func 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
112func (fp *FunctionProto) String() string {
113	return fp.str(1, 0)
114}
115
116func (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
155func 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
166func 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
177func (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/* }}} */
194