github.com/tul/gopher-lua@v0.0.0-20181008131706-f6fcaab0c612/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.CheckFunction(1) 262 nargs := L.GetTop() - 1 263 if err := L.PCall(nargs, MultRet, nil); err != nil { 264 L.Push(LFalse) 265 if aerr, ok := err.(*ApiError); ok { 266 L.Push(aerr.Object) 267 } else { 268 L.Push(LString(err.Error())) 269 } 270 return 2 271 } else { 272 L.Insert(LTrue, 1) 273 return L.GetTop() 274 } 275 } 276 277 func basePrint(L *LState) int { 278 top := L.GetTop() 279 for i := 1; i <= top; i++ { 280 fmt.Print(L.ToStringMeta(L.Get(i)).String()) 281 if i != top { 282 fmt.Print("\t") 283 } 284 } 285 fmt.Println("") 286 return 0 287 } 288 289 func base_PrintRegs(L *LState) int { 290 L.printReg() 291 return 0 292 } 293 294 func baseRawEqual(L *LState) int { 295 if L.CheckAny(1) == L.CheckAny(2) { 296 L.Push(LTrue) 297 } else { 298 L.Push(LFalse) 299 } 300 return 1 301 } 302 303 func baseRawGet(L *LState) int { 304 L.Push(L.RawGet(L.CheckTable(1), L.CheckAny(2))) 305 return 1 306 } 307 308 func baseRawSet(L *LState) int { 309 L.RawSet(L.CheckTable(1), L.CheckAny(2), L.CheckAny(3)) 310 return 0 311 } 312 313 func baseSelect(L *LState) int { 314 L.CheckTypes(1, LTNumber, LTString) 315 switch lv := L.Get(1).(type) { 316 case LNumber: 317 idx := int(lv) 318 num := L.reg.Top() - L.indexToReg(int(lv)) - 1 319 if idx < 0 { 320 num++ 321 } 322 return num 323 case LString: 324 if string(lv) != "#" { 325 L.ArgError(1, "invalid string '"+string(lv)+"'") 326 } 327 L.Push(LNumber(L.GetTop() - 1)) 328 return 1 329 } 330 return 0 331 } 332 333 func baseSetFEnv(L *LState) int { 334 var value LValue 335 if L.GetTop() == 0 { 336 value = LNumber(1) 337 } else { 338 value = L.Get(1) 339 } 340 env := L.CheckTable(2) 341 342 if fn, ok := value.(*LFunction); ok { 343 if fn.IsG { 344 L.RaiseError("cannot change the environment of given object") 345 } else { 346 fn.Env = env 347 L.Push(fn) 348 return 1 349 } 350 } 351 352 if number, ok := value.(LNumber); ok { 353 level := int(float64(number)) 354 if level <= 0 { 355 L.Env = env 356 return 0 357 } 358 359 cf := L.currentFrame 360 for i := 0; i < level && cf != nil; i++ { 361 cf = cf.Parent 362 } 363 if cf == nil || cf.Fn.IsG { 364 L.RaiseError("cannot change the environment of given object") 365 } else { 366 cf.Fn.Env = env 367 L.Push(cf.Fn) 368 return 1 369 } 370 } 371 372 L.RaiseError("cannot change the environment of given object") 373 return 0 374 } 375 376 func baseSetMetatable(L *LState) int { 377 L.CheckTypes(2, LTNil, LTTable) 378 obj := L.Get(1) 379 if obj == LNil { 380 L.RaiseError("cannot set metatable to a nil object.") 381 } 382 mt := L.Get(2) 383 if m := L.metatable(obj, true); m != LNil { 384 if tb, ok := m.(*LTable); ok && tb.RawGetString("__metatable") != LNil { 385 L.RaiseError("cannot change a protected metatable") 386 } 387 } 388 L.SetMetatable(obj, mt) 389 L.SetTop(1) 390 return 1 391 } 392 393 func baseToNumber(L *LState) int { 394 base := L.OptInt(2, 10) 395 noBase := L.Get(2) == LNil 396 397 switch lv := L.CheckAny(1).(type) { 398 case LNumber: 399 L.Push(lv) 400 case LString: 401 str := strings.Trim(string(lv), " \n\t") 402 if strings.Index(str, ".") > -1 { 403 if v, err := strconv.ParseFloat(str, LNumberBit); err != nil { 404 L.Push(LNil) 405 } else { 406 L.Push(LNumber(v)) 407 } 408 } else { 409 if noBase && strings.HasPrefix(strings.ToLower(str), "0x") { 410 base, str = 16, str[2:] // Hex number 411 } 412 if v, err := strconv.ParseInt(str, base, LNumberBit); err != nil { 413 L.Push(LNil) 414 } else { 415 L.Push(LNumber(v)) 416 } 417 } 418 default: 419 L.Push(LNil) 420 } 421 return 1 422 } 423 424 func baseToString(L *LState) int { 425 v1 := L.CheckAny(1) 426 L.Push(L.ToStringMeta(v1)) 427 return 1 428 } 429 430 func baseType(L *LState) int { 431 L.Push(LString(L.CheckAny(1).Type().String())) 432 return 1 433 } 434 435 func baseUnpack(L *LState) int { 436 tb := L.CheckTable(1) 437 start := L.OptInt(2, 1) 438 end := L.OptInt(3, tb.Len()) 439 for i := start; i <= end; i++ { 440 L.Push(tb.RawGetInt(i)) 441 } 442 ret := end - start + 1 443 if ret < 0 { 444 return 0 445 } 446 return ret 447 } 448 449 func baseXPCall(L *LState) int { 450 fn := L.CheckFunction(1) 451 errfunc := L.CheckFunction(2) 452 453 top := L.GetTop() 454 L.Push(fn) 455 if err := L.PCall(0, MultRet, errfunc); err != nil { 456 L.Push(LFalse) 457 if aerr, ok := err.(*ApiError); ok { 458 L.Push(aerr.Object) 459 } else { 460 L.Push(LString(err.Error())) 461 } 462 return 2 463 } else { 464 L.Insert(LTrue, top+1) 465 return L.GetTop() - top 466 } 467 } 468 469 /* }}} */ 470 471 /* load lib {{{ */ 472 473 func loModule(L *LState) int { 474 name := L.CheckString(1) 475 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 476 tb := L.GetField(loaded, name) 477 if _, ok := tb.(*LTable); !ok { 478 tb = L.FindTable(L.Get(GlobalsIndex).(*LTable), name, 1) 479 if tb == LNil { 480 L.RaiseError("name conflict for module: %v", name) 481 } 482 L.SetField(loaded, name, tb) 483 } 484 if L.GetField(tb, "_NAME") == LNil { 485 L.SetField(tb, "_M", tb) 486 L.SetField(tb, "_NAME", LString(name)) 487 names := strings.Split(name, ".") 488 pname := "" 489 if len(names) > 1 { 490 pname = strings.Join(names[:len(names)-1], ".") + "." 491 } 492 L.SetField(tb, "_PACKAGE", LString(pname)) 493 } 494 495 caller := L.currentFrame.Parent 496 if caller == nil { 497 L.RaiseError("no calling stack.") 498 } else if caller.Fn.IsG { 499 L.RaiseError("module() can not be called from GFunctions.") 500 } 501 L.SetFEnv(caller.Fn, tb) 502 503 top := L.GetTop() 504 for i := 2; i <= top; i++ { 505 L.Push(L.Get(i)) 506 L.Push(tb) 507 L.Call(1, 0) 508 } 509 L.Push(tb) 510 return 1 511 } 512 513 var loopdetection = &LUserData{} 514 515 func loRequire(L *LState) int { 516 name := L.CheckString(1) 517 loaded := L.GetField(L.Get(RegistryIndex), "_LOADED") 518 lv := L.GetField(loaded, name) 519 if LVAsBool(lv) { 520 if lv == loopdetection { 521 L.RaiseError("loop or previous error loading module: %s", name) 522 } 523 L.Push(lv) 524 return 1 525 } 526 loaders, ok := L.GetField(L.Get(RegistryIndex), "_LOADERS").(*LTable) 527 if !ok { 528 L.RaiseError("package.loaders must be a table") 529 } 530 messages := []string{} 531 var modasfunc LValue 532 for i := 1; ; i++ { 533 loader := L.RawGetInt(loaders, i) 534 if loader == LNil { 535 L.RaiseError("module %s not found:\n\t%s, ", name, strings.Join(messages, "\n\t")) 536 } 537 L.Push(loader) 538 L.Push(LString(name)) 539 L.Call(1, 1) 540 ret := L.reg.Pop() 541 switch retv := ret.(type) { 542 case *LFunction: 543 modasfunc = retv 544 goto loopbreak 545 case LString: 546 messages = append(messages, string(retv)) 547 } 548 } 549 loopbreak: 550 L.SetField(loaded, name, loopdetection) 551 L.Push(modasfunc) 552 L.Push(LString(name)) 553 L.Call(1, 1) 554 ret := L.reg.Pop() 555 modv := L.GetField(loaded, name) 556 if ret != LNil && modv == loopdetection { 557 L.SetField(loaded, name, ret) 558 L.Push(ret) 559 } else if modv == loopdetection { 560 L.SetField(loaded, name, LTrue) 561 L.Push(LTrue) 562 } else { 563 L.Push(modv) 564 } 565 return 1 566 } 567 568 /* }}} */ 569 570 /* hidden features {{{ */ 571 572 func baseNewProxy(L *LState) int { 573 ud := L.NewUserData() 574 L.SetTop(1) 575 if L.Get(1) == LTrue { 576 L.SetMetatable(ud, L.NewTable()) 577 } else if d, ok := L.Get(1).(*LUserData); ok { 578 L.SetMetatable(ud, L.GetMetatable(d)) 579 } 580 L.Push(ud) 581 return 1 582 } 583 584 /* }}} */ 585 586 //