Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

Overview

quickjs

MIT License go.dev reference Discord Chat

Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

These bindings are a WIP and do not match full parity with QuickJS' API, though expose just enough features to be usable. The version of QuickJS that these bindings bind to may be located here.

These bindings have been tested to cross-compile and run successfully on Linux, Windows, and Mac using gcc-7 and mingw32 without any addtional compiler or linker flags.

Usage

$ go get github.com/lithdew/quickjs

Guidelines

  1. Free quickjs.Runtime and quickjs.Context once you are done using them.
  2. Free quickjs.Value's returned by Eval() and EvalFile(). All other values do not need to be freed, as they get garbage-collected.
  3. You may access the stacktrace of an error returned by Eval() or EvalFile() by casting it to a *quickjs.Error.
  4. Make new copies of arguments should you want to return them in functions you created.
  5. Make sure to call runtime.LockOSThread() to ensure that QuickJS always operates in the exact same thread.

Example

The full example code below may be found by clicking here. Find more API examples here.

package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/lithdew/quickjs"
	"strings"
)

func check(err error) {
	if err != nil {
		var evalErr *quickjs.Error
		if errors.As(err, &evalErr) {
			fmt.Println(evalErr.Cause)
			fmt.Println(evalErr.Stack)
		}
		panic(err)
	}
}

func main() {
	runtime := quickjs.NewRuntime()
	defer runtime.Free()

	context := runtime.NewContext()
	defer context.Free()

	globals := context.Globals()

	// Test evaluating template strings.

	result, err := context.Eval("`Hello world! 2 ** 8 = ${2 ** 8}.`")
	check(err)
	defer result.Free()

	fmt.Println(result.String())
	fmt.Println()

	// Test evaluating numeric expressions.

	result, err = context.Eval(`1 + 2 * 100 - 3 + Math.sin(10)`)
	check(err)
	defer result.Free()

	fmt.Println(result.Int64())
	fmt.Println()

	// Test evaluating big integer expressions.

	result, err = context.Eval(`128n ** 16n`)
	check(err)
	defer result.Free()

	fmt.Println(result.BigInt())
	fmt.Println()

	// Test evaluating big decimal expressions.

	result, err = context.Eval(`128l ** 12l`)
	check(err)
	defer result.Free()

	fmt.Println(result.BigFloat())
	fmt.Println()

	// Test evaluating boolean expressions.

	result, err = context.Eval(`false && true`)
	check(err)
	defer result.Free()

	fmt.Println(result.Bool())
	fmt.Println()

	// Test setting and calling functions.

	A := func(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		fmt.Println("A got called!")
		return ctx.Null()
	}

	B := func(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
		fmt.Println("B got called!")
		return ctx.Null()
	}

	globals.Set("A", context.Function(A))
	globals.Set("B", context.Function(B))

	_, err = context.Eval(`for (let i = 0; i < 10; i++) { if (i % 2 === 0) A(); else B(); }`)
	check(err)

	fmt.Println()

	// Test setting global variables.

	_, err = context.Eval(`HELLO = "world"; TEST = false;`)
	check(err)

	names, err := globals.PropertyNames()
	check(err)

	fmt.Println("Globals:")
	for _, name := range names {
		val := globals.GetByAtom(name.Atom)
		defer val.Free()

		fmt.Printf("'%s': %s\n", name, val)
	}
	fmt.Println()

	// Test evaluating arbitrary expressions from flag arguments.

	flag.Parse()
	if flag.NArg() == 0 {
		return
	}

	result, err = context.Eval(strings.Join(flag.Args(), " "))
	check(err)
	defer result.Free()

	if result.IsObject() {
		names, err := result.PropertyNames()
		check(err)

		fmt.Println("Object:")
		for _, name := range names {
			val := result.GetByAtom(name.Atom)
			defer val.Free()

			fmt.Printf("'%s': %s\n", name, val)
		}
	} else {
		fmt.Println(result.String())
	}
}
$ go run examples/main.go '(() => ({hello: "world", test: 2 ** 3}))()'
Hello world! 2 ** 8 = 256.

197

5192296858534827628530496329220096

1.9342813113834066795e+25

false

A got called!
B got called!
A got called!
B got called!
A got called!
B got called!
A got called!
B got called!
A got called!
B got called!

