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 ¶
- Variables
- func Check(file *source.File, opts Options) bool
- func Convert(v value.Value, to string) (value.Value, string)
- func Eval(name, src string, opts Options) (value.Value, error)
- func Nodes(prog *ast.Program) []ast.Node
- func Run(file *source.File, opts Options) bool
- type Builtin
- type Error
- type Function
- type Interp
- type Module
- type Options
- type RecordDef
- type Session
Constants ¶
This section is empty.
Variables ¶
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
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 ¶
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 ¶
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 Run ¶
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.
type Error ¶
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.
type Function ¶
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.
type Interp ¶
type Interp struct {
Out io.Writer
Err io.Writer
In io.Reader
// contains filtered or unexported fields
}
Interp evaluates programs.
func (*Interp) Globals ¶
func (i *Interp) Globals() *env
Globals exposes the top-level scope, so a host can seed it.
func (*Interp) Modules ¶
Modules exposes declared modules, so a standard library evaluated separately can be carried into a later run.
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.
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
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 ¶
NewSession starts a session with the standard library loaded.
func (*Session) Declared ¶ added in v1.0.0
Declared lists the names earlier fragments introduced, in sorted order, so a REPL can show what is in scope.
func (*Session) Eval ¶
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.