Skip to content

Commit

Permalink
use return tuple so that we can provide error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
rogchap committed Aug 31, 2019
1 parent 69d20d6 commit 2e9d13a
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 45 deletions.
43 changes: 36 additions & 7 deletions context.go
@@ -1,26 +1,55 @@
package v8go

// #import <stdlib.h>
// #import "v8go.h"
import "C"
import "runtime"
import (
"errors"
"runtime"
"unsafe"
)

type Context struct {
ptr C.ContextPtr
}

func NewContext(iso *Isolate) *Context {
ctx := &Context{C.NewContext(iso.ptr)}
runtime.SetFinalizer(ctx, (*Context).release)
runtime.SetFinalizer(ctx, (*Context).finalizer)
return ctx
}

func (c *Context) RunScript(source string) (*Value, error) {
valuePtr := C.RunScript(c.ptr, C.CString(source), C.CString("origin"))
return &Value{valuePtr}, nil
// RunScript executes the source JavaScript; origin or filename provides a
// reference for the script and used in the exception stack trace.
func (c *Context) RunScript(source string, origin string) (*Value, error) {
cSource := C.CString(source)
cOrigin := C.CString(origin)
defer C.free(unsafe.Pointer(cSource))
defer C.free(unsafe.Pointer(cOrigin))

rtn := C.RunScript(c.ptr, cSource, cOrigin)
return getValue(rtn), getError(rtn)
}

func (c *Context) release() {
//TODO dispose of object in C++A
func (c *Context) finalizer() {
C.ContextDispose(c.ptr)
c.ptr = nil
runtime.SetFinalizer(c, nil)
}

func getValue(rtn C.RtnValue) *Value {
if rtn.value == nil {
return nil
}
v := &Value{rtn.value}
runtime.SetFinalizer(v, (*Value).finalizer)
return v
}

func getError(rtn C.RtnValue) error {
if rtn.error == nil {
return nil
}
defer C.free(unsafe.Pointer(rtn.error))
return errors.New(C.GoString(rtn.error))
}
35 changes: 35 additions & 0 deletions context_test.go
@@ -0,0 +1,35 @@
package v8go_test

import (
"testing"

"rogchap.com/v8go"
)

func TestRunScriptStringer(t *testing.T) {
t.Parallel()
var iso = v8go.NewIsolate()
ctx := v8go.NewContext(iso)
var tests = [...]struct {
name string
source string
out string
}{
{"Addition", "2 + 2", "4"},
{"Multiplication", "13 * 2", "26"},
{"String", `"string"`, "string"},
{"Object", `let obj = {}; obj`, "[object Object]"},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result, _ := ctx.RunScript(tt.source, "test.js")
str := result.String()
if str != tt.out {
t.Errorf("unespected result: expected %q, got %q", tt.out, str)
}
})
}
}
4 changes: 2 additions & 2 deletions isolate.go
Expand Up @@ -19,11 +19,11 @@ func NewIsolate() *Isolate {
C.Init()
})
iso := &Isolate{C.NewIsolate()}
runtime.SetFinalizer(iso, (*Isolate).release)
runtime.SetFinalizer(iso, (*Isolate).finalizer)
return iso
}

