Describing diagrams

Using YAML or Python literals

Diagram elements are described as simple types suitable for encoding in JSON-like formats. The specific representation was chosen to be ergonomic when writing diagrams in YAML syntax.

type syntax_diagrams.Element[T]

Describes an element of a syntax diagram.

Example:

- choice:
  - "lexer"
  -
  - "parser"
  default: 1
- grammar
- non_terminal: "identifier"
- ";"
diagram = sequence(
    choice(
        terminal("lexer"),
        skip(),
        terminal("parser"),
    ),
    terminal("grammar"),
    non_terminal("identifier"),
    terminal(";"),
)

lexerparsergrammaridentifier;

type syntax_diagrams.Terminal[T]

Describes a terminal node with optional additional settings.

Dict keys:

  • terminal: str, required

    Text of the terminal, required.

  • href: str

    Makes text node into a hyperlink.

  • title: str

    Title for hyperlink.

  • css_class: str

    Adds CSS class to node’s <g> element.

  • resolve: bool

    If set to False, this node will not be passed to HrefResolver before rendering.

  • resolver_data: T

    Additional data for HrefResolver.

Example:

terminal: "INT"
href: "#syntax_diagrams.Terminal"
diagram = terminal("INT", href="#syntax_diagrams.Terminal")

INT

Terminal nodes without settings can be encoded as simple strings:

"INT"

INT

type syntax_diagrams.NonTerminal[T]

Describes a non-terminal node with optional additional settings.

Dict keys:

  • non_terminal: str, required

    Text of the non-terminal, required.

  • href: str

    Makes text node into a hyperlink.

  • title: str

    Title for hyperlink.

  • css_class: str

    Adds CSS class to node’s <g> element.

  • resolve: bool

    If set to False, this node will not be passed to HrefResolver before rendering.

  • resolver_data: T

    Additional data for HrefResolver.

Example:

non_terminal: "expr"
href: "#syntax_diagrams.NonTerminal"
diagram = non_terminal("expr", href="#syntax_diagrams.NonTerminal")
type syntax_diagrams.Comment[T]

Describes a comment node with optional additional settings.

Dict keys:

  • comment: str, required

    Text of the terminal, required.

  • href: str

    Makes text node into a hyperlink.

  • title: str

    Title for hyperlink.

  • css_class: str

    Adds CSS class to node’s <g> element.

  • resolve: bool

    If set to False, this node will not be passed to HrefResolver before rendering.

  • resolver_data: T

    Additional data for HrefResolver.

Example:

comment: "escaped literal"
href: "#syntax_diagrams.Comment"
diagram = comment("escaped literal", href="#syntax_diagrams.Comment")
type syntax_diagrams.Sequence[T]

Describes an automatically wrapped sequence of elements.

Dict keys:

  • sequence: list[Element[T]], required

    Elements in the sequence.

  • linebreaks: _t.Literal["HARD", "SOFT", "DEFAULT"] | list[_t.Literal["HARD", "SOFT", "DEFAULT"]]

    Specifies line breaks after each element of the sequence.

    If given as a string or a LineBreak, this line break will be used after each of the sequence’s elements.

    If given as a list of line breaks, each of list’s element determines line break after each of the sequence’s elements. This list must be one item shorter than number of elements in the sequence.

Example:

sequence:
- comment: "escaped literal"
- "ESC"
- "CHAR"
linebreaks:
- "NO_BREAK"
- "DEFAULT"
diagram = sequence(
    comment("escaped literal"),
    terminal("ESC"),
    terminal("CHAR"),
    linebreaks=[
        LineBreak.NO_BREAK,
        LineBreak.DEFAULT,
    ],
)

escaped literalESCCHAR

Sequences without settings can also be encoded as simple lists:

- comment: "escaped literal"
- "ESC"
- "CHAR"

escaped literalESCCHAR

type syntax_diagrams.Stack[T]

Describes a sequence of elements that wraps after each element.

