Hare API reference

wren+x86_64 +linux

wren: embeddable scripting language

The wren module embeds the Wren scripting language in your Hare program and offers bindings for interacting with the Wren compiler and virtual machine. The user of this module is encouraged to refer to the upstream documentation for the general syntax and usage of Wren, especially the portions on embedding:

https://wren.io

The Hare module differs somewhat from the upstream C API. To create a VM, use new, providing a configuration which will likely derive from minimal_config or stdio_config, depending on your use-case. You can interpret programs with interpret, or call methods with call.

https://wren.io/embedding/calling-wren-from-c.html

The user is required to ensure that the API stack has the required number of slots for the operation they wish to perform. See:

https://wren.io/embedding/slots-and-handles.html#the-slot-array

Setting slots:

https://wren.io/embedding/slots-and-handles.html#writing-slots

Reading from slots:

https://wren.io/embedding/slots-and-handles.html#reading-slots

Working with variables:

https://wren.io/embedding/slots-and-handles.html#looking-up-variables

Working with lists:

https://wren.io/embedding/slots-and-handles.html#working-with-lists

Working with maps:

Working with handles:

https://wren.io/embedding/slots-and-handles.html#handles

Foreign methods are implemented by configuring a bind_foreign_method_fn in your VM config.

https://wren.io/embedding/calling-c-from-wren.html

Foreign classes are implemented by configuring a bind_foreign_class_fn in your VM config. The following functions assist with working with foreign objects on the API stack:

https://wren.io/embedding/storing-c-data.html

Submodules

  • api: async runtime and standard library for Wren

Index

Types

type bind_foreign_class_fn;
type bind_foreign_method_fn;
type config;
type error_fn;
type error_type;
type finalizer_fn;
type foreign_class_methods;
type foreign_method_fn;
type handle;
type load_module_fn;
type resolve_module_fn;
type slot_type;
type write_fn;

// Undocumented types:
type InterpretResult;
type vm;

Errors

type error;

Constants

def WREN_VERSION_MAJOR = 0;
def WREN_VERSION_MINOR = 4;
def WREN_VERSION_PATCH = 0;
def WREN_VERSION_STRING = "0.4.0";

Globals

let minimal_config;
let stdio_config;

Functions

fn abort_fiber(vm: *vm, reason: str, slot: int = 0) void;
fn call(vm: *vm, method: handle) (void | error);
@symbol("wrenCollectGarbage") fn collect_garbage(vm: *vm) void;
@symbol("wrenFreeVM") fn destroy(vm: *vm) void;
@symbol("wrenEnsureSlots") fn ensure_slots(vm: *vm, slots: int) void;
@symbol("wrenGetSlotBool") fn get_bool(vm: *vm, slot: int) bool;
fn get_bytes(vm: *vm, slot: int) []u8;
@symbol("wrenGetSlotDouble") fn get_f64(vm: *vm, slot: int) f64;
@symbol("wrenGetSlotForeign") fn get_foreign(vm: *vm, slot: int) *opaque;
@symbol("wrenGetSlotHandle") fn get_handle(vm: *vm, slot: int) handle;
@symbol("wrenGetSlotCount") fn get_slot_count(vm: *vm) int;
@symbol("wrenGetSlotType") fn get_slot_type(vm: *vm, slot: int) slot_type;
fn get_string(vm: *vm, slot: int) (const str | utf8::invalid);
fn get_variable(vm: *vm, module: str, name: str, slot: int = 0) void;
@symbol("wrenGetVersionNumber") fn get_version() int;
fn getuser(vm: *vm) nullable *opaque;
fn has_module(vm: *vm, module: str) bool;
fn has_variable(vm: *vm, module: str, name: str) bool;
fn interpret(vm: *vm, module: str, source: str) (void | error);
@symbol("wrenGetListElement") fn list_get(vm: *vm, list_slot: int, index: int, element_slot: int) void;
@symbol("wrenGetListCount") fn list_get_count(vm: *vm, slot: int) int;
@symbol("wrenInsertInList") fn list_insert(vm: *vm, list_slot: int, index: int, element_slot: int) void;
@symbol("wrenSetListElement") fn list_set(vm: *vm, list_slot: int, index: int, element_slot: int) void;
@symbol("wrenGetMapValue") fn map_get(vm: *vm, map_slot: int, key_slot: int, value_slot: int) void;
@symbol("wrenGetMapCount") fn map_get_count(vm: *vm, slot: int) int;
@symbol("wrenRemoveMapValue") fn map_remove(vm: nullable *vm, map_slot: int, key_slot: int, removed_value_slot: int) void;
@symbol("wrenSetMapValue") fn map_set(vm: nullable *vm, map_slot: int, key_slot: int, value_slot: int) void;
fn new(conf: *config) *vm;
fn new_call_handle(vm: *vm, signature: str) handle;
@symbol("wrenSetSlotNewForeign") fn new_foreign(vm: *vm, slot: int, classSlot: int, bytes: size) *opaque;
@symbol("wrenSetSlotNewList") fn new_list(vm: *vm, slot: int) void;
@symbol("wrenSetSlotNewMap") fn new_map(vm: *vm, slot: int) void;
@symbol("wrenReleaseHandle") fn release(vm: *vm, handle: handle) void;
fn set(vm: *vm, slot: int, value: (bool | f64 | []u8 | str | handle)) void;
@symbol("wrenSetSlotBool") fn set_bool(vm: *vm, slot: int, value: bool) void;
fn set_bytes(vm: *vm, slot: int, bytes: []u8) void;
@symbol("wrenSetSlotDouble") fn set_f64(vm: *vm, slot: int, value: f64) void;
@symbol("wrenSetSlotHandle") fn set_handle(vm: *vm, slot: int, handle: handle) void;
@symbol("wrenSetSlotNull") fn set_null(vm: *vm, slot: int) void;
fn set_string(vm: *vm, slot: int, string: str) void;
fn setuser(vm: *vm, user: nullable *opaque) void;
fn slot_type_str(t: slot_type) str;
fn strerror(err: error) str;

Types

type bind_foreign_class_fn[permalink]

type bind_foreign_class_fn = fn(vm: *vm, module: str, class_name: str) foreign_class_methods;

Returns a pair of pointers to the foreign methods used to allocate and finalize the data for instances of "class_name" in resolved "module".

type bind_foreign_method_fn[permalink]

type bind_foreign_method_fn = fn(vm: *vm, module: str, class_name: str, is_static: bool, signature: str) nullable *foreign_method_fn;

Returns a pointer to a foreign method on "class_name" in "module" with "signature".

type config[permalink]

type config = struct {
	// The callback Wren uses to resolve a module name.
	//
	// Some host applications may wish to support "relative" imports, where
	// the meaning of an import string depends on the module that contains
	// it. To support that without baking any policy into Wren itself, the
	// VM gives the host a chance to resolve an import string.
	//
	// Before an import is loaded, it calls this, passing in the name of the
	// module that contains the import and the import string. The host app
	// can look at both of those and produce a new "canonical" string that
	// uniquely identifies the module. This string is then used as the name
	// of the module going forward. It is what is passed to
	// [[load_module_fn]], how duplicate imports of the same module are
	// detected, and how the module is reported in stack traces.
	//
	// If you leave this function null, then the original import string is
	// treated as the resolved string.
	//
	// If an import cannot be resolved by the embedder, it should return
	// null and Wren will report that as a runtime error.
	//
	// Wren will take ownership of the string you return and free it for
	// you, so it should be allocated using the same allocation function you
	// provide above.
	resolve_module: nullable *resolve_module_fn,
	// The callback Wren uses to load a module.
	//
	// Since Wren does not talk directly to the file system, it relies on
	// the embedder to physically locate and read the source code for a
	// module. The first time an import appears, Wren will call this and
	// pass in the name of the module being imported. The method will return
	// a result, which contains the source code for that module. Memory for
	// the source is owned by the host application, and can be freed using
	// the on_complete callback.
	//
	// This will only be called once for any given module name. Wren caches
	// the result internally so subsequent imports of the same module will
	// use the previous source and not call this.
	//
	// If a module with the given name could not be found by the embedder,
	// it should return null and Wren will report that as a runtime error.
	load_module: nullable *load_module_fn,
	// The callback Wren uses to find a foreign method and bind it to a
	// class.
	//
	// When a foreign method is declared in a class, this will be called
	// with the foreign method's module, class, and signature when the class
	// body is executed. It should return a pointer to the foreign function
	// that will be bound to that method.
	//
	// If the foreign function could not be found, this should return null
	// and Wren will report it as runtime error.
	bind_foreign_method: nullable *bind_foreign_method_fn,
	// The callback Wren uses to find a foreign class and get its foreign
	// methods.
	//
	// When a foreign class is declared, this will be called with the
	// class's module and name when the class body is executed. It should
	// return the foreign functions uses to allocate and (optionally)
	// finalize the bytes stored in the foreign object when an instance is
	// created.
	bind_foreign_class: nullable *bind_foreign_class_fn,
	// The callback Wren uses to display text when `System.print()` or the
	// other related functions are called.
	//
	// If this is null, Wren discards any printed text.
	write: nullable *write_fn,
	// The callback Wren uses to report errors.
	//
	// When an error occurs, this will be called with the module name, line
	// number, and an error message. If this is null, Wren doesn't report
	// any errors.
	error: nullable *error_fn,
	// The number of bytes Wren will allocate before triggering the first
	// garbage collection.
	//
	// If zero, defaults to 10MB.
	initial_heap_size: size,
	// After a collection occurs, the threshold for the next collection is
	// determined based on the number of bytes remaining in use. This allows
	// Wren to shrink its memory usage automatically after reclaiming a
	// large amount of memory.
	//
	// This can be used to ensure that the heap does not get too small,
	// which can in turn lead to a large number of collections afterwards as
	// the heap grows back to a usable size.
	//
	// If zero, defaults to 1MB.
	min_heap_size: size,
	// Wren will resize the heap automatically as the number of bytes
	// remaining in use after a collection changes. This number determines
	// the amount of additional memory Wren will use after a collection, as
	// a percentage of the current heap size.
	//
	// For example, say that this is 50. After a garbage collection, when
	// there are 400 bytes of memory still in use, the next collection will
	// be triggered after a total of 600 bytes are allocated (including the
	// 400 already in use.)
	//
	// Setting this to a smaller number wastes less memory, but triggers
	// more frequent garbage collections.
	//
	// If zero, defaults to 50.
	heap_growth_pct: int,
	// User data associated with the VM
	user: nullable *opaque,
};

Wren virtual machine configuration. See minimal_config and stdio_config for recommended defaults.

type error_fn[permalink]

type error_fn = fn(vm: *vm, etype: error_type, module: str, line: int, message: str) void;

The callback Wren uses to report errors.

When an error occurs, this will be called with the module name, line number, and an error message.

type error_type[permalink]

type error_type = enum uint {
	COMPILE, // A syntax or resolution error detected at compile time.
	RUNTIME, // The error message for a runtime error.
	STACK_TRACE, // One entry of a runtime error's stack trace.
};

Type of error used in error_fn.

type finalizer_fn[permalink]

type finalizer_fn = fn(data: nullable *opaque) void;

A finalizer function for freeing resources owned by an instance of a foreign class. Unlike most foreign methods, finalizers do not have access to the VM and should not interact with it since it's in the middle of a garbage collection.

type foreign_class_methods[permalink]

type foreign_class_methods = struct {
	// The callback invoked when the foreign object is created.
	//
	// During execution of this callback, the user must call [[new_foreign]]
	// exactly once.
	allocate: nullable *foreign_method_fn,
	// The callback invoked when the garbage collector is about to collect a
	// foreign object's memory.
	//
	// This may be null if the foreign class does not need to finalize.
	finalize: nullable *finalizer_fn,
};

Return value of bind_foreign_class_fn.

type foreign_method_fn[permalink]

type foreign_method_fn = fn(vm: *vm) void;

A function callable from Wren code, but implemented in Hare.

type handle[permalink]

type handle = nullable *opaque;

An opaque reference to a persistent object.

type load_module_fn[permalink]

type load_module_fn = fn(vm: *vm, name: str) (str | errors::noentry);

Loads and returns the source code for the module "name". The return value should be heap-allocated and will be freed by wren:: after the module is loaded.

type resolve_module_fn[permalink]

type resolve_module_fn = fn(vm: *vm, importer: str, name: str) str;

Gives the host a chance to canonicalize the imported module name, potentially taking into account the (previously resolved) name of the module that contains the import. Typically, this is used to implement relative imports.

type slot_type[permalink]

type slot_type = enum uint {
	BOOL,
	NUM,
	FOREIGN,
	LIST,
	MAP,
	NULL,
	STRING,
	UNKNOWN, // The object is of a type that isn't accessible by the C API.
};

The type of an object stored in a slot.

This is not necessarily the object's class, but instead its low level representation type.

type write_fn[permalink]

type write_fn = fn(vm: *vm, data: []u8) void;

The callback Wren uses to display text when `System.print()` or the other related functions are called.

type InterpretResult[permalink]

Show undocumented member
type InterpretResult = enum uint {
	SUCCESS,
	COMPILE_ERROR,
	RUNTIME_ERROR,
};

type vm[permalink]

Show undocumented member
type vm = opaque;

Errors

type error[permalink]

type error = !InterpretResult;

An error returned from interpret or call.

Constants

def WREN_VERSION_MAJOR[permalink]

def WREN_VERSION_MAJOR = 0;

Wren language major version.

def WREN_VERSION_MINOR[permalink]

def WREN_VERSION_MINOR = 4;

Wren language minor version.

def WREN_VERSION_PATCH[permalink]

def WREN_VERSION_PATCH = 0;

Wren language patch version.

def WREN_VERSION_STRING[permalink]

def WREN_VERSION_STRING = "0.4.0";

Wren language version.

Globals

let minimal_config[permalink]

let minimal_config;

Minimal default configuration for Wren with no callbacks implemented. You may use this as-is but note that it does not implement write_fn or error_fn. stdio_config provides implementations of these functions, or you may derive your own configuration from these defaults like so:

let config = *wren::minimal;
config.writefn = &write;
// ... other config changes if needed ...
wren::new(&config);

let stdio_config[permalink]

let stdio_config;

Configuration for Wren with a default implementation of write and error that uses stdout/stderr for user feedback. You may use it directly, or you can use it as the basis of a customized configuration:

let config = *wren::stdio;
// ... whatever config changes if needed ...
wren::new(&config);

Functions

fn abort_fiber[permalink]

fn abort_fiber(vm: *vm, reason: str, slot: int = 0) void;

Causes the current fiber to abort with a runtime error.

fn call[permalink]

fn call(vm: *vm, method: handle) (void | error);

Calls a method, using the receiver and arguments previously set up on the stack.

The method must have been created by a call to new_call_handle. The arguments to the method must be already on the stack. The receiver should be in slot 0 with the remaining arguments following it, in order. It is an error if the number of arguments provided does not match the method's signature.

After this returns, you can access the return value from slot 0 on the stack.

fn collect_garbage[permalink]

@symbol("wrenCollectGarbage") fn collect_garbage(vm: *vm) void;

Immediately run the garbage collector to free unused memory.

fn destroy[permalink]

@symbol("wrenFreeVM") fn destroy(vm: *vm) void;

Disposes of all resources is use by "vm".

fn ensure_slots[permalink]

@symbol("wrenEnsureSlots") fn ensure_slots(vm: *vm, slots: int) void;

Ensures that the foreign method stack has at least a minimum number of slots available for use, growing the stack if needed.

Does not shrink the stack if it has more than enough slots.

It is an error to call this from a finalizer.

fn get_bool[permalink]

@symbol("wrenGetSlotBool") fn get_bool(vm: *vm, slot: int) bool;

Reads a boolean value from a slot.

