formula

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: MIT Imports: 7 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 Delocalize added in v0.3.0

func Delocalize(src string, loc *locale.Locale) string

Delocalize reads a formula typed in loc's syntax into the syntax it is stored and parsed in. It works on unfinished formulas too.

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 EscapeColumn added in v0.3.0

func EscapeColumn(name string) string

EscapeColumn writes a column's name as a structured reference holds it, with ' before each of [ ] # and '.

func ExcelTableRef added in v0.3.0

func ExcelTableRef(src string) (string, bool)

ExcelTableRef writes a structured reference, the table's name and its brackets as written in src, in Excel's file syntax, or reports false when it doesn't parse.

func Expr

func Expr(n Node) string

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

func Localize added in v0.3.0

func Localize(src string, loc *locale.Locale) string

Localize writes a formula (or any part of one) as stored in loc's syntax. Strings and sheet names are left alone.

func LocalizeError added in v0.3.0

func LocalizeError(err error, loc *locale.Locale) error

LocalizeError writes the message of a parse error in err (the error itself, or one it wraps) in loc's syntax, as the formula was typed: "Expected ; or ) in ROUND" where arguments are separated by ;, and the text typed where it names what it didn't expect. The position is the same in both syntaxes.

func LooksLikeCell added in v0.3.0

func LooksLikeCell(k string) bool

LooksLikeCell reports whether an upper-case name reads as a cell in Excel, A1 to XFD1048576 or R1C1, so a sheet of that name is quoted everywhere its formulas may go. Sheet1 doesn't: SHEET is no column.

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 SameSyntax added in v0.3.0

func SameSyntax(loc *locale.Locale) bool

SameSyntax reports whether loc writes formulas as they are stored.

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 StructuredEnd added in v0.3.0

func StructuredEnd(src string, i int) int

StructuredEnd returns the index just past the brackets of a structured reference whose "[" is at src[i], or -1 when they aren't closed.

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).

func WalkTables added in v0.3.0

func WalkTables(n Node, fn func(TableRef))

WalkTables calls fn for every structured reference in n.

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
	// contains filtered or unexported fields
}

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
	Table func(TableRef) 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 TableItems added in v0.3.0

type TableItems uint8

TableItems are the rows of a table a structured reference names.

const (
	ItemHeaders TableItems = 1 << iota // the header row: [#Headers]
	ItemData                           // the data rows: [#Data], or nothing
	ItemTotals                         // a totals row: [#Totals]
	ItemThisRow                        // the formula's own row: [#This Row] or @
	// ItemAll is the whole table: [#All].
	ItemAll = ItemHeaders | ItemData | ItemTotals
)

type TableRef added in v0.3.0

type TableRef struct {
	Table string // the table's name as written
	// Items are the rows named; zero means the data rows, as when no
	// item is written.
	Items TableItems
	// From and To are the first and last column named, as written: ""
	// for every column, To "" for From alone.
	From, To string
}

TableRef is a structured reference: Table[Column], Table[#All], Table[@Column], Table[[#Headers],[First]:[Last]].

func (TableRef) Cols added in v0.3.0

func (t TableRef) Cols() (string, string)

Cols are the first and last column the reference names, the same for one column, or "" for every column.

func (TableRef) Excel added in v0.3.0

func (t TableRef) Excel() string

Excel writes the reference as Excel's files hold it, where the formula's own row is [#This Row] rather than @.

func (TableRef) Rows added in v0.3.0

func (t TableRef) Rows() TableItems

Rows are the rows the reference names, with no item meaning the data rows.

func (TableRef) String added in v0.3.0

func (t TableRef) String() string

String writes the reference as 012 prints it: Sales[Amount], Sales[@Amount], Sales[[#Headers],[Amount]].

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