syntax

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultIndent = "  "

DefaultIndent is two spaces rather than a tab, because inside an HTML body the indentation is character data and a tab renders differently there.

View Source
const DefaultWidth = 100

DefaultWidth is the soft line width every layout pass aims at. It is soft because a construct that cannot break without changing meaning stays long.

Variables

This section is empty.

Functions

func ControlClose added in v0.3.1

func ControlClose(n Node) string

ControlClose renders the closing marker of a shared control node.

func ControlOpen added in v0.3.1

func ControlOpen(n Node) (string, bool)

ControlOpen renders the opening marker of a shared control node, without the braces the format owns. It reports false for a node that is not a control node.

func ErrorAt

func ErrorAt(filename, source string, localOffset, baseOffset int, message string) error

ErrorAt constructs a parser diagnostic for a format-specific body parser.

func ErrorAtPosition

func ErrorAtPosition(filename, source string, localOffset, baseOffset int, basePos Position, message string) error

ErrorAtPosition constructs a diagnostic for a source fragment while keeping its file-global byte offset and line/column position.

func ExprString added in v0.3.1

func ExprString(e Expr) string

ExprString renders an expression back to source. Parentheses are reinserted from precedence rather than remembered, so a redundant pair the author wrote is dropped and a necessary one is never lost.

func PrintModule added in v0.3.1

func PrintModule(module *Module, roots []RootPrinter, options PrintOptions) (string, error)

PrintModule prints a whole module: the shared declaration part here, and each declaration body through the format printer registered for its kind.

func TypeRefString added in v0.3.1

func TypeRefString(t TypeRef) string

TypeRefString renders a type expression. The AST does not distinguish the [T] and T[] spellings of an array, so both print as T[].

Types

type Annotation added in v0.1.16

type Annotation struct {
	Pos  Position        `json:"pos"`
	Name string          `json:"name"`
	Args []AnnotationArg `json:"args,omitempty"`
}

Annotation is one `@name(key: "value")` line attached to the declaration below it. The shared parser owns the grammar; each output format decides which names it accepts, so an unknown name is a generation error rather than a silently ignored line.

func (Annotation) Argument added in v0.1.16

func (a Annotation) Argument(name string) (AnnotationArg, bool)

Argument returns the value of a named annotation argument.

type AnnotationArg added in v0.1.16

type AnnotationArg struct {
	Pos   Position `json:"pos"`
	Name  string   `json:"name"`
	Value string   `json:"value"`
}

type AwaitBinding added in v0.1.16

type AwaitBinding struct {
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
	Call Expr     `json:"call"`
}

AwaitBinding names one asynchronous call whose result the primary subtree reads.

type AwaitNode added in v0.1.16

type AwaitNode struct {
	Kind     string         `json:"kind"`
	Pos      Position       `json:"pos"`
	Context  string         `json:"context"`
	Bindings []AwaitBinding `json:"bindings"`
	Primary  []Node         `json:"primary"`
	Fallback []Node         `json:"fallback"`
	// HasRecover distinguishes a declared but empty recover subtree from an
	// omitted one, which keeps the committed fallback instead.
	HasRecover bool     `json:"hasRecover,omitempty"`
	Recover    []Node   `json:"recover,omitempty"`
	ErrorName  string   `json:"errorName,omitempty"`
	ErrorPos   Position `json:"errorPos,omitempty"`
}

AwaitNode is one asynchronous boundary. Its bindings run concurrently; the primary subtree reads them, the fallback subtree is emitted while they are pending, and the optional recover subtree replaces the fallback on failure.

How many times the boundary renders is a property of what its bindings name, not of the clause: a binding on a settle-once source produces one render, and a binding on a live source produces one per delivery. The clause says which values the subtree waits for, and the declarations say how those values arrive, so nothing here has to be repeated at the wait site.

func (*AwaitNode) NodeType added in v0.1.16

func (n *AwaitNode) NodeType() string

type BinaryExpr

type BinaryExpr struct {
	Kind     string   `json:"kind"`
	Pos      Position `json:"pos"`
	Operator string   `json:"operator"`
	Left     Expr     `json:"left"`
	Right    Expr     `json:"right"`
}

type BodyContext

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

BodyContext is the shared cursor and control orchestrator for one declaration body. Format parsers must use it instead of owning an independent cursor.

func (*BodyContext) ErrorAt

func (c *BodyContext) ErrorAt(offset int, message string) error

