From 0eeb865ffc6d40c3290a122e990cf9f3d00de3d4 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Wed, 8 Sep 2021 10:17:07 -0400 Subject: [PATCH] Add Undefined(iso) and Null(iso) functions (#163) --- CHANGELOG.md | 1 + isolate.go | 5 +++++ v8go.cc | 20 ++++++++++++++++++++ v8go.h | 2 ++ value.go | 22 ++++++++++++++++++++++ value_test.go | 30 ++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e8acce5..4fcc46ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Build v8 with i18n support - Access "this" from function callback - value.SameValue(otherValue) function to compare values for sameness +- Undefined, Null functions to get these constant values for the isolate ### Changed - Removed error return value from Context.Isolate() which never fails diff --git a/isolate.go b/isolate.go index d623a1f8..be584589 100644 --- a/isolate.go +++ b/isolate.go @@ -22,6 +22,9 @@ type Isolate struct { cbMutex sync.RWMutex cbSeq int cbs map[int]FunctionCallback + + null *Value + undefined *Value } // HeapStatistics represents V8 isolate heap statistics @@ -54,6 +57,8 @@ func NewIsolate() (*Isolate, error) { ptr: C.NewIsolate(), cbs: make(map[int]FunctionCallback), } + iso.null = newValueNull(iso) + iso.undefined = newValueUndefined(iso) // TODO: [RC] catch any C++ exceptions and return as error return iso, nil } diff --git a/v8go.cc b/v8go.cc index f1f66eb0..1cb88aff 100644 --- a/v8go.cc +++ b/v8go.cc @@ -569,6 +569,26 @@ ValuePtr NewValueString(IsolatePtr iso_ptr, const char* v) { return tracked_value(ctx, val); } +ValuePtr NewValueNull(IsolatePtr iso_ptr) { + ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr); + m_value* val = new m_value; + val->iso = iso; + val->ctx = ctx; + val->ptr = Persistent>( + iso, Null(iso)); + return tracked_value(ctx, val); +} + +ValuePtr NewValueUndefined(IsolatePtr iso_ptr) { + ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr); + m_value* val = new m_value; + val->iso = iso; + val->ctx = ctx; + val->ptr = Persistent>( + iso, Undefined(iso)); + return tracked_value(ctx, val); +} + ValuePtr NewValueBoolean(IsolatePtr iso_ptr, int v) { ISOLATE_SCOPE_INTERNAL_CONTEXT(iso_ptr); m_value* val = new m_value; diff --git a/v8go.h b/v8go.h index 5b1fc221..51651edc 100644 --- a/v8go.h +++ b/v8go.h @@ -83,6 +83,8 @@ extern TemplatePtr NewFunctionTemplate(IsolatePtr iso_ptr, int callback_ref); extern ValuePtr FunctionTemplateGetFunction(TemplatePtr ptr, ContextPtr ctx_ptr); +extern ValuePtr NewValueNull(IsolatePtr iso_ptr); +extern ValuePtr NewValueUndefined(IsolatePtr iso_ptr); extern ValuePtr NewValueInteger(IsolatePtr iso_ptr, int32_t v); extern ValuePtr NewValueIntegerFromUnsigned(IsolatePtr iso_ptr, uint32_t v); extern ValuePtr NewValueString(IsolatePtr iso_ptr, const char* v); diff --git a/value.go b/value.go index 79d373f4..e5b87c7a 100644 --- a/value.go +++ b/value.go @@ -31,6 +31,28 @@ func (v *Value) value() *Value { return v } +func newValueNull(iso *Isolate) *Value { + return &Value{ + ptr: C.NewValueNull(iso.ptr), + } +} + +func newValueUndefined(iso *Isolate) *Value { + return &Value{ + ptr: C.NewValueUndefined(iso.ptr), + } +} + +// Undefined returns the `undefined` JS value +func Undefined(iso *Isolate) *Value { + return iso.undefined +} + +// Null returns the `null` JS value +func Null(iso *Isolate) *Value { + return iso.null +} + // NewValue will create a primitive value. Supported values types to create are: // string -> V8::String // int32 -> V8::Integer diff --git a/value_test.go b/value_test.go index d9a6b368..d264f109 100644 --- a/value_test.go +++ b/value_test.go @@ -160,6 +160,36 @@ func TestValueBoolean(t *testing.T) { } } +func TestValueConstants(t *testing.T) { + t.Parallel() + iso, _ := v8go.NewIsolate() + defer iso.Dispose() + ctx, _ := v8go.NewContext(iso) + defer ctx.Close() + + tests := [...]struct { + source string + value *v8go.Value + same bool + }{ + {"undefined", v8go.Undefined(iso), true}, + {"null", v8go.Null(iso), true}, + {"undefined", v8go.Null(iso), false}, + } + + for _, tt := range tests { + tt := tt + + val, err := ctx.RunScript(tt.source, "test.js") + failIf(t, err) + + if tt.value.SameValue(val) != tt.same { + t.Errorf("SameValue on JS `%s` and V8 value %+v didn't return %v", + tt.source, tt.value, tt.same) + } + } +} + func TestValueArrayIndex(t *testing.T) { t.Parallel() ctx, _ := v8go.NewContext(nil)