Documentation
¶
Overview ¶
ascii.go Vertical-flow ASCII renderer for railroad diagrams. Same flow model as the SVG renderer (sequences stack downward, choices fan sideways, loops return on the right), painted onto a character grid.
Rails are tracked as direction bits per cell (Up/Down/Left/Right) so junctions resolve automatically to the right box-drawing glyph. Boxes draw literal corners/sides. Plain mode (the CLI --ascii-plain) swaps the Unicode glyph set for plain | - +.
This file mirrors ts/src/ascii.ts.
extract.go Build a railroad GrammarModel by introspecting a live tabnas instance. Reads the rule set (tn.RSM()) and resolved config (tn.Config()) and reverse-maps the alt-based rule machine into railroad constructs (sequence / choice / optional / repetition).
Mapping (see doc + tests against @tabnas/json):
- open alt: the first sN-b token positions are consumed terminals; a P push appends a nonterminal. b == sN (pure peek) consumes nothing — render only the ref.
- several open alts -> choice.
- close alt R == <self> (+ guard token) -> repetition (OneOrMore with the guard token on the return path). R == <other> -> continuation. A close alt that consumes a token with no b/R is this rule's own closing terminal (append it). A backup close (b>0) leaves the token for the parent -> drop. End-of-source / pure-pop -> drop.
- synthetic helper rules (name has `$` or `_gen…`) are inlined.
- normalization factors common prefix/suffix across choice branches and turns an empty branch into Optional.
This file mirrors ts/src/extract.ts. The one structural difference from the TS port is the engine introspection shape: the Go engine resolves an alt's token spec into [][]Tin (the raw "#KEY"/"#VAL" set-name strings are not retained on the live RuleSpec), so the extractor recovers a readable set name by matching the resolved Tin set against the instance's named token sets, disambiguating identical sets (KEY vs VAL) by position role.
Package railroad is the Go port of @tabnas/railroad: it introspects a live tabnas grammar instance and renders railroad / syntax diagrams as a declarative JSON GrammarModel, vertical-flow SVG, and vertical ASCII.
The model (this file) is a small, engine-agnostic tree of nodes (terminal, nonterminal, sequence, choice, optional, repetition) plus the GrammarModel envelope (one node per grammar rule). It is pure, JSON-serializable data: the interchange format that the SVG and ASCII renderers consume, and that the extractor produces from a live tabnas instance.
This file mirrors ts/src/model.ts.
railroad.go Railroad-diagram plugin for the tabnas parser, the Go port of ts/src/railroad.ts. Loading the plugin decorates the instance with a "railroad" decoration: a *RailroadApi that introspects THIS instance's installed grammar and returns a declarative GrammarModel, plus helpers to render that grammar to a vertical-flow SVG or ASCII diagram.
tn := tabnas.Make() json.Json(tn, nil) railroad.Plugin(tn, nil) api := railroad.Of(tn) model, _ := api.ToJson() // GrammarModel svg, _ := api.ToSvg() // whole-grammar SVG ascii, _ := api.ToAscii() // whole-grammar ASCII
The extraction + rendering logic lives in extract.go / svg.go / ascii.go; this file is the plugin wiring plus the package-level entry points for instance-free use.
svg.go Vertical-flow SVG renderer for railroad diagrams. Flow runs top->bottom: sequences stack vertically, choice branches fan out side-by-side, and optional / repetition rails run parallel on the side. This biases the output tall-and-narrow, which suits laptop browsers and phones.
Each node measures to a vLayout{width, height, entryX, exitX, draw}. The rail enters the top edge at entryX and leaves the bottom edge at exitX (both equal — all nodes are horizontally symmetric). draw(x,y) emits SVG with the node's bounding box at top-left (x,y).
ModelToSvg stacks one titled, anchored sub-diagram per rule and turns nonterminal boxes into <a href="#rule"> links.
This file mirrors ts/src/svg.ts.
Index ¶
- Constants
- func ModelToAscii(model *GrammarModel, opts ...AsciiOptions) (string, error)
- func ModelToSvg(model *GrammarModel, _opts ...SvgOptions) (string, error)
- func NodeEqual(a, b *RailroadNode) bool
- func Plugin(tn *tabnas.Tabnas, _ map[string]any) error
- func RenderNodeAscii(node *RailroadNode, opts ...AsciiOptions) (string, error)
- func RenderNodeSvg(node *RailroadNode, opts ...SvgOptions) (string, error)
- func ToText(node *RailroadNode) (string, error)
- type AsciiOptions
- type ExtractOptions
- type GrammarModel
- type LegendEntry
- type NodeKind
- type RailroadApi
- func (a *RailroadApi) Extract(opts ...*ExtractOptions) *GrammarModel
- func (a *RailroadApi) RenderNode(node *RailroadNode, opts ...SvgOptions) (string, error)
- func (a *RailroadApi) RenderNodeAscii(node *RailroadNode, opts ...AsciiOptions) (string, error)
- func (a *RailroadApi) RenderNodeText(node *RailroadNode) (string, error)
- func (a *RailroadApi) ToAscii(asciiOpts AsciiOptions, opts ...*ExtractOptions) (string, error)
- func (a *RailroadApi) ToJson(opts ...*ExtractOptions) *GrammarModel
- func (a *RailroadApi) ToSvg(opts ...*ExtractOptions) (string, error)
- type RailroadError
- type RailroadNode
- func Choice(items ...*RailroadNode) (*RailroadNode, error)
- func Comment(text string) *RailroadNode
- func Diagram(items ...*RailroadNode) *RailroadNode
- func MustChoice(items ...*RailroadNode) *RailroadNode
- func NonTerminal(text string) *RailroadNode
- func Norm(item any) (*RailroadNode, error)
- func OneOrMore(item *RailroadNode, rep *RailroadNode) *RailroadNode
- func Optional(item *RailroadNode) *RailroadNode
- func Sequence(items ...*RailroadNode) *RailroadNode
- func SkipNode() *RailroadNode
- func Terminal(text string) *RailroadNode
- func ZeroOrMore(item *RailroadNode, rep *RailroadNode) *RailroadNode
- type SvgOptions
Constants ¶
const DecorationName = "railroad"
DecorationName is the key under which the plugin stores its API on the instance (retrieve via tn.Decoration(DecorationName) or railroad.Of(tn)).
const Version = "0.2.1"
Version is the current version of the module.
Variables ¶
This section is empty.
Functions ¶
func ModelToAscii ¶
func ModelToAscii(model *GrammarModel, opts ...AsciiOptions) (string, error)
ModelToAscii renders a whole grammar: each rule as a titled vertical block.
func ModelToSvg ¶
func ModelToSvg(model *GrammarModel, _opts ...SvgOptions) (string, error)
ModelToSvg renders a whole grammar: a vertical stack of titled, anchored rule tracks; nonterminal boxes link to the referenced rule's track.
func NodeEqual ¶ added in v0.2.1
func NodeEqual(a, b *RailroadNode) bool
NodeEqual reports deep structural equality of two nodes, used by choice prefix/suffix factoring to detect shared leading/trailing elements. It mirrors the TS `nodeEqual` export; two nil nodes compare equal.
func Plugin ¶
Plugin is the tabnas plugin entry point. Decoration is lazy: every helper re-reads the instance's current grammar when called, so install order does not matter. Mirrors the TS railroad plugin.
func RenderNodeAscii ¶
func RenderNodeAscii(node *RailroadNode, opts ...AsciiOptions) (string, error)
RenderNodeAscii renders a single node to an ASCII block.
func RenderNodeSvg ¶
func RenderNodeSvg(node *RailroadNode, opts ...SvgOptions) (string, error)
RenderNodeSvg renders a single node (wrapped in its own SVG document).
func ToText ¶
func ToText(node *RailroadNode) (string, error)
ToText renders a node as compact EBNF-ish text: terminals quoted, choice in (a | b), optional in [x], zero-or-more in {x}, one-or-more as x+. Mirrors ts/model.ts toText.
Types ¶
type AsciiOptions ¶
type AsciiOptions struct {
// Plain renders pure-ASCII glyphs (| - +) instead of Unicode.
Plain bool
}
AsciiOptions configures the ASCII renderer.
type ExtractOptions ¶
type ExtractOptions struct {
// NoFactor disables prefix/suffix factoring + empty-branch->optional
// (the TS `factor` defaults to true; this is its inverse).
NoFactor bool
// Start overrides the entry rule (defaults to config RuleStart).
Start string
// TokenSetNames lists the named token-set candidates the extractor may
// recover for a resolved Tin set, in preference order. When empty, the
// standard set ["VAL", "KEY"] is used (the json grammar's sets). A
// position immediately followed by a colon (CL) prefers "KEY".
TokenSetNames []string
// TokenDesc supplies human descriptions for named tokens/sets, keyed by
// bare or "#"-prefixed name. It is the Go analog of the TS cfg.tokenDesc
// hook a grammar attaches via config.modify.
TokenDesc map[string]string
}
ExtractOptions controls extraction.
type GrammarModel ¶
type GrammarModel struct {
Start string `json:"start"`
Rules map[string]*RailroadNode `json:"rules"`
RuleOrder []string `json:"-"`
Legend []LegendEntry `json:"legend,omitempty"`
Ignored []LegendEntry `json:"ignored,omitempty"`
Meta map[string]any `json:"meta,omitempty"`
}
GrammarModel is one whole grammar: an ordered rule map plus the entry rule. This is the declarative artifact emitted as grammar.railroad.json.
RuleOrder preserves the insertion order of rule names (Go maps have no stable order); the renderers and JSON emitter use it so output is deterministic and matches the TS object-key order.
func ExtractGrammar ¶
func ExtractGrammar(tn *tabnas.Tabnas, opts ...*ExtractOptions) *GrammarModel
ExtractGrammar builds a railroad GrammarModel from a live tabnas instance. It mirrors ts/extract.ts extractGrammar(tn).
func (*GrammarModel) MarshalJSON ¶
func (m *GrammarModel) MarshalJSON() ([]byte, error)
MarshalJSON emits the model with rules in RuleOrder (falling back to map order when RuleOrder is empty) so the serialized form is deterministic.
func (*GrammarModel) UnmarshalJSON ¶
func (m *GrammarModel) UnmarshalJSON(data []byte) error
UnmarshalJSON parses a model, recovering RuleOrder from the raw JSON key order so a round-tripped model renders identically.
type LegendEntry ¶
LegendEntry names a token (or token set) that appears in the diagram and gives its human meaning. Used for the diagram legend and the ignored set.
type NodeKind ¶
type NodeKind = string
NodeKind enumerates the railroad node variants (the tagged-union tag).
const ( KindTerminal NodeKind = "terminal" KindNonTerminal NodeKind = "nonterminal" KindComment NodeKind = "comment" KindSkip NodeKind = "skip" KindSeq NodeKind = "seq" KindChoice NodeKind = "choice" KindOptional NodeKind = "optional" KindOneOrMore NodeKind = "oneOrMore" KindZeroOrMore NodeKind = "zeroOrMore" KindDiagram NodeKind = "diagram" )
type RailroadApi ¶
type RailroadApi struct {
// contains filtered or unexported fields
}
RailroadApi is the shape the "railroad" decoration takes: a grammar extractor plus render helpers and the diagram-model constructors. It is the Go analog of the TS callable tn.railroad.
func Of ¶
func Of(tn *tabnas.Tabnas) *RailroadApi
Of returns the RailroadApi previously installed on tn by Plugin, or a freshly-bound API when the plugin has not been loaded (so callers can use the helpers without explicitly installing the plugin first).
func (*RailroadApi) Extract ¶
func (a *RailroadApi) Extract(opts ...*ExtractOptions) *GrammarModel
Extract introspects this instance's grammar and returns its GrammarModel. (Go analog of calling tn.railroad() / tn.railroad.toJson().)
func (*RailroadApi) RenderNode ¶
func (a *RailroadApi) RenderNode(node *RailroadNode, opts ...SvgOptions) (string, error)
RenderNode renders a single node to a standalone SVG.
func (*RailroadApi) RenderNodeAscii ¶
func (a *RailroadApi) RenderNodeAscii(node *RailroadNode, opts ...AsciiOptions) (string, error)
RenderNodeAscii renders a single node to an ASCII block.
func (*RailroadApi) RenderNodeText ¶
func (a *RailroadApi) RenderNodeText(node *RailroadNode) (string, error)
RenderNodeText renders a single node to compact EBNF text.
func (*RailroadApi) ToAscii ¶
func (a *RailroadApi) ToAscii(asciiOpts AsciiOptions, opts ...*ExtractOptions) (string, error)
ToAscii extracts this instance's grammar and renders it to ASCII. A trailing AsciiOptions controls plain mode.
func (*RailroadApi) ToJson ¶
func (a *RailroadApi) ToJson(opts ...*ExtractOptions) *GrammarModel
ToJson is an alias of Extract.
func (*RailroadApi) ToSvg ¶
func (a *RailroadApi) ToSvg(opts ...*ExtractOptions) (string, error)
ToSvg extracts this instance's grammar and renders it to SVG.
type RailroadError ¶
RailroadError is raised on a malformed diagram model (empty choice, unknown kind, invalid node). It mirrors the TS RailroadError.
func (*RailroadError) Error ¶
func (e *RailroadError) Error() string
type RailroadNode ¶
type RailroadNode struct {
Kind NodeKind
Text string
Items []*RailroadNode
Item *RailroadNode
Rep *RailroadNode
}
RailroadNode is one node of a railroad diagram tree. It is a faithful port of the TypeScript discriminated union: which fields are populated depends on Kind. Terminal/NonTerminal/Comment use Text; Seq/Choice/ Diagram use Items; Optional uses Item; OneOrMore/ZeroOrMore use Item and the optional Rep; Skip uses nothing.
Custom JSON marshalling reproduces the TS object shapes exactly: each kind serializes only its relevant fields (so a Terminal is {"kind":"terminal","text":"x"} and a Skip is {"kind":"skip"}), and Rep is omitted when absent.
func Choice ¶
func Choice(items ...*RailroadNode) (*RailroadNode, error)
Choice builds a choice of branches. It returns a RailroadError (via panic-free path: callers that may pass zero branches must check) when given no branches, mirroring the TS Choice throwing.
func Diagram ¶
func Diagram(items ...*RailroadNode) *RailroadNode
Diagram builds a top-level diagram wrapper of nodes.
func MustChoice ¶
func MustChoice(items ...*RailroadNode) *RailroadNode
MustChoice is Choice that panics with a RailroadError on no branches — the ergonomic form used internally where branch count is guaranteed.
func NonTerminal ¶
func NonTerminal(text string) *RailroadNode
NonTerminal builds a nonterminal (rule reference) node.
func Norm ¶ added in v0.2.1
func Norm(item any) (*RailroadNode, error)
Norm coerces an item to a valid *RailroadNode. It mirrors the TS `norm` export and its Item union (RailroadNode | string): a bare string is taken to be a terminal — the common case when hand-building diagrams — and a *RailroadNode is validated as-is. Any other value (including nil or a node with an empty Kind) yields a RailroadError.
func OneOrMore ¶
func OneOrMore(item *RailroadNode, rep *RailroadNode) *RailroadNode
OneOrMore builds a one-or-more repetition, with an optional rep node on the return path (e.g. a separator).
func Optional ¶
func Optional(item *RailroadNode) *RailroadNode
Optional builds an optional (bypassable) node.
func Sequence ¶
func Sequence(items ...*RailroadNode) *RailroadNode
Sequence builds a sequence of nodes.
func Terminal ¶
func Terminal(text string) *RailroadNode
Terminal builds a terminal (literal / named token) node.
func ZeroOrMore ¶
func ZeroOrMore(item *RailroadNode, rep *RailroadNode) *RailroadNode
ZeroOrMore builds a zero-or-more repetition (a bypassable OneOrMore).
func (*RailroadNode) MarshalJSON ¶
func (n *RailroadNode) MarshalJSON() ([]byte, error)
MarshalJSON emits the kind-specific object shape, matching ts/model.ts.
func (*RailroadNode) UnmarshalJSON ¶
func (n *RailroadNode) UnmarshalJSON(data []byte) error
UnmarshalJSON parses a kind-specific object shape into a RailroadNode, so a model round-trips through JSON (used by the render-mode CLI and the round-trip tests).
type SvgOptions ¶
type SvgOptions struct {
// LinkFor maps a nonterminal name to an href (whole-grammar linking).
// Returns ("", false) when the name should not be linked.
LinkFor func(name string) (string, bool)
}
SvgOptions configures the SVG renderer.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
tabnas-railroad
command
Command tabnas-railroad renders railroad (syntax) diagrams from a tabnas grammar.
|
Command tabnas-railroad renders railroad (syntax) diagrams from a tabnas grammar. |