expr

package
v0.16.14 Latest Latest
Warning

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

Go to latest
Published: Jun 15, 2026 License: MPL-2.0 Imports: 4 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func HasRef

func HasRef(segs []TextSegment) bool

HasRef returns true if any segment is a reference.

func IsFlexBlock

func IsFlexBlock(toks []RefNode) bool

IsFlexBlock reports whether the token slice begins with a flexion sigil (`%`, `@`, `~`, or `#N`), meaning ParseFlexBlock should be used instead of ParseReference. A lone `%var` (with optional path) is NOT a FlexBlock — it is a FmtBlock (see IsFmtBlock), routed to FmtPrinter for locale-aware formatting.

func IsFmtBlock

func IsFmtBlock(toks []RefNode) bool

IsFmtBlock reports whether toks is a lone %var with an optional path tail and optional :formatName suffix, and nothing else. Malformed path tails (e.g. trailing `.`) return false so the caller surfaces the error via ParseFmtBlock.

func IsPureReference

func IsPureReference(tree []RefNode) bool

IsPureReference returns true if the tree contains no literals (str/num/txt), i.e., it is a pure path of identifiers/expr (useful for two-way binding).

func IsPureSegs

func IsPureSegs(segs []TextSegment) bool

IsPureSegs returns true if there is exactly one IsRef segment with a pure reference.

func IsPureTextSegs

func IsPureTextSegs(segs []TextSegment) bool

IsPureTextSegs returns true if all segments are literals (no references).

Types

type FlexBlock

type FlexBlock struct {
	GenderVar  string    // @var root ident, "" when absent (degenerate-gender block)
	GenderPath []RefNode // full @-path (root ident + optional .ident/[expr] tail); nil when @var absent or bare
	CountVar   string    // %var root ident, "" when absent (pure-gender block)
	CountPath  []RefNode // full %-path; nil when %var absent or bare
	Idx        int       // #N rule index, -1 when absent (pre-gen_i18n form)
	TildeWords []string  // ~word lemmas in original order (build-time only)
	Tokens     []RefNode // input token sequence in original order; path-tail tokens consumed
	// by @var/%var are NOT re-emitted here (they are metadata attached to the
	// sigil RefNode that precedes them). For *var/$var/~$var the path tail is
	// stored in the token's Sub field, so Tokens carries enough for runtime
	// assembly in order.
	StarVars   []FlexVarRef // *var participants (CustomFlex engine/selector), in order
	DollarVars []FlexVarRef // $var plain dynamic binds (emitted verbatim), in order
	FlexBinds  []FlexVarRef // ~$var dynamic values to be inflected at runtime, in order
	DefName    string       // =name: names this block's message for reuse, "" when absent
	RefName    string       // #name: reuse — render the message named here, "" when absent
}

FlexBlock holds the resolved pieces of an i18n flexion reference such as `{{@genero %qt #42}}` or `{{@genero %qt ~o ~aluno ...}}`.

At runtime the rewritten form `{{@var %var #N}}` is what reaches the browser. Build-time (`gen_i18n`) also sees the `~word` form, so TildeWords is populated only when parsing the pre-rewrite template.

Tokens preserves the full input token sequence in original order so that build-time dict-consult can re-interleave passthrough words (non-sigil tokens that appear between ~words, e.g., "do terceiro ano que" in "{{@s %q ~o ~aluno do terceiro ano que ~está ~aprovado}}") with the flexed forms pulled from the dictionary.

func ParseFlexBlock

func ParseFlexBlock(toks *[]RefNode) (FlexBlock, error)

ParseFlexBlock consumes a flat sequence of flexion tokens and returns the composed FlexBlock. Enforces the unicity rules locked in the design:

  • at most one %var per block (hard error on second)
  • at most one @var per block (hard error on second)
  • at most one #N per block (hard error on second)

~word tokens are collected in order; repetitions are allowed since adjectives/verbs can legitimately repeat a lemma. Identifier/number/string tokens that appear between sigils are accepted as passthrough words (see the FlexBlock doc for the "do terceiro ano" example). Structural tokens (`.`, `[`, `]`, sub-expressions) are an error — a flex block cannot mix sigil syntax with path-reference syntax.

type FlexVarRef added in v0.15.0

type FlexVarRef struct {
	Var  string
	Path []RefNode
}

FlexVarRef is a resolved variable reference inside a flex block for one of the path-bearing sigils (*var, $var, ~$var). Var is the root identifier; Path is the full reference (root ident + `.field`/`[expr]` tail), nil when the reference is a bare name. Resolution at runtime goes through wings.Solve when Path is non-nil, or the cheap single-level lookup for bare Var.

type FmtBlock

type FmtBlock struct {
	Var        string    // %var root ident
	Path       []RefNode // full path (root ident + tail); nil when bare
	FormatName string    // name after ':' (e.g. "km" in %dist:km); "" when absent
}

