1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840 |
- package lua
- import (
- "bufio"
- "fmt"
- "github.com/vmihailenco/msgpack"
- "github.com/yuin/gopher-lua/parse"
- "golang.org/x/net/context"
- "io"
- "io/ioutil"
- "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 {
- tidx := ls.reg.Top() + idx
- if tidx < base {
- return -1
- }
- return tidx
- }
- }
- func (ls *LState) currentLocalBase() int {
- base := 0
- if ls.currentFrame != nil {
- base = ls.currentFrame.LocalBase
- }
- return base
- }
- func (ls *LState) currentEnv() *LTable {
- return ls.Env
- /*
- if ls.currentFrame == nil {
- return ls.Env
- }
- return ls.currentFrame.Fn.Env
- */
- }
- func (ls *LState) rkValue(idx int) LValue {
- /*
- if OpIsK(idx) {
- return ls.currentFrame.Fn.Proto.Constants[opIndexK(idx)]
- }
- return ls.reg.Get(ls.currentFrame.LocalBase + idx)
- */
- if (idx & opBitRk) != 0 {
- return ls.currentFrame.Fn.Proto.Constants[idx & ^opBitRk]
- }
- return ls.reg.array[ls.currentFrame.LocalBase+idx]
- }
- func (ls *LState) rkString(idx int) string {
- if (idx & opBitRk) != 0 {
- return ls.currentFrame.Fn.Proto.stringConstants[idx & ^opBitRk]
- }
- return string(ls.reg.array[ls.currentFrame.LocalBase+idx].(LString))
- }
- func (ls *LState) closeUpvalues(idx int) { // +inline-start
- if ls.uvcache != nil {
- var prev *Upvalue
- for uv := ls.uvcache; uv != nil; uv = uv.next {
- if uv.index >= idx {
- if prev != nil {
- prev.next = nil
- } else {
- ls.uvcache = nil
- }
- uv.Close()
- }
- prev = uv
- }
- }
- } // +inline-end
- func (ls *LState) findUpvalue(idx int) *Upvalue {
- var prev *Upvalue
- var next *Upvalue
- if ls.uvcache != nil {
- for uv := ls.uvcache; uv != nil; uv = uv.next {
- if uv.index == idx {
- return uv
- }
- if uv.index > idx {
- next = uv
- break
- }
- prev = uv
- }
- }
- uv := &Upvalue{reg: ls.reg, index: idx, closed: false}
- if prev != nil {
- prev.next = uv
- } else {
- ls.uvcache = uv
- }
- if next != nil {
- uv.next = next
- }
- return uv
- }
- func (ls *LState) metatable(lvalue LValue, rawget bool) LValue {
- var metatable LValue = LNil
- switch obj := lvalue.(type) {
- case *LTable:
- metatable = obj.Metatable
- case *LUserData:
- metatable = obj.Metatable
- default:
- if table, ok := ls.G.builtinMts[int(obj.Type())]; ok {
- metatable = table
- }
- }
- if !rawget && metatable != LNil {
- oldmt := metatable
- if tb, ok := metatable.(*LTable); ok {
- metatable = tb.RawGetString("__metatable")
- if metatable == LNil {
- metatable = oldmt
- }
- }
- }
- return metatable
- }
- func (ls *LState) metaOp1(lvalue LValue, event string) LValue {
- if mt := ls.metatable(lvalue, true); mt != LNil {
- if tb, ok := mt.(*LTable); ok {
- return tb.RawGetString(event)
- }
- }
- return LNil
- }
- func (ls *LState) metaOp2(value1, value2 LValue, event string) LValue {
- if mt := ls.metatable(value1, true); mt != LNil {
- if tb, ok := mt.(*LTable); ok {
- if ret := tb.RawGetString(event); ret != LNil {
- return ret
- }
- }
- }
- if mt := ls.metatable(value2, true); mt != LNil {
- if tb, ok := mt.(*LTable); ok {
- return tb.RawGetString(event)
- }
- }
- return LNil
- }
- func (ls *LState) metaCall(lvalue LValue) (*LFunction, bool) {
- if fn, ok := lvalue.(*LFunction); ok {
- return fn, false
- }
- if fn, ok := ls.metaOp1(lvalue, "__call").(*LFunction); ok {
- return fn, true
- }
- return nil, false
- }
- func (ls *LState) initCallFrame(cf *callFrame) { // +inline-start
- if cf.Fn.IsG {
- ls.reg.SetTop(cf.LocalBase + cf.NArgs)
- } else {
- proto := cf.Fn.Proto
- nargs := cf.NArgs
- np := int(proto.NumParameters)
- for i := nargs; i < np; i++ {
- ls.reg.array[cf.LocalBase+i] = LNil
- nargs = np
- }
- if (proto.IsVarArg & VarArgIsVarArg) == 0 {
- if nargs < int(proto.NumUsedRegisters) {
- nargs = int(proto.NumUsedRegisters)
- }
- for i := np; i < nargs; i++ {
- ls.reg.array[cf.LocalBase+i] = LNil
- }
- ls.reg.top = cf.LocalBase + int(proto.NumUsedRegisters)
- } else {
- /* swap vararg positions:
- closure
- namedparam1 <- lbase
- namedparam2
- vararg1
- vararg2
- TO
- closure
- nil
- nil
- vararg1
- vararg2
- namedparam1 <- lbase
- namedparam2
- */
- nvarargs := nargs - np
- if nvarargs < 0 {
- nvarargs = 0
- }
- ls.reg.SetTop(cf.LocalBase + nargs + np)
- for i := 0; i < np; i++ {
- //ls.reg.Set(cf.LocalBase+nargs+i, ls.reg.Get(cf.LocalBase+i))
- ls.reg.array[cf.LocalBase+nargs+i] = ls.reg.array[cf.LocalBase+i]
- //ls.reg.Set(cf.LocalBase+i, LNil)
- ls.reg.array[cf.LocalBase+i] = LNil
- }
- if CompatVarArg {
- ls.reg.SetTop(cf.LocalBase + nargs + np + 1)
- if (proto.IsVarArg & VarArgNeedsArg) != 0 {
- argtb := newLTable(nvarargs, 0)
- for i := 0; i < nvarargs; i++ {
- argtb.RawSetInt(i+1, ls.reg.Get(cf.LocalBase+np+i))
- }
- argtb.RawSetString("n", LNumber(nvarargs))
- //ls.reg.Set(cf.LocalBase+nargs+np, argtb)
- ls.reg.array[cf.LocalBase+nargs+np] = argtb
- } else {
- ls.reg.array[cf.LocalBase+nargs+np] = LNil
- }
- }
- cf.LocalBase += nargs
- maxreg := cf.LocalBase + int(proto.NumUsedRegisters)
- ls.reg.SetTop(maxreg)
- }
- }
- } // +inline-end
- func (ls *LState) pushCallFrame(cf callFrame, fn LValue, meta bool) { // +inline-start
- if meta {
- cf.NArgs++
- ls.reg.Insert(fn, cf.LocalBase)
- }
- if cf.Fn == nil {
- ls.RaiseError("attempt to call a non-function object")
- }
- if ls.stack.sp == ls.Options.CallStackSize {
- ls.RaiseError("stack overflow")
- }
- // +inline-call ls.stack.Push cf
- newcf := ls.stack.Last()
- // +inline-call ls.initCallFrame newcf
- ls.currentFrame = newcf
- } // +inline-end
- func (ls *LState) callR(nargs, nret, rbase int) {
- base := ls.reg.Top() - nargs - 1
- if rbase < 0 {
- rbase = base
- }
- lv := ls.reg.Get(base)
- fn, meta := ls.metaCall(lv)
- ls.pushCallFrame(callFrame{
- Fn: fn,
- Pc: 0,
- Base: base,
- LocalBase: base + 1,
- ReturnBase: rbase,
- NArgs: nargs,
- NRet: nret,
- Parent: ls.currentFrame,
- TailCall: 0,
- }, lv, meta)
- if ls.G.MainThread == nil {
- ls.G.MainThread = ls
- ls.G.CurrentThread = ls
- ls.mainLoop(ls, nil)
- } else {
- ls.mainLoop(ls, ls.currentFrame)
- }
- if nret != MultRet {
- ls.reg.SetTop(rbase + nret)
- }
- }
- func (ls *LState) getField(obj LValue, key LValue) LValue {
- curobj := obj
- for i := 0; i < MaxTableGetLoop; i++ {
- tb, istable := curobj.(*LTable)
- if istable {
- ret := tb.RawGet(key)
- if ret != LNil {
- return ret
- }
- }
- metaindex := ls.metaOp1(curobj, "__index")
- if metaindex == LNil {
- if !istable {
- ls.RaiseError("attempt to index a non-table object(%v)", curobj.Type().String())
- }
- return LNil
- }
- if metaindex.Type() == LTFunction {
- ls.reg.Push(metaindex)
- ls.reg.Push(curobj)
- ls.reg.Push(key)
- ls.Call(2, 1)
- return ls.reg.Pop()
- } else {
- curobj = metaindex
- }
- }
- ls.RaiseError("too many recursions in gettable")
- return nil
- }
- func (ls *LState) getFieldString(obj LValue, key string) LValue {
- curobj := obj
- for i := 0; i < MaxTableGetLoop; i++ {
- tb, istable := curobj.(*LTable)
- if istable {
- ret := tb.RawGetString(key)
- if ret != LNil {
- return ret
- }
- }
- metaindex := ls.metaOp1(curobj, "__index")
- if metaindex == LNil {
- if !istable {
- ls.RaiseError("attempt to index a non-table object(%v)", curobj.Type().String())
- }
- return LNil
- }
- if metaindex.Type() == LTFunction {
- ls.reg.Push(metaindex)
- ls.reg.Push(curobj)
- ls.reg.Push(LString(key))
- ls.Call(2, 1)
- return ls.reg.Pop()
- } else {
- curobj = metaindex
- }
- }
- ls.RaiseError("too many recursions in gettable")
- return nil
- }
- func (ls *LState) setField(obj LValue, key LValue, value LValue) {
- curobj := obj
- for i := 0; i < MaxTableGetLoop; i++ {
- tb, istable := curobj.(*LTable)
- if istable {
- if tb.RawGet(key) != LNil {
- ls.RawSet(tb, key, value)
- return
- }
- }
- metaindex := ls.metaOp1(curobj, "__newindex")
- if metaindex == LNil {
- if !istable {
- ls.RaiseError("attempt to index a non-table object(%v)", curobj.Type().String())
- }
- ls.RawSet(tb, key, value)
- return
- }
- if metaindex.Type() == LTFunction {
- ls.reg.Push(metaindex)
- ls.reg.Push(curobj)
- ls.reg.Push(key)
- ls.reg.Push(value)
- ls.Call(3, 0)
- return
- } else {
- curobj = metaindex
- }
- }
- ls.RaiseError("too many recursions in settable")
- }
- func (ls *LState) setFieldString(obj LValue, key string, value LValue) {
- curobj := obj
- for i := 0; i < MaxTableGetLoop; i++ {
- tb, istable := curobj.(*LTable)
- if istable {
- if tb.RawGetString(key) != LNil {
- tb.RawSetString(key, value)
- return
- }
- }
- metaindex := ls.metaOp1(curobj, "__newindex")
- if metaindex == LNil {
- if !istable {
- ls.RaiseError("attempt to index a non-table object(%v)", curobj.Type().String())
- }
- tb.RawSetString(key, value)
- return
- }
- if metaindex.Type() == LTFunction {
- ls.reg.Push(metaindex)
- ls.reg.Push(curobj)
- ls.reg.Push(LString(key))
- ls.reg.Push(value)
- ls.Call(3, 0)
- return
- } else {
- curobj = metaindex
- }
- }
- ls.RaiseError("too many recursions in settable")
- }
- /* }}} */
- /* api methods {{{ */
- func NewState(opts ...Options) *LState {
- var ls *LState
- if len(opts) == 0 {
- ls = newLState(Options{
- CallStackSize: CallStackSize,
- RegistrySize: RegistrySize,
- })
- ls.OpenLibs()
- } else {
- if opts[0].CallStackSize < 1 {
- opts[0].CallStackSize = CallStackSize
- }
- if opts[0].RegistrySize < 128 {
- opts[0].RegistrySize = RegistrySize
- }
- ls = newLState(opts[0])
- if !opts[0].SkipOpenLibs {
- ls.OpenLibs()
- }
- }
- return ls
- }
- func (ls *LState) Close() {
- atomic.AddInt32(&ls.stop, 1)
- for _, file := range ls.G.tempFiles {
- // ignore errors in these operations
- file.Close()
- os.Remove(file.Name())
- }
- }
- /* registry operations {{{ */
- func (ls *LState) GetTop() int {
- return ls.reg.Top() - ls.currentLocalBase()
- }
- func (ls *LState) SetTop(idx int) {
- base := ls.currentLocalBase()
- newtop := ls.indexToReg(idx) + 1
- if newtop < base {
- ls.reg.SetTop(base)
- } else {
- ls.reg.SetTop(newtop)
- }
- }
- func (ls *LState) Replace(idx int, value LValue) {
- base := ls.currentLocalBase()
- if idx > 0 {
- reg := base + idx - 1
- if reg < ls.reg.Top() {
- ls.reg.Set(reg, value)
- }
- } else if idx == 0 {
- } else if idx > RegistryIndex {
- if tidx := ls.reg.Top() + idx; tidx >= base {
- ls.reg.Set(tidx, value)
- }
- } else {
- switch idx {
- case RegistryIndex:
- if tb, ok := value.(*LTable); ok {
- ls.G.Registry = tb
- } else {
- ls.RaiseError("registry must be a table(%v)", value.Type().String())
- }
- case EnvironIndex:
- if ls.currentFrame == nil {
- ls.RaiseError("no calling environment")
- }
- if tb, ok := value.(*LTable); ok {
- ls.currentFrame.Fn.Env = tb
- } else {
- ls.RaiseError("environment must be a table(%v)", value.Type().String())
- }
- case GlobalsIndex:
- if tb, ok := value.(*LTable); ok {
- ls.G.Global = tb
- } else {
- ls.RaiseError("_G must be a table(%v)", value.Type().String())
- }
- default:
- fn := ls.currentFrame.Fn
- index := GlobalsIndex - idx - 1
- if index < len(fn.Upvalues) {
- fn.Upvalues[index].SetValue(value)
- }
- }
- }
- }
- func (ls *LState) Get(idx int) LValue {
- base := ls.currentLocalBase()
- if idx > 0 {
- reg := base + idx - 1
- if reg < ls.reg.Top() {
- return ls.reg.Get(reg)
- }
- return LNil
- } else if idx == 0 {
- return LNil
- } else if idx > RegistryIndex {
- tidx := ls.reg.Top() + idx
- if tidx < base {
- return LNil
- }
- return ls.reg.Get(tidx)
- } else {
- switch idx {
- case RegistryIndex:
- return ls.G.Registry
- case EnvironIndex:
- if ls.currentFrame == nil {
- return ls.Env
- }
- return ls.currentFrame.Fn.Env
- case GlobalsIndex:
- return ls.G.Global
- default:
- fn := ls.currentFrame.Fn
- index := GlobalsIndex - idx - 1
- if index < len(fn.Upvalues) {
- return fn.Upvalues[index].Value()
- }
- return LNil
- }
- }
- return LNil
- }
- func (ls *LState) Push(value LValue) {
- ls.reg.Push(value)
- }
- func (ls *LState) Pop(n int) {
- for i := 0; i < n; i++ {
- if ls.GetTop() == 0 {
- ls.RaiseError("register underflow")
- }
- ls.reg.Pop()
- }
- }
- func (ls *LState) Insert(value LValue, index int) {
- reg := ls.indexToReg(index)
- top := ls.reg.Top()
- if reg >= top {
- ls.reg.Set(reg, value)
- return
- }
- if reg <= ls.currentLocalBase() {
- reg = ls.currentLocalBase()
- }
- top--
- for ; top >= reg; top-- {
- ls.reg.Set(top+1, ls.reg.Get(top))
- }
- ls.reg.Set(reg, value)
- }
- func (ls *LState) Remove(index int) {
- reg := ls.indexToReg(index)
- top := ls.reg.Top()
- switch {
- case reg >= top:
- return
- case reg < ls.currentLocalBase():
- return
- case reg == top-1:
- ls.Pop(1)
- return
- }
- for i := reg; i < top-1; i++ {
- ls.reg.Set(i, ls.reg.Get(i+1))
- }
- ls.reg.SetTop(top - 1)
- }
- /* }}} */
- /* object allocation {{{ */
- func (ls *LState) NewTable() *LTable {
- return newLTable(defaultArrayCap, defaultHashCap)
- }
- func (ls *LState) CreateTable(acap, hcap int) *LTable {
- return newLTable(acap, hcap)
- }
- // NewThread returns a new LState that shares with the original state all global objects.
- // 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.
- func (ls *LState) NewThread() (*LState, context.CancelFunc) {
- thread := newLState(ls.Options)
- thread.G = ls.G
- thread.Env = ls.Env
- var f context.CancelFunc = nil
- if ls.ctx != nil {
- thread.mainLoop = mainLoopWithContext
- thread.ctx, f = context.WithCancel(ls.ctx)
- }
- return thread, f
- }
- func (ls *LState) NewUserData() *LUserData {
- return &LUserData{
- Env: ls.currentEnv(),
- Metatable: LNil,
- }
- }
- func (ls *LState) NewFunction(fn LGFunction) *LFunction {
- return newLFunctionG(fn, ls.currentEnv(), 0)
- }
- func (ls *LState) NewClosure(fn LGFunction, upvalues ...LValue) *LFunction {
- cl := newLFunctionG(fn, ls.currentEnv(), len(upvalues))
- for i, lv := range upvalues {
- cl.Upvalues[i] = &Upvalue{}
- cl.Upvalues[i].Close()
- cl.Upvalues[i].SetValue(lv)
- }
- return cl
- }
- /* }}} */
- /* toType {{{ */
- func (ls *LState) ToBool(n int) bool {
- return LVAsBool(ls.Get(n))
- }
- func (ls *LState) ToInt(n int) int {
- if lv, ok := ls.Get(n).(LNumber); ok {
- return int(lv)
- }
- if lv, ok := ls.Get(n).(LString); ok {
- if num, err := parseNumber(string(lv)); err == nil {
- return int(num)
- }
- }
- return 0
- }
- func (ls *LState) ToInt64(n int) int64 {
- if lv, ok := ls.Get(n).(LNumber); ok {
- return int64(lv)
- }
- if lv, ok := ls.Get(n).(LString); ok {
- if num, err := parseNumber(string(lv)); err == nil {
- return int64(num)
- }
- }
- return 0
- }
- func (ls *LState) ToNumber(n int) LNumber {
- return LVAsNumber(ls.Get(n))
- }
- func (ls *LState) ToString(n int) string {
- return LVAsString(ls.Get(n))
- }
- func (ls *LState) ToTable(n int) *LTable {
- if lv, ok := ls.Get(n).(*LTable); ok {
- return lv
- }
- return nil
- }
- func (ls *LState) ToFunction(n int) *LFunction {
- if lv, ok := ls.Get(n).(*LFunction); ok {
- return lv
- }
- return nil
- }
- func (ls *LState) ToUserData(n int) *LUserData {
- if lv, ok := ls.Get(n).(*LUserData); ok {
- return lv
- }
- return nil
- }
- func (ls *LState) ToThread(n int) *LState {
- if lv, ok := ls.Get(n).(*LState); ok {
- return lv
- }
- return nil
- }
- /* }}} */
- /* error & debug operations {{{ */
- // This function is equivalent to luaL_error( http://www.lua.org/manual/5.1/manual.html#luaL_error ).
- func (ls *LState) RaiseError(format string, args ...interface{}) {
- ls.raiseError(1, format, args...)
- }
- // This function is equivalent to lua_error( http://www.lua.org/manual/5.1/manual.html#lua_error ).
- func (ls *LState) Error(lv LValue, level int) {
- if str, ok := lv.(LString); ok {
- ls.raiseError(level, string(str))
- } else {
- if !ls.hasErrorFunc {
- ls.closeAllUpvalues()
- }
- ls.Push(lv)
- ls.Panic(ls)
- }
- }
- func (ls *LState) GetInfo(what string, dbg *Debug, fn LValue) (LValue, error) {
- if !strings.HasPrefix(what, ">") {
- fn = dbg.frame.Fn
- } else {
- what = what[1:]
- }
- f, ok := fn.(*LFunction)
- if !ok {
- return LNil, newApiErrorS(ApiErrorRun, "can not get debug info(an object in not a function)")
- }
- retfn := false
- for _, c := range what {
- switch c {
- case 'f':
- retfn = true
- case 'S':
- if dbg.frame != nil && dbg.frame.Parent == nil {
- dbg.What = "main"
- } else if f.IsG {
- dbg.What = "G"
- } else if dbg.frame != nil && dbg.frame.TailCall > 0 {
- dbg.What = "tail"
- } else {
- dbg.What = "Lua"
- }
- if !f.IsG {
- dbg.Source = f.Proto.SourceName
- dbg.LineDefined = f.Proto.LineDefined
- dbg.LastLineDefined = f.Proto.LastLineDefined
- }
- case 'l':
- if !f.IsG && dbg.frame != nil {
- if dbg.frame.Pc > 0 {
- dbg.CurrentLine = f.Proto.DbgSourcePositions[dbg.frame.Pc-1]
- }
- } else {
- dbg.CurrentLine = -1
- }
- case 'u':
- dbg.NUpvalues = len(f.Upvalues)
- case 'n':
- if dbg.frame != nil {
- dbg.Name = ls.rawFrameFuncName(dbg.frame)
- }
- default:
- return LNil, newApiErrorS(ApiErrorRun, "invalid what: "+string(c))
- }
- }
- if retfn {
- return f, nil
- }
- return LNil, nil
- }
- func (ls *LState) GetStack(level int) (*Debug, bool) {
- frame := ls.currentFrame
- for ; level > 0 && frame != nil; frame = frame.Parent {
- level--
- if !frame.Fn.IsG {
- level -= frame.TailCall
- }
- }
- if level == 0 && frame != nil {
- return &Debug{frame: frame}, true
- } else if level < 0 && ls.stack.Sp() > 0 {
- return &Debug{frame: ls.stack.At(0)}, true
- }
- return &Debug{}, false
- }
- func (ls *LState) GetLocal(dbg *Debug, no int) (string, LValue) {
- frame := dbg.frame
- if name := ls.findLocal(frame, no); len(name) > 0 {
- return name, ls.reg.Get(frame.LocalBase + no - 1)
- }
- return "", LNil
- }
- func (ls *LState) SetLocal(dbg *Debug, no int, lv LValue) string {
- frame := dbg.frame
- if name := ls.findLocal(frame, no); len(name) > 0 {
- ls.reg.Set(frame.LocalBase+no-1, lv)
- return name
- }
- return ""
- }
- func (ls *LState) GetUpvalue(fn *LFunction, no int) (string, LValue) {
- if fn.IsG {
- return "", LNil
- }
- no--
- if no >= 0 && no < len(fn.Upvalues) {
- return fn.Proto.DbgUpvalues[no], fn.Upvalues[no].Value()
- }
- return "", LNil
- }
- func (ls *LState) SetUpvalue(fn *LFunction, no int, lv LValue) string {
- if fn.IsG {
- return ""
- }
- no--
- if no >= 0 && no < len(fn.Upvalues) {
- fn.Upvalues[no].SetValue(lv)
- return fn.Proto.DbgUpvalues[no]
- }
- return ""
- }
- /* }}} */
- /* env operations {{{ */
- func (ls *LState) GetFEnv(obj LValue) LValue {
- switch lv := obj.(type) {
- case *LFunction:
- return lv.Env
- case *LUserData:
- return lv.Env
- case *LState:
- return lv.Env
- }
- return LNil
- }
- func (ls *LState) SetFEnv(obj LValue, env LValue) {
- tb, ok := env.(*LTable)
- if !ok {
- ls.RaiseError("cannot use %v as an environment", env.Type().String())
- }
- switch lv := obj.(type) {
- case *LFunction:
- lv.Env = tb
- case *LUserData:
- lv.Env = tb
- case *LState:
- lv.Env = tb
- }
- /* do nothing */
- }
- /* }}} */
- /* table operations {{{ */
- func (ls *LState) RawGet(tb *LTable, key LValue) LValue {
- return tb.RawGet(key)
- }
- func (ls *LState) RawGetInt(tb *LTable, key int) LValue {
- return tb.RawGetInt(key)
- }
- func (ls *LState) GetField(obj LValue, skey string) LValue {
- return ls.getFieldString(obj, skey)
- }
- func (ls *LState) GetTable(obj LValue, key LValue) LValue {
- return ls.getField(obj, key)
- }
- func (ls *LState) RawSet(tb *LTable, key LValue, value LValue) {
- if n, ok := key.(LNumber); ok && math.IsNaN(float64(n)) {
- ls.RaiseError("table index is NaN")
- } else if key == LNil {
- ls.RaiseError("table index is nil")
- }
- tb.RawSet(key, value)
- }
- func (ls *LState) RawSetInt(tb *LTable, key int, value LValue) {
- tb.RawSetInt(key, value)
- }
- func (ls *LState) SetField(obj LValue, key string, value LValue) {
- ls.setFieldString(obj, key, value)
- }
- func (ls *LState) SetTable(obj LValue, key LValue, value LValue) {
- ls.setField(obj, key, value)
- }
- func (ls *LState) ForEach(tb *LTable, cb func(LValue, LValue)) {
- tb.ForEach(cb)
- }
- func (ls *LState) GetGlobal(name string) LValue {
- return ls.GetField(ls.Get(GlobalsIndex), name)
- }
- func (ls *LState) SetGlobal(name string, value LValue) {
- ls.SetField(ls.Get(GlobalsIndex), name, value)
- }
- func (ls *LState) Next(tb *LTable, key LValue) (LValue, LValue) {
- return tb.Next(key)
- }
- /* }}} */
- /* unary operations {{{ */
- func (ls *LState) ObjLen(v1 LValue) int {
- if v1.Type() == LTString {
- return len(string(v1.(LString)))
- }
- op := ls.metaOp1(v1, "__len")
- if op.Type() == LTFunction {
- ls.Push(op)
- ls.Push(v1)
- ls.Call(1, 1)
- ret := ls.reg.Pop()
- if ret.Type() == LTNumber {
- return int(ret.(LNumber))
- }
- } else if v1.Type() == LTTable {
- return v1.(*LTable).Len()
- }
- return 0
- }
- /* }}} */
- /* binary operations {{{ */
- func (ls *LState) Concat(values ...LValue) string {
- top := ls.reg.Top()
- for _, value := range values {
- ls.reg.Push(value)
- }
- ret := stringConcat(ls, len(values), ls.reg.Top()-1)
- ls.reg.SetTop(top)
- return LVAsString(ret)
- }
- func (ls *LState) LessThan(lhs, rhs LValue) bool {
- return lessThan(ls, lhs, rhs)
- }
- func (ls *LState) Equal(lhs, rhs LValue) bool {
- return equals(ls, lhs, rhs, false)
- }
- func (ls *LState) RawEqual(lhs, rhs LValue) bool {
- return equals(ls, lhs, rhs, true)
- }
- /* }}} */
- /* register operations {{{ */
- func (ls *LState) Register(name string, fn LGFunction) {
- ls.SetGlobal(name, ls.NewFunction(fn))
- }
- /* }}} */
- /* load and function call operations {{{ */
- func container2proto(container *functionProtoContainer) *FunctionProto {
- protos := []*FunctionProto{}
- for _, c := range container.FunctionPrototypes {
- protos = append(protos, container2proto(c))
- }
- constants := []LValue{}
- stringConstants := []string{}
- for _, c := range container.Constants {
- if s, ok := c.(string); ok {
- constants = append(constants, LString(s))
- stringConstants = append(stringConstants, s)
- } else {
- constants = append(constants, LNumber(c.(float64)))
- }
- }
- return &FunctionProto{
- SourceName: container.SourceName,
- LineDefined: container.LineDefined,
- LastLineDefined: container.LastLineDefined,
- NumUpvalues: container.NumUpvalues,
- NumParameters: container.NumParameters,
- IsVarArg: container.IsVarArg,
- NumUsedRegisters: container.NumUsedRegisters,
- Code: container.Code,
- Constants: constants,
- FunctionPrototypes: protos,
- DbgSourcePositions: container.DbgSourcePositions,
- DbgLocals: container.DbgLocals,
- DbgCalls: container.DbgCalls,
- DbgUpvalues: container.DbgUpvalues,
- stringConstants: stringConstants,
- }
- }
- func (ls *LState) Load(reader io.Reader, name string) (*LFunction, error) {
- b := bufio.NewReader(reader)
- if sbuf, err := b.Peek(4); err == nil {
- if string(sbuf) == dumpSignature {
- b.Discard(4)
- buf, err := ioutil.ReadAll(b)
- if err != nil {
- ls.RaiseError(err.Error())
- }
- var container functionProtoContainer
- if err := msgpack.Unmarshal(buf, &container); err != nil {
- ls.RaiseError(err.Error())
- }
- return newLFunctionL(container2proto(&container), ls.currentEnv(), 0), nil
- }
- }
- chunk, err := parse.Parse(b, name)
- if err != nil {
- return nil, newApiErrorE(ApiErrorSyntax, err)
- }
- proto, err := Compile(chunk, name)
- if err != nil {
- return nil, newApiErrorE(ApiErrorSyntax, err)
- }
- return newLFunctionL(proto, ls.currentEnv(), 0), nil
- }
- func (ls *LState) Call(nargs, nret int) {
- ls.callR(nargs, nret, -1)
- }
- func (ls *LState) PCall(nargs, nret int, errfunc *LFunction) (err error) {
- err = nil
- sp := ls.stack.Sp()
- base := ls.reg.Top() - nargs - 1
- oldpanic := ls.Panic
- ls.Panic = panicWithoutTraceback
- if errfunc != nil {
- ls.hasErrorFunc = true
- }
- defer func() {
- ls.Panic = oldpanic
- ls.hasErrorFunc = false
- rcv := recover()
- if rcv != nil {
- if _, ok := rcv.(*ApiError); !ok {
- err = newApiErrorS(ApiErrorPanic, fmt.Sprint(rcv))
- if ls.Options.IncludeGoStackTrace {
- buf := make([]byte, 4096)
- runtime.Stack(buf, false)
- err.(*ApiError).StackTrace = strings.Trim(string(buf), "\000") + "\n" + ls.stackTrace(0)
- }
- } else {
- err = rcv.(*ApiError)
- }
- if errfunc != nil {
- ls.Push(errfunc)
- ls.Push(err.(*ApiError).Object)
- ls.Panic = panicWithoutTraceback
- defer func() {
- ls.Panic = oldpanic
- rcv := recover()
- if rcv != nil {
- if _, ok := rcv.(*ApiError); !ok {
- err = newApiErrorS(ApiErrorPanic, fmt.Sprint(rcv))
- if ls.Options.IncludeGoStackTrace {
- buf := make([]byte, 4096)
- runtime.Stack(buf, false)
- err.(*ApiError).StackTrace = strings.Trim(string(buf), "\000") + ls.stackTrace(0)
- }
- } else {
- err = rcv.(*ApiError)
- err.(*ApiError).StackTrace = ls.stackTrace(0)
- }
- }
- }()
- ls.Call(1, 1)
- err = newApiError(ApiErrorError, ls.Get(-1))
- } else if len(err.(*ApiError).StackTrace) == 0 {
- err.(*ApiError).StackTrace = ls.stackTrace(0)
- }
- ls.reg.SetTop(base)
- }
- ls.stack.SetSp(sp)
- if sp == 0 {
- ls.currentFrame = nil
- }
- }()
- ls.Call(nargs, nret)
- return
- }
- func (ls *LState) GPCall(fn LGFunction, data LValue) error {
- ls.Push(newLFunctionG(fn, ls.currentEnv(), 0))
- ls.Push(data)
- return ls.PCall(1, MultRet, nil)
- }
- func (ls *LState) CallByParam(cp P, args ...LValue) error {
- ls.Push(cp.Fn)
- for _, arg := range args {
- ls.Push(arg)
- }
- if cp.Protect {
- return ls.PCall(len(args), cp.NRet, cp.Handler)
- }
- ls.Call(len(args), cp.NRet)
- return nil
- }
- /* }}} */
- /* metatable operations {{{ */
- func (ls *LState) GetMetatable(obj LValue) LValue {
- return ls.metatable(obj, false)
- }
- func (ls *LState) SetMetatable(obj LValue, mt LValue) {
- switch mt.(type) {
- case *LNilType, *LTable:
- default:
- ls.RaiseError("metatable must be a table or nil, but got %v", mt.Type().String())
- }
- switch v := obj.(type) {
- case *LTable:
- v.Metatable = mt
- case *LUserData:
- v.Metatable = mt
- default:
- ls.G.builtinMts[int(obj.Type())] = mt
- }
- }
- /* }}} */
- /* coroutine operations {{{ */
- func (ls *LState) Status(th *LState) string {
- status := "suspended"
- if th.Dead {
- status = "dead"
- } else if ls.G.CurrentThread == th {
- status = "running"
- } else if ls.Parent == th {
- status = "normal"
- }
- return status
- }
- func (ls *LState) Resume(th *LState, fn *LFunction, args ...LValue) (ResumeState, error, []LValue) {
- isstarted := th.isStarted()
- if !isstarted {
- base := 0
- th.stack.Push(callFrame{
- Fn: fn,
- Pc: 0,
- Base: base,
- LocalBase: base + 1,
- ReturnBase: base,
- NArgs: 0,
- NRet: MultRet,
- Parent: nil,
- TailCall: 0,
- })
- }
- if ls.G.CurrentThread == th {
- return ResumeError, newApiErrorS(ApiErrorRun, "can not resume a running thread"), nil
- }
- if th.Dead {
- return ResumeError, newApiErrorS(ApiErrorRun, "can not resume a dead thread"), nil
- }
- th.Parent = ls
- ls.G.CurrentThread = th
- if !isstarted {
- cf := th.stack.Last()
- th.currentFrame = cf
- th.SetTop(0)
- for _, arg := range args {
- th.Push(arg)
- }
- cf.NArgs = len(args)
- th.initCallFrame(cf)
- th.Panic = panicWithoutTraceback
- } else {
- for _, arg := range args {
- th.Push(arg)
- }
- }
- top := ls.GetTop()
- threadRun(th)
- haserror := LVIsFalse(ls.Get(top + 1))
- ret := make([]LValue, 0, ls.GetTop())
- for idx := top + 2; idx <= ls.GetTop(); idx++ {
- ret = append(ret, ls.Get(idx))
- }
- if len(ret) == 0 {
- ret = append(ret, LNil)
- }
- ls.SetTop(top)
- if haserror {
- return ResumeError, newApiError(ApiErrorRun, ret[0]), nil
- } else if th.stack.IsEmpty() {
- return ResumeOK, nil, ret
- }
- return ResumeYield, nil, ret
- }
- func (ls *LState) Yield(values ...LValue) int {
- ls.SetTop(0)
- for _, lv := range values {
- ls.Push(lv)
- }
- return -1
- }
- func (ls *LState) XMoveTo(other *LState, n int) {
- if ls == other {
- return
- }
- top := ls.GetTop()
- n = intMin(n, top)
- for i := n; i > 0; i-- {
- other.Push(ls.Get(top - i + 1))
- }
- ls.SetTop(top - n)
- }
- /* }}} */
- /* GopherLua original APIs {{{ */
- // Set maximum memory size. This function can only be called from the main thread.
- func (ls *LState) SetMx(mx int) {
- if ls.Parent != nil {
- ls.RaiseError("sub threads are not allowed to set a memory limit")
- }
- go func() {
- limit := uint64(mx * 1024 * 1024) //MB
- var s runtime.MemStats
- for ls.stop == 0 {
- runtime.ReadMemStats(&s)
- if s.Alloc >= limit {
- fmt.Println("out of memory")
- os.Exit(3)
- }
- time.Sleep(100 * time.Millisecond)
- }
- }()
- }
- // SetContext set a context ctx to this LState. The provided ctx must be non-nil.
- func (ls *LState) SetContext(ctx context.Context) {
- ls.mainLoop = mainLoopWithContext
- ls.ctx = ctx
- }
- // Context returns the LState's context. To change the context, use WithContext.
- func (ls *LState) Context() context.Context {
- return ls.ctx
- }
- // RemoveContext removes the context associated with this LState and returns this context.
- func (ls *LState) RemoveContext() context.Context {
- oldctx := ls.ctx
- ls.mainLoop = mainLoop
- ls.ctx = nil
- return oldctx
- }
- // Converts the Lua value at the given acceptable index to the chan LValue.
- func (ls *LState) ToChannel(n int) chan LValue {
- if lv, ok := ls.Get(n).(LChannel); ok {
- return (chan LValue)(lv)
- }
- return nil
- }
- /* }}} */
- /* }}} */
- //
|