wren

package module
v0.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 25, 2022 License: MIT Imports: 6 Imported by: 0

README

wren-go

Wren scripting language in pure Go

Go Reference GoReportCard Wren

wren-go is a port of the Wren scripting language to pure Go using WebAssembly and wagu. Thanks to wagu, wren-go needs almost no dependencies and does not use CGo, making it easier to target web and tinygo targets.

Wren-go also uses a modified version of wren similar to wren-bindings-for-go meant for embedding in non C projects. This means theres no need to preallocate foreign functions and the VM.Exit function is meant to stop the wren VM in the middle of execution.

Installation

go get github.com/crazyinfin8/wren-go

Usage

func main() {
	cfg := wren.Config{
		WriteFn: func(vm wren.VM, message string) { fmt.Print(message) },
	}

	vm := wren.NewVM(cfg)

	vm.Interpret("main", `System.print("Hello from wren!")`)
}

Building wren-go

To build, run:

cd path/to/github.com/crazyinfin8/wren-go
go generate

this runs build-wren.go which:

  1. first fetches wren (requires git)
  2. generates the wren amalgamation file
  3. downloads WASI-libc (it has been buggy to download and run wasi-libc in one go using this script so you may need to run this script twice)
  4. compiles the wren amalgamation with src/shim.c to a webassembly binary using wasi-libc
  5. installs wagu
  6. generates the IR for wagu
  7. finally generates Go source code into the internals folder.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var StdErr io.Writer

StdErr is where error messages from any context is printed to. This may contain debug information from the incorrect use of wren.

View Source
var StdOut io.Writer

StdOut is where output from any context is printed to.

Functions

This section is empty.

Types

type Config

type Config struct {
	// ResolveModuleFn allows the host to canonicalize the imported name beofre
	// it is passed to LoadModuleFn.
	//
	// It takes the name of the module doing the import and the target module to
	// import. It should return the new name to be passed to LoadModuleFn as
	// well as if the import is ok. If an import cannot be resolved, this
	// function should return false.
	ResolveModuleFn func(vm VM, importer, name string) (newName string, ok bool)

	// LoadModuleFn load a modules source code. It takes the name of the module
	// to import and returns the wren source code as well as whether the module
	// was successfully loaded.
	LoadModuleFn func(vm VM, name string) (src string, ok bool)

	// BindForeignMethodFn binds a foreign function to a class method in wren.
	//
	// It is passed the module, class name, and call signature of the function
	// as well as whether the function is static.
	//
	// Returning nil signifies that such function does not exist, raising an
	// error in wren
	//
	// The call signature's format varies between the type of function it is but
	// usually begins with the function name and ends with the amount of
	// parameters indicated as underscores.
	//
	//     - Regular functions enclose the parameters in parenthesis:
	//       "function(_,_,_)"
	//     - Getters do not have anything following the name: "function"
	//     - Setters have an equal sign before the parameters surrounded by
	//       parenthesis (and should only have one parameter): "function=(_)"
	//     - Indexes have no names but parameters surrounded by brackets:
	//       "[_,_,_]"
	//     - Index setters also have no name but parameters surrounded by
	//       brackets. It also has an equal sign and one parameter surrounded by
	//       parenthesis: "[_,_,_]=(_)"
	//     - Operators begin with the operation followed by one parameter
	//       surrounded by parenthesis: "+(_)", ">=(_)", "<<(_)"
	//
	BindForeignMethodFn func(vm VM, module, class,
		signature string, static bool) func(VM)

	// BindForeignClassMethodFn binds the allocator and finalizer of a class.
	//
	// It takes the name of the class and it's module and should return two
	// functions: one called during the creation of a foreign object (when a
	// constructor is called) and one called when the foreign object is garbage
	// collected. Setting the allocator to nil signifies an error to wren but
	// finalizer is optional and can be set to nil to indicate no finalizer
	// function.
	BindForeignClassMethodFn func(vm VM, module, class string) (allocator func(VM),
		finalizer func(VM, interface{}))

	// WriteFn is called when "System.write", "System.print", and related
	// functions have been called in wren.
	WriteFn func(vm VM, message string)

	// ErrorFn is called whenever acompilation or runtime error has occurred in
	// wren. The error value should always be of type WrenError.
	ErrorFn func(vm VM, err error)

	// InitialHeapSize is the number of bytes wren will allocate before
	// triggering the first garbage collection.
	//
	// Set this to zero to use wren's default value
	InitialHeapSize uint

	// MinHeapSize is the minimum size threshold after a garbage collection has
	// occured. This ensures that the heap does not get to small.
	//
	// Set this to zero to use wren's default value
	MinHeapSize uint

	// HeapGrowthPercent determines the amount of additional memory the heap
	// will grow to after garbage collection. This is specified as a percent of
	// the current heap size with a value like 50 increasing the heap size by
	// 50%
	//
	// The smaller this value is means the less memory wasted but the garbage
	// collector may be triggered more often
	//
	// Set this to zero to use wren's default value
	HeapGrowthPercent int
}
Example (Foreign)
type ID struct {
	module, class, signature string
	bool
}
cfg := wren.Config{
	WriteFn: func(vm wren.VM, message string) { println(message) },
	ErrorFn: func(vm wren.VM, err error) { println(err.Error()) },
	LoadModuleFn: func(vm wren.VM, name string) (src string, ok bool) {
		src, ok = map[ID]string{
			{module: "foreign"}: `
				foreign class Foreign {
					foreign static greet(name)
					construct new() {
						System.print("Hello world")
					}
				}
				`,
		}[ID{module: name}]
		return
	},
	BindForeignMethodFn: func(vm wren.VM, module, class, signature string, static bool) func(wren.VM) {
		return map[ID]func(wren.VM){
			{"foreign", "Foreign", "greet(_)", true}: func(v wren.VM) {
				if v.SlotCount() != 2 { // slot 0 is the "Foreign" class
					v.AbortError(errors.New("Expected 1 parameter"))
				}
				if v.SlotType(1) != wren.TypeString {
					v.AbortError(errors.New("Expected parameter 1 to be string"))
				}
				println("Hello", v.GetString(1))
			},
		}[ID{module, class, signature, static}]
	},
}

vm := wren.NewVM(cfg)

vm.Interpret("main", `
	import "foreign" for Foreign

	Foreign.greet("wren")
	`)
Output:

type ErrorType

type ErrorType int32

ErrorType represents what type of error occured in wren.

const (
	// ErrorCompile represents an error during compilation.
	ErrorCompile ErrorType = iota
	// ErrorRuntime represunts an error during runtime.
	ErrorRuntime
	// ErrorStackTrace represents previous callstacks that lead to a runtime
	// error.
	ErrorStackTrace
)

type Handle

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

Handle is used to keep a reference to a value in the VM as to prevent it from being garbage collected and to refer to it later in foreign functions, but can also be used to call methods from the VM.

func (*Handle) Call

func (h *Handle) Call() InterpretResult

Call calls this handle, using the receiver in slot 0 and arguments from slot 1 or greater.

The handle should have been created using NewCallHandle.

Note: that wren is not reentrant. You should not call this function from a foreign method or while the VM is currently running.

func (*Handle) Free

func (h *Handle) Free()

Free releases and frees up this handle. Handles prevent values from being garbage collected so releasing a handle removes this referance to that value, allowing it to be garbage collected when all references are gone.

type InterpretResult

type InterpretResult int32

InterpretResult represents the result of running code in the VM.

const (
	// ResultSuccess represents no errors
	ResultSuccess InterpretResult = iota
	// ResultCompileError represents an error during the compilation of a module
	ResultCompileError
	// ResultRuntimeError represents an error during the running of a module.
	ResultRuntimeError
)

type Type

type Type int32

Type represents the value type of a slot in wren.

const (
	TypeBool Type = iota
	TypeNum
	// TypeForeign represents a foreign object.
	TypeForeign
	TypeList
	TypeMap
	TypeNull
	TypeString
	// TypeUnknown represents a type that cannot currently be accessed by the
	// API.
	TypeUnknown
)

type VM

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

VM interacts with the wren virtual machine.

Example
cfg := wren.Config{
	WriteFn: func(vm wren.VM, message string) { fmt.Print(message) },
}

vm := wren.NewVM(cfg)

vm.Interpret("main", `System.print("Hello from wren!")`)
Output:

Hello from wren!

func NewVM