func (i *Isolate) release() {
func (i *Isolate) finalizer() {
C.IsolateDispose(i.ptr)
i.ptr = nil
runtime.SetFinalizer(i, nil)
Expand Down
40 changes: 36 additions & 4 deletions v8go.cc
Expand Up @@ -71,7 +71,7 @@ ContextPtr NewContext(IsolatePtr ptr) {
return static_cast<ContextPtr>(ctx);
}

ValuePtr RunScript(ContextPtr ctx_ptr, const char* source, const char* origin) {
RtnValue RunScript(ContextPtr ctx_ptr, const char* source, const char* origin) {
m_ctx* ctx = static_cast<m_ctx*>(ctx_ptr);
Isolate* iso = ctx->iso;
Locker locker(iso);
Expand All @@ -85,6 +85,8 @@ ValuePtr RunScript(ContextPtr ctx_ptr, const char* source, const char* origin) {
Local<String> src = String::NewFromUtf8(iso, source, NewStringType::kNormal).ToLocalChecked();
Local<String> ogn = String::NewFromUtf8(iso, origin, NewStringType::kNormal).ToLocalChecked();

RtnValue rtn = { nullptr, nullptr };

ScriptOrigin script_origin(ogn);
Local<Script> script = Script::Compile(local_ctx, src, &script_origin).ToLocalChecked();

Expand All @@ -96,13 +98,43 @@ ValuePtr RunScript(ContextPtr ctx_ptr, const char* source, const char* origin) {
val->ctx_ptr = ctx;
val->ptr.Reset(iso, Persistent<Value>(iso, result));

return static_cast<ValuePtr>(val);
rtn.value = static_cast<ValuePtr>(val);
return rtn;
}

void ContextDispose(ContextPtr ptr) {
if (ptr == nullptr) {
return;
}
m_ctx* ctx = static_cast<m_ctx*>(ptr);
Isolate* iso = ctx->iso;
Locker locker(iso);
Isolate::Scope isolate_scope(iso);

ctx->ptr.Reset();
}

/********** Value **********/

const char* ValueToString(ValuePtr val_ptr) {
m_value* val = static_cast<m_value*>(val_ptr);
void ValueDispose(ValuePtr ptr) {
m_value* val = static_cast<m_value*>(ptr);
if (val == nullptr) {
return;
}
m_ctx* ctx = val->ctx_ptr;
if (ctx == nullptr) {
return;
}

Isolate* iso = ctx->iso;
Locker locker(iso);
Isolate::Scope isolate_scope(iso);

val->ptr.Reset();
}

const char* ValueToString(ValuePtr ptr) {
m_value* val = static_cast<m_value*>(ptr);
m_ctx* ctx = val->ctx_ptr;
Isolate* iso = ctx->iso;

Expand Down
11 changes: 9 additions & 2 deletions v8go.h
Expand Up @@ -8,15 +8,22 @@ typedef void* IsolatePtr;
typedef void* ContextPtr;
typedef void* ValuePtr;

typedef struct {
ValuePtr value;
const char* error;
} RtnValue;

extern void Init();
extern IsolatePtr NewIsolate();
extern void IsolateDispose(IsolatePtr ptr);
extern void TerminateExecution(IsolatePtr ptr);

extern ContextPtr NewContext(IsolatePtr prt);
extern ValuePtr RunScript(ContextPtr ctx_ptr, const char* source, const char* origin);
extern void ContextDispose(ContextPtr ptr);
extern RtnValue RunScript(ContextPtr ctx_ptr, const char* source, const char* origin);

const char* ValueToString(ValuePtr val_ptr);
extern void ValueDispose(ValuePtr ptr);
const char* ValueToString(ValuePtr ptr);

const char* Version();

Expand Down
30 changes: 0 additions & 30 deletions v8go_test.go
Expand Up @@ -7,8 +7,6 @@ import (
"rogchap.com/v8go"
)

var iso = v8go.NewIsolate()

func TestVersion(t *testing.T) {
t.Parallel()
rgx := regexp.MustCompile(`^\d+\.\d+\.\d+\.\d+-v8go$`)
Expand All @@ -17,31 +15,3 @@ func TestVersion(t *testing.T) {
t.Errorf("version string is in the incorrect format: %s", v)
}
}

func TestRunScriptStringer(t *testing.T) {
t.Parallel()
ctx := v8go.NewContext(iso)
var tests = [...]struct {
name string
source string
out string
}{
{"Addition", "2 + 2", "4"},
{"Multiplication", "13 * 2", "26"},
{"String", `"string"`, "string"},
{"Object", `let obj = {}; obj`, "[object Object]"},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
result, _ := ctx.RunScript(tt.source)
str := result.String()
if str != tt.out {
t.Errorf("unespected result: expected %q, got %q", tt.out, str)
}
})
}

}
7 changes: 7 additions & 0 deletions value.go
Expand Up @@ -2,6 +2,7 @@ package v8go

// #import "v8go.h"
import "C"
import "runtime"

type Value struct {
ptr C.ValuePtr
Expand All @@ -10,3 +11,9 @@ type Value struct {
func (v *Value) String() string {
return C.GoString(C.ValueToString(v.ptr))
}

func (v *Value) finalizer() {
C.ValueDispose(v.ptr)
v.ptr = nil
runtime.SetFinalizer(v, nil)
}

0 comments on commit 2e9d13a

Please sign in to comment.