github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/bas/value.go (about)

     1  package bas
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"io"
     7  	"math"
     8  	"reflect"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  	"unicode/utf8"
    13  	"unsafe"
    14  
    15  	"github.com/coyove/nj/internal"
    16  	"github.com/coyove/nj/typ"
    17  )
    18  
    19  //go:linkname strhash runtime.strhash
    20  func strhash(p unsafe.Pointer, h uintptr) uintptr
    21  
    22  //go:linkname memhash64 runtime.memhash64
    23  func memhash64(p unsafe.Pointer, h uintptr) uintptr
    24  
    25  var (
    26  	baseMarker = func() []byte {
    27  		// Ensures baseMarker is at least 256 bytes long and its memory aligns with 256 bytes
    28  		b := make([]byte, 512)
    29  		for i := range b {
    30  			if byte(uintptr(unsafe.Pointer(&b[i]))) == 0 {
    31  				return b[i:]
    32  			}
    33  		}
    34  		panic("memory")
    35  	}()
    36  	baseStart  = uintptr(unsafe.Pointer(&baseMarker[0]))
    37  	baseLength = uintptr(len(baseMarker))
    38  	// baseEnd    = uintptr(unsafe.Pointer(&baseMarker[0])) + baseLength
    39  
    40  	int64Marker    = unsafe.Pointer(&baseMarker[int(typ.Number)])
    41  	float64Marker  = unsafe.Pointer(&baseMarker[int(typ.Number)+8])
    42  	trueMarker     = unsafe.Pointer(&baseMarker[int(typ.Bool)])
    43  	falseMarker    = unsafe.Pointer(&baseMarker[int(typ.Bool)+8])
    44  	smallStrMarker = unsafe.Pointer(&baseMarker[int(typ.String)])
    45  	int64Marker2   = uintptr(int64Marker) * 2
    46  
    47  	Nil     = Value{}
    48  	Zero    = Int64(0)
    49  	NullStr = Str("")
    50  	False   = Value{0, falseMarker}
    51  	True    = Value{1, trueMarker}
    52  )
    53  
    54  const (
    55  	ValueSize = unsafe.Sizeof(Value{})
    56  
    57  	errNeedNumber           = "operator requires number, got %v"
    58  	errNeedNumbers          = "operator requires numbers, got %v and %v"
    59  	errNeedNumbersOrStrings = "operator requires numbers or strings, got %v and %v"
    60  )
    61  
    62  // Value is the basic data type used by the intepreter, an empty Value naturally represent nil.
    63  type Value struct {
    64  	v uint64
    65  	p unsafe.Pointer
    66  }
    67  
    68  // Type returns the type of value.
    69  func (v Value) Type() typ.ValueType {
    70  	if uintptr(v.p)&0xffffffffffffff00 == baseStart {
    71  		return typ.ValueType(uintptr(v.p) & 7)
    72  	}
    73  	return typ.ValueType(v.v)
    74  }
    75  
    76  func (v Value) pType() typ.ValueType {
    77  	return typ.ValueType(uintptr(v.p) & 7)
    78  }
    79  
    80  // IsFalse returns true if value is falsy: nil, false, empty string or 0.
    81  func (v Value) IsFalse() bool { return v.v == 0 }
    82  
    83  // IsTrue returns true if value is not falsy.
    84  func (v Value) IsTrue() bool { return v.v != 0 }
    85  
    86  // IsInt64 returns true if value is an integer number.
    87  func (v Value) IsInt64() bool { return v.p == int64Marker }
    88  
    89  // IsNumber returns true if value is a number.
    90  func (v Value) IsNumber() bool { return v.pType() == typ.Number }
    91  
    92  // IsString returns true if value is a string.
    93  func (v Value) IsString() bool { return v.Type() == typ.String }
    94  
    95  // IsObject returns true if value is an object.
    96  func (v Value) IsObject() bool { return v.Type() == typ.Object }
    97  
    98  // IsArray returns true if value is an array.
    99  func (v Value) IsArray() bool {
   100  	return v.Type() == typ.Native && v.Native().meta.Proto.HasPrototype(&Proto.Array)
   101  }
   102  
   103  // IsNil returns true if value is nil.
   104  func (v Value) IsNil() bool { return v == Nil }
   105  
   106  // Bool creates a boolean value.
   107  func Bool(v bool) Value {
   108  	if v {
   109  		return True
   110  	}
   111  	return False
   112  }
   113  
   114  // Float64 creates a number value.
   115  func Float64(f float64) Value {
   116  	if float64(int64(f)) == f {
   117  		// if math.Floor(f) == f {
   118  		return Value{v: uint64(int64(f)), p: int64Marker}
   119  	}
   120  	return Value{v: math.Float64bits(f), p: float64Marker}
   121  }
   122  
   123  // Int creates a number value.
   124  func Int(i int) Value {
   125  	return Int64(int64(i))
   126  }
   127  
   128  // Int64 creates a number value.
   129  func Int64(i int64) Value {
   130  	return Value{v: uint64(i), p: int64Marker}
   131  }
   132  
   133  // Str creates a string value.
   134  func Str(s string) Value {
   135  	if len(s) <= 8 { // payload 8b
   136  		var x [8]byte
   137  		switch len(s) {
   138  		case 1:
   139  			a := s[0]
   140  			x = [8]byte{a, a, a, a, a, a, a, a + 1}
   141  		case 2:
   142  			a, b := s[0], s[1]
   143  			x = [8]byte{a, b, a, b, a, b, a, b + 1}
   144  		case 3:
   145  			copy(x[:], s)
   146  			copy(x[3:], s)
   147  			x[6], x[7] = s[0], s[1]+1
   148  		case 4, 5, 6, 7:
   149  			copy(x[:], s)
   150  			copy(x[len(s):], s)
   151  			x[7]++
   152  		case 8:
   153  			if s == "\x00\x00\x00\x00\x00\x00\x00\x00" {
   154  				return Value{v: uint64(typ.String), p: unsafe.Pointer(&s)}
   155  			}
   156  			copy(x[:], s)
   157  		}
   158  		return Value{
   159  			v: binary.BigEndian.Uint64(x[:]),
   160  			p: unsafe.Pointer(uintptr(smallStrMarker) + uintptr(len(s))*8),
   161  		}
   162  	}
   163  	return Value{v: uint64(typ.String), p: unsafe.Pointer(&s)}
   164  }
   165  
   166  // UnsafeStr creates a string value from []byte, its content may change if []byte changed.
   167  func UnsafeStr(b []byte) Value {
   168  	var s string
   169  	*(*[2]uintptr)(unsafe.Pointer(&s)) = *(*[2]uintptr)(unsafe.Pointer(&b))
   170  	return Str(s)
   171  }
   172  
   173  // Byte creates a one-byte string value.
   174  func Byte(s byte) Value {
   175  	x := [8]byte{s, s, s, s, s, s, s, s + 1}
   176  	return Value{v: binary.BigEndian.Uint64(x[:]), p: unsafe.Pointer(uintptr(smallStrMarker) + 8)}
   177  }
   178  
   179  // Rune creates a one-rune string value encoded in UTF-8.
   180  func Rune(r rune) Value {
   181  	x := [8]byte{}
   182  	n := utf8.EncodeRune(x[:], r)
   183  	switch n {
   184  	case 1:
   185  		x[1], x[2], x[3], x[4], x[5], x[6], x[7] = x[0], x[0], x[0], x[0], x[0], x[0], x[0]+1
   186  	case 2:
   187  		x[2], x[3], x[4], x[5], x[6], x[7] = x[0], x[1], x[0], x[1], x[0], x[1]+1
   188  	case 3:
   189  		x[3], x[4], x[5], x[6], x[7] = x[0], x[1], x[2], x[0], x[1]+1
   190  	case 4:
   191  		copy(x[4:], x[:4])
   192  		x[7]++
   193  	}
   194  	return Value{v: binary.BigEndian.Uint64(x[:]), p: unsafe.Pointer(uintptr(smallStrMarker) + uintptr(n)*8)}
   195  }
   196  
   197  // Bytes creates a bytes array.
   198  func Bytes(b []byte) Value {
   199  	return NewNativeWithMeta(b, &Proto.BytesMeta).ToValue()
   200  }
   201  
   202  // Error creates an error, 'e' can be nil, indicating that the returned error has no stacktrace.
   203  func Error(e *Env, err interface{}) Value {
   204  	if err == nil {
   205  		return Nil
   206  	}
   207  	ee := &ExecError{root: err}
   208  	if e != nil {
   209  		ee.stacks = e.runtime.Stacktrace(true)
   210  	}
   211  	return NewNativeWithMeta(ee, &Proto.ErrorMeta).ToValue()
   212  }
   213  
   214  // Array creates an untyped array from values.
   215  func Array(v ...Value) Value {
   216  	return newArray(v...).ToValue()
   217  }
   218  
   219  // ValueOf creates a Value from any golang types.
   220  func ValueOf(i interface{}) Value {
   221  	switch v := i.(type) {
   222  	case nil:
   223  		return Nil
   224  	case bool:
   225  		return Bool(v)
   226  	case float64:
   227  		return Float64(v)
   228  	case int:
   229  		return Int64(int64(v))
   230  	case int8:
   231  		return Int64(int64(v))
   232  	case int16:
   233  		return Int64(int64(v))
   234  	case int32:
   235  		return Int64(int64(v))
   236  	case int64:
   237  		return Int64(v)
   238  	case uint:
   239  		return Int64(int64(uint64(v)))
   240  	case uint8:
   241  		return Int64(int64(uint64(v)))
   242  	case uint16:
   243  		return Int64(int64(uint64(v)))
   244  	case uint32:
   245  		return Int64(int64(uint64(v)))
   246  	case uint64:
   247  		return Int64(int64(v))
   248  	case uintptr:
   249  		return Int64(int64(v))
   250  	case string:
   251  		return Str(v)
   252  	case []byte:
   253  		return Bytes(v)
   254  	case *Object:
   255  		return v.ToValue()
   256  	case *Map:
   257  		return newObjectInplace(*v).ToValue()
   258  	case Map:
   259  		return newObjectInplace(v).ToValue()
   260  	case []Value:
   261  		return Array(v...)
   262  	case Value:
   263  		return v
   264  	case error:
   265  		return Error(nil, v)
   266  	case reflect.Value:
   267  		return ValueOf(v.Interface())
   268  	case func(*Env):
   269  		return Func(internal.UnnamedFunc(), v)
   270  	}
   271  
   272  	if rv := reflect.ValueOf(i); rv.Kind() == reflect.Func {
   273  		rt := rv.Type()
   274  		nf := func(env *Env) {
   275  			rtNumIn := rt.NumIn()
   276  			ins := make([]reflect.Value, 0, rtNumIn)
   277  			if !rt.IsVariadic() {
   278  				if env.Size() != rtNumIn {
   279  					internal.Panic("native function expects %d arguments, got %d", rtNumIn, env.Size())
   280  				}
   281  				for i := 0; i < rtNumIn; i++ {
   282  					ins = append(ins, env.Get(i).ToType(rt.In(i)))
   283  				}
   284  			} else {
   285  				if env.Size() < rtNumIn-1 {
   286  					internal.Panic("native variadic function expects at least %d arguments, got %d", rtNumIn-1, env.Size())
   287  				}
   288  				for i := 0; i < rtNumIn-1; i++ {
   289  					ins = append(ins, env.Get(i).ToType(rt.In(i)))
   290  				}
   291  				for i := rtNumIn - 1; i < env.Size(); i++ {
   292  					ins = append(ins, env.Get(i).ToType(rt.In(rtNumIn-1).Elem()))
   293  				}
   294  			}
   295  			if outs := rv.Call(ins); len(outs) == 0 {
   296  				env.A = Nil
   297  			} else if len(outs) == 1 {
   298  				env.A = ValueOf(outs[0].Interface())
   299  			} else {
   300  				env.A = NewNative(outs).ToValue()
   301  			}
   302  		}
   303  		return Func("<"+rt.String()+">", nf)
   304  	}
   305  	return NewNative(i).ToValue()
   306  }
   307  
   308  func (v Value) isSmallString() bool {
   309  	return uintptr(v.p) >= uintptr(smallStrMarker) && uintptr(v.p) <= uintptr(smallStrMarker)+8*8
   310  }
   311  
   312  // Str returns value as a string, Type() should be checked beforehand.
   313  func (v Value) Str() string {
   314  	if v.isSmallString() {
   315  		sz := (uintptr(v.p) - uintptr(smallStrMarker)) / 8
   316  		if sz == 0 {
   317  			return ""
   318  		}
   319  		buf := make([]byte, 8)
   320  		binary.BigEndian.PutUint64(buf, v.v)
   321  		buf = buf[:sz]
   322  		return *(*string)(unsafe.Pointer(&buf))
   323  	}
   324  	return *(*string)(v.p)
   325  }
   326  
   327  // Int returns value as an int.
   328  func (v Value) Int() int { return int(v.Int64()) }
   329  
   330  // Int64 returns value as an int64 (floats will be truncated to integers), Type() should be checked beforehand.
   331  func (v Value) Int64() int64 {
   332  	if v.p == int64Marker {
   333  		return int64(v.v)
   334  	}
   335  	return int64(math.Float64frombits(v.v))
   336  }
   337  
   338  // Float64 returns value as a float (integers will be promoted to floats), Type() should be checked beforehand.
   339  func (v Value) Float64() float64 {
   340  	if v.p == int64Marker {
   341  		return float64(int64(v.v))
   342  	}
   343  	return math.Float64frombits(v.v)
   344  }
   345  
   346  // Duration returns the number value as a time.Duration,
   347  // it assumes the number represents the Unix timestamp in seconds.
   348  func (v Value) Duration() time.Duration {
   349  	return time.Duration(v.Float64()*1e6) * 1e3
   350  }
   351  
   352  // Bool returns value as a boolean, Type() should be checked beforehand.
   353  func (v Value) Bool() bool { return v.p == trueMarker }
   354  
   355  // Object returns value as an Object, Type() should be checked beforehand.
   356  func (v Value) Object() *Object { return (*Object)(v.p) }
   357  
   358  // Native returns value as a Native, Type() should be checked beforehand.
   359  func (v Value) Native() *Native { return (*Native)(v.p) }
   360  
   361  // Interface returns value as an interface{}
   362  func (v Value) Interface() interface{} {
   363  	switch v.Type() {
   364  	case typ.Bool:
   365  		return v.Bool()
   366  	case typ.Number:
   367  		if v.IsInt64() {
   368  			return v.Int64()
   369  		}
   370  		return v.Float64()
   371  	case typ.String:
   372  		return v.Str()
   373  	case typ.Object:
   374  		return v.Object()
   375  	case typ.Native:
   376  		return v.Native().Unwrap()
   377  	}
   378  	return nil
   379  }
   380  
   381  func (v Value) unsafeAddr() uintptr { return uintptr(v.p) }
   382  
   383  func (v Value) UnsafeInt64() int64 { return int64(v.v) }
   384  
   385  func (v Value) UnsafeFloat64() float64 { return math.Float64frombits(v.v) }
   386  
   387  // Equal returns true if two values are equal.
   388  func (v Value) Equal(r Value) bool {
   389  	if v == r {
   390  		return true
   391  	}
   392  	return v.v == uint64(typ.String) && v.v == r.v && *(*string)(v.p) == *(*string)(r.p)
   393  }
   394  
   395  // HashCode returns the hash of value.
   396  func (v Value) HashCode() uint32 {
   397  	if typ.ValueType(v.v) == typ.String {
   398  		return uint32(strhash(v.p, 0))
   399  	}
   400  
   401  	x := uint64(uintptr(v.p))
   402  	xp := uintptr(unsafe.Pointer(&x))
   403  	h := memhash64(unsafe.Pointer(xp^0), uintptr(v.v))
   404  	return uint32(h)
   405  
   406  	// x := v.v ^ uint64(uintptr(v.p))
   407  	// h := uint32(x) ^ uint32(x>>32)
   408  	// h ^= h >> 16
   409  	// h *= 0x85ebca6b
   410  	// h ^= h >> 13
   411  	// // h *= 0xc2b2ae35
   412  	// // h ^= h >> 16
   413  	// return h
   414  }
   415  
   416  func (v Value) String() string {
   417  	p := &bytes.Buffer{}
   418  	v.Stringify(p, typ.MarshalToString)
   419  	return p.String()
   420  }
   421  
   422  func (v Value) JSONString() string {
   423  	p := &bytes.Buffer{}
   424  	v.Stringify(p, typ.MarshalToJSON)
   425  	return strings.TrimSpace(p.String())
   426  }
   427  
   428  func (v Value) MarshalJSON() ([]byte, error) {
   429  	p := &bytes.Buffer{}
   430  	v.Stringify(p, typ.MarshalToJSON)
   431  	return bytes.TrimSpace(p.Bytes()), nil
   432  }
   433  
   434  func (v Value) Stringify(p io.Writer, j typ.MarshalType) {
   435  	switch v.Type() {
   436  	case typ.Bool:
   437  		internal.WriteString(p, strconv.FormatBool(v.Bool()))
   438  	case typ.Number:
   439  		if v.IsInt64() {
   440  			internal.WriteString(p, strconv.FormatInt(v.Int64(), 10))
   441  		} else {
   442  			internal.WriteString(p, strconv.FormatFloat(v.Float64(), 'f', -1, 64))
   443  		}
   444  	case typ.String:
   445  		internal.WriteString(p, internal.IfQuote(j == typ.MarshalToJSON, v.Str()))
   446  	case typ.Object:
   447  		if j == typ.MarshalToJSON || j == typ.MarshalToString {
   448  			v.Object().rawPrint(p, j)
   449  		} else {
   450  			internal.WriteString(p, v.Object().Name())
   451  		}
   452  	case typ.Native:
   453  		if j == typ.MarshalToJSON || j == typ.MarshalToString {
   454  			v.Native().Marshal(p, j)
   455  		} else {
   456  			internal.WriteString(p, "@"+v.Native().meta.Name)
   457  		}
   458  	default:
   459  		internal.WriteString(p, internal.IfStr(j == typ.MarshalToJSON, "null", "nil"))
   460  	}
   461  }