evaluator

package
v0.1.211 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2025 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package evaluator executes a given Evy program by walking its AST.

Initially, an Evy program is turned into a sequence of tokens by the lexer. Then, the parser generates an Abstract Syntax Tree(AST) from the tokens. Finally, the Evaluator of this package walks the AST and executes the program.

The Evaluator is a tree-walking interpreter. It directly interprets the AST, without any preprocessing, intermediate representation, or compilation step. This is a straightforward way to implement an interpreter, but it trades off execution performance for simplicity.

The Evaluator uses different Platform implementations to target different environments. For example, there is a JS/WASM platform for the browser, which has full support for all graphics built-in functions. There is also a command line environment, which does not have graphics functions support.

The NewEvaluator function creates a new Evaluator for a given Platform. The evaluator can then be used by either:

After the Evaluator has finished evaluating all top-level code and returned, the environment is responsible for starting an event loop if external events such as key press events or pointer/mouse move events are supported.

In the event loop, new events are queued and handled sequentially by calling the Evaluator.HandleEvent function. Each event is passed to its event handler once. The event handler body runs to completion, and then the control is returned to the event loop. The event loop is terminated when the Evaluator is stopped. For a sample implementation of an event loop, see the main package in the pkg/wasm directory used in the browser environment.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrStopped = errors.New("stopped")

	ErrTest = errors.New("failed test")

	ErrPanic         = errors.New("panic")
	ErrIndexValue    = fmt.Errorf("%w: index not an integer", ErrPanic)
	ErrBounds        = fmt.Errorf("%w: index out of bounds", ErrPanic)
	ErrRangevalue    = fmt.Errorf("%w: bad range value", ErrPanic)
	ErrMapKey        = fmt.Errorf("%w: no value for map key", ErrPanic)
	ErrSlice         = fmt.Errorf("%w: bad slice", ErrPanic)
	ErrBadArguments  = fmt.Errorf("%w: bad arguments", ErrPanic)
	ErrBadRepetition = fmt.Errorf("%w: bad repetition count", ErrPanic)
	ErrAnyConversion = fmt.Errorf("%w: error converting any to type", ErrPanic)
	ErrVarNotSet     = fmt.Errorf("%w: variable has not been set yet", ErrPanic)

	ErrInternal         = errors.New("internal error")
	ErrUnknownNode      = fmt.Errorf("%w: unknown AST node", ErrInternal)
	ErrType             = fmt.Errorf("%w: type error", ErrInternal)
	ErrRangeType        = fmt.Errorf("%w: bad range type", ErrInternal)
	ErrOperation        = fmt.Errorf("%w: unknown operation", ErrInternal)
	ErrAssignmentTarget = fmt.Errorf("%w: bad assignment target", ErrInternal)
)

The Evaluator can return the following sentinel errors:

  • ErrStopped is returned when the program has been stopped externally.
  • ErrPanic and errors wrapping ErrPanic report runtime errors, such as an index out of bounds error.
  • ErrInternal and errors wrapping ErrInternal report internal errors of the evaluator or AST. These errors should not occur.
  • ErrTest and errors wrapping ErrTest for failed tests.
View Source
var RandSource = rand.New(rand.NewSource(time.Now().UnixNano())) //nolint:gosec

RandSource is the source used by the rand1 and rand builtins. By default it is initialized with the current time. It is exported so it can be overridden by a fixed seed to generate deterministic output.

Functions

func BuiltinDecls

func BuiltinDecls() parser.Builtins

BuiltinDecls returns the signatures of all built-in functions and event handlers, as well as predefined global variables, for use by the parser.Parse function.

Types

type Error

type Error struct {
	Token *lexer.Token
	// contains filtered or unexported fields
}

Error is an Evy evaluator error associated with a lexer.Token that points to a location in the Evy source code that caused the error.

func (*Error) Error

func (e *Error) Error() string

Error implements the error interface and returns the wrapped error message prefixed with the source location.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the wrapped error.

type Evaluator

type Evaluator struct {
	// Stopped flags the evaluation to be stopped.
	// The unsynchronized access to the Stopped field is safe in WASM because
	// WASM is a single-threaded environment. TinyGo does not currently support
	// synchronization in reactor mode, see
	// https://github.com/tinygo-org/tinygo/issues/2735.
	Stopped           bool
	EventHandlerNames []string
	TestInfo          TestInfo
	// contains filtered or unexported fields
}

