formula

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Sep 27, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package formula is the formula language: A1 references and ranges, sheet names in references, the lexer and Pratt parser, the syntax tree, the printer that writes trees back in Sheets' spelling, and the rewriting of references when cells are copied, moved, inserted or deleted. It knows nothing of cells or values: the engine evaluates the trees, and tells the parser which functions exist.

Index

Constants

View Source
const (
	MaxCols = 16384
	MaxRows = 1048576
)

Worksheet bounds, matching Excel (A..XFD, 1..1048576). A reference past them isn't a reference: XFE1 reads as a name.

View Source
const MaxDepth = 1024

MaxDepth is how deeply a formula may nest: parentheses, function calls and prefix operators each open a level (an operator of higher precedence may add one or two). Excel allows 64 nested functions; this is far more than a formula written by hand needs, and it bounds the recursion of everything that walks a formula (the parser, printer, evaluator and reference rewriting), so a pathological file fails to parse rather than exhausting the stack.

Variables

This section is empty.

Functions

func AxisMaps

func AxisMaps(rows bool, sp Span) (func(Addr) (Addr, bool), func(Rect) (Rect, bool))

AxisMaps are the cell and range mappings for inserting or deleting rows (rows true) or columns, for Relocate.

func ColName

func ColName(c int) string

ColName converts a zero-based column index to letters: 0 -> A, 26 -> AA, 702 -> AAA.

func EachChild added in v0.2.0

func EachChild(n Node, fn func(Node))

EachChild calls fn with every expression directly inside n: operands, arguments and array elements.

func Expr

func Expr(n Node) string

Expr prints an expression without the leading "=", e.g. to quote part of a formula.

func LooksLikeRef

func LooksLikeRef(k string) bool

LooksLikeRef reports whether an upper-case name reads as a cell in A1 or R1C1 style, even beyond this sheet's edges, so names stay unambiguous in other spreadsheets too.

func ParseCol

func ParseCol(s string) (int, bool)

ParseCol converts column letters (case-insensitive) to a zero-based index.

func ParseLines

func ParseLines(from, to string) (Rect, [2]Abs, bool)

ParseLines parses the ends of whole columns ("A", "$C") or whole rows ("2", "$5") as the range they span, with their absolute markers.

func ParseRef

func ParseRef(s string) (Addr, Abs, bool)

ParseRef parses a reference written as A1, $A1, A$1 or $A$1.

func Qualified

func Qualified(sheet string, r Rect) string

Qualified writes r on sheet as a formula would: Sheet2!A1:B3.

func QuoteSheet

func QuoteSheet(name string) string

QuoteSheet writes a sheet name as a formula needs it: bare when it reads as a plain identifier (Sheet2), otherwise in single quotes with quotes doubled, e.g. 'Q3 plan'.

func RangeString

func RangeString(r Rect, abs [2]Abs) string

RangeString writes a range as written in a formula, with its absolute markers: A1:B3, $A$1:B3, or whole columns (A:C) and rows (2:5).

func RefString

func RefString(a Addr, abs Abs) string

RefString writes a with its absolute markers, e.g. $A1.

func SheetKey

func SheetKey(name string) string

SheetKey is how sheet names compare: ignoring case, as in Sheets.

func SplitSheet

func SplitSheet(s string) (sheet, rest string)

SplitSheet splits a reference such as "Sheet2!A1:B3" or "'Q3 plan'!B2" into the sheet name, unquoted, and the rest. Without a sheet, sheet is "" and rest is s.

func Text

func Text(n Node) string

Text prints a parsed formula back to text, with a leading "=". Rewritten formulas (after a paste or an inserted row) are stored this way, in Sheets' spelling: ranges as A1:B3, functions without @.

func WalkNames

func WalkNames(n Node, fn func(Name))

WalkNames calls fn for every name in n. It walks the tree itself rather than through EachChild, as every formula entered is walked.

func WalkRefs

func WalkRefs(n Node, ref func(string, Addr), rng func(string, Rect))

WalkRefs calls fn for every single-cell reference and range in n, with the sheet it was qualified with ("" for the formula's own sheet).

Types

type Abs

type Abs uint8

Abs records which parts of a reference are absolute ($A$1). Copying a formula shifts only the relative parts.

const (
	AbsCol Abs = 1 << iota
	AbsRow
)

type Addr

type Addr struct {
	Col, Row int
}

Addr identifies a cell by zero-based column and row.

func ParseAddr

func ParseAddr(s string) (Addr, bool)

ParseAddr parses an A1-style reference. Absolute markers ($A$1) are accepted and ignored.

func (Addr) String

func (a Addr) String() string

String returns the A1-style name of the cell.

func (Addr) Valid

func (a Addr) Valid() bool

Valid reports whether a lies inside the worksheet.

type Array added in v0.2.0

type Array struct{ Rows [][]Node }

Array is an array literal, {1,2;3,4}: rows of elements separated by ";", elements by ",". An element may itself be a range or an array, as {A1:A3,B1:B3} joins two columns.

type Binary

type Binary struct {
	Op   string
	L, R Node
}

type Binding added in v0.2.0

type Binding uint8

Binding is how a function's arguments bind names (Local).

const (
	BindNone Binding = iota
	// BindLet: LET(name1, value1, [name2, value2, ...], expression),
	// each name bound for the arguments after it.
	BindLet
	// BindLambda: LAMBDA([name, ...], expression), the names bound in
	// the expression.
	BindLambda
)

type Bool

type Bool struct{ V bool }

type Call

type Call struct {
	Fn   Func
	Args []Node
}

type Empty

type Empty struct{} // an omitted argument, as in XLOOKUP(a, b, c, , 1)

type Func

type Func interface {
	Signature() Signature
}

Func is a function a formula can call. The parser checks calls against its signature; what a call computes is up to the engine, which recovers its own type from Call.Fn.

type Funcs

type Funcs func(name string) (Func, bool)

Funcs finds a function by its upper-case name or alias.

type Invoke added in v0.2.0

type Invoke struct {
	Fn   Node
	Args []Node
}

Invoke calls what Fn computes to, a LAMBDA, with Args: LAMBDA(x, x*2)(3), or f(3) where LET bound f to a LAMBDA.

type Local added in v0.2.0

type Local struct{ Name string }

Local is a name LET or LAMBDA binds, used within that call, as in LET(total, SUM(A:A), total*2). Named ranges never replace it.

type Name

type Name struct{ Name string } // a named range as spelled in the formula

type Node

type Node any

Node is a parsed formula expression: one of the types below.

func Parse

func Parse(src string, funcs Funcs) (Node, error)

Parse parses a formula, finding the functions it calls with funcs. src may start with "=", as typed in a cell; error positions are relative to src.

func Rewrite

func Rewrite(n Node, rw Rewriter) (Node, bool)

Rewrite returns n with its references mapped, and whether anything changed. Unchanged subtrees are shared.

type Num

type Num struct{ V float64 }

type ParseError

type ParseError struct {
	Pos int
	Msg string
}

ParseError describes a formula that could not be parsed. Pos is the byte offset in the entry where the problem was found, used to place the edit cursor.

func (*ParseError) Error

func (e *ParseError) Error() string

type Range

type Range struct {
	Rect  Rect
	Abs   [2]Abs
	Sheet string
}

Range is kept normalized (Rect.From is the top-left corner); Abs holds the absolute markers of Rect.From and Rect.To.

func NewRange

func NewRange(a, b Addr, aAbs, bAbs Abs) Range

NewRange builds a normalized range from two corners as written. Each absolute marker stays with its column or row, so $B1:A$2 becomes A1:$B$2.

type Rect

type Rect struct {
	From, To Addr
}

Rect is an inclusive rectangular range of cells.

func NewRect

func NewRect(a, b Addr) Rect

NewRect returns the normalized rectangle spanning a and b.

func ParseRange

func ParseRange(s string) (Rect, bool)

ParseRange parses "A1", "A1:B3", 1-2-3 style "A1..B3", or whole columns "A:C" and rows "2:5".

func (Rect) AllCols

func (r Rect) AllCols() bool

AllCols reports whether r spans every column: whole rows, 1:1.

func (Rect) AllRows

func (r Rect) AllRows() bool

AllRows reports whether r spans every row: whole columns, A:A.

func (Rect) Contains

func (r Rect) Contains(a Addr) bool

Contains reports whether a lies inside r.

func (Rect) String

func (r Rect) String() string

String returns the range as A1:B3, A1 for a single cell, or A:C and 2:5 for whole columns and rows.

type Ref

type Ref struct {
	Addr  Addr
	Abs   Abs
	Sheet string
}

Ref is a cell reference. Sheet is the sheet name as written before the "!" (Sheet2!A1), or "" for the formula's own sheet.

type RefErr

type RefErr struct{} // a reference to deleted cells: #REF!

type Rewriter

type Rewriter struct {
	Ref   func(Ref) Node
	Range func(Range) Node
	Name  func(Name) Node
	Local func(Local) Node
}

Rewriter maps the references in a formula. Any function may return RefErr; a nil function leaves those nodes alone.

func Relocate

func Relocate(on func(sheet string) bool, cell func(Addr) (Addr, bool), rng func(Rect) (Rect, bool)) Rewriter

Relocate is the rewrite for cells that move on one sheet: cell maps where each cell went (false if it's gone), and rng maps whole ranges. on reports whether a reference written with a sheet name ("" for none) points at the sheet whose cells moved; other references stay.

func Shift

func Shift(dc, dr int) Rewriter

Shift is the rewrite for copying a formula by (dc, dr): relative parts move, $absolute parts stay, and references pushed off the sheet become #REF!.

type Signature

type Signature struct {
	Name string // canonical, upper case
	Args string // shown to users, e.g. "value1, [value2, ...]"
	Min  int
	Max  int // -1 for variadic
	// Step > 0 means arguments after Min come in groups of Step, like
	// SUMIFS' (range, criterion) pairs.
	Step int
	// Binds says which arguments name values for the rest of the call,
	// as LET's and LAMBDA's do.
	Binds Binding
}

Signature is how a function is called.

type Span

type Span struct{ At, N, Size int }

Span inserts (N > 0) or deletes (N < 0) lines starting at index At, along an axis with Size lines.

func (Span) Interval

func (sp Span) Interval(lo, hi int) (int, int, bool)

Interval maps a range's lines lo..hi as Sheets does: inserting inside the range grows it, deleting part of it shrinks it, and deleting all of it leaves #REF!.

func (Span) Point

func (sp Span) Point(v int) (int, bool)

Point maps a line index; false if the line was deleted or pushed off the end.

type Str

type Str struct{ V string }

type Unary

type Unary struct {
	Op string // "-", "+", "%" (postfix) or "#NOT#"
	X  Node
}

Jump to

Keyboard shortcuts

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