Globals:
'Object': function Object() {
    [native code]
}
'Function': function Function() {
    [native code]
}
'Error': function Error() {
    [native code]
}
'EvalError': function EvalError() {
    [native code]
}
'RangeError': function RangeError() {
    [native code]
}
'ReferenceError': function ReferenceError() {
    [native code]
}
'SyntaxError': function SyntaxError() {
    [native code]
}
'TypeError': function TypeError() {
    [native code]
}
'URIError': function URIError() {
    [native code]
}
'InternalError': function InternalError() {
    [native code]
}
'AggregateError': function AggregateError() {
    [native code]
}
'Array': function Array() {
    [native code]
}
'parseInt': function parseInt() {
    [native code]
}
'parseFloat': function parseFloat() {
    [native code]
}
'isNaN': function isNaN() {
    [native code]
}
'isFinite': function isFinite() {
    [native code]
}
'decodeURI': function decodeURI() {
    [native code]
}
'decodeURIComponent': function decodeURIComponent() {
    [native code]
}
'encodeURI': function encodeURI() {
    [native code]
}
'encodeURIComponent': function encodeURIComponent() {
    [native code]
}
'escape': function escape() {
    [native code]
}
'unescape': function unescape() {
    [native code]
}
'Infinity': Infinity
'NaN': NaN
'undefined': undefined
'__date_clock': function __date_clock() {
    [native code]
}
'Number': function Number() {
    [native code]
}
'Boolean': function Boolean() {
    [native code]
}
'String': function String() {
    [native code]
}
'Math': [object Math]
'Reflect': [object Object]
'Symbol': function Symbol() {
    [native code]
}
'eval': function eval() {
    [native code]
}
'globalThis': [object Object]
'Date': function Date() {
    [native code]
}
'RegExp': function RegExp() {
    [native code]
}
'JSON': [object JSON]
'Proxy': function Proxy() {
    [native code]
}
'Map': function Map() {
    [native code]
}
'Set': function Set() {
    [native code]
}
'WeakMap': function WeakMap() {
    [native code]
}
'WeakSet': function WeakSet() {
    [native code]
}
'ArrayBuffer': function ArrayBuffer() {
    [native code]
}
'SharedArrayBuffer': function SharedArrayBuffer() {
    [native code]
}
'Uint8ClampedArray': function Uint8ClampedArray() {
    [native code]
}
'Int8Array': function Int8Array() {
    [native code]
}
'Uint8Array': function Uint8Array() {
    [native code]
}
'Int16Array': function Int16Array() {
    [native code]
}
'Uint16Array': function Uint16Array() {
    [native code]
}
'Int32Array': function Int32Array() {
    [native code]
}
'Uint32Array': function Uint32Array() {
    [native code]
}
'BigInt64Array': function BigInt64Array() {
    [native code]
}
'BigUint64Array': function BigUint64Array() {
    [native code]
}
'Float32Array': function Float32Array() {
    [native code]
}
'Float64Array': function Float64Array() {
    [native code]
}
'DataView': function DataView() {
    [native code]
}
'Atomics': [object Atomics]
'Promise': function Promise() {
    [native code]
}
'BigInt': function BigInt() {
    [native code]
}
'BigFloat': function BigFloat() {
    [native code]
}
'BigFloatEnv': function BigFloatEnv() {
    [native code]
}
'BigDecimal': function BigDecimal() {
    [native code]
}
'Operators': function Operators() {
    [native code]
}
'A': function() { return proxy.call(this, id, ...arguments); }
'B': function() { return proxy.call(this, id, ...arguments); }
'HELLO': world
'TEST': false

Object:
'hello': world
'test': 8

License

QuickJS is released under the MIT license.

QuickJS bindings are copyright Kenta Iwasaki, with code copyright Fabrice Bellard and Charlie Gordon.