Evaluator is a tree-walking interpreter that directly interprets the AST using the Run and Eval methods. The HandleEvent method can be used to allow the evaluator to handle events. The Evaluator does not preprocess or compile the AST to an intermediate representation, which results in a straightforward implementation that trades off execution performance for simplicity.

func NewEvaluator

func NewEvaluator(rt Platform) *Evaluator

NewEvaluator creates a new Evaluator for a given Platform. Platforms target different environments, such as the browser or the command line.

func (*Evaluator) Eval

func (e *Evaluator) Eval(prog *parser.Program) error

Eval evaluates a parser.Program, which is the root node of the AST. The program's statements are evaluated in order. If a platform panic occurs, a wrapped ErrPanic is returned. If an internal error occurs, a wrapped ErrInternal is returned. Evaluation is also stopped if the built-in exit function is called, which results in an ExitError. If the evaluator's Stopped flag is externally set to true, evaluation is stopped and ErrStopped is returned.

func (*Evaluator) HandleEvent

func (e *Evaluator) HandleEvent(ev Event) error

HandleEvent is called by an environment's event loop, passing the event ev to be handled. If the event's name and parameters match those of a predefined, built-in event handler signature, and if there is an event handler implementation in the Evy source code with the following signature:

on <event-name> [<event-params>]

then the event handler implementation of the Evy source code is executed.

For more details, see the built-in documentation on event handlers.

func (*Evaluator) Run

func (e *Evaluator) Run(input string) error

Run is a convenience function that parses and evaluates a given Evy source code input string. See the Evaluator type and Evaluator.Eval method for details on evaluation and errors.

type Event

type Event struct {
	Name   string
	Params []any
}

Event is a generic data structure that is passed to the Evaluator through the Evaluator.HandleEvent function. The evaluator tries to match the event's name and parameters to an event handler implementation in the Evy source code. If a matching handler is found, it is executed.

type ExitError

type ExitError int

ExitError is returned by Evaluator.Eval if Evy's builtin exit function is called.

func (ExitError) Error

func (e ExitError) Error() string

Error implements the error interface and returns message containing the exit status.

type GraphicsPlatform added in v0.1.206

type GraphicsPlatform interface {
	Move(x, y float64)
	Line(x, y float64)
	Rect(dx, dy float64)
	Circle(radius float64)
	Width(w float64)
	Color(s string)
	Clear(color string)

	// advanced graphics functions
	Poly(vertices [][]float64)
	Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64)
	Stroke(s string)
	Fill(s string)
	Dash(segments []float64)
	Linecap(s string)
	Text(s string)
	// font optionally sets font properties such as family, size or weight.
	// font properties match their CSS properties. Here's an exhaustive list
	// of mapped properties:
	//
	//		font {
	//			family: "Georgia, serif"
	//			size: 3 // relative to canvas, numbers only no "12px" etc.
	//			weight: 100 | 200| 300 | 400 == "normal" | 500 | 600 | 700 == "bold" | 800 | 900
	//			style: "italic" | "oblique 35deg" | "normal"
	//			baseline: "top" | "middle" | "bottom"
	//			align: "left" | "center" | "right"
	//			letterspacing: 1 // number, see size. extra inter-character space. negative allowed.
	//		}
	Font(props map[string]any)
	Gridn(unit float64, color string)
}

The GraphicsPlatform interface contains all methods that are required by the graphics built-ins. For more details see the graphics built-ins documentation.

type PanicError

type PanicError string

PanicError is returned by Evaluator.Eval if Evy's builtin panic function is called or a runtime error occurs.

func (PanicError) Error

func (e PanicError) Error() string

Error implements the error interface and returns the panic message.

func (PanicError) Unwrap

func (e PanicError) Unwrap() error

Unwrap returns the ErrPanic sentinel error so that it can be used in

errors.Is(err, evaluator.ErrPanic)

type Platform added in v0.1.206

type Platform interface {
	GraphicsPlatform
	Print(string)
	Read() string
	Cls()
	Sleep(dur time.Duration)
	Yielder() Yielder
}

