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