func NewVM(cfg Config) VM

New creates and initializes a new VM.

func (VM) AbortError

func (vm VM) AbortError(err error)

AbortError is a helper function that takes a Go error and uses it to abort wren.

func (VM) AbortFiber

func (vm VM) AbortFiber(slot int)

AbortFiber stops the current fiber using the value in slot as the error value.

func (VM) Allocated

func (vm VM) Allocated() int

Allocated returns the amount of bytes allocated by the wren VM. This does not include foreign objects or functions as those are still handled by Go and it doesn't reflect the entire amount of memory needed to run this instance of VM but it is useful to compare against the original version of wren.

func (VM) Call

func (vm VM) Call(handle Handle) InterpretResult

CallHandle calls the handle, using the receiver in slot 0 and arguments from slot 1 or greater.

The handle should have been created using NewCallHandle.

Note: that wren is not reentrant. You should not call this function from a foreign method or while the VM is currently running.

func (VM) CollectGarbage

func (vm VM) CollectGarbage()

CollectGarbage runs the garbage collector for wren.

func (VM) EnsureSlots

func (vm VM) EnsureSlots(numSlots int)

EnsureSlots ensures that the callstack has enough slots to accomadate the value passed.

Each slot coorosponds to one receiver or parameter

func (VM) Exit

func (vm VM) Exit()

Exit attempts to interrupt wren while it is running and exit. The VM has not been tested to verify that it's state is usable afterwards so it is recommended to free it, though your mileage may vary.

func (VM) Free

func (vm VM) Free()

Free disposes all data used by the VM. This isn't always necessary and won't immediately free it's data because the VM's memory is still managed by Go and must be garbage collected by Go. However, this function garbage collects any remaining foreign objects existing in the VM to ensure their finalizers are called.

This VM should no longer be used after calling this function.

func (VM) GetBool

func (vm VM) GetBool(slot int) bool

GetBool retreives a bool in the slot provided.

func (VM) GetBytes

func (vm VM) GetBytes(slot int, writer io.Writer) error

GetBytes retrieves string data from wren and writes it into writer. Error values from writer are returned.

func (VM) GetForeign

func (vm VM) GetForeign(slot int) any

GetForeign returns the foreign object referenced in the current slot. It's value reflects what was passed from SetNewForeign.

func (VM) GetHandle

func (vm VM) GetHandle(slot int) Handle

GetSlotHandle creates a new handle from the value in the slot provided. Handles prevent a value from being garbage collected.

func (VM) GetListElement

func (vm VM) GetListElement(listSlot, index, elementSlot int)

GetListElement places an element at the specified index from a list located in listSlot into elementSlot.

func (VM) GetMapValue

func (vm VM) GetMapValue(mapSlot, keySlot, valueSlot int)

GetMapValue puts the element at index of keySlot from the map in mapSlot into valueSlot.

func (VM) GetNum

func (vm VM) GetNum(slot int) float64

GetNum returns a number in the slot provided.

func (VM) GetString

func (vm VM) GetString(slot int) string

GetString copies a string from the slot provided and returns it.

func (VM) GetVariable

func (vm VM) GetVariable(module, name string, slot int)

GetVariable retreives a variable from the VM and stores it in the specified slot.

func (VM) HasModule

func (vm VM) HasModule(module string) bool

HasModule returns true if the module has previously been imported or interpreted.

func (VM) HasVariable

func (vm VM) HasVariable(module, name string) bool

HasVariable returns true if the value exists in this module.

func (VM) InsertInList

func (vm VM) InsertInList(listSlot, index, elementSlot int)

InsertInList inserts an element into the list at the specified index.

Negative values are supported to index an array from the end.

func (VM) Interpret

func (vm VM) Interpret(module, source string) InterpretResult

Interpret runs the source code in a new fiber in the resolved module.

Note: that wren is not reentrant. You should not call this function from a foreign method or while the VM is currently running.

func (VM) ListCount

func (vm VM) ListCount(slot int) int

ListCount returns the list of the list in the given slot.

func (VM) MapCount

func (vm VM) MapCount(slot int) int

MapCount returns the amount of elements in the map at the specified slot.

func (VM) MapHasKey

func (vm VM) MapHasKey(mapSlot, keySlot int) bool

