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