1package lua
2
3import (
4	"context"
5	"fmt"
6	"github.com/yuin/gopher-lua/parse"
7	"io"
8	"math"
9	"os"
10	"runtime"
11	"strings"
12	"sync"
13	"sync/atomic"
14	"time"
15)
16
17const MultRet = -1
18const RegistryIndex = -10000
19const EnvironIndex = -10001
20const GlobalsIndex = -10002
21
22/* ApiError {{{ */
23
24type ApiError struct {
25	Type       ApiErrorType
26	Object     LValue
27	StackTrace string
28	// Underlying error. This attribute is set only if the Type is ApiErrorFile or ApiErrorSyntax
29	Cause error
30}
31
32func newApiError(code ApiErrorType, object LValue) *ApiError {
33	return &ApiError{code, object, "", nil}
34}
35
36func newApiErrorS(code ApiErrorType, message string) *ApiError {
37	return newApiError(code, LString(message))
38}
39
40func newApiErrorE(code ApiErrorType, err error) *ApiError {
41	return &ApiError{code, LString(err.Error()), "", err}
42}
43
44func (e *ApiError) Error() string {
45	if len(e.StackTrace) > 0 {
46		return fmt.Sprintf("%s\n%s", e.Object.String(), e.StackTrace)
47	}
48	return e.Object.String()
49}
50
51type ApiErrorType int
52
53const (
54	ApiErrorSyntax ApiErrorType = iota
55	ApiErrorFile
56	ApiErrorRun
57	ApiErrorError
58	ApiErrorPanic
59)
60
61/* }}} */
62
63/* ResumeState {{{ */
64
65type ResumeState int
66
67const (
68	ResumeOK ResumeState = iota
69	ResumeYield
70	ResumeError
71)
72
73/* }}} */
74
75/* P {{{ */
76
77type P struct {
78	Fn      LValue
79	NRet    int
80	Protect bool
81	Handler *LFunction
82}
83
84/* }}} */
85
86/* Options {{{ */
87
88// Options is a configuration that is used to create a new LState.
89type Options struct {
90	// Call stack size. This defaults to `lua.CallStackSize`.
91	CallStackSize int
92	// Data stack size. This defaults to `lua.RegistrySize`.
93	RegistrySize int
94	// Allow the registry to grow from the registry size specified up to a value of RegistryMaxSize. A value of 0
95	// indicates no growth is permitted. The registry will not shrink again after any growth.
96	RegistryMaxSize int
97	// If growth is enabled, step up by an additional `RegistryGrowStep` each time to avoid having to resize too often.
98	// This defaults to `lua.RegistryGrowStep`
99	RegistryGrowStep int
100	// Controls whether or not libraries are opened by default
101	SkipOpenLibs bool
102	// Tells whether a Go stacktrace should be included in a Lua stacktrace when panics occur.
103	IncludeGoStackTrace bool
104	// If `MinimizeStackMemory` is set, the call stack will be automatically grown or shrank up to a limit of
105	// `CallStackSize` in order to minimize memory usage. This does incur a slight performance penalty.
106	MinimizeStackMemory bool
107}
108
109/* }}} */
110
111/* Debug {{{ */
112
113type Debug struct {
114	frame           *callFrame
115	Name            string
116	What            string
117	Source          string
118	CurrentLine     int
119	NUpvalues       int
120	LineDefined     int
121	LastLineDefined int
122}
123
124/* }}} */
125
126/* callFrame {{{ */
127
128type callFrame struct {
129	Idx        int
130	Fn         *LFunction
131	Parent     *callFrame
132	Pc         int
133	Base       int
134	LocalBase  int
135	ReturnBase int
136	NArgs      int
137	NRet       int
138	TailCall   int
139}
140
141type callFrameStack interface {
142	Push(v callFrame)
143	Pop() *callFrame
144	Last() *callFrame
145
146	SetSp(sp int)
147	Sp() int
148	At(sp int) *callFrame
149
150	IsFull() bool
151	IsEmpty() bool
152
153	FreeAll()
154}
155
156type fixedCallFrameStack struct {
157	array []callFrame
158	sp    int
159}
160
161func newFixedCallFrameStack(size int) callFrameStack {
162	return &fixedCallFrameStack{
163		array: make([]callFrame, size),
164		sp:    0,
165	}
166}
167
168func (cs *fixedCallFrameStack) IsEmpty() bool { return cs.sp == 0 }
169
170func (cs *fixedCallFrameStack) IsFull() bool { return cs.sp == len(cs.array) }
171
172func (cs *fixedCallFrameStack) Clear() {
173	cs.sp = 0
174}
175
176func (cs *fixedCallFrameStack) Push(v callFrame) {
177	cs.array[cs.sp] = v
178	cs.array[cs.sp].Idx = cs.sp
179	cs.sp++
180}
181
182func (cs *fixedCallFrameStack) Sp() int {
183	return cs.sp
184}
185
186func (cs *fixedCallFrameStack) SetSp(sp int) {
187	cs.sp = sp
188}
189
190func (cs *fixedCallFrameStack) Last() *callFrame {
191	if cs.sp == 0 {
192		return nil
193	}
194	return &cs.array[cs.sp-1]
195}
196
197func (cs *fixedCallFrameStack) At(sp int) *callFrame {
198	return &cs.array[sp]
199}
200
201func (cs *fixedCallFrameStack) Pop() *callFrame {
202	cs.sp--
203	return &cs.array[cs.sp]
204}
205
206func (cs *fixedCallFrameStack) FreeAll() {
207	// nothing to do for fixed callframestack
208}
209
210// FramesPerSegment should be a power of 2 constant for performance reasons. It will allow the go compiler to change
211// the divs and mods into bitshifts. Max is 256 due to current use of uint8 to count how many frames in a segment are
212// used.
213const FramesPerSegment = 8
214
215type callFrameStackSegment struct {
216	array [FramesPerSegment]callFrame
217}
218type segIdx uint16
219type autoGrowingCallFrameStack struct {
220	segments []*callFrameStackSegment
221	segIdx   segIdx
222	// segSp is the number of frames in the current segment which are used. Full 'sp' value is segIdx * FramesPerSegment + segSp.
223	// It points to the next stack slot to use, so 0 means to use the 0th element in the segment, and a value of
224	// FramesPerSegment indicates that the segment is full and cannot accommodate another frame.
225	segSp uint8
226}
227
228var segmentPool sync.Pool
229
230func newCallFrameStackSegment() *callFrameStackSegment {
231	seg := segmentPool.Get()
232	if seg == nil {
233		return &callFrameStackSegment{}
234	}
235	return seg.(*callFrameStackSegment)
236}
237
238func freeCallFrameStackSegment(seg *callFrameStackSegment) {
239	segmentPool.Put(seg)
240}
241
242// newCallFrameStack allocates a new stack for a lua state, which will auto grow up to a max size of at least maxSize.
243// it will actually grow up to the next segment size multiple after maxSize, where the segment size is dictated by
244// FramesPerSegment.
245func newAutoGrowingCallFrameStack(maxSize int) callFrameStack {
246	cs := &autoGrowingCallFrameStack{
247		segments: make([]*callFrameStackSegment, (maxSize+(FramesPerSegment-1))/FramesPerSegment),
248		segIdx:   0,
249	}
250	cs.segments[0] = newCallFrameStackSegment()
251	return cs
252}
253
254func (cs *autoGrowingCallFrameStack) IsEmpty() bool {
255	return cs.segIdx == 0 && cs.segSp == 0
256}
257
258// IsFull returns true if the stack cannot receive any more stack pushes without overflowing
259func (cs *autoGrowingCallFrameStack) IsFull() bool {
260	return int(cs.segIdx) == len(cs.segments) && cs.segSp >= FramesPerSegment
261}
262
263func (cs *autoGrowingCallFrameStack) Clear() {
264	for i := segIdx(1); i <= cs.segIdx; i++ {
265		freeCallFrameStackSegment(cs.segments[i])
266		cs.segments[i] = nil
267	}
268	cs.segIdx = 0
269	cs.segSp = 0
270}
271
272func (cs *autoGrowingCallFrameStack) FreeAll() {
273	for i := segIdx(0); i <= cs.segIdx; i++ {
274		freeCallFrameStackSegment(cs.segments[i])
275		cs.segments[i] = nil
276	}
277}
278
279// Push pushes the passed callFrame onto the stack. it panics if the stack is full, caller should call IsFull() before
280// invoking this to avoid this.
281func (cs *autoGrowingCallFrameStack) Push(v callFrame) {
282	curSeg := cs.segments[cs.segIdx]
283	if cs.segSp >= FramesPerSegment {
284		// segment full, push new segment if allowed
285		if cs.segIdx < segIdx(len(cs.segments)-1) {
286			curSeg = newCallFrameStackSegment()
287			cs.segIdx++
288			cs.segments[cs.segIdx] = curSeg
289			cs.segSp = 0
290		} else {
291			panic("lua callstack overflow")
292		}
293	}
294	curSeg.array[cs.segSp] = v
295	curSeg.array[cs.segSp].Idx = int(cs.segSp) + FramesPerSegment*int(cs.segIdx)
296	cs.segSp++
297}
298
299// Sp retrieves the current stack depth, which is the number of frames currently pushed on the stack.
300func (cs *autoGrowingCallFrameStack) Sp() int {
301	return int(cs.segSp) + int(cs.segIdx)*FramesPerSegment
302}
303
304// SetSp can be used to rapidly unwind the stack, freeing all stack frames on the way. It should not be used to
305// allocate new stack space, use Push() for that.
306func (cs *autoGrowingCallFrameStack) SetSp(sp int) {
307	desiredSegIdx := segIdx(sp / FramesPerSegment)
308	desiredFramesInLastSeg := uint8(sp % FramesPerSegment)
309	for {
310		if cs.segIdx <= desiredSegIdx {
311			break
312		}
313		freeCallFrameStackSegment(cs.segments[cs.segIdx])
314		cs.segments[cs.segIdx] = nil
315		cs.segIdx--
316	}
317	cs.segSp = desiredFramesInLastSeg
318}
319
320func (cs *autoGrowingCallFrameStack) Last() *callFrame {
321	curSeg := cs.segments[cs.segIdx]
322	segSp := cs.segSp
323	if segSp == 0 {
324		if cs.segIdx == 0 {
325			return nil
326		}
327		curSeg = cs.segments[cs.segIdx-1]
328		segSp = FramesPerSegment
329	}
330	return &curSeg.array[segSp-1]
331}
332
333func (cs *autoGrowingCallFrameStack) At(sp int) *callFrame {
334	segIdx := segIdx(sp / FramesPerSegment)
335	frameIdx := uint8(sp % FramesPerSegment)
336	return &cs.segments[segIdx].array[frameIdx]
337}
338
339// Pop pops off the most recent stack frame and returns it
340func (cs *autoGrowingCallFrameStack) Pop() *callFrame {
341	curSeg := cs.segments[cs.segIdx]
342	if cs.segSp == 0 {
343		if cs.segIdx == 0 {
344			// stack empty
345			return nil
346		}
347		freeCallFrameStackSegment(curSeg)
348		cs.segments[cs.segIdx] = nil
349		cs.segIdx--
350		cs.segSp = FramesPerSegment
351		curSeg = cs.segments[cs.segIdx]
352	}
353	cs.segSp--
354	return &curSeg.array[cs.segSp]
355}
356
357/* }}} */
358
359/* registry {{{ */
360
361type registryHandler interface {
362	registryOverflow()
363}
364type registry struct {
365	array   []LValue
366	top     int
367	growBy  int
368	maxSize int
369	alloc   *allocator
370	handler registryHandler
371}
372
373func newRegistry(handler registryHandler, initialSize int, growBy int, maxSize int, alloc *allocator) *registry {
374	return &registry{make([]LValue, initialSize), 0, growBy, maxSize, alloc, handler}
375}
376
377func (rg *registry) checkSize(requiredSize int) { // +inline-start
378	if requiredSize > cap(rg.array) {
379		rg.resize(requiredSize)
380	}
381} // +inline-end
382
383func (rg *registry) resize(requiredSize int) { // +inline-start
384	newSize := requiredSize + rg.growBy // give some padding
385	if newSize > rg.maxSize {
386		newSize = rg.maxSize
387	}
388	if newSize < requiredSize {
389		rg.handler.registryOverflow()
390		return
391	}
392	rg.forceResize(newSize)
393} // +inline-end
394
395func (rg *registry) forceResize(newSize int) {
396	newSlice := make([]LValue, newSize)
397	copy(newSlice, rg.array[:rg.top]) // should we copy the area beyond top? there shouldn't be any valid values there so it shouldn't be necessary.
398	rg.array = newSlice
399}
400func (rg *registry) SetTop(top int) {
401	// +inline-call rg.checkSize top
402	oldtop := rg.top
403	rg.top = top
404	for i := oldtop; i < rg.top; i++ {
405		rg.array[i] = LNil
406	}
407	// values beyond top don't need to be valid LValues, so setting them to nil is fine
408	// setting them to nil rather than LNil lets us invoke the golang memclr opto
409	if rg.top < oldtop {
410		nilRange := rg.array[rg.top:oldtop]
411		for i := range nilRange {
412			nilRange[i] = nil
413		}
414	}
415	//for i := rg.top; i < oldtop; i++ {
416	//	rg.array[i] = LNil
417	//}
418}
419
420func (rg *registry) Top() int {
421	return rg.top
422}
423
424func (rg *registry) Push(v LValue) {
425	newSize := rg.top + 1
426	// +inline-call rg.checkSize newSize
427	rg.array[rg.top] = v
428	rg.top++
429}
430
431func (rg *registry) Pop() LValue {
432	v := rg.array[rg.top-1]
433	rg.array[rg.top-1] = LNil
434	rg.top--
435	return v
436}
437
438func (rg *registry) Get(reg int) LValue {
439	return rg.array[reg]
440}
441
442// CopyRange will move a section of values from index `start` to index `regv`
443// It will move `n` values.
444// `limit` specifies the maximum end range that can be copied from. If it's set to -1, then it defaults to stopping at
445// the top of the registry (values beyond the top are not initialized, so if specifying an alternative `limit` you should
446// pass a value <= rg.top.
447// If start+n is beyond the limit, then nil values will be copied to the destination slots.
448// After the copy, the registry is truncated to be at the end of the copied range, ie the original of the copied values
449// are nilled out. (So top will be regv+n)
450// CopyRange should ideally be renamed to MoveRange.
451func (rg *registry) CopyRange(regv, start, limit, n int) { // +inline-start
452	newSize := regv + n
453	// +inline-call rg.checkSize newSize
454	if limit == -1 || limit > rg.top {
455		limit = rg.top
456	}
457	for i := 0; i < n; i++ {
458		srcIdx := start + i
459		if srcIdx >= limit || srcIdx < 0 {
460			rg.array[regv+i] = LNil
461		} else {
462			rg.array[regv+i] = rg.array[srcIdx]
463		}
464	}
465
466	// values beyond top don't need to be valid LValues, so setting them to nil is fine
467	// setting them to nil rather than LNil lets us invoke the golang memclr opto
468	oldtop := rg.top
469	rg.top = regv + n
470	if rg.top < oldtop {
471		nilRange := rg.array[rg.top:oldtop]
472		for i := range nilRange {
473			nilRange[i] = nil
474		}
475	}
476} // +inline-end
477
478// FillNil fills the registry with nil values from regm to regm+n and then sets the registry top to regm+n
479func (rg *registry) FillNil(regm, n int) { // +inline-start
480	newSize := regm + n
481	// +inline-call rg.checkSize newSize
482	for i := 0; i < n; i++ {
483		rg.array[regm+i] = LNil
484	}
485	// values beyond top don't need to be valid LValues, so setting them to nil is fine
486	// setting them to nil rather than LNil lets us invoke the golang memclr opto
487	oldtop := rg.top
488	rg.top = regm + n
489	if rg.top < oldtop {
490		nilRange := rg.array[rg.top:oldtop]
491		for i := range nilRange {
492			nilRange[i] = nil
493		}
494	}
495} // +inline-end
496
497func (rg *registry) Insert(value LValue, reg int) {
498	top := rg.Top()
499	if reg >= top {
500		rg.Set(reg, value)
501		return
502	}
503	top--
504	for ; top >= reg; top-- {
505		// FIXME consider using copy() here if Insert() is called enough
506		rg.Set(top+1, rg.Get(top))
507	}
508	rg.Set(reg, value)
509}
510
511func (rg *registry) Set(reg int, val LValue) {
512	newSize := reg + 1
513	// +inline-call rg.checkSize newSize
514	rg.array[reg] = val
515	if reg >= rg.top {
516		rg.top = reg + 1
517	}
518}
519
520func (rg *registry) SetNumber(reg int, val LNumber) {
521	newSize := reg + 1
522	// +inline-call rg.checkSize newSize
523	rg.array[reg] = rg.alloc.LNumber2I(val)
524	if reg >= rg.top {
525		rg.top = reg + 1
526	}
527}
528
529func (rg *registry) IsFull() bool {
530	return rg.top >= cap(rg.array)
531}
532
533/* }}} */
534
535/* Global {{{ */
536
537func newGlobal() *Global {
538	return &Global{
539		MainThread: nil,
540		Registry:   newLTable(0, 32),
541		Global:     newLTable(0, 64),
542		builtinMts: make(map[int]LValue),
543		tempFiles:  make([]*os.File, 0, 10),
544	}
545}
546
547/* }}} */
548
549/* package local methods {{{ */
550
551func panicWithTraceback(L *LState) {
552	err := newApiError(ApiErrorRun, L.Get(-1))
553	err.StackTrace = L.stackTrace(0)
554	panic(err)
555}
556
557func panicWithoutTraceback(L *LState) {
558	err := newApiError(ApiErrorRun, L.Get(-1))
559	panic(err)
560}
561
562func newLState(options Options) *LState {
563	al := newAllocator(32)
564	ls := &LState{
565		G:       newGlobal(),
566		Parent:  nil,
567		Panic:   panicWithTraceback,
568		Dead:    false,
569		Options: options,
570
571		stop:         0,
572		alloc:        al,
573		currentFrame: nil,
574		wrapped:      false,
575		uvcache:      nil,
576		hasErrorFunc: false,
577		mainLoop:     mainLoop,
578		ctx:          nil,
579	}
580	if options.MinimizeStackMemory {
581		ls.stack = newAutoGrowingCallFrameStack(options.CallStackSize)
582	} else {
583		ls.stack = newFixedCallFrameStack(options.CallStackSize)
584	}
585	ls.reg = newRegistry(ls, options.RegistrySize, options.RegistryGrowStep, options.RegistryMaxSize, al)
586	ls.Env = ls.G.Global
587	return ls
588}
589
590func (ls *LState) printReg() {
591	println("-------------------------")
592	println("thread:", ls)
593	println("top:", ls.reg.Top())
594	if ls.currentFrame != nil {
595		println("function base:", ls.currentFrame.Base)
596		println("return base:", ls.currentFrame.ReturnBase)
597	} else {
598		println("(vm not started)")
599	}
600	println("local base:", ls.currentLocalBase())
601	for i := 0; i < ls.reg.Top(); i++ {
602		println(i, ls.reg.Get(i).String())
603	}
604	println("-------------------------")
605}
606
607func (ls *LState) printCallStack() {
608	println("-------------------------")
609	for i := 0; i < ls.stack.Sp(); i++ {
610		print(i)
611		print(" ")
612		frame := ls.stack.At(i)
613		if frame == nil {
614			break
615		}
616		if frame.Fn.IsG {
617			println("IsG:", true, "Frame:", frame, "Fn:", frame.Fn)
618		} else {
619			println("IsG:", false, "Frame:", frame, "Fn:", frame.Fn, "pc:", frame.Pc)
620		}
621	}
622	println("-------------------------")
623}
624
625func (ls *LState) closeAllUpvalues() { // +inline-start
626	for cf := ls.currentFrame; cf != nil; cf = cf.Parent {
627		if !cf.Fn.IsG {
628			ls.closeUpvalues(cf.LocalBase)
629		}
630	}
631} // +inline-end
632
633func (ls *LState) raiseError(level int, format string, args ...interface{}) {
634	if !ls.hasErrorFunc {
635		ls.closeAllUpvalues()
636	}
637	message := format
638	if len(args) > 0 {
639		message = fmt.Sprintf(format, args...)
640	}
641	if level > 0 {
642		message = fmt.Sprintf("%v %v", ls.where(level-1, true), message)
643	}
644	if ls.reg.IsFull() {
645		// if the registry is full then it won't be possible to push a value, in this case, force a larger size
646		ls.reg.forceResize(ls.reg.Top() + 1)
647	}
648	ls.reg.Push(LString(message))
649	ls.Panic(ls)
650}
651
652func (ls *LState) findLocal(frame *callFrame, no int) string {
653	fn := frame.Fn
654	if !fn.IsG {
655		if name, ok := fn.LocalName(no, frame.Pc-1); ok {
656			return name
657		}
658	}
659	var top int
660	if ls.currentFrame == frame {
661		top = ls.reg.Top()
662	} else if frame.Idx+1 < ls.stack.Sp() {
663		top = ls.stack.At(frame.Idx + 1).Base
664	} else {
665		return ""
666	}
667	if top-frame.LocalBase >= no {
668		return "(*temporary)"
669	}
670	return ""
671}
672
673func (ls *LState) where(level int, skipg bool) string {
674	dbg, ok := ls.GetStack(level)
675	if !ok {
676		return ""
677	}
678	cf := dbg.frame
679	proto := cf.Fn.Proto
680	sourcename := "[G]"
681	if proto != nil {
682		sourcename = proto.SourceName
683	} else if skipg {
684		return ls.where(level+1, skipg)
685	}
686	line := ""
687	if proto != nil {
688		line = fmt.Sprintf("%v:", proto.DbgSourcePositions[cf.Pc-1])
689	}
690	return fmt.Sprintf("%v:%v", sourcename, line)
691}
692
693func (ls *LState) stackTrace(level int) string {
694	buf := []string{}
695	header := "stack traceback:"
696	if ls.currentFrame != nil {
697		i := 0
698		for dbg, ok := ls.GetStack(i); ok; dbg, ok = ls.GetStack(i) {
699			cf := dbg.frame
700			buf = append(buf, fmt.Sprintf("\t%v in %v", ls.Where(i), ls.formattedFrameFuncName(cf)))
701			if !cf.Fn.IsG && cf.TailCall > 0 {
702				for tc := cf.TailCall; tc > 0; tc-- {
703					buf = append(buf, "\t(tailcall): ?")
704					i++
705				}
706			}
707			i++
708		}
709	}
710	buf = append(buf, fmt.Sprintf("\t%v: %v", "[G]", "?"))
711	buf = buf[intMax(0, intMin(level, len(buf))):len(buf)]
712	if len(buf) > 20 {
713		newbuf := make([]string, 0, 20)
714		newbuf = append(newbuf, buf[0:7]...)
715		newbuf = append(newbuf, "\t...")
716		newbuf = append(newbuf, buf[len(buf)-7:len(buf)]...)
717		buf = newbuf
718	}
719	return fmt.Sprintf("%s\n%s", header, strings.Join(buf, "\n"))
720}
721
722func (ls *LState) formattedFrameFuncName(fr *callFrame) string {
723	name, ischunk := ls.frameFuncName(fr)
724	if ischunk {
725		return name
726	}
727	if name[0] != '(' && name[0] != '<' {
728		return fmt.Sprintf("function '%s'", name)
729	}
730	return fmt.Sprintf("function %s", name)
731}
732
733func (ls *LState) rawFrameFuncName(fr *callFrame) string {
734	name, _ := ls.frameFuncName(fr)
735	return name
736}
737
738func (ls *LState) frameFuncName(fr *callFrame) (string, bool) {
739	frame := fr.Parent
740	if frame == nil {
741		if ls.Parent == nil {
742			return "main chunk", true
743		} else {
744			return "corountine", true
745		}
746	}
747	if !frame.Fn.IsG {
748		pc := frame.Pc - 1
749		for _, call := range frame.Fn.Proto.DbgCalls {
750			if call.Pc == pc {
751				name := call.Name
752				if (name == "?" || fr.TailCall > 0) && !fr.Fn.IsG {
753					name = fmt.Sprintf("<%v:%v>", fr.Fn.Proto.SourceName, fr.Fn.Proto.LineDefined)
754				}
755				return name, false
756			}
757		}
758	}
759	if !fr.Fn.IsG {
760		return fmt.Sprintf("<%v:%v>", fr.Fn.Proto.SourceName, fr.Fn.Proto.LineDefined), false
761	}
762	return "(anonymous)", false
763}
764
765func (ls *LState) isStarted() bool {
766	return ls.currentFrame != nil
767}
768
769func (ls *LState) kill() {
770	ls.Dead = true
771}
772
773func (ls *LState) indexToReg(idx int) int {
774	base := ls.currentLocalBase()
775	if idx > 0 {
776		return base + idx - 1
777	} else if idx == 0 {
778		return -1
779	} else {
780		tidx := ls.reg.Top() + idx
781		if tidx < base {
782			return -1
783		}
784		return tidx
785	}
786}
787
788func (ls *LState) currentLocalBase() int {
789	base := 0
790	if ls.currentFrame != nil {
791		base = ls.currentFrame.LocalBase
792	}
793	return base
794}
795
796func (ls *LState) currentEnv() *LTable {
797	return ls.Env
798	/*
799		if ls.currentFrame == nil {
800			return ls.Env
801		}
802		return ls.currentFrame.Fn.Env
803	*/
804}
805
806func (ls *LState) rkValue(idx int) LValue {
807	/*
808		if OpIsK(idx) {
809			return ls.currentFrame.Fn.Proto.Constants[opIndexK(idx)]
810		}
811		return ls.reg.Get(ls.currentFrame.LocalBase + idx)
812	*/
813	if (idx & opBitRk) != 0 {
814		return ls.currentFrame.Fn.Proto.Constants[idx & ^opBitRk]
815	}
816	return ls.reg.array[ls.currentFrame.LocalBase+idx]
817}
818
819func (ls *LState) rkString(idx int) string {
820	if (idx & opBitRk) != 0 {
821		return ls.currentFrame.Fn.Proto.stringConstants[idx & ^opBitRk]
822	}
823	return string(ls.reg.array[ls.currentFrame.LocalBase+idx].(LString))
824}
825
826func (ls *LState) closeUpvalues(idx int) { // +inline-start
827	if ls.uvcache != nil {
828		var prev *Upvalue
829		for uv := ls.uvcache; uv != nil; uv = uv.next {
830			if uv.index >= idx {
831				if prev != nil {
832					prev.next = nil
833				} else {
834					ls.uvcache = nil
835				}
836				uv.Close()
837			}
838			prev = uv
839		}
840	}
841} // +inline-end
842
843func (ls *LState) findUpvalue(idx int) *Upvalue {
844	var prev *Upvalue
845	var next *Upvalue
846	if ls.uvcache != nil {
847		for uv := ls.uvcache; uv != nil; uv = uv.next {
848			if uv.index == idx {
849				return uv
850			}
851			if uv.index > idx {
852				next = uv
853				break
854			}
855			prev = uv
856		}
857	}
858	uv := &Upvalue{reg: ls.reg, index: idx, closed: false}
859	if prev != nil {
860		prev.next = uv
861	} else {
862		ls.uvcache = uv
863	}
864	if next != nil {
865		uv.next = next
866	}
867	return uv
868}
869
870func (ls *LState) metatable(lvalue LValue, rawget bool) LValue {
871	var metatable LValue = LNil
872	switch obj := lvalue.(type) {
873	case *LTable:
874		metatable = obj.Metatable
875	case *LUserData:
876		metatable = obj.Metatable
877	default:
878		if table, ok := ls.G.builtinMts[int(obj.Type())]; ok {
879			metatable = table
880		}
881	}
882
883	if !rawget && metatable != LNil {
884		oldmt := metatable
885		if tb, ok := metatable.(*LTable); ok {
886			metatable = tb.RawGetString("__metatable")
887			if metatable == LNil {
888				metatable = oldmt
889			}
890		}
891	}
892
893	return metatable
894}
895
896func (ls *LState) metaOp1(lvalue LValue, event string) LValue {
897	if mt := ls.metatable(lvalue, true); mt != LNil {
898		if tb, ok := mt.(*LTable); ok {
899			return tb.RawGetString(event)
900		}
901	}
902	return LNil
903}
904
905func (ls *LState) metaOp2(value1, value2 LValue, event string) LValue {
906	if mt := ls.metatable(value1, true); mt != LNil {
907		if tb, ok := mt.(*LTable); ok {
908			if ret := tb.RawGetString(event); ret != LNil {
909				return ret
910			}
911		}
912	}
913	if mt := ls.metatable(value2, true); mt != LNil {
914		if tb, ok := mt.(*LTable); ok {
915			return tb.RawGetString(event)
916		}
917	}
918	return LNil
919}
920
921func (ls *LState) metaCall(lvalue LValue) (*LFunction, bool) {
922	if fn, ok := lvalue.(*LFunction); ok {
923		return fn, false
924	}
925	if fn, ok := ls.metaOp1(lvalue, "__call").(*LFunction); ok {
926		return fn, true
927	}
928	return nil, false
929}
930
931func (ls *LState) initCallFrame(cf *callFrame) { // +inline-start
932	if cf.Fn.IsG {
933		ls.reg.SetTop(cf.LocalBase + cf.NArgs)
934	} else {
935		proto := cf.Fn.Proto
936		nargs := cf.NArgs
937		np := int(proto.NumParameters)
938		newSize := cf.LocalBase + np
939		// +inline-call ls.reg.checkSize newSize
940		for i := nargs; i < np; i++ {
941			ls.reg.array[cf.LocalBase+i] = LNil
942			nargs = np
943		}
944
945		if (proto.IsVarArg & VarArgIsVarArg) == 0 {
946			if nargs < int(proto.NumUsedRegisters) {
947				nargs = int(proto.NumUsedRegisters)
948			}
949			newSize = cf.LocalBase + nargs
950			// +inline-call ls.reg.checkSize newSize
951			for i := np; i < nargs; i++ {
952				ls.reg.array[cf.LocalBase+i] = LNil
953			}
954			ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
955		} else {
956			/* swap vararg positions:
957					   closure
958					   namedparam1 <- lbase
959					   namedparam2
960					   vararg1
961					   vararg2
962
963			           TO
964
965					   closure
966					   nil
967					   nil
968					   vararg1
969					   vararg2
970					   namedparam1 <- lbase
971					   namedparam2
972			*/
973			nvarargs := nargs - np
974			if nvarargs < 0 {
975				nvarargs = 0
976			}
977
978			ls.reg.SetTop(cf.LocalBase + nargs + np)
979			for i := 0; i < np; i++ {
980				//ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
981				ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
982				//ls.reg.Set(cf.LocalBase+i, LNil)
983				ls.reg.array[cf.LocalBase+i] = LNil
984			}
985
986			if CompatVarArg {
987				ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
988				if (proto.IsVarArg & VarArgNeedsArg) != 0 {
989					argtb := newLTable(nvarargs, 0)
990					for i := 0; i < nvarargs; i++ {
991						argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
992					}
993					argtb.RawSetString("n", LNumber(nvarargs))
994					//ls.reg.Set(cf.LocalBase+nargs+np, argtb)
995					ls.reg.array[cf.LocalBase+nargs+np] = argtb
996				} else {
997					ls.reg.array[cf.LocalBase+nargs+np] = LNil
998				}
999			}
1000			cf.LocalBase += nargs
1001			maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
1002			ls.reg.SetTop(maxreg)
1003		}
1004	}
1005} // +inline-end
1006
1007func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) { // +inline-start
1008	if meta {
1009		cf.NArgs++
1010		ls.reg.Insert(fn, cf.LocalBase)
1011	}
1012	if cf.Fn == nil {
1013		ls.RaiseError("attempt to call a non-function object")
1014	}
1015	if ls.stack.IsFull() {
1016		ls.RaiseError("stack overflow")
1017	}
1018	ls.stack.Push(cf)
1019	newcf := ls.stack.Last()
1020	// +inline-call ls.initCallFrame newcf
1021	ls.currentFrame = newcf
1022} // +inline-end
1023
1024func (ls *LState) callR(nargs, nret, rbase int) {
1025	base := ls.reg.Top() - nargs - 1
1026	if rbase < 0 {
1027		rbase = base
1028	}
1029	lv := ls.reg.Get(base)
1030	fn, meta := ls.metaCall(lv)
1031	ls.pushCallFrame(callFrame{
1032		Fn:         fn,
1033		Pc:         0,
1034		Base:       base,
1035		LocalBase:  base + 1,
1036		ReturnBase: rbase,
1037		NArgs:      nargs,
1038		NRet:       nret,
1039		Parent:     ls.currentFrame,
1040		TailCall:   0,
1041	}, lv, meta)
1042	if ls.G.MainThread == nil {
1043		ls.G.MainThread = ls
1044		ls.G.CurrentThread = ls
1045		ls.mainLoop(ls, nil)
1046	} else {
1047		ls.mainLoop(ls, ls.currentFrame)
1048	}
1049	if nret != MultRet {
1050		ls.reg.SetTop(rbase + nret)
1051	}
1052}
1053
1054func (ls *LState) getField(obj LValue, key LValue) LValue {
1055	curobj := obj
1056	for i := 0; i < MaxTableGetLoop; i++ {
1057		tb, istable := curobj.(*LTable)
1058		if istable {
1059			ret := tb.RawGet(key)
1060			if ret != LNil {
1061				return ret
1062			}
1063		}
1064		metaindex := ls.metaOp1(curobj, "__index")
1065		if metaindex == LNil {
1066			if !istable {
1067				ls.RaiseError("attempt to index a non-table object(%v) with key '%s'", curobj.Type().String(), key.String())
1068			}
1069			return LNil
1070		}
1071		if metaindex.Type() == LTFunction {
1072			ls.reg.Push(metaindex)
1073			ls.reg.Push(curobj)
1074			ls.reg.Push(key)
1075			ls.Call(2, 1)
1076			return ls.reg.Pop()
1077		} else {
1078			curobj = metaindex
1079		}
1080	}
1081	ls.RaiseError("too many recursions in gettable")
1082	return nil
1083}
1084
1085func (ls *LState) getFieldString(obj LValue, key string) LValue {
1086	curobj := obj
1087	for i := 0; i < MaxTableGetLoop; i++ {
1088		tb, istable := curobj.(*LTable)
1089		if istable {
1090			ret := tb.RawGetString(key)
1091			if ret != LNil {
1092				return ret
1093			}
1094		}
1095		metaindex := ls.metaOp1(curobj, "__index")
1096		if metaindex == LNil {
1097			if !istable {
1098				ls.RaiseError("attempt to index a non-table object(%v) with key '%s'", curobj.Type().String(), key)
1099			}
1100			return LNil
1101		}
1102		if metaindex.Type() == LTFunction {
1103			ls.reg.Push(metaindex)
1104			ls.reg.Push(curobj)
1105			ls.reg.Push(LString(key))
1106			ls.Call(2, 1)
1107			return ls.reg.Pop()
1108		} else {
1109			curobj = metaindex
1110		}
1111	}
1112	ls.RaiseError("too many recursions in gettable")
1113	return nil
1114}
1115
1116func (ls *LState) setField(obj LValue, key LValue, value LValue) {
1117	curobj := obj
1118	for i := 0; i < MaxTableGetLoop; i++ {
1119		tb, istable := curobj.(*LTable)
1120		if istable {
1121			if tb.RawGet(key) != LNil {
1122				ls.RawSet(tb, key, value)
1123				return
1124			}
1125		}
1126		metaindex := ls.metaOp1(curobj, "__newindex")
1127		if metaindex == LNil {
1128			if !istable {
1129				ls.RaiseError("attempt to index a non-table object(%v) with key '%s'", curobj.Type().String(), key.String())
1130			}
1131			ls.RawSet(tb, key, value)
1132			return
1133		}
1134		if metaindex.Type() == LTFunction {
1135			ls.reg.Push(metaindex)
1136			ls.reg.Push(curobj)
1137			ls.reg.Push(key)
1138			ls.reg.Push(value)
1139			ls.Call(3, 0)
1140			return
1141		} else {
1142			curobj = metaindex
1143		}
1144	}
1145	ls.RaiseError("too many recursions in settable")
1146}
1147
1148func (ls *LState) setFieldString(obj LValue, key string, value LValue) {
1149	curobj := obj
1150	for i := 0; i < MaxTableGetLoop; i++ {
1151		tb, istable := curobj.(*LTable)
1152		if istable {
1153			if tb.RawGetString(key) != LNil {
1154				tb.RawSetString(key, value)
1155				return
1156			}
1157		}
1158		metaindex := ls.metaOp1(curobj, "__newindex")
1159		if metaindex == LNil {
1160			if !istable {
1161				ls.RaiseError("attempt to index a non-table object(%v) with key '%s'", curobj.Type().String(), key)
1162			}
1163			tb.RawSetString(key, value)
1164			return
1165		}
1166		if metaindex.Type() == LTFunction {
1167			ls.reg.Push(metaindex)
1168			ls.reg.Push(curobj)
1169			ls.reg.Push(LString(key))
1170			ls.reg.Push(value)
1171			ls.Call(3, 0)
1172			return
1173		} else {
1174			curobj = metaindex
1175		}
1176	}
1177	ls.RaiseError("too many recursions in settable")
1178}
1179
1180/* }}} */
1181
1182/* api methods {{{ */
1183
1184func NewState(opts ...Options) *LState {
1185	var ls *LState
1186	if len(opts) == 0 {
1187		ls = newLState(Options{
1188			CallStackSize: CallStackSize,
1189			RegistrySize:  RegistrySize,
1190		})
1191		ls.OpenLibs()
1192	} else {
1193		if opts[0].CallStackSize < 1 {
1194			opts[0].CallStackSize = CallStackSize
1195		}
1196		if opts[0].RegistrySize < 128 {
1197			opts[0].RegistrySize = RegistrySize
1198		}
1199		if opts[0].RegistryMaxSize < opts[0].RegistrySize {
1200			opts[0].RegistryMaxSize = 0 // disable growth if max size is smaller than initial size
1201		} else {
1202			// if growth enabled, grow step is set
1203			if opts[0].RegistryGrowStep < 1 {
1204				opts[0].RegistryGrowStep = RegistryGrowStep
1205			}
1206		}
1207		ls = newLState(opts[0])
1208		if !opts[0].SkipOpenLibs {
1209			ls.OpenLibs()
1210		}
1211	}
1212	return ls
1213}
1214
1215func (ls *LState) Close() {
1216	atomic.AddInt32(&ls.stop, 1)
1217	for _, file := range ls.G.tempFiles {
1218		// ignore errors in these operations
1219		file.Close()
1220		os.Remove(file.Name())
1221	}
1222	ls.stack.FreeAll()
1223	ls.stack = nil
1224}
1225
1226/* registry operations {{{ */
1227
1228func (ls *LState) GetTop() int {
1229	return ls.reg.Top() - ls.currentLocalBase()
1230}
1231
1232func (ls *LState) SetTop(idx int) {
1233	base := ls.currentLocalBase()
1234	newtop := ls.indexToReg(idx) + 1
1235	if newtop < base {
1236		ls.reg.SetTop(base)
1237	} else {
1238		ls.reg.SetTop(newtop)
1239	}
1240}
1241
1242func (ls *LState) Replace(idx int, value LValue) {
1243	base := ls.currentLocalBase()
1244	if idx > 0 {
1245		reg := base + idx - 1
1246		if reg < ls.reg.Top() {
1247			ls.reg.Set(reg, value)
1248		}
1249	} else if idx == 0 {
1250	} else if idx > RegistryIndex {
1251		if tidx := ls.reg.Top() + idx; tidx >= base {
1252			ls.reg.Set(tidx, value)
1253		}
1254	} else {
1255		switch idx {
1256		case RegistryIndex:
1257			if tb, ok := value.(*LTable); ok {
1258				ls.G.Registry = tb
1259			} else {
1260				ls.RaiseError("registry must be a table(%v)", value.Type().String())
1261			}
1262		case EnvironIndex:
1263			if ls.currentFrame == nil {
1264				ls.RaiseError("no calling environment")
1265			}
1266			if tb, ok := value.(*LTable); ok {
1267				ls.currentFrame.Fn.Env = tb
1268			} else {
1269				ls.RaiseError("environment must be a table(%v)", value.Type().String())
1270			}
1271		case GlobalsIndex:
1272			if tb, ok := value.(*LTable); ok {
1273				ls.G.Global = tb
1274			} else {
1275				ls.RaiseError("_G must be a table(%v)", value.Type().String())
1276			}
1277		default:
1278			fn := ls.currentFrame.Fn
1279			index := GlobalsIndex - idx - 1
1280			if index < len(fn.Upvalues) {
1281				fn.Upvalues[index].SetValue(value)
1282			}
1283		}
1284	}
1285}
1286
1287func (ls *LState) Get(idx int) LValue {
1288	base := ls.currentLocalBase()
1289	if idx > 0 {
1290		reg := base + idx - 1
1291		if reg < ls.reg.Top() {
1292			return ls.reg.Get(reg)
1293		}
1294		return LNil
1295	} else if idx == 0 {
1296		return LNil
1297	} else if idx > RegistryIndex {
1298		tidx := ls.reg.Top() + idx
1299		if tidx < base {
1300			return LNil
1301		}
1302		return ls.reg.Get(tidx)
1303	} else {
1304		switch idx {
1305		case RegistryIndex:
1306			return ls.G.Registry
1307		case EnvironIndex:
1308			if ls.currentFrame == nil {
1309				return ls.Env
1310			}
1311			return ls.currentFrame.Fn.Env
1312		case GlobalsIndex:
1313			return ls.G.Global
1314		default:
1315			fn := ls.currentFrame.Fn
1316			index := GlobalsIndex - idx - 1
1317			if index < len(fn.Upvalues) {
1318				return fn.Upvalues[index].Value()
1319			}
1320			return LNil
1321		}
1322	}
1323	return LNil
1324}
1325
1326func (ls *LState) Push(value LValue) {
1327	ls.reg.Push(value)
1328}
1329
1330func (ls *LState) Pop(n int) {
1331	for i := 0; i < n; i++ {
1332		if ls.GetTop() == 0 {
1333			ls.RaiseError("register underflow")
1334		}
1335		ls.reg.Pop()
1336	}
1337}
1338
1339func (ls *LState) Insert(value LValue, index int) {
1340	reg := ls.indexToReg(index)
1341	top := ls.reg.Top()
1342	if reg >= top {
1343		ls.reg.Set(reg, value)
1344		return
1345	}
1346	if reg <= ls.currentLocalBase() {
1347		reg = ls.currentLocalBase()
1348	}
1349	top--
1350	for ; top >= reg; top-- {
1351		ls.reg.Set(top+1, ls.reg.Get(top))
1352	}
1353	ls.reg.Set(reg, value)
1354}
1355
1356func (ls *LState) Remove(index int) {
1357	reg := ls.indexToReg(index)
1358	top := ls.reg.Top()
1359	switch {
1360	case reg >= top:
1361		return
1362	case reg < ls.currentLocalBase():
1363		return
1364	case reg == top-1:
1365		ls.Pop(1)
1366		return
1367	}
1368	for i := reg; i < top-1; i++ {
1369		ls.reg.Set(i, ls.reg.Get(i+1))
1370	}
1371	ls.reg.SetTop(top - 1)
1372}
1373
1374/* }}} */
1375
1376/* object allocation {{{ */
1377
1378func (ls *LState) NewTable() *LTable {
1379	return newLTable(defaultArrayCap, defaultHashCap)
1380}
1381
1382func (ls *LState) CreateTable(acap, hcap int) *LTable {
1383	return newLTable(acap, hcap)
1384}
1385
1386// NewThread returns a new LState that shares with the original state all global objects.
1387// If the original state has context.Context, the new state has a new child context of the original state and this function returns its cancel function.
1388func (ls *LState) NewThread() (*LState, context.CancelFunc) {
1389	thread := newLState(ls.Options)
1390	thread.G = ls.G
1391	thread.Env = ls.Env
1392	var f context.CancelFunc = nil
1393	if ls.ctx != nil {
1394		thread.mainLoop = mainLoopWithContext
1395		thread.ctx, f = context.WithCancel(ls.ctx)
1396	}
1397	return thread, f
1398}
1399
1400func (ls *LState) NewFunctionFromProto(proto *FunctionProto) *LFunction {
1401	return newLFunctionL(proto, ls.Env, int(proto.NumUpvalues))
1402}
1403
1404func (ls *LState) NewUserData() *LUserData {
1405	return &LUserData{
1406		Env:       ls.currentEnv(),
1407		Metatable: LNil,
1408	}
1409}
1410
1411func (ls *LState) NewFunction(fn LGFunction) *LFunction {
1412	return newLFunctionG(fn, ls.currentEnv(), 0)
1413}
1414
1415func (ls *LState) NewClosure(fn LGFunction, upvalues ...LValue) *LFunction {
1416	cl := newLFunctionG(fn, ls.currentEnv(), len(upvalues))
1417	for i, lv := range upvalues {
1418		cl.Upvalues[i] = &Upvalue{}
1419		cl.Upvalues[i].Close()
1420		cl.Upvalues[i].SetValue(lv)
1421	}
1422	return cl
1423}
1424
1425/* }}} */
1426
1427/* toType {{{ */
1428
1429func (ls *LState) ToBool(n int) bool {
1430	return LVAsBool(ls.Get(n))
1431}
1432
1433func (ls *LState) ToInt(n int) int {
1434	if lv, ok := ls.Get(n).(LNumber); ok {
1435		return int(lv)
1436	}
1437	if lv, ok := ls.Get(n).(LString); ok {
1438		if num, err := parseNumber(string(lv)); err == nil {
1439			return int(num)
1440		}
1441	}
1442	return 0
1443}
1444
1445func (ls *LState) ToInt64(n int) int64 {
1446	if lv, ok := ls.Get(n).(LNumber); ok {
1447		return int64(lv)
1448	}
1449	if lv, ok := ls.Get(n).(LString); ok {
1450		if num, err := parseNumber(string(lv)); err == nil {
1451			return int64(num)
1452		}
1453	}
1454	return 0
1455}
1456
1457func (ls *LState) ToNumber(n int) LNumber {
1458	return LVAsNumber(ls.Get(n))
1459}
1460
1461func (ls *LState) ToString(n int) string {
1462	return LVAsString(ls.Get(n))
1463}
1464
1465func (ls *LState) ToTable(n int) *LTable {
1466	if lv, ok := ls.Get(n).(*LTable); ok {
1467		return lv
1468	}
1469	return nil
1470}
1471
1472func (ls *LState) ToFunction(n int) *LFunction {
1473	if lv, ok := ls.Get(n).(*LFunction); ok {
1474		return lv
1475	}
1476	return nil
1477}
1478
1479func (ls *LState) ToUserData(n int) *LUserData {
1480	if lv, ok := ls.Get(n).(*LUserData); ok {
1481		return lv
1482	}
1483	return nil
1484}
1485
1486func (ls *LState) ToThread(n int) *LState {
1487	if lv, ok := ls.Get(n).(*LState); ok {
1488		return lv
1489	}
1490	return nil
1491}
1492
1493/* }}} */
1494
1495/* error & debug operations {{{ */
1496
1497func (ls *LState) registryOverflow() {
1498	ls.RaiseError("registry overflow")
1499}
1500
1501// This function is equivalent to luaL_error( http://www.lua.org/manual/5.1/manual.html#luaL_error ).
1502func (ls *LState) RaiseError(format string, args ...interface{}) {
1503	ls.raiseError(1, format, args...)
1504}
1505
1506// This function is equivalent to lua_error( http://www.lua.org/manual/5.1/manual.html#lua_error ).
1507func (ls *LState) Error(lv LValue, level int) {
1508	if str, ok := lv.(LString); ok {
1509		ls.raiseError(level, string(str))
1510	} else {
1511		if !ls.hasErrorFunc {
1512			ls.closeAllUpvalues()
1513		}
1514		ls.Push(lv)
1515		ls.Panic(ls)
1516	}
1517}
1518
1519func (ls *LState) GetInfo(what string, dbg *Debug, fn LValue) (LValue, error) {
1520	if !strings.HasPrefix(what, ">") {
1521		fn = dbg.frame.Fn
1522	} else {
1523		what = what[1:]
1524	}
1525	f, ok := fn.(*LFunction)
1526	if !ok {
1527		return LNil, newApiErrorS(ApiErrorRun, "can not get debug info(an object in not a function)")
1528	}
1529
1530	retfn := false
1531	for _, c := range what {
1532		switch c {
1533		case 'f':
1534			retfn = true
1535		case 'S':
1536			if dbg.frame != nil && dbg.frame.Parent == nil {
1537				dbg.What = "main"
1538			} else if f.IsG {
1539				dbg.What = "G"
1540			} else if dbg.frame != nil && dbg.frame.TailCall > 0 {
1541				dbg.What = "tail"
1542			} else {
1543				dbg.What = "Lua"
1544			}
1545			if !f.IsG {
1546				dbg.Source = f.Proto.SourceName
1547				dbg.LineDefined = f.Proto.LineDefined
1548				dbg.LastLineDefined = f.Proto.LastLineDefined
1549			}
1550		case 'l':
1551			if !f.IsG && dbg.frame != nil {
1552				if dbg.frame.Pc > 0 {
1553					dbg.CurrentLine = f.Proto.DbgSourcePositions[dbg.frame.Pc-1]
1554				}
1555			} else {
1556				dbg.CurrentLine = -1
1557			}
1558		case 'u':
1559			dbg.NUpvalues = len(f.Upvalues)
1560		case 'n':
1561			if dbg.frame != nil {
1562				dbg.Name = ls.rawFrameFuncName(dbg.frame)
1563			}
1564		default:
1565			return LNil, newApiErrorS(ApiErrorRun, "invalid what: "+string(c))
1566		}
1567	}
1568
1569	if retfn {
1570		return f, nil
1571	}
1572	return LNil, nil
1573
1574}
1575
1576func (ls *LState) GetStack(level int) (*Debug, bool) {
1577	frame := ls.currentFrame
1578	for ; level > 0 && frame != nil; frame = frame.Parent {
1579		level--
1580		if !frame.Fn.IsG {
1581			level -= frame.TailCall
1582		}
1583	}
1584
1585	if level == 0 && frame != nil {
1586		return &Debug{frame: frame}, true
1587	} else if level < 0 && ls.stack.Sp() > 0 {
1588		return &Debug{frame: ls.stack.At(0)}, true
1589	}
1590	return &Debug{}, false
1591}
1592
1593func (ls *LState) GetLocal(dbg *Debug, no int) (string, LValue) {
1594	frame := dbg.frame
1595	if name := ls.findLocal(frame, no); len(name) > 0 {
1596		return name, ls.reg.Get(frame.LocalBase + no - 1)
1597	}
1598	return "", LNil
1599}
1600
1601func (ls *LState) SetLocal(dbg *Debug, no int, lv LValue) string {
1602	frame := dbg.frame
1603	if name := ls.findLocal(frame, no); len(name) > 0 {
1604		ls.reg.Set(frame.LocalBase+no-1, lv)
1605		return name
1606	}
1607	return ""
1608}
1609
1610func (ls *LState) GetUpvalue(fn *LFunction, no int) (string, LValue) {
1611	if fn.IsG {
1612		return "", LNil
1613	}
1614
1615	no--
1616	if no >= 0 && no < len(fn.Upvalues) {
1617		return fn.Proto.DbgUpvalues[no], fn.Upvalues[no].Value()
1618	}
1619	return "", LNil
1620}
1621
1622func (ls *LState) SetUpvalue(fn *LFunction, no int, lv LValue) string {
1623	if fn.IsG {
1624		return ""
1625	}
1626
1627	no--
1628	if no >= 0 && no < len(fn.Upvalues) {
1629		fn.Upvalues[no].SetValue(lv)
1630		return fn.Proto.DbgUpvalues[no]
1631	}
1632	return ""
1633}
1634
1635/* }}} */
1636
1637/* env operations {{{ */
1638
1639func (ls *LState) GetFEnv(obj LValue) LValue {
1640	switch lv := obj.(type) {
1641	case *LFunction:
1642		return lv.Env
1643	case *LUserData:
1644		return lv.Env
1645	case *LState:
1646		return lv.Env
1647	}
1648	return LNil
1649}
1650
1651func (ls *LState) SetFEnv(obj LValue, env LValue) {
1652	tb, ok := env.(*LTable)
1653	if !ok {
1654		ls.RaiseError("cannot use %v as an environment", env.Type().String())
1655	}
1656
1657	switch lv := obj.(type) {
1658	case *LFunction:
1659		lv.Env = tb
1660	case *LUserData:
1661		lv.Env = tb
1662	case *LState:
1663		lv.Env = tb
1664	}
1665	/* do nothing */
1666}
1667
1668/* }}} */
1669
1670/* table operations {{{ */
1671
1672func (ls *LState) RawGet(tb *LTable, key LValue) LValue {
1673	return tb.RawGet(key)
1674}
1675
1676func (ls *LState) RawGetInt(tb *LTable, key int) LValue {
1677	return tb.RawGetInt(key)
1678}
1679
1680func (ls *LState) GetField(obj LValue, skey string) LValue {
1681	return ls.getFieldString(obj, skey)
1682}
1683
1684func (ls *LState) GetTable(obj LValue, key LValue) LValue {
1685	return ls.getField(obj, key)
1686}
1687
1688func (ls *LState) RawSet(tb *LTable, key LValue, value LValue) {
1689	if n, ok := key.(LNumber); ok && math.IsNaN(float64(n)) {
1690		ls.RaiseError("table index is NaN")
1691	} else if key == LNil {
1692		ls.RaiseError("table index is nil")
1693	}
1694	tb.RawSet(key, value)
1695}
1696
1697func (ls *LState) RawSetInt(tb *LTable, key int, value LValue) {
1698	tb.RawSetInt(key, value)
1699}
1700
1701func (ls *LState) SetField(obj LValue, key string, value LValue) {
1702	ls.setFieldString(obj, key, value)
1703}
1704
1705func (ls *LState) SetTable(obj LValue, key LValue, value LValue) {
1706	ls.setField(obj, key, value)
1707}
1708
1709func (ls *LState) ForEach(tb *LTable, cb func(LValue, LValue)) {
1710	tb.ForEach(cb)
1711}
1712
1713func (ls *LState) GetGlobal(name string) LValue {
1714	return ls.GetField(ls.Get(GlobalsIndex), name)
1715}
1716
1717func (ls *LState) SetGlobal(name string, value LValue) {
1718	ls.SetField(ls.Get(GlobalsIndex), name, value)
1719}
1720
1721func (ls *LState) Next(tb *LTable, key LValue) (LValue, LValue) {
1722	return tb.Next(key)
1723}
1724
1725/* }}} */
1726
1727/* unary operations {{{ */
1728
1729func (ls *LState) ObjLen(v1 LValue) int {
1730	if v1.Type() == LTString {
1731		return len(string(v1.(LString)))
1732	}
1733	op := ls.metaOp1(v1, "__len")
1734	if op.Type() == LTFunction {
1735		ls.Push(op)
1736		ls.Push(v1)
1737		ls.Call(1, 1)
1738		ret := ls.reg.Pop()
1739		if ret.Type() == LTNumber {
1740			return int(ret.(LNumber))
1741		}
1742	} else if v1.Type() == LTTable {
1743		return v1.(*LTable).Len()
1744	}
1745	return 0
1746}
1747
1748/* }}} */
1749
1750/* binary operations {{{ */
1751
1752func (ls *LState) Concat(values ...LValue) string {
1753	top := ls.reg.Top()
1754	for _, value := range values {
1755		ls.reg.Push(value)
1756	}
1757	ret := stringConcat(ls, len(values), ls.reg.Top()-1)
1758	ls.reg.SetTop(top)
1759	return LVAsString(ret)
1760}
1761
1762func (ls *LState) LessThan(lhs, rhs LValue) bool {
1763	return lessThan(ls, lhs, rhs)
1764}
1765
1766func (ls *LState) Equal(lhs, rhs LValue) bool {
1767	return equals(ls, lhs, rhs, false)
1768}
1769
1770func (ls *LState) RawEqual(lhs, rhs LValue) bool {
1771	return equals(ls, lhs, rhs, true)
1772}
1773
1774/* }}} */
1775
1776/* register operations {{{ */
1777
1778func (ls *LState) Register(name string, fn LGFunction) {
1779	ls.SetGlobal(name, ls.NewFunction(fn))
1780}
1781
1782/* }}} */
1783
1784/* load and function call operations {{{ */
1785
1786func (ls *LState) Load(reader io.Reader, name string) (*LFunction, error) {
1787	chunk, err := parse.Parse(reader, name)
1788	if err != nil {
1789		return nil, newApiErrorE(ApiErrorSyntax, err)
1790	}
1791	proto, err := Compile(chunk, name)
1792	if err != nil {
1793		return nil, newApiErrorE(ApiErrorSyntax, err)
1794	}
1795	return newLFunctionL(proto, ls.currentEnv(), 0), nil
1796}
1797
1798func (ls *LState) Call(nargs, nret int) {
1799	ls.callR(nargs, nret, -1)
1800}
1801
1802func (ls *LState) PCall(nargs, nret int, errfunc *LFunction) (err error) {
1803	err = nil
1804	sp := ls.stack.Sp()
1805	base := ls.reg.Top() - nargs - 1
1806	oldpanic := ls.Panic
1807	ls.Panic = panicWithoutTraceback
1808	if errfunc != nil {
1809		ls.hasErrorFunc = true
1810	}
1811	defer func() {
1812		ls.Panic = oldpanic
1813		ls.hasErrorFunc = false
1814		rcv := recover()
1815		if rcv != nil {
1816			if _, ok := rcv.(*ApiError); !ok {
1817				err = newApiErrorS(ApiErrorPanic, fmt.Sprint(rcv))
1818				if ls.Options.IncludeGoStackTrace {
1819					buf := make([]byte, 4096)
1820					runtime.Stack(buf, false)
1821					err.(*ApiError).StackTrace = strings.Trim(string(buf), "\000") + "\n" + ls.stackTrace(0)
1822				}
1823			} else {
1824				err = rcv.(*ApiError)
1825			}
1826			if errfunc != nil {
1827				ls.Push(errfunc)
1828				ls.Push(err.(*ApiError).Object)
1829				ls.Panic = panicWithoutTraceback
1830				defer func() {
1831					ls.Panic = oldpanic
1832					rcv := recover()
1833					if rcv != nil {
1834						if _, ok := rcv.(*ApiError); !ok {
1835							err = newApiErrorS(ApiErrorPanic, fmt.Sprint(rcv))
1836							if ls.Options.IncludeGoStackTrace {
1837								buf := make([]byte, 4096)
1838								runtime.Stack(buf, false)
1839								err.(*ApiError).StackTrace = strings.Trim(string(buf), "\000") + ls.stackTrace(0)
1840							}
1841						} else {
1842							err = rcv.(*ApiError)
1843							err.(*ApiError).StackTrace = ls.stackTrace(0)
1844						}
1845					}
1846				}()
1847				ls.Call(1, 1)
1848				err = newApiError(ApiErrorError, ls.Get(-1))
1849			} else if len(err.(*ApiError).StackTrace) == 0 {
1850				err.(*ApiError).StackTrace = ls.stackTrace(0)
1851			}
1852			ls.stack.SetSp(sp)
1853			ls.currentFrame = ls.stack.Last()
1854			ls.reg.SetTop(base)
1855		}
1856		ls.stack.SetSp(sp)
1857		if sp == 0 {
1858			ls.currentFrame = nil
1859		}
1860	}()
1861
1862	ls.Call(nargs, nret)
1863
1864	return
1865}
1866
1867func (ls *LState) GPCall(fn LGFunction, data LValue) error {
1868	ls.Push(newLFunctionG(fn, ls.currentEnv(), 0))
1869	ls.Push(data)
1870	return ls.PCall(1, MultRet, nil)
1871}
1872
1873func (ls *LState) CallByParam(cp P, args ...LValue) error {
1874	ls.Push(cp.Fn)
1875	for _, arg := range args {
1876		ls.Push(arg)
1877	}
1878
1879	if cp.Protect {
1880		return ls.PCall(len(args), cp.NRet, cp.Handler)
1881	}
1882	ls.Call(len(args), cp.NRet)
1883	return nil
1884}
1885
1886/* }}} */
1887
1888/* metatable operations {{{ */
1889
1890func (ls *LState) GetMetatable(obj LValue) LValue {
1891	return ls.metatable(obj, false)
1892}
1893
1894func (ls *LState) SetMetatable(obj LValue, mt LValue) {
1895	switch mt.(type) {
1896	case *LNilType, *LTable:
1897	default:
1898		ls.RaiseError("metatable must be a table or nil, but got %v", mt.Type().String())
1899	}
1900
1901	switch v := obj.(type) {
1902	case *LTable:
1903		v.Metatable = mt
1904	case *LUserData:
1905		v.Metatable = mt
1906	default:
1907		ls.G.builtinMts[int(obj.Type())] = mt
1908	}
1909}
1910
1911/* }}} */
1912
1913/* coroutine operations {{{ */
1914
1915func (ls *LState) Status(th *LState) string {
1916	status := "suspended"
1917	if th.Dead {
1918		status = "dead"
1919	} else if ls.G.CurrentThread == th {
1920		status = "running"
1921	} else if ls.Parent == th {
1922		status = "normal"
1923	}
1924	return status
1925}
1926
1927func (ls *LState) Resume(th *LState, fn *LFunction, args ...LValue) (ResumeState, error, []LValue) {
1928	isstarted := th.isStarted()
1929	if !isstarted {
1930		base := 0
1931		th.stack.Push(callFrame{
1932			Fn:         fn,
1933			Pc:         0,
1934			Base:       base,
1935			LocalBase:  base + 1,
1936			ReturnBase: base,
1937			NArgs:      0,
1938			NRet:       MultRet,
1939			Parent:     nil,
1940			TailCall:   0,
1941		})
1942	}
1943
1944	if ls.G.CurrentThread == th {
1945		return ResumeError, newApiErrorS(ApiErrorRun, "can not resume a running thread"), nil
1946	}
1947	if th.Dead {
1948		return ResumeError, newApiErrorS(ApiErrorRun, "can not resume a dead thread"), nil
1949	}
1950	th.Parent = ls
1951	ls.G.CurrentThread = th
1952	if !isstarted {
1953		cf := th.stack.Last()
1954		th.currentFrame = cf
1955		th.SetTop(0)
1956		for _, arg := range args {
1957			th.Push(arg)
1958		}
1959		cf.NArgs = len(args)
1960		th.initCallFrame(cf)
1961		th.Panic = panicWithoutTraceback
1962	} else {
1963		for _, arg := range args {
1964			th.Push(arg)
1965		}
1966	}
1967	top := ls.GetTop()
1968	threadRun(th)
1969	haserror := LVIsFalse(ls.Get(top + 1))
1970	ret := make([]LValue, 0, ls.GetTop())
1971	for idx := top + 2; idx <= ls.GetTop(); idx++ {
1972		ret = append(ret, ls.Get(idx))
1973	}
1974	if len(ret) == 0 {
1975		ret = append(ret, LNil)
1976	}
1977	ls.SetTop(top)
1978
1979	if haserror {
1980		return ResumeError, newApiError(ApiErrorRun, ret[0]), nil
1981	} else if th.stack.IsEmpty() {
1982		return ResumeOK, nil, ret
1983	}
1984	return ResumeYield, nil, ret
1985}
1986
1987func (ls *LState) Yield(values ...LValue) int {
1988	ls.SetTop(0)
1989	for _, lv := range values {
1990		ls.Push(lv)
1991	}
1992	return -1
1993}
1994
1995func (ls *LState) XMoveTo(other *LState, n int) {
1996	if ls == other {
1997		return
1998	}
1999	top := ls.GetTop()
2000	n = intMin(n, top)
2001	for i := n; i > 0; i-- {
2002		other.Push(ls.Get(top - i + 1))
2003	}
2004	ls.SetTop(top - n)
2005}
2006
2007/* }}} */
2008
2009/* GopherLua original APIs {{{ */
2010
2011// Set maximum memory size. This function can only be called from the main thread.
2012func (ls *LState) SetMx(mx int) {
2013	if ls.Parent != nil {
2014		ls.RaiseError("sub threads are not allowed to set a memory limit")
2015	}
2016	go func() {
2017		limit := uint64(mx * 1024 * 1024) //MB
2018		var s runtime.MemStats
2019		for ls.stop == 0 {
2020			runtime.ReadMemStats(&s)
2021			if s.Alloc >= limit {
2022				fmt.Println("out of memory")
2023				os.Exit(3)
2024			}
2025			time.Sleep(100 * time.Millisecond)
2026		}
2027	}()
2028}
2029
2030// SetContext set a context ctx to this LState. The provided ctx must be non-nil.
2031func (ls *LState) SetContext(ctx context.Context) {
2032	ls.mainLoop = mainLoopWithContext
2033	ls.ctx = ctx
2034}
2035
2036// Context returns the LState's context. To change the context, use WithContext.
2037func (ls *LState) Context() context.Context {
2038	return ls.ctx
2039}
2040
2041// RemoveContext removes the context associated with this LState and returns this context.
2042func (ls *LState) RemoveContext() context.Context {
2043	oldctx := ls.ctx
2044	ls.mainLoop = mainLoop
2045	ls.ctx = nil
2046	return oldctx
2047}
2048
2049// Converts the Lua value at the given acceptable index to the chan LValue.
2050func (ls *LState) ToChannel(n int) chan LValue {
2051	if lv, ok := ls.Get(n).(LChannel); ok {
2052		return (chan LValue)(lv)
2053	}
2054	return nil
2055}
2056
2057// RemoveCallerFrame removes the stack frame above the current stack frame. This is useful in tail calls. It returns
2058// the new current frame.
2059func (ls *LState) RemoveCallerFrame() *callFrame {
2060	cs := ls.stack
2061	sp := cs.Sp()
2062	parentFrame := cs.At(sp - 2)
2063	currentFrame := cs.At(sp - 1)
2064	parentsParentFrame := parentFrame.Parent
2065	*parentFrame = *currentFrame
2066	parentFrame.Parent = parentsParentFrame
2067	parentFrame.Idx = sp - 2
2068	cs.Pop()
2069	return parentFrame
2070}
2071
2072/* }}} */
2073
2074/* }}} */
2075
2076//
2077