func (*BodyContext) Filename

func (c *BodyContext) Filename() string

func (*BodyContext) Offset

func (c *BodyContext) Offset() int

func (*BodyContext) ParseEmbedded

func (c *BodyContext) ParseEmbedded(fragment Embedded, context string) (Node, *Terminator, error)

ParseEmbedded parses one fragment after the active format parser has found its boundaries. It returns either a shared node or a control terminator.

func (*BodyContext) Position

func (c *BodyContext) Position(offset int) Position

func (*BodyContext) SetOffset

func (c *BodyContext) SetOffset(offset int)

func (*BodyContext) Source

func (c *BodyContext) Source() string

type BodyPrinter added in v0.3.1

type BodyPrinter interface {
	PrintBody(p *Printer, decl *TemplateDecl) error
}

BodyPrinter lays out one declaration body, from just after the opening brace to just before the closing one. It is the printing half of FormatParser: a format that can be parsed can be printed.

The body printer owns its own indentation and the line breaks at both braces, because whether a body may open on its own line is a property of the format: SQL whitespace is insignificant and HTML whitespace is content.

type CallExpr

type CallExpr struct {
	Kind      string   `json:"kind"`
	Pos       Position `json:"pos"`
	Callee    Expr     `json:"callee"`
	Arguments []Expr   `json:"arguments,omitempty"`
}

type Comment added in v0.3.1

type Comment struct {
	Pos Position `json:"pos"`
	// Text is the comment including its own delimiters, so a printer never has
	// to reconstruct whether it was a line or a block comment.
	Text string `json:"text"`
	// Block reports a /* */ comment.
	Block bool `json:"block,omitempty"`
	// Trailing reports a comment that began on a line which already had code on
	// it, which is what decides whether a printer keeps it on that line.
	Trailing bool `json:"trailing,omitempty"`
	// BlankBefore reports a blank line between the previous content and this
	// comment, so a deliberately detached comment stays detached.
	BlankBefore bool `json:"blankBefore,omitempty"`
	// contains filtered or unexported fields
}

Comment is one comment read from the declaration part of a source file. The parser keeps it because a formatter that drops comments is a formatter nobody may run; every compiler stage ignores it.

func CommentsBefore added in v0.3.1

func CommentsBefore(comments []Comment, pos Position) (before, rest []Comment)

CommentsBefore returns the module comments positioned before pos, and the remainder. A printer walks its declarations in order and flushes what belongs above each one, which is why attachment needs no separate pass.

type ConditionalExpr

type ConditionalExpr struct {
	Kind      string   `json:"kind"`
	Pos       Position `json:"pos"`
	Condition Expr     `json:"condition"`
	Then      Expr     `json:"then"`
	Else      Expr     `json:"else"`
}

type DeclComment added in v0.3.6

type DeclComment struct {
	Line        int
	Text        string
	Trailing    bool
	BlankBefore bool
	// contains filtered or unexported fields
}

DeclComment is one comment kept for requirement:template-comment-retention.

func ScanDeclComments added in v0.3.6

func ScanDeclComments(source string) []DeclComment

ScanDeclComments collects every comment with the line it sits on.

It scans the raw source rather than the token stream, so a comment survives a grammar that discards it. Only "//" comments exist in these languages.

type DeclFormatter added in v0.3.6

type DeclFormatter struct {
	P *Printer
	// contains filtered or unexported fields
}

DeclFormatter places scanned comments around whatever a grammar's own formatter writes. It owns the blank lines between constructs, so a comment stays attached to what it documents.

func NewDeclFormatter added in v0.3.6

func NewDeclFormatter(p *Printer, comments []DeclComment) *DeclFormatter

NewDeclFormatter starts a formatter over one source's comments.

func (*DeclFormatter) FlushBefore added in v0.3.6

func (f *DeclFormatter) FlushBefore(line int)

FlushBefore writes the standalone comments that stood above the given line.

func (*DeclFormatter) FlushRemaining added in v0.3.6

func (f *DeclFormatter) FlushRemaining()

FlushRemaining writes the comments that stood after every construct, so a trailing note at the end of a file is not dropped.

func (*DeclFormatter) FlushTrailing added in v0.3.6

func (f *DeclFormatter) FlushTrailing(line int)

FlushTrailing writes the comment that ended the given line, if any.

func (*DeclFormatter) MarkWrote added in v0.3.6

func (f *DeclFormatter) MarkWrote()

MarkWrote records that the grammar's own formatter wrote something.

func (*DeclFormatter) SeparateFor added in v0.3.6

func (f *DeclFormatter) SeparateFor(line int)

SeparateFor opens the blank line above a construct, unless a comment sits directly on the line above it.

func (*DeclFormatter) Wrote added in v0.3.6

func (f *DeclFormatter) Wrote() bool

Wrote reports whether anything has been written yet, which is what decides whether a separator is wanted.

type Declaration

type Declaration interface {
	// contains filtered or unexported methods
}

Declaration is implemented by all root declarations.

type Embedded

type Embedded struct {
	Text          string
	StartOffset   int
	ContentOffset int
}

Embedded is one brace-delimited template fragment discovered by a format parser. Offsets are file-global byte offsets.

type EnumDecl

type EnumDecl struct {
	Kind    string       `json:"kind"`
	Pos     Position     `json:"pos"`
	Name    string       `json:"name"`
	Members []EnumMember `json:"members"`
}

type EnumMember

type EnumMember struct {
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
}

type Expr

type Expr interface {
	// contains filtered or unexported methods
}

Expr is the shared expression AST embedded by every output format.

func ParseExpression

func ParseExpression(filename, source string, baseOffset int) (Expr, error)

ParseExpression parses a complete shared template expression.

func ParseExpressionAt

func ParseExpressionAt(filename, source string, baseOffset int, basePos Position) (Expr, error)

ParseExpressionAt parses an expression whose first byte starts at baseOffset and basePos in its containing template file.

type ExpressionNode

type ExpressionNode struct {
	Kind       string   `json:"kind"`
	Pos        Position `json:"pos"`
	Context    string   `json:"context"`
	Expression Expr     `json:"expression"`
}

func (*ExpressionNode) NodeType

func (n *ExpressionNode) NodeType() string

type ExternalDecl

type ExternalDecl struct {
	Kind string   `json:"kind"`
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
	// Async marks a function that runs concurrently and may fail. It is a
	// keyword rather than an annotation because it changes the Go signature the
	// package must provide.
	Async bool `json:"async,omitempty"`
	// Live marks a function that yields many values over time rather than
	// settling once. It is a keyword for the same reason Async is: the Go
	// signature becomes an iter.Seq2 over the result type, with a leading
	// context that is mandatory rather than optional, because an endless source
	// has to be stoppable.
	Live       bool        `json:"live,omitempty"`
	Parameters []Parameter `json:"parameters,omitempty"`
	Result     TypeRef     `json:"result"`
}

type Field

type Field struct {
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
	Type TypeRef  `json:"type"`
}

type ForNode

type ForNode struct {
	Kind     string   `json:"kind"`
	Pos      Position `json:"pos"`
	Context  string   `json:"context"`
	Variable string   `json:"variable"`
	Index    string   `json:"index,omitempty"`
	Iterable Expr     `json:"iterable"`
	Body     []Node   `json:"body"`
}

func (*ForNode) NodeType

func (n *ForNode) NodeType() string

type FormatParser

type FormatParser interface {
	ParseBody(*BodyContext, string) ([]Node, *Terminator, error)
}

FormatParser owns format tokenization and discovers embedded template boundaries. The shared BodyContext parses those boundaries and recursively calls the same format parser for control bodies.

type IdentifierExpr

type IdentifierExpr struct {
	Kind string   `json:"kind"`
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
}

type IfNode

type IfNode struct {
	Kind      string   `json:"kind"`
	Pos       Position `json:"pos"`
	Context   string   `json:"context"`
	Condition Expr     `json:"condition"`
	Then      []Node   `json:"then"`
	Else      []Node   `json:"else,omitempty"`
}

func (*IfNode) NodeType

func (n *IfNode) NodeType() string

type ImportDecl

type ImportDecl struct {
	Pos   Position `json:"pos"`
	Path  string   `json:"path"`
	Alias string   `json:"alias,omitempty"`
}

type IndexExpr

type IndexExpr struct {
	Kind   string   `json:"kind"`
	Pos    Position `json:"pos"`
	Object Expr     `json:"object"`
	Index  Expr     `json:"index"`
}

type LiteralExpr

type LiteralExpr struct {
	Kind      string   `json:"kind"`
	Pos       Position `json:"pos"`
	ValueKind string   `json:"valueKind"`
	Value     any      `json:"value"`
}

type MemberExpr

type MemberExpr struct {
	Kind   string   `json:"kind"`
	Pos    Position `json:"pos"`
	Object Expr     `json:"object"`
	Member string   `json:"member"`
}

type Module

type Module struct {
	Pos          Position      `json:"pos"`
	Package      *PackageDecl  `json:"package,omitempty"`
	Imports      []ImportDecl  `json:"imports,omitempty"`
	Declarations []Declaration `json:"declarations"`
	// Comments holds every comment in the declaration part of the file, in
	// source order. They are attached by position rather than to nodes, because
	// a printer walks declarations in order anyway and node-by-node plumbing
	// would touch every declaration type for no extra information.
	Comments []Comment `json:"comments,omitempty"`
}

Module is the format-neutral root of a template source file.

func ParseModule

func ParseModule(filename, source string, roots []RootDeclaration) (*Module, error)

ParseModule parses standard declarations plus the registered format roots.

type NameRule added in v0.3.1

type NameRule struct {
	// PascalCase requires an uppercase initial, exported or not. HTML sets it
	// because in markup an element whose tag name starts uppercase is the
	// component-call syntax: a lowercase component could never be called, and
	// would collide with a standard element.
	PascalCase bool
	// ExportedNameIsGo says the public generated identifier is the declaration
	// name itself, so an exported declaration needs an exported name. A format
	// that composes its public name instead leaves this off.
	ExportedNameIsGo bool
	// PrivateNameIsGo says the private generated identifier is also the name
	// itself, so an unexported declaration needs an unexported name. A format
	// that prefixes its private name leaves this off, and may then keep an
	// uppercase name on a private declaration.
	PrivateNameIsGo bool
}

NameRule is the per-format declaration name policy of decision:declaration-name-policy. Each field states a fact about what the format's emitter does with the name, so the constraint is derived from the generated code rather than asserted as a convention.

type Node

type Node interface {
	NodeType() string
}

Node is a body AST node produced either by the shared parser or a registered format parser. Type IDs are namespaced as <language>:<node-type>.

type PackageDecl

type PackageDecl struct {
	Kind string   `json:"kind"`
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
}

type Parameter

type Parameter struct {
	Pos  Position `json:"pos"`
	Name string   `json:"name"`
	Type TypeRef  `json:"type"`
}

type ParseError

type ParseError struct {
	Filename string
	Offset   int
	Line     int
	Column   int
	Message  string
}

ParseError reports a stable source location for syntax diagnostics.

func (*ParseError) Error

func (e *ParseError) Error() string

type Position

type Position struct {
	Line int `json:"line"`
	Col  int `json:"col"`
}

Position is a one-based source position. Offset is intentionally not part of the serialized AST; parsers use offsets internally while later compiler stages report the stable line and column pair.

type PrintOptions added in v0.3.1

type PrintOptions struct {
	// Width is the soft line width; zero uses DefaultWidth.
	Width int
	// Indent is one indentation level; empty uses DefaultIndent.
	Indent string
	// PreserveWhitespace mirrors the generator option of the same name. With it
	// set, static whitespace is no longer collapsed at generation time, so an
	// HTML layout pass may only touch positions the HTML parser discards.
	PreserveWhitespace bool
}

PrintOptions configures the shared printer and every format printer.

type Printer added in v0.3.1

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

Printer is the shared output buffer with indentation state. Format printers write through it so one file has one notion of a line and a level.

func NewPrinter added in v0.3.1

func NewPrinter(options PrintOptions) *Printer

NewPrinter creates a standalone printer, for a format printer under test.

func (*Printer) AtLineStart added in v0.3.1

func (p *Printer) AtLineStart() bool

AtLineStart reports that nothing has been written on the current line, which is when a layout drops the leading space a construct carries.

func (*Printer) Blank added in v0.3.1

func (p *Printer) Blank()

Blank ends the current line and leaves one empty line after it.

func (*Printer) Column added in v0.3.1

func (p *Printer) Column() int

Column reports how many bytes are already on the current line, for a layout deciding whether the next construct still fits the width.

func (*Printer) Dedent added in v0.3.1

func (p *Printer) Dedent()

Dedent closes one level.

func (*Printer) Depth added in v0.3.1

func (p *Printer) Depth() int

Depth returns the current indentation level.

func (*Printer) Indent added in v0.3.1

func (p *Printer) Indent()

