func IntLen(t *Thread, v Value) (int64, *Error) {
	if s, ok := v.TryString(); ok {
		return int64(len(s)), nil
	}
	res := NewTerminationWith(1, false)
	err, ok := Metacall(t, v, "__len", []Value{v}, res)
	if ok {
		if err != nil {
			return 0, err
		}
		l, ok := ToInt(res.Get(0))
		if !ok {
			err = NewErrorS("len should return an integer")
		}
		return l, err
	}
	if tbl, ok := v.TryTable(); ok {
		return tbl.Len(), nil
	}
	return 0, NewErrorS("Cannot compute len")
}
IntLen returns the length of v as an int64, possibly calling the '__len'
metamethod.  This is an optimization of Len for an integer output.
package runtime
import (
	"fmt"
	"strconv"
	"github.com/arnodel/golua/ast"
	"github.com/arnodel/golua/astcomp"
	"github.com/arnodel/golua/code"
	"github.com/arnodel/golua/ir"
	"github.com/arnodel/golua/ircomp"
	"github.com/arnodel/golua/parsing"
	"github.com/arnodel/golua/scanner"
)
const maxIndexChainLength = 100
func IsNil(v Value) bool {
	return v.IsNil()
}
func RawGet(t *Table, k Value) Value {
	if t == nil {
		return NilValue
	}
	return t.Get(k)
}
func Index(t *Thread, coll Value, k Value) (Value, *Error) {
	for i := 0; i < maxIndexChainLength; i++ {
		if tbl, ok := coll.TryTable(); ok {
			if val := RawGet(tbl, k); !val.IsNil() {
				return val, nil
			}
		}
		metaIdx := t.metaGetS(coll, "__index")
		if metaIdx.IsNil() {
			return NilValue, nil
		}
		if _, ok := metaIdx.TryTable(); ok {
			coll = metaIdx
		} else {
			res := NewTerminationWith(1, false)
			if err := Call(t, metaIdx, []Value{coll, k}, res); err != nil {
				return NilValue, err
			}
			return res.Get(0), nil
		}
	}
	return NilValue, NewErrorF("'__index' chain too long; possible loop")
}
func SetIndex(t *Thread, coll Value, idx Value, val Value) *Error {
	if idx.IsNil() {
		return NewErrorS("index is nil")
	}
	for i := 0; i < maxIndexChainLength; i++ {
		tbl, isTable := coll.TryTable()
		if isTable && tbl.Reset(idx, val) {
			return nil
		}
		metaNewIndex := t.metaGetS(coll, "__newindex")
		if metaNewIndex.IsNil() {
			if isTable {
				if err := tbl.SetCheck(idx, val); err != nil {
					return NewErrorE(err)
				}
			}
			return nil
		}
		if _, ok := metaNewIndex.TryTable(); ok {
			coll = metaNewIndex
		} else {
			return Call(t, metaNewIndex, []Value{coll, idx, val}, NewTermination(nil, nil))
		}
	}
	return NewErrorF("'__newindex' chain too long; possible loop")
}
func Truth(v Value) bool {
	if v.IsNil() {
		return false
	}
	b, ok := v.TryBool()
	return !ok || b
}
func Metacall(t *Thread, obj Value, method string, args []Value, next Cont) (*Error, bool) {
	if f := t.metaGetS(obj, method); !f.IsNil() {
		return Call(t, f, args, next), true
	}
	return nil, false
}
func Continue(t *Thread, f Value, next Cont) (Cont, *Error) {
	callable, ok := f.TryCallable()
	if ok {
		return callable.Continuation(next), nil
	}
	cont, err, ok := metacont(t, f, "__call", next)
	if !ok {
		return nil, NewErrorF("cannot call %v", f)
	}
	if cont != nil {
		cont.Push(f)
	}
	return cont, err
}
func Call(t *Thread, f Value, args []Value, next Cont) *Error {
	if f.IsNil() {
		return NewErrorS("attempt to call a nil value")
	}
	callable, ok := f.TryCallable()
	if ok {
		return t.call(callable, args, next)
	}
	err, ok := Metacall(t, f, "__call", append([]Value{f}, args...), next)
	if ok {
		return err
	}
	return NewErrorS("call expects a callable")
}
func Call1(t *Thread, f Value, args ...Value) (Value, *Error) {
	term := NewTerminationWith(1, false)
	if err := Call(t, f, args, term); err != nil {
		return NilValue, err
	}
	return term.Get(0), nil
}
func ToString(x Value) (string, bool) {
	switch x.Type() {
	case NilType:
		return "nil", true
	case StringType:
		return x.AsString(), true
	case IntType:
		return strconv.Itoa(int(x.AsInt())), true
	case FloatType:
		return strconv.FormatFloat(x.AsFloat(), 'g', -1, 64), true
	case BoolType:
		if x.AsBool() {
			return "true", false
		}
		return "false", false
	}
	return "", false
}
func Concat(t *Thread, x, y Value) (Value, *Error) {
	if sx, ok := ToString(x); ok {
		if sy, ok := ToString(y); ok {
			return StringValue(sx + sy), nil
		}
	}
	res, err, ok := metabin(t, "__concat", x, y)
	if ok {
		return res, err
	}
	return NilValue, NewErrorS("concat expects concatable values")
}