func (l *State) ToValue(index int) interface{} {
	v := l.indexToValue(index)
	switch v := v.(type) {
	case string, float64, bool, *table, *luaClosure, *goClosure, *goFunction, *State:
	case *userData:
		return v.data
	default:
		return nil
	}
	return v
}
ToValue convertes the value at index into a generic Go interface{}.  The
value can be a userdata, a table, a thread, a function, or Go string, bool
or float64 types. Otherwise, the function returns nil.

Different objects will give different values.  There is no way to convert
the value back into its original value.

Typically, this function is used only for debug information.

http://www.lua.org/manual/5.2/manual.html#lua_tovalue
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
}
func (l *State) ToInteger(index int) (int, bool) {
	if n, ok := l.toNumber(l.indexToValue(index)); ok {
		return int(n), true
	}
	return 0, false
}
func (l *State) ToUnsigned(index int) (uint, bool) {
	if n, ok := l.toNumber(l.indexToValue(index)); ok {
		const supUnsigned = float64(^uint32(0)) + 1
		return uint(n - math.Floor(n/supUnsigned)*supUnsigned), true
	}
	return 0, false
}
func (l *State) ToString(index int) (s string, ok bool) {
	if s, ok = toString(l.indexToValue(index)); ok {  
		l.setIndexToValue(index, s)
	}
	return
}
func (l *State) RawLength(index int) int {
	switch v := l.indexToValue(index).(type) {
	case string:
		return len(v)
	case *table:
		return v.length()
	}
	return 0
}
func (l *State) ToGoFunction(index int) Function {
	switch v := l.indexToValue(index).(type) {
	case *goFunction:
		return v.Function
	case *goClosure:
		return v.function
	}
	return nil
}
func (l *State) ToUserData(index int) interface{} {
	if d, ok := l.indexToValue(index).(*userData); ok {
		return d.data
	}
	return nil
}
func (l *State) ToThread(index int) *State {
	if t, ok := l.indexToValue(index).(*State); ok {
		return t
	}
	return nil
}