Functions are the key feature of Quarkdown, distinguishing it from other Markdown dialects and many other markup languages. They are loaded from external libraries, either native (e.g., standard library) or defined in a Quarkdown source, and come in different categories:
| Category | Examples |
|---|---|
| Layout rules | row, column, grid, center |
| Utility views | tableofcontents, whitespace |
| Mathematical and logical operations | sum, divide, pow, sin, isgreater |
| Control structures and statements | if, foreach, repeat, var, let, function |
| File data | include, csv, read |
| Alteration of document metadata | docname, docauthor, doctype, theme, pageformat |
When called from a Quarkdown source, the function name is preceded by a . (dot) and each argument is wrapped in curly brackets.
.myfunction {arg1} {arg2}.multiply {6} {3}18
In the previous snippet, arg1 and arg2 refer to the first and second parameter of the function signature respectively. These are called positional arguments because their meaning is determined by their position in the call.
An argument can also refer to a parameter by name. These named arguments use the syntax name:{arg}.
.myfunction firstparam:{arg1} secondparam:{arg2}You can mix positional and named arguments to improve readability of the function call, as long as all arguments that follow a named argument are named as well.
.multiply {6} by:{3}18
Arguments can span over multiple lines. Indentation is optional and arbitrary.
.divide {
.cos {.pi}
} by:{
.sum {2} {1}
}-0.33333334
Function calls can be nested in arguments, allowing you to compose complex expressions.
.multiply {.pow {3} to:{2}} by:{.pi}28.274334
Although Quarkdown exclusively relies on top-level declarations, it exploits some OOP-like syntactic sugar that greatly increases the readability of nested function calls.
Consider the following call:
.sum {.subtract {.pow {3} {2}} {1}} {2}This performs
.pow {3} {2}::subtract {1}::sum {2}Much better. It now resembles the way we naturally read math.
To understand how chaining works, consider this simpler example (see Variables to learn more about variables):
.myvar::uppercaseBehind the scenes, the compiler transforms this call into:
.uppercase {.myvar}.var {myvar} {hello!}
.myvar::uppercaseHELLO!
Generally speaking, .a::b is transformed into .b {.a}, .a::b::c into .c {.b {.a}}, and so on.
You can append additional arguments to any function in the chain. Just keep in mind that the chained value is always the first argument, positionally speaking, of the next call.
.a {x}::b {y} is transformed into .b {.a {x}} {y}:
.sum {10} {5}::multiply {2}30
Many core functions are designed to be called in a chain, for example None operations.
Function calls can appear in two contexts: inline or block.
An inline function call is preceded and/or followed by other inline content, such as text. The output of an inline function call is simply replaced in the parent’s block.
Ever wondered what **26+16** equals? It's .sum {26} {16}. Here you go.Ever wondered what 26+16 equals? It’s 42. Here you go.
A block function call is an isolated one. For context, in Markdown, a block is a paragraph, a code snippet, a quote, a list, and so on.
Paragraph 1
.myfunction {arg1} {arg2}
Paragraph 2The main difference between inline and block function calls is a special argument called body argument. This argument always refers to the last parameter of the signature (even if named arguments were used).
A body argument expands over multiple lines, is not wrapped by brackets, and requires each line to be indented by at least two spaces or one tab:
.myfunction {arg1} {arg2}
Body argument, line 1
and line 2.The whole body must share the same indentation. The following produces unexpected results, as indentation is inconsistent:
.myfunction {arg1} {arg2}
Body argument, line 1
and line 2. <!-- This is a 4-spaces indented code block! -->Other functions, block or inline, can be nested inside body arguments:
.row alignment:{center} <!-- Block -->
This document was made by .docauthor <!-- Inline -->
.column <!-- Block -->
The document name is .docname <!-- Inline -->
.loremipsum <!-- Block -->When nested inside inline arguments, function calls are always inline. Thus, the following is invalid since body arguments are accepted only in block calls:
.center {
.row
Hi
}While this is valid as .row is called within a body argument:
.center
.row
Hi