This is a shortcut for creating a Sequence with linebreaks set to HARD.

Dict keys:

  • stack: list[Element[T]], required

    Elements in the stack.

Example:

stack:
- comment: "escaped literal"
- "ESC"
- "CHAR"
diagram = stack(
    comment("escaped literal"),
    terminal("ESC"),
    terminal("CHAR"),
)

escaped literalESCCHAR

type syntax_diagrams.NoBreak[T]

Describes a sequence of elements that doesn’t wrap.

This is a shortcut for creating a Sequence with linebreaks set to NO_BREAK.

Dict keys:

  • no_break: list[Element[T]], required

    Elements in the no-break sequence.

Example:

no_break:
- comment: "escaped literal"
- "ESC"
- "CHAR"
diagram = no_break(
    comment("escaped literal"),
    terminal("ESC"),
    terminal("CHAR"),
)

escaped literalESCCHAR

type syntax_diagrams.Choice[T]

Describes a choice between several elements.

Dict keys:

  • choice: list[Element[T]], required

    Elements to choose from.

  • default: int

    Index of item that will be placed on the main line.

    Should be less then number of choice elements.

Example:

choice:
- "INT"
- "STR"
- sequence:
  - "("
  - non_terminal: "expr"
  - ")"
default: 1
diagram = choice(
    terminal("INT"),
    terminal("STR"),
    sequence(
      terminal("("),
      non_terminal("expr"),
      terminal(")"),
    ),
    default=1,
)

INTSTR(expr)

type syntax_diagrams.Optional[T]

Describes an optional element.

This is a shortcut for creating a Choice with a skip() and a single element.

Dict keys:

  • optional: Element[T], required

    Element that will be made optional.

  • skip: bool

    If set to True, the optional element will be rendered off the main line.

  • skip_bottom: bool

    If set to True, the skip line will be rendered below the skipped element.

Example:

optional:
- non_terminal: "annotation"
skip: true
diagram = optional(
    non_terminal("annotation"),
    skip=True,
)

annotation

type syntax_diagrams.OneOrMore[T]

Describes a repeated element.

Dict keys:

  • one_or_more: Element[T], required

    Element that will be repeated.

  • repeat: Element[T]

    An element that will be placed on the backwards path.

Example:

one_or_more:
  non_terminal: "expr"
repeat: "COMMA"
diagram = one_or_more(
    non_terminal("expr"),
    repeat=terminal("COMMA"),
)

exprCOMMA

type syntax_diagrams.ZeroOrMore[T]

Describes an optional repeated element.

This is a shortcut for creating an Optional with an OneOrMore element inside.

Dict keys:

  • zero_or_more: Element[T], required

    Element that will be repeated.

  • repeat: Element[T]

    An element that will be placed on the backwards path.

  • skip: bool

    If set to True, the optional repeated element will be rendered off the main line.

  • skip_bottom: bool

    If set to True, the skip line will be rendered below the skipped element.

Example:

zero_or_more:
  non_terminal: "expr"
repeat: "COMMA"
diagram = zero_or_more(
    non_terminal("expr"),
    repeat=terminal("COMMA"),
)

exprCOMMA

type syntax_diagrams.Barrier[T]

Isolates an element and disables optimizations that merge lines between this element and the rest of the diagram.

Dict keys:

  • barrier: Element[T], required

    Element that will be isolated.

Example:

- "A"
- optional:
  - "B"
  - barrier:
    - optional:
      - "C"
diagram = sequence(
    terminal("A"),
    optional(
        terminal("B"),
        barrier(
            optional(
                terminal("C"),
            )
        )
    )
)

Without barrier:

With barrier:

ABC

ABC

type syntax_diagrams.Group[T]

Draws a box around some element.

Dict keys:

  • group: Element[T], required

    Element that will be placed in a group.

  • href: text

    Optional caption for this group.

  • href: str

    Makes group’s caption into a hyperlink.

  • title: str

    Title for hyperlink.

  • css_class: str

    Adds CSS class to group’s <g> element.

