zombiezen.com/go/lua@v0.0.0-20231013005828-290725fb9140/internal/lua54/lua.go (about) 1 // Copyright 2023 Ross Light 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 // this software and associated documentation files (the “Software”), to deal in 5 // the Software without restriction, including without limitation the rights to 6 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 // the Software, and to permit persons to whom the Software is furnished to do so, 8 // subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in all 11 // copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 // 20 // SPDX-License-Identifier: MIT 21 22 package lua54 23 24 import ( 25 "errors" 26 "fmt" 27 "io" 28 "runtime/cgo" 29 "strings" 30 "unsafe" 31 ) 32 33 // #cgo unix CFLAGS: -DLUA_USE_POSIX 34 // #cgo unix LDFLAGS: -lm 35 // #include <stdlib.h> 36 // #include <stddef.h> 37 // #include <stdint.h> 38 // #include <string.h> 39 // #include "lua.h" 40 // #include "lauxlib.h" 41 // #include "lualib.h" 42 // 43 // char *zombiezen_lua_readercb(lua_State *L, void *data, size_t *size); 44 // int zombiezen_lua_writercb(lua_State *L, const void *p, size_t size, void *ud); 45 // int zombiezen_lua_gocb(lua_State *L); 46 // int zombiezen_lua_gcfunc(lua_State *L); 47 // 48 // static int trampoline(lua_State *L) { 49 // int nresults = zombiezen_lua_gocb(L); 50 // if (nresults < 0) { 51 // lua_error(L); 52 // } 53 // return nresults; 54 // } 55 // 56 // static void pushclosure(lua_State *L, uint64_t funcID, int n) { 57 // uint8_t *data = lua_newuserdatauv(L, 8, 0); 58 // data[0] = (uint8_t)funcID; 59 // data[1] = (uint8_t)(funcID >> 8); 60 // data[2] = (uint8_t)(funcID >> 16); 61 // data[3] = (uint8_t)(funcID >> 24); 62 // data[4] = (uint8_t)(funcID >> 32); 63 // data[5] = (uint8_t)(funcID >> 40); 64 // data[6] = (uint8_t)(funcID >> 48); 65 // data[7] = (uint8_t)(funcID >> 56); 66 // 67 // if (luaL_newmetatable(L, "zombiezen.com/go/lua.Function")) { 68 // lua_pushcfunction(L, zombiezen_lua_gcfunc); 69 // lua_setfield(L, -2, "__gc"); 70 // lua_pushboolean(L, 0); 71 // lua_setfield(L, -2, "__metatable"); 72 // } 73 // lua_setmetatable(L, -2); 74 // lua_insert(L, -1 - n); 75 // lua_pushcclosure(L, trampoline, 1 + n); 76 // } 77 // 78 // void zombiezen_lua_pushstring(lua_State *L, _GoString_ s) { 79 // lua_pushlstring(L, _GoStringPtr(s), _GoStringLen(s)); 80 // } 81 // 82 // const char *zombiezen_lua_reader(lua_State *L, void *data, size_t *size) { 83 // const char *p = zombiezen_lua_readercb(L, data, size); 84 // if (p == NULL) { 85 // lua_error(L); 86 // } 87 // return p; 88 // } 89 // 90 // struct readStringData { 91 // _GoString_ s; 92 // int done; 93 // }; 94 // 95 // static const char *readstring(lua_State *L, void *data, size_t *size) { 96 // struct readStringData *myData = (struct readStringData*)(data); 97 // if (myData->done) { 98 // *size = 0; 99 // return NULL; 100 // } 101 // *size = _GoStringLen(myData->s); 102 // myData->done = 1; 103 // return _GoStringPtr(myData->s); 104 // } 105 // 106 // static int loadstring(lua_State *L, _GoString_ s, const char* chunkname, const char* mode) { 107 // struct readStringData myData = {s, 0}; 108 // return lua_load(L, readstring, &myData, chunkname, mode); 109 // } 110 // 111 // static int gettablecb(lua_State *L) { 112 // lua_gettable(L, 1); 113 // return 1; 114 // } 115 // 116 // static int gettable(lua_State *L, int index, int msgh, int *tp) { 117 // index = lua_absindex(L, index); 118 // msgh = msgh != 0 ? lua_absindex(L, msgh) : 0; 119 // lua_pushcfunction(L, gettablecb); 120 // lua_pushvalue(L, index); 121 // lua_rotate(L, -3, -1); 122 // int ret = lua_pcall(L, 2, 1, msgh); 123 // if (tp != NULL) { 124 // *tp = ret == LUA_OK ? lua_type(L, -1) : LUA_TNIL; 125 // } 126 // return ret; 127 // } 128 // 129 // static int settablecb(lua_State *L) { 130 // lua_settable(L, 1); 131 // return 0; 132 // } 133 // 134 // static int settable(lua_State *L, int index, int msgh) { 135 // index = lua_absindex(L, index); 136 // msgh = msgh != 0 ? lua_absindex(L, msgh) : 0; 137 // lua_pushcfunction(L, settablecb); 138 // lua_pushvalue(L, index); 139 // lua_rotate(L, -4, -2); 140 // return lua_pcall(L, 3, 0, msgh); 141 // } 142 // 143 // static void pushlightuserdata(lua_State *L, uintptr_t p) { 144 // lua_pushlightuserdata(L, (void *)p); 145 // } 146 // 147 // static int lencb(lua_State *L) { 148 // lua_len(L, 1); 149 // return 1; 150 // } 151 // 152 // static void pushlenfunction(lua_State *L) { 153 // lua_pushcfunction(L, lencb); 154 // } 155 // 156 // static void *newuserdata(lua_State *L, size_t size, int nuvalue) { 157 // void *ptr = lua_newuserdatauv(L, size, nuvalue); 158 // memset(ptr, 0, size); 159 // return ptr; 160 // } 161 // 162 // static size_t userdatalen(lua_State *L, int index) { 163 // if (lua_type(L, index) != LUA_TUSERDATA) { 164 // return 0; 165 // } 166 // return (size_t)lua_rawlen(L, index); 167 // } 168 // 169 // static lua_State *newstate(uintptr_t id) { 170 // lua_State *L = luaL_newstate(); 171 // if (L == NULL) { 172 // return NULL; 173 // } 174 // lua_setwarnf(L, NULL, NULL); 175 // *(uintptr_t *)(lua_getextraspace(L)) = id; 176 // return L; 177 // } 178 // 179 // static uintptr_t stateid(lua_State *L) { 180 // return *(uintptr_t *)(lua_getextraspace(L)); 181 // } 182 // 183 // static int gcniladic(lua_State *L, int what) { 184 // return lua_gc(L, what); 185 // } 186 // 187 // static int gcstep(lua_State *L, int stepsize) { 188 // return lua_gc(L, LUA_GCSTEP, stepsize); 189 // } 190 // 191 // static int gcinc(lua_State *L, int pause, int stepmul, int stepsize) { 192 // return lua_gc(L, LUA_GCINC, pause, stepmul, stepsize); 193 // } 194 // 195 // static int gcgen(lua_State *L, int minormul, int majormul) { 196 // return lua_gc(L, LUA_GCGEN, minormul, majormul); 197 // } 198 import "C" 199 200 const ( 201 VersionMajor = C.LUA_VERSION_MAJOR 202 VersionMinor = C.LUA_VERSION_MINOR 203 VersionRelease = C.LUA_VERSION_RELEASE 204 205 VersionNum = C.LUA_VERSION_NUM 206 VersionReleaseNum = C.LUA_VERSION_RELEASE_NUM 207 208 Version = C.LUA_VERSION 209 Release = C.LUA_RELEASE 210 Copyright = C.LUA_COPYRIGHT 211 Authors = C.LUA_AUTHORS 212 ) 213 214 const RegistryIndex int = C.LUA_REGISTRYINDEX 215 216 const ( 217 RegistryIndexMainThread int64 = C.LUA_RIDX_MAINTHREAD 218 RegistryIndexGlobals int64 = C.LUA_RIDX_GLOBALS 219 ) 220 221 const ( 222 LoadedTable = C.LUA_LOADED_TABLE 223 PreloadTable = C.LUA_PRELOAD_TABLE 224 ) 225 226 type Type C.int 227 228 const ( 229 TypeNone Type = C.LUA_TNONE 230 TypeNil Type = C.LUA_TNIL 231 TypeBoolean Type = C.LUA_TBOOLEAN 232 TypeLightUserdata Type = C.LUA_TLIGHTUSERDATA 233 TypeNumber Type = C.LUA_TNUMBER 234 TypeString Type = C.LUA_TSTRING 235 TypeTable Type = C.LUA_TTABLE 236 TypeFunction Type = C.LUA_TFUNCTION 237 TypeUserdata Type = C.LUA_TUSERDATA 238 TypeThread Type = C.LUA_TTHREAD 239 ) 240 241 func (tp Type) String() string { 242 switch tp { 243 case TypeNone: 244 return "no value" 245 case TypeNil: 246 return "nil" 247 case TypeBoolean: 248 return "boolean" 249 case TypeLightUserdata, TypeUserdata: 250 return "userdata" 251 case TypeNumber: 252 return "number" 253 case TypeString: 254 return "string" 255 case TypeTable: 256 return "table" 257 case TypeFunction: 258 return "function" 259 case TypeThread: 260 return "thread" 261 default: 262 return fmt.Sprintf("lua.Type(%d)", C.int(tp)) 263 } 264 } 265 266 type State struct { 267 ptr *C.lua_State 268 top int 269 cap int 270 main bool 271 } 272 273 type stateData struct { 274 nextID uint64 275 closures map[uint64]Function 276 } 277 278 // stateForCallback returns a new State for the given *lua_State. 279 // stateForCallback assumes that it is called 280 // before any other functions are called on the *lua_State. 281 func stateForCallback(ptr *C.lua_State) *State { 282 l := &State{ 283 ptr: ptr, 284 top: int(C.lua_gettop(ptr)), 285 } 286 l.cap = l.top + C.LUA_MINSTACK 287 return l 288 } 289 290 func (l *State) init() { 291 if l.ptr == nil { 292 data := cgo.NewHandle(&stateData{ 293 nextID: 1, 294 closures: make(map[uint64]Function), 295 }) 296 l.ptr = C.newstate(C.uintptr_t(data)) 297 if l == nil { 298 panic("could not allocate memory for new state") 299 } 300 l.top = 0 301 l.cap = C.LUA_MINSTACK 302 l.main = true 303 } 304 } 305 306 func (l *State) Close() error { 307 if l.ptr != nil { 308 if !l.main { 309 return errors.New("lua: cannot close non-main thread") 310 } 311 data := cgo.Handle(C.stateid(l.ptr)) 312 C.lua_close(l.ptr) 313 data.Delete() 314 *l = State{} 315 } 316 return nil 317 } 318 319 // data returns the interpreter-wide data. 320 func (l *State) data() *stateData { 321 return cgo.Handle(C.stateid(l.ptr)).Value().(*stateData) 322 } 323 324 func (l *State) AbsIndex(idx int) int { 325 switch { 326 case isPseudo(idx): 327 return idx 328 case idx == 0 || idx < -l.top || idx > l.cap: 329 panic("unacceptable index") 330 case idx < 0: 331 return l.top + idx + 1 332 default: 333 return idx 334 } 335 } 336 337 func (l *State) isValidIndex(idx int) bool { 338 if idx == goClosureUpvalueIndex { 339 // Forbid users of the package from accessing the GoClosure upvalue. 340 return false 341 } 342 if isPseudo(idx) { 343 return true 344 } 345 if idx < 0 { 346 idx = -idx 347 } 348 return 1 <= idx && idx <= l.top 349 } 350 351 func (l *State) isAcceptableIndex(idx int) bool { 352 return l.isValidIndex(idx) || l.top <= idx && idx <= l.cap 353 } 354 355 func (l *State) checkElems(n int) { 356 if l.top < n { 357 panic("not enough elements in the stack") 358 } 359 } 360 361 func (l *State) checkMessageHandler(msgHandler int) int { 362 switch { 363 case msgHandler == 0: 364 return 0 365 case isPseudo(msgHandler): 366 panic("pseudo-indexed message handler") 367 case 1 <= msgHandler && msgHandler <= l.top: 368 return msgHandler 369 case -l.top <= msgHandler && msgHandler <= -1: 370 return l.top + msgHandler + 1 371 default: 372 panic("invalid message handler index") 373 } 374 } 375 376 func (l *State) Top() int { 377 return l.top 378 } 379 380 func (l *State) SetTop(idx int) { 381 // lua_settop can raise errors, which will be undefined behavior, 382 // but only if we mark stack slots as to-be-closed. 383 // We have a simple solution: don't let the user do that. 384 385 switch { 386 case isPseudo(idx): 387 panic("pseudo-index invalid for top") 388 case idx == 0: 389 if l.ptr != nil { 390 C.lua_settop(l.ptr, 0) 391 l.top = 0 392 } 393 return 394 case idx < 0: 395 idx += l.top + 1 396 if idx < 0 { 397 panic("stack underflow") 398 } 399 case idx > l.cap: 400 panic("stack overflow") 401 } 402 l.init() 403 404 C.lua_settop(l.ptr, C.int(idx)) 405 l.top = idx 406 } 407 408 func (l *State) Pop(n int) { 409 l.SetTop(-n - 1) 410 } 411 412 func (l *State) PushValue(idx int) { 413 l.init() 414 if l.top >= l.cap { 415 panic("stack overflow") 416 } 417 C.lua_pushvalue(l.ptr, C.int(idx)) 418 l.top++ 419 } 420 421 func (l *State) Rotate(idx, n int) { 422 l.init() 423 if !l.isValidIndex(idx) || isPseudo(idx) { 424 panic("invalid index") 425 } 426 idx = l.AbsIndex(idx) 427 absN := n 428 if n < 0 { 429 absN = -n 430 } 431 if absN > l.top-idx+1 { 432 panic("invalid rotation") 433 } 434 C.lua_rotate(l.ptr, C.int(idx), C.int(n)) 435 } 436 437 func (l *State) Remove(idx int) { 438 l.Rotate(idx, -1) 439 l.Pop(1) 440 } 441 442 func (l *State) Insert(idx int) { 443 l.Rotate(idx, 1) 444 } 445 446 func (l *State) Copy(fromIdx, toIdx int) { 447 l.init() 448 if !l.isAcceptableIndex(fromIdx) || !l.isAcceptableIndex(toIdx) { 449 panic("unacceptable index") 450 } 451 C.lua_copy(l.ptr, C.int(fromIdx), C.int(toIdx)) 452 } 453 454 func (l *State) Replace(idx int) { 455 l.Copy(-1, idx) 456 l.Pop(1) 457 } 458 459 func (l *State) CheckStack(n int) bool { 460 if l.top+n <= l.cap { 461 return true 462 } 463 l.init() 464 ok := C.lua_checkstack(l.ptr, C.int(n)) != 0 465 if ok { 466 l.cap = max(l.cap, l.top+n) 467 } 468 return ok 469 } 470 471 func (l *State) IsNumber(idx int) bool { 472 if l.ptr == nil { 473 return false 474 } 475 if !l.isAcceptableIndex(idx) { 476 panic("unacceptable index") 477 } 478 return C.lua_isnumber(l.ptr, C.int(idx)) != 0 479 } 480 481 func (l *State) IsString(idx int) bool { 482 if l.ptr == nil { 483 return false 484 } 485 if !l.isAcceptableIndex(idx) { 486 panic("unacceptable index") 487 } 488 return C.lua_isstring(l.ptr, C.int(idx)) != 0 489 } 490 491 func (l *State) IsNativeFunction(idx int) bool { 492 if l.ptr == nil { 493 return false 494 } 495 if !l.isAcceptableIndex(idx) { 496 panic("unacceptable index") 497 } 498 return C.lua_iscfunction(l.ptr, C.int(idx)) != 0 499 } 500 501 func (l *State) IsInteger(idx int) bool { 502 if l.ptr == nil { 503 return false 504 } 505 if !l.isAcceptableIndex(idx) { 506 panic("unacceptable index") 507 } 508 return C.lua_isinteger(l.ptr, C.int(idx)) != 0 509 } 510 511 func (l *State) IsUserdata(idx int) bool { 512 if l.ptr == nil { 513 return false 514 } 515 if !l.isAcceptableIndex(idx) { 516 panic("unacceptable index") 517 } 518 return C.lua_isuserdata(l.ptr, C.int(idx)) != 0 519 } 520 521 func (l *State) Type(idx int) Type { 522 if l.ptr == nil { 523 return TypeNone 524 } 525 if !l.isAcceptableIndex(idx) { 526 panic("unacceptable index") 527 } 528 return Type(C.lua_type(l.ptr, C.int(idx))) 529 } 530 531 func (l *State) IsFunction(idx int) bool { return l.Type(idx) == TypeFunction } 532 func (l *State) IsTable(idx int) bool { return l.Type(idx) == TypeTable } 533 func (l *State) IsNil(idx int) bool { return l.Type(idx) == TypeNil } 534 func (l *State) IsBoolean(idx int) bool { return l.Type(idx) == TypeBoolean } 535 func (l *State) IsThread(idx int) bool { return l.Type(idx) == TypeThread } 536 func (l *State) IsNone(idx int) bool { return l.Type(idx) == TypeNone } 537 538 func (l *State) IsNoneOrNil(idx int) bool { 539 tp := l.Type(idx) 540 return tp == TypeNone || tp == TypeNil 541 } 542 543 func (l *State) ToNumber(idx int) (n float64, ok bool) { 544 if l.ptr == nil { 545 return 0, false 546 } 547 if !l.isAcceptableIndex(idx) { 548 panic("unacceptable index") 549 } 550 var isNum C.int 551 n = float64(C.lua_tonumberx(l.ptr, C.int(idx), &isNum)) 552 return n, isNum != 0 553 } 554 555 func (l *State) ToInteger(idx int) (n int64, ok bool) { 556 if l.ptr == nil { 557 return 0, false 558 } 559 if !l.isAcceptableIndex(idx) { 560 panic("unacceptable index") 561 } 562 var isNum C.int 563 n = int64(C.lua_tointegerx(l.ptr, C.int(idx), &isNum)) 564 return n, isNum != 0 565 } 566 567 func (l *State) ToBoolean(idx int) bool { 568 if l.ptr == nil { 569 return false 570 } 571 if !l.isAcceptableIndex(idx) { 572 panic("unacceptable index") 573 } 574 return C.lua_toboolean(l.ptr, C.int(idx)) != 0 575 } 576 577 func (l *State) ToString(idx int) (s string, ok bool) { 578 if l.ptr == nil { 579 return "", false 580 } 581 if !l.isAcceptableIndex(idx) { 582 panic("unacceptable index") 583 } 584 var len C.size_t 585 ptr := C.lua_tolstring(l.ptr, C.int(idx), &len) 586 if ptr == nil { 587 return "", false 588 } 589 return C.GoStringN(ptr, C.int(len)), true 590 } 591 592 func (l *State) RawLen(idx int) uint64 { 593 if l.ptr == nil { 594 return 0 595 } 596 if !l.isAcceptableIndex(idx) { 597 panic("unacceptable index") 598 } 599 return uint64(C.lua_rawlen(l.ptr, C.int(idx))) 600 } 601 602 func (l *State) CopyUserdata(dst []byte, idx, start int) int { 603 if l.ptr == nil { 604 return 0 605 } 606 if !l.isAcceptableIndex(idx) { 607 panic("unacceptable index") 608 } 609 return l.copyUserdata(dst, idx, start) 610 } 611 612 func (l *State) copyUserdata(dst []byte, idx, start int) int { 613 if start < 0 { 614 panic("negative userdata start") 615 } 616 size := int(C.userdatalen(l.ptr, C.int(idx))) 617 if start >= size { 618 return 0 619 } 620 src := unsafe.Slice((*byte)(C.lua_touserdata(l.ptr, C.int(idx))), size) 621 return copy(dst, src[start:]) 622 } 623 624 func (l *State) ToPointer(idx int) uintptr { 625 if l.ptr == nil { 626 return 0 627 } 628 if !l.isAcceptableIndex(idx) { 629 panic("unacceptable index") 630 } 631 return uintptr(C.lua_topointer(l.ptr, C.int(idx))) 632 } 633 634 func (l *State) RawEqual(idx1, idx2 int) bool { 635 if l.ptr == nil { 636 return false 637 } 638 if !l.isAcceptableIndex(idx1) || !l.isAcceptableIndex(idx2) { 639 panic("unacceptable index") 640 } 641 return C.lua_rawequal(l.ptr, C.int(idx1), C.int(idx2)) != 0 642 } 643 644 func (l *State) PushNil() { 645 l.init() 646 if l.top >= l.cap { 647 panic("stack overflow") 648 } 649 C.lua_pushnil(l.ptr) 650 l.top++ 651 } 652 653 func (l *State) PushNumber(n float64) { 654 l.init() 655 if l.top >= l.cap { 656 panic("stack overflow") 657 } 658 C.lua_pushnumber(l.ptr, C.lua_Number(n)) 659 l.top++ 660 } 661 662 func (l *State) PushInteger(n int64) { 663 l.init() 664 if l.top >= l.cap { 665 panic("stack overflow") 666 } 667 C.lua_pushinteger(l.ptr, C.lua_Integer(n)) 668 l.top++ 669 } 670 671 func (l *State) PushString(s string) { 672 l.init() 673 if l.top >= l.cap { 674 panic("stack overflow") 675 } 676 C.zombiezen_lua_pushstring(l.ptr, s) 677 l.top++ 678 } 679 680 func (l *State) PushBoolean(b bool) { 681 l.init() 682 if l.top >= l.cap { 683 panic("stack overflow") 684 } 685 i := C.int(0) 686 if b { 687 i = 1 688 } 689 C.lua_pushboolean(l.ptr, i) 690 l.top++ 691 } 692 693 func (l *State) PushLightUserdata(p uintptr) { 694 l.init() 695 if l.top >= l.cap { 696 panic("stack overflow") 697 } 698 C.pushlightuserdata(l.ptr, C.uintptr_t(p)) 699 l.top++ 700 } 701 702 type Function = func(*State) (int, error) 703 704 func pcall(f Function, l *State) (nResults int, err error) { 705 defer func() { 706 if v := recover(); v != nil { 707 nResults = 0 708 switch v := v.(type) { 709 case error: 710 err = v 711 case string: 712 err = errors.New(v) 713 default: 714 err = fmt.Errorf("%v", v) 715 } 716 } 717 }() 718 return f(l) 719 } 720 721 func (l *State) PushClosure(n int, f Function) { 722 if f == nil { 723 panic("nil Function") 724 } 725 if n < 0 || n > 254 { 726 panic("invalid upvalue count") 727 } 728 l.checkElems(n) 729 l.init() 730 if !l.CheckStack(3) { 731 panic("stack overflow") 732 } 733 data := l.data() 734 funcID := data.nextID 735 if funcID == 0 { 736 panic("ID wrap-around") 737 } 738 data.nextID++ 739 data.closures[funcID] = f 740 741 C.pushclosure(l.ptr, C.uint64_t(funcID), C.int(n)) 742 // lua_pushcclosure pops n, but pushes 1. 743 l.top -= n - 1 744 } 745 746 func (l *State) Global(name string, msgHandler int) (Type, error) { 747 l.init() 748 msgHandler = l.checkMessageHandler(msgHandler) 749 l.RawIndex(RegistryIndex, RegistryIndexGlobals) 750 tp, err := l.Field(-1, name, msgHandler) 751 l.Remove(-2) // remove the globals table 752 return tp, err 753 } 754 755 func (l *State) Table(idx, msgHandler int) (Type, error) { 756 l.checkElems(1) 757 if !l.CheckStack(2) { // gettable needs 2 additional stack slots 758 panic("stack overflow") 759 } 760 if !l.isAcceptableIndex(idx) { 761 panic("unacceptable index") 762 } 763 msgHandler = l.checkMessageHandler(msgHandler) 764 var tp C.int 765 ret := C.gettable(l.ptr, C.int(idx), C.int(msgHandler), &tp) 766 if ret != C.LUA_OK { 767 return TypeNil, fmt.Errorf("lua: table lookup: %w", l.newError(ret)) 768 } 769 return Type(tp), nil 770 } 771 772 func (l *State) Field(idx int, k string, msgHandler int) (Type, error) { 773 l.init() 774 if !l.CheckStack(3) { // gettable needs 2 additional stack slots 775 panic("stack overflow") 776 } 777 idx = l.AbsIndex(idx) 778 msgHandler = l.checkMessageHandler(msgHandler) 779 l.PushString(k) 780 var tp C.int 781 ret := C.gettable(l.ptr, C.int(idx), C.int(msgHandler), &tp) 782 if ret != C.LUA_OK { 783 return TypeNil, fmt.Errorf("lua: get field %q: %w", k, l.newError(ret)) 784 } 785 return Type(tp), nil 786 } 787 788 func (l *State) RawGet(idx int) Type { 789 l.checkElems(1) 790 if !l.isAcceptableIndex(idx) { 791 panic("unacceptable index") 792 } 793 tp := Type(C.lua_rawget(l.ptr, C.int(idx))) 794 return tp 795 } 796 797 func (l *State) RawIndex(idx int, n int64) Type { 798 l.init() 799 if l.top >= l.cap { 800 panic("stack overflow") 801 } 802 if !l.isAcceptableIndex(idx) { 803 panic("unacceptable index") 804 } 805 tp := Type(C.lua_rawgeti(l.ptr, C.int(idx), C.lua_Integer(n))) 806 l.top++ 807 return tp 808 } 809 810 func (l *State) RawField(idx int, k string) Type { 811 idx = l.AbsIndex(idx) 812 l.PushString(k) 813 return l.RawGet(idx) 814 } 815 816 func (l *State) CreateTable(nArr, nRec int) { 817 l.init() 818 if l.top >= l.cap { 819 panic("stack overflow") 820 } 821 C.lua_createtable(l.ptr, C.int(nArr), C.int(nRec)) 822 l.top++ 823 } 824 825 func (l *State) NewUserdataUV(size, nUValue int) { 826 l.init() 827 if l.top >= l.cap { 828 panic("stack overflow") 829 } 830 if size < 0 { 831 panic("negative userdata size") 832 } 833 C.newuserdata(l.ptr, C.size_t(size), C.int(nUValue)) 834 l.top++ 835 } 836 837 func (l *State) SetUserdata(idx int, start int, src []byte) { 838 if !l.isAcceptableIndex(idx) { 839 panic("unacceptable index") 840 } 841 l.setUserdata(idx, start, src) 842 } 843 844 func (l *State) setUserdata(idx int, start int, src []byte) { 845 if start < 0 { 846 panic("negative start") 847 } 848 849 size := int(C.userdatalen(l.ptr, C.int(idx))) 850 if start+len(src) > size { 851 panic("out of userdata bounds") 852 } 853 if len(src) == 0 { 854 return 855 } 856 dst := unsafe.Slice((*byte)(C.lua_touserdata(l.ptr, C.int(idx))), size) 857 copy(dst[start:], src) 858 } 859 860 func (l *State) Metatable(idx int) bool { 861 l.init() 862 if l.top >= l.cap { 863 panic("stack overflow") 864 } 865 if !l.isAcceptableIndex(idx) { 866 panic("unacceptable index") 867 } 868 return l.metatable(idx) 869 } 870 871 func (l *State) metatable(idx int) bool { 872 ok := C.lua_getmetatable(l.ptr, C.int(idx)) != 0 873 if ok { 874 l.top++ 875 } 876 return ok 877 } 878 879 func (l *State) UserValue(idx int, n int) Type { 880 l.init() 881 if l.top >= l.cap { 882 panic("stack overflow") 883 } 884 if !l.isAcceptableIndex(idx) { 885 panic("unacceptable index") 886 } 887 tp := TypeNone 888 if n < 1 { 889 C.lua_pushnil(l.ptr) 890 } else { 891 tp = Type(C.lua_getiuservalue(l.ptr, C.int(idx), C.int(n))) 892 } 893 l.top++ 894 return tp 895 } 896 897 func (l *State) SetGlobal(name string, msgHandler int) error { 898 l.checkElems(1) 899 if msgHandler != 0 { 900 msgHandler = l.AbsIndex(msgHandler) 901 } 902 l.RawIndex(RegistryIndex, RegistryIndexGlobals) 903 l.Rotate(-2, 1) // swap globals table with value 904 err := l.SetField(-2, name, msgHandler) 905 l.Pop(1) // remove the globals table 906 return err 907 } 908 909 func (l *State) SetTable(idx, msgHandler int) error { 910 l.checkElems(2) 911 if !l.CheckStack(2) { // settable needs 2 additional stack slots 912 panic("stack overflow") 913 } 914 if !l.isAcceptableIndex(idx) || msgHandler != 0 && !l.isAcceptableIndex(msgHandler) { 915 panic("unacceptable index") 916 } 917 ret := C.settable(l.ptr, C.int(idx), C.int(msgHandler)) 918 if ret != C.LUA_OK { 919 l.top-- 920 return fmt.Errorf("lua: set table field: %w", l.newError(ret)) 921 } 922 l.top -= 2 923 return nil 924 } 925 926 func (l *State) SetField(idx int, k string, msgHandler int) error { 927 l.checkElems(1) 928 if !l.CheckStack(3) { // settable needs 2 additional stack slots 929 panic("stack overflow") 930 } 931 932 idx = l.AbsIndex(idx) 933 if msgHandler != 0 { 934 msgHandler = l.AbsIndex(msgHandler) 935 } 936 937 l.PushString(k) 938 l.Rotate(-2, 1) 939 ret := C.settable(l.ptr, C.int(idx), C.int(msgHandler)) 940 if ret != C.LUA_OK { 941 l.top-- 942 return fmt.Errorf("lua: set field %q: %w", k, l.newError(ret)) 943 } 944 l.top -= 2 945 return nil 946 } 947 948 func (l *State) RawSet(idx int) { 949 l.checkElems(2) 950 if !l.isAcceptableIndex(idx) { 951 panic("unacceptable index") 952 } 953 C.lua_rawset(l.ptr, C.int(idx)) 954 l.top -= 2 955 } 956 957 func (l *State) RawSetIndex(idx int, n int64) { 958 l.checkElems(1) 959 if !l.isAcceptableIndex(idx) { 960 panic("unacceptable index") 961 } 962 C.lua_rawseti(l.ptr, C.int(idx), C.lua_Integer(n)) 963 l.top-- 964 } 965 966 func (l *State) RawSetField(idx int, k string) { 967 idx = l.AbsIndex(idx) 968 l.PushString(k) 969 l.Rotate(-2, 1) 970 l.RawSet(idx) 971 } 972 973 func (l *State) SetMetatable(objIndex int) { 974 l.checkElems(1) 975 if !l.isAcceptableIndex(objIndex) { 976 panic("unacceptable index") 977 } 978 C.lua_setmetatable(l.ptr, C.int(objIndex)) 979 l.top-- 980 } 981 982 func (l *State) SetUserValue(idx int, n int) bool { 983 l.init() 984 if l.top >= l.cap { 985 panic("stack overflow") 986 } 987 if !l.isAcceptableIndex(idx) { 988 panic("unacceptable index") 989 } 990 if n < 1 { 991 l.Pop(1) 992 return false 993 } 994 ok := C.lua_setiuservalue(l.ptr, C.int(idx), C.int(n)) != 0 995 l.top-- 996 return ok 997 } 998 999 func (l *State) Call(nArgs, nResults, msgHandler int) error { 1000 if nArgs < 0 { 1001 panic("negative arguments") 1002 } 1003 toPop := 1 + nArgs 1004 l.checkElems(toPop) 1005 newTop := -1 1006 if nResults != MultipleReturns { 1007 if nResults < 0 { 1008 panic("negative results") 1009 } 1010 newTop = l.top - toPop + nResults 1011 if newTop > l.cap { 1012 panic("stack overflow") 1013 } 1014 } 1015 msgHandler = l.checkMessageHandler(msgHandler) 1016 1017 ret := C.lua_pcallk(l.ptr, C.int(nArgs), C.int(nResults), C.int(msgHandler), 0, nil) 1018 if ret != C.LUA_OK { 1019 l.top -= toPop - 1 1020 return l.newError(ret) 1021 } 1022 if newTop >= 0 { 1023 l.top = newTop 1024 } else { 1025 l.top = int(C.lua_gettop(l.ptr)) 1026 l.cap = max(l.cap, l.top) 1027 } 1028 return nil 1029 } 1030 1031 const MultipleReturns int = C.LUA_MULTRET 1032 1033 func (l *State) Load(r io.Reader, chunkName string, mode string) error { 1034 l.init() 1035 if l.top >= l.cap { 1036 panic("stack overflow") 1037 } 1038 1039 modeC, err := loadMode(mode) 1040 if err != nil { 1041 l.PushString(err.Error()) 1042 return fmt.Errorf("lua: load %s: %v", formatChunkName(chunkName), err) 1043 } 1044 1045 rr := newReader(r) 1046 defer rr.free() 1047 handle := cgo.NewHandle(rr) 1048 defer handle.Delete() 1049 1050 chunkNameC := C.CString(chunkName) 1051 defer C.free(unsafe.Pointer(chunkNameC)) 1052 1053 ret := C.lua_load(l.ptr, C.lua_Reader(C.zombiezen_lua_reader), unsafe.Pointer(&handle), chunkNameC, modeC) 1054 l.top++ 1055 if ret != C.LUA_OK { 1056 return fmt.Errorf("lua: load %s: %w", formatChunkName(chunkName), l.newError(ret)) 1057 } 1058 return nil 1059 } 1060 1061 func (l *State) LoadString(s string, chunkName string, mode string) error { 1062 l.init() 1063 if l.top >= l.cap { 1064 panic("stack overflow") 1065 } 1066 1067 modeC, err := loadMode(mode) 1068 if err != nil { 1069 l.PushString(err.Error()) 1070 return fmt.Errorf("lua: load %s: %v", formatChunkName(chunkName), err) 1071 } 1072 1073 chunkNameC := C.CString(chunkName) 1074 defer C.free(unsafe.Pointer(chunkNameC)) 1075 1076 ret := C.loadstring(l.ptr, s, chunkNameC, modeC) 1077 l.top++ 1078 if ret != C.LUA_OK { 1079 return fmt.Errorf("lua: load %s: %w", formatChunkName(chunkName), l.newError(ret)) 1080 } 1081 return nil 1082 } 1083 1084 func formatChunkName(chunkName string) string { 1085 if len(chunkName) == 0 || (chunkName[0] != '@' && chunkName[0] != '=') { 1086 return "(string)" 1087 } 1088 return chunkName[1:] 1089 } 1090 1091 func loadMode(mode string) (*C.char, error) { 1092 const modeCStrings = "bt\x00t\x00b\x00" 1093 switch mode { 1094 case "bt": 1095 return (*C.char)(unsafe.Pointer(unsafe.StringData(modeCStrings))), nil 1096 case "t": 1097 return (*C.char)(unsafe.Pointer(unsafe.StringData(modeCStrings[3:]))), nil 1098 case "b": 1099 return (*C.char)(unsafe.Pointer(unsafe.StringData(modeCStrings[5:]))), nil 1100 default: 1101 return nil, fmt.Errorf("unknown load mode %q", mode) 1102 } 1103 } 1104 1105 func (l *State) Dump(w io.Writer, strip bool) (int64, error) { 1106 l.checkElems(1) 1107 state := &writerState{w: cgo.NewHandle(w)} 1108 defer state.w.Delete() 1109 stripInt := C.int(0) 1110 if strip { 1111 stripInt = 1 1112 } 1113 ret := C.lua_dump(l.ptr, C.lua_Writer(C.zombiezen_lua_writercb), unsafe.Pointer(state), stripInt) 1114 var err error 1115 switch { 1116 case state.err != 0: 1117 err = fmt.Errorf("lua: dump function: %w", state.err.Value().(error)) 1118 state.err.Delete() 1119 case ret != 0: 1120 err = fmt.Errorf("lua: dump function: not a function") 1121 } 1122 return state.n, err 1123 } 1124 1125 func (l *State) GC() { 1126 l.init() 1127 C.gcniladic(l.ptr, C.LUA_GCCOLLECT) 1128 } 1129 1130 func (l *State) GCStop() { 1131 l.init() 1132 C.gcniladic(l.ptr, C.LUA_GCSTOP) 1133 } 1134 1135 func (l *State) GCRestart() { 1136 l.init() 1137 C.gcniladic(l.ptr, C.LUA_GCRESTART) 1138 } 1139 1140 func (l *State) GCCount() int64 { 1141 l.init() 1142 kb := int64(C.gcniladic(l.ptr, C.LUA_GCCOUNT)) 1143 b := int64(C.gcniladic(l.ptr, C.LUA_GCCOUNTB)) 1144 return kb<<10 | b 1145 } 1146 1147 func (l *State) GCStep(stepSize int) { 1148 l.init() 1149 C.gcstep(l.ptr, C.int(stepSize)) 1150 } 1151 1152 func (l *State) IsGCRunning() bool { 1153 l.init() 1154 return C.gcniladic(l.ptr, C.LUA_GCISRUNNING) != 0 1155 } 1156 1157 func (l *State) GCIncremental(pause, stepMul, stepSize int) { 1158 l.init() 1159 C.gcinc(l.ptr, C.int(pause), C.int(stepMul), C.int(stepSize)) 1160 } 1161 1162 func (l *State) GCGenerational(minorMul, majorMul int) { 1163 l.init() 1164 C.gcgen(l.ptr, C.int(minorMul), C.int(majorMul)) 1165 } 1166 1167 func (l *State) Next(idx int) bool { 1168 l.checkElems(1) 1169 if !l.isAcceptableIndex(idx) { 1170 panic("unacceptable index") 1171 } 1172 ok := C.lua_next(l.ptr, C.int(idx)) != 0 1173 if ok { 1174 l.top++ 1175 } else { 1176 l.top-- 1177 } 1178 return ok 1179 } 1180 1181 func (l *State) Len(idx int, msgHandler int) error { 1182 l.init() 1183 idx = l.AbsIndex(idx) 1184 msgHandler = l.checkMessageHandler(msgHandler) 1185 C.pushlenfunction(l.ptr) 1186 l.top++ 1187 l.PushValue(idx) 1188 if err := l.Call(1, 1, msgHandler); err != nil { 1189 return fmt.Errorf("lua: length: %w", err) 1190 } 1191 return nil 1192 } 1193 1194 func (l *State) Stack(level int) *ActivationRecord { 1195 l.init() 1196 ar := new(C.lua_Debug) 1197 if C.lua_getstack(l.ptr, C.int(level), ar) == 0 { 1198 return nil 1199 } 1200 return &ActivationRecord{ 1201 state: l, 1202 lptr: l.ptr, 1203 ar: ar, 1204 } 1205 } 1206 1207 func (l *State) Info(what string) *Debug { 1208 l.checkElems(1) 1209 1210 what = strings.TrimPrefix(what, ">") 1211 cwhat := make([]C.char, 0, len(">\x00")+len(what)) 1212 cwhat = append(cwhat, '>') 1213 for _, c := range []byte(what) { 1214 cwhat = append(cwhat, C.char(c)) 1215 } 1216 cwhat = append(cwhat, 0) 1217 1218 var tmp C.lua_Debug 1219 return l.getinfo(&cwhat[0], &tmp) 1220 } 1221 1222 func (l *State) getinfo(what *C.char, ar *C.lua_Debug) *Debug { 1223 if *what == '>' { 1224 l.top-- 1225 } 1226 1227 C.lua_getinfo(l.ptr, what, ar) 1228 1229 db := &Debug{ 1230 CurrentLine: -1, 1231 } 1232 pushFunction := false 1233 pushLines := false 1234 for ; *what != 0; what = (*C.char)(unsafe.Add(unsafe.Pointer(what), 1)) { 1235 switch *what { 1236 case 'f': 1237 pushFunction = true 1238 case 'l': 1239 db.CurrentLine = int(ar.currentline) 1240 case 'n': 1241 if ar.name != nil { 1242 db.Name = C.GoString(ar.name) 1243 } 1244 if ar.namewhat != nil { 1245 db.NameWhat = C.GoString(ar.namewhat) 1246 } 1247 case 'S': 1248 if ar.what != nil { 1249 db.What = C.GoString(ar.what) 1250 } 1251 if ar.source != nil { 1252 db.Source = C.GoStringN(ar.source, C.int(ar.srclen)) 1253 } 1254 db.LineDefined = int(ar.linedefined) 1255 db.LastLineDefined = int(ar.lastlinedefined) 1256 db.ShortSource = C.GoString(&ar.short_src[0]) 1257 case 't': 1258 db.IsTailCall = ar.istailcall != 0 1259 case 'u': 1260 db.NumUpvalues = uint8(ar.nups) 1261 db.NumParams = uint8(ar.nparams) 1262 db.IsVararg = ar.isvararg != 0 1263 case 'L': 1264 pushLines = true 1265 } 1266 } 1267 if pushFunction { 1268 l.top++ 1269 } 1270 if pushLines { 1271 l.top++ 1272 } 1273 return db 1274 } 1275 1276 type Debug struct { 1277 Name string 1278 NameWhat string 1279 What string 1280 Source string 1281 ShortSource string 1282 CurrentLine int 1283 LineDefined int 1284 LastLineDefined int 1285 NumUpvalues uint8 1286 NumParams uint8 1287 IsVararg bool 1288 IsTailCall bool 1289 } 1290 1291 type ActivationRecord struct { 1292 state *State 1293 lptr *C.lua_State 1294 ar *C.lua_Debug 1295 } 1296 1297 func (ar *ActivationRecord) isValid() bool { 1298 return ar != nil && ar.state != nil && ar.state.ptr == ar.lptr 1299 } 1300 1301 func (ar *ActivationRecord) Info(what string) *Debug { 1302 if strings.HasPrefix(what, ">") { 1303 panic("what must not start with '>'") 1304 } 1305 if !ar.isValid() { 1306 return nil 1307 } 1308 cwhat := C.CString(what) 1309 defer C.free(unsafe.Pointer(cwhat)) 1310 return ar.state.getinfo(cwhat, ar.ar) 1311 } 1312 1313 const ( 1314 GName = C.LUA_GNAME 1315 1316 CoroutineLibraryName = C.LUA_COLIBNAME 1317 TableLibraryName = C.LUA_TABLIBNAME 1318 IOLibraryName = C.LUA_IOLIBNAME 1319 OSLibraryName = C.LUA_OSLIBNAME 1320 StringLibraryName = C.LUA_STRLIBNAME 1321 UTF8LibraryName = C.LUA_UTF8LIBNAME 1322 MathLibraryName = C.LUA_MATHLIBNAME 1323 DebugLibraryName = C.LUA_DBLIBNAME 1324 PackageLibraryName = C.LUA_LOADLIBNAME 1325 ) 1326 1327 func PushOpenBase(l *State) { 1328 l.init() 1329 if l.top >= l.cap { 1330 panic("stack overflow") 1331 } 1332 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_base), 0) 1333 l.top++ 1334 } 1335 1336 func PushOpenCoroutine(l *State) { 1337 l.init() 1338 if l.top >= l.cap { 1339 panic("stack overflow") 1340 } 1341 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_coroutine), 0) 1342 l.top++ 1343 } 1344 1345 func PushOpenTable(l *State) { 1346 l.init() 1347 if l.top >= l.cap { 1348 panic("stack overflow") 1349 } 1350 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_table), 0) 1351 l.top++ 1352 } 1353 1354 func PushOpenString(l *State) { 1355 l.init() 1356 if l.top >= l.cap { 1357 panic("stack overflow") 1358 } 1359 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_string), 0) 1360 l.top++ 1361 } 1362 1363 func PushOpenUTF8(l *State) { 1364 l.init() 1365 if l.top >= l.cap { 1366 panic("stack overflow") 1367 } 1368 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_utf8), 0) 1369 l.top++ 1370 } 1371 1372 func PushOpenMath(l *State) { 1373 l.init() 1374 if l.top >= l.cap { 1375 panic("stack overflow") 1376 } 1377 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_math), 0) 1378 l.top++ 1379 } 1380 1381 func PushOpenDebug(l *State) { 1382 l.init() 1383 if l.top >= l.cap { 1384 panic("stack overflow") 1385 } 1386 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_debug), 0) 1387 l.top++ 1388 } 1389 1390 func PushOpenPackage(l *State) { 1391 l.init() 1392 if l.top >= l.cap { 1393 panic("stack overflow") 1394 } 1395 C.lua_pushcclosure(l.ptr, C.lua_CFunction(C.luaopen_package), 0) 1396 l.top++ 1397 } 1398 1399 const readerBufferSize = 4096 1400 1401 type reader struct { 1402 r io.Reader 1403 buf *C.char 1404 } 1405 1406 func newReader(r io.Reader) *reader { 1407 return &reader{ 1408 r: r, 1409 buf: (*C.char)(C.calloc(readerBufferSize, C.size_t(unsafe.Sizeof(C.char(0))))), 1410 } 1411 } 1412 1413 func (r *reader) free() { 1414 if r.buf != nil { 1415 C.free(unsafe.Pointer(r.buf)) 1416 r.buf = nil 1417 } 1418 } 1419 1420 func copyUint64(l *State, idx int) uint64 { 1421 var buf [8]byte 1422 l.copyUserdata(buf[:], idx, 0) 1423 var x uint64 1424 for i, b := range buf { 1425 x |= uint64(b) << (i * 8) 1426 } 1427 return x 1428 } 1429 1430 func setUint64(l *State, idx int, x uint64) { 1431 var buf [8]byte 1432 for i := range buf { 1433 buf[i] = byte(x >> (i * 8)) 1434 } 1435 l.setUserdata(idx, 0, buf[:]) 1436 } 1437 1438 // NewMetatable is the auxlib NewMetatable function. 1439 func NewMetatable(l *State, tname string) bool { 1440 if Metatable(l, tname) != TypeNil { 1441 // Name already in use. 1442 return false 1443 } 1444 l.Pop(1) 1445 l.CreateTable(0, 2) 1446 l.PushString(tname) 1447 l.RawSetField(-2, "__name") // metatable.__name = tname 1448 l.PushValue(-1) 1449 l.RawSetField(RegistryIndex, tname) 1450 return true 1451 } 1452 1453 // Metatable is the auxlib Metatable function. 1454 func Metatable(l *State, tname string) Type { 1455 return l.RawField(RegistryIndex, tname) 1456 } 1457 1458 func isPseudo(i int) bool { 1459 return i <= RegistryIndex 1460 } 1461 1462 const goClosureUpvalueIndex = C.LUA_REGISTRYINDEX - 1 1463 1464 func UpvalueIndex(i int) int { 1465 if i < 1 || i > 255 { 1466 panic("invalid upvalue index") 1467 } 1468 return C.LUA_REGISTRYINDEX - (i + 1) 1469 } 1470 1471 type luaError struct { 1472 code C.int 1473 msg string 1474 } 1475 1476 func (l *State) newError(code C.int) error { 1477 e := &luaError{code: code} 1478 e.msg, _ = l.ToString(-1) 1479 return e 1480 } 1481 1482 func (e *luaError) Error() string { 1483 if e.msg != "" { 1484 return e.msg 1485 } 1486 switch e.code { 1487 case C.LUA_ERRRUN: 1488 return "runtime error" 1489 case C.LUA_ERRMEM: 1490 return "memory allocation error" 1491 case C.LUA_ERRERR: 1492 return "error while running message handler" 1493 case C.LUA_ERRSYNTAX: 1494 return "syntax error" 1495 case C.LUA_YIELD: 1496 return "coroutine yield" 1497 default: 1498 return "unknown error" 1499 } 1500 } 1501 1502 const ( 1503 ErrRun int = C.LUA_ERRRUN 1504 ErrMem int = C.LUA_ERRMEM 1505 ErrErr int = C.LUA_ERRERR 1506 ErrSyntax int = C.LUA_ERRSYNTAX 1507 Yield int = C.LUA_YIELD 1508 ) 1509 1510 func AsError(err error) (code int, ok bool) { 1511 if err == nil { 1512 return C.LUA_OK, true 1513 } 1514 var e *luaError 1515 if !errors.As(err, &e) { 1516 return 0, false 1517 } 1518 return int(e.code), true 1519 }