github.com/awirix/lua@v1.6.0/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 // TODO: support strings as the first argument 172 arg := L.CheckAny(1) 173 var ( 174 fn *LFunction 175 buf []string 176 ) 177 178 if arg.Type() == LTFunction { 179 fn = arg.(*LFunction) 180 } else if arg.Type() == LTString { 181 buf = append(buf, arg.String()) 182 } else { 183 L.RaiseError("load: argument must be a function or a string") 184 return 0 185 } 186 187 chunkname := L.OptString(2, "?") 188 top := L.GetTop() 189 if fn != nil { 190 for { 191 L.SetTop(top) 192 L.Push(fn) 193 L.Call(0, 1) 194 ret := L.reg.Pop() 195 if ret == LNil { 196 break 197 } else if LVCanConvToString(ret) { 198 str := ret.String() 199 if len(str) > 0 { 200 buf = append(buf, string(str)) 201 } else { 202 break 203 } 204 } else { 205 L.Push(LNil) 206 L.Push(LString("reader function must return a string")) 207 return 2 208 } 209 } 210 } 211 return loadaux(L, strings.NewReader(strings.Join(buf, "")), chunkname) 212 } 213 214 func baseLoadFile(L *LState) int { 215 var reader io.Reader 216 var chunkname string 217 var err error 218 if L.GetTop() < 1 { 219 reader = os.Stdin 220 chunkname = "<stdin>" 221 } else { 222 chunkname = L.CheckString(1) 223 reader, err = os.Open(chunkname) 224 if err != nil { 225 L.Push(LNil) 226 L.Push(LString(fmt.Sprintf("can not open file: %v", chunkname))) 227 return 2 228 } 229 defer reader.(*os.File).Close() 230 } 231 return loadaux(L, reader, chunkname) 232 } 233 234 func baseLoadString(L *LState) int { 235 return loadaux(L, strings.NewReader(L.CheckString(1)), L.OptString(2, "<string>")) 236 } 237 238 func baseNext(L *LState) int { 239 tb := L.CheckTable(1) 240 index := LNil 241 if L.GetTop() >= 2 { 242 index = L.Get(2) 243 } 244 key, value := tb.Next(index) 245 if key == LNil { 246 L.Push(LNil) 247 return 1 248 } 249 L.Push(key) 250 L.Push(value) 251 return 2 252 } 253 254 func pairsaux(L *LState) int { 255 tb := L.CheckTable(1) 256 key, value := tb.Next(L.Get(2)) 257 if key == LNil { 258 return 0 259 } else { 260 L.Pop(1) 261 L.Push(key) 262 L.Push(key) 263 L.Push(value) 264 return 2 265 } 266 } 267 268 func basePairs(L *LState) int { 269 tb := L.CheckTable(1) 270 L.Push(L.Get(UpvalueIndex(1))) 271 L.Push(tb) 272 L.Push(LNil) 273 return 3 274 } 275 276 func basePCall(L *LState) int { 277 L.CheckAny(1) 278 v := L.Get(1) 279 if v.Type() != LTFunction && L.GetMetaField(v, "__call").Type() != LTFunction { 280 L.Push(LFalse) 281 L.Push(LString("attempt to call a " + v.Type().String() + " value")) 282 return 2 283 } 284 nargs := L.GetTop() - 1 285 if err := L.PCall(nargs, MultRet, nil); err != nil { 286 L.Push(LFalse) 287 if aerr, ok := err.(*ApiError); ok { 288 L.Push(aerr.Object) 289 } else { 290 L.Push(LString(err.Error())) 291 } 292 return 2 293 } else { 294 L.Insert(LTrue, 1) 295 return L.GetTop() 296 } 297 } 298 299 func basePrint(L *LState) int { 300 top := L.GetTop() 301 for i := 1; i <= top; i++ { 302 fmt.Fprint(L.Options.Stdout, L.ToStringMeta(L.Get(i)).String()) 303 if i != top { 304 fmt.Fprint(L.Options.Stdout, "\t") 305 } 306 } 307 fmt.Fprintln(L.Options.Stdout, "") 308 return 0 309 } 310 311 func base_PrintRegs(L *LState) int { 312 L.printReg() 313 return 0 314 } 315 316 func baseRawEqual(L *LState) int { 317 if L.CheckAny(1) == L.CheckAny(2) { 318 L.Push(LTrue) 319 } else { 320 L.Push(LFalse) 321 } 322 return 1 323 } 324 325 func baseRawGet(L *LState) int { 326 L.Push(L.RawGet(L.CheckTable(1), L.CheckAny(2))) 327 return 1 328 } 329 330 func baseRawSet(L *LState) int { 331 L.RawSet(L.CheckTable(1), L.CheckAny(2), L.CheckAny(3)) 332 return 0 333 } 334 335 func baseSelect(L *LState) int { 336 L.CheckTypes(1, LTNumber, LTString) 337 switch lv := L.Get(1).(type) { 338 case LNumber: 339 idx := int(lv) 340 num := L.GetTop() 341 if idx < 0 { 342 idx = num + idx 343 } else if idx > num { 344 idx = num 345 } 346 if 1 > idx { 347 L.ArgError(1, "index out of range") 348 } 349 return num - idx 350 case LString: 351 if string(lv) != "#" { 352 L.ArgError(1, "invalid string '"+string(lv)+"'") 353 } 354 L.Push(LNumber(L.GetTop() - 1)) 355 return 1 356 } 357 return 0 358 } 359 360 func baseSetFEnv(L *LState) int { 361 var value LValue 362 if L.GetTop() == 0 { 363 value = LNumber(1) 364 } else { 365 value = L.Get(1) 366 } 367 env := L.CheckTable(2) 368 369 if fn, ok := value.(*LFunction); ok { 370 if fn.IsG { 371 L.RaiseError("cannot change the environment of given object") 372 } else { 373 fn.Env = env 374 L.Push(fn) 375 return 1 376 } 377 } 378 379 if number, ok := value.(LNumber); ok { 380 level := int(float64(number)) 381 if level <= 0 { 382 L.Env = env 383 return 0 384 } 385 386 cf := L.currentFrame 387 for i := 0; i < level && cf != nil; i++ { 388 cf = cf.Parent 389 } 390 if cf == nil || cf.Fn.IsG { 391 L.RaiseError("cannot change the environment of given object") 392 } else { 393 cf.Fn.Env = env 394 L.Push(cf.Fn) 395 return 1 396 } 397 } 398 399 L.RaiseError("cannot change the environment of given object") 400 return 0 401 } 402 403 func baseSetMetatable(L *LState) int { 404 L.CheckTypes(2, LTNil, LTTable) 405 obj := L.Get(1) 406 if obj == LNil { 407 L.RaiseError("cannot set metatable to a nil object.") 408 } 409 mt := L.Get(2) 410 if m := L.metatable(obj, true); m != LNil { 411 if tb, ok := m.(*LTable); ok && tb.RawGetString("__metatable") != LNil { 412 L.RaiseError("cannot change a protected metatable") 413 } 414 } 415 L.SetMetatable(obj, mt) 416 L.SetTop(1) 417 return 1 418 } 419 420 func baseToNumber(L *LState) int { 421 base := L.OptInt(2, 10) 422 noBase := L.Get(2) == LNil 423 424 switch lv := L.CheckAny(1).(type) { 425 case LNumber: 426 L.Push(lv) 427 case LString: 428 str := strings.Trim(string(lv), " \n\t") 429 if strings.Index(str, ".") > -1 { 430 if v, err := strconv.ParseFloat(str, LNumberBit); err != nil { 431 L.Push(LNil) 432 } else { 433 L.Push(LNumber(v)) 434 } 435 } else { 436 if noBase && strings.HasPrefix(strings.ToLower(str), "0x") { 437 base, str = 16, str[2:] // Hex number 438 } 439 if v, err := strconv.ParseInt(str, base, LNumberBit); err != nil { 440 L.Push(LNil) 441 } else { 442 L.Push(LNumber(v)) 443 } 444 } 445 default: 446 L.Push(LNil) 447 } 448 return 1 449 } 450 451 func baseToString(L *LState) int { 452 v1 := L.CheckAny(1) 453 L.Push(L.ToStringMeta(v1)) 454 return 1 455 } 456 457 func baseType(L *LState) int { 458 L.Push(LString(L.CheckAny(1).Type().String())) 459 return 1 460 } 461 462 func baseUnpack(L *LState) int { 463 tb := L.CheckTable(1) 464 start := L.OptInt(2, 1) 465 end := L.OptInt(3, tb.Len()) 466 for i := start; i <= end; i++ { 467 L.Push(tb.RawGetInt(i)) 468 } 469 ret := end - start + 1 470 if ret < 0 { 471 return 0 472 } 473 return ret 474 } 475 476 func baseXPCall(L *LState) int { 477 fn := L.CheckFunction(1) 478 errfunc := L.CheckFunction(2) 479 480 top := L.GetTop() 481 L.Push(fn) 482 if err := L.PCall(0, MultRet, errfunc); err != nil { 483 L.Push(LFalse) 484 if aerr, ok := err.(*ApiError); ok { 485 L.Push(aerr.Object) 486 } else { 487 L.Push(LString(err.Error())) 488 } 489 return 2 490 } else { 491 L.Insert(LTrue, top+1) 492 return L.GetTop() - top 493 } 494 } 495 496 /* }}} */ 497 498 /* load lib {{{ */ 499 500 func loModule(L *LState) int { 501 name := L.CheckString(1) 502 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 503 tb := L.GetField(loaded, name) 504 if _, ok := tb.(*LTable); !ok { 505 tb = L.FindTable(L.Get(GlobalsIndex).(*LTable), name, 1) 506 if tb == LNil { 507 L.RaiseError("name conflict for module: %v", name) 508 } 509 L.SetField(loaded, name, tb) 510 } 511 if L.GetField(tb, "_NAME") == LNil { 512 L.SetField(tb, "_M", tb) 513 L.SetField(tb, "_NAME", LString(name)) 514 names := strings.Split(name, ".") 515 pname := "" 516 if len(names) > 1 { 517 pname = strings.Join(names[:len(names)-1], ".") + "." 518 } 519 L.SetField(tb, "_PACKAGE", LString(pname)) 520 } 521 522 caller := L.currentFrame.Parent 523 if caller == nil { 524 L.RaiseError("no calling stack.") 525 } else if caller.Fn.IsG { 526 L.RaiseError("module() can not be called from GFunctions.") 527 } 528 L.SetFEnv(caller.Fn, tb) 529 530 top := L.GetTop() 531 for i := 2; i <= top; i++ { 532 L.Push(L.Get(i)) 533 L.Push(tb) 534 L.Call(1, 0) 535 } 536 L.Push(tb) 537 return 1 538 } 539 540 var loopdetection = &LUserData{} 541 542 func loRequire(L *LState) int { 543 name := L.CheckString(1) 544 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 545 lv := L.GetField(loaded, name) 546 if LVAsBool(lv) { 547 if lv == loopdetection { 548 L.RaiseError("loop or previous error loading module: %s", name) 549 } 550 L.Push(lv) 551 return 1 552 } 553 loaders, ok := L.GetField(L.Get(RegistryIndex), "_LOADERS").(*LTable) 554 if !ok { 555 L.RaiseError("package.loaders must be a table") 556 } 557 messages := []string{} 558 var modasfunc LValue 559 for i := 1; ; i++ { 560 loader := L.RawGetInt(loaders, i) 561 if loader == LNil { 562 L.RaiseError("module %s not found:\n\t%s, ", name, strings.Join(messages, "\n\t")) 563 } 564 L.Push(loader) 565 L.Push(LString(name)) 566 L.Call(1, 1) 567 ret := L.reg.Pop() 568 switch retv := ret.(type) { 569 case *LFunction: 570 modasfunc = retv 571 goto loopbreak 572 case LString: 573 messages = append(messages, string(retv)) 574 } 575 } 576 loopbreak: 577 L.SetField(loaded, name, loopdetection) 578 L.Push(modasfunc) 579 L.Push(LString(name)) 580 L.Call(1, 1) 581 ret := L.reg.Pop() 582 modv := L.GetField(loaded, name) 583 if ret != LNil && modv == loopdetection { 584 L.SetField(loaded, name, ret) 585 L.Push(ret) 586 } else if modv == loopdetection { 587 L.SetField(loaded, name, LTrue) 588 L.Push(LTrue) 589 } else { 590 L.Push(modv) 591 } 592 return 1 593 } 594 595 /* }}} */ 596 597 /* hidden features {{{ */ 598 599 func baseNewProxy(L *LState) int { 600 ud := L.NewUserData() 601 L.SetTop(1) 602 if L.Get(1) == LTrue { 603 L.SetMetatable(ud, L.NewTable()) 604 } else if d, ok := L.Get(1).(*LUserData); ok { 605 L.SetMetatable(ud, L.GetMetatable(d)) 606 } 607 L.Push(ud) 608 return 1 609 } 610 611 /* }}} */ 612 613 //