1package lua 2 3import ( 4 "bufio" 5 "fmt" 6 "io" 7 "os" 8 "strings" 9) 10 11/* checkType {{{ */ 12 13func (ls *LState) CheckAny(n int) LValue { 14 if n > ls.GetTop() { 15 ls.ArgError(n, "value expected") 16 } 17 return ls.Get(n) 18} 19 20func (ls *LState) CheckInt(n int) int { 21 v := ls.Get(n) 22 if intv, ok := v.(LNumber); ok { 23 return int(intv) 24 } 25 ls.TypeError(n, LTNumber) 26 return 0 27} 28 29func (ls *LState) CheckInt64(n int) int64 { 30 v := ls.Get(n) 31 if intv, ok := v.(LNumber); ok { 32 return int64(intv) 33 } 34 ls.TypeError(n, LTNumber) 35 return 0 36} 37 38func (ls *LState) CheckNumber(n int) LNumber { 39 v := ls.Get(n) 40 if lv, ok := v.(LNumber); ok { 41 return lv 42 } 43 ls.TypeError(n, LTNumber) 44 return 0 45} 46 47func (ls *LState) CheckString(n int) string { 48 v := ls.Get(n) 49 if lv, ok := v.(LString); ok { 50 return string(lv) 51 } else if LVCanConvToString(v) { 52 return ls.ToString(n) 53 } 54 ls.TypeError(n, LTString) 55 return "" 56} 57 58func (ls *LState) CheckBool(n int) bool { 59 v := ls.Get(n) 60 if lv, ok := v.(LBool); ok { 61 return bool(lv) 62 } 63 ls.TypeError(n, LTBool) 64 return false 65} 66 67func (ls *LState) CheckTable(n int) *LTable { 68 v := ls.Get(n) 69 if lv, ok := v.(*LTable); ok { 70 return lv 71 } 72 ls.TypeError(n, LTTable) 73 return nil 74} 75 76func (ls *LState) CheckFunction(n int) *LFunction { 77 v := ls.Get(n) 78 if lv, ok := v.(*LFunction); ok { 79 return lv 80 } 81 ls.TypeError(n, LTFunction) 82 return nil 83} 84 85func (ls *LState) CheckUserData(n int) *LUserData { 86 v := ls.Get(n) 87 if lv, ok := v.(*LUserData); ok { 88 return lv 89 } 90 ls.TypeError(n, LTUserData) 91 return nil 92} 93 94func (ls *LState) CheckThread(n int) *LState { 95 v := ls.Get(n) 96 if lv, ok := v.(*LState); ok { 97 return lv 98 } 99 ls.TypeError(n, LTThread) 100 return nil 101} 102 103func (ls *LState) CheckType(n int, typ LValueType) { 104 v := ls.Get(n) 105 if v.Type() != typ { 106 ls.TypeError(n, typ) 107 } 108} 109 110func (ls *LState) CheckTypes(n int, typs ...LValueType) { 111 vt := ls.Get(n).Type() 112 for _, typ := range typs { 113 if vt == typ { 114 return 115 } 116 } 117 buf := []string{} 118 for _, typ := range typs { 119 buf = append(buf, typ.String()) 120 } 121 ls.ArgError(n, strings.Join(buf, " or ")+" expected, got "+ls.Get(n).Type().String()) 122} 123 124func (ls *LState) CheckOption(n int, options []string) int { 125 str := ls.CheckString(n) 126 for i, v := range options { 127 if v == str { 128 return i 129 } 130 } 131 ls.ArgError(n, fmt.Sprintf("invalid option: %s (must be one of %s)", str, strings.Join(options, ","))) 132 return 0 133} 134 135/* }}} */ 136 137/* optType {{{ */ 138 139func (ls *LState) OptInt(n int, d int) int { 140 v := ls.Get(n) 141 if v == LNil { 142 return d 143 } 144 if intv, ok := v.(LNumber); ok { 145 return int(intv) 146 } 147 ls.TypeError(n, LTNumber) 148 return 0 149} 150 151func (ls *LState) OptInt64(n int, d int64) int64 { 152 v := ls.Get(n) 153 if v == LNil { 154 return d 155 } 156 if intv, ok := v.(LNumber); ok { 157 return int64(intv) 158 } 159 ls.TypeError(n, LTNumber) 160 return 0 161} 162 163func (ls *LState) OptNumber(n int, d LNumber) LNumber { 164 v := ls.Get(n) 165 if v == LNil { 166 return d 167 } 168 if lv, ok := v.(LNumber); ok { 169 return lv 170 } 171 ls.TypeError(n, LTNumber) 172 return 0 173} 174 175func (ls *LState) OptString(n int, d string) string { 176 v := ls.Get(n) 177 if v == LNil { 178 return d 179 } 180 if lv, ok := v.(LString); ok { 181 return string(lv) 182 } 183 ls.TypeError(n, LTString) 184 return "" 185} 186 187func (ls *LState) OptBool(n int, d bool) bool { 188 v := ls.Get(n) 189 if v == LNil { 190 return d 191 } 192 if lv, ok := v.(LBool); ok { 193 return bool(lv) 194 } 195 ls.TypeError(n, LTBool) 196 return false 197} 198 199func (ls *LState) OptTable(n int, d *LTable) *LTable { 200 v := ls.Get(n) 201 if v == LNil { 202 return d 203 } 204 if lv, ok := v.(*LTable); ok { 205 return lv 206 } 207 ls.TypeError(n, LTTable) 208 return nil 209} 210 211func (ls *LState) OptFunction(n int, d *LFunction) *LFunction { 212 v := ls.Get(n) 213 if v == LNil { 214 return d 215 } 216 if lv, ok := v.(*LFunction); ok { 217 return lv 218 } 219 ls.TypeError(n, LTFunction) 220 return nil 221} 222 223func (ls *LState) OptUserData(n int, d *LUserData) *LUserData { 224 v := ls.Get(n) 225 if v == LNil { 226 return d 227 } 228 if lv, ok := v.(*LUserData); ok { 229 return lv 230 } 231 ls.TypeError(n, LTUserData) 232 return nil 233} 234 235/* }}} */ 236 237/* error operations {{{ */ 238 239func (ls *LState) ArgError(n int, message string) { 240 ls.RaiseError("bad argument #%v to %v (%v)", n, ls.rawFrameFuncName(ls.currentFrame), message) 241} 242 243func (ls *LState) TypeError(n int, typ LValueType) { 244 ls.RaiseError("bad argument #%v to %v (%v expected, got %v)", n, ls.rawFrameFuncName(ls.currentFrame), typ.String(), ls.Get(n).Type().String()) 245} 246 247/* }}} */ 248 249/* debug operations {{{ */ 250 251func (ls *LState) Where(level int) string { 252 return ls.where(level, false) 253} 254 255/* }}} */ 256 257/* table operations {{{ */ 258 259func (ls *LState) FindTable(obj *LTable, n string, size int) LValue { 260 names := strings.Split(n, ".") 261 curobj := obj 262 for _, name := range names { 263 if curobj.Type() != LTTable { 264 return LNil 265 } 266 nextobj := ls.RawGet(curobj, LString(name)) 267 if nextobj == LNil { 268 tb := ls.CreateTable(0, size) 269 ls.RawSet(curobj, LString(name), tb) 270 curobj = tb 271 } else if nextobj.Type() != LTTable { 272 return LNil 273 } else { 274 curobj = nextobj.(*LTable) 275 } 276 } 277 return curobj 278} 279 280/* }}} */ 281 282/* register operations {{{ */ 283 284func (ls *LState) RegisterModule(name string, funcs map[string]LGFunction) LValue { 285 tb := ls.FindTable(ls.Get(RegistryIndex).(*LTable), "_LOADED", 1) 286 mod := ls.GetField(tb, name) 287 if mod.Type() != LTTable { 288 newmod := ls.FindTable(ls.Get(GlobalsIndex).(*LTable), name, len(funcs)) 289 if newmodtb, ok := newmod.(*LTable); !ok { 290 ls.RaiseError("name conflict for module(%v)", name) 291 } else { 292 for fname, fn := range funcs { 293 newmodtb.RawSetString(fname, ls.NewFunction(fn)) 294 } 295 ls.SetField(tb, name, newmodtb) 296 return newmodtb 297 } 298 } 299 return mod 300} 301 302func (ls *LState) SetFuncs(tb *LTable, funcs map[string]LGFunction, upvalues ...LValue) *LTable { 303 for fname, fn := range funcs { 304 tb.RawSetString(fname, ls.NewClosure(fn, upvalues...)) 305 } 306 return tb 307} 308 309/* }}} */ 310 311/* metatable operations {{{ */ 312 313func (ls *LState) NewTypeMetatable(typ string) *LTable { 314 regtable := ls.Get(RegistryIndex) 315 mt := ls.GetField(regtable, typ) 316 if tb, ok := mt.(*LTable); ok { 317 return tb 318 } 319 mtnew := ls.NewTable() 320 ls.SetField(regtable, typ, mtnew) 321 return mtnew 322} 323 324func (ls *LState) GetMetaField(obj LValue, event string) LValue { 325 return ls.metaOp1(obj, event) 326} 327 328func (ls *LState) GetTypeMetatable(typ string) LValue { 329 return ls.GetField(ls.Get(RegistryIndex), typ) 330} 331 332func (ls *LState) CallMeta(obj LValue, event string) LValue { 333 op := ls.metaOp1(obj, event) 334 if op.Type() == LTFunction { 335 ls.reg.Push(op) 336 ls.reg.Push(obj) 337 ls.Call(1, 1) 338 return ls.reg.Pop() 339 } 340 return LNil 341} 342 343/* }}} */ 344 345/* load and function call operations {{{ */ 346 347func (ls *LState) LoadFile(path string) (*LFunction, error) { 348 var file *os.File 349 var err error 350 if len(path) == 0 { 351 file = os.Stdin 352 } else { 353 file, err = os.Open(path) 354 defer file.Close() 355 if err != nil { 356 return nil, newApiErrorE(ApiErrorFile, err) 357 } 358 } 359 360 reader := bufio.NewReader(file) 361 // get the first character. 362 c, err := reader.ReadByte() 363 if err != nil && err != io.EOF { 364 return nil, newApiErrorE(ApiErrorFile, err) 365 } 366 if c == byte('#') { 367 // Unix exec. file? 368 // skip first line 369 _, err, _ = readBufioLine(reader) 370 if err != nil { 371 return nil, newApiErrorE(ApiErrorFile, err) 372 } 373 } 374 375 if err != io.EOF { 376 // if the file is not empty, 377 // unread the first character of the file or newline character(readBufioLine's last byte). 378 err = reader.UnreadByte() 379 if err != nil { 380 return nil, newApiErrorE(ApiErrorFile, err) 381 } 382 } 383 384 return ls.Load(reader, path) 385} 386 387func (ls *LState) LoadString(source string) (*LFunction, error) { 388 return ls.Load(strings.NewReader(source), "<string>") 389} 390 391func (ls *LState) DoFile(path string) error { 392 if fn, err := ls.LoadFile(path); err != nil { 393 return err 394 } else { 395 ls.Push(fn) 396 return ls.PCall(0, MultRet, nil) 397 } 398} 399 400func (ls *LState) DoString(source string) error { 401 if fn, err := ls.LoadString(source); err != nil { 402 return err 403 } else { 404 ls.Push(fn) 405 return ls.PCall(0, MultRet, nil) 406 } 407} 408 409/* }}} */ 410 411/* GopherLua original APIs {{{ */ 412 413// ToStringMeta returns string representation of given LValue. 414// This method calls the `__tostring` meta method if defined. 415func (ls *LState) ToStringMeta(lv LValue) LValue { 416 if fn, ok := ls.metaOp1(lv, "__tostring").assertFunction(); ok { 417 ls.Push(fn) 418 ls.Push(lv) 419 ls.Call(1, 1) 420 return ls.reg.Pop() 421 } else { 422 return LString(lv.String()) 423 } 424} 425 426// Set a module loader to the package.preload table. 427func (ls *LState) PreloadModule(name string, loader LGFunction) { 428 preload := ls.GetField(ls.GetField(ls.Get(EnvironIndex), "package"), "preload") 429 if _, ok := preload.(*LTable); !ok { 430 ls.RaiseError("package.preload must be a table") 431 } 432 ls.SetField(preload, name, ls.NewFunction(loader)) 433} 434 435// Checks whether the given index is an LChannel and returns this channel. 436func (ls *LState) CheckChannel(n int) chan LValue { 437 v := ls.Get(n) 438 if ch, ok := v.(LChannel); ok { 439 return (chan LValue)(ch) 440 } 441 ls.TypeError(n, LTChannel) 442 return nil 443} 444 445// If the given index is a LChannel, returns this channel. If this argument is absent or is nil, returns ch. Otherwise, raises an error. 446func (ls *LState) OptChannel(n int, ch chan LValue) chan LValue { 447 v := ls.Get(n) 448 if v == LNil { 449 return ch 450 } 451 if ch, ok := v.(LChannel); ok { 452 return (chan LValue)(ch) 453 } 454 ls.TypeError(n, LTChannel) 455 return nil 456} 457 458/* }}} */ 459 460// 461