Indent opens one level.

func (*Printer) Line added in v0.3.1

func (p *Printer) Line()

Line ends the current line. The newline and the next line's indentation are written lazily, so a line that turns out to be empty leaves no trailing spaces behind.

func (*Printer) Options added in v0.3.1

func (p *Printer) Options() PrintOptions

Options returns the active options.

func (*Printer) Raw added in v0.3.1

func (p *Printer) Raw() string

Raw returns the buffer as written, without the trailing-whitespace cleanup String applies. An inline measurement needs it, because a trailing space it produced is a space the layout has to keep.

func (*Printer) String added in v0.3.1

func (p *Printer) String() string

String returns the printed text with exactly one trailing newline.

func (*Printer) Width added in v0.3.1

func (p *Printer) Width() int

Width returns the soft line width.

func (*Printer) Write added in v0.3.1

func (p *Printer) Write(text string)

Write appends text on the current line, opening the line first when one is owed. Text must not contain a newline; use Line for that.

func (*Printer) WriteRaw added in v0.3.1

func (p *Printer) WriteRaw(text string)

WriteRaw appends text exactly, without indentation and without owing a line. It exists for content copied byte for byte, such as a script body.

type RootDeclaration

type RootDeclaration struct {
	Keyword      string
	NodeType     string
	OutputPrefix string
	Context      string
	Parser       FormatParser
	// Names states what this format needs from a declaration name. The zero
	// value asks for nothing, which is what a format wants when every generated
	// identifier is composed rather than copied.
	Names NameRule
}

RootDeclaration registers one format-specific declaration with the shared root driver.

type RootPrinter added in v0.3.1

type RootPrinter struct {
	// Kind is the TemplateDecl.Kind the format parser assigned.
	Kind string
	// Keyword is the root declaration keyword to print.
	Keyword string
	Printer BodyPrinter
}

RootPrinter registers one format's body printer against the declaration kind its parser produced.

type TemplateDecl

type TemplateDecl struct {
	Kind        string       `json:"kind"`
	Pos         Position     `json:"pos"`
	Exported    bool         `json:"exported"`
	Annotations []Annotation `json:"annotations,omitempty"`
	Name        string       `json:"name"`
	Parameters  []Parameter  `json:"parameters,omitempty"`
	Output      TypeRef      `json:"output"`
	Body        any          `json:"body"`
}

func (*TemplateDecl) Annotation added in v0.1.16

func (d *TemplateDecl) Annotation(name string) (Annotation, bool)

Annotation returns the declaration's annotation with the given name.

type Terminator

type Terminator struct {
	Kind          TerminatorKind
	Pos           Position
	Header        string
	HeaderOffset  int
	ContentOffset int
}

Terminator is discovered by a format parser and interpreted by the shared control parser.

type TerminatorKind

type TerminatorKind string
const (
	TerminatorRoot     TerminatorKind = "root"
	TerminatorElse     TerminatorKind = "else"
	TerminatorElseIf   TerminatorKind = "else-if"
	TerminatorEndIf    TerminatorKind = "end-if"
	TerminatorEndFor   TerminatorKind = "end-for"
	TerminatorFallback TerminatorKind = "fallback"
	TerminatorRecover  TerminatorKind = "recover"
	TerminatorEndAwait TerminatorKind = "end-await"
)

type TypeDecl

type TypeDecl struct {
	Kind   string   `json:"kind"`
	Pos    Position `json:"pos"`
	Name   string   `json:"name"`
	Fields []Field  `json:"fields"`
}

type TypeRef

type TypeRef struct {
	Pos       Position  `json:"pos"`
	Name      string    `json:"name"`
	Arguments []TypeRef `json:"arguments,omitempty"`
	Array     bool      `json:"array,omitempty"`
	Optional  bool      `json:"optional,omitempty"`
	// Async marks a value the caller starts and the template waits for in an
	// await clause. It modifies the whole type expression, so `async Order[]`
	// is one pending array rather than an array of pending values.
	Async bool `json:"async,omitempty"`
}

TypeRef represents named, generic, array, optional, and asynchronous types without binding them to Go types during parsing.

type UnaryExpr

type UnaryExpr struct {
	Kind     string   `json:"kind"`
	Pos      Position `json:"pos"`
	Operator string   `json:"operator"`
	Operand  Expr     `json:"operand"`
}

Jump to

Keyboard shortcuts

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