func (l *State) ToInteger(index int) (int, bool) {
	if n, ok := l.toNumber(l.indexToValue(index)); ok {
		return int(n), true
	}
	return 0, false
}
ToInteger converts the Lua value at index into a signed integer. The Lua
value must be a number, or a string convertible to a number.

If the number is not an integer, it is truncated in some non-specified way.

If the operation failed, the second return value will be false.

http://www.lua.org/manual/5.2/manual.html#lua_tointegerx
package lua
import (
	"errors"
	"fmt"
	"io"
	"math"
	"strings"
)
const MultipleReturns = -1
const (
	HookCall, MaskCall = iota, 1 << iota
	HookReturn, MaskReturn
	HookLine, MaskLine
	HookCount, MaskCount
	HookTailCall, MaskTailCall
)
var (
	SyntaxError = errors.New("syntax error")
	MemoryError = errors.New("memory error")
	ErrorError  = errors.New("error within the error handler")
	FileError   = errors.New("file error")
)
type RuntimeError string
func (r RuntimeError) Error() string { return "runtime error: " + string(r) }
type Type int
const (
	TypeNil Type = iota
	TypeBoolean
	TypeLightUserData
	TypeNumber
	TypeString
	TypeTable
	TypeFunction
	TypeUserData
	TypeThread
	TypeCount
	TypeNone = TypeNil - 1
)
type Operator int
const (
	OpAdd        Operator = iota  
	OpSub                         
	OpMul                         
	OpDiv                         
	OpMod                         
	OpPow                         
	OpUnaryMinus                  
)
type ComparisonOperator int
const (
	OpEq ComparisonOperator = iota  
	OpLT                            
	OpLE                            
)
const (
	RegistryIndex = firstPseudoIndex
	RegistryIndexMainThread = iota
	RegistryIndexGlobals
)
const Signature = "\033Lua"
const MinStack = 20
const (
	VersionMajor  = 5
	VersionMinor  = 2
	VersionNumber = 502
	VersionString = "Lua " + string('0'+VersionMajor) + "." + string('0'+VersionMinor)
)
type RegistryFunction struct {
	Name     string
	Function Function
}
type Debug struct {
	Event int
	Name string
	NameKind string
	What string
	Source string
	ShortSource string
	CurrentLine int
	LineDefined int
	LastLineDefined int
	UpValueCount int
	ParameterCount int
	IsVarArg bool
	IsTailCall bool
	callInfo *callInfo
}
type Hook func(state *State, activationRecord Debug)
type Function func(state *State) int
type pc int
type callStatus byte
const (
	callStatusLua                callStatus = 1 << iota  
	callStatusHooked                                     
	callStatusReentry                                    
	callStatusYielded                                    
	callStatusYieldableProtected                         
	callStatusError                                      
	callStatusTail                                       
	callStatusHookYielded                                
)
type State struct {
	error                 error
	shouldYield           bool
	top                   int  
	global                *globalState
	callInfo              *callInfo  
	oldPC                 pc         
	stackLast             int        
	stack                 []value
	nonYieldableCallCount int
	nestedGoCallCount     int
	hookMask              byte
	allowHook             bool
	internalHook          bool
	baseHookCount         int
	hookCount             int
	hooker                Hook
	upValues              *openUpValue
	errorFunction         int       
	baseCallInfo          callInfo  
	protectFunction       func()
}
type globalState struct {
	mainThread         *State
	tagMethodNames     [tmCount]string
	metaTables         [TypeCount]*table  
	registry           *table
	panicFunction      Function  
	version            *float64  
	memoryErrorMessage string
}
func (g *globalState) metaTable(o value) *table {
	var t Type
	switch o.(type) {
	case nil:
		t = TypeNil
	case bool:
		t = TypeBoolean
	case float64:
		t = TypeNumber
	case string:
		t = TypeString
	case *table:
		t = TypeTable
	case *goFunction:
		t = TypeFunction
	case closure:
		t = TypeFunction
	case *userData:
		t = TypeUserData
	case *State:
		t = TypeThread
	default:
		return nil
	}
	return g.metaTables[t]
}
func (l *State) adjustResults(resultCount int) {
	if resultCount == MultipleReturns && l.callInfo.top < l.top {
		l.callInfo.setTop(l.top)
	}
}
func (l *State) apiIncrementTop() {
	l.top++
	if apiCheck && l.top > l.callInfo.top {
		panic("stack overflow")
	}
}
func (l *State) apiPush(v value) {
	l.push(v)
	if apiCheck && l.top > l.callInfo.top {
		panic("stack overflow")
	}
}
func (l *State) checkElementCount(n int) {
	if apiCheck && n >= l.top-l.callInfo.function {
		panic("not enough elements in the stack")
	}
}
func (l *State) checkResults(argCount, resultCount int) {
	if apiCheck && resultCount != MultipleReturns && l.callInfo.top-l.top < resultCount-argCount {
		panic("results from function overflow current stack size")
	}
}
func (l *State) Context() (int, bool, error) {
	if l.callInfo.isCallStatus(callStatusYielded) {
		return l.callInfo.context, l.callInfo.shouldYield, l.callInfo.error
	}
	return 0, false, nil
}
func (l *State) CallWithContinuation(argCount, resultCount, context int, continuation Function) {
	if apiCheck && continuation != nil && l.callInfo.isLua() {
		panic("cannot use continuations inside hooks")
	}
	l.checkElementCount(argCount + 1)
	if apiCheck && l.shouldYield {
		panic("cannot do calls on non-normal thread")
	}
	l.checkResults(argCount, resultCount)
	f := l.top - (argCount + 1)
	if continuation != nil && l.nonYieldableCallCount == 0 {  
		l.callInfo.continuation = continuation
		l.callInfo.context = context
		l.call(f, resultCount, true)  
	} else {  
		l.call(f, resultCount, false)  
	}
	l.adjustResults(resultCount)
}
func (l *State) ProtectedCall(argCount, resultCount, errorFunction int) error {
	return l.ProtectedCallWithContinuation(argCount, resultCount, errorFunction, 0, nil)
}
func (l *State) ProtectedCallWithContinuation(argCount, resultCount, errorFunction, context int, continuation Function) (err error) {
	if apiCheck && continuation != nil && l.callInfo.isLua() {
		panic("cannot use continuations inside hooks")
	}
	l.checkElementCount(argCount + 1)
	if apiCheck && l.shouldYield {
		panic("cannot do calls on non-normal thread")
	}
	l.checkResults(argCount, resultCount)
	if errorFunction != 0 {
		apiCheckStackIndex(errorFunction, l.indexToValue(errorFunction))
		errorFunction = l.AbsIndex(errorFunction)
	}
	f := l.top - (argCount + 1)
	if continuation == nil || l.nonYieldableCallCount > 0 {
		err = l.protectedCall(func() { l.call(f, resultCount, false) }, f, errorFunction)
	} else {
		c := l.callInfo
		c.continuation, c.context, c.extra, c.oldAllowHook, c.oldErrorFunction = continuation, context, f, l.allowHook, l.errorFunction
		l.errorFunction = errorFunction
		l.callInfo.setCallStatus(callStatusYieldableProtected)
		l.call(f, resultCount, true)
		l.callInfo.clearCallStatus(callStatusYieldableProtected)
		l.errorFunction = c.oldErrorFunction
	}
	l.adjustResults(resultCount)
	return
}
func (l *State) Load(r io.Reader, chunkName string, mode string) error {
	if chunkName == "" {
		chunkName = "?"
	}
	if err := protectedParser(l, r, chunkName, mode); err != nil {
		return err
	}
	if f := l.stack[l.top-1].(*luaClosure); f.upValueCount() == 1 {
		f.setUpValue(0, l.global.registry.atInt(RegistryIndexGlobals))
	}
	return nil
}
func NewState() *State {
	v := float64(VersionNumber)
	l := &State{allowHook: true, error: nil, nonYieldableCallCount: 1}
	g := &globalState{mainThread: l, registry: newTable(), version: &v, memoryErrorMessage: "not enough memory"}
	l.global = g
	l.initializeStack()
	g.registry.putAtInt(RegistryIndexMainThread, l)
	g.registry.putAtInt(RegistryIndexGlobals, newTable())
	copy(g.tagMethodNames[:], eventNames)
	return l
}
func apiCheckStackIndex(index int, v value) {
	if apiCheck && (v == none || isPseudoIndex(index)) {
		panic(fmt.Sprintf("index %d not in the stack", index))
	}
}
func (l *State) SetField(index int, key string) {
	l.checkElementCount(1)
	t := l.indexToValue(index)
	l.push(key)
	l.setTableAt(t, key, l.stack[l.top-2])
	l.top -= 2
}
var none value = &struct{}{}
func (l *State) indexToValue(index int) value {
	switch {
	case index > 0:
		if l.callInfo.function+index >= l.top {
			return none
		}
		return l.stack[l.callInfo.function:l.top][index]
	case index > RegistryIndex:  
		return l.stack[l.top+index]
	case index == RegistryIndex:
		return l.global.registry
	default:  
		i := RegistryIndex - index
		return l.stack[l.callInfo.function].(*goClosure).upValues[i-1]
	}
}
func (l *State) setIndexToValue(index int, v value) {
	switch {
	case index > 0:
		l.stack[l.callInfo.function:l.top][index] = v
	case index > RegistryIndex:  
		l.stack[l.top+index] = v
	case index == RegistryIndex:
		l.global.registry = v.(*table)
	default:  
		i := RegistryIndex - index
		l.stack[l.callInfo.function].(*goClosure).upValues[i-1] = v
	}
}
func (l *State) AbsIndex(index int) int {
	if index > 0 || isPseudoIndex(index) {
		return index
	}
	return l.top - l.callInfo.function + index
}
func (l *State) SetTop(index int) {
	f := l.callInfo.function
	if index >= 0 {
		if apiCheck && index > l.stackLast-(f+1) {
			panic("new top too large")
		}
		i := l.top
		for l.top = f + 1 + index; i < l.top; i++ {
			l.stack[i] = nil
		}
	} else {
		if apiCheck && -(index+1) > l.top-(f+1) {
			panic("invalid new top")
		}
		l.top += index + 1  
	}
}
func (l *State) Remove(index int) {
	apiCheckStackIndex(index, l.indexToValue(index))
	i := l.callInfo.function + l.AbsIndex(index)
	copy(l.stack[i:l.top-1], l.stack[i+1:l.top])
	l.top--
}
func (l *State) Insert(index int) {
	apiCheckStackIndex(index, l.indexToValue(index))
	i := l.callInfo.function + l.AbsIndex(index)
	copy(l.stack[i+1:l.top+1], l.stack[i:l.top])
	l.stack[i] = l.stack[l.top]
}
func (l *State) move(dest int, src value) { l.setIndexToValue(dest, src) }
func (l *State) Replace(index int) {
	l.checkElementCount(1)
	l.move(index, l.stack[l.top-1])
	l.top--
}
func (l *State) CheckStack(size int) bool {
	callInfo := l.callInfo
	ok := l.stackLast-l.top > size
	if !ok && l.top+extraStack <= maxStack-size {
		ok = l.protect(func() { l.growStack(size) }) == nil
	}
	if ok && callInfo.top < l.top+size {
		callInfo.setTop(l.top + size)
	}
	return ok
}
func AtPanic(l *State, panicFunction Function) Function {
	panicFunction, l.global.panicFunction = l.global.panicFunction, panicFunction
	return panicFunction
}
func (l *State) valueToType(v value) Type {
	switch v.(type) {
	case nil:
		return TypeNil
	case bool:
		return TypeBoolean
	case float64:
		return TypeNumber
	case string:
		return TypeString
	case *table:
		return TypeTable
	case *goFunction:
		return TypeFunction
	case *userData:
		return TypeUserData
	case *State:
		return TypeThread
	case *luaClosure:
		return TypeFunction
	case *goClosure:
		return TypeFunction
	}
	return TypeNone
}
func (l *State) TypeOf(index int) Type {
	return l.valueToType(l.indexToValue(index))
}
func (l *State) IsGoFunction(index int) bool {
	if _, ok := l.indexToValue(index).(*goFunction); ok {
		return true
	}
	_, ok := l.indexToValue(index).(*goClosure)
	return ok
}
func (l *State) IsNumber(index int) bool {
	_, ok := l.toNumber(l.indexToValue(index))
	return ok
}
func (l *State) IsString(index int) bool {
	if _, ok := l.indexToValue(index).(string); ok {
		return true
	}
	_, ok := l.indexToValue(index).(float64)
	return ok
}
func (l *State) IsUserData(index int) bool {
	_, ok := l.indexToValue(index).(*userData)
	return ok
}
func (l *State) Arith(op Operator) {
	if op != OpUnaryMinus {
		l.checkElementCount(2)
	} else {
		l.checkElementCount(1)
		l.push(l.stack[l.top-1])
	}
	o1, o2 := l.stack[l.top-2], l.stack[l.top-1]
	if n1, n2, ok := pairAsNumbers(o1, o2); ok {
		l.stack[l.top-2] = arith(op, n1, n2)
	} else {
		l.stack[l.top-2] = l.arith(o1, o2, tm(op-OpAdd)+tmAdd)
	}
	l.top--
}
func (l *State) RawEqual(index1, index2 int) bool {
	if o1, o2 := l.indexToValue(index1), l.indexToValue(index2); o1 != nil && o2 != nil {
		return o1 == o2
	}
	return false
}
func (l *State) Compare(index1, index2 int, op ComparisonOperator) bool {
	if o1, o2 := l.indexToValue(index1), l.indexToValue(index2); o1 != nil && o2 != nil {
		switch op {
		case OpEq:
			return l.equalObjects(o1, o2)
		case OpLT:
			return l.lessThan(o1, o2)
		case OpLE:
			return l.lessOrEqual(o1, o2)
		default:
			panic("invalid option")
		}
	}
	return false
}