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  }