mirror of https://github.com/tidwall/tile38.git
1873 lines
39 KiB
Go
1873 lines
39 KiB
Go
|
package lua
|
||
|
|
||
|
////////////////////////////////////////////////////////
|
||
|
// This file was generated by go-inline. DO NOT EDIT. //
|
||
|
////////////////////////////////////////////////////////
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"github.com/yuin/gopher-lua/parse"
|
||
|
"io"
|
||
|
"math"
|
||
|
"os"
|
||
|
"runtime"
|
||
|
"strings"
|
||
|
"sync/atomic"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
const MultRet = -1
|
||
|
const RegistryIndex = -10000
|
||
|
const EnvironIndex = -10001
|
||
|
const GlobalsIndex = -10002
|
||
|
|
||
|
/* ApiError {{{ */
|
||
|
|
||
|
type ApiError struct {
|
||
|
Type ApiErrorType
|
||
|
Object LValue
|
||
|
StackTrace string
|
||
|
// Underlying error. This attribute is set only if the Type is ApiErrorFile or ApiErrorSyntax
|
||
|
Cause error
|
||
|
}
|
||
|
|
||
|
func newApiError(code ApiErrorType, object LValue) *ApiError {
|
||
|
return &ApiError{code, object, "", nil}
|
||
|
}
|
||
|
|
||
|
func newApiErrorS(code ApiErrorType, message string) *ApiError {
|
||
|
return newApiError(code, LString(message))
|
||
|
}
|
||
|
|
||
|
func newApiErrorE(code ApiErrorType, err error) *ApiError {
|
||
|
return &ApiError{code, LString(err.Error()), "", err}
|
||
|
}
|
||
|
|
||
|
func (e *ApiError) Error() string {
|
||
|
if len(e.StackTrace) > 0 {
|
||
|
return fmt.Sprintf("%s\n%s", e.Object.String(), e.StackTrace)
|
||
|
}
|
||
|
return e.Object.String()
|
||
|
}
|
||
|
|
||
|
type ApiErrorType int
|
||
|
|
||
|
const (
|
||
|
ApiErrorSyntax ApiErrorType = iota
|
||
|
ApiErrorFile
|
||
|
ApiErrorRun
|
||
|
ApiErrorError
|
||
|
ApiErrorPanic
|
||
|
)
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* ResumeState {{{ */
|
||
|
|
||
|
type ResumeState int
|
||
|
|
||
|
const (
|
||
|
ResumeOK ResumeState = iota
|
||
|
ResumeYield
|
||
|
ResumeError
|
||
|
)
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* P {{{ */
|
||
|
|
||
|
type P struct {
|
||
|
Fn LValue
|
||
|
NRet int
|
||
|
Protect bool
|
||
|
Handler *LFunction
|
||
|
}
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* Options {{{ */
|
||
|
|
||
|
// Options is a configuration that is used to create a new LState.
|
||
|
type Options struct {
|
||
|
// Call stack size. This defaults to `lua.CallStackSize`.
|
||
|
CallStackSize int
|
||
|
// Data stack size. This defaults to `lua.RegistrySize`.
|
||
|
RegistrySize int
|
||
|
// Controls whether or not libraries are opened by default
|
||
|
SkipOpenLibs bool
|
||
|
// Tells whether a Go stacktrace should be included in a Lua stacktrace when panics occur.
|
||
|
IncludeGoStackTrace bool
|
||
|
}
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* Debug {{{ */
|
||
|
|
||
|
type Debug struct {
|
||
|
frame *callFrame
|
||
|
Name string
|
||
|
What string
|
||
|
Source string
|
||
|
CurrentLine int
|
||
|
NUpvalues int
|
||
|
LineDefined int
|
||
|
LastLineDefined int
|
||
|
}
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* callFrame {{{ */
|
||
|
|
||
|
type callFrame struct {
|
||
|
Idx int
|
||
|
Fn *LFunction
|
||
|
Parent *callFrame
|
||
|
Pc int
|
||
|
Base int
|
||
|
LocalBase int
|
||
|
ReturnBase int
|
||
|
NArgs int
|
||
|
NRet int
|
||
|
TailCall int
|
||
|
}
|
||
|
|
||
|
type callFrameStack struct {
|
||
|
array []callFrame
|
||
|
sp int
|
||
|
}
|
||
|
|
||
|
func newCallFrameStack(size int) *callFrameStack {
|
||
|
return &callFrameStack{
|
||
|
array: make([]callFrame, size),
|
||
|
sp: 0,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) IsEmpty() bool { return cs.sp == 0 }
|
||
|
|
||
|
func (cs *callFrameStack) Clear() {
|
||
|
cs.sp = 0
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) Push(v callFrame) { // +inline-start
|
||
|
cs.array[cs.sp] = v
|
||
|
cs.array[cs.sp].Idx = cs.sp
|
||
|
cs.sp++
|
||
|
} // +inline-end
|
||
|
|
||
|
func (cs *callFrameStack) Remove(sp int) {
|
||
|
psp := sp - 1
|
||
|
nsp := sp + 1
|
||
|
var pre *callFrame
|
||
|
var next *callFrame
|
||
|
if psp > 0 {
|
||
|
pre = &cs.array[psp]
|
||
|
}
|
||
|
if nsp < cs.sp {
|
||
|
next = &cs.array[nsp]
|
||
|
}
|
||
|
if next != nil {
|
||
|
next.Parent = pre
|
||
|
}
|
||
|
for i := sp; i+1 < cs.sp; i++ {
|
||
|
cs.array[i] = cs.array[i+1]
|
||
|
cs.array[i].Idx = i
|
||
|
cs.sp = i
|
||
|
}
|
||
|
cs.sp++
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) Sp() int {
|
||
|
return cs.sp
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) SetSp(sp int) {
|
||
|
cs.sp = sp
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) Last() *callFrame {
|
||
|
if cs.sp == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
return &cs.array[cs.sp-1]
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) At(sp int) *callFrame {
|
||
|
return &cs.array[sp]
|
||
|
}
|
||
|
|
||
|
func (cs *callFrameStack) Pop() *callFrame {
|
||
|
cs.sp--
|
||
|
return &cs.array[cs.sp]
|
||
|
}
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* registry {{{ */
|
||
|
|
||
|
type registry struct {
|
||
|
array []LValue
|
||
|
top int
|
||
|
alloc *allocator
|
||
|
}
|
||
|
|
||
|
func newRegistry(size int, alloc *allocator) *registry {
|
||
|
return ®istry{make([]LValue, size), 0, alloc}
|
||
|
}
|
||
|
|
||
|
func (rg *registry) SetTop(top int) {
|
||
|
oldtop := rg.top
|
||
|
rg.top = top
|
||
|
for i := oldtop; i < rg.top; i++ {
|
||
|
rg.array[i] = LNil
|
||
|
}
|
||
|
for i := rg.top; i < oldtop; i++ {
|
||
|
rg.array[i] = LNil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (rg *registry) Top() int {
|
||
|
return rg.top
|
||
|
}
|
||
|
|
||
|
func (rg *registry) Push(v LValue) {
|
||
|
rg.array[rg.top] = v
|
||
|
rg.top++
|
||
|
}
|
||
|
|
||
|
func (rg *registry) Pop() LValue {
|
||
|
v := rg.array[rg.top-1]
|
||
|
rg.array[rg.top-1] = LNil
|
||
|
rg.top--
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
func (rg *registry) Get(reg int) LValue {
|
||
|
return rg.array[reg]
|
||
|
}
|
||
|
|
||
|
func (rg *registry) CopyRange(regv, start, limit, n int) { // +inline-start
|
||
|
for i := 0; i < n; i++ {
|
||
|
if tidx := start + i; tidx >= rg.top || limit > -1 && tidx >= limit || tidx < 0 {
|
||
|
rg.array[regv+i] = LNil
|
||
|
} else {
|
||
|
rg.array[regv+i] = rg.array[tidx]
|
||
|
}
|
||
|
}
|
||
|
rg.top = regv + n
|
||
|
} // +inline-end
|
||
|
|
||
|
func (rg *registry) FillNil(regm, n int) { // +inline-start
|
||
|
for i := 0; i < n; i++ {
|
||
|
rg.array[regm+i] = LNil
|
||
|
}
|
||
|
rg.top = regm + n
|
||
|
} // +inline-end
|
||
|
|
||
|
func (rg *registry) Insert(value LValue, reg int) {
|
||
|
top := rg.Top()
|
||
|
if reg >= top {
|
||
|
rg.Set(reg, value)
|
||
|
return
|
||
|
}
|
||
|
top--
|
||
|
for ; top >= reg; top-- {
|
||
|
rg.Set(top+1, rg.Get(top))
|
||
|
}
|
||
|
rg.Set(reg, value)
|
||
|
}
|
||
|
|
||
|
func (rg *registry) Set(reg int, val LValue) {
|
||
|
rg.array[reg] = val
|
||
|
if reg >= rg.top {
|
||
|
rg.top = reg + 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (rg *registry) SetNumber(reg int, val LNumber) {
|
||
|
rg.array[reg] = rg.alloc.LNumber2I(val)
|
||
|
if reg >= rg.top {
|
||
|
rg.top = reg + 1
|
||
|
}
|
||
|
} /* }}} */
|
||
|
|
||
|
/* Global {{{ */
|
||
|
|
||
|
func newGlobal() *Global {
|
||
|
return &Global{
|
||
|
MainThread: nil,
|
||
|
Registry: newLTable(0, 32),
|
||
|
Global: newLTable(0, 64),
|
||
|
builtinMts: make(map[int]LValue),
|
||
|
tempFiles: make([]*os.File, 0, 10),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* }}} */
|
||
|
|
||
|
/* package local methods {{{ */
|
||
|
|
||
|
func panicWithTraceback(L *LState) {
|
||
|
err := newApiError(ApiErrorRun, L.Get(-1))
|
||
|
err.StackTrace = L.stackTrace(0)
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
func panicWithoutTraceback(L *LState) {
|
||
|
err := newApiError(ApiErrorRun, L.Get(-1))
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
func newLState(options Options) *LState {
|
||
|
al := newAllocator(32)
|
||
|
ls := &LState{
|
||
|
G: newGlobal(),
|
||
|
Parent: nil,
|
||
|
Panic: panicWithTraceback,
|
||
|
Dead: false,
|
||
|
Options: options,
|
||
|
|
||
|
stop: 0,
|
||
|
reg: newRegistry(options.RegistrySize, al),
|
||
|
stack: newCallFrameStack(options.CallStackSize),
|
||
|
alloc: al,
|
||
|
currentFrame: nil,
|
||
|
wrapped: false,
|
||
|
uvcache: nil,
|
||
|
hasErrorFunc: false,
|
||
|
mainLoop: mainLoop,
|
||
|
ctx: nil,
|
||
|
}
|
||
|
ls.Env = ls.G.Global
|
||
|
return ls
|
||
|
}
|
||
|
|
||
|
func (ls *LState) printReg() {
|
||
|
println("-------------------------")
|
||
|
println("thread:", ls)
|
||
|
println("top:", ls.reg.Top())
|
||
|
if ls.currentFrame != nil {
|
||
|
println("function base:", ls.currentFrame.Base)
|
||
|
println("return base:", ls.currentFrame.ReturnBase)
|
||
|
} else {
|
||
|
println("(vm not started)")
|
||
|
}
|
||
|
println("local base:", ls.currentLocalBase())
|
||
|
for i := 0; i < ls.reg.Top(); i++ {
|
||
|
println(i, ls.reg.Get(i).String())
|
||
|
}
|
||
|
println("-------------------------")
|
||
|
}
|
||
|
|
||
|
func (ls *LState) printCallStack() {
|
||
|
println("-------------------------")
|
||
|
for i := 0; i < ls.stack.Sp(); i++ {
|
||
|
print(i)
|
||
|
print(" ")
|
||
|
frame := ls.stack.At(i)
|
||
|
if frame == nil {
|
||
|
break
|
||
|
}
|
||
|
if frame.Fn.IsG {
|
||
|
println("IsG:", true, "Frame:", frame, "Fn:", frame.Fn)
|
||
|
} else {
|
||
|
println("IsG:", false, "Frame:", frame, "Fn:", frame.Fn, "pc:", frame.Pc)
|
||
|
}
|
||
|
}
|
||
|
println("-------------------------")
|
||
|
}
|
||
|
|
||
|
func (ls *LState) closeAllUpvalues() { // +inline-start
|
||
|
for cf := ls.currentFrame; cf != nil; cf = cf.Parent {
|
||
|
if !cf.Fn.IsG {
|
||
|
ls.closeUpvalues(cf.LocalBase)
|
||
|
}
|
||
|
}
|
||
|
} // +inline-end
|
||
|
|
||
|
func (ls *LState) raiseError(level int, format string, args ...interface{}) {
|
||
|
if !ls.hasErrorFunc {
|
||
|
ls.closeAllUpvalues()
|
||
|
}
|
||
|
message := format
|
||
|
if len(args) > 0 {
|
||
|
message = fmt.Sprintf(format, args...)
|
||
|
}
|
||
|
if level > 0 {
|
||
|
message = fmt.Sprintf("%v %v", ls.where(level-1, true), message)
|
||
|
}
|
||
|
ls.reg.Push(LString(message))
|
||
|
ls.Panic(ls)
|
||
|
}
|
||
|
|
||
|
func (ls *LState) findLocal(frame *callFrame, no int) string {
|
||
|
fn := frame.Fn
|
||
|
if !fn.IsG {
|
||
|
if name, ok := fn.LocalName(no, frame.Pc-1); ok {
|
||
|
return name
|
||
|
}
|
||
|
}
|
||
|
var top int
|
||
|
if ls.currentFrame == frame {
|
||
|
top = ls.reg.Top()
|
||
|
} else if frame.Idx+1 < ls.stack.Sp() {
|
||
|
top = ls.stack.At(frame.Idx + 1).Base
|
||
|
} else {
|
||
|
return ""
|
||
|
}
|
||
|
if top-frame.LocalBase >= no {
|
||
|
return "(*temporary)"
|
||
|
}
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
func (ls *LState) where(level int, skipg bool) string {
|
||
|
dbg, ok := ls.GetStack(level)
|
||
|
if !ok {
|
||
|
return ""
|
||
|
}
|
||
|
cf := dbg.frame
|
||
|
proto := cf.Fn.Proto
|
||
|
sourcename := "[G]"
|
||
|
if proto != nil {
|
||
|
sourcename = proto.SourceName
|
||
|
} else if skipg {
|
||
|
return ls.where(level+1, skipg)
|
||
|
}
|
||
|
line := ""
|
||
|
if proto != nil {
|
||
|
line = fmt.Sprintf("%v:", proto.DbgSourcePositions[cf.Pc-1])
|
||
|
}
|
||
|
return fmt.Sprintf("%v:%v", sourcename, line)
|
||
|
}
|
||
|
|
||
|
func (ls *LState) stackTrace(level int) string {
|
||
|
buf := []string{}
|
||
|
header := "stack traceback:"
|
||
|
if ls.currentFrame != nil {
|
||
|
i := 0
|
||
|
for dbg, ok := ls.GetStack(i); ok; dbg, ok = ls.GetStack(i) {
|
||
|
cf := dbg.frame
|
||
|
buf = append(buf, fmt.Sprintf("\t%v in %v", ls.Where(i), ls.formattedFrameFuncName(cf)))
|
||
|
if !cf.Fn.IsG && cf.TailCall > 0 {
|
||
|
for tc := cf.TailCall; tc > 0; tc-- {
|
||
|
buf = append(buf, "\t(tailcall): ?")
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
i++
|
||
|
}
|
||
|
}
|
||
|
buf = append(buf, fmt.Sprintf("\t%v: %v", "[G]", "?"))
|
||
|
buf = buf[intMax(0, intMin(level, len(buf))):len(buf)]
|
||
|
if len(buf) > 20 {
|
||
|
newbuf := make([]string, 0, 20)
|
||
|
newbuf = append(newbuf, buf[0:7]...)
|
||
|
newbuf = append(newbuf, "\t...")
|
||
|
newbuf = append(newbuf, buf[len(buf)-7:len(buf)]...)
|
||
|
buf = newbuf
|
||
|
}
|
||
|
return fmt.Sprintf("%s\n%s", header, strings.Join(buf, "\n"))
|
||
|
}
|
||
|
|
||
|
func (ls *LState) formattedFrameFuncName(fr *callFrame) string {
|
||
|
name, ischunk := ls.frameFuncName(fr)
|
||
|
if ischunk {
|
||
|
return name
|
||
|
}
|
||
|
if name[0] != '(' && name[0] != '<' {
|
||
|
return fmt.Sprintf("function '%s'", name)
|
||
|
}
|
||
|
return fmt.Sprintf("function %s", name)
|
||
|
}
|
||
|
|
||
|
func (ls *LState) rawFrameFuncName(fr *callFrame) string {
|
||
|
name, _ := ls.frameFuncName(fr)
|
||
|
return name
|
||
|
}
|
||
|
|
||
|
func (ls *LState) frameFuncName(fr *callFrame) (string, bool) {
|
||
|
frame := fr.Parent
|
||
|
if frame == nil {
|
||
|
if ls.Parent == nil {
|
||
|
return "main chunk", true
|
||
|
} else {
|
||
|
return "corountine", true
|
||
|
}
|
||
|
}
|
||
|
if !frame.Fn.IsG {
|
||
|
pc := frame.Pc - 1
|
||
|
for _, call := range frame.Fn.Proto.DbgCalls {
|
||
|
if call.Pc == pc {
|
||
|
name := call.Name
|
||
|
if (name == "?" || fr.TailCall > 0) && !fr.Fn.IsG {
|
||
|
name = fmt.Sprintf("<%v:%v>", fr.Fn.Proto.SourceName, fr.Fn.Proto.LineDefined)
|
||
|
}
|
||
|
return name, false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if !fr.Fn.IsG {
|
||
|
return fmt.Sprintf("<%v:%v>", fr.Fn.Proto.SourceName, fr.Fn.Proto.LineDefined), false
|
||
|
}
|
||
|
return "(anonymous)", false
|
||
|
}
|
||
|
|
||
|
func (ls *LState) isStarted() bool {
|
||
|
return ls.currentFrame != nil
|
||
|
}
|
||
|
|
||
|
func (ls *LState) kill() {
|
||
|
ls.Dead = true
|
||
|
}
|
||
|
|
||
|
func (ls *LState) indexToReg(idx int) int {
|
||
|
base := ls.currentLocalBase()
|
||
|
if idx > 0 {
|
||
|
return base + idx - 1
|
||
|
} else if idx == 0 {
|
||
|
return -1
|
||
|
} else {
|
||
|