interp

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Overview

Package interp is the heart of gojs: a tree-walking evaluator for the AST produced by github.com/iceisfun/gojs/parser, together with the JavaScript value model, the intrinsic prototypes (the "realm"), the capability providers, and the host-facing embedding API.

An Interpreter runs script on a single logical thread with an event loop. Host code drives it through the embedding API — Enqueue, QueueMicrotask, ResolvePromise, RejectPromise, and RunLoop — which is how concurrent Go work hands results back without ever running JavaScript on two goroutines at once. Capabilities (printing, time, timers, module loading) are supplied by providers and are absent by default, and execution can be bounded with Limits and a context deadline.

Most embedders do not import this package directly; the root gojs package re-exports the common surface. Import interp when you need lower-level access such as building custom host functions, providers, or values.

Package interp implements a tree-walking interpreter for the JavaScript AST produced by the parser. It is the runtime core of gojs — the analogue of a bytecode VM, executing ast nodes directly.

Values

JavaScript values are modeled by the Value interface. The primitive kinds (undefined, null, boolean, number, string, bigint, symbol) are small immutable Go types; objects (including arrays and functions) are represented by *Object.

Execution and cancellation

All evaluation threads a context.Context so that a host embedding gojs can cancel a running script and shut the interpreter down cleanly, including any goroutines started for timers (setTimeout/setInterval). See Interpreter and its Close method.

Capabilities

Access to host facilities (console output, wall-clock time, timers) is gated behind provider interfaces, mirroring the golua design. Without a provider, the corresponding globals are absent or inert, keeping the default sandbox closed.

ECMA-262 Reference: §6 (values), §7 (abstract operations).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BriefValue

func BriefValue(v Value) string

BriefValue renders a value for host-facing display (e.g. printing an uncaught exception). It does not run user toString methods; for full formatting use an Interpreter's ToStringV.

func IsNull

func IsNull(v Value) bool

IsNull reports whether v is null.

func IsNullish

func IsNullish(v Value) bool

IsNullish reports whether v is null or undefined.

func IsUndefined

func IsUndefined(v Value) bool

IsUndefined reports whether v is undefined.

func NumberToString

func NumberToString(f float64) string

NumberToString implements Number::toString in base 10 (§7.1.12.1), producing the shortest round-trippable representation and JavaScript's spellings for special values.

func ToBoolean

func ToBoolean(v Value) bool

ToBoolean implements the abstract ToBoolean conversion (§7.1.2).

func ToInt32

func ToInt32(f float64) int32

ToInt32 implements the ToInt32 abstraction (§7.1.6) used by bitwise operators.

func ToInteger

func ToInteger(f float64) float64

ToInteger truncates a number toward zero, mapping NaN to 0 (§7.1.5).

func ToNumber

func ToNumber(v Value) float64

ToNumber implements the abstract ToNumber conversion (§7.1.4) for primitives. Object operands must first be reduced with ToPrimitive by the caller (the interpreter does this at operator sites, where a ctx is available).

func ToUint32

func ToUint32(f float64) uint32

ToUint32 implements the ToUint32 abstraction (§7.1.7).

Types

type AgentCluster

type AgentCluster struct {
	// contains filtered or unexported fields
}

An "agent cluster" (§9.7) is a set of agents — here, gojs Interpreters running on separate goroutines — that can share memory through a SharedArrayBuffer and coordinate through Atomics.wait/notify. Each agent has its own heap and runs its own event loop; the ONLY state they share is a SharedArrayBuffer's backing bytes and the Atomics waiter registry.

AgentCluster carries exactly that shared, engine-level state:

  • waiters: one waiter registry for the whole cluster, so an Atomics.notify in one agent wakes an Atomics.wait/waitAsync parked in another. Because a waiterKey is keyed by the shared *arrayBufferData (whose pointer every agent holds identically for the same SAB) plus the element index, a single shared registry Just Works across agents.
  • atomicsMu: a big lock serialising Atomics read-modify-write on shared memory so a cross-agent RMW (add, compareExchange, exchange, ...) is indivisible. It is taken only for shared buffers in a cluster, so a single-agent VM pays nothing.

