Browse Source

Added IsNumber(), IsBigInt() and IsString() convenience methods. Treat nil *big.Int as 0n.

Dmitry Panov 6 months ago
parent
commit
bcd7cc6bf6
2 changed files with 41 additions and 1 deletions
  1. 31 1
      runtime.go
  2. 10 0
      runtime_test.go

+ 31 - 1
runtime.go

@@ -1620,6 +1620,13 @@ Notes on individual types:
 Primitive types (numbers, string, bool) are converted to the corresponding JavaScript primitives. These values
 Primitive types (numbers, string, bool) are converted to the corresponding JavaScript primitives. These values
 are goroutine-safe and can be transferred between runtimes.
 are goroutine-safe and can be transferred between runtimes.
 
 
+# *big.Int
+
+A *big.Int value is converted to a BigInt value. Note, because BigInt is immutable, but *big.Int isn't, the value is
+copied. Export()'ing this value returns a *big.Int which is also a copy.
+
+If the pointer value is nil, the resulting BigInt is 0n.
+
 # Strings
 # Strings
 
 
 Because of the difference in internal string representation between ECMAScript (which uses UTF-16) and Go (which uses
 Because of the difference in internal string representation between ECMAScript (which uses UTF-16) and Go (which uses
@@ -1861,7 +1868,11 @@ func (r *Runtime) toValue(i interface{}, origValue reflect.Value) Value {
 	case float64:
 	case float64:
 		return floatToValue(i)
 		return floatToValue(i)
 	case *big.Int:
 	case *big.Int:
-		return (*valueBigInt)(new(big.Int).Set(i))
+		v := new(big.Int)
+		if i != nil {
+			v.Set(i)
+		}
+		return (*valueBigInt)(v)
 	case map[string]interface{}:
 	case map[string]interface{}:
 		if i == nil {
 		if i == nil {
 			return _null
 			return _null
@@ -2536,6 +2547,25 @@ func IsInfinity(v Value) bool {
 	return v == _positiveInf || v == _negativeInf
 	return v == _positiveInf || v == _negativeInf
 }
 }
 
 
+func IsNumber(v Value) bool {
+	switch v.(type) {
+	case valueInt, valueFloat:
+		return true
+	default:
+		return false
+	}
+}
+
+func IsBigInt(v Value) bool {
+	_, ok := v.(*valueBigInt)
+	return ok
+}
+
+func IsString(v Value) bool {
+	_, ok := v.(String)
+	return ok
+}
+
 // Undefined returns JS undefined value. Note if global 'undefined' property is changed this still returns the original value.
 // Undefined returns JS undefined value. Note if global 'undefined' property is changed this still returns the original value.
 func Undefined() Value {
 func Undefined() Value {
 	return _undefined
 	return _undefined

+ 10 - 0
runtime_test.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
 	"math"
 	"math"
+	"math/big"
 	"reflect"
 	"reflect"
 	"runtime"
 	"runtime"
 	"strconv"
 	"strconv"
@@ -2845,6 +2846,9 @@ func TestErrorFormatSymbols(t *testing.T) {
 	vm := New()
 	vm := New()
 	vm.Set("a", func() (Value, error) { return nil, errors.New("something %s %f") })
 	vm.Set("a", func() (Value, error) { return nil, errors.New("something %s %f") })
 	_, err := vm.RunString("a()")
 	_, err := vm.RunString("a()")
+	if err == nil {
+		t.Fatal("expected error")
+	}
 	if !strings.Contains(err.Error(), "something %s %f") {
 	if !strings.Contains(err.Error(), "something %s %f") {
 		t.Fatalf("Wrong value %q", err.Error())
 		t.Fatalf("Wrong value %q", err.Error())
 	}
 	}
@@ -3107,6 +3111,12 @@ func TestToNumber(t *testing.T) {
 	testScriptWithTestLib(SCRIPT, _undefined, t)
 	testScriptWithTestLib(SCRIPT, _undefined, t)
 }
 }
 
 
+func TestToValueNilBigInt(t *testing.T) {
+	vm := New()
+	vm.Set("n", (*big.Int)(nil))
+	vm.testScript(`n === 0n`, valueTrue, t)
+}
+
 /*
 /*
 func TestArrayConcatSparse(t *testing.T) {
 func TestArrayConcatSparse(t *testing.T) {
 function foo(a,b,c)
 function foo(a,b,c)