wdte

package module
v0.3.8 Latest Latest
Warning

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

Go to latest
Published: Oct 26, 2018 License: MIT Imports: 10 Imported by: 1

README

wdte

GoDoc Go Report Card cover.run

WDTE is a simple, functional-ish, embedded scripting language.

Why does this exist?

Good question. In fact, I found myself asking the same thing, hence the name.

I had a number of design goals in mind when I started working on this project:

  • Extremely simple. Entire grammar is less than 20-30 lines of specification.
  • Grammar is LL(1) parseable.
  • Functional-ish, but not particularly strict about it.
  • Designed primarily for embedding. No command-line interpreter by default.
  • Extremely easy to use from the binding side. In this case, that's primarily Go.

If you want to try the language yourself, feel free to take a look at the playground. It shows not only some of the features of the language in terms of actually writing code in it, but also how embeddable it is. The playground runs entirely in the browser on the client's end thanks to WebAssembly.

Example

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/DeedleFake/wdte"
)

const src = `
let i => import 'some/import/path/or/another';

i.print 3;
+ 5 2 -> i.print;
`

func im(from string) (*wdte.Scope, error) {
	var print wdte.GoFunc
	print = wdte.GoFunc(func(frame wdte.Frame, args ...wdte.Func) wdte.Func {
		if len(args) < 1 {
			return print
		}

		a := args[0].Call(frame)
		fmt.Println(a)
		return a
	})

	return wdte.S().Map(map[wdte.ID]wdte.Func{
		"print": print,
	}), nil
}

func main() {
	m, err := wdte.Parse(strings.NewReader(src), wdte.ImportFunc(im))
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing module: %v\n", err)
		os.Exit(1)
	}

	scope := wdte.S().Sub("+", wdte.GoFunc(func(frame wdte.Frame, args ...wdte.Func) wdte.Func {
		var sum wdte.Number
		for _, arg := range args {
			sum += arg.Call(frame).(wdte.Number)
		}
		return sum
	}))

	m.Call(wdte.F().WithScope(scope))
}
Output
3
7

Documentation

For an overview of the language's design and features, see the GitHub wiki.

Status

WDTE is in a pre-alpha state. It is filled with bugs and large amounts of stuff are subject to change without warning. That being said, if you're interested in anything, feel free to submit a pull request and get things fixed and/or implemented faster.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Array

type Array []Func

An Array represents a WDTE array type. It's similar to a Compound, but when evaluated, it returns itself with its own members replaced with their own evaluations. This allows it to be passed around as a value in the same way as strings and numbers.

func (Array) At

func (a Array) At(i Func) (Func, bool)

func (Array) Call

func (a Array) Call(frame Frame, args ...Func) Func

func (Array) Len

func (a Array) Len() int

func (Array) String added in v0.2.3

func (a Array) String() string

type Atter

type Atter interface {
	// At returns the value at index i. If the index is out of range, it
	// should return false as its second return value.
	At(i Func) (Func, bool)
}

An Atter is a Func that can be indexed, like an array or a string.

type Bool

type Bool bool

Bool is a boolean. Like other primitive types, it simply returns itself when called.

func (Bool) Call

func (b Bool) Call(frame Frame, args ...Func) Func

func (Bool) Compare

func (b Bool) Compare(other Func) (int, bool)

type Chain

type Chain []*FuncCall

Chain is an unevaluated chain expression.

func (Chain) Call

func (f Chain) Call(frame Frame, args ...Func) Func

type Comparer

type Comparer interface {
	// Compare returns two values. The meaning of the first is dependent
	// upon the second. If the second is true, then the first indicates
	// ordering via the standard negative, positive, and zero results to
	// indicate less than, greater than, and equal, respectively. If the
	// second is false, then the first indicates only equality, with
	// zero still meaning equal, but other values simply meaning unequal.
	Compare(other Func) (int, bool)
}

A Comparer is a Func that is able to be compared to other functions.

type Compound

type Compound []Func

