github.com/shawnclovie/gopher-lua@v0.0.0-20200520092726-90b44ec0e2f2/baselib.go (about) 1 package lua 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "runtime" 8 "strconv" 9 "strings" 10 ) 11 12 /* basic functions {{{ */ 13 14 func OpenBase(L *LState) int { 15 global := L.Get(GlobalsIndex).(*LTable) 16 L.SetGlobal("_G", global) 17 L.SetGlobal("_VERSION", LString(LuaVersion)) 18 L.SetGlobal("_GOPHER_LUA_VERSION", LString(PackageName+" "+PackageVersion)) 19 basemod := L.RegisterModule("_G", baseFuncs) 20 global.RawSetString("ipairs", L.NewClosure(baseIpairs, L.NewFunction(ipairsaux))) 21 global.RawSetString("pairs", L.NewClosure(basePairs, L.NewFunction(pairsaux))) 22 L.Push(basemod) 23 return 1 24 } 25 26 var baseFuncs = map[string]LGFunction{ 27 "assert": baseAssert, 28 "collectgarbage": baseCollectGarbage, 29 "dofile": baseDoFile, 30 "error": baseError, 31 "getfenv": baseGetFEnv, 32 "getmetatable": baseGetMetatable, 33 "load": baseLoad, 34 "loadfile": baseLoadFile, 35 "loadstring": baseLoadString, 36 "next": baseNext, 37 "pcall": basePCall, 38 "print": basePrint, 39 "rawequal": baseRawEqual, 40 "rawget": baseRawGet, 41 "rawset": baseRawSet, 42 "select": baseSelect, 43 "_printregs": base_PrintRegs, 44 "setfenv": baseSetFEnv, 45 "setmetatable": baseSetMetatable, 46 "tonumber": baseToNumber, 47 "tostring": baseToString, 48 "type": baseType, 49 "unpack": baseUnpack, 50 "xpcall": baseXPCall, 51 // loadlib 52 "module": loModule, 53 "require": loRequire, 54 // hidden features 55 "newproxy": baseNewProxy, 56 } 57 58 func baseAssert(L *LState) int { 59 if !L.ToBool(1) { 60 L.RaiseError(L.OptString(2, "assertion failed!")) 61 return 0 62 } 63 return L.GetTop() 64 } 65 66 func baseCollectGarbage(L *LState) int { 67 runtime.GC() 68 return 0 69 } 70 71 func baseDoFile(L *LState) int { 72 src := L.ToString(1) 73 top := L.GetTop() 74 fn, err := L.LoadFile(src) 75 if err != nil { 76 L.Push(LString(err.Error())) 77 L.Panic(L) 78 } 79 L.Push(fn) 80 L.Call(0, MultRet) 81 return L.GetTop() - top 82 } 83 84 func baseError(L *LState) int { 85 obj := L.CheckAny(1) 86 level := L.OptInt(2, 1) 87 L.Error(obj, level) 88 return 0 89 } 90 91 func baseGetFEnv(L *LState) int { 92 var value LValue 93 if L.GetTop() == 0 { 94 value = LNumber(1) 95 } else { 96 value = L.Get(1) 97 } 98 99 if fn, ok := value.(*LFunction); ok { 100 if !fn.IsG { 101 L.Push(fn.Env) 102 } else { 103 L.Push(L.G.Global) 104 } 105 return 1 106 } 107 108 if number, ok := value.(LNumber); ok { 109 level := int(float64(number)) 110 if level <= 0 { 111 L.Push(L.Env) 112 } else { 113 cf := L.currentFrame 114 for i := 0; i < level && cf != nil; i++ { 115 cf = cf.Parent 116 } 117 if cf == nil || cf.Fn.IsG { 118 L.Push(L.G.Global) 119 } else { 120 L.Push(cf.Fn.Env) 121 } 122 } 123 return 1 124 } 125 126 L.Push(L.G.Global) 127 return 1 128 } 129 130 func baseGetMetatable(L *LState) int { 131 L.Push(L.GetMetatable(L.CheckAny(1))) 132 return 1 133 } 134 135 func ipairsaux(L *LState) int { 136 tb := L.CheckTable(1) 137 i := L.CheckInt(2) 138 i++ 139 v := tb.RawGetInt(i) 140 if v == LNil { 141 return 0 142 } else { 143 L.Pop(1) 144 L.Push(LNumber(i)) 145 L.Push(LNumber(i)) 146 L.Push(v) 147 return 2 148 } 149 } 150 151 func baseIpairs(L *LState) int { 152 tb := L.CheckTable(1) 153 L.Push(L.Get(UpvalueIndex(1))) 154 L.Push(tb) 155 L.Push(LNumber(0)) 156 return 3 157 } 158 159 func loadaux(L *LState, reader io.Reader, chunkname string) int { 160 if fn, err := L.Load(reader, chunkname); err != nil { 161 L.Push(LNil) 162 L.Push(LString(err.Error())) 163 return 2 164 } else { 165 L.Push(fn) 166 return 1 167 } 168 } 169 170 func baseLoad(L *LState) int { 171 fn := L.CheckFunction(1) 172 chunkname := L.OptString(2, "?") 173 top := L.GetTop() 174 buf := []string{} 175 for { 176 L.SetTop(top) 177 L.Push(fn) 178 L.Call(0, 1) 179 ret := L.reg.Pop() 180 if ret == LNil { 181 break 182 } else if LVCanConvToString(ret) { 183 str := ret.String() 184 if len(str) > 0 { 185 buf = append(buf, string(str)) 186 } else { 187 break 188 } 189 } else { 190 L.Push(LNil) 191 L.Push(LString("reader function must return a string")) 192 return 2 193 } 194 } 195 return loadaux(L, strings.NewReader(strings.Join(buf, "")), chunkname) 196 } 197 198 func baseLoadFile(L *LState) int { 199 var reader io.Reader 200 var chunkname string 201 var err error 202 if L.GetTop() < 1 { 203 reader = os.Stdin 204 chunkname = "<stdin>" 205 } else { 206 chunkname = L.CheckString(1) 207 reader, err = os.Open(chunkname) 208 if err != nil { 209 L.Push(LNil) 210 L.Push(LString(fmt.Sprintf("can not open file: %v", chunkname))) 211 return 2 212 } 213 defer reader.(*os.File).Close() 214 } 215 return loadaux(L, reader, chunkname) 216 } 217 218 func baseLoadString(L *LState) int { 219 return loadaux(L, strings.NewReader(L.CheckString(1)), L.OptString(2, "<string>")) 220 } 221 222 func baseNext(L *LState) int { 223 tb := L.CheckTable(1) 224 index := LNil 225 if L.GetTop() >= 2 { 226 index = L.Get(2) 227 } 228 key, value := tb.Next(index) 229 if key == LNil { 230 L.Push(LNil) 231 return 1 232 } 233 L.Push(key) 234 L.Push(value) 235 return 2 236 } 237 238 func pairsaux(L *LState) int { 239 tb := L.CheckTable(1) 240 key, value := tb.Next(L.Get(2)) 241 if key == LNil { 242 return 0 243 } else { 244 L.Pop(1) 245 L.Push(key) 246 L.Push(key) 247 L.Push(value) 248 return 2 249 } 250 } 251 252 func basePairs(L *LState) int { 253 tb := L.CheckTable(1) 254 L.Push(L.Get(UpvalueIndex(1))) 255 L.Push(tb) 256 L.Push(LNil) 257 return 3 258 } 259 260 func basePCall(L *LState) int { 261 L.CheckAny(1) 262 v := L.Get(1) 263 if v.Type() != LTFunction { 264 L.Push(LFalse) 265 L.Push(LString("attempt to call a " + v.Type().String() + " value")) 266 return 2 267 } 268 nargs := L.GetTop() - 1 269 if err := L.PCall(nargs, MultRet, nil); err != nil { 270 L.Push(LFalse) 271 if aerr, ok := err.(*ApiError); ok { 272 L.Push(aerr.Object) 273 } else { 274 L.Push(LString(err.Error())) 275 } 276 return 2 277 } else { 278 L.Insert(LTrue, 1) 279 return L.GetTop() 280 } 281 } 282 283 func basePrint(L *LState) int { 284 top := L.GetTop() 285 for i := 1; i <= top; i++ { 286 fmt.Print(L.ToStringMeta(L.Get(i)).String()) 287 if i != top { 288 fmt.Print("\t") 289 } 290 } 291 fmt.Println("") 292 return 0 293 } 294 295 func base_PrintRegs(L *LState) int { 296 L.printReg() 297 return 0 298 } 299 300 func baseRawEqual(L *LState) int { 301 if L.CheckAny(1) == L.CheckAny(2) { 302 L.Push(LTrue) 303 } else { 304 L.Push(LFalse) 305 } 306 return 1 307 } 308 309 func baseRawGet(L *LState) int { 310 L.Push(L.RawGet(L.CheckTable(1), L.CheckAny(2))) 311 return 1 312 } 313 314 func baseRawSet(L *LState) int { 315 L.RawSet(L.CheckTable(1), L.CheckAny(2), L.CheckAny(3)) 316 return 0 317 } 318 319 func baseSelect(L *LState) int { 320 L.CheckTypes(1, LTNumber, LTString) 321 switch lv := L.Get(1).(type) { 322 case LNumber: 323 idx := int(lv) 324 num := L.reg.Top() - L.indexToReg(int(lv)) - 1 325 if idx < 0 { 326 num++ 327 } 328 return num 329 case LString: 330 if string(lv) != "#" { 331 L.ArgError(1, "invalid string '"+string(lv)+"'") 332 } 333 L.Push(LNumber(L.GetTop() - 1)) 334 return 1 335 } 336 return 0 337 } 338 339 func baseSetFEnv(L *LState) int { 340 var value LValue 341 if L.GetTop() == 0 { 342 value = LNumber(1) 343 } else { 344 value = L.Get(1) 345 } 346 env := L.CheckTable(2) 347 348 if fn, ok := value.(*LFunction); ok { 349 if fn.IsG { 350 L.RaiseError("cannot change the environment of given object") 351 } else { 352 fn.Env = env 353 L.Push(fn) 354 return 1 355 } 356 } 357 358 if number, ok := value.(LNumber); ok { 359 level := int(float64(number)) 360 if level <= 0 { 361 L.Env = env 362 return 0 363 } 364 365 cf := L.currentFrame 366 for i := 0; i < level && cf != nil; i++ { 367 cf = cf.Parent 368 } 369 if cf == nil || cf.Fn.IsG { 370 L.RaiseError("cannot change the environment of given object") 371 } else { 372 cf.Fn.Env = env 373 L.Push(cf.Fn) 374 return 1 375 } 376 } 377 378 L.RaiseError("cannot change the environment of given object") 379 return 0 380 } 381 382 func baseSetMetatable(L *LState) int { 383 L.CheckTypes(2, LTNil, LTTable) 384 obj := L.Get(1) 385 if obj == LNil { 386 L.RaiseError("cannot set metatable to a nil object.") 387 } 388 mt := L.Get(2) 389 if m := L.metatable(obj, true); m != LNil { 390 if tb, ok := m.(*LTable); ok && tb.RawGetString("__metatable") != LNil { 391 L.RaiseError("cannot change a protected metatable") 392 } 393 } 394 L.SetMetatable(obj, mt) 395 L.SetTop(1) 396 return 1 397 } 398 399 func baseToNumber(L *LState) int { 400 base := L.OptInt(2, 10) 401 noBase := L.Get(2) == LNil 402 403 switch lv := L.CheckAny(1).(type) { 404 case LNumber: 405 L.Push(lv) 406 case LString: 407 str := strings.Trim(string(lv), " \n\t") 408 if strings.Index(str, ".") > -1 { 409 if v, err := strconv.ParseFloat(str, LNumberBit); err != nil { 410 L.Push(LNil) 411 } else { 412 L.Push(LNumber(v)) 413 } 414 } else { 415 if noBase && strings.HasPrefix(strings.ToLower(str), "0x") { 416 base, str = 16, str[2:] // Hex number 417 } 418 if v, err := strconv.ParseInt(str, base, LNumberBit); err != nil { 419 L.Push(LNil) 420 } else { 421 L.Push(LNumber(v)) 422 } 423 } 424 default: 425 L.Push(LNil) 426 } 427 return 1 428 } 429 430 func baseToString(L *LState) int { 431 v1 := L.CheckAny(1) 432 L.Push(L.ToStringMeta(v1)) 433 return 1 434 } 435 436 func baseType(L *LState) int { 437 L.Push(LString(L.CheckAny(1).Type().String())) 438 return 1 439 } 440 441 func baseUnpack(L *LState) int { 442 tb := L.CheckTable(1) 443 start := L.OptInt(2, 1) 444 end := L.OptInt(3, tb.Len()) 445 for i := start; i <= end; i++ { 446 L.Push(tb.RawGetInt(i)) 447 } 448 ret := end - start + 1 449 if ret < 0 { 450 return 0 451 } 452 return ret 453 } 454 455 func baseXPCall(L *LState) int { 456 fn := L.CheckFunction(1) 457 errfunc := L.CheckFunction(2) 458 459 top := L.GetTop() 460 L.Push(fn) 461 if err := L.PCall(0, MultRet, errfunc); err != nil { 462 L.Push(LFalse) 463 if aerr, ok := err.(*ApiError); ok { 464 L.Push(aerr.Object) 465 } else { 466 L.Push(LString(err.Error())) 467 } 468 return 2 469 } else { 470 L.Insert(LTrue, top+1) 471 return L.GetTop() - top 472 } 473 } 474 475 /* }}} */ 476 477 /* load lib {{{ */ 478 479 func loModule(L *LState) int { 480 name := L.CheckString(1) 481 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 482 tb := L.GetField(loaded, name) 483 if _, ok := tb.(*LTable); !ok { 484 tb = L.FindTable(L.Get(GlobalsIndex).(*LTable), name, 1) 485 if tb == LNil { 486 L.RaiseError("name conflict for module: %v", name) 487 } 488 L.SetField(loaded, name, tb) 489 } 490 if L.GetField(tb, "_NAME") == LNil { 491 L.SetField(tb, "_M", tb) 492 L.SetField(tb, "_NAME", LString(name)) 493 names := strings.Split(name, ".") 494 pname := "" 495 if len(names) > 1 { 496 pname = strings.Join(names[:len(names)-1], ".") + "." 497 } 498 L.SetField(tb, "_PACKAGE", LString(pname)) 499 } 500 501 caller := L.currentFrame.Parent 502 if caller == nil { 503 L.RaiseError("no calling stack.") 504 } else if caller.Fn.IsG { 505 L.RaiseError("module() can not be called from GFunctions.") 506 } 507 L.SetFEnv(caller.Fn, tb) 508 509 top := L.GetTop() 510 for i := 2; i <= top; i++ { 511 L.Push(L.Get(i)) 512 L.Push(tb) 513 L.Call(1, 0) 514 } 515 L.Push(tb) 516 return 1 517 } 518 519 var loopdetection = &LUserData{} 520 521 func loRequire(L *LState) int { 522 name := L.CheckString(1) 523 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 524 lv := L.GetField(loaded, name) 525 if LVAsBool(lv) { 526 if lv == loopdetection { 527 L.RaiseError("loop or previous error loading module: %s", name) 528 } 529 L.Push(lv) 530 return 1 531 } 532 loaders, ok := L.GetField(L.Get(RegistryIndex), "_LOADERS").(*LTable) 533 if !ok { 534 L.RaiseError("package.loaders must be a table") 535 } 536 messages := []string{} 537 var modasfunc LValue 538 for i := 1; ; i++ { 539 loader := L.RawGetInt(loaders, i) 540 if loader == LNil { 541 L.RaiseError("module %s not found:\n\t%s, ", name, strings.Join(messages, "\n\t")) 542 } 543 L.Push(loader) 544 L.Push(LString(name)) 545 L.Call(1, 1) 546 ret := L.reg.Pop() 547 switch retv := ret.(type) { 548 case *LFunction: 549 modasfunc = retv 550 goto loopbreak 551 case LString: 552 messages = append(messages, string(retv)) 553 } 554 } 555 loopbreak: 556 L.SetField(loaded, name, loopdetection) 557 L.Push(modasfunc) 558 L.Push(LString(name)) 559 L.Call(1, 1) 560 ret := L.reg.Pop() 561 modv := L.GetField(loaded, name) 562 if ret != LNil && modv == loopdetection { 563 L.SetField(loaded, name, ret) 564 L.Push(ret) 565 } else if modv == loopdetection { 566 L.SetField(loaded, name, LTrue) 567 L.Push(LTrue) 568 } else { 569 L.Push(modv) 570 } 571 return 1 572 } 573 574 /* }}} */ 575 576 /* hidden features {{{ */ 577 578 func baseNewProxy(L *LState) int { 579 ud := L.NewUserData() 580 L.SetTop(1) 581 if L.Get(1) == LTrue { 582 L.SetMetatable(ud, L.NewTable()) 583 } else if d, ok := L.Get(1).(*LUserData); ok { 584 L.SetMetatable(ud, L.GetMetatable(d)) 585 } 586 L.Push(ud) 587 return 1 588 } 589 590 /* }}} */ 591 592 //