macros

package
v0.20.0 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package macros extends the compiler with a @macro engine.

A @macro directive stores a declaration; OnPreprocess turns each declaration into a PrimaryExtension dispatching on TokAtPrompt; and every expansion re-enters the parser with the caller's arguments substituted into the body.

Typical use:

@macro greet(name) { runtime.const @{ value: $name } }
@greet("World")   // expands to: runtime.const @{ value: "World" }

Without this bundle, @name is "unexpected token @name".

Index

Constants

View Source
const DeclarationKey = "macros"

DeclarationKey is the meta slot where @macro declarations land before OnPreprocess converts them to a PrimaryExtension.

View Source
const ID = "macros"

Variables

View Source
var DefaultBuiltinMacros = []Declaration{
	{
		Name:   "check_required",
		Params: []string{"field"},
		Body:   `assert(.$field != nil && .$field != "", "field '" + "$field" + "' is required")`,
	},
	{
		Name:   "check_choice",
		Params: []string{"field", "choices"},
		Body:   `assert(.$field in $choices, "field '" + "$field" + "' must be one of " + string($choices))`,
	},
	{
		Name:   "check_range",
		Params: []string{"field", "min", "max"},
		Body:   `assert(.$field >= $min && .$field <= $max, "field '" + "$field" + "' must be between " + string($min) + " and " + string($max))`,
	},
}

DefaultBuiltinMacros provides standard reusable validation and guard macros. In expr-lang, membership testing uses the 'in' operator rather than contains().

View Source
var Directive = core.Directive{
	Name:    "macro",
	Example: "@macro greet(name) {\n  runtime.const @{ value: $name }\n}",
	Handler: handleDirective,
}

Directive parses `@macro name(p1, p2) { body }` into a Declaration appended to meta[DeclarationKey]. Duplicate names are a compile error, not a silent override.

Every declaration is also checked against two static limits at declaration time — body size and recursion — so a bad macro is rejected before any invocation. Expansion depth is bounded at parse time by macroPrimary, not here: it depends on invocation order, not on the declaration order.

Functions

func Bundle

func Bundle(_ map[string]string) core.Bundle

func WithTrace added in v0.14.0

func WithTrace(ctx context.Context, t *Trace) context.Context

WithTrace installs a trace into ctx. A nil trace is a no-op.

func WithWhere added in v0.14.0

func WithWhere(ctx context.Context, where string) context.Context

WithWhere records the current source label ("top-level", "pipeline p") on the parser's context. nflow expand installs it so each expansion can be attributed to the source it appeared in; without it, the trace labels every expansion "top-level".

Types

type Declaration

type Declaration struct {
	Name     string
	Params   []string
	Body     string
	DefLine  int
	BodyLine int
}

Declaration is the parsed form of `@macro name(params) { body }`.

DefLine and BodyLine are 1-based file lines. DefLine is the line of the @macro directive itself. BodyLine is the line where body content begins — the same line for an inline body like `@macro x { ... }`, or the line after the opening brace for a multi-line body. They are used to remap parse errors from inside the expanded body back to the correct file position so diagnostics are clickable.

type Expansion added in v0.14.0

type Expansion struct {
	Macro      string
	DefLine    int
	InvokeLine int
	Where      string // "top-level" or "pipeline <name>"
	Body       string
	Err        error
}

Expansion is one recorded macro invocation and its substituted body. DefLine and InvokeLine are 1-based. For an expansion that occurred at the top level, InvokeLine is file-relative. For an expansion inside a pipeline body, InvokeLine is body-relative and Where names the pipeline.

type Trace added in v0.14.0

type Trace struct {
	// contains filtered or unexported fields
}

Trace records every macro expansion that occurs during one parse. Install it into the parser's context before Parse; if no trace is installed, expansion runs without recording anything.

func TraceFrom added in v0.14.0

func TraceFrom(ctx context.Context) *Trace

TraceFrom returns the trace installed in ctx, or nil.

func (*Trace) Expansions added in v0.14.0

func (t *Trace) Expansions() []Expansion

Expansions returns a copy of the recorded expansions, in the order they completed.

func (*Trace) Record added in v0.14.0

func (t *Trace) Record(e Expansion)

Record appends one expansion.

Jump to

Keyboard shortcuts

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