A Compound represents a compound expression. Calling it calls each of the expressions in the compound, returning the value of the last one. If the compound is empty, nil is returned.

If an element of a compound is a *Let, then the unevaluated right-hand side is placed into a new subscope under the ID specified by the right-hand side. The remainder of the elements in the compound are then evaluated under this new subscope. If the last element in the compound is a *Let, the right-hand side is returned as a lambda if it has arugments.

func FromAST

func FromAST(root ast.Node, im Importer) (Compound, error)

FromAST translates an AST into a top-level compound. im is used to handle import statements. If im is nil, a no-op importer is used.

func Parse

func Parse(r io.Reader, im Importer) (Compound, error)

Parse parses an AST from r and then translates it into a top-level compound. im is used to handle import statements. If im is nil, a no-op importer is used. In most cases, std.Import is a good default.

func (Compound) Call

func (c Compound) Call(frame Frame, args ...Func) Func

func (Compound) Collect

func (c Compound) Collect(frame Frame) (*Scope, Func)

Collect executes the compound the same as Call, but also returns the collected scope that has been modified by let expressions alongside the usual return value. This is useful when dealing with scopes as modules, as it allows you to evaluate specific functions in a script.

type Error

type Error struct {
	// Err is the error that generated the Error. In a lot of cases,
	// this is just a simple error message.
	Err error

	// Frame is the frame of the function that the error was first
	// generated in.
	Frame Frame
}

An Error is returned by any of the built-in functions when they run into an error.

func (Error) Call

func (e Error) Call(frame Frame, args ...Func) Func

func (Error) Error

func (e Error) Error() string

type Frame

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

A Frame tracks information about the current function call, such as the scope that the function is being executed in and debugging info.

func F

func F() Frame

F returns a top-level frame. This can be used by Go code calling WDTE functions directly if another frame is not available.

In many cases, it may be preferable to use std.F() instead.

func (Frame) Backtrace

func (f Frame) Backtrace(w io.Writer) error

Backtrace prints a backtrace to w.

func (Frame) Context

func (f Frame) Context() context.Context

func (Frame) ID

func (f Frame) ID() ID

ID returns the ID of the frame. This is generally the function that created the frame.

func (Frame) Parent

func (f Frame) Parent() Frame

Parent returns the frame that this frame was created from, or a blank frame if there was none.

func (Frame) Scope

func (f Frame) Scope() *Scope

Scope returns the scope associated with the frame.

func (Frame) Sub

func (f Frame) Sub(id ID) Frame

Sub returns a new child frame of f with the given ID and the same scope as f.

Under most circumstances, a GoFunc should call this before calling any WDTE functions, as it is useful for debugging. For example:

func Example(frame wdte.Frame, args ...wdte.Func) wdte.Func {
    frame = frame.Sub("example")
    ...
}

func (Frame) WithContext

func (f Frame) WithContext(ctx context.Context) Frame

WithContext returns a copy of f with the given context.

func (Frame) WithScope

func (f Frame) WithScope(scope *Scope) Frame

WithScope returns a copy of f with the given scope.

type Func

type Func interface {
	// Call calls the function with the given arguments, returning its
	// return value. frame represents the current call frame, which
	// tracks scope as well as debugging info.
	Call(frame Frame, args ...Func) Func
}

Func is the base type through which all data is handled by WDTE. It represents everything that can be passed around in the language. This includes functions, of course, expressions, strings, numbers, Go functions, and anything else the client wants to pass into WDTE.

type FuncCall added in v0.2.1

type FuncCall struct {
	Func Func
	Args []Func

	Slot    ID
	Ignored bool
}

A FuncCall is an unevaluated function call. This is usually the right-hand side of a function declaration, but could also be any of various pieces of switches, compounds, or arrays.

func (FuncCall) Call added in v0.2.1

func (f FuncCall) Call(frame Frame, args ...Func) Func

func (FuncCall) String added in v0.3.3

func (f FuncCall) String() string

type GoFunc

type GoFunc func(frame Frame, args ...Func) Func

