package goja
import (
"hash/maphash"
"io"
"math"
"math/big"
"reflect"
"strconv"
"strings"
"github.com/dop251/goja/unistring"
)
type asciiString string
type asciiRuneReader struct {
s asciiString
pos int
}
func (rr *asciiRuneReader ) ReadRune () (r rune , size int , err error ) {
if rr .pos < len (rr .s ) {
r = rune (rr .s [rr .pos ])
size = 1
rr .pos ++
} else {
err = io .EOF
}
return
}
type asciiUtf16Reader struct {
s asciiString
pos int
}
func (rr *asciiUtf16Reader ) readChar () (c uint16 , err error ) {
if rr .pos < len (rr .s ) {
c = uint16 (rr .s [rr .pos ])
rr .pos ++
} else {
err = io .EOF
}
return
}
func (rr *asciiUtf16Reader ) ReadRune () (r rune , size int , err error ) {
if rr .pos < len (rr .s ) {
r = rune (rr .s [rr .pos ])
rr .pos ++
size = 1
} else {
err = io .EOF
}
return
}
func (s asciiString ) Reader () io .RuneReader {
return &asciiRuneReader {
s : s ,
}
}
func (s asciiString ) utf16Reader () utf16Reader {
return &asciiUtf16Reader {
s : s ,
}
}
func (s asciiString ) utf16RuneReader () io .RuneReader {
return &asciiUtf16Reader {
s : s ,
}
}
func (s asciiString ) utf16Runes () []rune {
runes := make ([]rune , len (s ))
for i := 0 ; i < len (s ); i ++ {
runes [i ] = rune (s [i ])
}
return runes
}
func stringToInt(ss string ) (int64 , error ) {
if ss == "" {
return 0 , nil
}
if ss == "-0" {
return 0 , strconv .ErrSyntax
}
if len (ss ) > 2 {
switch ss [:2 ] {
case "0x" , "0X" :
return strconv .ParseInt (ss [2 :], 16 , 64 )
case "0b" , "0B" :
return strconv .ParseInt (ss [2 :], 2 , 64 )
case "0o" , "0O" :
return strconv .ParseInt (ss [2 :], 8 , 64 )
}
}
return strconv .ParseInt (ss , 10 , 64 )
}
func (s asciiString ) _toInt (trimmed string ) (int64 , error ) {
return stringToInt (trimmed )
}
func isRangeErr(err error ) bool {
if err , ok := err .(*strconv .NumError ); ok {
return err .Err == strconv .ErrRange
}
return false
}
func (s asciiString ) _toFloat (trimmed string ) (float64 , error ) {
if trimmed == "" {
return 0 , nil
}
if trimmed == "-0" {
var f float64
return -f , nil
}
if strings .ContainsRune (trimmed , '_' ) {
return 0 , strconv .ErrSyntax
}
if len (trimmed ) >= 2 {
var prefix string
if trimmed [0 ] == '-' || trimmed [0 ] == '+' {
prefix = trimmed [1 :]
} else {
prefix = trimmed
}
if len (prefix ) >= 2 && prefix [0 ] == '0' && (prefix [1 ] == 'x' || prefix [1 ] == 'X' ) {
return 0 , strconv .ErrSyntax
}
}
f , err := strconv .ParseFloat (trimmed , 64 )
if err == nil && math .IsInf (f , 0 ) {
ss := strings .ToLower (trimmed )
if strings .HasPrefix (ss , "inf" ) || strings .HasPrefix (ss , "-inf" ) || strings .HasPrefix (ss , "+inf" ) {
return 0 , strconv .ErrSyntax
}
}
if isRangeErr (err ) {
err = nil
}
return f , err
}
func (s asciiString ) ToInteger () int64 {
ss := strings .TrimSpace (string (s ))
if ss == "" {
return 0
}
if ss == "Infinity" || ss == "+Infinity" {
return math .MaxInt64
}
if ss == "-Infinity" {
return math .MinInt64
}
i , err := s ._toInt (ss )
if err != nil {
f , err := s ._toFloat (ss )
if err == nil {
return int64 (f )
}
}
return i
}
func (s asciiString ) toString () String {
return s
}
func (s asciiString ) ToString () Value {
return s
}
func (s asciiString ) String () string {
return string (s )
}
func (s asciiString ) ToFloat () float64 {
ss := strings .TrimSpace (string (s ))
if ss == "" {
return 0
}
if ss == "Infinity" || ss == "+Infinity" {
return math .Inf (1 )
}
if ss == "-Infinity" {
return math .Inf (-1 )
}
f , err := s ._toFloat (ss )
if err != nil {
i , err := s ._toInt (ss )
if err == nil {
return float64 (i )
}
f = math .NaN ()
}
return f
}
func (s asciiString ) ToBoolean () bool {
return s != ""
}
func (s asciiString ) ToNumber () Value {
ss := strings .TrimSpace (string (s ))
if ss == "" {
return intToValue (0 )
}
if ss == "Infinity" || ss == "+Infinity" {
return _positiveInf
}
if ss == "-Infinity" {
return _negativeInf
}
if i , err := s ._toInt (ss ); err == nil {
return intToValue (i )
}
if f , err := s ._toFloat (ss ); err == nil {
return floatToValue (f )
}
return _NaN
}
func (s asciiString ) ToObject (r *Runtime ) *Object {
return r ._newString (s , r .getStringPrototype ())
}
func (s asciiString ) SameAs (other Value ) bool {
return s .StrictEquals (other )
}
func (s asciiString ) Equals (other Value ) bool {
if s .StrictEquals (other ) {
return true
}
if o , ok := other .(valueInt ); ok {
if o1 , e := s ._toInt (strings .TrimSpace (string (s ))); e == nil {
return o1 == int64 (o )
}
return false
}
if o , ok := other .(valueFloat ); ok {
return s .ToFloat () == float64 (o )
}
if o , ok := other .(valueBool ); ok {
if o1 , e := s ._toFloat (strings .TrimSpace (string (s ))); e == nil {
return o1 == o .ToFloat ()
}
return false
}
if o , ok := other .(*valueBigInt ); ok {
bigInt , err := stringToBigInt (s .toTrimmedUTF8 ())
if err != nil {
return false
}
return bigInt .Cmp ((*big .Int )(o )) == 0
}
if o , ok := other .(*Object ); ok {
return s .Equals (o .toPrimitive ())
}
return false
}
func (s asciiString ) StrictEquals (other Value ) bool {
if otherStr , ok := other .(asciiString ); ok {
return s == otherStr
}
if otherStr , ok := other .(*importedString ); ok {
if otherStr .u == nil {
return string (s ) == otherStr .s
}
}
return false
}
func (s asciiString ) baseObject (r *Runtime ) *Object {
ss := r .getStringSingleton ()
ss .value = s
ss .setLength ()
return ss .val
}
func (s asciiString ) hash (hash *maphash .Hash ) uint64 {
_, _ = hash .WriteString (string (s ))
h := hash .Sum64 ()
hash .Reset ()
return h
}
func (s asciiString ) CharAt (idx int ) uint16 {
return uint16 (s [idx ])
}
func (s asciiString ) Length () int {
return len (s )
}
func (s asciiString ) Concat (other String ) String {
a , u := devirtualizeString (other )
if u != nil {
b := make ([]uint16 , len (s )+len (u ))
b [0 ] = unistring .BOM
for i := 0 ; i < len (s ); i ++ {
b [i +1 ] = uint16 (s [i ])
}
copy (b [len (s )+1 :], u [1 :])
return unicodeString (b )
}
return s + a
}
func (s asciiString ) Substring (start , end int ) String {
return s [start :end ]
}
func (s asciiString ) CompareTo (other String ) int {
switch other := other .(type ) {
case asciiString :
return strings .Compare (string (s ), string (other ))
case unicodeString :
return strings .Compare (string (s ), other .String ())
case *importedString :
return strings .Compare (string (s ), other .s )
default :
panic (newTypeError ("Internal bug: unknown string type: %T" , other ))
}
}
func (s asciiString ) index (substr String , start int ) int {
a , u := devirtualizeString (substr )
if u == nil {
if start > len (s ) {
return -1
}
p := strings .Index (string (s [start :]), string (a ))
if p >= 0 {
return p + start
}
}
return -1
}
func (s asciiString ) lastIndex (substr String , pos int ) int {
a , u := devirtualizeString (substr )
if u == nil {
end := pos + len (a )
var ss string
if end > len (s ) {
ss = string (s )
} else {
ss = string (s [:end ])
}
return strings .LastIndex (ss , string (a ))
}
return -1
}
func (s asciiString ) toLower () String {
return asciiString (strings .ToLower (string (s )))
}
func (s asciiString ) toUpper () String {
return asciiString (strings .ToUpper (string (s )))
}
func (s asciiString ) toTrimmedUTF8 () string {
return strings .TrimSpace (string (s ))
}
func (s asciiString ) string () unistring .String {
return unistring .String (s )
}
func (s asciiString ) Export () interface {} {
return string (s )
}
func (s asciiString ) ExportType () reflect .Type {
return reflectTypeString
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .