Documentation
¶
Overview ¶
Package ast defines the Abstract Syntax Tree node types for CalcMark
Index ¶
- func ContainsScaleRef(node Node) bool
- func SetRangeIfMissing(n Node, r *Range)
- type AsPercentOf
- type Assignment
- type BetweenExpr
- type BinaryOp
- type BooleanLiteral
- type ComparisonOp
- type CurrencyLiteral
- type DateLiteral
- type DirectiveRef
- type DurationLiteral
- type EndOfExpr
- type Expression
- type FractionLiteral
- type FunctionCall
- type Identifier
- type LengthOfExpr
- type MemberAccess
- type NapkinConversion
- type Node
- type NumberLiteral
- type PercentageOf
- type Position
- type PreciseConversion
- type QuantityLiteral
- type Range
- type RateLiteral
- type RelativeDateLiteral
- type StartOfExpr
- type TimeLiteral
- type UTCOffset
- type UnaryOp
- type UnitConversion
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ContainsScaleRef ¶
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.
func SetRangeIfMissing ¶ added in v2.3.0
SetRangeIfMissing gives n the range r when n has no usable range yet. A nil Range and a zero-valued Range (`&Range{}`) both count as missing. Nodes that already know their position keep it, so callers can apply this unconditionally at parser boundaries without clobbering the tighter ranges set by inner constructors.
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 ¶
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 BooleanLiteral ¶
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
}
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.
type Expression ¶
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 ¶
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 MemberAccess ¶ added in v2.3.0
type MemberAccess struct {
Object Node // the table reference, normally an *Identifier
Field string // column name
Range *Range
}
DirectiveRef represents a reference to a frontmatter directive (@scale, @globals.name). MemberAccess is dot access on a named table: `rates.rate` reads the `rate` column of the `rates` table as an Array (go-calcmark#118). Distinct from DirectiveRef (`@globals.field`). Nested access (`a.b.c`) is rejected by the parser.
func (*MemberAccess) GetRange ¶ added in v2.3.0
func (m *MemberAccess) GetRange() *Range
func (*MemberAccess) String ¶ added in v2.3.0
func (m *MemberAccess) String() string
type NapkinConversion ¶
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 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 PreciseConversion ¶
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 ¶
Range represents a range in source text
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 ¶
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
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