FmtBlock holds the resolved pieces of a locale-aware formatting reference such as `{{%preco}}`, `{{%cart[i].total}}`, or `{{%dist:km}}`. The value is resolved at sync time from the data context and rendered by wings.FmtPrinter, which chooses the output format from the Go type of the value, the current locale, and the optional format name.

A FmtBlock is the lone-%var form, with an optional `:formatName` suffix. When %var co-occurs with @var/~word/#N (or passthrough literals) inside the same {{...}} block, it is a FlexBlock count axis instead — routed to SynPrinter.

func ParseFmtBlock

func ParseFmtBlock(toks *[]RefNode) (FmtBlock, error)

ParseFmtBlock consumes a lone-%var FmtBlock token sequence, including an optional :formatName suffix. Caller should gate on IsFmtBlock first; ParseFmtBlock returns an error on any mismatch so FlexBlocks mis-routed here surface loudly rather than silently.

type RefNode

type RefNode struct {
	Type   TokenType
	StrVal string
	IntVal int
	Sub    []RefNode // populated only when Type == TokExpr
}

RefNode is a node in the parsed reference tree. For TokExpr, Sub contains the sub-expression (e.g. the index in arr[expr]).

func ParseReference

func ParseReference(toks *[]RefNode) ([]RefNode, error)

ParseReference builds the reference tree from a list of tokens. Consumes tokens from the beginning of the slice pointed to by toks.

func Tokenize

func Tokenize(s string) []RefNode

Tokenize converts a reference expression into a list of RefNodes. First extracts string literals, then tokenizes the remaining fragments.

func TokenizeFlexContent added in v0.15.0

func TokenizeFlexContent(s string) []RefNode

TokenizeFlexContent tokenizes a flex block authored as inline content: a run of literal text interleaved with flex sigils. Unlike Tokenize (which discards whitespace, treating the block as a reference expression), this preserves the authored text faithfully, following HTML text-node semantics:

  • a whitespace run (\s+: spaces, tabs, newlines) collapses to a single TokSpace token (the browser collapses it anyway in a text node);
  • a run of non-whitespace, non-sigil characters becomes one TokTxt token, preserving punctuation and non-ASCII (e.g. Japanese) verbatim;
  • a sigil ($var, ~$var, ~word, @var, %var, *var, #N) becomes its token; path-bearing sigils ($/*/~$/@/%) carry their `.field`/`[expr]` tail in Sub. `$$`/`**`/`~~`/`%%`/`@@` are escapes → literal text.

A sigil character that does not form a valid sigil (e.g. a lone `$` before a digit, as in a price "US$ 5") is treated as literal text. This is the tokenizer for the per-locale content phrase of a programmable flex rule; the legacy `{{@g %c ~word}}` path keeps using Tokenize + ParseFlexBlock.

type TextSegment

type TextSegment struct {
	IsRef bool
	Lit   string    // if !IsRef: literal text
	Ref   []RefNode // if IsRef: parsed reference tree
}

TextSegment is a template text segment: literal or reference.

func ParseText

func ParseText(s string) ([]TextSegment, error)

ParseText splits a template string into literal segments and references. References are delimited by {{ and }}. Each reference is immediately tokenized and parsed into a RefNode tree.

type TokenType

type TokenType int8

TokenType represents the type of a token in the template parser.

const (
	TokTxt       TokenType = 0  // literal text
	TokRef       TokenType = 1  // reference {{ }}
	TokStr       TokenType = 2  // string literal in quotes
	TokDot       TokenType = 3  // operator .
	TokOpen      TokenType = 4  // operator [
	TokClose     TokenType = 5  // operator ]
	TokNum       TokenType = 6  // integer number
	TokIdent     TokenType = 7  // identifier
	TokWSep      TokenType = 8  // internal state: waiting for separator
	TokExpr      TokenType = 9  // sub-expression (dynamic index access)
	TokAttr      TokenType = 10 // attribute node (DOMRefNode type)
	TokPctVar    TokenType = 11 // %ident  — count variable + emission
	TokAtVar     TokenType = 12 // @ident  — gender variable, no emission
	TokTildeWord TokenType = 13 // ~ident  — flex marker (build-time only)
	TokFlexIdx   TokenType = 14 // #N      — inflection rule index
	TokColon     TokenType = 15 // :       — format-name separator in %var:name
	TokStarVar   TokenType = 16 // *ident  — CustomFlex object (engine/selector)
	TokDollarVar TokenType = 17 // $ident  — dynamic bind value, emitted verbatim
	TokFlexBind  TokenType = 18 // ~$ident — dynamic value to be inflected at runtime
	TokSpace     TokenType = 19 // collapsed whitespace run (\s+ → one space) in flex content
	TokDefName   TokenType = 20 // =ident  — names this block's message for reuse
	TokFlexName  TokenType = 21 // #ident  — reuse: render the message named by ident
)

Token types produced by the expression lexer.

Jump to

Keyboard shortcuts

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