From 3a200355a152a0c7026c5e38f054fbd68b31aacb Mon Sep 17 00:00:00 2001 From: Tommie Gannert Date: Wed, 13 Oct 2021 18:31:35 +0200 Subject: [PATCH] Add Exception type and New*Error constructors. --- exception.go | 87 +++++++++++++++++++++++++++++++++++++++++++++++ exception_test.go | 44 ++++++++++++++++++++++++ v8go.cc | 53 +++++++++++++++++++++++++++++ v8go.h | 15 ++++++++ 4 files changed, 199 insertions(+) create mode 100644 exception.go create mode 100644 exception_test.go diff --git a/exception.go b/exception.go new file mode 100644 index 000000000..2d51f4315 --- /dev/null +++ b/exception.go @@ -0,0 +1,87 @@ +// Copyright 2021 Roger Chapman and the v8go contributors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package v8go + +import ( + // #include + // #include "v8go.h" + "C" + + "fmt" + "unsafe" +) + +// NewRangeError creates a RangeError. +func NewRangeError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_RANGE, msg) +} + +// NewReferenceError creates a ReferenceError. +func NewReferenceError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_REFERENCE, msg) +} + +// NewSyntaxError creates a SyntaxError. +func NewSyntaxError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_SYNTAX, msg) +} + +// NewTypeError creates a TypeError. +func NewTypeError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_TYPE, msg) +} + +// NewWasmCompileError creates a WasmCompileError. +func NewWasmCompileError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_WASM_COMPILE, msg) +} + +// NewWasmLinkError creates a WasmLinkError. +func NewWasmLinkError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_WASM_LINK, msg) +} + +// NewWasmRuntimeError creates a WasmRuntimeError. +func NewWasmRuntimeError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_WASM_RUNTIME, msg) +} + +// NewError creates an Error, which is the common thing to throw from +// user code. +func NewError(iso *Isolate, msg string) *Exception { + return newExceptionError(iso, C.ERROR_GENERIC, msg) +} + +func newExceptionError(iso *Isolate, typ C.ErrorTypeIndex, msg string) *Exception { + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + eptr := C.NewValueError(iso.ptr, typ, cmsg) + if eptr == nil { + panic(fmt.Errorf("invalid error type index: %d", typ)) + } + return &Exception{&Value{ptr: eptr}} +} + +// An Exception is a JavaScript exception. +type Exception struct { + *Value +} + +// value implements Valuer. +func (e *Exception) value() *Value { + return e.Value +} + +// Error implements error. +func (e *Exception) Error() string { + return e.String() +} + +// String implements fmt.Stringer. +func (e *Exception) String() string { + s := C.ExceptionGetMessageString(e.ptr) + defer C.free(unsafe.Pointer(s)) + return C.GoString(s) +} diff --git a/exception_test.go b/exception_test.go new file mode 100644 index 000000000..2107fd971 --- /dev/null +++ b/exception_test.go @@ -0,0 +1,44 @@ +// Copyright 2021 Roger Chapman and the v8go contributors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package v8go_test + +import ( + "strings" + "testing" + + v8 "rogchap.com/v8go" +) + +func TestNewError(t *testing.T) { + t.Parallel() + + tsts := []struct { + New func(*v8.Isolate, string) *v8.Exception + WantType string + }{ + {v8.NewRangeError, "RangeError"}, + {v8.NewReferenceError, "ReferenceError"}, + {v8.NewSyntaxError, "SyntaxError"}, + {v8.NewTypeError, "TypeError"}, + {v8.NewWasmCompileError, "CompileError"}, + {v8.NewWasmLinkError, "LinkError"}, + {v8.NewWasmRuntimeError, "RuntimeError"}, + {v8.NewError, "Error"}, + } + for _, tst := range tsts { + t.Run(tst.WantType, func(t *testing.T) { + iso := v8.NewIsolate() + defer iso.Dispose() + + got := tst.New(iso, "amessage") + if !got.IsNativeError() { + t.Error("IsNativeError returned false, want true") + } + if got := got.Error(); !strings.Contains(got, " "+tst.WantType+":") { + t.Errorf("Error(): got %q, want containing %q", got, tst.WantType) + } + }) + } +} diff --git a/v8go.cc b/v8go.cc index 144470fc2..92632731a 100644 --- a/v8go.cc +++ b/v8go.cc @@ -660,6 +660,48 @@ RtnValue NewValueBigIntFromWords(IsolatePtr iso, return rtn; } +ValuePtr NewValueError(IsolatePtr iso, ErrorTypeIndex idx, const char* message) { + ISOLATE_SCOPE_INTERNAL_CONTEXT(iso); + Local local_ctx = ctx->ptr.Get(iso); + Context::Scope context_scope(local_ctx); + + Local local_msg = String::NewFromUtf8(iso, message).ToLocalChecked(); + Local v; + switch (idx) { + case ERROR_RANGE: + v = Exception::RangeError(local_msg); + break; + case ERROR_REFERENCE: + v = Exception::ReferenceError(local_msg); + break; + case ERROR_SYNTAX: + v = Exception::SyntaxError(local_msg); + break; + case ERROR_TYPE: + v = Exception::TypeError(local_msg); + break; + case ERROR_WASM_COMPILE: + v = Exception::WasmCompileError(local_msg); + break; + case ERROR_WASM_LINK: + v = Exception::WasmLinkError(local_msg); + break; + case ERROR_WASM_RUNTIME: + v = Exception::WasmRuntimeError(local_msg); + break; + case ERROR_GENERIC: + v = Exception::Error(local_msg); + break; + default: + return nullptr; + } + m_value* val = new m_value; + val->iso = iso; + val->ctx = ctx; + val->ptr = Persistent>(iso, v); + return tracked_value(ctx, val); +} + const uint32_t* ValueToArrayIndex(ValuePtr ptr) { LOCAL_VALUE(ptr); Local array_index; @@ -1030,6 +1072,17 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr) { return value->IsModuleNamespaceObject(); } +/********** Exception **********/ + +const char* ExceptionGetMessageString(ValuePtr ptr) { + LOCAL_VALUE(ptr); + + Local local_msg = Exception::CreateMessage(iso, value); + Local local_str = local_msg->Get(); + String::Utf8Value utf8(iso, local_str); + return CopyString(utf8); +} + /********** Object **********/ #define LOCAL_OBJECT(ptr) \ diff --git a/v8go.h b/v8go.h index 339f424b2..a04265660 100644 --- a/v8go.h +++ b/v8go.h @@ -30,6 +30,17 @@ typedef m_ctx* ContextPtr; typedef m_value* ValuePtr; typedef m_template* TemplatePtr; +typedef enum { + ERROR_RANGE = 1, + ERROR_REFERENCE, + ERROR_SYNTAX, + ERROR_TYPE, + ERROR_WASM_COMPILE, + ERROR_WASM_LINK, + ERROR_WASM_RUNTIME, + ERROR_GENERIC, +} ErrorTypeIndex; + typedef struct { const char* msg; const char* location; @@ -115,6 +126,7 @@ extern RtnValue NewValueBigIntFromWords(IsolatePtr iso_ptr, int sign_bit, int word_count, const uint64_t* words); +extern ValuePtr NewValueError(IsolatePtr iso_ptr, ErrorTypeIndex idx, const char* message); const char* ValueToString(ValuePtr ptr); const uint32_t* ValueToArrayIndex(ValuePtr ptr); int ValueToBoolean(ValuePtr ptr); @@ -185,6 +197,9 @@ extern void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr); extern void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr); extern RtnValue ObjectGet(ValuePtr ptr, const char* key); extern RtnValue ObjectGetIdx(ValuePtr ptr, uint32_t idx); + +const char* ExceptionGetMessageString(ValuePtr ptr); + int ObjectHas(ValuePtr ptr, const char* key); int ObjectHasIdx(ValuePtr ptr, uint32_t idx); int ObjectDelete(ValuePtr ptr, const char* key);