Documentation
¶
Overview ¶
Package functions is 012's function library: the FuncDef table, the evaluation of formulas (operators and calls), the argument, range and criteria helpers functions share, decimal arithmetic, and the questions JEV functions ask.
It knows nothing of sheets or storage. A formula reads cells through a Reader over a Book, which the engine (internal/sheet) implements, and the engine finds functions through the table (LookupFunc) when it parses formulas. Dependencies point one way: formula and value below, the engine above.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // Pending is shown while an answer is on its way. Pending = Value{Kind: value.Error, Str: "Loading…"} // ErrNoRemote means JEV functions can't run: there is no API key. ErrNoRemote = Value{Kind: value.Error, Str: "#N/A"} )
var ErrRemote = Value{Kind: value.Error, Str: "#ERROR!"}
ErrRemote is a question the model couldn't answer, e.g. a network failure; the context line says why.
Functions ¶
func IsVolatile ¶
IsVolatile reports whether n calls a function whose result changes without its inputs changing (TODAY, NOW, RAND).
Types ¶
type Addr ¶
Addr identifies a cell by zero-based column and row.
func Intersect ¶
Intersect is the cell of r a formula in the cell at reads where it wants one value: a single cell is itself; a single column gives the cell in at's row, a single row the cell in at's column, when that lies within r (implicit intersection, on whatever sheet r is on). Any other range has no such cell, which is #VALUE!.
type Agg ¶
type Agg struct {
// contains filtered or unexported fields
}
Agg is the running aggregate of SUM-like functions (SUM, AVERAGE, COUNT, COUNTA, MIN, MAX, PRODUCT): what they read of a range, added in order. The engine keeps one per range shared by a recalculation (Book.RangeAgg).
type Book ¶
type Book interface {
// Cell is the current value of a cell, evaluated first if it's
// dirty; #REF! on a sheet that doesn't exist.
Cell(sheet string, a Addr) Value
// Scan reads the cells of r that hold something, row by row, from
// the cell from on (those before it in that order are skipped): their
// addresses into addrs and, unless vals is nil, their values into
// vals, evaluating them as Cell does. It stops when addrs is full or
// just after a value that is an error, so no cell past the first
// error is evaluated, and returns how many it read: -1 when the sheet
// doesn't exist.
Scan(sheet string, r Rect, from Addr, addrs []Addr, vals []Value) int
// Bounds is the smallest range holding every stored cell of r, with
// false if r holds none; exists is false when the sheet doesn't.
Bounds(sheet string, r Rect) (b Rect, any, exists bool)
// RangeAgg is the aggregate of r that SUM-like functions share within
// a recalculation (see Agg), with the first error in it, or false
// when r should be read directly.
RangeAgg(sheet string, r Rect) (Agg, *Value, bool)
// Fold adds the cells of r that hold something to s, row by row, as
// SUM-like functions read a range (Agg.Add), evaluating them as Cell
// does and stopping at the first error, which it returns. On a sheet
// that doesn't exist the range is one #REF!.
Fold(sheet string, r Rect, s Agg) (Agg, *Value)
// Ask looks up the answer to a remote question (JEV functions). The
// value is an error when there is none to give: Pending while it is
// on its way, ErrNoRemote when nothing answers them.
Ask(call RemoteCall) (RemoteAnswer, Value)
}
Book is how formulas reach the workbook: the engine implements it, once for each sheet whose formulas it evaluates. Sheets are named as references write them; "" is the formula's own sheet.
Every method takes and returns plain values, never a callback: a function value or pointer passed through an interface escapes to the heap, so a callback per range read would cost an allocation that an engine reading its own cells doesn't pay. Ranges are read instead in chunks, into buffers the Reader keeps and reuses (Scan), and each function walks them with callbacks of its own that stay on the stack.
type Format ¶
Format is a cell's number format.
func InferFormat ¶
InferFormat picks the format Sheets shows a formula's result in when the cell is Automatic: dates from date functions, and otherwise the format of the first formatted input, so =B2+B3 of currency shows currency and a date plus days shows a date.
type FuncDef ¶
type FuncDef struct {
Name string
Args string // signature shown to users, e.g. "value1, [value2, ...]"
Desc string
Min int
Max int // -1 for variadic
// Volatile functions (TODAY, NOW, RAND) change without their inputs
// changing, so every recalculation recomputes them.
Volatile bool
// contains filtered or unexported fields
}
FuncDef describes a spreadsheet function. The table drives parsing (arity checks), evaluation, autocomplete and help.
func LookupFunc ¶
LookupFunc finds a function by name or alias, case-insensitively (callers pass upper case).
func Of ¶
Of is the function a parsed call calls: always one of the table's, as long as the parser found functions through LookupFunc.
func (*FuncDef) Question ¶
func (f *FuncDef) Question(args []Node, get *Reader) (RemoteCall, error)
Question is the remote question a call of f asks with its current arguments, or an error when they don't make one.
type Node ¶
Node is a parsed formula expression.
func Decimalize ¶
Decimalize returns a copy of n that evaluates in decimal: operators are marked, and functions with a decimal twin call it.
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader is what a function is given to read the cells its arguments refer to: a Book, and the buffers ranges are read through. It is a concrete type so the callbacks functions pass to it stay on the stack.
func NewReader ¶
NewReader reads cells through book. depth counts how deeply evaluation nests (cells, operators and calls), for the engine to put off cells past its limit. With dense, functions read every address of their ranges, as they did before ranges were clipped to what they hold, so tests can check that the two agree.
type RemoteAnswer ¶
type RemoteAnswer struct {
Noul float64 // probability of yes
Choice string
Score float64
Confidence float64 // in Choice or Score, not a probability of truth
Failed string
}
RemoteAnswer is the model's answer. Which fields are set depends on the call's Kind; Failed explains an answer that couldn't be had.
type RemoteCall ¶
type RemoteCall struct {
Kind string `json:"kind"` // "noul", "choice" or "score"
State any `json:"state"`
Instructions string `json:"instructions"`
// Criteria depends on Kind: noul is [2]string{yes, no} (either may be
// empty), choice is map[label]description, score is []string levels.
Criteria any `json:"criteria"`
}
RemoteCall is one question for the model, built from a function's arguments. It isn't comparable: Key identifies it by its content.
func (RemoteCall) Key ¶
func (c RemoteCall) Key() string
Key identifies a question by its content: the answer cache and the engine's list of cells waiting for answers are keyed by it. JEV cells are volatile, so every recalculation looks each one up: with thousands of them, encoding the key with encoding/json took most of the time an answer spent in recalc. The shapes a RemoteCall holds are encoded by hand, each value tagged and each string length-prefixed so different calls never share a key; anything else falls back to JSON.
type RemoteSource ¶
type RemoteSource interface {
Lookup(RemoteCall) (RemoteAnswer, bool)
}
RemoteSource answers RemoteCalls. Lookup returns false while an answer isn't known, and queues the call.
type Value ¶
Value is the computed contents of a cell.
func Eval ¶
Eval computes a formula, reading the cells it refers to through get. A range where one value is wanted reads as the cell in the row or column last given to EvalAt (see intersect).
func EvalAt ¶
EvalAt computes the formula in the cell at, so that a range used where one value is wanted reads as the cell in at's row or column (implicit intersection, as Sheets and Excel do). Evaluations nest, one cell's formula reading another's through the same Reader, so the cell before is given back afterwards.