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