Example:

- "def"
- "("
- group:
  - zero_or_more:
    - non_terminal: "param"
    - optional:
      - ":"
      - non_terminal: "type"
    repeat: ","
  - optional: ","
  text: Function parameters
- ")"
- ":"
diagram = sequence(
    terminal("def"),
    terminal("("),
    group(
        zero_or_more(
            non_terminal("param"),
            optional(
                terminal(":"),
                non_terminal("type"),
            ),
            repeat=terminal(","),
        ),
        optional(terminal(",")),
        text="Function parameters",
    ),
    terminal(")"),
    terminal(":"),
)

def(Function parametersparam:type,,):

Using constructors

If you’re building diagrams manually in python code, you can use these constructors:

syntax_diagrams.skip() Element[T]

Create an element that renders as a single line without content.

See Element for more information.

syntax_diagrams.terminal(text: str, *, href: str | None = None, title: str | None = None, css_class: str | None = None, resolve: bool | None = None, resolver_data: T | None = None) Element[T]

Create a terminal node with optional additional settings.

See Terminal for description of parameters.

syntax_diagrams.non_terminal(text: str, *, href: str | None = None, title: str | None = None, css_class: str | None = None, resolve: bool | None = None, resolver_data: T | None = None) Element[T]

Create a non-terminal node with optional additional settings.

See NonTerminal for description of parameters.

syntax_diagrams.comment(text: str, *, href: str | None = None, title: str | None = None, css_class: str | None = None, resolve: bool | None = None, resolver_data: T | None = None) Element[T]

Create a comment node with optional additional settings.

See Comment for description of parameters.

syntax_diagrams.sequence(*items: Element[T], linebreaks: _t.Literal['HARD', 'SOFT', 'DEFAULT', 'NO_BREAK'] | LineBreak | list[_t.Literal['HARD', 'SOFT', 'DEFAULT', 'NO_BREAK'] | LineBreak] | None = None) Element[T]

Create an automatically wrapped sequence of elements.

See Sequence for description of parameters.

syntax_diagrams.stack(*items: Element[T]) Element[T]

Create a sequence of elements that wraps after each element.

See Stack for description of parameters.

syntax_diagrams.no_break(*items: Element[T]) Element[T]

Create a sequence of elements that doesn’t wrap.

See NoBreak for description of parameters.

syntax_diagrams.choice(*items: Element[T], default: int = 0) Element[T]

Create a choice between several elements.

See Choice for description of parameters.

syntax_diagrams.optional(*items: Element[T], skip: bool = False, skip_bottom: bool = False) Element[T]

Create an optional element.

See Optional for description of parameters.

syntax_diagrams.one_or_more(*items: Element[T], repeat: Element[T] | None = None) Element[T]

Create a repeated element.

See OneOrMore for description of parameters.

syntax_diagrams.zero_or_more(*items: Element[T], repeat: Element[T] | None = None, skip: bool = False, skip_bottom: bool = False) Element[T]

Create an optional repeated element.

See ZeroOrMore for description of parameters.

syntax_diagrams.barrier(*items: Element[T]) Element[T]

Create a barrier element.

See Barrier for description of parameters.

syntax_diagrams.group(*items: Element[T], text: str | None = None, href: str | None = None, title: str | None = None, css_class: str | None = None) Element[T]

Create a group element.

See Group for description of parameters.

Line breaks and wrapping

You can use Stack and NoBreak to control how diagram lines are wrapped. Additionally, you can pass a list of line breaks to a Sequence element.

class syntax_diagrams.LineBreak(*values)

Type of a line break that can be specified when creating a sequence.

DEFAULT = 'DEFAULT'

Prefers not to break line in this position unless necessary.

HARD = 'HARD'

Always breaks a line in this position.

NO_BREAK = 'NO_BREAK'

Disables breaking in this position.

SOFT = 'SOFT'

Breaks a line in this position if the sequence can’t fit in allowed dimensions.