Raises an assertion if the slot does not contain a boolean value.

fn get_bytes[permalink]

fn get_bytes(vm: *vm, slot: int) []u8;

Reads a byte array from a slot. The return value is borrowed from the VM and may be garbage collected at the next VM entry.

Raises an assertion if this slot does not contain a string.

fn get_f64[permalink]

@symbol("wrenGetSlotDouble") fn get_f64(vm: *vm, slot: int) f64;

Reads a number from a slot.

Raises an assertion if the slot does not contain a number.

fn get_foreign[permalink]

@symbol("wrenGetSlotForeign") fn get_foreign(vm: *vm, slot: int) *opaque;

Reads a foreign object from a slot and returns a pointer to the foreign data stored with it.

It is an error to call this if the slot does not contain an instance of a foreign class.

fn get_handle[permalink]

@symbol("wrenGetSlotHandle") fn get_handle(vm: *vm, slot: int) handle;

Creates a handle for the value stored in a slot.

This will prevent the object that is referred to from being garbage collected until the handle is released by calling release.

fn get_slot_count[permalink]

@symbol("wrenGetSlotCount") fn get_slot_count(vm: *vm) int;

Returns the number of slots available to the current foreign method.

fn get_slot_type[permalink]

@symbol("wrenGetSlotType") fn get_slot_type(vm: *vm, slot: int) slot_type;

Gets the type of the object in a slot.

fn get_string[permalink]

fn get_string(vm: *vm, slot: int) (const str | utf8::invalid);

Reads a string from a slot. The return value is borrowed from the VM and may be garbage collected at the next VM entry.

It is an error to call this if the slot does not contain a string.

Hare strings are required to be valid UTF-8, but Wren strings are not. This function will return an error if the value is not valid UTF-8. To prevent this, see get_bytes.

fn get_variable[permalink]

fn get_variable(vm: *vm, module: str, name: str, slot: int = 0) void;

Looks up the top level variable with name in a resolved module and stores it in the given slot. Ensures that there are sufficient slots.

fn get_version[permalink]

@symbol("wrenGetVersionNumber") fn get_version() int;

Returns a monotonically increasing numeric representation of the version number. Use this if you want to do range checks over versions.

fn getuser[permalink]

fn getuser(vm: *vm) nullable *opaque;

Returns the user data pointer associated with this vm.

fn has_module[permalink]

fn has_module(vm: *vm, module: str) bool;

Returns true if a module has been imported/resolved before, false if not.

fn has_variable[permalink]

fn has_variable(vm: *vm, module: str, name: str) bool;

Looks up the top level variable with name in a resolved module, returning false if not found. The module must be imported at the time -- see has_module.

fn interpret[permalink]

fn interpret(vm: *vm, module: str, source: str) (void | error);

Runs "source", a string of Wren source code in a new fiber in "vm" in the context of resolved "module".

fn list_get[permalink]

@symbol("wrenGetListElement") fn list_get(vm: *vm, list_slot: int, index: int, element_slot: int) void;

Reads element at index from the list in "list_slot" and stores it in "element_slot".

fn list_get_count[permalink]

@symbol("wrenGetListCount") fn list_get_count(vm: *vm, slot: int) int;

Returns the number of elements in the list stored in a slot.

fn list_insert[permalink]

@symbol("wrenInsertInList") fn list_insert(vm: *vm, list_slot: int, index: int, element_slot: int) void;

Takes the value stored at "element_slot" and inserts it into the list stored at "list_slot" at "index".

As in Wren, negative indexes can be used to insert from the end. To append an element, use `-1` for the index.

fn list_set[permalink]

@symbol("wrenSetListElement") fn list_set(vm: *vm, list_slot: int, index: int, element_slot: int) void;

Sets the value stored at "index" in the list at "list_slot", to the value from "element_slot".

fn map_get[permalink]

@symbol("wrenGetMapValue") fn map_get(vm: *vm, map_slot: int, key_slot: int, value_slot: int) void;

Retrieves a value with the key in 'key_slot' from the map in 'map_slot' and stores it in 'value_slot'.

