github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/io/scan.go (about) 1 package io 2 3 import ( 4 "io" 5 "strings" 6 7 "github.com/hirochachacha/plua/internal/strconv" 8 "github.com/hirochachacha/plua/object" 9 ) 10 11 type scanner struct { 12 sc io.ByteScanner 13 c byte 14 err error 15 buf []byte 16 } 17 18 func newScanner(sc io.ByteScanner) *scanner { 19 s := &scanner{ 20 sc: sc, 21 } 22 23 s.next() 24 25 return s 26 } 27 28 func (s *scanner) next() { 29 if s.err == nil { 30 s.c, s.err = s.sc.ReadByte() 31 } 32 } 33 34 func (s *scanner) accept() { 35 s.buf = append(s.buf, s.c) 36 s.next() 37 } 38 39 func (s *scanner) skip() { 40 s.next() 41 } 42 43 func (s *scanner) acceptByte(c byte) bool { 44 if s.c == c { 45 s.accept() 46 return true 47 } 48 return false 49 } 50 51 func (s *scanner) skipByte(c byte) bool { 52 if s.c == c { 53 s.skip() 54 return true 55 } 56 return false 57 } 58 59 func (s *scanner) accepts(str string) bool { 60 if strings.IndexByte(str, s.c) != -1 { 61 s.accept() 62 return true 63 } 64 return false 65 } 66 67 func (s *scanner) acceptUntil(pred func(c byte) bool) { 68 for pred(s.c) { 69 s.accept() 70 } 71 } 72 73 func (s *scanner) skipUntil(pred func(c byte) bool) { 74 for pred(s.c) { 75 s.skip() 76 } 77 } 78 79 func (s *scanner) skipSpace() { 80 s.skipUntil(isSpace) 81 } 82 83 func (s *scanner) acceptSign() (neg bool, ok bool) { 84 if s.acceptByte('+') { 85 return false, true 86 } 87 if s.acceptByte('-') { 88 return true, true 89 } 90 return false, false 91 } 92 93 func (s *scanner) acceptBase() (base int, zero bool, ok bool) { 94 base = 10 95 if s.acceptByte('0') { 96 if s.accepts("xX") { 97 base = 16 98 } else { 99 for s.c == '0' { 100 s.accept() 101 } 102 if s.err == io.EOF { 103 return 10, true, true 104 } 105 } 106 } 107 108 return base, false, true 109 } 110 111 func (s *scanner) acceptDigits() { 112 s.acceptUntil(isDigit) 113 } 114 115 func (s *scanner) acceptHexDigits() { 116 s.acceptUntil(isXdigit) 117 } 118 119 func (s *scanner) scanNumber() (object.Value, error) { 120 s.skipSpace() 121 122 s.acceptSign() 123 124 base, zero, _ := s.acceptBase() 125 if zero { 126 return object.Integer(0), nil 127 } 128 129 if base == 16 { 130 s.acceptHexDigits() 131 if s.acceptByte('.') { 132 s.acceptHexDigits() 133 } 134 if s.accepts("pP") { 135 s.acceptSign() 136 s.acceptDigits() 137 } 138 } else { 139 s.acceptDigits() 140 if s.acceptByte('.') { 141 s.acceptDigits() 142 } 143 if s.accepts("eE") { 144 s.acceptSign() 145 s.acceptDigits() 146 } 147 } 148 149 if s.err != nil { 150 return nil, s.err 151 } 152 153 if err := s.sc.UnreadByte(); err != nil { 154 return nil, err 155 } 156 157 str := string(s.buf) 158 159 if i, err := strconv.ParseInt(str); err == nil { 160 return object.Integer(i), err 161 } 162 163 f, err := strconv.ParseFloat(str) 164 if err != nil { 165 return nil, err 166 } 167 168 return object.Number(f), nil 169 } 170 171 func isXdigit(c byte) bool { 172 return uint(c)-'0' < 10 || (uint(c)|32)-'a' < 6 173 } 174 175 func isSpace(c byte) bool { 176 return c == ' ' || uint(c)-'\t' < 5 177 } 178 179 func isDigit(c byte) bool { 180 return uint(c)-'0' < 10 181 }