A GoFunc is an implementation of Func that calls a Go function. This is the easiest way to implement lower-level systems for WDTE scripts to make use of.

For example, to implement a simple, non-type-safe addition function:

GoFunc(func(frame wdte.Frame, args ...wdte.Func) wdte.Func {
  frame = frame.Sub("+")
  var sum wdte.Number
  for _, arg := range(args) {
    sum += arg.Call(frame).(wdte.Number)
  }
  return sum
})

If placed into a scope with the ID "+", this function can then be called from WDTE as follows:

  • 3 6 9

As shown, it is recommended that arguments be passed the given frame when evaluating them. Failing to do so without knowing what you're doing can cause unexpected behavior, including sending the evaluation system into infinite loops or causing panics.

In the event that a GoFunc panics with an error value, it will be automatically caught and converted into an Error, which will then be returned.

func (GoFunc) Call

func (f GoFunc) Call(frame Frame, args ...Func) (r Func)

func (GoFunc) String added in v0.2.3

func (f GoFunc) String() string

type ID

type ID string

ID represents a WDTE ID, such as a local variable.

type ImportFunc

type ImportFunc func(from string) (*Scope, error)

ImportFunc is a wrapper around simple functions to allow them to be used as Importers.

func (ImportFunc) Import

func (f ImportFunc) Import(from string) (*Scope, error)

type Importer

type Importer interface {
	Import(from string) (*Scope, error)
}

An Importer creates scopes from strings. When parsing a WDTE script, an importer is used to import scopes into namespaces.

When the WDTE import expression

import 'example'

is parsed, the associated Importer will be invoked as follows:

im.Import("example")

type Lambda

type Lambda struct {
	ID   ID
	Expr Func
	Args []ID

	Stored   []Func
	Scope    *Scope
	Original *Lambda
}

A Lambda is a closure. When called, it calls its inner expression with itself and its own arguments placed into the scope. In other words, given the lambda

(@ ex x y => + x y)

it will create a new subscope containing itself under the ID "ex", and its first and second arguments under the IDs "x" and "y", respectively. It will then evaluate `+ x y` in that new scope.

The arguments in the subscope, not including the self-reference, are contained in the boundary "args". The self-reference is contained in the boundary "self".

func (*Lambda) Call

func (lambda *Lambda) Call(frame Frame, args ...Func) Func

func (*Lambda) String

func (lambda *Lambda) String() string

type Lenner

type Lenner interface {
	Len() int
}

A Lenner is a Func that has a length, such as arrays and strings.

type Let

type Let struct {
	ID   ID
	Expr Func
}

A Let is an expression that maps an expression to an ID. It's used inside compounds to create subscopes, essentially allowing for read-only, shadowable variable declarations.

When evaluated, a Let simply passes everything through to its inner expression.

func (*Let) Call

func (let *Let) Call(frame Frame, args ...Func) Func

type Memo

type Memo struct {
	Func Func
	Args []ID
	// contains filtered or unexported fields
}

A Memo wraps another function, caching the results of calls with the same arguments.

func (*Memo) Call

func (m *Memo) Call(frame Frame, args ...Func) Func

type Number

type Number float64

A Number is a number, as parsed from a number literal. That's about it. Like everything else, it's a function. It simply returns itself when called.

func (Number) Call

func (n Number) Call(frame Frame, args ...Func) Func

func (Number) Compare

func (n Number) Compare(other Func) (int, bool)

func (Number) String added in v0.3.1

func (n Number) String() string

type Scope

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

Scope is a tiered storage space for local variables. This includes function parameters and chain slots. A nil *Scope is equivalent to a blank, top-level scope.

func S

func S() *Scope

S is a convenience function that returns a blank, top-level scope.

func (*Scope) Add

func (s *Scope) Add(id ID, val Func) *Scope

Add returns a new subscope with the given variable stored in it.

func (*Scope) At

func (s *Scope) At(i Func) (Func, bool)

func (*Scope) Call

func (s *Scope) Call(frame Frame, args ...Func) Func

