interp

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package interp evaluates a resolved Aria program.

Three things differ structurally from the original evaluator.

A runtime error stops the program. The old one collected errors and carried on with a nil in hand, so one real failure produced a second misleading message about the call that received the nil, and a statement that legitimately produced nothing silently discarded the rest of its block. Here a failure unwinds to the top and the process exits non-zero (7.1, 7.5).

Control flow is a signal, not a value. `return`, `break` and `continue` used to be ordinary values flowing through the same paths as data, which is what made "no value" and "stop evaluating" indistinguishable.

Collections are immutable. `a[] = v` rebinds `a` to a new collection rather than growing one in place, so no operator can corrupt its own operand.

Index

Constants

This section is empty.

Variables

View Source
var ErrIncomplete = errors.New("incomplete input")

ErrIncomplete says the source given to Session.Eval opened a construct it did not close, so more input could complete it. A REPL buffers on this rather than reporting it.

Functions

func Check added in v1.0.0

func Check(file *source.File, opts Options) bool

Check compiles file without evaluating it, reporting into Options.Err.

It is the same pipeline Run uses, stopped after resolution — which is what an editor or a CI step wants, and what Run already did internally before evaluating anything.

func Convert

func Convert(v value.Value, to string) (value.Value, string)

Convert implements the `as` operator and the conversion builtins. It returns a message rather than reporting, so both call sites can attach their own span.

func Eval

func Eval(name, src string, opts Options) (value.Value, error)

Eval compiles and evaluates src, returning its value. It is the entry point tests use, and skips the standard library unless asked for it.

func Nodes

func Nodes(prog *ast.Program) []ast.Node

Nodes exposes a parsed program's nodes, for tests that need the tree.

func Run

func Run(file *source.File, opts Options) bool

Run compiles and evaluates one source file.

It returns false if anything went wrong, having already written the reason to Options.Err. The phases are deliberately separate and ordered: nothing is evaluated until the whole file has parsed and resolved, so a name error in a branch that never executes is still reported.

Types

type Builtin

type Builtin struct {
	Name string
	// Fn receives evaluated arguments and the interpreter, so a builtin can
	// reach the configured input and output streams.
	Fn func(i *Interp, args []value.Value, span source.Span) value.Value
}

Builtin is a function implemented in Go.

func (*Builtin) Inspect

func (b *Builtin) Inspect() string

func (*Builtin) String

func (b *Builtin) String() string

func (*Builtin) Type

func (*Builtin) Type() value.Type

type Error

type Error struct {
	File *source.File
	Span source.Span
	Msg  string
}

Error is a runtime failure, located in the source.

File is the file Span indexes into, which is not necessarily the file that was run: a fault inside an imported file or a standard library module is located in that file's text. Without it the span was rendered against the wrong source and pointed at unrelated lines, or past the end of the file.

func (*Error) Error

func (e *Error) Error() string

type Function

type Function struct {
	Decl *ast.Function
	Env  *env
	File *source.File
}

Function is a user-defined function closed over its defining scope.

File is where the body was written, which the interpreter running the call need not know otherwise: a standard library function is called by the interpreter for the user's file, and a fault in its body belongs to the library's text, not the user's.

func (*Function) Inspect

func (f *Function) Inspect() string

func (*Function) String

func (f *Function) String() string

func (*Function) Type

func (*Function) Type() value.Type

type Interp

type Interp struct {
	Out io.Writer
	Err io.Writer
	In  io.Reader
	// contains filtered or unexported fields
}

Interp evaluates programs.

func New

func New(file *source.File, info *resolver.Info) *Interp

New returns an interpreter writing to stdout and stderr.

func (*Interp) Globals

func (i *Interp) Globals() *env

Globals exposes the top-level scope, so a host can seed it.

func (*Interp) Modules

func (i *Interp) Modules() map[string]*Module

Modules exposes declared modules, so a standard library evaluated separately can be carried into a later run.

func (*Interp) Report

func (i *Interp) Report(err *Error)

Report writes a runtime error in the same shape as a compile-time diagnostic, so both look the same to whoever is reading the terminal.

func (*Interp) Run

func (i *Interp) Run(prog *ast.Program) (result value.Value, err error)

Run evaluates prog. It returns the program's final value, or an error if a runtime failure stopped it.

type Module

type Module struct {
	Name string
	// contains filtered or unexported fields
}

Module is a named container of values.

A module is an ordinary value: it lives in the environment under its name, so it can be bound, passed and returned like anything else.

That exposed a collision the two-namespace design used to hide. `String` is both a conversion builtin and a standard library module, and as a value the name has to mean one thing. It means both: a module that shadows a builtin of its own name carries it, so `String("x")` converts and `String.join(...)` reads a member, and `let S = String` gets a value that still does both.

func (*Module) Inspect

func (m *Module) Inspect() string

func (*Module) Member

func (m *Module) Member(name string) (value.Value, bool)

Member looks a module member up.

func (*Module) Names

func (m *Module) Names() []string

Names lists the module's members in declaration order.

func (*Module) String

func (m *Module) String() string

func (*Module) Type

func (*Module) Type() value.Type

type Options

type Options struct {
	Out io.Writer
	Err io.Writer
	In  io.Reader
	// Args is what the program was told: everything after the source file. The
	// CLI keeps its own flags.
	Args []string
	// NoStdlib skips loading the standard library, for tests that want a bare
	// interpreter.
	NoStdlib bool
}

Options configure a run.

type RecordDef added in v1.0.0

type RecordDef struct {
	Decl *ast.Record
	Def  *value.RecordType
	// File is where the declaration was written, so a fault building an
	// instance is reported there.
	File *source.File
}

RecordDef is a declared record, bound to its own name.

Calling it constructs an instance, which is why a record needs no construction syntax: its fields are a parameter list, so `Point(1, 2)` is an ordinary call, with the same arity check, type hints and defaults every other call has.

Anything shaped like a domain object used to have no home. A module holds only `let` and cannot be instantiated; a dictionary carries data but no identity, so `typeof` said "Dictionary" for every one of them and `is` could not tell a point from a config.

func (*RecordDef) FieldNames added in v1.0.0

func (d *RecordDef) FieldNames() []string

func (*RecordDef) Inspect added in v1.0.0

func (d *RecordDef) Inspect() string

func (*RecordDef) String added in v1.0.0

func (d *RecordDef) String() string

func (*RecordDef) Type added in v1.0.0

func (*RecordDef) Type() value.Type

type Session

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

A Session evaluates one line at a time against persistent state, for a REPL.

Each line is a complete compilation: it is parsed and resolved before it runs, so an undefined name is reported without the line having any effect. Names declared by earlier lines are carried forward and predeclared for later ones.

func NewSession

func NewSession(opts Options) (*Session, error)

NewSession starts a session with the standard library loaded.

func (*Session) Declared added in v1.0.0

func (s *Session) Declared() []string

Declared lists the names earlier fragments introduced, in sorted order, so a REPL can show what is in scope.

func (*Session) Eval

func (s *Session) Eval(src string) (value.Value, error)

Eval runs one fragment. It returns its value, or an error describing why it could not run — already formatted with a caret, as a file would be.

A REPL that reads one line at a time cannot enter a multi-line func, module, if or for at all, which rules out most of what a REPL is for. Eval takes a whole fragment and says ErrIncomplete when more input could complete it.

func (*Session) Modules added in v1.0.0

func (s *Session) Modules() []string

Modules lists the modules in scope, standard library included.

Jump to

Keyboard shortcuts

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