aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go')
-rw-r--r--vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go356
1 files changed, 356 insertions, 0 deletions
diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go
new file mode 100644
index 000000000..f0806fcae
--- /dev/null
+++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duktape.go
@@ -0,0 +1,356 @@
+package duktape
+
+/*
+#cgo !windows CFLAGS: -std=c99 -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
+#cgo windows CFLAGS: -O3 -Wall -fomit-frame-pointer -fstrict-aliasing
+#cgo linux LDFLAGS: -lm
+#cgo freebsd LDFLAGS: -lm
+
+#include "duktape.h"
+#include "duk_logging.h"
+#include "duk_print_alert.h"
+#include "duk_module_duktape.h"
+#include "duk_console.h"
+extern duk_ret_t goFunctionCall(duk_context *ctx);
+extern void goFinalizeCall(duk_context *ctx);
+*/
+import "C"
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "sync"
+ "unsafe"
+)
+
+var reFuncName = regexp.MustCompile("^[a-z_][a-z0-9_]*([A-Z_][a-z0-9_]*)*$")
+
+const (
+ goFunctionPtrProp = "\xff" + "goFunctionPtrProp"
+ goContextPtrProp = "\xff" + "goContextPtrProp"
+)
+
+type Context struct {
+ *context
+}
+
+// transmute replaces the value from Context with the value of pointer
+func (c *Context) transmute(p unsafe.Pointer) {
+ *c = *(*Context)(p)
+}
+
+// this is a pojo containing only the values of the Context
+type context struct {
+ sync.Mutex
+ duk_context *C.duk_context
+ fnIndex *functionIndex
+ timerIndex *timerIndex
+}
+
+// New returns plain initialized duktape context object
+// See: http://duktape.org/api.html#duk_create_heap_default
+func New() *Context {
+ d := &Context{
+ &context{
+ duk_context: C.duk_create_heap(nil, nil, nil, nil, nil),
+ fnIndex: newFunctionIndex(),
+ timerIndex: &timerIndex{},
+ },
+ }
+
+ ctx := d.duk_context
+ C.duk_logging_init(ctx, 0)
+ C.duk_print_alert_init(ctx, 0)
+ C.duk_module_duktape_init(ctx)
+ C.duk_console_init(ctx, 0)
+
+ return d
+}
+
+// Flags is a set of flags for controlling the behaviour of duktape.
+type Flags struct {
+ Logging uint
+ PrintAlert uint
+ Console uint
+}
+
+// FlagConsoleProxyWrapper is a Console flag.
+// Use a proxy wrapper to make undefined methods (console.foo()) no-ops.
+const FlagConsoleProxyWrapper = 1 << 0
+
+// FlagConsoleFlush is a Console flag.
+// Flush output after every call.
+const FlagConsoleFlush = 1 << 1
+
+// NewWithFlags returns plain initialized duktape context object
+// You can control the behaviour of duktape by setting flags.
+// See: http://duktape.org/api.html#duk_create_heap_default
+func NewWithFlags(flags *Flags) *Context {
+ d := &Context{
+ &context{
+ duk_context: C.duk_create_heap(nil, nil, nil, nil, nil),
+ fnIndex: newFunctionIndex(),
+ timerIndex: &timerIndex{},
+ },
+ }
+
+ ctx := d.duk_context
+ C.duk_logging_init(ctx, C.duk_uint_t(flags.Logging))
+ C.duk_print_alert_init(ctx, C.duk_uint_t(flags.PrintAlert))
+ C.duk_module_duktape_init(ctx)
+ C.duk_console_init(ctx, C.duk_uint_t(flags.Console))
+
+ return d
+}
+
+func contextFromPointer(ctx *C.duk_context) *Context {
+ return &Context{&context{duk_context: ctx}}
+}
+
+// PushGlobalGoFunction push the given function into duktape global object
+// Returns non-negative index (relative to stack bottom) of the pushed function
+// also returns error if the function name is invalid
+func (d *Context) PushGlobalGoFunction(name string, fn func(*Context) int) (int, error) {
+ if !reFuncName.MatchString(name) {
+ return -1, errors.New("Malformed function name '" + name + "'")
+ }
+
+ d.PushGlobalObject()
+ idx := d.PushGoFunction(fn)
+ d.PutPropString(-2, name)
+ d.Pop()
+
+ return idx, nil
+}
+
+// PushGoFunction push the given function into duktape stack, returns non-negative
+// index (relative to stack bottom) of the pushed function
+func (d *Context) PushGoFunction(fn func(*Context) int) int {
+ funPtr := d.fnIndex.add(fn)
+ ctxPtr := contexts.add(d)
+
+ idx := d.PushCFunction((*[0]byte)(C.goFunctionCall), C.DUK_VARARGS)
+ d.PushCFunction((*[0]byte)(C.goFinalizeCall), 1)
+ d.PushPointer(funPtr)
+ d.PutPropString(-2, goFunctionPtrProp)
+ d.PushPointer(ctxPtr)
+ d.PutPropString(-2, goContextPtrProp)
+ d.SetFinalizer(-2)
+
+ d.PushPointer(funPtr)
+ d.PutPropString(-2, goFunctionPtrProp)
+ d.PushPointer(ctxPtr)
+ d.PutPropString(-2, goContextPtrProp)
+
+ return idx
+}
+
+//export goFunctionCall
+func goFunctionCall(cCtx *C.duk_context) C.duk_ret_t {
+ d := contextFromPointer(cCtx)
+
+ funPtr, ctx := d.getFunctionPtrs()
+ d.transmute(unsafe.Pointer(ctx))
+
+ result := d.fnIndex.get(funPtr)(d)
+
+ return C.duk_ret_t(result)
+}
+
+//export goFinalizeCall
+func goFinalizeCall(cCtx *C.duk_context) {
+ d := contextFromPointer(cCtx)
+
+ funPtr, ctx := d.getFunctionPtrs()
+ d.transmute(unsafe.Pointer(ctx))
+
+ d.fnIndex.delete(funPtr)
+}
+
+func (d *Context) getFunctionPtrs() (unsafe.Pointer, *Context) {
+ d.PushCurrentFunction()
+ d.GetPropString(-1, goFunctionPtrProp)
+ funPtr := d.GetPointer(-1)
+
+ d.Pop()
+
+ d.GetPropString(-1, goContextPtrProp)
+ ctx := contexts.get(d.GetPointer(-1))
+ d.Pop2()
+ return funPtr, ctx
+}
+
+// Destroy destroy all the references to the functions and freed the pointers
+func (d *Context) Destroy() {
+ d.fnIndex.destroy()
+ contexts.delete(d)
+}
+
+type Error struct {
+ Type string
+ Message string
+ FileName string
+ LineNumber int
+ Stack string
+}
+
+func (e *Error) Error() string {
+ return fmt.Sprintf("%s: %s", e.Type, e.Message)
+}
+
+type Type int
+
+func (t Type) IsNone() bool { return t == TypeNone }
+func (t Type) IsUndefined() bool { return t == TypeUndefined }
+func (t Type) IsNull() bool { return t == TypeNull }
+func (t Type) IsBool() bool { return t == TypeBoolean }
+func (t Type) IsNumber() bool { return t == TypeNumber }
+func (t Type) IsString() bool { return t == TypeString }
+func (t Type) IsObject() bool { return t == TypeObject }
+func (t Type) IsBuffer() bool { return t == TypeBuffer }
+func (t Type) IsPointer() bool { return t == TypePointer }
+func (t Type) IsLightFunc() bool { return t == TypeLightFunc }
+
+func (t Type) String() string {
+ switch t {
+ case TypeNone:
+ return "None"
+ case TypeUndefined:
+ return "Undefined"
+ case TypeNull:
+ return "Null"
+ case TypeBoolean:
+ return "Boolean"
+ case TypeNumber:
+ return "Number"
+ case TypeString:
+ return "String"
+ case TypeObject:
+ return "Object"
+ case TypeBuffer:
+ return "Buffer"
+ case TypePointer:
+ return "Pointer"
+ case TypeLightFunc:
+ return "LightFunc"
+ default:
+ return "Unknown"
+ }
+}
+
+type functionIndex struct {
+ functions map[unsafe.Pointer]func(*Context) int
+ sync.RWMutex
+}
+
+type timerIndex struct {
+ c float64
+ sync.Mutex
+}
+
+func (t *timerIndex) get() float64 {
+ t.Lock()
+ defer t.Unlock()
+ t.c++
+ return t.c
+}
+
+func newFunctionIndex() *functionIndex {
+ return &functionIndex{
+ functions: make(map[unsafe.Pointer]func(*Context) int, 0),
+ }
+}
+
+func (i *functionIndex) add(fn func(*Context) int) unsafe.Pointer {
+ ptr := C.malloc(1)
+
+ i.Lock()
+ i.functions[ptr] = fn
+ i.Unlock()
+
+ return ptr
+}
+
+func (i *functionIndex) get(ptr unsafe.Pointer) func(*Context) int {
+ i.RLock()
+ fn := i.functions[ptr]
+ i.RUnlock()
+
+ return fn
+}
+
+func (i *functionIndex) delete(ptr unsafe.Pointer) {
+ i.Lock()
+ delete(i.functions, ptr)
+ i.Unlock()
+
+ C.free(ptr)
+}
+
+func (i *functionIndex) destroy() {
+ i.Lock()
+
+ for ptr, _ := range i.functions {
+ delete(i.functions, ptr)
+ C.free(ptr)
+ }
+ i.Unlock()
+}
+
+type ctxIndex struct {
+ sync.RWMutex
+ ctxs map[unsafe.Pointer]*Context
+}
+
+func (ci *ctxIndex) add(ctx *Context) unsafe.Pointer {
+
+ ci.RLock()
+ for ptr, ctxPtr := range ci.ctxs {
+ if ctxPtr == ctx {
+ ci.RUnlock()
+ return ptr
+ }
+ }
+ ci.RUnlock()
+
+ ci.Lock()
+ for ptr, ctxPtr := range ci.ctxs {
+ if ctxPtr == ctx {
+ ci.Unlock()
+ return ptr
+ }
+ }
+ ptr := C.malloc(1)
+ ci.ctxs[ptr] = ctx
+ ci.Unlock()
+
+ return ptr
+}
+
+func (ci *ctxIndex) get(ptr unsafe.Pointer) *Context {
+ ci.RLock()
+ ctx := ci.ctxs[ptr]
+ ci.RUnlock()
+ return ctx
+}
+
+func (ci *ctxIndex) delete(ctx *Context) {
+ ci.Lock()
+ for ptr, ctxPtr := range ci.ctxs {
+ if ctxPtr == ctx {
+ delete(ci.ctxs, ptr)
+ C.free(ptr)
+ ci.Unlock()
+ return
+ }
+ }
+ panic(fmt.Sprintf("context (%p) doesn't exist", ctx))
+}
+
+var contexts *ctxIndex
+
+func init() {
+ contexts = &ctxIndex{
+ ctxs: make(map[unsafe.Pointer]*Context),
+ }
+}