MapHasKey returns true if the value in keySlot is a valid key in this map

func (VM) NewCallHandle

func (vm VM) NewCallHandle(signature string) Handle

NewCallHandle creates a handle used to invoke methods in wren. When the handle is no longer needed, you should free the handle using ReleaseHandle.

The Handle is reusable and is not locked to a specific receiver. Instead the receiver must be added to the callstack by setting slot 0.

Note: that wren is not reentrant. You should not call this handle from a foreign method or while the VM is currently running.

The call signature's format varies between the type of function it is but usually begins with the function name and ends with the amount of parameters indicated as underscores.

  • Regular functions enclose the parameters in parenthesis: "function(_,_,_)"
  • Getters do not have anything following the name: "function"
  • Setters have an equal sign before the parameters surrounded by parenthesis (and should only have one parameter): "function=(_)"
  • Indexes have no names but parameters surrounded by brackets: "[_,_,_]"
  • Index setters also have no name but parameters surrounded by brackets. It also has an equal sign and one parameter surrounded by parenthesis: "[_,_,_]=(_)"
  • Operators begin with the operation followed by one parameter surrounded by parenthesis: "+(_)", ">=(_)", "<<(_)"

func (VM) ReleaseHandle

func (vm VM) ReleaseHandle(handle Handle)

ReleaseHandle releases and frees up this handle. Handles prevent values from being garbage collected so releasing a handle removes this referance to that value, allowing it to be garbage collected when all references are gone.

func (VM) RemoveMapValue

func (vm VM) RemoveMapValue(mapSlot, keySlot, valueSlot int)

RemoveMapValue removes an element from the map. If the element was found, it is put into valueSlot. If not, then valueSlot will be set to null.

func (VM) SetBool

func (vm VM) SetBool(slot int, value bool)

SetSlotBool sets the provided slot to a boolean value.

func (VM) SetBytes

func (vm VM) SetBytes(slot int, data []byte)

SetSlotBytes sets the provided slot to a string value from the given bytes.

func (VM) SetHandle

func (vm VM) SetHandle(slot int, handle Handle)

SetHandle sets the provided slot to the value held by the given handle.

func (VM) SetListElement

func (vm VM) SetListElement(listSlot, index, elementSlot int)

SetListElement sets a lists element at the specified index from a list locates in listSLot to the value locates at elementSlot.

func (VM) SetMapValue

func (vm VM) SetMapValue(mapSlot, keySlot, valueSlot int)

SetMapValue sets the element at index of keySlot from the map in mapSlot into valueSlot.

func (VM) SetNewForeign

func (vm VM) SetNewForeign(slot, classSlot int, obj interface{})

SetNewForeign creates a new foreign object in wren.

func (VM) SetNewList

func (vm VM) SetNewList(slot int)

SetNewList creates an empty list and sets it in the slot provided.

func (VM) SetNewMap

func (vm VM) SetNewMap(slot int)

SetNewMap creates an empty map and sets it in the slot provided.

func (VM) SetNull

func (vm VM) SetNull(slot int)

SetNull sets the provided slot to a null value.

func (VM) SetNum

func (vm VM) SetNum(slot int, value float64)

SetNum sets the provided slot to a number value from the given float64.

func (VM) SetString

func (vm VM) SetString(slot int, value string)

SetString sets the provided slot to the given string value.

func (VM) SetUserdata

func (vm VM) SetUserdata(data interface{})

SetUserdata sets the user data for this VM

func (VM) SlotCount

func (vm VM) SlotCount() int

SlotCount returns the numbers of slots currently available to the current foreign method.

func (VM) SlotType

func (vm VM) SlotType(slot int) Type

SlotType gets the value type located in the slot provided.

func (VM) UserData

func (vm VM) UserData() any

UserData gets the user data of this VM.

func (VM) VersionNumber

func (vm VM) VersionNumber() int

func (VM) VersionString

func (vm VM) VersionString() string

func (VM) VersionTuple

func (vm VM) VersionTuple() [3]int

type WrenError

type WrenError struct {
	Type    ErrorType
	Module  string
	Line    int
	Message string
}

WrenError represents a compile or runtime error from wren. Depending on the ErrorType, not all field may be populated

func (WrenError) Error

func (err WrenError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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