github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/lib/base/tonumber.go (about) 1 package base 2 3 import ( 4 "bytes" 5 "errors" 6 7 rt "github.com/arnodel/golua/runtime" 8 ) 9 10 func tonumber(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 11 if err := c.Check1Arg(); err != nil { 12 return nil, err 13 } 14 nargs := c.NArgs() 15 next := c.Next() 16 n := c.Arg(0) 17 if nargs == 1 { 18 n, tp := rt.ToNumberValue(n) 19 if tp != rt.NaN { 20 t.Push1(next, n) 21 } else { 22 t.Push1(next, rt.NilValue) 23 } 24 return next, nil 25 } 26 base, err := c.IntArg(1) 27 if err != nil { 28 return nil, err 29 } 30 if base < 2 || base > 36 { 31 return nil, errors.New("#2 out of range") 32 } 33 s, ok := n.TryString() 34 if !ok { 35 return nil, errors.New("#1 must be a string") 36 } 37 digits := bytes.TrimSpace([]byte(s)) 38 if len(digits) == 0 { 39 t.Push1(next, rt.NilValue) 40 return next, nil 41 } 42 var number int64 43 var sign int64 = 1 44 if digits[0] == '-' || digits[0] == '+' { 45 if digits[0] == '-' { 46 sign = -1 47 } 48 digits = digits[1:] 49 if len(digits) == 0 { 50 t.Push1(next, rt.NilValue) 51 return next, nil 52 } 53 } 54 for _, digit := range digits { 55 var d int64 56 switch { 57 case '0' <= digit && digit <= '9': 58 d = int64(digit - '0') 59 case 'a' <= digit && digit <= 'z': 60 d = int64(digit - 'a' + 10) 61 case 'A' <= digit && digit <= 'Z': 62 d = int64(digit - 'A' + 10) 63 default: 64 t.Push1(next, rt.NilValue) 65 return next, nil 66 } 67 if d >= base { 68 t.Push1(next, rt.NilValue) 69 return next, nil 70 } 71 number = number*base + d 72 } 73 t.Push1(next, rt.IntValue(sign*number)) 74 return next, nil 75 }