go.ketch.com/lib/goja@v0.0.1/string_ascii.go (about)

     1  package goja
     2  
     3  import (
     4  	"hash/maphash"
     5  	"io"
     6  	"math"
     7  	"reflect"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"go.ketch.com/lib/goja/unistring"
    12  )
    13  
    14  type asciiString string
    15  
    16  type asciiRuneReader struct {
    17  	s   asciiString
    18  	pos int
    19  }
    20  
    21  func (rr *asciiRuneReader) ReadRune() (r rune, size int, err error) {
    22  	if rr.pos < len(rr.s) {
    23  		r = rune(rr.s[rr.pos])
    24  		size = 1
    25  		rr.pos++
    26  	} else {
    27  		err = io.EOF
    28  	}
    29  	return
    30  }
    31  
    32  func (s asciiString) reader() io.RuneReader {
    33  	return &asciiRuneReader{
    34  		s: s,
    35  	}
    36  }
    37  
    38  func (s asciiString) utf16Reader() io.RuneReader {
    39  	return s.reader()
    40  }
    41  
    42  func (s asciiString) utf16Runes() []rune {
    43  	runes := make([]rune, len(s))
    44  	for i := 0; i < len(s); i++ {
    45  		runes[i] = rune(s[i])
    46  	}
    47  	return runes
    48  }
    49  
    50  // ss must be trimmed
    51  func stringToInt(ss string) (int64, error) {
    52  	if ss == "" {
    53  		return 0, nil
    54  	}
    55  	if ss == "-0" {
    56  		return 0, strconv.ErrSyntax
    57  	}
    58  	if len(ss) > 2 {
    59  		switch ss[:2] {
    60  		case "0x", "0X":
    61  			return strconv.ParseInt(ss[2:], 16, 64)
    62  		case "0b", "0B":
    63  			return strconv.ParseInt(ss[2:], 2, 64)
    64  		case "0o", "0O":
    65  			return strconv.ParseInt(ss[2:], 8, 64)
    66  		}
    67  	}
    68  	return strconv.ParseInt(ss, 10, 64)
    69  }
    70  
    71  func (s asciiString) _toInt() (int64, error) {
    72  	return stringToInt(strings.TrimSpace(string(s)))
    73  }
    74  
    75  func isRangeErr(err error) bool {
    76  	if err, ok := err.(*strconv.NumError); ok {
    77  		return err.Err == strconv.ErrRange
    78  	}
    79  	return false
    80  }
    81  
    82  func (s asciiString) _toFloat() (float64, error) {
    83  	ss := strings.TrimSpace(string(s))
    84  	if ss == "" {
    85  		return 0, nil
    86  	}
    87  	if ss == "-0" {
    88  		var f float64
    89  		return -f, nil
    90  	}
    91  	f, err := strconv.ParseFloat(ss, 64)
    92  	if isRangeErr(err) {
    93  		err = nil
    94  	}
    95  	return f, err
    96  }
    97  
    98  func (s asciiString) ToInteger() int64 {
    99  	if s == "" {
   100  		return 0
   101  	}
   102  	if s == "Infinity" || s == "+Infinity" {
   103  		return math.MaxInt64
   104  	}
   105  	if s == "-Infinity" {
   106  		return math.MinInt64
   107  	}
   108  	i, err := s._toInt()
   109  	if err != nil {
   110  		f, err := s._toFloat()
   111  		if err == nil {
   112  			return int64(f)
   113  		}
   114  	}
   115  	return i
   116  }
   117  
   118  func (s asciiString) toString() valueString {
   119  	return s
   120  }
   121  
   122  func (s asciiString) ToString() Value {
   123  	return s
   124  }
   125  
   126  func (s asciiString) String() string {
   127  	return string(s)
   128  }
   129  
   130  func (s asciiString) ToFloat() float64 {
   131  	if s == "" {
   132  		return 0
   133  	}
   134  	if s == "Infinity" || s == "+Infinity" {
   135  		return math.Inf(1)
   136  	}
   137  	if s == "-Infinity" {
   138  		return math.Inf(-1)
   139  	}
   140  	f, err := s._toFloat()
   141  	if err != nil {
   142  		i, err := s._toInt()
   143  		if err == nil {
   144  			return float64(i)
   145  		}
   146  		f = math.NaN()
   147  	}
   148  	return f
   149  }
   150  
   151  func (s asciiString) ToBoolean() bool {
   152  	return s != ""
   153  }
   154  
   155  func (s asciiString) ToNumber() Value {
   156  	if s == "" {
   157  		return intToValue(0)
   158  	}
   159  	if s == "Infinity" || s == "+Infinity" {
   160  		return _positiveInf
   161  	}
   162  	if s == "-Infinity" {
   163  		return _negativeInf
   164  	}
   165  
   166  	if i, err := s._toInt(); err == nil {
   167  		return intToValue(i)
   168  	}
   169  
   170  	if f, err := s._toFloat(); err == nil {
   171  		return floatToValue(f)
   172  	}
   173  
   174  	return _NaN
   175  }
   176  
   177  func (s asciiString) ToObject(r *Runtime) *Object {
   178  	return r._newString(s, r.global.StringPrototype)
   179  }
   180  
   181  func (s asciiString) SameAs(other Value) bool {
   182  	return s.StrictEquals(other)
   183  }
   184  
   185  func (s asciiString) Equals(other Value) bool {
   186  	if s.StrictEquals(other) {
   187  		return true
   188  	}
   189  
   190  	if o, ok := other.(valueInt); ok {
   191  		if o1, e := s._toInt(); e == nil {
   192  			return o1 == int64(o)
   193  		}
   194  		return false
   195  	}
   196  
   197  	if o, ok := other.(valueFloat); ok {
   198  		return s.ToFloat() == float64(o)
   199  	}
   200  
   201  	if o, ok := other.(valueBool); ok {
   202  		if o1, e := s._toFloat(); e == nil {
   203  			return o1 == o.ToFloat()
   204  		}
   205  		return false
   206  	}
   207  
   208  	if o, ok := other.(*Object); ok {
   209  		return s.Equals(o.toPrimitive())
   210  	}
   211  	return false
   212  }
   213  
   214  func (s asciiString) StrictEquals(other Value) bool {
   215  	if otherStr, ok := other.(asciiString); ok {
   216  		return s == otherStr
   217  	}
   218  	if otherStr, ok := other.(*importedString); ok {
   219  		if otherStr.u == nil {
   220  			return string(s) == otherStr.s
   221  		}
   222  	}
   223  	return false
   224  }
   225  
   226  func (s asciiString) baseObject(r *Runtime) *Object {
   227  	ss := r.stringSingleton
   228  	ss.value = s
   229  	ss.setLength()
   230  	return ss.val
   231  }
   232  
   233  func (s asciiString) hash(hash *maphash.Hash) uint64 {
   234  	_, _ = hash.WriteString(string(s))
   235  	h := hash.Sum64()
   236  	hash.Reset()
   237  	return h
   238  }
   239  
   240  func (s asciiString) charAt(idx int) rune {
   241  	return rune(s[idx])
   242  }
   243  
   244  func (s asciiString) length() int {
   245  	return len(s)
   246  }
   247  
   248  func (s asciiString) concat(other valueString) valueString {
   249  	a, u := devirtualizeString(other)
   250  	if u != nil {
   251  		b := make([]uint16, len(s)+len(u))
   252  		b[0] = unistring.BOM
   253  		for i := 0; i < len(s); i++ {
   254  			b[i+1] = uint16(s[i])
   255  		}
   256  		copy(b[len(s)+1:], u[1:])
   257  		return unicodeString(b)
   258  	}
   259  	return s + a
   260  }
   261  
   262  func (s asciiString) substring(start, end int) valueString {
   263  	return s[start:end]
   264  }
   265  
   266  func (s asciiString) compareTo(other valueString) int {
   267  	switch other := other.(type) {
   268  	case asciiString:
   269  		return strings.Compare(string(s), string(other))
   270  	case unicodeString:
   271  		return strings.Compare(string(s), other.String())
   272  	case *importedString:
   273  		return strings.Compare(string(s), other.s)
   274  	default:
   275  		panic(newTypeError("Internal bug: unknown string type: %T", other))
   276  	}
   277  }
   278  
   279  func (s asciiString) index(substr valueString, start int) int {
   280  	a, u := devirtualizeString(substr)
   281  	if u == nil {
   282  		p := strings.Index(string(s[start:]), string(a))
   283  		if p >= 0 {
   284  			return p + start
   285  		}
   286  	}
   287  	return -1
   288  }
   289  
   290  func (s asciiString) lastIndex(substr valueString, pos int) int {
   291  	a, u := devirtualizeString(substr)
   292  	if u == nil {
   293  		end := pos + len(a)
   294  		var ss string
   295  		if end > len(s) {
   296  			ss = string(s)
   297  		} else {
   298  			ss = string(s[:end])
   299  		}
   300  		return strings.LastIndex(ss, string(a))
   301  	}
   302  	return -1
   303  }
   304  
   305  func (s asciiString) toLower() valueString {
   306  	return asciiString(strings.ToLower(string(s)))
   307  }
   308  
   309  func (s asciiString) toUpper() valueString {
   310  	return asciiString(strings.ToUpper(string(s)))
   311  }
   312  
   313  func (s asciiString) toTrimmedUTF8() string {
   314  	return strings.TrimSpace(string(s))
   315  }
   316  
   317  func (s asciiString) string() unistring.String {
   318  	return unistring.String(s)
   319  }
   320  
   321  func (s asciiString) Export() interface{} {
   322  	return string(s)
   323  }
   324  
   325  func (s asciiString) ExportType() reflect.Type {
   326  	return reflectTypeString
   327  }