func makeValueProxy(L *lua.State, val reflect.Value, proxyMT string) { rawptr := L.NewUserdata(uintptr(unsafe.Sizeof(ValueProxy{}))) ptr := (*ValueProxy)(rawptr) ptr.value = val ptr.t = val.Type() L.LGetMetaTable(proxyMT) L.SetMetaTable(-2) }
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 }