fn map_get_count[permalink]

@symbol("wrenGetMapCount") fn map_get_count(vm: *vm, slot: int) int;

Returns the number of entries in the map stored in 'slot'.

fn map_remove[permalink]

@symbol("wrenRemoveMapValue") fn map_remove(vm: nullable *vm, map_slot: int, key_slot: int, removed_value_slot: int) void;

Removes a value from the map in 'map_slot', with the key from 'key_slot', and place it in 'removed_value_slot'. If not found, 'removed_value_slot' is set to null, the same behaviour as the Wren Map API.

fn map_set[permalink]

@symbol("wrenSetMapValue") fn map_set(vm: nullable *vm, map_slot: int, key_slot: int, value_slot: int) void;

Takes the value stored at 'value_slot' and inserts it into the map stored at 'map_slot' with key 'key_slot'.

fn new[permalink]

fn new(conf: *config) *vm;

Initializes a new Wren virtual machine. The configuration object is borrowed for the lifetime of the virtual machine. Pass the return value to destroy after use.

fn new_call_handle[permalink]

fn new_call_handle(vm: *vm, signature: str) handle;

Creates a handle that can be used to invoke a method with a given signature using a receiver and arguments that are set up on the stack.

This handle can be used repeatedly to directly invoke that method from C code using call.

When you are done with this handle, it must be released using release.

fn new_foreign[permalink]

@symbol("wrenSetSlotNewForeign") fn new_foreign(vm: *vm, slot: int, classSlot: int, bytes: size) *opaque;

Creates a new instance of the foreign class stored in 'class_slot' with a given 'bytes' of raw storage and places the resulting object in 'slot'.

This does not invoke the foreign class's constructor on the new instance. If you need that to happen, call the constructor from Wren, which will then call the allocator foreign method. In there, call this to create the object and then the constructor will be invoked when the allocator returns.

Returns a pointer to the foreign object's data.

fn new_list[permalink]

@symbol("wrenSetSlotNewList") fn new_list(vm: *vm, slot: int) void;

Stores a new empty list in the specified slot.

fn new_map[permalink]

@symbol("wrenSetSlotNewMap") fn new_map(vm: *vm, slot: int) void;

Stores a new empty map in 'slot'.

fn release[permalink]

@symbol("wrenReleaseHandle") fn release(vm: *vm, handle: handle) void;

Releases the reference stored in a handle. After calling this, the handle can no longer be used.

fn set[permalink]

fn set(vm: *vm, slot: int, value: (bool | f64 | []u8 | str | handle)) void;

Convenience function that sets the value of a slot. Calls ensure_slots for you.

fn set_bool[permalink]

@symbol("wrenSetSlotBool") fn set_bool(vm: *vm, slot: int, value: bool) void;

Stores a boolean value in a slot.

fn set_bytes[permalink]

fn set_bytes(vm: *vm, slot: int, bytes: []u8) void;

Stores a slice of bytes in a slot.

The underlying byte array is copied to the Wren heap.

fn set_f64[permalink]

@symbol("wrenSetSlotDouble") fn set_f64(vm: *vm, slot: int, value: f64) void;

Stores a numeric value in a slot.

fn set_handle[permalink]

@symbol("wrenSetSlotHandle") fn set_handle(vm: *vm, slot: int, handle: handle) void;

Stores the value captured by a handle in a slot.

Does not release the handle.

fn set_null[permalink]

@symbol("wrenSetSlotNull") fn set_null(vm: *vm, slot: int) void;

Stores null in a slot.

fn set_string[permalink]

fn set_string(vm: *vm, slot: int, string: str) void;

Stores a string in a slot.

The underlying data is copied to the Wren heap.

fn setuser[permalink]

fn setuser(vm: *vm, user: nullable *opaque) void;

Sets the user data pointer associated with this vm.

fn slot_type_str[permalink]

fn slot_type_str(t: slot_type) str;

Converts an slot_type to a string.

fn strerror[permalink]

fn strerror(err: error) str;

Provides a human-readable representation of an error.