func outputNumbersToStrings(L *lua.State) { L.GetGlobal("output") if !L.IsTable(-1) { L.NewTable() L.SetGlobal("output") } L.GetField(-1, "tags") if L.IsTable(-1) { // First key. L.PushNil() for L.Next(-2) != 0 { // Use 'key' at index -2 and 'value' at index -1. if L.IsString(-2) && L.IsString(-1) { // Convert numbers to strings. L.ToString(-1) L.SetField(-3, L.ToString(-2)) } else { // Remove 'value' and keep 'key' for next iteration. L.Pop(1) } } } L.Pop(1) L.Pop(1) }
func register(L *lua.State, table string, values Map, convertFun bool) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { t := reflect.TypeOf(val) if t.Kind() == reflect.Func { if convertFun { L.PushGoFunction(GoLuaFunc(L, val)) } else { lf := val.(func(*lua.State) int) L.PushGoFunction(lf) } } else { GoToLua(L, t, valueOf(val), false) } L.SetField(-2, name) } if pop { L.Pop(1) } }
// Registers a Go function as a global variable and add it to the sandbox. func sandboxRegister(L *lua.State, name string, f interface{}) { goToLua(L, name, f) L.PushString(registryWhitelist) L.GetTable(lua.LUA_REGISTRYINDEX) L.GetGlobal(name) L.SetField(-2, name) }
// Register makes a number of Go values available in Lua code. // 'values' is a map of strings to Go values. // // - If table is non-nil, then create or reuse a global table of that name and // put the values in it. // // - If table is '' then put the values in the global table (_G). // // - If table is '*' then assume that the table is already on the stack. func Register(L *lua.State, table string, values Map) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { GoToLua(L, nil, reflect.ValueOf(val), false) L.SetField(-2, name) } if pop { L.Pop(1) } }
func initializeProxies(L *lua.State) { flagValue := func() { L.SetMetaMethod("__tostring", proxy__tostring) L.SetMetaMethod("__gc", proxy__gc) L.SetMetaMethod("__eq", proxy__eq) L.PushBoolean(true) L.SetField(-2, "luago.value") L.Pop(1) } L.NewMetaTable(cSLICE_META) L.SetMetaMethod("__index", slice__index) L.SetMetaMethod("__newindex", slice__newindex) L.SetMetaMethod("__len", slicemap__len) L.SetMetaMethod("__ipairs", slice__ipairs) flagValue() L.NewMetaTable(cMAP_META) L.SetMetaMethod("__index", map__index) L.SetMetaMethod("__newindex", map__newindex) L.SetMetaMethod("__len", slicemap__len) L.SetMetaMethod("__pairs", map__pairs) flagValue() L.NewMetaTable(cSTRUCT_META) L.SetMetaMethod("__index", struct__index) L.SetMetaMethod("__newindex", struct__newindex) flagValue() L.NewMetaTable(cINTERFACE_META) L.SetMetaMethod("__index", interface__index) flagValue() L.NewMetaTable(cCHANNEL_META) //~ RegisterFunctions(L,"*",FMap { //~ "Send":channel_send, //~ "Recv":channel_recv, //~ }) L.NewTable() L.PushGoFunction(channel_send) L.SetField(-2, "Send") L.PushGoFunction(channel_recv) L.SetField(-2, "Recv") L.SetField(-2, "__index") flagValue() }
func register(L *lua.State, table string, values Map, convertFun bool) { pop := true if table == "*" { pop = false } else if len(table) > 0 { L.GetGlobal(table) if L.IsNil(-1) { L.NewTable() L.SetGlobal(table) L.GetGlobal(table) } } else { L.GetGlobal("_G") } for name, val := range values { t := reflect.TypeOf(val) if t.Kind() == reflect.Func { if convertFun { L.PushGoFunction(GoLuaFunc(L, val)) } else { lf := val.(func(*lua.State) int) L.PushGoFunction(lf) } } else { GoToLua(L, t, valueOf(val), false) } L.SetField(-2, name) if t.Kind() == reflect.Func { var lf func(*lua.State) int if convertFun { lf = GoLuaFunc(L, val) } else { lf = val.(func(*lua.State) int) } L.PushGoFunction(func(L *lua.State) (ret int) { defer func() { if err2 := recover(); err2 != nil { GoToLua(L, typeof(err2), valueOf(err2), false) ret = 1 return } }() ret = lf(L) pos := L.GetTop() - ret + 1 L.PushNil() L.Insert(pos) for i := 0; i < L.GetTop(); i++ { fmt.Println(L.Typename(int(L.Type(i + 1)))) } return ret + 1 }) L.SetField(-2, "safe_"+name) } } if pop { L.Pop(1) } }
func installWorld(state *lua.State) { log.Println("Installing world") printStackTypes(state) state.NewMetaTable(ThingMetaTableName) // ( -- mtbl ) state.SetMetaMethod("__index", MessThingIndex) // ( mtbl -- mtbl ) state.Pop(1) // ( mtbl -- ) worldTable := map[string]interface{}{ /* "Root": "Create": func... */ } pushValue(state, worldTable) // Install Thing types as singleton sentinel values. As userdata, these will only compare if the values are exactly equal. state.NewUserdata(uintptr(0)) state.SetField(-2, "Player") state.NewUserdata(uintptr(0)) state.SetField(-2, "Place") state.NewUserdata(uintptr(0)) state.SetField(-2, "Program") state.NewUserdata(uintptr(0)) state.SetField(-2, "Action") state.NewUserdata(uintptr(0)) state.SetField(-2, "Thing") state.SetGlobal("world") state.GetGlobal("table") // ( -- tblTable ) state.PushGoFunction(TableFormat) state.SetField(-2, "format") state.Pop(1) // ( tblTable -- ) log.Println("Finished installing world") printStackTypes(state) }
func pushValue(state *lua.State, value interface{}) error { switch v := value.(type) { default: return fmt.Errorf("An item of unknown type was included in the environment or arguments of a Lua call (skipping it): %v", value) case nil: log.Println("Pushing nil onto lua stack") state.PushNil() case string: log.Println("Pushing string onto lua stack") state.PushString(v) case int: log.Println("Pushing int onto lua stack") state.PushInteger(int64(v)) case int64: log.Println("Pushing int64 onto lua stack") state.PushInteger(v) case float64: log.Println("Pushing float64 onto lua stack") state.PushNumber(v) case bool: log.Println("Pushing bool onto lua stack") state.PushBoolean(v) case map[string]interface{}: log.Println("Pushing map[string]interface{} onto lua stack") state.CreateTable(0, len(v)) for name, value := range v { err := pushValue(state, value) if err != nil { // error means nothing was added to stack. So pop our new table so *we* leave nothing added to the stack. state.Pop(1) return err } state.SetField(-2, name) } // then leave the table on the stack case ThingType: // These are singleton sentinel values, so load them from Lua-land. state.GetGlobal("world") state.GetField(-1, strings.Title(v.String())) state.Remove(-2) case *Thing: log.Println("Pushing *Thing onto lua stack") return pushValue(state, v.Id) case ThingId: log.Println("Pushing ThingId onto lua stack") // We're pushing a ThingId, so make a new userdata for it, with the Thing metatable. userdata := state.NewUserdata(uintptr(unsafe.Sizeof(int64(0)))) thingPtr := (*int64)(userdata) *thingPtr = int64(v) if !state.IsUserdata(-1) { log.Println("!!! HOGAD JUST PUSHED NEW USERDATA BUT IT ISN'T OMG !!!") } log.Println("Pushed ThingId", *thingPtr, "onto lua stack") // Now make it act like a Thing. state.LGetMetaTable(ThingMetaTableName) // ( udata -- udata mtbl ) state.SetMetaTable(-2) // ( udata mtbl -- udata ) // Let's just check that it's that, for sures. if !state.IsUserdata(-1) { log.Println("!!! WOOP WOOP DID NOT SET METATABLE RIGHT :( !!!") } } return nil }