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