Brocatel Markdown Grammar Spec
Texts
- Usage: Same as texts in Markdown: if the text does not match any spec below, then it is a text.
- Semantics: Texts.
Comments
Usage: Similar to HTML/XML comments since Markdown does not provide a comment grammar.
Semantics: Comments.
<!-- comment -->
.One may also use Lua comments in Lua code blocks if they find it convenient:
`-- comment`
markdown```lua --[[ comment ]]-- ```
Interpolation
Usage: Use Lua code in MDX expressions to interpolate the text with Lua values.
Semantics: The MDX expression is evaluated in the context of the current routine.
1 + 1 is { 1 + 1 }
evaluates to1 + 1 is 2
.
Marking Plural Variables For Gettext
Usage: Adds a
?
in the MDX expression to mark the variable that affects the plural forms of words in the text.Semantics: The variable is marked for Gettext for easier I18N.
You have { 1 + 1 ?} apples.
will generate amsgid_plural
entry in the POT file so that the translation can be done in a better way.
Tags
Usage: Prefixes the text with an inline directive to tag the text.
Semantics: Attaches extra info to the text to be used by external programs.
:tag Text
.:tag[value] Text
.:data[{ 1 + 1 }] Text.
: Interpolation is allowed in tags. However, since tags are intended to pass program-specific data, plurality marks are ignored, and the string will not get passed to Gettext.
Headings
- Usage: Same as headings in Markdown.
- Semantics: A heading defines an anchor that a link can jump to.
Routine Definitions
Usage: A heading that contains a MDX expression.
Semantics: A routine definition defines a routine. The string in the MDX expression is treated as routine-local variable names.
## heading 1 {}
defines a routine namedheading-1
.## heading 1 { var1 }
defines a routine namedheading-1
with a routine-local variablevar1
.
Links & Routine Calls
Usage: Mostly the same as links in Markdown.
If the link looks like a "normal" link (e.g. begins with
https
), the compiler treats the link as it.Semantics: A link either directs the story flow to a certain heading or calls a routine.
[](#heading-1)
jumps to the headingheading-1
if the heading is not a routine. Otherwise, it calls the routineheading-1
.[{ var1 = 1 }](#heading-1)
calls the routineheading-1
with the routine-local variablevar1
set to1
.[](another.md#heading-1)
similarly calls/jumps to story inanother.md
with the headingheading-1
. This allows splitting a story into multiple files. No manual file linking is needed.
Lua Evaluation
Compile-Time Evaluation
Usage: A code block with its meta string set to
macro
.Semantics: The code block is evaluated at compile-time to extend the compiler with macros, etc.
For example,
markdown```lua macro function hello_world() return md.paragraph({ md.text("hello world from a macro") }) end ```
defines a macro
hello_world
that returns a Markdown paragraph with the text.
Runtime Evaluation
Global Lua Evaluation
Usage: A code block with its meta string set to
global
.Semantics: The code block is evaluated at runtime when loading the story.
For example,
markdown```lua global player_name = "Alice" initial_score = 0 ```
initializes the global state.
Local Lua Evaluation
Usage: Inline code snippets on a single line or Lua code blocks.
Semantics: These Lua code is run when the story passes through the code block.
`v = 1`
sets the variablev
to1
, which is the same as:markdown```lua v = 1 ```
Conditional Execution
Usage: A paragraph starts with a inline code snippet, following by texts.
Semantics: The snippet is evaluated as Lua code, and if the result is true, the paragraph is show as texts.
`score == 100` You win!
If the variable
score
is equal to100
, the paragraph is shown.
Lua Runtime Environment
See arch.md.
Macro Usage
Usage: A customized Markdown grammar:
markdown:::macro_name `extra info` - Macro specific argument 1 - Macro specific argument 2 - ... - :::nested_macro - Correct indentation is needed.
Alternatively:
markdown:::any_macro_name ```lua func local new_node = process(arg) return new_node ``` - Macro specific argument 1 - Macro specific argument 2 - ... - :::nested_macro - Correct indentation is needed.
Built-In Macros
The if
, do
, local
and nil
macros are implemented by the JS/TS compiler, whose names are intentionally selected be Lua keywords to avoid conflicts with the user-defined macros.
if
: Extended form of the`condition` Text.
grammar with anelse
branch.markdown:::if `score == 100` - You win! - You lose. (The else branch here.)
do
: Calls a Lua function, passing the arguments specified in the list.markdown:::do `function_name` - Argument 1 - Argument 2
local
: A quoted block of text, useful to avoid conflicting heading levels, mostly used by macros.markdown# heading-1 :::local - # heading-1 No heading name conflict. - :::local - Nesting allowed.
nil
: Ask the compiler to treat the arguments as plain Markdown.markdown:::nil - `this is no more Lua expression but a Markdown code snippet`
The following macros are also built-in macros, but instead implemented in Lua as examples of custom macros. See mdc/src/macros/builtin.lua
for details.
loop
: Repeatedly executes part of the story.markdown:::loop `label` - Text 1. - Text 2.
switch
: Evaluates an expression, and executes the corresponding case.markdown:::switch `a = 100` - `a == 0` Result: 0 - `0 < a and a < 100` Result: 1~99 - `a == 100` Result: 100
Threads & Coroutine Grammar
Coroutine
Usage: Use
> [](#routine)
to create a coroutine.If a coroutine runs to the end, one of the remaining threads will be selected as the next thread to run. If there is none, the story ends.