func (*Scope) Custom

func (s *Scope) Custom(getFunc func(ID) Func, known func(map[ID]struct{})) *Scope

Custom returns a new subscope that uses the given lookup function to retrieve values. If getFunc returns nil, the parent of s will be searched. known is an optional function which adds all variables known to this layer of the scope into the map that it is passed as keys.

func (*Scope) Freeze

func (s *Scope) Freeze(f Func) Func

Freeze returns a new function which executes in the scope s regardless of whatever Frame it is called with.

func (*Scope) Get

func (s *Scope) Get(id ID) Func

Get returns the value of the variable with the given ID. If the variable doesn't exist in either the current scope or any of its parent scopes, nil is returned.

func (*Scope) Known

func (s *Scope) Known() []ID

Known returns a sorted list of variables that are in scope.

func (*Scope) Map

func (s *Scope) Map(vars map[ID]Func) *Scope

Map returns a subscope that includes the given mapping of variable names to functions. Note that no copy is made of vars, so changing the map after passing it to this method may result in undefined behavior.

func (*Scope) Parent

func (s *Scope) Parent() *Scope

Parent returns the parent of the current scope.

func (*Scope) String

func (s *Scope) String() string

func (*Scope) Sub

func (s *Scope) Sub(sub *Scope) *Scope

Sub subscopes sub to s such that variables in sub will shadow variables in s.

type ScopedFunc

type ScopedFunc struct {
	Func  Func
	Scope *Scope
}

A ScopedFunc is an expression that uses a predefined scope instead of the one that comes with its frame. This is to make sure that a lazily evaluated expression has access to the correct scope.

func (ScopedFunc) Call

func (f ScopedFunc) Call(frame Frame, args ...Func) Func

func (ScopedFunc) String added in v0.2.3

func (f ScopedFunc) String() string

type String

type String string

A String is a string, as parsed from a string literal. That's about it. Like everything else, it's a function. It simply returns itself when called.

func (String) At

func (s String) At(i Func) (Func, bool)

func (String) Call

func (s String) Call(frame Frame, args ...Func) Func

func (String) Compare

func (s String) Compare(other Func) (int, bool)

func (String) Len

func (s String) Len() int

type Sub

type Sub []Func

A Sub is a function that is in a subscope. This is most commonly an imported function.

func (Sub) Call

func (sub Sub) Call(frame Frame, args ...Func) Func

type Switch

type Switch struct {
	// Check is the condition at the front of the switch.
	Check Func

	// Cases is the switch's cases. Each contains two functions. The
	// first index is the left-hand side, while the second is the
	// right-hand side. When the switch is evaluated, the cases are run
	// in order. If any matches, the right-hand side is evaluated and
	// its return value is returned.
	Cases [][2]Func
}

Switch represents a switch expression.

func (Switch) Call

func (s Switch) Call(frame Frame, args ...Func) Func

type Var

type Var ID

A Var represents a local variable. When called, it looks itself up in the frame that it's given and calls whatever it finds.

func (Var) Call

func (v Var) Call(frame Frame, args ...Func) Func

Directories

Path Synopsis
ast
cmd
std
all
Package all is a convience package that imports the entire standard library, thus registering it with std.Import.
Package all is a convience package that imports the entire standard library, thus registering it with std.Import.
arrays
Package arrays contains functions for manipulating arrays.
Package arrays contains functions for manipulating arrays.
io
Package io contains WDTE functions for dealing with files and other types of data streams.
Package io contains WDTE functions for dealing with files and other types of data streams.
io/file
Package file provides functions for dealing with files.
Package file provides functions for dealing with files.
math
Package math contains wdte.Funcs for performing mathematical operations.
Package math contains wdte.Funcs for performing mathematical operations.
stream
Package stream provides WDTE functions for manipulating streams of data.
Package stream provides WDTE functions for manipulating streams of data.
strings
Package strings contains functions for dealing with strings.
Package strings contains functions for dealing with strings.

Jump to

Keyboard shortcuts

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