The Platform interface must be implemented by an environment in order to execute Evy source code and Evy builtins. To create a new platform implementation, you can embed UnimplementedPlatform and override the methods that your platform can provide. For example, there is a jsPlatform implementation for the browser, which has full support for all graphics built-in functions. There is also a command-line environment implementation, which does not have graphics function support. For more details on the built-in functions, see the built-ins documentation.

type TestErrors added in v0.1.167

type TestErrors []error

TestErrors is an Evy evaluator error list associated with multiple failed tests.

func (TestErrors) Error added in v0.1.167

func (e TestErrors) Error() string

Error prints all test errors separated by newline.

func (TestErrors) Unwrap added in v0.1.167

func (e TestErrors) Unwrap() []error

Unwrap returns the wrapped error.

type TestInfo added in v0.1.167

type TestInfo struct {
	FailFast      bool
	NoTestSummary bool
	// contains filtered or unexported fields
}

TestInfo contains flags for test runs, e.g. FailFast and test result information, e.g. total count.

func (*TestInfo) FailCount added in v0.1.167

func (t *TestInfo) FailCount() int

FailCount returns the number of failed tests.

func (*TestInfo) Report added in v0.1.167

func (t *TestInfo) Report(printFn func(string))

Report prints a summary of the test results.

func (*TestInfo) SuccessCount added in v0.1.167

func (t *TestInfo) SuccessCount() int

SuccessCount returns the number of successful tests.

func (*TestInfo) TotalCount added in v0.1.167

func (t *TestInfo) TotalCount() int

TotalCount returns the total number of tests executed.

type UnimplementedPlatform added in v0.1.206

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

UnimplementedPlatform implements Platform with no-ops and prints a "<func> not implemented" message.

func (*UnimplementedPlatform) Circle added in v0.1.206

func (rt *UnimplementedPlatform) Circle(float64)

Circle is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Clear added in v0.1.206

func (rt *UnimplementedPlatform) Clear(string)

Clear is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Cls added in v0.1.206

func (rt *UnimplementedPlatform) Cls()

Cls is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Color added in v0.1.206

func (rt *UnimplementedPlatform) Color(string)

Color is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Dash added in v0.1.206

func (rt *UnimplementedPlatform) Dash([]float64)

Dash is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Ellipse added in v0.1.206

Ellipse is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Fill added in v0.1.206

func (rt *UnimplementedPlatform) Fill(string)

Fill is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Font added in v0.1.206

func (rt *UnimplementedPlatform) Font(map[string]any)

Font is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Gridn added in v0.1.206

func (rt *UnimplementedPlatform) Gridn(float64, string)

Gridn is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Line added in v0.1.206

Line is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Linecap added in v0.1.206

func (rt *UnimplementedPlatform) Linecap(string)

Linecap is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Move added in v0.1.206

Move is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Poly added in v0.1.206

func (rt *UnimplementedPlatform) Poly([][]float64)

Poly is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Print added in v0.1.206

func (rt *UnimplementedPlatform) Print(s string)

Print prints to os.Stdout.

func (*UnimplementedPlatform) Read added in v0.1.206

func (rt *UnimplementedPlatform) Read() string

Read is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Rect added in v0.1.206

Rect is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Sleep added in v0.1.206

func (rt *UnimplementedPlatform) Sleep(time.Duration)

Sleep is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Stroke added in v0.1.206

func (rt *UnimplementedPlatform) Stroke(string)

Stroke is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Text added in v0.1.206

func (rt *UnimplementedPlatform) Text(string)

Text is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Width added in v0.1.206

func (rt *UnimplementedPlatform) Width(float64)

Width is a no-op that prints an "unimplemented" message.

func (*UnimplementedPlatform) Yielder added in v0.1.206

func (rt *UnimplementedPlatform) Yielder() Yielder

Yielder is a no-op that prints an "unimplemented" message.

type Yielder

type Yielder interface {
	Yield()
}

Yielder is a platform-implemented mechanism that causes the evaluation process to periodically give up control to the platform. The Yield method of the Yielder interface is called at the beginning of each evaluation step. This allows the platform to handle external tasks, such as processing events. For a sample implementation, see the sleepingYielder of the browser environment in the pkg/wasm directory.

Jump to

Keyboard shortcuts

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