Host-level agent plumbing (the $262.agent report queue, broadcast, and start/receiveBroadcast rendezvous) is deliberately NOT here: that is embedder policy, built on top of this engine primitive by whoever installs the host object (see the Test262 runner's installAgentHost).

func NewAgentCluster

func NewAgentCluster() *AgentCluster

NewAgentCluster creates an empty cluster. Attach it to each participating Interpreter with WithAgentCluster; interpreters sharing one AgentCluster form one agent cluster.

type BigInt

type BigInt struct {
	Int *big.Int
}

BigInt is an arbitrary-precision integer primitive. It wraps a math/big.Int.

func NewBigInt

func NewBigInt(v int64) *BigInt

NewBigInt returns a BigInt with the given int64 value.

func (*BigInt) Typeof

func (*BigInt) Typeof() string

Typeof returns "bigint".

type Boolean

type Boolean bool

Boolean is a JavaScript boolean.

func (Boolean) Typeof

func (Boolean) Typeof() string

type CallFn

type CallFn func(ctx context.Context, this Value, args []Value) (Value, error)

CallFn is the signature shared by native (Go) and script (JS) callables. this is the receiver; args are the actual arguments. Native functions may return a Go error, which the interpreter converts into a thrown JavaScript value; a *Throw error carries an explicit JS value.

type DefaultNetProvider

type DefaultNetProvider struct {
	// Dialer is the underlying dialer; the zero value is a plain net.Dialer.
	Dialer net.Dialer
}

DefaultNetProvider is a pass-through NetProvider backed by net.Dialer — the "just enable the wall" default. Wrap or replace its DialContext to enforce a policy (allowlist, custom resolver, proxy, deny).

func NewDefaultNetProvider

func NewDefaultNetProvider() *DefaultNetProvider

NewDefaultNetProvider returns a pass-through NetProvider that dials normally.

func (*DefaultNetProvider) DialContext

func (p *DefaultNetProvider) DialContext(ctx context.Context, network, addr string) (net.Conn, error)

DialContext dials through the underlying net.Dialer.

type DefaultOsProvider

type DefaultOsProvider struct {
	// contains filtered or unexported fields
}

DefaultOsProvider grants ordinary host OS access, optionally filtering which environment variables are visible.

func NewDefaultOsProvider

func NewDefaultOsProvider() *DefaultOsProvider

NewDefaultOsProvider returns an OsProvider backed by the real OS, with the full environment visible.

func NewFilteredOsProvider

func NewFilteredOsProvider(allow func(name string) bool) *DefaultOsProvider

NewFilteredOsProvider is like NewDefaultOsProvider but only exposes the environment variables for which allow(name) is true; all others are invisible (Getenv reports not-present and they are omitted from Environ). Everything else — cwd, exit, platform, arch, pid — behaves as the default.

func (*DefaultOsProvider) Arch

func (*DefaultOsProvider) Arch() string

Arch maps runtime.GOARCH to Node's architecture names.

func (*DefaultOsProvider) Cwd

Cwd returns the current working directory.

func (*DefaultOsProvider) Environ

func (p *DefaultOsProvider) Environ(_ context.Context) map[string]string

Environ returns every visible environment variable.

func (*DefaultOsProvider) Exit

func (*DefaultOsProvider) Exit(_ context.Context, code int)

Exit terminates the program via os.Exit.

func (*DefaultOsProvider) Getenv

func (p *DefaultOsProvider) Getenv(_ context.Context, name string) (string, bool)

Getenv reports the value of name, subject to the environment filter.

func (*DefaultOsProvider) Pid

func (*DefaultOsProvider) Pid() int

Pid returns the process id.

func (*DefaultOsProvider) Platform

func (*DefaultOsProvider) Platform() string

Platform maps runtime.GOOS to Node's platform names.

type DefaultPrintProvider

type DefaultPrintProvider struct{}

DefaultPrintProvider writes normal output to stdout and warnings to stderr.

func NewDefaultPrintProvider

func NewDefaultPrintProvider() *DefaultPrintProvider

NewDefaultPrintProvider returns a PrintProvider backed by os.Stdout/os.Stderr.

func (*DefaultPrintProvider) Print

func (*DefaultPrintProvider) Print(_ context.Context, msg string)

Print writes msg and a newline to stdout.

func (*DefaultPrintProvider) Warn

Warn writes msg and a newline to stderr.

type DefaultTimeProvider

type DefaultTimeProvider struct {
	// contains filtered or unexported fields
}

DefaultTimeProvider reads the host clock via the time package.

func NewDefaultTimeProvider

func NewDefaultTimeProvider() *DefaultTimeProvider

NewDefaultTimeProvider returns a TimeProvider backed by the host clock.

func (*DefaultTimeProvider) Monotonic

Monotonic returns milliseconds elapsed since the provider was created.

func (*DefaultTimeProvider) Now

Now returns the current host time.

type DefaultTimerProvider

type DefaultTimerProvider struct{}

DefaultTimerProvider schedules callbacks with time.AfterFunc.

func NewDefaultTimerProvider

func NewDefaultTimerProvider() *DefaultTimerProvider

NewDefaultTimerProvider returns a TimerProvider backed by time.AfterFunc.

func (*DefaultTimerProvider) AfterFunc

func (*DefaultTimerProvider) AfterFunc(_ context.Context, delay time.Duration, fn func()) func()

AfterFunc schedules fn using a runtime timer.

type DirModuleProvider

type DirModuleProvider struct {
	// contains filtered or unexported fields
}

DirModuleProvider serves modules from a directory on the real filesystem, confined to that root (a specifier cannot escape it via ".."). Use it for the CLI or trusted local development; prefer a custom provider or MapModuleProvider for untrusted embeddings.

func NewDirModuleProvider

func NewDirModuleProvider(dir string) *DirModuleProvider

NewDirModuleProvider returns a provider rooted at dir.

func (*DirModuleProvider) Load

func (p *DirModuleProvider) Load(_ context.Context, id string) (string, error)

Load reads the module file under the root.

func (*DirModuleProvider) Resolve

func (p *DirModuleProvider) Resolve(_ context.Context, specifier, referrer string) (string, error)

Resolve joins the specifier against the referrer directory (for relative specifiers) or the root, appending ".js" if needed, and verifies the result stays within the root.

type Environment

type Environment struct {
	// contains filtered or unexported fields
}

Environment is a lexical scope: a set of variable bindings plus a link to the enclosing scope. Environments form a chain from the innermost block out to the global environment.

Binding kinds:

  • var / function declarations are hoisted to the nearest function (or global) scope; these use mutable, pre-initialized bindings.
  • let / const are block-scoped and start uninitialized, giving the Temporal Dead Zone: reading before initialization is a ReferenceError.

func NewEnvironment

func NewEnvironment(parent *Environment, fnScope bool) *Environment

NewEnvironment creates a child environment of parent. If fnScope is true, the environment acts as a var/function hoisting target.

type EvalInfo

type EvalInfo struct {
	Kind    EvalKind     // which entry point compiled this source
	Source  string       // the exact source text handed to the parser
	Program *ast.Program // the parsed AST, or nil when Err is non-nil
	Err     error        // non-nil when the source failed to parse
}

EvalInfo describes one dynamic compilation delivered to a WithDumpEval observer.

type EvalKind

type EvalKind string

EvalKind identifies which dynamic-code entry point compiled a source string.

const (
	EvalIndirect EvalKind = "eval"        // an indirect eval(str)
	EvalDirect   EvalKind = "eval:direct" // a direct eval(str)
	EvalFunction EvalKind = "Function"    // Function(...) / new Function(...) / fn.constructor(...)
)

type EvalObserver

type EvalObserver func(EvalInfo)

EvalObserver receives every dynamic compilation (eval / Function) on the VM goroutine, before the compiled code runs — a lens for unwinding obfuscated, self-generating payloads one stage at a time.

type HostFunc

type HostFunc func(args []Value) (Value, error)

HostFunc is the ergonomic signature for a Go function exposed to JavaScript. It receives the call arguments and returns a result value or an error; a returned error is thrown into the script (wrap a Value with NewThrow to throw a specific JS value, or return an ordinary error for a generic Error).

type Interpreter

type Interpreter struct {
	// contains filtered or unexported fields
}

Interpreter is a single JavaScript runtime instance: a global object and environment, the set of intrinsic prototypes (the "realm"), the capability providers, and the execution context used for cancellation.

An Interpreter is not safe for concurrent use by multiple goroutines running scripts; however, timer callbacks scheduled via a TimerProvider are run on the interpreter's own event loop, serialized with script execution.

func New

func New(opts ...Option) *Interpreter

New creates an Interpreter with the standard global environment installed.

func (*Interpreter) ArrayBufferBytes

func (i *Interpreter) ArrayBufferBytes(v Value) ([]byte, bool)

ArrayBufferBytes returns the live backing bytes of an ArrayBuffer. Mutating the returned slice mutates the buffer in place. It returns (nil, false) when v is not an ArrayBuffer or has been detached.

func (*Interpreter) Call

func (i *Interpreter) Call(fn Value, this Value, args ...Value) (Value, error)

Call invokes a callable JavaScript value from Go with the given receiver and arguments, returning its result. It is the counterpart to exposing a Go function: use it to drive script logic from the host.

func (*Interpreter) Close

func (i *Interpreter) Close() error

Close cancels the interpreter's context, stops the timer event loop, and waits for any in-flight timer goroutines to finish. It is safe to call multiple times.

func (*Interpreter) Context

func (i *Interpreter) Context() context.Context

Context returns the interpreter's execution context.

func (*Interpreter) DetachArrayBuffer

func (i *Interpreter) DetachArrayBuffer(v Value) bool

DetachArrayBuffer detaches an ArrayBuffer (as the spec's DetachArrayBuffer operation does), freeing its data block and rendering every view over it out-of-bounds. It reports whether v was an attachable ArrayBuffer. This backs host-driven transfer scenarios and the Test262 $262.detachArrayBuffer hook.

func (*Interpreter) Enqueue

func (i *Interpreter) Enqueue(fn func() error)

Enqueue schedules fn to run as a macrotask on the interpreter's event loop. It is safe to call from any goroutine. fn runs on the VM goroutine, so it may freely read and mutate interpreter state. A non-nil error returned by fn aborts the event loop and surfaces from RunProgram/RunString.

Enqueue also registers the continuation as pending work, so a running event loop will not exit before fn has had a chance to run — this keeps the process alive while an outstanding host operation is in flight (like a pending timer).

func (*Interpreter) FormatError

func (i *Interpreter) FormatError(v Value) string

FormatError renders v as a rich, developer-facing stack trace: a header, the full call stack (source-mapped), and a code frame pointing at the throw site. It is colorized with ANSI unless WithErrorColor(false) was set. For a non-error value it falls back to a brief rendering.

func (*Interpreter) FromGo

func (i *Interpreter) FromGo(x any) Value

FromGo converts an idiomatic Go value to a JavaScript value:

nil                       -> null
bool                      -> boolean
int kinds / float kinds   -> number
string                    -> string
[]any / []T               -> array
map[string]any / map[string]T -> object
Value                     -> returned unchanged

Unsupported types convert to undefined.

func (*Interpreter) GetGlobal

func (i *Interpreter) GetGlobal(name string) Value

GetGlobal reads a global binding, returning undefined when absent. It checks the global lexical environment first (where script-level function/var/let/ const/class declarations live) and then the global object (host-installed globals and built-ins), using the interpreter's context for any accessor invocation.

func (*Interpreter) Global

func (i *Interpreter) Global() *Object

Global returns the global object.

func (*Interpreter) NetProvider

func (i *Interpreter) NetProvider() NetProvider

NetProvider returns the configured outbound-dial provider, or nil. Networking host packages consult it when building their default client/dialer.

func (*Interpreter) NewArray

func (i *Interpreter) NewArray(elems ...Value) *Object

NewArray is the exported constructor used by embedders and other packages.

func (*Interpreter) NewArrayBuffer

func (i *Interpreter) NewArrayBuffer(b []byte) *Object

NewArrayBuffer returns a fresh ArrayBuffer that owns a copy of b. The returned object is a fully-formed %ArrayBuffer% instance usable from scripts (e.g. as the backing store for a DataView or TypedArray).

func (*Interpreter) NewChildRealm

func (i *Interpreter) NewChildRealm() *Interpreter

NewChildRealm creates a second, fully independent realm (a fresh Interpreter with its own global object and complete set of intrinsics) that nonetheless belongs to the same agent as i: it shares i's GlobalSymbolRegistry (so Symbol.for is consistent across realms), inherits i's cancellation context, clock/timer providers, module provider, and bytecode setting, and is closed automatically when i is closed. Objects flow between the two realms directly as ordinary values (no wrapping) — each retains the [[Prototype]] and, for built-ins, the [[Realm]] of the realm that created it. This backs multi-realm host hooks such as Test262's $262.createRealm.

func (*Interpreter) NewError

func (i *Interpreter) NewError(name, message string) *Object

NewError creates an Error-family object (name is "Error", "TypeError", …).

func (*Interpreter) NewFunction

func (i *Interpreter) NewFunction(name string, fn HostFunc) *Object

NewFunction wraps a Go function as a callable JavaScript value with the given name. The wrapper adapts the ergonomic HostFunc signature; errors it returns are surfaced as thrown exceptions in the script.

func (*Interpreter) NewFunctionRaw

func (i *Interpreter) NewFunctionRaw(name string, length int, fn CallFn) *Object

NewFunctionRaw wraps a Go function using the full native signature, giving access to the call context and `this` receiver. Prefer [NewFunction] unless you need those.

func (*Interpreter) NewPlainObject

func (i *Interpreter) NewPlainObject() *Object

NewPlainObject creates an empty JavaScript object with Object.prototype.

func (*Interpreter) NewPromiseCapability

func (i *Interpreter) NewPromiseCapability() *PromiseCapability

NewPromiseCapability creates a pending promise and its settlement functions. It must be called on the VM goroutine (e.g. from inside a native function), but the returned Resolve/Reject may be called from any goroutine.

func (*Interpreter) NewSharedArrayBufferFromBacking

func (i *Interpreter) NewSharedArrayBufferFromBacking(b SharedBacking) Value

NewSharedArrayBufferFromBacking wraps an existing shared backing in a fresh SharedArrayBuffer object in i's realm — same bytes, new wrapper object. Used to deliver a broadcast SAB into a receiving agent.

func (*Interpreter) NewUint8Array

func (i *Interpreter) NewUint8Array(b []byte) *Object

NewUint8Array returns a fresh Uint8Array viewing a fresh ArrayBuffer that owns a copy of b. It is the convenient way to hand binary data to a script.

func (*Interpreter) OsProvider

func (i *Interpreter) OsProvider() OsProvider

OsProvider returns the configured OS-facilities provider, or nil.

func (*Interpreter) Pin

func (i *Interpreter) Pin() (release func())

Pin registers a unit of outstanding host work so the event loop keeps running even when both task queues are momentarily empty — the same mechanism a pending timer uses. It returns a release function that removes the registration; call it exactly once when the work completes (extra calls are no-ops). Use it to hold the loop open for the lifetime of a long-lived host resource such as an open socket or event stream, so RunString/RunLoop does not return while the resource can still deliver events. Safe to call from any goroutine.

func (*Interpreter) PrintProvider

func (i *Interpreter) PrintProvider() PrintProvider

PrintProvider returns the configured console-output sink, or nil. It lets host packages (e.g. host/process's process.stdout) route their output through the same capability as console.

func (*Interpreter) QueueMicrotask

func (i *Interpreter) QueueMicrotask(fn func() error)

QueueMicrotask schedules fn to run as a microtask: after the current task and before the next macrotask. Promise reactions use this. Safe to call from any goroutine; fn runs on the VM goroutine.

func (*Interpreter) QueueNextTick

func (i *Interpreter) QueueNextTick(fn func() error)

QueueNextTick schedules fn on the higher-priority "next tick" queue, which is drained ahead of the microtask (Promise) queue — the ordering Node's process.nextTick provides. Safe to call from any goroutine; fn runs on the VM goroutine.

func (*Interpreter) RejectPromise

func (i *Interpreter) RejectPromise(p *Object, reason Value)

RejectPromise settles a promise object as rejected, from any goroutine.

func (*Interpreter) ResolvePromise

func (i *Interpreter) ResolvePromise(p *Object, value Value)

ResolvePromise settles a promise object previously created by NewPromiseCapability's Promise (or any native promise), from any goroutine. It is a convenience for providers that pass the *Object around rather than the capability.

func (*Interpreter) RunLoop

func (i *Interpreter) RunLoop(_ context.Context) error

RunLoop drains the event loop until there is no pending work (no queued tasks and no outstanding timers/enqueued continuations). Embedders that drive the interpreter manually — rather than via RunString — call this after posting work. RunString already calls it.

func (*Interpreter) RunProgram

func (i *Interpreter) RunProgram(prog *ast.Program) (Value, error)

RunProgram executes an already-parsed program.

func (*Interpreter) RunString

func (i *Interpreter) RunString(sourceName, source string) (Value, error)

RunString parses and executes JavaScript source, returning the completion value of the program (the value of its last expression statement) after the event loop has drained. sourceName appears in error messages.

func (*Interpreter) SetGlobal

func (i *Interpreter) SetGlobal(name string, v Value)

SetGlobal defines a global binding visible to scripts (enumerable, like a user-declared global). Use it to install host objects and functions.

func (*Interpreter) SetLimits

func (i *Interpreter) SetLimits(l Limits)

SetLimits updates the resource limits at runtime.

func (*Interpreter) SetRandomSeed

func (i *Interpreter) SetRandomSeed(seed uint64)

SetRandomSeed reseeds the interpreter's Math.random generator.

func (*Interpreter) SourceMapper

func (i *Interpreter) SourceMapper() SourceMapper

SourceMapper returns the configured source mapper, or nil.

func (*Interpreter) TakeUnhandledRejections

func (i *Interpreter) TakeUnhandledRejections() []Value

TakeUnhandledRejections returns the reasons of every promise that rejected without ever having a handler attached, and clears the internal log. Call it after RunString/RunProgram (i.e. after the event loop has drained), when a promise that is still unhandled is genuinely unhandled. A standalone runner uses this to report unhandled rejections and exit non-zero, mirroring Node.

func (*Interpreter) TimeProvider

func (i *Interpreter) TimeProvider() TimeProvider

TimeProvider returns the configured clock, or nil.

func (*Interpreter) ToGo

func (i *Interpreter) ToGo(v Value) any

ToGo converts a JavaScript value to an idiomatic Go value:

undefined / null -> nil
boolean          -> bool
number           -> float64
string           -> string
array            -> []any
other object     -> map[string]any (own enumerable string keys)

Functions and symbols convert to nil. Cyclic objects are not followed past the first repeat (the repeat becomes nil).

func (*Interpreter) ToNumberV

func (i *Interpreter) ToNumberV(ctx context.Context, v Value) (float64, error)

ToNumberV converts a value to a number per §7.1.4, reducing objects via ToPrimitive with a number hint. BigInt operands throw (mixed arithmetic is handled at operator sites).

func (*Interpreter) ToObject

func (i *Interpreter) ToObject(ctx context.Context, v Value) (*Object, error)

ToObject boxes a primitive into its wrapper object, or throws a TypeError for null/undefined (§7.1.18).

func (*Interpreter) ToPrimitive

func (i *Interpreter) ToPrimitive(ctx context.Context, v Value, hint string) (Value, error)

ToPrimitive converts v to a primitive following §7.1.1. hint is "number", "string", or "default". For non-objects, v is returned unchanged.

func (*Interpreter) ToPropertyKey

func (i *Interpreter) ToPropertyKey(ctx context.Context, v Value) (PropertyKey, error)

ToPropertyKey converts a value to a property key per §7.1.19: it first reduces the argument to a primitive with a string hint (so an object whose @@toPrimitive/toString yields a Symbol produces a symbol key), then passes a Symbol result through and coerces anything else to a string key.

func (*Interpreter) ToString

func (i *Interpreter) ToString(v Value) (string, error)

ToString converts any value to its JavaScript string form using the interpreter's context (running user toString/valueOf if needed).

func (*Interpreter) ToStringV

func (i *Interpreter) ToStringV(ctx context.Context, v Value) (string, error)

ToStringV converts a value to a Go string per §7.1.17, reducing objects via ToPrimitive with a string hint.

func (*Interpreter) TypedArrayBytes

func (i *Interpreter) TypedArrayBytes(v Value) ([]byte, bool)

TypedArrayBytes returns the live bytes viewed by any TypedArray or DataView, respecting its byteOffset and (current) byteLength. Mutating the returned slice mutates the underlying buffer. It returns (nil, false) when v is not a view or the view is out of bounds / detached.

type LimitError

type LimitError struct {
	// Kind identifies the limit that tripped ("steps").
	Kind string
	Msg  string
}

LimitError is returned when an execution resource limit is exceeded. Unlike a JavaScript exception it is NOT a thrown value: try/catch cannot catch it and it unwinds all the way out of RunString, guaranteeing the script stops.

func (*LimitError) Error

func (e *LimitError) Error() string

Error implements the error interface.

type Limits

type Limits struct {
	// MaxCallDepth bounds nested JavaScript function invocations. Exceeding it
	// raises a catchable RangeError ("Maximum call stack size exceeded"), just
	// as engines do for runaway recursion. It also keeps recursion well below
	// the point at which the Go goroutine stack would overflow.
	// Default: 6000. A negative value disables the limit (not recommended).
	MaxCallDepth int

	// MaxSteps bounds the number of evaluation steps (statements executed, loop
	// iterations, and function entries). Exceeding it aborts execution with an
	// uncatchable [*LimitError] — try/catch cannot swallow it — so a tight loop
	// like `while (true) {}` terminates deterministically even without a context
	// deadline. Default: 0, meaning unlimited (rely on the context deadline).
	MaxSteps int64
}

Limits bounds the resources a script may consume, so a host can run untrusted or buggy code without risking a crash or an unbounded loop. It mirrors the spirit of golua's vm.Limits, adapted to a tree-walking JavaScript engine.

A zero value for a field means "use the default"; set a field explicitly to override. Apply limits at construction with WithLimits or at runtime with Interpreter.SetLimits.

type MapModuleProvider

type MapModuleProvider struct {
	// Sources maps a module id to its JavaScript source.
	Sources map[string]string
}

MapModuleProvider serves module source from an in-memory map of id -> source. It is ideal for embeddings that already hold their scripts in memory (game data files, bundled assets) and never want to touch the filesystem. Specifier resolution is by exact key, with a leading "./" stripped.

func NewMapModuleProvider

func NewMapModuleProvider(sources map[string]string) *MapModuleProvider

NewMapModuleProvider returns a MapModuleProvider over the given sources.

func (*MapModuleProvider) Load

func (p *MapModuleProvider) Load(_ context.Context, id string) (string, error)

Load returns the stored source for id.

func (*MapModuleProvider) Resolve

func (p *MapModuleProvider) Resolve(_ context.Context, specifier, referrer string) (string, error)

Resolve normalizes a specifier to a map key: a relative specifier is joined against the referrer's directory; otherwise it is used as-is. A ".js" suffix is optional.

type ModuleProvider

type ModuleProvider interface {
	// Resolve maps a specifier (exactly as written in require(specifier)) to a
	// canonical module id, relative to the module doing the require. referrer is
	// the id of the requiring module, or "" for the top-level program. The
	// returned id is used as the module cache key and passed to Load.
	Resolve(ctx context.Context, specifier, referrer string) (string, error)

	// Load returns the source text of the module with the given canonical id.
	Load(ctx context.Context, id string) (string, error)
}

ModuleProvider is the capability interface a host implements to control how a script loads other scripts via require(specifier). It is the JavaScript analogue of golua's LuaCodeProvider: without a provider, require is not available at all, so a script cannot pull in code the host has not sanctioned.

A game embedding gojs, for example, implements ModuleProvider to serve module source out of its own asset/data files (a pak archive, a virtual filesystem, a database) — the engine never touches the real filesystem unless the provider does.

type NetProvider

type NetProvider interface {
	// DialContext connects to addr ("host:port") over network ("tcp", "tcp4", …).
	// The signature matches net.Dialer.DialContext so it drops into
	// http.Transport.DialContext and direct dialers alike.
	DialContext(ctx context.Context, network, addr string) (net.Conn, error)
}

NetProvider is the one choke point for outbound connections made by the networking host packages (host/fetch, host/sse, host/websocket). Because every dial — and therefore every DNS resolution — passes through DialContext, the host owns network egress: it can allowlist destinations, pin addresses, use a custom resolver or proxy, meter, log, or deny outright.

It is opt-in and orthogonal to the per-package client/dialer options: when a NetProvider is installed, a net package that builds its own default client routes dialing through it; a client the host supplied explicitly (e.g. fetch.WithClient) is left untouched, since that is the host taking direct control. Without a NetProvider, packages dial normally — but they are opt-in to begin with, so nothing reaches the network unless the host installed them.

type Null

type Null struct{}

Null is the type of the single `null` value.

func (Null) Typeof

func (Null) Typeof() string

type Number

type Number float64

Number is a JavaScript number (IEEE-754 double).

func (Number) Typeof

func (Number) Typeof() string

type Object

type Object struct {
	// contains filtered or unexported fields
}

Object is the representation of every non-primitive JavaScript value. The class field records the object's kind ("Object", "Array", "Function", "Error", ...). Arrays additionally use elems for dense element storage; functions use fn; boxed primitives and Date use primitive.

func NewObject

func NewObject(proto *Object) *Object

NewObject creates a bare object with the given prototype (which may be nil).

func (*Object) ArrayLen

func (o *Object) ArrayLen() int

ArrayLen returns the logical length of an array object: the dense backing length, extended by any sparse tail recorded in arrayLen.

func (*Object) Class

func (o *Object) Class() string

Class returns the internal class string.

func (*Object) DefineAccessor

func (o *Object) DefineAccessor(name string, get, set *Object, enumerable bool)

DefineAccessor installs a getter/setter accessor property.

func (*Object) Delete

func (o *Object) Delete(key PropertyKey) bool

Delete removes an own property, returning whether the object no longer has it.

func (*Object) Get

func (o *Object) Get(ctx context.Context, key PropertyKey) (Value, error)

Get returns the value of the property key on the object, walking the prototype chain and invoking a getter if the property is an accessor.

func (*Object) GetStr

func (o *Object) GetStr(ctx context.Context, name string) (Value, error)

GetStr is Get for a string key.

func (*Object) Has

func (o *Object) Has(key PropertyKey) bool

Has reports whether key exists anywhere on the prototype chain.

func (*Object) HasOwn

func (o *Object) HasOwn(key PropertyKey) bool

HasOwn reports whether key is an own property of o.

func (*Object) IsArray

func (o *Object) IsArray() bool

IsArray reports whether the object is an Array exotic object.

func (*Object) IsCallable

func (o *Object) IsCallable() bool

IsCallable reports whether the object can be called.

func (*Object) IsConstructor

func (o *Object) IsConstructor() bool

IsConstructor reports whether the object can be used with `new`.

func (*Object) OwnKeys

func (o *Object) OwnKeys() []string

OwnKeys returns the own enumerable and non-enumerable string keys in the order mandated by the spec: integer indices ascending, then other string keys in insertion order. Symbol keys are excluded.

func (*Object) Proto

func (o *Object) Proto() *Object

Proto returns the object's prototype (may be nil).

func (*Object) Set

func (o *Object) Set(ctx context.Context, key PropertyKey, v Value) error

Set assigns v to key, honoring inherited setters and non-writable data properties. In this (non-strict-by-default) implementation, writes that the spec would silently ignore are silently ignored.

func (*Object) SetData

func (o *Object) SetData(name string, v Value)

SetData defines (or overwrites) an enumerable, writable, configurable data property. It is the common path for populating objects from Go.

func (*Object) SetHidden

func (o *Object) SetHidden(name string, v Value)

SetHidden defines a non-enumerable data property (used for methods and internal wiring like "constructor").

func (*Object) SetProto

func (o *Object) SetProto(p *Object)

SetProto sets the object's prototype.

func (*Object) SetStr

func (o *Object) SetStr(ctx context.Context, name string, v Value) error

SetStr is Set for a string key.

func (*Object) Typeof

func (o *Object) Typeof() string

Typeof returns "function" for callable objects and "object" otherwise.

type Option

type Option func(*Interpreter)

Option configures an Interpreter at construction time.

func WithAgentCluster

func WithAgentCluster(c *AgentCluster) Option

WithAgentCluster attaches i to a shared agent cluster so its Atomics.wait / notify / waitAsync coordinate with the other agents in the cluster.

func WithBytecode

func WithBytecode() Option

WithBytecode enables the bytecode VM. The VM is on by default, so this option is now a no-op kept for backward compatibility; see WithTreeWalker to opt out.

func WithContext

func WithContext(ctx context.Context) Option

WithContext sets the parent context used for cancellation. When the context is cancelled, running scripts observe the cancellation at the next interruption check and timer goroutines are stopped.

func WithDumpEval

func WithDumpEval(obs EvalObserver) Option

WithDumpEval installs an observer called for every eval() and Function() compilation, handing it the source text and parsed AST. It is a debugging / reverse-engineering aid; it does not change execution.

func WithErrorColor

func WithErrorColor(on bool) Option

WithErrorColor enables (default) or disables ANSI color in the rich error rendering produced by FormatError. Disable it when output goes to a log or web sink rather than a terminal.

func WithLimits

func WithLimits(l Limits) Option

WithLimits sets the resource limits for the interpreter.

func WithModuleProvider

func WithModuleProvider(p ModuleProvider) Option

WithModuleProvider enables CommonJS-style require(specifier) backed by p.

func WithNetProvider

func WithNetProvider(p NetProvider) Option

WithNetProvider routes outbound dialing done by the networking host packages (host/fetch, host/sse, host/websocket) through p — the single egress wall (and a convenient test seam; point it at a loopback server). See NetProvider.

func WithOsProvider

func WithOsProvider(p OsProvider) Option

WithOsProvider grants access to host OS facilities (environment, cwd, exit, platform/arch/pid) — see OsProvider. Without one, those facilities are unavailable. It backs the `process` global installed by host/process.

func WithPrintProvider

func WithPrintProvider(p PrintProvider) Option

WithPrintProvider sets the provider that receives console output. Without one, console methods are inert (nothing is written).

func WithRegExpEngine

func WithRegExpEngine(e RegExpEngine) Option

WithRegExpEngine selects the RegExp backend. The default (RegExpCompat) is the ECMAScript-conformant jsregexp engine; RegExpRE2 opts into the faster, non-conformant RE2 engine. See RegExpEngine for the trade-offs.

func WithSecurity

func WithSecurity(s Security) Option

WithSecurity applies the given hardening options to the interpreter.

func WithSourceMapper

func WithSourceMapper(m SourceMapper) Option

WithSourceMapper installs a SourceMapper used to rewrite positions in error stacks back to their original source.

func WithTimeProvider

func WithTimeProvider(p TimeProvider) Option

WithTimeProvider sets the wall-clock provider backing Date.now and Date.

func WithTimerProvider

func WithTimerProvider(p TimerProvider) Option

WithTimerProvider enables setTimeout/setInterval/setImmediate backed by p.

func WithTreeWalker

func WithTreeWalker() Option

WithTreeWalker forces the tree-walking interpreter, disabling the bytecode VM that New enables by default. The two engines are behaviorally identical (the compiler falls back to the tree-walker for any construct it declines); use it as a differential reference or to sidestep a suspected VM regression.

type OsProvider

type OsProvider interface {
	// Getenv returns the value of the named environment variable and whether it
	// is visible. A filtered provider reports (", false) for hidden names.
	Getenv(ctx context.Context, name string) (string, bool)
	// Environ returns the full set of visible environment variables.
	Environ(ctx context.Context) map[string]string
	// Cwd returns the current working directory.
	Cwd(ctx context.Context) (string, error)
	// Exit terminates the program with the given status code. An embedder that
	// must not let a script kill the host should implement this to record the
	// code and cancel the VM's context instead of calling os.Exit.
	Exit(ctx context.Context, code int)
	// Platform is the host OS as Node names it ("linux", "darwin", "win32", …).
	Platform() string
	// Arch is the host architecture as Node names it ("x64", "arm64", …).
	Arch() string
	// Pid is the process id.
	Pid() int
}

OsProvider gates a script's access to the host operating system: the environment, the working directory, process termination, and host identity (platform / architecture / pid). Without one, none of these exist — a script cannot read an env var, learn what OS it is on, or terminate the process. This is the wall that keeps an embedded VM (a game server, a plugin host) from leaking or touching the host: install a provider to grant exactly what you intend, and route it wherever you like. Environment visibility is further narrowable with NewFilteredOsProvider.

type PrintProvider

type PrintProvider interface {
	// Print receives normal console output (console.log/info/debug). msg is the
	// fully formatted line without a trailing newline; the provider adds one if
	// desired.
	Print(ctx context.Context, msg string)
	// Warn receives diagnostic output (console.warn/error).
	Warn(ctx context.Context, msg string)
}

PrintProvider routes console output through a host-defined sink. All writes that a user script makes to stdout/stderr (console.log, console.error, and friends) pass through here, so an embedder can capture, redirect, or silence them. Without a provider, console methods produce no output.

type PrivateName

type PrivateName struct {
	// contains filtered or unexported fields
}

PrivateName is the unique identity of a private class element (#x). Each evaluation of a class body mints fresh PrivateNames for the names it declares, so the same textual name produced by two evaluations of the same class are distinct identities that fail each other's brand checks (ECMA-262 uses a PrivateName value for exactly this). desc is the "#name" text, kept only for diagnostics.

func (*PrivateName) String

func (p *PrivateName) String() string

String returns the textual private name (e.g. "#x").

type ProgramLoader

type ProgramLoader interface {
	LoadProgram(ctx context.Context, id string) (prog *ast.Program, source string, handled bool, err error)
}

ProgramLoader is an optional interface a ModuleProvider may also implement to supply an already-parsed program for a module id, bypassing the text Load + parse step. It lets a provider that holds a richer source representation — for example a TypeScript frontend that lowers straight to the gojs AST instead of emitting JavaScript text and re-parsing it — skip the round trip.

LoadProgram returns handled=false to defer to the normal Load path (the interpreter then loads and parses text as usual); this is how a provider opts out per module — for non-TypeScript files, unsupported constructs, or any case it would rather the text path handle. When handled is true, source is the module's original text, registered for diagnostics and code-frame rendering.

type PromiseCapability

type PromiseCapability struct {
	Promise *Object
	// contains filtered or unexported fields
}

PromiseCapability is a promise together with Go functions to settle it. Host providers create one, hand the promise to the script, and later — from any goroutine — call Resolve or Reject (which internally marshal the settlement onto the VM goroutine via the microtask queue).

func (*PromiseCapability) Reject

func (c *PromiseCapability) Reject(reason Value)

Reject settles the promise as rejected with reason. Safe from any goroutine.

func (*PromiseCapability) Resolve

func (c *PromiseCapability) Resolve(value Value)

Resolve settles the promise with value. Safe to call from any goroutine: the settlement is scheduled onto the VM event loop, preserving single-threaded access to interpreter state.

type Property

type Property struct {
	Value        Value
	Get          *Object
	Set          *Object
	Writable     bool
	Enumerable   bool
	Configurable bool
	Accessor     bool
}

Property is an own-property descriptor. A property is either a data property (Value + Writable) or an accessor property (Get/Set) when Accessor is true.

type PropertyKey

type PropertyKey struct {
	Str string
	Sym *Symbol
}

PropertyKey identifies an own property. Exactly one of Sym/Str is significant: when Sym is non-nil the key is a symbol, otherwise it is the string in Str.

func StrKey

func StrKey(s string) PropertyKey

StrKey returns a string property key.

func SymKey

func SymKey(s *Symbol) PropertyKey

SymKey returns a symbol property key.

func (PropertyKey) IsSymbol

func (k PropertyKey) IsSymbol() bool

IsSymbol reports whether the key is a symbol key.

type RegExpEngine

type RegExpEngine int

RegExpEngine selects which regular-expression backend the VM installs.

const (
	// RegExpCompat is the default: the pure-Go jsregexp engine, a full
	// ECMAScript implementation (backreferences, lookahead/lookbehind, named
	// groups, u/v Unicode modes) with a step budget that bounds catastrophic
	// backtracking. Correct, sandbox-safe, and the right choice for running real
	// or untrusted JavaScript.
	RegExpCompat RegExpEngine = iota

	// RegExpRE2 backs RegExp with Go's regexp package (RE2). It is faster and
	// linear-time, but it is NOT ECMAScript-conformant: patterns using
	// backreferences or lookaround fail to compile (SyntaxError), and capture,
	// flag, and Unicode semantics follow RE2 rather than the spec. Use it only
	// for performance-sensitive scripting over simple, trusted patterns where
	// full conformance is not required.
	RegExpRE2
)

type Security

type Security struct {
	// DisableProtoMutation blocks mutation of an object's prototype through the
	// __proto__ accessor and Object.setPrototypeOf / Reflect.setPrototypeOf.
	// Prototype pollution is a frequent sandbox-escape and gadget vector.
	DisableProtoMutation bool

	// DisableEval makes the global eval() throw instead of executing code from
	// a string. (gojs does not implement dynamic eval regardless; this makes
	// the refusal explicit and observable.)
	DisableEval bool

	// DisableFunctionCtor makes the Function constructor throw, preventing
	// construction of functions from strings (another dynamic-code path).
	DisableFunctionCtor bool

	// DisableWith rejects the `with` statement at parse/eval time. gojs does
	// not support `with` at all, so this is always effectively on; the flag is
	// retained for parity and forward compatibility.
	DisableWith bool

	// StrictModulesOnly forces every program to be evaluated in strict mode,
	// regardless of a "use strict" directive.
	StrictModulesOnly bool
}

Security collects opt-in hardening switches for an interpreter. They restrict language and runtime features that are common footguns or escape hatches in an embedded/sandboxed setting. All default to false (feature enabled); set a field to true to disable the corresponding capability.

This mirrors golua's capability-gating philosophy, but because JavaScript's dangerous surfaces are language features (not just host APIs), the knobs live in one struct applied at construction via WithSecurity.

type SharedBacking

type SharedBacking struct {
	// contains filtered or unexported fields
}

SharedBacking is an opaque handle to a SharedArrayBuffer's backing store. It lets an embedder hand the SAME bytes to another agent: extract it from a SAB value in one agent with SharedBackingOf, then rewrap it in another agent with NewSharedArrayBufferFromBacking. The wrapper objects differ per realm; the bytes are one block.

func SharedBackingOf

func SharedBackingOf(v Value) (SharedBacking, bool)

SharedBackingOf returns the shared backing of a SharedArrayBuffer value, or ok=false if v is not a SharedArrayBuffer.

type SourceMapper

type SourceMapper interface {
	MapPosition(source string, line, column int) (origSource string, origLine, origColumn int, ok bool)
	// SourceText returns the original source text for a mapped source name (used
	// to render code frames), or ok=false if unavailable.
	SourceText(origSource string) (string, bool)
}

SourceMapper translates a generated (transpiled) source position back to its original position, so error stacks can report original .ts line/column for code that was transpiled to JavaScript (see the ts package). line and column are 1-based; ok is false when the position is not mapped.

type String

type String string

String is a JavaScript string. gojs stores strings as Go UTF-8 for simplicity; APIs that are sensitive to UTF-16 code units approximate over runes. (A future revision may switch to a UTF-16 representation.)

func (String) Typeof

func (String) Typeof() string

type Symbol

type Symbol struct {
	Desc string // optional description, for debugging and Symbol.prototype.toString
	// HasDesc reports whether a description was supplied. It distinguishes
	// Symbol() (description undefined) from Symbol("") (empty-string
	// description), which Symbol.prototype.description must report differently.
	HasDesc bool
	// Registered marks a symbol produced by Symbol.for and held in the
	// GlobalSymbolRegistry. Registered symbols are excluded from CanBeHeldWeakly
	// (§7.3.11): they can never be reclaimed, so keying a WeakMap/WeakSet or
	// registering a WeakRef/FinalizationRegistry target with one is a TypeError.
	Registered bool
}

Symbol is a unique, immutable primitive used as a property key. Two symbols are equal only by pointer identity.

func (*Symbol) Typeof

func (*Symbol) Typeof() string

Typeof returns "symbol".

type Throw

type Throw struct {
	Value Value
}

Throw is a JavaScript exception. Value is the thrown value (commonly an Error object, but any value may be thrown).

func NewThrow

func NewThrow(v Value) *Throw

NewThrow wraps a value as a throwable error.

func (*Throw) Error

func (t *Throw) Error() string

Error implements the error interface with a short, host-facing message. The full JS value is available via Value.

type TimeProvider

type TimeProvider interface {
	// Now returns the current wall-clock time (backs Date.now and new Date()).
	Now(ctx context.Context) time.Time
	// Monotonic returns a monotonically increasing millisecond timestamp for
	// performance.now(); the zero point is arbitrary.
	Monotonic(ctx context.Context) float64
}

TimeProvider supplies the notion of "now" to Date and performance.now. Gating it lets an embedder present a fixed or virtual clock for deterministic tests.

type TimerProvider

type TimerProvider interface {
	// AfterFunc arranges for fn to be called once after delay. The returned
	// cancel function stops the timer if it has not yet fired. Implementations
	// should stop the timer when ctx is cancelled.
	AfterFunc(ctx context.Context, delay time.Duration, fn func()) (cancel func())
}

TimerProvider backs setTimeout/setInterval/setImmediate. It gates the ability of a script to schedule future work (and thereby to keep the process alive). The interpreter guarantees fn runs on its own event-loop goroutine, so implementations only need to arrange for fn to be invoked after the delay.

type Undefined

type Undefined struct{}

Undefined is the type of the single `undefined` value.

func (Undefined) Typeof

func (Undefined) Typeof() string

type Value

type Value interface {
	// Typeof returns the string that the JavaScript `typeof` operator yields
	// for this value ("undefined", "boolean", "number", "string", "bigint",
	// "symbol", "object", or "function").
	Typeof() string
}

Value is the interface implemented by every JavaScript runtime value.

var (
	Undef Value = Undefined{}
	Nul   Value = Null{}
	True  Value = Boolean(true)
	False Value = Boolean(false)
)

Singleton primitive values. Using package-level values avoids allocating a fresh boxed value for every undefined/null result.

func Bool

func Bool(b bool) Value

Bool returns the interned Boolean value for b.

func NewBorrowedString added in v0.2.0

func NewBorrowedString(b []byte) Value

NewBorrowedString wraps host bytes as a JavaScript string WITHOUT copying, via an unsafe borrow of b's backing array. It is the zero-copy path for a large buffer whose lifetime the host controls, but it is UNSAFE: the caller MUST NOT mutate or free b for as long as the returned string (or any string derived from it) is reachable from the VM, and b MUST be valid UTF-8. Because the engine never writes to a string, reads are always safe; the hazard is solely the host mutating the shared backing. When in doubt use NewReadOnlyString, which copies.

func NewReadOnlyString added in v0.2.0

func NewReadOnlyString(b []byte) Value

NewReadOnlyString wraps host bytes as a JavaScript string. It COPIES b, so the caller may reuse or mutate b freely afterward — the safe default for handing host data (an HTTP body, a file's contents, a Go→VM argument) to a script. The result is a metadata-bearing flat string. b must be valid UTF-8.

A []byte is mutable and its backing is not copy-on-write, so a zero-copy borrow of one is a "dangerous primitive": if the host later mutates b, an immutable JS string would observably change, and a borrowed string reaching a durable sink (a property key, a Map key, an object slot) would alias the mutable backing — Go maps store the string header, they do not copy its bytes. Copying here shuts that door. Use NewBorrowedString only when you can honor its lifetime contract.

func ThrownValue

func ThrownValue(err error) (Value, bool)

ThrownValue returns the JavaScript value carried by a *Throw error, or nil if err is not a thrown exception. Embedders use it to inspect uncaught errors.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL