ast

package
v2.2.9 Latest Latest
Warning

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

Go to latest
Published: May 14, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package ast defines the Abstract Syntax Tree node types for CalcMark

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ContainsScaleRef

func ContainsScaleRef(node Node) bool

ContainsScaleRef returns true if the AST node tree contains a DirectiveRef with Directive=="scale". Used by the scale transform to exempt statements that explicitly reference @scale.

Types

type AsPercentOf

type AsPercentOf struct {
	Numerator   Node // The value to express as a percentage
	Denominator Node // The reference value (the "whole")
	Range       *Range
}

AsPercentOf represents "X as % of Y" — computes the ratio X/Y as a Percentage. This is the inverse of PercentageOf: "20% of 500" = 100, "100 as % of 500" = 20%.

func (*AsPercentOf) GetRange

func (a *AsPercentOf) GetRange() *Range

func (*AsPercentOf) String

func (a *AsPercentOf) String() string

type Assignment

type Assignment struct {
	Name  string
	Value Node
	Range *Range
}

Assignment represents a variable assignment

func (*Assignment) GetRange

func (a *Assignment) GetRange() *Range

func (*Assignment) String

func (a *Assignment) String() string

type BetweenExpr

type BetweenExpr struct {
	// Start is the period's first day; End is its last (closed
	// interval, day precision -- mirrors *types.Period).
	Start Node
	End   Node

	// SourceText is the original source slice for diagnostics +
	// AST round-tripping.
	SourceText string

	Range *Range
}

BetweenExpr represents `between A and B` / `from A to B` -- a user-defined custom Period spanning two Date endpoints. Both endpoints are generic Node so any expression typing as Date is well-formed at the AST layer; semantic check (spec/semantic) is where Date typing + start <= end constraints are enforced. The runtime constructs a *types.Period (PeriodCustom kind) from the evaluated endpoints.

func (*BetweenExpr) GetRange

func (b *BetweenExpr) GetRange() *Range

func (*BetweenExpr) String

func (b *BetweenExpr) String() string

type BinaryOp

type BinaryOp struct {
	Operator string
	Left     Node
	Right    Node
	Range    *Range
}

BinaryOp represents a binary operation (+, -, *, /, etc.)

func (*BinaryOp) GetRange

func (b *BinaryOp) GetRange() *Range

func (*BinaryOp) String

func (b *BinaryOp) String() string

type BooleanLiteral

type BooleanLiteral struct {
	Value string // "true", "false", "yes", "no", etc.
	Range *Range
}

BooleanLiteral represents a boolean literal

func (*BooleanLiteral) GetRange

func (b *BooleanLiteral) GetRange() *Range

func (*BooleanLiteral) String

func (b *BooleanLiteral) String() string

type ComparisonOp

type ComparisonOp struct {
	Operator string // ">", "<", ">=", "<=", "==", "!="
	Left     Node
	Right    Node
	Range    *Range
}

ComparisonOp represents a comparison operation (>, <, ==, etc.)

func (*ComparisonOp) GetRange

func (c *ComparisonOp) GetRange() *Range

func (*ComparisonOp) String

func (c *ComparisonOp) String() string

type CurrencyLiteral

type CurrencyLiteral struct {
	Symbol     string // Currency symbol or code
	Value      string // Numeric value
	SourceText string // Original text for debugging
	Range      *Range
}

CurrencyLiteral represents a currency value (e.g., "$100", "50 EUR").

func (*CurrencyLiteral) GetRange

func (c *CurrencyLiteral) GetRange() *Range

func (*CurrencyLiteral) String

func (c *CurrencyLiteral) String() string

type DateLiteral

type DateLiteral struct {
	Month string // "Dec", "December"
	Day   string // "25" — the literal day. When the user wrote no
	// day number in source, Day is "1" (lexer default) AND
	// HasExplicitDay is false.
	Year *string // nil if not provided, "2024" if provided

	// HasExplicitDay reports whether a day number was scanned from
	// the source. Discriminates `April 1` (true: specific date) from
	// `April` (false: bare month, semantically a Period). The parser
	// uses this flag to route bare-month forms to RelativeDateLiteral
	// instead of DateLiteral. Lexer-driven so the discriminator
	// doesn't depend on substring inspection of SourceText (which
	// drifts with whitespace / future lexer changes).
	HasExplicitDay bool

	SourceText string
	Range      *Range
}

DateLiteral represents a date literal: "Dec 25" or "Dec 25 2024"

func (*DateLiteral) GetRange

func (d *DateLiteral) GetRange() *Range

func (*DateLiteral) String

func (d *DateLiteral) String() string

type DirectiveRef

type DirectiveRef struct {
	Directive string // "scale" or "globals" (or any identifier — semantic checker validates)
	Field     string // "" for @scale, "tax_rate" for @globals.tax_rate
	Range     *Range
}

DirectiveRef represents a reference to a frontmatter directive (@scale, @globals.name).

func (*DirectiveRef) GetRange

func (d *DirectiveRef) GetRange() *Range

func (*DirectiveRef) String

func (d *DirectiveRef) String() string

type DurationLiteral

type DurationLiteral struct {
	Value      string // Numeric value ("5", "3.5", etc.)
	Unit       string // Time unit ("days", "hours", "minutes", etc.)
	SourceText string // Original text from source
	Range      *Range
}

DurationLiteral represents a duration literal: "5 days", "3 hours"

func (*DurationLiteral) GetRange

func (d *DurationLiteral) GetRange() *Range

func (*DurationLiteral) String

func (d *DurationLiteral) String() string

type EndOfExpr

type EndOfExpr struct {
	// Period is the inner expression. Must type as Period at semantic
	// check time; runtime panics if non-Period flows through. Parser
	// uses parsePrimary() so precedence is preserved
	// (`end of Q1 + 1 day` parses as `(end of Q1) + 1 day`).
	Period Node

	// SourceText is the original source slice ("end of Q1") for
	// diagnostics + AST round-tripping.
	SourceText string

	Range *Range
}

EndOfExpr represents `end of <period>` -- the operator that resolves a Period-typed inner expression to its last day. The inner is a generic Node so any expression that types as Period (literal, identifier-bound period, parenthesized period expression) parses uniformly. Type-check enforcement of "must be a Period" lives in spec/semantic; at the AST layer the constraint is unenforced -- a NumberLiteral here is well-formed but semantically rejected.

Replaces the previous string-flatten in spec/parser/primary.go which produced ast.RelativeDateLiteral{Keyword: "end of " + innerKeyword} -- losing the inner's structure, bounding the inner-token set to an enumeration, and forcing string-prefix dispatch in the interpreter.

func (*EndOfExpr) GetRange

func (e *EndOfExpr) GetRange() *Range

func (*EndOfExpr) String

func (e *EndOfExpr) String() string

type Expression

type Expression struct {
	Expr  Node
	Range *Range
}

Expression represents a standalone expression (no assignment)

func (*Expression) GetRange

func (e *Expression) GetRange() *Range

func (*Expression) String

func (e *Expression) String() string

type FractionLiteral

type FractionLiteral struct {
	Numerator   int64  // The numerator value
	Denominator int64  // The denominator value
	Unit        string // Optional unit (e.g., "cup" for "1/3 cup"), empty if dimensionless
	SourceText  string // Original text from source (e.g., "1/3")
	Range       *Range
}

FractionLiteral represents a fraction literal (e.g., "1/3", "7/8", "1/3 cup"). Numerator and Denominator are stored as int64, parsed once at parse time.

func (*FractionLiteral) GetRange

func (f *FractionLiteral) GetRange() *Range

func (*FractionLiteral) String

func (f *FractionLiteral) String() string

type FunctionCall

type FunctionCall struct {
	Name      string // Canonical function name: "avg", "sqrt"
	Arguments []Node
	Range     *Range
}

FunctionCall represents a function call (avg, sqrt, etc.)

func (*FunctionCall) GetRange

func (f *FunctionCall) GetRange() *Range

func (*FunctionCall) String

func (f *FunctionCall) String() string

type Identifier

type Identifier struct {
	Name  string
	Range *Range
}

Identifier represents a variable identifier

func (*Identifier) GetRange

func (i *Identifier) GetRange() *Range

func (*Identifier) String

func (i *Identifier) String() string

type LengthOfExpr

type LengthOfExpr struct {
	// Period is the inner expression. Must type as Period at
	// semantic check time. Parser uses parsePrimary() so precedence
	// is preserved.
	Period Node

	// AsNumber discriminates the surface form: false = `length of`
	// (returns Duration); true = `days in` (returns Number, integer
	// day count).
	AsNumber bool

	// SourceText is the original source slice.
	SourceText string

	Range *Range
}

LengthOfExpr represents `length of <Period>` (returns Duration) and `days in <Period>` (returns Number). Both forms desugar to the same node; AsNumber discriminates the return shape.

AST layer doesn't enforce that Period types as Period -- semantic (spec/semantic) does. Period field is generic Node so any expression typing as Period (literal, variable-bound, parenthesized) parses uniformly.

func (*LengthOfExpr) GetRange

func (l *LengthOfExpr) GetRange() *Range

func (*LengthOfExpr) String

func (l *LengthOfExpr) String() string

type NapkinConversion

type NapkinConversion struct {
	Expression Node
	Range      *Range
}

NapkinConversion represents human-readable number formatting (e.g., "1234567 as napkin").

func (*NapkinConversion) GetRange

func (n *NapkinConversion) GetRange() *Range

func (*NapkinConversion) String

func (n *NapkinConversion) String() string

type Node

type Node interface {
	String() string
	GetRange() *Range
}

Node is the interface that all AST nodes implement

type NumberLiteral

type NumberLiteral struct {
	Value      string // Normalized value (e.g., "1000" for both "1000" and "1,000")
	SourceText string // Original text from source (e.g., "1,000", "1k", "10000")
	Range      *Range
}

NumberLiteral represents a numeric literal

func (*NumberLiteral) GetRange

func (n *NumberLiteral) GetRange() *Range

func (*NumberLiteral) String

func (n *NumberLiteral) String() string

type PercentageOf

type PercentageOf struct {
	Percentage Node // The percentage value (e.g., NumberLiteral for "10%")
	Value      Node // The value to take percentage of
	Range      *Range
}

PercentageOf represents percentage of a value (e.g., "10% of 200").

func (*PercentageOf) GetRange

func (p *PercentageOf) GetRange() *Range

func (*PercentageOf) String

func (p *PercentageOf) String() string

type Position

type Position struct {
	Line   int
	Column int
}

Position represents a position in source text (1-indexed)

func (Position) String

func (p Position) String() string

String formats the position as "line:column"

type PreciseConversion

type PreciseConversion struct {
	Expression Node
	Range      *Range
}

PreciseConversion represents full-precision display (e.g., "1 second as hour as precise").

func (*PreciseConversion) GetRange

func (n *PreciseConversion) GetRange() *Range

func (*PreciseConversion) String

func (n *PreciseConversion) String() string

type QuantityLiteral

type QuantityLiteral struct {
	Value      string // The numeric value (used when Expr is nil)
	Expr       Node   // Expression providing the value (e.g., DirectiveRef); nil for literal quantities
	Unit       string // The unit identifier
	SourceText string // Original text
	Range      *Range
}

QuantityLiteral represents a number with a unit (e.g., "5 kg", "10 meters"). When Expr is non-nil, the quantity value comes from evaluating the expression (e.g., "@scale meters" uses a DirectiveRef as the value source).

func (*QuantityLiteral) GetRange

func (q *QuantityLiteral) GetRange() *Range

func (*QuantityLiteral) String

func (q *QuantityLiteral) String() string

type Range

type Range struct {
	Start Position
	End   Position
}

Range represents a range in source text

func SpanNodes

func SpanNodes(left, right Node) *Range

SpanNodes returns a Range spanning from the start of left to the end of right. Returns the best partial range if one side is nil; returns nil if both are nil.

func (Range) String

func (r Range) String() string

String formats the range as "start-end"

type RateLiteral

type RateLiteral struct {
	Amount     Node   // The quantity numerator (e.g., QuantityLiteral for "100 MB")
	PerUnit    string // The time unit denominator (e.g., "second", "hour", "day")
	SourceText string //Original text
	Range      *Range
}

RateLiteral represents a rate expression (e.g., "100 MB/s", "5 GB per day", "$0.10 per hour"). Rates combine a quantity (amount) with a time period.

func (*RateLiteral) GetRange

func (r *RateLiteral) GetRange() *Range

func (*RateLiteral) String

func (r *RateLiteral) String() string

type RelativeDateLiteral

type RelativeDateLiteral struct {
	Keyword    string // "today", "tomorrow", "yesterday", "now"
	SourceText string
	Range      *Range
}

RelativeDateLiteral represents relative date keywords: today, tomorrow, yesterday, now

func (*RelativeDateLiteral) GetRange

func (r *RelativeDateLiteral) GetRange() *Range

func (*RelativeDateLiteral) String

func (r *RelativeDateLiteral) String() string

type StartOfExpr

type StartOfExpr struct {
	Period     Node
	SourceText string
	Range      *Range
}

StartOfExpr is the symmetric partner of EndOfExpr -- resolves a Period to its first day. Parser-level identical to EndOfExpr; interpreter just returns Period.Start unchanged. Useful in expressions where intent matters (e.g. `forecast = start of next fiscal quarter` reads better than the implicit `next fiscal quarter` even though they evaluate the same).

func (*StartOfExpr) GetRange

func (s *StartOfExpr) GetRange() *Range

func (*StartOfExpr) String

func (s *StartOfExpr) String() string

type TimeLiteral

type TimeLiteral struct {
	Hour       string     // "10", "14"
	Minute     string     // "30"
	Second     *string    // nil or "45"
	Period     *string    // nil, "AM", or "PM"
	UTCOffset  *UTCOffset // nil or offset spec
	SourceText string
	Range      *Range
}

TimeLiteral represents a time literal: "10:30AM", "14:30", "10:30:45PM", "10:30AM UTC-7"

func (*TimeLiteral) GetRange

func (t *TimeLiteral) GetRange() *Range

func (*TimeLiteral) String

func (t *TimeLiteral) String() string

type UTCOffset

type UTCOffset struct {
	Sign    string  // "+" or "-"
	Hours   string  // "7", "5"
	Minutes *string // nil or "30" (for UTC+5:30)
}

UTCOffset represents a UTC timezone offset: UTC-7, UTC+5:30

func (*UTCOffset) String

func (u *UTCOffset) String() string

type UnaryOp

type UnaryOp struct {
	Operator string
	Operand  Node
	Range    *Range
}

UnaryOp represents a unary operation (-, +)

func (*UnaryOp) GetRange

func (u *UnaryOp) GetRange() *Range

func (*UnaryOp) String

func (u *UnaryOp) String() string

type UnitConversion

type UnitConversion struct {
	Quantity       Node   // The quantity expression to convert
	TargetUnit     string // The target unit to convert to
	TargetTimeUnit string // For rate conversions: the target time unit (e.g., "s" in "inch/s")
	Range          *Range
}

UnitConversion represents explicit unit conversion (e.g., "10 meters in feet"). For rate conversions (e.g., "10 m/s in inch/s"), TargetTimeUnit is set.

func (*UnitConversion) GetRange

func (u *UnitConversion) GetRange() *Range

func (*UnitConversion) String

func (u *UnitConversion) String() string

Jump to

Keyboard shortcuts

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