Nyarna's syntax is primarily inspired by LaTeX. Some may say that this kind of syntax is outdated or clunky, but it actually caters to Nyarna's use cases quite well. Alternatives have been evaluated and deemed inept: Indentation-based structuring (like Python or YAML) isn't a good fit for a language where data structures can frequently be longer than what's visible on the screen. Minimal syntax like AsciiDoc doesn't provide a sensible way of accessing more complex features.
The syntax, like LaTeX'es, assumes that by default, input is literal data. It then provides a small set of special characters that start command structures. Similar to LaTeX, you are able to modify this set of characters.
In LaTeX, each command defines how you are to provide its arguments:
It may want them positionally (after the command, typically within {…}
), named (like [<name>=<value>, …]
), or as block (between \begin{env}…\end{env}
).
Nyarna unifies these by allowing the usage any mechanism for each argument when calling an entity.
It also uses parentheses and commas for arguments that are not blocks, which is syntax a typical user might be more familiar with.
This is literal data.
Here's a command: \if(true, spam, egg)
\if(true, # give arguments positional,
then=spam # named,
):
egg # or as block
\end(if)
\if(true):
spam # You can have multiple blocks
:else:
egg # by separating them with names
\end(if)
Some LaTeX commands introduce new syntax or change how following content is parsed.
For example, \begin{verbatim}
would parse all following text as content regardless of command characters, until it sees \end{verbatim}
.
This is defined per command.
Nyarna provides similar functionality, but again unifies it by allowing the usage of parser-influencing definitions on any block. Each block can explicitly define how it modifies the parser, or can implicitly inherit a default that is defined on the parameter the block argument binds to.
Some LaTeX environments, like for example TikZ, even introduce completely new syntax. Nyarna can currently do this in a limited way for predefined functionality, like the syntax for defining variables or types. Eventually, it is planned to add functionality to let the user define syntax and use it in blocks.
\block:<off #>
The # character doesn't start a comment in
this block, since it has been turned off.
\end(block)
# after the block, the change is reverted.
\declare:
Bold = \Record:
content: \Text {primary}:<off \>
\end(Record)
\end(declare)
\Bold:
\ doesn't start commands in here due to
the default block header that is inherited.
\end(Bold)
A syntactic feature that doesn't exist in LaTeX is swallowing:
Instead of starting a block for a nested level and ending it with \end(…)
, you can have a call swallow the following content till the end of the surrounding block.
This block will then be an argument as if it were a primary or named block.
Swallowing also ends when a following call swallows at the same or a higher level.
With swallowing, Nyarna allows you to have freestanding heading lines of chapters, sections, subsections etc., while still being able to define that they create nested structure. This is useful to avoid deep syntactic nesting and has been inspired by markup languages like Markdown, AsciiDoc or reStructuredText.
The example code assumes that the given called heading types have been declared somewhere.
\Chapter(First Chapter):1> # swallows at a depth of 1
Some content
\Section(First Section):2> # contained in chapter
More content
# same swallow depth ends previous section
\Section(Another):2>
# ends previous section and chapter
\Chapter(Second Chapter):1>
# swallowing can be implicit if the target
# entity is set up appropriately.
\Section(Implict)
Content of section Implicit