Issues
  • Possible to use inside an http.Handler?

    Possible to use inside an http.Handler?

    Thanks for putting this package together! It works great out of the box without any additional installation scripts.

    I was wondering about Guideline 5.

    Make sure to call runtime.LockOSThread() to ensure that QuickJS always operates in the exact same thread.

    Does this make QuickJS unsuitable to run inside http.Handlers where you can have many goroutines servicing requests at the same time? The use-case in mind is server-side rendering.

    question 
    opened by matthewmueller 6
  • Freeing quickjs.Runtime after creating a new function causes a segmentation fault.

    Freeing quickjs.Runtime after creating a new function causes a segmentation fault.

    The suspicion is of possible misuse of JS_NewCFunctionData, which is used over JS_NewCFunction to provide an opaque pointer to proxy() in Go to dispatch Go functions in C.

    It may be that this is not the intended use of JS_NewCFunctionData, and that calling JS_FreeRuntime frees unintended memory as a result.

    func main() {
    	runtime := quickjs.NewRuntime()
    	defer runtime.Free()
    
    	ctx := runtime.NewContext()
    	defer ctx.Free()
    
    	globals := ctx.Globals()
    	defer globals.Free()
    
    	httpFunc := ctx.Function(func(ctx quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
    		if len(args) != 1 || !args[0].IsString() {
    			return ctx.ThrowTypeError("http(request: string)")
    		}
    
    		request := args[0]
    		fmt.Println(request.String())
    
    		return request
    	})
    	defer httpFunc.Free()
    
    	globals.Set("http", httpFunc)
    
    	result, err := ctx.Eval(`http('test')`)
    	check(err)
    	defer result.Free()
    
    	fmt.Println(result)
    }
    
    $ CGO_CFLAGS="-DDUMP_LEAKS" go run main.go
    # command-line-arguments
    /tmp/go-link-072279044/000024.o: In function `_cgo_26061493d47f_C2func_getaddrinfo':
    cgo_unix.cgo2.c:(.text+0x81): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    test
    test
    main: quickjs.c:5625: gc_decref_child: Assertion `p->ref_count > 0' failed.
    SIGABRT: abort
    PC=0x782978 m=0 sigcode=18446744073709551610
    
    goroutine 0 [idle]:
    runtime: unknown pc 0x782978
    stack: frame={sp:0x7ffd922906b8, fp:0x0} stack=[0x7ffd91a91ae8,0x7ffd92290b10)
    00007ffd922905b8:  000000000092db5c  0000000000000000 
    00007ffd922905c8:  0000000000798780  00000000fbad8000 
    00007ffd922905d8:  00000000022c1a00  00000000022c1a00 
    00007ffd922905e8:  00000000022c1a00  00000000022c1a00 
    00007ffd922905f8:  00000000022c1a4c  00000000022c1a64 
    00007ffd92290608:  00000000022c1a00  00000000022c1a64 
    00007ffd92290618:  0000000000000000  0000000000000000 
    00007ffd92290628:  0000000000000000  0000000000000000 
    00007ffd92290638:  0000000000000000  0000000092290660 
    00007ffd92290648:  0000000000688a26  00000000022c0000 
    00007ffd92290658:  0000000000000000  00007ffd92290690 
    00007ffd92290668:  0000000000688aae  ffffffffffffffff 
    00007ffd92290678:  0000000000000000  00000000022b70c8 
    00007ffd92290688:  00007f356e578000  00000000009b2420 
    00007ffd92290698:  000000000092d5c4  00000000000015f9 
    00007ffd922906a8:  000000000092db5c  0000000000000000 
    00007ffd922906b8: <0000000000782d0a  0000000000000020 
    00007ffd922906c8:  0000000000000000  0000000000000000 
    00007ffd922906d8:  0000000000000000  0000000000000000 
    00007ffd922906e8:  0000000000000000  0000000000000000 
    00007ffd922906f8:  0000000000000000  0000000000000000 
    00007ffd92290708:  0000000000000000  0000000000000000 
    00007ffd92290718:  0000000000000000  0000000000000000 
    00007ffd92290728:  0000000000000000  0000000000000000 
    00007ffd92290738:  0000000000000000  0000000000000004 
    00007ffd92290748:  00000000022b7ab0  00007ffd92290720 
    00007ffd92290758:  00000016022c9230  0000000000000000 
    00007ffd92290768:  00007f356e578000  00000000009b2420 
    00007ffd92290778:  000000000092d5c4  00000000000015f9 
    00007ffd92290788:  000000000092db5c  0000000000000000 
    00007ffd92290798:  00000000007a5377  00000000022c3bf0 
    00007ffd922907a8:  fffffffffffffff9  00000000009c9e9c 
    runtime: unknown pc 0x782978
    stack: frame={sp:0x7ffd922906b8, fp:0x0} stack=[0x7ffd91a91ae8,0x7ffd92290b10)
    00007ffd922905b8:  000000000092db5c  0000000000000000 
    00007ffd922905c8:  0000000000798780  00000000fbad8000 
    00007ffd922905d8:  00000000022c1a00  00000000022c1a00 
    00007ffd922905e8:  00000000022c1a00  00000000022c1a00 
    00007ffd922905f8:  00000000022c1a4c  00000000022c1a64 
    00007ffd92290608:  00000000022c1a00  00000000022c1a64 
    00007ffd92290618:  0000000000000000  0000000000000000 
    00007ffd92290628:  0000000000000000  0000000000000000 
    00007ffd92290638:  0000000000000000  0000000092290660 
    00007ffd92290648:  0000000000688a26  00000000022c0000 
    00007ffd92290658:  0000000000000000  00007ffd92290690 
    00007ffd92290668:  0000000000688aae  ffffffffffffffff 
    00007ffd92290678:  0000000000000000  00000000022b70c8 
    00007ffd92290688:  00007f356e578000  00000000009b2420 
    00007ffd92290698:  000000000092d5c4  00000000000015f9 
    00007ffd922906a8:  000000000092db5c  0000000000000000 
    00007ffd922906b8: <0000000000782d0a  0000000000000020 
    00007ffd922906c8:  0000000000000000  0000000000000000 
    00007ffd922906d8:  0000000000000000  0000000000000000 
    00007ffd922906e8:  0000000000000000  0000000000000000 
    00007ffd922906f8:  0000000000000000  0000000000000000 
    00007ffd92290708:  0000000000000000  0000000000000000 
    00007ffd92290718:  0000000000000000  0000000000000000 
    00007ffd92290728:  0000000000000000  0000000000000000 
    00007ffd92290738:  0000000000000000  0000000000000004 
    00007ffd92290748:  00000000022b7ab0  00007ffd92290720 
    00007ffd92290758:  00000016022c9230  0000000000000000 
    00007ffd92290768:  00007f356e578000  00000000009b2420 
    00007ffd92290778:  000000000092d5c4  00000000000015f9 
    00007ffd92290788:  000000000092db5c  0000000000000000 
    00007ffd92290798:  00000000007a5377  00000000022c3bf0 
    00007ffd922907a8:  fffffffffffffff9  00000000009c9e9c 
    
    goroutine 1 [syscall]:
    runtime.cgocall(0x6578e2, 0xc000059db0, 0x1f9)
            /snap/go/current/src/runtime/cgocall.go:133 +0x5b fp=0xc000059d80 sp=0xc000059d48 pc=0x403fab
    github.com/lithdew/quickjs._Cfunc_JS_FreeRuntime(0x22b7030)
            _cgo_gotypes.go:260 +0x41 fp=0xc000059db0 sp=0xc000059d80 pc=0x504551
    github.com/lithdew/quickjs.Runtime.Free.func1(0x22b7030)
            /home/kenta/lithdew/quickjs/quickjs.go:33 +0x4d fp=0xc000059de0 sp=0xc000059db0 pc=0x50691d
    github.com/lithdew/quickjs.Runtime.Free(0x22b7030)
            /home/kenta/lithdew/quickjs/quickjs.go:33 +0x2b fp=0xc000059df8 sp=0xc000059de0 pc=0x50556b
    main.main()
            /home/kenta/lithdew/ghost/main.go:109 +0x40e fp=0xc000059f88 sp=0xc000059df8 pc=0x656d2e
    runtime.main()
            /snap/go/current/src/runtime/proc.go:203 +0x1fa fp=0xc000059fe0 sp=0xc000059f88 pc=0x4359fa
    runtime.goexit()
            /snap/go/current/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000059fe8 sp=0xc000059fe0 pc=0x4620d1
    
    rax    0x0
    rbx    0x7f356e578000
    rcx    0x782978
    rdx    0x6
    rdi    0x6960
    rsi    0x6960
    rbp    0x9b2420
    rsp    0x7ffd922906b8
    r8     0x22c1a00
    r9     0x0
    r10    0x8
    r11    0x206
    r12    0x92d5c4
    r13    0x15f9
    r14    0x92db5c
    r15    0x0
    rip    0x782978
    rflags 0x206
    cs     0x33
    fs     0x0
    gs     0x0
    exit status 2
    
    func main() {
    	runtime := quickjs.NewRuntime()
    	defer runtime.Free()
    
    	ctx := runtime.NewContext()
    	defer ctx.Free()
    
    	globals := ctx.Globals()
    	defer globals.Free()
    
    	httpFunc := ctx.Function(func(ctx quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
    		if len(args) != 1 || !args[0].IsString() {
    			return ctx.ThrowTypeError("http(request: string)")
    		}
    
    		request := args[0]
    		fmt.Println(request.String())
    
    		return request
    	})
    	//defer httpFunc.Free()
    
    	globals.Set("http", httpFunc)
    
    	result, err := ctx.Eval(`http('test')`)
    	check(err)
    	//defer result.Free()
    
    	fmt.Println(result)
    }
    
    $ CGO_CFLAGS="-DDUMP_LEAKS" go run main.go
    # command-line-arguments
    /tmp/go-link-896294616/000024.o: In function `_cgo_26061493d47f_C2func_getaddrinfo':
    cgo_unix.cgo2.c:(.text+0x81): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    test
    test
    fatal error: unexpected signal during runtime execution
    [signal SIGSEGV: segmentation violation code=0x2 addr=0x1e4c030 pc=0x1e4c030]
    
    runtime stack:
    runtime.throw(0x8bd124, 0x2a)
            /snap/go/current/src/runtime/panic.go:1116 +0x72
    runtime.sigpanic()
            /snap/go/current/src/runtime/signal_unix.go:679 +0x46a
    
    goroutine 1 [syscall]:
    runtime.cgocall(0x6577e2, 0xc000059e08, 0x1f9)
            /snap/go/current/src/runtime/cgocall.go:133 +0x5b fp=0xc000059dd8 sp=0xc000059da0 pc=0x403fab
    github.com/lithdew/quickjs._Cfunc_JS_FreeRuntime(0x1e38010)
            _cgo_gotypes.go:260 +0x41 fp=0xc000059e08 sp=0xc000059dd8 pc=0x504551
    github.com/lithdew/quickjs.Runtime.Free.func1(0x1e38010)
            /home/kenta/lithdew/quickjs/quickjs.go:33 +0x4d fp=0xc000059e38 sp=0xc000059e08 pc=0x50691d
    github.com/lithdew/quickjs.Runtime.Free(0x1e38010)
            /home/kenta/lithdew/quickjs/quickjs.go:33 +0x2b fp=0xc000059e50 sp=0xc000059e38 pc=0x50556b
    main.main()
            /home/kenta/lithdew/ghost/main.go:109 +0x329 fp=0xc000059f88 sp=0xc000059e50 pc=0x656c49
    runtime.main()
            /snap/go/current/src/runtime/proc.go:203 +0x1fa fp=0xc000059fe0 sp=0xc000059f88 pc=0x4359fa
    runtime.goexit()
            /snap/go/current/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000059fe8 sp=0xc000059fe0 pc=0x4620d1
    exit status 2
    
    bug 
    opened by lithdew 2
  • "At code:1" error message

    1. platform: mac
    2. code
    func TestName(t *testing.T) {
    	const code = `
    var name = "test_hello";
    
    function main() {
    }
    
    main();
    `
    	runtime := quickjs.NewRuntime()
    
    	context := runtime.NewContext()
    	defer context.Free()
    
    	for {
    		val, err := context.Eval(code)
    		if err != nil {
    			fmt.Printf("%#v\n", err)
    			time.Sleep(time.Second)
    			continue
    		}
    
    		g:=context.Globals()
    		fmt.Println(g.Get("name"),val)
    		time.Sleep(time.Millisecond*10)
    		val.Free()
    	}
    }
    
    1. output
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    test_hello undefined
    
    opened by kooksee 1
Owner
Kenta Iwasaki
Theorist at heart; engineer at scale.
Kenta Iwasaki
Interpreter - The Official Interpreter for the Infant Lang written in Go

Infant Lang Interpreter Infant Lang Minimalistic Less Esoteric Programming Langu

Infant Lang 2 Jan 10, 2022
Small Clojure interpreter, linter and formatter.

Joker is a small Clojure interpreter, linter and formatter written in Go. Installation On macOS, the easiest way to install Joker is via Homebrew: bre

Roman Bataev 1.4k Jul 31, 2022
❄️ Elsa is a minimal, fast and secure runtime for JavaScript and TypeScript written in Go

Elsa Elsa is a minimal, fast and secure runtime for JavaScript and TypeScript written in Go, leveraging the power from QuickJS. Features URL based imp

Elsa 2.6k Jul 29, 2022
a dynamically typed, garbage collected, embeddable programming language built with Go

The agora programming language Agora is a dynamically typed, garbage collected, embeddable programming language. It is built with the Go programming l

Martin Angers 324 Jul 26, 2022
Sabre is highly customisable, embeddable LISP engine for Go. :computer:

Sabre DEPRECATED: This repository is deprecated in favour much better slurp project and will be archived/removed soon. Sabre is highly customizable, e

Shivaprasad Bhat 28 May 23, 2021
Interactive Go interpreter and debugger with REPL, Eval, generics and Lisp-like macros

gomacro - interactive Go interpreter and debugger with generics and macros gomacro is an almost complete Go interpreter, implemented in pure Go. It of

Massimiliano Ghilardi 1.9k Aug 1, 2022
⛳ A minimal programming language inspired by Ink, JavaScript, and Python.

⛳ Golfcart My blog post: Creating the Golfcart Programming Language Getting Started Scope Rules Usage Building and tests Contributions License Golfcar

Andrew Healey 26 Feb 23, 2022
A shell parser, formatter, and interpreter with bash support; includes shfmt

sh A shell parser, formatter, and interpreter. Supports POSIX Shell, Bash, and mksh. Requires Go 1.14 or later. Quick start To parse shell scripts, in

Daniel Martí 5k Aug 8, 2022
Monkey programming language project from 'Writing An Interpreter In Go'and 'Writing A Compiler In Go' Books

Monkey Monkey programming language ?? project from "Writing An Interpreter In Go

Amr Hesham 1 Dec 16, 2021
ECMAScript/JavaScript engine in pure Go

goja ECMAScript 5.1(+) implementation in Go. Goja is an implementation of ECMAScript 5.1 in pure Go with emphasis on standard compliance and performan

Dmitry Panov 3.1k Jul 29, 2022
v8 javascript engine binding for golang

Go-V8 V8 JavaScript engine bindings for Go. Features Thread safe Thorough and careful testing Boolean, Number, String, Object, Array, Regexp, Function

Hoping White 203 Aug 8, 2022
A Go API for the V8 javascript engine.

V8 Bindings for Go The v8 bindings allow a user to execute javascript from within a go executable. The bindings are tested to work with several recent

Augusto Roman 380 May 24, 2022
Execute JavaScript from Go

Execute JavaScript from Go Usage import "rogchap.com/v8go" Running a script ctx, _ := v8go.NewContext() // creates a new V8 context with a new Isolate

Roger Chapman 2.1k Aug 1, 2022
Scriptable interpreter written in golang

Anko Anko is a scriptable interpreter written in Go. (Picture licensed under CC BY-SA 3.0, photo by Ocdp) Usage Example - Embedded package main impor

mattn 1.3k Aug 1, 2022
A POSIX-compliant AWK interpreter written in Go

GoAWK: an AWK interpreter written in Go AWK is a fascinating text-processing language, and somehow after reading the delightfully-terse The AWK Progra

Ben Hoyt 1.6k Jul 31, 2022
A BASIC interpreter written in golang.

05 PRINT "Index" 10 PRINT "GOBASIC!" 20 PRINT "Limitations" Arrays Line Numbers IF Statement DATA / READ Statements Builtin Functions Types 30 PRINT "

Steve Kemp 280 Jul 14, 2022
Prolog interpreter in Go

golog Prolog interpreter in Go with aspirations to be ISO compatible. See the full package documentation for usage details. Install with go get github

Michael Hendricks 371 Jun 29, 2022
A simple virtual machine - compiler & interpreter - written in golang

go.vm Installation Build without Go Modules (Go before 1.11) Build with Go Modules (Go 1.11 or higher) Usage Opcodes Notes The compiler The interprete

Steve Kemp 235 Jul 29, 2022
Yaegi is Another Elegant Go Interpreter

Yaegi is Another Elegant Go Interpreter. It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go

Traefik Labs 4.7k Aug 8, 2022