Emblem logo

Introduction

When writing documentation, there are generally two choices: good looking source, and good looking output. In spite of their ease-of-use, word-processors are typically unable to produce good-quality typographic output, with poor hyphenation and justification algorithms, lax placement of figures and only rudimentary support for global document styling. On the flip-side, high-quality typesetting programs can be unintuitive, have odd behaviours and use a notation which us unfriendly to the user. Emblem bridges the gap between these two realities.

When many existing programs were created, some particularly useful technologies either did not exist or were in their infancy. Emblem is designed with a more modern approach to the process of typesetting large documents, in particular, it is designed to be extensible, hackable and with support for global styling rules with CSS.

Although significant effort has been expended to make Emblem easy to use, it is expected that the user will have some familiarity with:

  • Running programs from the command-line / shell
  • Basic knowledge of CSS styling rules

What’s Emblem?

Emblem is an elegant, extensible typesetter with both a friendly interface and good output. It sports:

  • A lightweight, uncluttered, unified syntax
    • With Markdown syntactic sugar
  • Extension support through a simple interface
    • User-space extensions allow for the creation of arbitrary document elements
    • Driver-extensions allow for output on any device
  • Excellent typographic quality output
  • Global document styling through either CSS, SCSS or SASS

Usage & Document Format

Suppose we have a simple document called hello.em---

# Hello, world!

How are you today? Here's a poem I like.

.centre:
	Murder Squad, Murder Squad,
	Does whatever a murder squad does
	Can they swing from a web?
	No they can’t ... Murder Squad

Hope _you_ **like** `it`.

This can be compiled into a PDF (the default output driver) with the following command---

em hello

The command-line interface allows for a good amount of customisation of the typesetting run. For example, the above could be modified to apply a different base style, ‘my-article-style,’ outputting to HTML---

em hello -cmy-article-style -Thtml

Remarks

This documentation has sections for all kinds of Emblem users, from document- and extension-writers to Emblem-developers. No user is expected to require all of the information in these docs, hence they are split into separate sections which contain:

How Emblem Works

In this document, we will discuss the how documents are processed, how documents are styled, extensions and input and output drivers.

At its most abstracted level, Emblem takes input of a document, typesets it and outputs it. It does this by parsing its input looking for directives, structuring-calls calls which sub-divide a document’s source, which can apply both styles to and perform computation upon document content. Emblem contains a standard library of directives to facilitate many common tasks encountered when writing. For example, to create a document with a table of contents and some headings, something akin to the following could be used.

.toc // Constructs the table of contents
.h1: Hello, world!
This is my first document.

If this is in a file called my-first-doc.em, we can typeset it by executing the following.

em my-first-doc

As one might expect, this creates a table of contents followed by a level-1 header and then a some text. The .h1 directive is a good example of what directives can do as it applies both the .h1 style (by default is an emboldened and enlarged form of main text) and computes the heading number. This latter follows the convention of technical documents for headings and sub-headings, so for example the heading numbered 2.5.3 would be the third sub-sub-heading under the fifth sub-heading in the second section of a document.

The order in which elements are computed leads us to the first defining feature of Emblem.

The typesetting Loop

Emblem processes its input from start to finish and whilst this lends itself naturally to some concepts, it is somewhat at-odds with others. A notable example of this latter case is the creation of a table of contents. As is both customary and seen in the above document, the table of contents is placed before the body of the text where the headings which it will contain are defined. The problem is that when the table of contents is required, we cannot guarantee that headings have been processed, so Emblem would not be able to construct an accurate table of contents.

To alleviate this, Emblem operates a typesetting loop whereby it repeatedly typesets the document until either it has settled to a consistent state, or until a cut-off number of iterations is reached. As such, the overall operation of Emblem can be considered as below.

How Emblem loops

The typesetting loop gives the user the guarantee that---with sufficiently-many iterations---the document output by Emblem will fully typeset after a single execution of the ‘em’ binary. These docs also provide more information on how to control the typesetting loop elsewhere. For now, however, we turn to the question of document styling.

Styling documents with CSS

Writing documents inherently brings two concerns: the writing of good text to appeal to the mind, and the application of pleasant styles to appeal to the eye. Naturally, when writing, some modicum of consideration must be lent to each, but they are naturally at-odds. Given finite time, an author must decide how best to partition their efforts to please their audience. In the extreme cases, we have on the one hand the screen-writer who, knowing their document is but a means to the realisation of their work, will choose to write using mono-spaced typefaces, with minimal concern of layout, and on the other hand the graphic designer who pours endless hours into the presentation and adjustment of but a few important words.

By making use of Cascading Style Sheets (CSS), Emblem supports this writers’ dichotomy. CSS is an expressive and highly extensible method of applying visual information to structured documents and, through industrious use of its selection rules, an author can construct good abstractions for how their document will appear. This allows styling information to be automatically applied, thereby allowing the user to focus their attention entirely upon one of style and content, when the time comes.

A very useful example is in the insertion of indents at the start of paragraphs. In long-form text in the Latin alphabet, the modern style starts each paragraph on the line immediately below the last and, to highlight the boundary, adds an indent to the first line of each paragraph after the first. This allows the first paragraph to neatly sit upon the upper left reaches of its allotted space, the entire body of text to calmly flow uninterrupted, and for paragraphs to be clearly yet unobtrusively be delimited. This can be concisely encoded through the use of CSS’s selectors as below.

p { /* By default, paragraphs are not indented */
	text-indent: none;
}
p + p { /* A paragraph which directly follows another requires an indent */
	text-indent: 2em;
}

As a result of this short snippet, the author no longer needs to consider where paragraph indents are applied as it will be handled automatically.

The user is able to add their own styles by specifying some style sheet which can be used to override the defaults and thereby tailor the look of their document.

Extensions

Automation and extensibility are at the heart of Emblem, and in this section we’ll describe how it is possible to direct Emblem to do some of the author’s work for them. When a call to a directive, d, is evaluated, Emblem first checks to see whether d is associated with an extension function. If it is, then this function is executed and its result is taken to be a part of the document. An example of this can be seen above concerning the .toc directive, which constructs a table of contents from headings.

Extensions are simply Lua files and have two purposes in Emblem---the import of custom style sheets and the creation of new directive functions. These style sheets are considered to be ‘above’ the user’s one, thus allowing for defaults to be created and overridden as required. Conversely, directive functions have slightly more nuance. As Emblem processes a document, it maintains a Lua environment which contains a public table called ‘em.’ It is this table which is checked to determine whether a given directive name has an associated function to call.

Extensions can be added to the runtime by use of the -x/--extension option and arguments can be passed to these extensions through use of the -a/--ext-arg option. For example, to include an extension ext with parameter param given a value arg, the following can be used.

em -x ext -a ext.param=arg

To define a new directive function, an extension simply adds an entry into the ‘em’ table,1 alongside help text and the number of parameters it expects. The entry also encodes some basic type information, so if a directive is called with the wrong number of arguments, a warning can be issued. These entries also encode a help message which can be accessed through the .help directive. The following example shows information about the .echo directive:

.help{echo}

Being constructed from Lua, extensions allow for arbitrary functionality when writing a document, however this is not the only place where extensions can operate.

Input and output drivers

The other place in Emblem where extensions are accepted is when the program takes input or writes output. Until this point, we have only discussed the writing of documents in Emblem source files (*.em) however in truth, Emblem can parse any format for which it has the appropriate input driver. The same is true when writing output---the formats to which Emblem may output depend only the output drivers it knows.

These options can be accessed through the command-line api by using the -F/--from and -T/--to options. The following will take input of html and output markdown.

em -Fhtml -Tmd mydoc.html

The above is somewhat redundant---we have specified that the input file is html both explicitly with the -F option, but also implicitly with the .html file extension. Therefore, Emblem also maintains a mapping of file-extensions to input languages and when no -F option is specified, the input file extension is used to determine the parser to use. The core Emblem parser is used by default.

In the case of input drivers, it is also possible to access this same functionality from within a document, thus allowing for a document’s source to comprise of multiple languages as the author requires. This is done through use of the .include directive.

.include{some-file} // Includes some-file.em
.include{some-file.em} // Same as the above
.include{some-other-file.html}{html} // Includes ‘some-other-file.html’ using the html language explicitly
.include{some-other-file.html} // Same as the above but Emblem implictly figures out that the input language is ‘html’

Information on how to write input drivers and output drivers can be found elsewhere in these docs.

1

The Emblem public table, ‘em,’ can be imported from std.base

Expressions and Conditions

In Emblem, an expression is a section of text which is parsed and evaluated as a mathematical statement. These can be used to concisely represent maths operations without using the arithmetic or logic directives. A condition is a special case of an expression, where if the expression is empty, false is returned instead of emitting a parse-error. These are commonly used in the flow-control directives.

It must be noted that expressions are only capable of handling numbers, so for checking textual equality for example, the .streq directive must still be used.

The following operators are recognised in expressions with the numbers giving their precedence level with higher numbers indicating that the associated operators bind more tightly. As the multiplication operator, *, has a higher precedence than the binary subtraction operator, -, we can see that the expression 1+2*3 is correctly evaluated to 7 instead of 9.

    • <==> -- Dual implication
    • ==> -- Single-implication (right)
    • <== -- Single-implication (left)
    • || -- Disjunction (‘lazy-or’)
    • && -- Conjunction (‘lazy-and’)
    • <=> -- Dual implication (higher precedence)
    • => -- Single implication (right, higher precedence)
    • != -- Numeric inequality
    • == -- Numeric equality
    • <= -- Inequality, less-than-or-equal, lazy
    • < -- Inequality, less-than, lazy
    • >= -- Inequality, greater-than-or-equal, lazy
    • > -- Inequality, less-than, lazy
    • ~ -- Bitwise exclusive disjunction (‘xor’)
    • | -- Bitwise disjunction (‘strict-or’)
    • & -- Bitwise conjunction (‘strict-and’)
    • + -- Addition
    • - -- Subtraction
    • // -- Integer division
    • % -- Modulo
    • * -- Multiplication
    • / -- Division
    • ! -- Logical negation
    • - -- Numeric negation
    • ~ -- Bitwise negation
    • + -- Unary plus
    • ^ -- Exponentiation

Example -- Fizz-Buzz

The following is a solution in Emblem to the FizzBuzz common interview problem. This is by no means a model solution for Emblem is not a programming language---first and foremost it is a typesetter, it just happens to have a handy extension language which can be programmed in.

.for{!i <- 1}{1 <= !i <= 100}{!i <~ !i + 1}:
	.if{!i % 15 == 0}:
		.echo: FizzBuzz
	::
		.if{!i % 5 == 0}:
			.echo: Buzz
		::
			.if{!i % 3 == 0}:
				.echo: Fizz
			::
				.echo: !i

Document directives

In Emblem, the semantic structure of a document is partitioned by the use of directives. As the document is processed, they are used to enact not only styling changes but also extension functions.

  • If an extension function exists a same-name entry in the Emblem public table (em to extension-writers), then it is executed
  • If there is a style with the same name as the directive, then that is applied.

All syntactic sugars (such as surrounding a word in underscores to make it italic) are simple translations to directive calls.

Example - Styling part of a sentence

The following lines will all yield the same result---an entire or part of a sentence emboldened by use of the .bf directive.

.bf: This entire sentence is bold
This sentence is only has .bf{two bold} words.
Hello **rather obnoxious** world!

Example - Cross-referencing

In academic papers and technical documents, it is often necessary to refer the reader to different sections, often to inform them of the location if pertinent information. In Emblem, this is done through the label-anchor-reference system: headings and other document items set a label, a document-writer places an anchor at an important location which makes note of the label value there, and then calls a reference to that anchor which returns the required label value.

# If this is some section with some useful things in (behind the scenes it edits the current label value, for example this may be section 6.2.3)

And perhaps this is the location of that useful thing, then an anchor is set with .anchor{a-useful-thing} or the syntactic sugar @useful-thing.

# Some other document sections may then be written

Which contain other things to interest the reader.

When the time comes, and the reader’s attention must be brought back to what was before, the relevant label can be automatically determined when by calling .ref{a-useful-thing} or #a-useful-thing.

Document structure

When writing large documents, it is typically necessary to convey the structure of the piece to the reader to allow them to not only focus their attention where is most beneficial to them, but also to convey the significance of all parts of the text.

For this, it is customary to use a system of headings---declarations of upcoming content---and a table of contents to allow a reader to navigate to wherever they will.

An analogous structure may be befitting of an author---to avoid an overlarge monolithic source, Emblem provides directives and pragmas to allow the source of a document to be partitioned into many different files.

In this section, we will detail each of these concepts:

Example - Multi-section document

The following is a possible outline of the sections of a technical report.

# Introduction
# Background
## Motivating Example
## Concepts
# Literature Review
# Design
## Specification
## Architecture
## UI
# Implementation
## Tools and Libraries
## User-Extensions
# Results and Discussion
# Further Analysis and Extensions
# Evaluation
# Conclusion

Example - Multi-file document

If the above example were written in a single file, it would be reasonable to assume that editing the document would slowly become more and more cumbersome. A more manageable structure may result from taking each heading with both subheadings and a significant amount of content beneath it, and place this in a directory beneath the project root.

.
|- report.em
|- introduction.em
|- background/
|   |- background.em
|   |- motivating-example.em
|   |- concepts.em
|- literature-review.em
|- design/
|   |- design.em
|   |- specification.em
|   |- architecture.em
|   |- ui.em
|- implementation/
|   |- implementation.em
|   |- tools-and-libraries.em
|- results-and-discussion.em
|- further-analysis-and-extensions.em
|- evaluation.em
|- conclusion.em

As we are only including Emblem source files, we can make use of the :include pragma to invoke the source of each document, hence the main file, report.em---and also the main file in each of the sections in subdirectories will look something like the below.

As a part of the file inclusion process for Emblem source, if a file file.em is not found, then file/file.em is tried, hence the root does not need to encode exactly how its contained sections are laid out in the file system.

:include "introduction"
:include "background"
:include "literature-review"
:include "design"
:include "implementation"
:include "results-and-discussion"
:include "further-analysis-and-extensions"
:include "evaluation"
:include "conclusion"

Where possible, the user should try to use the :include pragma instead of the .include directive as the former is more efficient, skipping a translation step between extension space and the core, which contains the Emblem parser used by both methods.

.h1, .h2, .h3, .h4, .h5, .h6

These directives create level 1--6 headers respectively, that is, markers to delimit the sections of a document to the reader. These headers be numbered and will appear in the table of contents. To create a header which does not appear in the =toc,= the starred variants may be used, that is .h1* in place of .h1 etc.

The header directives take a single argument, the text of the header.

Given the frequency with which headers appear in documents, syntactic sugar is available---any line which starts with between one and six hashes and some space will have the remainder of the line taken as a header, just as in markdown. Hence the line .h3: some text is the same as ### some text. Similarly, .h3*: some other text is the same as ###* some other text.

Example -- Document structure

Sections can be used to break different parts of a document (or in this case presentation script) into smaller marked areas for consumption by an intended audience.

# Introduction
Hello and welcome to our presentation on the dangers of garden gnomes.
# Why Garden Gnomes are Dangerous
You might not know this but garden gnomes are dangerous.
## What a Garden Gnome can do
You never know what a gnome will do when your back is turned.
## What Have Garden Gnomes Been Observed Doing?
Nobody has been able to record any suspicious activity in relation to garden gnomes, but that's exactly what they'd want.
# Conclusion
Watch your back out there, kiddos.

Example -- Document sections (exhaustive document)

The following is an exhaustive list of available headers and their related syntactic sugars.

.h1: This is the largest header
.h2: This is a sub-header
.h3: This is a sub-sub-header
.h4: This header is even deeper
.h5: This is an extremely deep header
.h6: This header is so deep its utility is questionable but here it is

# This is the largest header
## This is a sub-header
### This is a sub-sub-header
#### This header is even deeper
##### This is an extremely deep header
###### This header is so deep its utility is questionable but here it is

.h1*: This appears the same as `.h1` but is un-numbered and absent from the TOC
.h2*: Same as the above but smaller
.h3*: Same as the above but smaller
.h4*: Same as the above but smaller
.h5*: Same as the above but smaller
.h6*: Same as the above but smaller

#* This appears the same as `.h1` but is un-numbered and absent from the TOC
##* Same as the above but smaller
###* Same as the above but smaller
####* Same as the above but smaller
#####* Same as the above but smaller
######* Same as the above but smaller

.include, .include* and :include

When writing large documents which consist of a large number of sections, it can be beneficial to partition the source into a number of smaller files. The result can be a document which is much easier to work upon than a single monolithic source file.

In Emblem, there are three methods by which the contents of another file can be included in a document:

  1. The .include directive,
  2. The .include* directive and
  3. The :include pragma (notice the ‘:’ prefix rather than ‘.’).

We will explain the basic usage of each, before discussing how paths and languages are handled.

Basic Usage

In basic use, the .include directive takes input of a file name with either no extension or ending in ‘.em,’ tries to find that file, parses it as an Emblem document and then returns the result. This result is also cached to avoid repeatedly re-parsing the same file.

The contents of the specified file is then pasted into the document in the current location. Due to how paragraphs are recognised, if the call to .include is the only thing in a paragraph, then the given file’s contents are scanned to discern paragraphs, however, if it is not the sole member of the paragraph, then its contents is added directly into the paragraph.

.include: some-file // Paragraphs in some-file.em are parsed as if were written directly in the source file

Some sentence.
.include: some-file // Content of some-file.em are pasted into the surrounding paragraph so likely appear as more sentences.
Some other sentence.

If the file being read is expected to change between typesetting iterations, the .include* directive may be used, which does not cache its result. This is hence less efficient for un-changing source files. The .include* directive shares all other properties of the .include directive.

The :include pragma differs from the .include directive as it is handled at parse-time, beyond the extension environment and as such, the file-path is fixed. The following will include ‘some-file.em’ like the above---

:include "some-file"

As this is handled separately from extensions, the file path given to :include is constant---it cannot be changed dynamically by the user and is read exactly as seen in the source file. Hence although the :include pragma is restrictive, it provides a guarantee to external tools parsing Emblem source as to the structure of the document, without needing to implement evaluation mechanics.

File name handling

The sections in a large document naturally differ in size---the introduction and conclusion are likely dwarfed by the body of a report, the preamble and acknowledgements are likely dwarfed by these in turn, and even among the main passages of work, some will bring together content from many sources and some only few. As such, it can be useful to partition a document’s source files into multiple folders, each helping group together relevant materials. The file structure of a report may hence look something like this, with report.em as the main file.

.
|- report.em
|- introduction.em
|- background/
|   |- background.em
|   |- motivating-example.em
|   |- concepts.em
|- literature-review.em
|- design/
|   |- design.em
|   |- specification.em
|   |- architecture.em
|   |- ui.em
|- implementation/
|   |- implementation.em
|   |- tools-and-libraries.em
|- results-and-discussion.em
|- further-analysis-and-extensions.em
|- evaluation.em
|- conclusion.em

In Emblem, this file structure is embraced by the method by which Emblem searches for ‘.em’ files. When given a file name either file.em or just file (no extension), Emblem first searches for that file in the current directory, and if this is not found, it searches for file/file.em. As such, we can include all of the required ‘.em’ files from the main one without needing to know how the files are laid out on disk, allowing for a more abstracted view. The main file can hence be written as:

:include "introduction"
:include "background"
:include "literature-review"
:include "design"
:include "implementation"
:include "results-and-discussion"
:include "further-analysis-and-extensions"
:include "evaluation"
:include "conclusion"

Languages and input drivers

So far, we have only discussed the inclusion of Emblem source files, however, this is not the only format accepted by Emblem. By making use of input drivers either explicitly or implicitly, we can make use of document source written in other languages.

To explicitly make use of input drivers, we can make use of the optional second argument of the .include and .include* directives. In this parameter, we can specify the language of the given source file, prompting Emblem to look for a parse function associated with that language.1 The result of calling this function on the input file is then returned.

.include{some-file.html}{html} // Asserts that some-file.html should be parsed as html

The implicit use of input drivers helps eliminate some redundancy in the above statement---when a file extension is given, Emblem uses a mapping of extensions to input languages before finding the parse function as before. As such, the second parameter in the above .include call can be removed, relying on Emblem to recognise the input language, hence leading to a cleaner source.

.include{some-file.html}

As extensions are involved in the processing of languages, we can see that the above logic only applies to the .include and .include* directives, and not the :include pragma.

1

Recall that input drivers are just extensions which declare an association between an input language and a parse function.

.toc

The .toc directive creates a table of contents by making a list of all of the headings of a document. As this list is only complete at the end of a run, after the .toc has been processed, a document with a table of contents always requires at least two iterations of the typesetting loop. No arguments are taken.

.toc

If there are headings which an author does not wish to be seen in the contents table, starred variants of the heading directives should be used, that is, every appearance of .h1 or # ... should be replaced with .h1* or #* ... respectively, for .h1 to .h6, and # ... to ###### ....

References

Any respectable document needs a way of referring to content both within and without, the former being used to soundly structure the arguments of a document, and the latter to invoke facts presented elsewhere.

In Emblem, these two modes of reference are handled by two systems:

The concepts presented in this section will likely be familiar to LaTeX users as much inspiration has been taken from the \label, \ref, \bibliography and \cite commands therein.

.anchor and .ref

  • Note differences between anchor, label and ref
  • Note scoping due to label storage in variable

.bib and .cite

To reference other works outside of a document, we can use citations which point to bibliography entries with information on how to find the exact source. In Emblem, these are done using the .cite and .bib directives.

The .cite directive takes input of a key, a unique string which provides a reference to a particular bibliography item.

The bibliography is both parsed and produced by the .bib directive. // TODO: talk about the optional argument!

.bib // Reads from the default location
.bib: file // Reads from some-file if it exists, otherwise, file.yml, file.yaml or file.json

Unless the optional bibliography file-name parameter is given, this directive reads searches for a file called ‘bib’.

carlson2011you:
  title: "You probably think this paper's about you: Narcissists' perceptions of their personality and reputation."
  author: Carlson, Erika N and Vazire, Simine and Oltmanns, Thomas F
  journal: Journal of personality and social psychology
  volume: 101
  number: 1
  pages: 185
  year: 2011
  publisher: American Psychological Association
greenfield2015asdf:
  title: "ASDF: A new data format for astronomy"
  author: Greenfield, P and Droettboom, M and Bray, E
  journal: Astronomy and Computing
  volume: 12
  pages: 240--251
  year: 2015
  publisher: Elsevier

Flow control

Some directives can be used to manipulate the contents of the document in response to some conditions. Indeed, this subset of available directives are designed to act as a small Turing-complete programming language.

Over the following sections, we will explore directives for:

.call

The .call directive takes input of a directive name and some arguments to pass to it. It returns a call to the specified directive with the arguments given. For example, one could call .echo with three arguments like so---

.call{echo}{Hello}{world}{how are you?}

Which is implicitly translated by the .call to---

.echo{Hello}{world}{how are you?}

As the name of the directive is required, note that the . which precedes directive calls is omitted, so .echo above becomes just echo.

Example - Specifying an error function

The following code could be used to change the severity of an error condition based on a user’s preference. That the user inputs a number is assumed for brevity.

!err_severity <- .readline
!err_func <- .case{!err_severity}{echo}{warn}{error}
...
.call{!err_func}: Something went wrong!

.case

The case directive is used to select one of a number of cases by index. These cases are 1-indexed, so the first is referenced by index 1. So for example if !index is 2, the following will be evaluated to ‘World.’

.case{!index}:
	Hello
::
	World
::
	How are you?

If the index supplied is higher than the number of cases present or is negative, the last case is returned as a fallback option, hence if above !index is -1 or 12 for example, ‘How are you?’ will be returned.

The index given to .case is parsed as an expression, hence it is possible to compute the index using mathematical operators.

Example -- Chinese calendar year name

The following could be used to translate from the year number in the Gregorian calendar to its Chinese calendar name, assuming the current year is stored in !year.

.case{1 + !year % 12}{Rooster}{Dog}{Pig}{Rat}{Ox}{Tiger}{Rabbit}{Dragon}{Snake}{Horse}{Goat}{Monkey}

.def

This directive allows the user to define their own directives for later use. It takes two inputs: a directive name and a directive body to be executed whenever the new directive is called. The new directive is allowed to take parameters which can be referenced by values !n in the loop body, so !1 evaluates to the first argument given, !2 the second and so on.

Note that as a directive name is taken, there is no . preceding the new directive name when .def is called. If functions are nested, it may be useful to use multiple exclamation marks when accessing arguments from different scopes.

Example -- Checking input

The following could be used to perform type-checking upon a given value.

.def{bool}:
	.if{! .streq{!1}{true} || .streq{!1}{false}}:
		.error: Expected either ‘true’ or ‘false’ but got !1
	!1

Then, later in the document the following could be written:

.bool{true}
.bool{false}

This would give certainty that boolean values have indeed been given. The .bool function may be useful if some values are stored in variables, or some other method which obscures the value from the source.

The .def directive is provided to allow an author to extend the functionality of Emblem from within their document. It is useful for simple tasks, however for more complicated ones, it may be easier to write an extension and make use of Moonscript or Lua’s abstractions instead.

.defined

The .defined directive checks whether a given directive name corresponds to a known directive function and returns 1 or 0 accordingly.

.defined{echo} // Returns 1 as .echo exists
.undef{echo} // Undefines .echo
.defined{echo} // Returns 0 as .echo no longer exists.

.exists

The .exists directive checks whether a given variable name exists in current scope or in a parent and then returns 1 or 0 accordingly.

.exists{x} // Returns 0 as !x does not exist
!x <- asdf
.exists{x} // Returns 1 as !x now exists.

.for

The .for directive emulates the standard for-loop seen in many programming languages. It takes input of:

  1. An initialiser -- a statement which is performed before iterations commence. It is customary to define an iteration variable here.
  2. A condition -- a condition which is evaluated before each iteration, and if it is found to be false, .for execution terminates
  3. A mutator -- a statement which is executed at the end of each iteration. It is customary to mutate the iteration variable here.
  4. A loop body -- a section of emblem script to execute each iteration which is included in the for-loop’s return value

There are two scope considerations:

  • The loop body is evaluated within its own scope
  • The initialiser, condition and mutator are evaluated within a scope which surrounds the loop body.

This second point means that whereas the default assignment operator, <-, can be used in the initialiser and mutator, for the same effect on the iteration variable, the finding-assignment operator, <--, should be used to ensure that the change to the iteration variable is not lost at inner scope-closure. The same is true of the expression-assignment and finding-expression-assignment operators, <~ and <~~.

Example -- Iterating over even numbers

The following outputs the even numbers inclusively between one and one hundred by allowing an iteration variable, !i to take values from 2 to 100 in increments of 2.

.for{!i <- 2}{1 <= !i <= 100}{!i <~ !i + 2}:
	.echo: !i

.foreach

The .foreach directive takes three inputs: an iteration variable name, a list of values and a loop body, and evaluates the loop body once for each value in the given list, assigning the iteration variable as it goes. The list of values is parsed as a space-separated list.

As an example, the following will write the help text associated with each known directive to the console.

.foreach{d}{.known-directives}:
	.echo: .help: !d

The .foreach directive hence performs a bounded iteration---the number of times it loops is bounded by the size of its ‘values’ input.

Example -- Testing the truth values of a boolean function

This code will iterate over input values to the .expr implication operator, =>, and output the associated truth value.

.foreach{x}{false true}:
	.foreach{y}{false true}:
		.echo: !x !y .expr: !x => !y

.get-var

This directive takes input of a variable name and obtains its value in the current scope. If there is no such value with that name, nothing is returned.

The .get-var directive has associated syntactic sugar, so the following two are equivalent.

.get-var{variable}
!variable

More exclamation points can be used to widen the scope searched, hence !!var will obtain the value of ‘var’ in the scope above its current definition.

The .get-var directive is the counter-part to .set-var, which sets variables to given values.

.if

This directive allows for the selection of a single branch (or none) by use of a condition. This directive takes two forms:

.if{condition}{branch}
.if{condition}{branch 1}{branch 2}

The two-argument form operates as follows:

  • If condition is true, branch is returned
  • Otherwise nothing is returned

The three-argument form operates as follows:1

  • If condition is true, branch 1 is returned
  • Otherwise, branch 2 is returned

Example -- Greetings message

Assuming that the variable !is_morning contains a value which represents whether the current time is morning, we could tailor the user’s greeting message to the current time.

.echo:
	.if{!is_morning}:
		Good morning!
	::
		Hello!
1

This form operates exactly the same as an if-else block common to many programming languages.

.set-var

The .set-var directive is what the !var <- val syntactic sugar is translated to at parse-time. This directive takes the name of a variable and a value, and assigns that variable to the string representation of the given value at the point of call.

By syntactic sugar, the following two lines are equivalent and both set the value of variable hello in the current scope to ‘world.’

.set-var{hello}{world}
!hello <- world

Note the initial exclamation mark required on the second line. This is required by the parser and is reflected in the same number of exclamation marks when referencing that variable.

If the variable name contains exclamation marks, the scope of the assignment is widened, so for example, to set the variable hello in the parent scope and set that to ‘world,’ we can call

.set-var{\!hello}{world}

Note that as we want the literal variable name, the initial exclamation mark must be escaped to prevent variable recognition at parse-time and hence expansion. Only the first exclamation mark requires an escape, so the literal !!asdf can be escaped into \!!asdf. The above snippet is equivalent by syntactic sugar to the following.

!!hello <- world

More exclamation marks will widen the scope-search further.

The .set-var directive has some variants for some specialised use-cases. We combine .expr with .set-var with the .set-var-expr directive, which evaluates the value parameter as an expression before performing assignment. We also have .find-set-var and .find-set-var-expr, which are the same as .set-var and .set-var-expr, except that the search for an existing instance of the variable is always performed, even when the number of exclamation marks specified would not trigger it with the non-find assignment directives. This cleans up the syntax slightly for the common operation of extracting a value from the scope of a loop for example---the following two are equivalent.

!!hello <- world
!hello <-- world

The variants of .set-var each have their own syntactic sugar. The following is a list of all sugars associated with assignment

!var <- value // Equivalent to .set-var{var}{value}
!var <~ exp // Equivalent to .set-var-expr{var}{exp} or !var <- .expr: exp
!var <-- value // Equivalent to .find-set-var{var}{value}
!var <~~ exp // Equivalent to .find-set-var-expr{var}{exp} or !var <-- .expr: exp

Example -- Recording a user’s name for later use

We could write a document like so which takes input of the user’s name and then re-uses that value multiple times. By storing the user’s response in a variable, we can avoid the need to re-ask them.

.echo: Please enter your name
!name <- .readline
Dear !name,
It has come to my attention that the name !name is shared by us both.
Please change yours.
Warmest regards,
!name

.undef

Calling .undef with the name of a directive removes that directive from use. If the given directive is not known, nothing is done.

Example -- Preventing system calls

The following example un-defines the system directive, .$.

.undef{$}

Example -- Ruining user experience

The .undef directive can be used to remove all directives from availability.

.foreach{d}{.known-directives}:
	.undef{!d}

.while

The .while directive takes two inputs: a condition and a loop body and does the following:

  1. Check to see if the condition is true
  2. If it is, evaluate the loop body and go to step 1

The results of each iteration are concatenated together beneath a Content node:

Example -- Sanitising user input

When using the .readline directive which reads a single line from the standard input, some sanitisation may be needed on a user’s input. The following will ask the user for an input until they enter something which isn’t empty

.echo: Please input a number
!x <- .readline
.while{.streq{}: !x}:
	.warn: User didn't enter anything
	!x <-- .readline

Logging

Some directives can be used to report the state of the document, either for general information (.echo), for warning the user about a possibly problematic state (.warn) or for halting execution at a catastrophic failure (.error).

.echo and .echo-on

These directives write text to the standard output. If multiple text arguments are given, they are concatenated together with spaces before being echoed. The .echo-on directive treats its first input as a typesetting loop pass number and will only output on that pass.

Example -- Asking the user’s name

Using the .readline directive a line of input can be read from stdin, allowing the program to respond to the user.

.echo: Hello, what’s your name?
!name <- .readline
.echo: Oh hello, !name

Example -- Outputting the current pass

The following could be placed at the top of an input file to more explicitly show which typesetting pass is currently being evaluated.

.echo-on{1}: Hello this is the first pass
.echo-on{2}: This is the second pass
.echo-on{3}: This is the third one

.error and .error-on

When something has gone terribly wrong, the user may wish to stop the program. In Emblem, this can be done by use of the .error directive, which takes input of a message and outputs it as an error from the current source location before halting the program. If multiple arguments are given, all are concatenated together before output is given as usual.

If the error is only applicable to a certain typesetting pass, the .error-on directive may be used. This takes input of a number and message(s) as the .error directive, but only outputs when the current typesetting iteration is equal to the number given.

For non-critical errors, that is, those for which execution can safely continue, consider using the .warn or .warn-on directives.

Example -- Sanitising user input

When using the .readline directive which reads a single line from the standard input, some sanitisation may be needed on a user’s input. The following will check to see that the user has indeed input something.

.echo: Please input a number
!x <- .readline
.if{.streq{}: !x}:
	.error: User didn't enter anything

.warn and .warn-on

When something has gone wrong but the problem isn’t fatal, a warning may be required to notify the user of what has happened. This can be done using the .warn directive, which takes input of a message and outputs it as a warning from the current source location. If multiple arguments are given, all are concatenated together before output is given as usual.

The .warn directive is subject to the warning-handling specified at the command-line, in particular the -E flag turns warnings into errors.

If the warning is only applicable to a particular typesetting pass, the .warn-on directive may be used, which takes input of a pass number to perform the output upon and the remainder of its arguments as .warn.

Example -- Sanitising user input

When using the .readline directive which reads a single line from the standard input, some sanitisation may be needed on a user’s input. The following will ask the user for an input until they enter something which isn’t empty

.echo: Please input a number
!x <- .readline
.while{.streq{}: !x}:
	.warn: User didn't enter anything
	!x <-- .readline

Logic

To augment the capabilities of the flow control directives, it is possible to construct logical conditions from other statements.

In particular, directives are provided to:

These are discussed in this section.

.eq, .numeq, .streq

In Emblem, there are three modes of equality: structural, textual and numerical. These correspond to the equality functions .eq, .streq and .numeq respectively. Although all compute equality, the differences between each should be noted.

Structural equality -- .eq

This definition of equality is the strongest, it looks at the document structure of two items and asks whether they are identical, that is, not only does it look at each literal fragment, but also checks whether these are arranged in memory in the same way.

It must be noted that results of directive calls are also checked, which can lead to some odd results.

Example -- Identical structures

The following examples all return true as they are identical

.eq{}{}
.eq{hello, world!}{hello, world!}
.eq:
	.it:
		Hello, world!
::
	.it:
		Hello, world!

Example -- Non-equal, apparently identical structures

However, all of the following are false as, although they may appear the same in output they differ in how they got there. Some of the following behaviour may seem strange, but comes as a consequence of the very insistent nature of this kind of equality.

!x <- a
!y <- b
.eq{!x}{!y} // This is false as different variables are referenced (‘x’ and ‘y’)
.eq: // This is false as when evaluated these two sections are given distinct numbers
	# Hello, world!
::
	# Hello, world!
.eq: // This is false due to the method by which trailing arguments are handled (a node to represent hold possibly multiple lines is necessarily inserted
	.it{Hello, world!}
	.it:
		Hello, world!

Example -- Apparently non-equal, identical structures

As syntactic sugar is translated into directive calls when parsing is performed, all of the following are true.

.eq{_something emphasised_}{.it{something emphasised}}
.eq{[a-citation]}{.cite{a-citation}}
.eq{!x <- asdf}{.set-var{x}{asdf}}

Textual equality -- .streq

Whereas structural equality checks the internal representation of structures, textual or ‘string’ equality simply checks to see whether the literal text from two sources is the same, regardless of how they were constructed.

Any structurally-equal pair of values is necessarily textually-equal.

Example -- Non-identical structures with textual equality 1

The following all resolve to a true value at the point when the standard library has finished loading.

.streq{**something emphasised**}{_something emphasised_}
.streq{.tt{something}}{.bf{something}}
.streq{.it{two words}}{.it{two}{words}}

Example -- Apparently-equal structures without textual equality

The following evaluates to a false value for the same reason that it does not have structural-equality---when constructing a .h1 header, a section number is prepended

.streq:
	// The text here is ‘1. Hello, world!’
	# Hello, world!
::
	// The text here is ‘2. Hello, world!’
	# Hello, world!

Numerical equality -- .numeq

Whereas textual equality checks that all literals in the text are equal, numerical equality first attempts to translate the text into a number before doing the same. As a result, numerical equality is weaker than textual equality. The numbers considered are base-10.

It should be noted that the numerical equality function does not perform any operations such as addition or subtraction. If these are required, they must be invoked explicitly through other directives whose results are passed as inputs to .numeq. More information on arithmetic directives is available elsewhere.

Example -- Equal numbers

Prepended zeros have no bearing on the value of a number and hence are ignored under numerical equality. All of the following evaluate to a true value.

.numeq{1234}{1234}
.numeq{1234}{000000000000000001234}

.expr

The .expr directive takes input of an expression, parses and evaluates it. As it uses the same parsing logic as the flow-control directives, it is possible to use .expr for debugging.

Example -- A simple calculator

Using .expr and a while loop, a simple calculator can be made. The following will repeatedly read an expression to evaluate from the user, until they input nothing.

!resp <- .readline
.while{! .streq{}{!resp}}:
	.echo: .expr: !resp
	!resp <-- .readline

.gt, .ge, .lt, .le

The inequality functions take input of numerical values and return a boolean value as one might expect them to in maths. At their heart, they take pairs of numbers and check whether they satisfy the relevant condition:

  • .gt---Greater than
  • .ge---Greater than or equal
  • .lt---Less than
  • .le---Less than or equal

Example -- Checking pairs of numbers

The following are simple examples of inequalities

.gt{123}{321} // Evaluates to false
.ge{123}{321} // Evaluates to false
.lt{123}{321} // Evaluates to true
.le{123}{321} // Evaluates to true
.gt{456}{456} // Evaluates to false
.ge{456}{456} // Evaluates to true
.lt{456}{456} // Evaluates to false
.le{456}{456} // Evaluates to true

Example -- Checking more than two numbers

Sometimes, multiple numbers must be checked, and in this case maths often uses the following shorthand:

\( a \leq b \leq c \Longleftrightarrow a \leq b \mathrel{\&} b \leq c \)

The directives we discuss here also allow the same functionality---if more than two arguments are presented, from left to right, each consecutive pair is checked for inequality and a true value is only returned if all these conditions hold. It should be noted that computation can be halted early, so later arguments will not be evaluated if an earlier pair evaluates to a false value.

Boolean

Sometimes, it is necessary to combine several conditions into one, more complicated one.

It must be noted that each of these directives consider their input values in the same way as the flow-control directives:

  1. If the value is empty, it is false
  2. If the value is ‘0’, it is false
  3. If the value is ‘false’ (case-insensitive), it is false
  4. Any other value is true

In the following section, we describe an adequate set of operators with which any boolean expression may be represented:

  • .all---conjunction, similar to the ‘and’ operator of many programming languages
  • .any---disjunction, similar to the ‘or’ operator of many programming languages
  • .impl---implication
  • .not---negation
  • .xor---exclusive disjunction

.all

The .all directive interprets its inputs as conditions and iff none is false, it returns a true value. It evaluates its arguments from left to right as required to resolve its value---if any are false, the rest of its arguments are not evaluated.

.all{true}{true}{true} // returns true
.all{true}{true}{false} // returns false
.all{false}{false} // returns false
.all // Vacuously returns true
.all{false}{.error{Something went wrong}} // This returns false and never calls .error

.any

The .any directive interprets its inputs as conditions and iff at least one is true, it returns a true value. It evaluates its arguments from left to right as required to resolve its value---if any are true, the rest of its arguments are not evaluated.

.any{true}{true}{true} // returns true
.any{true}{true}{false} // returns true
.any{false}{false} // returns false
.any // Vacuously returns false
.any{true}{.error{Something went wrong}} // This returns true and never calls .error

.impl

This directive computes boolean implication, that is, given two inputs whether one implies the other by the following truth table.

\( a \)\( b \)\( a \Rightarrow b \)
falsefalsetrue
falsetruefalse
truefalsetrue
truetruetrue

.not

This takes a single boolean input and negates it---

\( a \)\( \neg b \)
falsetrue
truefalse

.xor

This directive takes two conditions and outputs their exclusive disjunction, that is, it returns true iff they have different boolean values.

\( a \)\( b \)\( a \oplus b \)
falsefalsefalse
falsetruetrue
truefalsetrue
truetruefalse

Arithmetic

Directives are provided to handle numbers. They do what one might expect, they take numbers, operate upon them and output a number. This section details these directives.

When parsing numbers, it is important to note some things. In particular, numbers:

  • are in base-10
  • cannot contain spaces
  • can be negative
  • can contain fractional parts (after the radical point)
  • can be \( \pm \infty \)
  • can be NaN (not-a-number)

.abs

Computes the absolute value or magnitude of a given number, that is, the unsigned distance between it and zero.

\( \mathtt{.abs}(x) = \vert{x}\vert = \begin{cases} x & \text{if}\ x \geq 0 \\ -x & \text{if}\ x < 0 \end{cases} \)

.add

Takes two numbers, adds them and returns the result.

.add{4}{25} // Returns 29

.div

Takes two numbers, returns the left divided by the right. There are some special cases:

  • When only the right input is zero:
    • Returns \( +\infty \) when the left input is positive
    • Returns \( -\infty \) when the left input is negative
  • When both inputs are zero:
    • Returns ±NaN

The .div, .idiv and .mod functions are related by the following identity---

\[ \frac ab = a \mathbin{//} b + \frac{a \mathbin{\%}b} b \]

.idiv

Takes two numbers, returns the left integer-divided by the right, that is, division is performed and then the result is rounded down to the nearest integer (the quotient).

There are some special cases:

  • When only the right input is zero:
    • Returns \( +\infty \) when the left input is positive
    • Returns \( -\infty \) when the left input is negative
  • When both inputs are zero:
    • Returns ±NaN

The .div, .idiv and .mod functions are related by the following identity---

\[ \frac ab = a \mathbin{//} b + \frac{a \mathbin{\%}b} b \]

.mod

Takes two numbers, and returns the remainder of the left when integer-divided by the right.

There are some special cases:

  • When only the right input is zero:
    • Returns \( +\infty \) when the left input is positive
    • Returns \( -\infty \) when the left input is negative
  • When both inputs are zero:
    • Returns ±NaN

The .div, .idiv and .mod functions are related by the following identity---

\[ \frac ab = a \mathbin{//} b + \frac{a \mathbin{\%}b} b \]

.mul

Takes input of two numbers and returns their product.

.mul{4}{25} // Returns 100

.pow

Takes a base and an exponent and returns the base raised to the power of the exponent.

.pow{2}{3} // Returns 8
.pow{2}{-3} // Returns 0.125
.pow{3}{2} // Returns 9
.pow{-3}{2} // Returns 9

.sign

Computes a given number’s sign. Takes input of a number \(x\) and returns:

  • 1 if \(x > 0\)
  • 0 if \(x = 0\)
  • -1 if \(x < 0\)

.sub

Takes two numbers, subtracts the second from the first and returns the result.

.sub{4}{25} // Returns -21

Miscellaneous Directives

The directives in this section didn’t neatly fit into any of the other sections.

.curr-version

When developing documents and iterating through multiple cycles of drafting and improvements, it is possible that multiple versions of the same document may be in close proximity, thus leading to some confusion. This can be avoided by adding some indication of the document’s version in the output.

The .curr-version directive does this my making use of the between-run store.

Example -- Placing the version in the title

# Research, Re: Search and Re-Search (version .curr-version)

.help

When the user is unsure of how to use a directive, they can get some assistance by calling the .help directive. This takes input of a directive-name, and returns a some associated help-text. It should be noted that the preceding . from the directive name is omitted.

Example -- Getting the help of the help function

Even the .help directive can be input into .help

.help: help // Returns ‘Show documentation for a given directive’ (or there-abouts)

Example -- Getting all help

The following will iterate through all known directives, outputting their help text to the command-line.

.foreach{d}{.known-directives}:
	.echo: .help: !d

.known-directives

This function outputs a list of known directives. Currently, this list contains only directives for which a function has been defined, however in future this will be expanded to cover all directives which have associated styling information. This list is also sorted in alphabetical order for convenience.

Example -- Getting all help

The following will iterate through all known directives, outputting their help text to the command-line.

.foreach{d}{.known-directives}:
	.echo: .help: !d

.vars

Variables in Emblem exist within a given scope. The .vars directive returns a list of these scopes and the variables which they contain at the time of calling. This may be useful for debugging.

.readline

The .readline directive reads a single line from standard input and returns it.

Example -- Interacting with a user

As stdin is read, the .readline directive can be used to interact with a user.

.echo: Ahoy there! What’s yer name?
!resp <- .readline
.echo: Ahoy there, !resp

.$

Emblem allows the user to run arbitrary shell commands with use of the .$ or ‘system’ directive. As the command it takes is run externally, there are two problems:

  1. The command given to the system directive has no guarantee of portability
  2. This directive has all the security risks associated with random code execution so be careful when executing someone else’s source code. This can be alleviated by use of sandboxing.

The system directive is given the .$ name for visual similarity to a terminal when used.

Example -- Listing files in the current directory

Using the standard UNIX ls program, we can see the contents of the current directory:

.$: ls
<!-- Hello, this is some text which may contain repeated words. -->
<!-- We wonder how long it is, but we we’d rather know now many repeated words the text might contain. -->

.env

The .env directive provides a way to read external environment variables. It takes input of an environment variable name and returns its value. If the environment variable does not exist, the empty string is returned.

Example -- Getting the name of the user’s editor

On Linux, it is common to record the name of the user’s text editor in EDITOR environment variable. This can be accessed within an Emblem document as follows.

.env: EDITOR // May or may not return ‘vim’

API

Interactions with Emblem come in three categories, each of which is handled in this section.

Command-line API

Takes input of a markdown-like document, processes it and typesets it before passing the result to a driver for outputting in some format. Extensions can be used to include arbitrary functionality; device drivers are also extensions.

Examples

em -Tutf8 example.em
em hello

Positional arguments

The following arguments are written anywhere in the call to em (after the program name itself).

file

File to typeset or - to read from stdin.

  • type: string
  • default: ‘-’

Optional arguments

The following are used to modify the behaviour of Emblem, to suit a user’s preferences.

-a extension.param=value, --ext-arg extension.param=value

Pass parameter param with value value to extension ext.

  • type: List

-c style, --class style

Set the output class.

  • type: string
  • default: ‘” DATA_DIR “/article’

-C, --colourise-output

Specify output colourisation, -1 for none, 1 for always, 0 for auto-detect (default is 0).

  • type: int
  • default: 0

-E, --fatal-warnings

Treat warnings as errors.

  • type: flag

-F driver, --from driver

Set the input driver, if none is specified, the emblem parser is used.

  • type: string
  • default: ‘’

-f family, --font-family family

Specify a default font family.

  • type: string
  • default: ‘’

-h, --help

Display this help message and exit.

  • type: help

-M, --max-iters

Max number of typesetting iterations allowed.

  • type: int
  • default: 4

-o stem, --output-to stem

Name of the output file without file-extension. If left unspecified the input file (with its extension removed) is used, otherwise emdoc.

  • type: string
  • default: ‘’

-S size, --font-size size

Specify the default font size.

  • type: double
  • default: 0

-s, --sandbox-level

Restrict access to the system, 0 makes no restrictions, 1 restricts creation of new subprocesses, 2 restricts uses all level 1 restrictions and prevents file system access. Default is 1.

  • type: int
  • default: 1

-T driver, --to driver

Set the output driver, default is html.

  • type: string
  • default: ‘html’

-t, --tab-size

The assumed size of tabs when reading input files.

  • type: int
  • default: 4

-v verbosity, --verbose verbosity

Set output verbosity, 3 outputs everything, 0 suppresses all messages including errors. Default is 1.

  • type: int
  • default: 1

-V, --version

Display version and license information and exit.

  • type: version

-x extension, --extension extension

Specify an extension to load. When used multiple times, the specified extensions are loaded in the order given.

  • type: List

Moonscript/Lua Extension API

Emblem is hackable, that is, arbitrary functionality may be added by its users. This is done in one of three ways:

  1. In code executed as the document goes through its typesetting cycle (‘extensions’)
  2. In code executed to convert a given input format to Emblem’s internal structures (‘input drivers’)
  3. In code executed to convert to a given output format (‘output drivers’)

In this section, we will explore the Emblem standard library, std.*:


Typesetting-time extensions

Typesetting-time extensions, hereafter referred to simply as ‘extensions,’ are snippets of Lua code which are imported after the document has been parsed and are executed as it undergoes its typesetting run.

Emblem Public Table

Extensions can define functions to be accessed in the document by editing the Emblem Public Table stored in the em variable. For example, we may wish create a document which includes a note of how long it took to compile. To do this, we must create a function which creates the desired string, and place it into some field in the em table, say cpu_time_used

em.cpu_time_used = function()
	return 'This document was typeset in ' .. os.clock() .. ' seconds of CPU time'
end

If this code is written in a file called cpu-time.lua, it can be imported by adding the flag -fcpu-time when em is run (note the file extension is optional). Now, when the directive .cpu_time_used is seen in the document, the above code will be executed, it will be replaced with the message.

Evaluation Order

Emblem is lazy, that is, it tries to do no more work than is necessary to typeset a document. So for example, if a directive takes three inputs and just outputs the first one, emblem will not bother to evaluate the others. This is because by default, Emblem will only evaluate a node if it can guarantee that it will appear in the output.

Sometimes, however, it can be useful to force Emblem to use a different evaluation order, such as to inspect the results which would not otherwise appear directly in the output. This can be done using the eval function, which takes a node and evaluates it, or the eval_string function which Evaluation order is manipulated in the definition of the .if directive, which looks something like the following:

local base = require('std.base')
base.em['if'] = function(c, b)
	cs = base.eval_string(c)
	if cs == '' or cs == '0' or string.lower(cs) == 'false' then
		return nil
	else
		return b
	end
end

Here, although input c is never present in what is returned, by calling eval_string upon it we can reason about it.

Events

To help extensions react to how the document is being processed, there are several events which are triggered. These are triggered on objects which extend the Component class defined in the std.base module and are as follows.

  1. on_start, executed once after all extensions are loaded
  2. on_iter_start, executed at the start of each iteration
  3. on_iter_end, executed at the end of each iteration
  4. on_end, executed once, after the final iteration but before output

There are a number of classes which may be imported from the std.std module which provide frameworks for storing data whilst reacting to these events. For example, the table of contents is a subclass of Component which stores the names and numbers of headings as the document is processed, requesting another run if the table of contents at the end of the previous run is different to that at the end of the current (e.g. a page-number has been updated by some other change).

A re-iteration can be requested by calling the requires_reiter function in Lua. This will cause the typesetting loop to be run again, unless the (user-configurable) number of maximum iterations has been reached. The number of the current iteration (starting from 1) is accessible through the em_iter variable.

Input Drivers

Emblem can take input of any format for which it has an input driver. When Emblem inputs a file through the .include directive, a language can optionally be specified in the second parameter to determine the parser to use. This language is used to look up the parser to use in the std.in.drivers.known_languages table. An input driver is simply a module which adds at least one parser function into this table.

Output Drivers

Emblem is capable of outputting to any format for which it has an output driver. The binary itself contains some output drivers, but it is also possible to import ones from other sources as desired. In analogy with input drivers, there exists a table, std.out.drivers.output_drivers, which is used when looking up the language into which the document will be output. An output driver is simply module which adds at least one outputting function into this table.

std.ast

Provides an interface for constructing Emblem document nodes.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

mkcall

Make a function which constructs a call to a given directive.

  • Param Name: of the directive to call

Returns: A function which takes arguments and returns a call upon those arguments

mkcall = (name) -> (args) -> ...

std.base

Provides the base library for use with extensions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

close_var_scope

Closes the most recently-opened variable scope.

close_var_scope = -> ...

copy_loc

Copy a source-code location.

Returns: A copy of the current source code location

copy_loc = -> ...

em_loc

Get the current location in the source code.

Returns: A pointer to the current source location

em_loc = -> ...

eval_string

Evaluates a node pointer and extracts the text contained in and below it.

  • Param d: The userdata pointer to evaluate and extract from

Returns: A string which represents all text at and beneath d

eval_string = (d) -> ...

get_var

Gets the value of a given variable, if the variable name starts with n > 0 exclamation marks, then that many possible matches are skipped while searching from the innermost scope.

  • Param rn: The raw variable name as a string or core pointer
  • Param d: An optional default value to return if rn does not exist

Returns: The value of variable rn in the current scope otherwise d

get_var = (rn, d) -> ...

is_instance

Tests whether an object is an instance of a given class.

  • Param cls: The class to test, may be a class name or a class itself
  • Param obj: The object to test

Returns: true if obj is an instance of a sub-class of cls, otherwise false

is_instance = (cls, obj) -> ...

iter_num

Returns the number of the current iteration of the typesetting loop (starts at 1).

Returns: The number of times the typesetting loop has been started this run

iter_num = -> ...

node_string

Extracts the text beneath a given node.

  • Param n: The node to convert into a string, must be a table

Returns: The text stored at and under the given node

node_string = (n) -> ...

open_var_scope

Opens a new variable scope.

open_var_scope = -> ...

set_var

Set a variable to a given value, if the variable name starts with n > 0 exclamation marks, then a search is performed to set the n-th variable with the same name in found whilst searching parent scopes.

  • Param n: The name of the variable (string or code pointer)
  • Param v: The value to set (not changed by this operation)
  • Param surrounding_scope: If set to true, search is bumped up one scope (useful for the .set-var directive which would otherwise have the set value swallowed in its own scope)
set_var = (n, v, surrounding_scope=false, search=false) -> ...

set_var_string

Set a given variable to a given value as a string.

  • Param n: Variable name as for set_var
  • Param v: Value to evaluate then set to n
  • Param w: Scope widening paramerer as for set_var
set_var_string = (n, v, ...) -> ...

wrap_indices

Wrap the __get and __set methods into the __index and __newindex methods if available.

  • Param object: (table) to wrap

Returns: nil

wrap_indices = => ...

std.bib

Provides bibliographies and citations.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

get_cite_style

Get the current citation style.

Returns: The current citation style

get_cite_style = -> ...

set_cite_style

Set the current citation style to a given style.

  • Param style: The new current citation style
set_cite_style = (style) -> ...

std.edit

Provides functions to compute and interpret edit distance.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

closest

Find the closest string to a given one from a list of strings.

  • Param s: A source string
  • Param ts: A list of strings

Returns: The t in ts which is closest to s

closest = (s, ts) -> ...

edit_distance

Compute the edit distance between two strings.

  • Param u: A string
  • Param v: Another string

Returns: The edit distance between u and v

edit_distance = (u, v) -> ...

unknown_x_msg

Create a suggestion message when an incorrect value was supplied which should have been in a list of options.

  • Param x: The name of the type of v
  • Param v: The incorrect value given
  • Param vs: The list of valid values of which v should have been a member

Returns: A user-friendly message which suggests the u in vs which is closest to v if it is not too distant

unknown_x_msg = (x, v, vs) -> ...

std.events

Prpvides functionality for responding to typesetting events.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.expr

Provides a framework for evaluating expressions.

  • Author: Edward Jones
  • Date: 2021-09-25

Source file

expr

Takes a string (or document pointer), parses it and evaluates it as an expression.

  • Param str: The text to parse and evaluate

Returns: An integer which was evaluated from the expression represented by str or nil on failure

expr = (s) -> ...

std.func

Provides functional abstractions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

co_to_list

Creates a list from the values yielded from a coroutine.

  • Param c: Coroutine from which to extract values

Returns: A list of values returned from c

co_to_list = (c) -> ...

co_to_table

Constructs a table from a coroutine which yields {k,v} pairs.

  • Param c: Coroutine from which to extract kv-pairs

Returns: A table t such that for each {k,v} yielded from c, t\[k] = v

co_to_table = (c) -> ...

do_nothing

A function which does nothing.

do_nothing = -> ...

filter

Creates a coroutine whihc filters the values of a coroutine by a predicate.

  • Param p: A predicate
  • Param es: A coroutine which yields values to be filtered

Returns: A coroutine which yields the values of e of es which satisfy p(e) in the order they are yielded from es

filter = (p, es) -> ...

filter_list

Returns a list of values of a given list which satisfy a predicate.

  • Param p: A predicate
  • Param es: A list of values

Returns: A list of elements e of es which satisfy p(e)

filter_list = (p, es) -> ...

id

Identity function, takes a value and returns it.

  • Param x: Value to return

Returns: x

id = (x) -> ...

int

Creates a coroutine which yields the integers.

Returns: a coroutine which yields the integers

int = -> ...

key_list

Construct a list of keys from a table.

  • Param t: A table from which to extract keys

Returns: A list of keys in t

key_list = (t) -> ...

keys

Creates a coroutine which yields the keys of a table.

  • Param t: A table from which to extract keys

Returns: A coroutine which yields the keys of t

keys = (t) -> ...

kv_pairs

Creates a coroutine which yields {k,v} pairs of a table.

  • Param t: A table from which to extract key-value pairs

Returns: A coroutine which yields the kv-pairs of t

kv_pairs = (t) -> ...

map

Maps the values yielded by a coroutine with a given function.

  • Param f: The mapping function
  • Param es: The values to map

Returns: a coroutine which yields values f(e) for each e yielded from es

map = (f, es) -> ...

nat

Creates a coroutine which yields the natural numbers.

Returns: A coroutine which yields the natural numbers

nat = -> ...

seq

Creates a coroutine which yields the values of a sequence.

  • Param first: The first value of the sequence
  • Param last: The last value of the sequence
  • Param step: The difference between consecutive yielded values

Returns: A coroutine which yields values starting from first, in increments of step until last is reached

seq = (first, last, step) -> ...

take

Takes values from a coroutine whilst a predicate holds.

  • Param p: Predicate to check
  • Param es: From which to take values

Returns: A coroutine which yields values e of es for which p(e) holds, until the first which does not (at which point the coroutine finishes

take = (p, es) -> ...

value_list

Construct a list of values in a table.

  • Param t: A table from which to extract values

Returns: A list of the values in v

value_list = (t) -> ...

values

Creates a coroutine which yields the values of a table.

  • Param t: A table from which to extract values

Returns: A coroutine which yields the values of t

values = (t) -> ...

whole

Creates a coroutine which yields whole numbers.

Returns: A coroutine which yields the whole numbers

whole = -> ...

std.hdr

Provides headings and tables of contents.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.in/

This module collection provides the machinery for defining and implementing the core set of input drivers.

Its most important file is std.in.drivers, which contains the code to handle parsing inputs and which defines some useful classes for input drivers. All other modules in this module collection are implementations of input drivers which are always available when running Emblem.

std.in.drivers

Manages input drivers, heeps associations for mapping input languages to parsers, and file extensions to input languages.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.lingo

Provides a rudamentary scripting language for use in documents.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

cond

Takes input of value and evaluates it as a condition.

  • Param c: Lua value or core pointer to evaluate as a condition

Returns: false if c is false or is the empty string, ‘0’ or ‘false’ (case-insensitive), otherwise true

cond = (c) -> ...

toint

Converts a value to a condition integer (for a more compact representation.

  • Param b: A value to check

Returns: 0 if b is 0, the empty string, false or nil, otherwise 1

toint = (b) -> ...

std.log

Provides logging functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.out/

This module collection provides the machinery for defining and implementing the core set of output drivers.

Its most important file is std.out.drivers, which contains the code to translation to output formats and writing to files, and defines some useful classes for output drivers. All other modules in this module collection are implementations of input drivers which are always available when running Emblem.

std.out.bb

Provides an output driver for BBCode.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

This module does not contain any documented interface items.

std.out.drivers

Provides a framework for handling and creating output drivers.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

get_output_driver

Gets the current output driver.

Returns: The current output driver

get_output_driver = -> ...

set_output_driver

Sets the current output driver.

  • Param dname: The name of the new output driver
set_output_driver = (dname) -> ...

std.out.html

Provides an output driver for HTML.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

This module does not contain any documented interface items.

std.out.latex

Provides an output driver for LaTeX.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

This module does not contain any documented interface items.

std.out.md

Provides an output driver for markdown.

  • Author: Edward Jones
  • Date: 2021-09-24

Source file

This module does not contain any documented interface items.

std.ref

Implements the label-anchor-reference system for cross-referencing within documents.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

get_label

Get the label in the current context.

Returns: The value of the label in the current context

get_label = -> ...

set_label

Set the current label.

  • Param c: The new label
set_label = (c) -> ...

std.show

Provides functions to show the values of lua-tables in more human-readible formats.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

show

Construct a string-representation of an object.

  • Param v: Value for which to construct a string-representation

Returns: A string representation of v

show = (v) -> ...

showp

Construct a prettier string-representation of an object.

  • Param v: Value for which to construct a string-representation

Returns: A string representation of v which is slightly prettier than that of show.

showp = (v) -> ...

std.store

Allows values to be stored between executions of Emblem.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.style

Provides wrappers for basic styling directives.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

std.util

Provides miscellaneous utility functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

argmax

Computes the argmax of a function over a set of values.

  • Param f: The function to compute
  • Param vs: a list of values to test

Returns: The argmax of f over vs, that is the v in vs which maximises f(v), also returns the value of f(v)

argmax = (f, vs) -> ...

argmin

Computes the argmin of a function over a set of values.

  • Param f: The function to compute
  • Param vs: a list of values to test

Returns: The argmin of f over vs, that is the v in vs which minimises f(v), also returns the value of f(v)

argmin = (f, vs) -> ...

bool_to_int

Converts a boolean value to an integer.

  • Param b: The value to check

Returns: true if b is considered true otherwise 0

bool_to_int = (b) -> ...

char_at

Returns a string representing the character at a given index.

  • Param i: The index to obtain
  • Param s: The string from which to extract

Returns: A string which contains just the i-th character of s

char_at = (i, s) -> ...

chars

Creates a coroutine which yields the characters of a string.

  • Param s: The string from which to yield

Returns: A coroutine which yields strings of length 1 which represent the individual characters of s

chars = (s) -> ...

elem

Returns whether a value is an element of a list.

  • Param v: A value to check membership
  • Param vs: A list of values to search

Returns: true if v is a value if vs, otherwise false

elem = (v, vs) -> ...

eq

Recursively computes the equality of two values.

  • Param a: A value to check
  • Param b: A value to check

Returns: true if a and b are equal, otherwise false

eq = (a,b) -> ...

extend

Computes the result of extending a given list by other lists (pure).

  • Param xs: A list to extend
  • Param ...: Further lists

Returns: A list which is the concatenation of the lists passed, in the order passed.

extend = (xs, ...) -> ...

is_list

Returns whether a given value represents a list.

  • Param l: The value to check

Returns: true if l is a list, otherwise false

is_list = (l) -> ...

non_nil

Returns whether a value is not nil.

  • Param v: Value to check

Returns: true if v is not nil otherwise false

non_nil = (v) -> ...

on_iter_wrap

Wrap a given function so that it is only run on a particular typesetting iteration.

  • Param f: The function to wrap

Returns: A function which takes a number n and the parameters to f which when called will only execute f if the current typesetting loop iteration is equal to n

on_iter_wrap = (f) -> (n, ...) -> ...

sorted

Sort a list and then return it (impure).

  • Param t: A list to sort
  • Param ...: Further parameters to table.sort

Returns: t, having been sorted in place

sorted = (t, ...) -> ...

C API

Following the C-style of headers and body files, this section of the docs follows the same partition between module interfaces, which correspond to files *.h in the source repo, and module bodies, which correspond to files *.c. It must be noted that some of the files in this section of the docs do not directly exist in the source as they are auto-generated. Some examples of this are the lexer body and parser body, which is are generated from Flex and Bison sources respectively.

Module interfaces

This section details the interfaces exposed from each core module, that is, documentation present in files *.h in the repository.

data/

Defines the generic data structures used to represent internal data.

array.h

Exposes functions for handling arrays, fixed-length composite data-structures, with elements accessible by index.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

dest_arr

Destroy an array object.

  • Param arr: Pointer to the array to destroy
  • Param ed: Element destructor function or NULL
void dest_arr(Array* arr, func_sig(void, ed, (void*)));

dest_arr_iter

Destror an array iterator.

  • Param iter: Pointer to the iterator to destroy
void dest_arr_iter(ArrayIter* iter);

get_arrv

Get array value at a given index.

  • Param ret: Pointer to a Maybe type to populate with the result
  • Param arr: Pointer to the array containing the required value
  • Param idx: Index of the array element to find
void get_arrv(Maybe* ret, Array* arr, size_t idx);

iter_arr

Iterate once over an array.

  • Param v: Pointer to the return value
  • Param iter: Pointer to the array iterator to use

Returns: True iff a value was successfully written to v, false iff there were no elements left

bool iter_arr(void** v, ArrayIter* iter);

make_arr

Make an array object, a block of memory of finite length.

  • Param arr: Pointer to the array to initialise.
  • Param cnt: Length of the array

Returns: True iff memory allocation was successful

bool make_arr(Array* arr, size_t cnt);

make_arr_iter

Make an array iterator.

  • Param iter: Pointer to the iterator to make
  • Param arr: Pointer to the array to iterate over
void make_arr_iter(ArrayIter* iter, Array* arr);

set_arrv

Set the value of an array at a particular index.

  • Param arr: Pointer to the array to modify
  • Param idx: Index of the value to change
  • Param val: Value to assign to arr[idx]

Returns: Returns true iff idx is a valid index of arr

bool set_arrv(Array* arr, size_t idx, void* val);

cmp.h

Exposes comparator functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

CMP_SIG

Compare float.

  • Param v1: A float to compare
  • Param v2: Another float to compare
CMP_SIG(float);

CMP_SIG

Compare strings.

  • Param v1: A string to compare
  • Param v2: Another string to compare
CMP_SIG(str);

CMP_SIG

Compare ints.

  • Param v1: An int to compare
  • Param v2: Another int to compare
CMP_SIG(int);

CMP_SIG

Compare size_ts.

  • Param v1: A size_t to compare
  • Param v2: Another size_t to compare
CMP_SIG(size_t);

CMP_SIG

Compare doubles.

  • Param v1: A double to compare
  • Param v2: Another double to compare
CMP_SIG(double);

CMP_SIG

The signature of a comparator.

  • Param name: The name of the comparison functino

Returns: The signature of the comparison function for names

#	define CMP_SIG(name) Cmp cmp_##name##s(void* v1, void* v2)

CMP_SIG

Compare characters.

  • Param v1: A character to compare
  • Param v2: Another character to compare
CMP_SIG(char);

CMP_SIG

Compare void pointer. This compares the numerical value of the pointers, not their content!

  • Param v1: A void pointer to compare
  • Param v2: Another void pointer to compare
CMP_SIG(ptr);

Cmp

Type of a function which compares two values.

  • Param v1: A value to compare
  • Param v2: Another value to compare

Returns: The comparison result of v1 against v2

typedef Cmp(fun Comparator)(void* v1, void* v2);

streq

Check if two C-strings are equal (to improve readability with strcmp).

  • Param s: Pointer to a string to check
  • Param t: Pointer to a string to check

Returns: true if the strings are equal, false otherwise

bool streq(char const* s, char const* t);

dest-free.h

Defines preprocessor rules for the creation of functions which destroy and then free memory of a given type.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

destructor.h

Provides type definition for destructors, functions responsible for finalising and freeing the memory of a given structure.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

void

Type of an object destructor.

  • Param o: Pointer to an object to destroy
typedef void(fun Destructor)(void* o);

either.h

Exposes functions for processing Either objects, which can represent values of two types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

dest_either

Destroy an either-type object.

  • Param e: Pointer to the either object to destroy
  • Param led: Element destructor for the left
  • Param red: Element destructor for the right
void dest_either(Either* e, Destructor led, Destructor red);

fmap_either

Fmap over either-type object.

  • Param eo: Output either type
  • Param ei: Input Either type
  • Param f: Function to apply to the contents of ei to produce eo
void fmap_either(Either* eo, Either* ei, Fmap f);

make_either_left

Construct an either-type object with the left constructor.

  • Param e: Pointer to the either object to initialise
  • Param left_val: Value to place into the left constructor
void make_either_left(Either* e, void* left_val);

make_either_right

Construct an either-type object with the right constructor.

  • Param e: Pointer to the either object to initialise
  • Param right_val: Value to place into the right constructor
void make_either_right(Either* e, void* right_val);

succ_either

Return whether a given either-type object represents a successful result.

  • Param e: Pointer to the either object to check

Returns: true if e uses the right constructor otherwise false

bool succ_either(Either* e);

fmap.h

Provides type definition for fmap functions, which allow computations on data within structures.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

Fmap

Type of a function which can be used in an fmap operation.

  • Param o: The value outputted by the fmap
  • Param i: The unput value
typedef void (*Fmap)(void** o, void* i);

hash.h

Exposes hash functions for standard data types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

HASH_SIG

Hash a string.

  • Param v: A value to hash

Returns: The hash of v

HASH_SIG(str);

HASH_SIG

Hash a size_t.

  • Param v: A value to hash

Returns: The hash of v

HASH_SIG(size_t);

HASH_SIG

Hash a void pointer. This operates on the numerical value of the pointer, and not its content!

  • Param v: A value to hash

Returns: The hash of v

HASH_SIG(ptr);

HASH_SIG

Hash an int.

  • Param v: A value to hash

Returns: The hash of v

HASH_SIG(int);

HASH_SIG

Signature of a hashing function.

  • Param name: The name of the type to hash

Returns: A signature for a function which hashes names

#define HASH_SIG(name) Hash hash_##name(void* v)

HASH_SIG

Hash a character.

  • Param v: A value to hash

Returns: The hash of v

HASH_SIG(char);

Hasher

Type of a function which takes an object and returns its hash.

  • Param v: A value to hash

Returns: The hash of v

typedef Hash (*Hasher)(void* v);

list-array-conversions.h

Exposes conversion functiosn between arrays and lists.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

make_arr_from_list

Create an array from a list.

  • Param arr: Array to write to
  • Param l: List ot read
void make_arr_from_list(Array* arr, List* l);

make_list_from_arr

Create a list from an array. List myst be freed.

  • Param l: Pointer to the list to create
  • Param arr: Pointer to the array to copy
void make_list_from_arr(List* l, Array* arr);

list.h

Exposes functions to handle the list data structure.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

all_list

Return whether all elements of a list of booleans are true.

  • Param l: List to check

Returns: true iff all elements of the list are true

bool all_list(List* l);

any_list

Return whether there is some element in a list of booleans which is true.

  • Param l: List to check

Returns: true iff at at least one element of a list is true.

bool any_list(List* l);

append_list

Append a value to a list.

  • Param l: Pointer to the list to affect
  • Param v: Pointer to the node to add

Returns: true iff successful

bool append_list(List* l, void* v);

append_list_node

Append a list node to a list.

  • Param l: Pointer to the list to affect
  • Param ln: Pointer to the node to add

Returns: true iff successful

bool append_list_node(List* l, ListNode* ln);

cconcat_list

Concatenate a list in place, affecting exactly one list (takes time linear in the length of the second list).

  • Param r: List to output
  • Param l: List to concatenate to r
void cconcat_list(List* r, List* l);

concat_list

Concatenate a pair of lists into another.

  • Param r: The list outputted
  • Param l1: The first list to concatenate.
  • Param l2: The second list to concatenate.
void concat_list(List* r, List* l1, List* l2);

dest_list

Destroy a list. Does not affect list elements.

  • Param l: Pointer to the list to destroy.
  • Param freeNodes: Iff not false, frees the memory used by the contained ListNodes
  • Param ed: Element destructor called on the data field of each ListNode or NULL
void dest_list(List* l, Destructor ed);

dest_list_iter

Destroy an iterator.

  • Param i: Pointer to the iterator to destroy
void dest_list_iter(ListIter* i);

dest_list_node

Destroy a list node.

  • Param ln: Pointer to the list node to destroy
  • Param ed: Element destructor to be called on the data field of the list node or NULL
void dest_list_node(ListNode* ln, Destructor ed);

dest_reversed_list_iter

Destroy a reversed iterator.

  • Param i: Pointer to the iterator to destroy
void dest_reversed_list_iter(ReversedListIter* i);

iconcat_list

Concatenate a pair of lists in place. Takes constant time and the second list is no longer valid and should be.

  • Param l1: List to concatenate (left)
  • Param l2: List to concatenate (right)
void iconcat_list(List* r, List* l);

in_list

Checks whether a given element is in a list (by reference-equality).

  • Param l: Pointer to the list to check
  • Param val: Pointer to the value to test

Returns: true iff the value is in the list

bool in_list(List* l, void* val);

in_list_eq

Tests whether there exists an element in a given list which is equal under some function.

  • Param m: Maybe container for the value found to be equal to val under cmp
  • Param l: Pointer to the list to check
  • Param cmp: Comparator function to check, val is placed into the first argument.
  • Param val: The value to test against
void in_list_eq(Maybe* m, List* l, Comparator cmp, void* val);

is_empty_list

Return whether a list is empty.

  • Param l: List to check

Returns: false iff the list is not empty

bool is_empty_list(List* l);

iter_list

Move the iterator to the next element in the list.

  • Param v: A location where the value at the current point in the list will be written
  • Param i: Pointer to the iterator to use

Returns: false if there are no more elements to iterate, true otherwise

bool iter_list(void** v, ListIter* i);

iter_list_nodes

Move the iterator to the next node in the list.

  • Param n: A location where a pointer to the current node will be written
  • Param i: Pointer to the iterator to use

Returns: false if there are no more elements to iterate, true otherwise

bool iter_list_nodes(ListNode** n, ListIter* i);

iter_list_reversed

Move the iterator to the next element in the list (when iterated backwards).

  • Param val: A location where the value at the current point in the list will be written
  • Param i: Pointer to the iterator to use

Returns: false if there are no more elements to iterate, true otherwise

bool iter_list_reversed(void** val, ReversedListIter* i);

make_list

Initialise a list.

  • Param l: Pointer to the area of memory to initialise
void make_list(List* l);

make_list_iter

Initialise an iterator for a list.

  • Param i: Pointer to the iterator to initialise
  • Param l: Pointer to the list which the iterator will run over
void make_list_iter(ListIter* i, List* l);

make_list_node

Initialise a list node.

  • Param ln: Pointer to the memory to initialise
  • Param data: The data to store in the node
void make_list_node(ListNode* ln, void* data);

make_reversed_list_iter

Initialise a reverse-iterator for a list.

  • Param i: Pointer to the iterator to initialise
  • Param l: Pointer to the list which the iterator will run over
void make_reversed_list_iter(ReversedListIter* i, List* l);

prepend_list

Add a value to the head of a list.

  • Param l: pointer to the list to change
  • Param v: Pointer to the value to prepend

Returns: true iff successful

bool prepend_list(List* l, void* v);

prepend_list_node

Add a node to the front of a list.

  • Param l: Pointer to the list to change
  • Param ln: Pointer to the node to add

Returns: true iff successfil

bool prepend_list_node(List* l, ListNode* ln);

remove_list_node

Remove a node from a list.

  • Param l: Pointer to the list which contains ln
  • Param ln: Pointer to the node to remove

Returns: Returns true iff successful

bool remove_list_node(List* l, ListNode* ln);

set_sublist

Declare whether all nodes of a list are now entirely contained within another, preventing double-frees.

  • Param l: List to modify
  • Param is_sublist: Whether l is a sublist of another list
void set_sublist(List* l, bool is_sublist);

locked.h

Exposes functions for data-structure locking, designed to reduce the possibility of race conditions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

map.h

Exposes functions to handle the Map data structure.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

dest_map

Destroy a map.

  • Param map: Pointer to the map to destroy
  • Param ved: Value destructor
void dest_map(Map* map, Destructor ved);

dest_map_iter

Destroy a map iterator.

  • Param iter: Pointer to the iterator to destroy
void dest_map_iter(MapIter* iter);

get_map

Get a value from a map.

  • Param mo: Return value populated with the value if present
  • Param map: Pointer to the map to retrieve the value from
  • Param key: Key to use
void get_map(Maybe* mo, Map* map, void* key);

iter_map

Iterate once over key-value pairs using a specified iterator.

  • Param p: Pointer to the return pair
  • Param iter: Pointer to the iterator to use

Returns: true if iteration was successful, otherwise false as iteration has finished

bool iter_map(Pair** p, MapIter* iter);

iter_map_keys

Iterate once over the keys in a map using a given iterator.

  • Param k: Pointer to the key to return
  • Param iter: Pointer to the iterator to use

Returns: true iff iteration was successful, otherwise false as iteration has finished

bool iter_map_keys(void** k, MapIter* iter);

iter_map_values

Iterate over the values in a map using a given iterator.

  • Param v: Pointer to the value to return
  • Param iter: Pointer to the iterator to use

Returns: true iff iteration was successful, otherwise false as iteration has finished

bool iter_map_values(void** v, MapIter* iter);

make_map

Make a map.

  • Param map: Pointer to the map to create
  • Param hash: Hash function to use on keys
  • Param kcmp: Comparator to use on keys
  • Param ked: Destructor to use on keys

Returns: true iff sufficient memory could be allocated to the map, false otherwise

bool make_map(Map* map, Hasher hash, Comparator kcmp, Destructor ked);

make_map_from_list

Make a map from a list of key-value Pairs.

  • Param map: Pointer to the map to create
  • Param list: Pointer to the list of key-value Pairs
  • Param hash: Hash function to use on keys
  • Param kcmp: Comparison function to use on keys
  • Param ked: Destructor for the keys

Returns: true iff enough memory could be allocated to create the map, false otherwise

bool make_map_from_list(Map* map, List* list, Hasher hash, Comparator kcmp, Destructor ked);

make_map_iter

Make an iterator over the map.

  • Param iter: Pointer to the iterator to make
  • Param map: Pointer to the map to iterate over
void make_map_iter(MapIter* iter, Map* map);

push_map

Push a value into a map.

  • Param oldval: Pointer to a maybe type to be populated with the old value at a given key, if present
  • Param m: Pointer to the map to populate
  • Param k: Key to push
  • Param v: Value to push

Returns: true iff sufficient memory was available during pushing and (if necessary) resizing, otherwise false

bool push_map(Maybe* oldval, Map* m, void* k, void* v);

maybe.h

Exposes functions to handle the maybe data-type, which can represent either a value or nothing.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

dest_maybe

Destroy a maybe-type object. Any stored data must be destroyed separately.

  • Param m: Pointer to a meybe object to destroy
  • Param ed: Element destructor to be called on the just field if the constructor permits
void dest_maybe(Maybe* m, Destructor ed);

fmap_maybe

Apply a function to the stored data in the maybe and output a new maybe object with the new value.

  • Param mo: Ouptut maybe object. Should be an uninitialised maybe-type pointer.
  • Param mi: Input maybe object which will have f applied to it
  • Param f: Function to apply to any data inside mi
void fmap_maybe(Maybe* restrict mo, Maybe* restrict mi, Fmap f);

make_maybe_just

Construct a maybe-type object with the just constructor.

  • Param m: Pointer to a location to initialise
  • Param data: Data to store in the just
void make_maybe_just(Maybe* m, void* data);

make_maybe_nothing

Construct a maybe-type object with the nothing constructor.

  • Param m: Pointer to a location to initialise
void make_maybe_nothing(Maybe* m);

succ_maybe

Check whether a maybe-type object represents a success.

  • Param m: Pointer to a maybe object

Returns: Returns true if the constructor of m is Just, otherwise false

bool succ_maybe(Maybe* m) __attribute__((pure));

str.h

Exposes functions to hendle the string data-type.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

arr_to_str

Create a string from an array of characters.

  • Param str: Pointer to the string to create
  • Param arr: Pointer to the array to read
void arr_to_str(Str* str, Array* arr);

copy_into_str

Copy the value of a string into another string starting at a given index. Only mutates if the entire string.

  • Param cont: The container string to write into
  • Param ins: The insertion string to read from
  • Param startIdx: The index to start writing from

Returns: true iff startIdx is low enough to allow all of ins to fit in cont otherwise false

bool copy_into_str(Str* cont, Str* ins, size_t startIdx);

dest_free_sig

Destroy and free a string.

  • Param str: String to destroy
dest_free_sig(str, Str);

dest_str

Destroy a string and free its memory if required.

  • Param str: Pointer to the string to destroy
void dest_str(Str* str);

get_strc

Get the character at a specified index.

  • Param ret: Pointer to the return value, creates a Maybe object of constructor JUST iff the index was valid. In this
  • Param str: Pointer to the string to search
  • Param idx: Index to get if valid
void get_strc(Maybe* ret, Str* str, size_t idx);

make_str

Make an empty string.

  • Param str: Pointer to the String object to initialise
void make_str(Str* str);

make_strc

Make a string by copying another.

  • Param str: Pointer to the string to make
  • Param raw: Pointer to the raw characters to copy
void make_strc(Str* str, char* raw);

make_strl

Make a string of specified length.

  • Param str: Pointer to the string to initialise
  • Param len: Length of the string to create

Returns: True iff memory was successfully allocated

bool make_strl(Str* str, size_t len);

make_strr

Make a string by reference to a raw value, freeing the raw value when destroyed.

  • Param str: Pointer to the string to make
  • Param raw: Pointer to the raw characters
void make_strr(Str* str, char* raw);

make_strv

Make a string by reference to a raw value.

  • Param str: Pointer to the string to make
  • Param raw: Pointer to the raw characters
void make_strv(Str* str, char* raw);

set_strc

Set the value of a character in a string at a specified index.

  • Param str: Pointer to the string to mutate
  • Param idx: Index of the mutation
  • Param val: Value to write

Returns: true if idx was valid else false

bool set_strc(Str* str, size_t idx, char val);

str_to_arr

Create an array (of character values) from a string.

  • Param arr: Pointer to the array to make
  • Param str: Pointer to the string whose data will be copied
void str_to_arr(Array* arr, Str* str);

tuple.h

Provides definitions for tuples, fixed-length heterogeneous data-types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

unit.h

Exposes functions to handle the Unit data type, which cannot represent any information.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

dest_unit

Destroy a unit.

  • Param unitp: Pointer to a unit to destroy
void dest_unit(Unit* unitp);

make_unit

Make a unit.

  • Param unitp: Pointer to the unit to make
void make_unit(Unit* unitp);

doc-struct/

This directory contains modules used to define and handle document structure.

ast.h

Exposes functions to handle Emblem document structures.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

discern-pars.h

Exposes functionality for automatically placing paragraph nodes in a document.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

location.h

Exposes functions to handle the Location structure for keeping track of places in the document source.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

drivers/

This directory contains files used for interacting with output drivers. It is responsibly for both defining a set of core output drivers, and also interfacing with those defined in extension-space.

driver-params.h

Exposes functionality to handle output drivers parameters.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

drivers.h

Exposes functions for handling output drivers.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

driver-util.h

This module lacks a documentation header.

Source file

This module does not contain any documented interface items.

write-out.h

This module lacks a documentation header.

Source file

This module does not contain any documented interface items.

ext/

This directory contains the code which manages and interacts with extension space. It allows the execution of arbitrary Lua code as the program executes and is the module primarily responsible for Emblem’s extensibility.

In the source code, the standard extension library is defined in the lib/ directory beneath this one.

debug.h

Exposes functions for debugging the Lua API stack.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-env.h

Exposes functions for handling the Lua extension environment.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-loader.h

Exposes the extension loader.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-params.h

Exposes functions to handle extension-environment parameters.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-ast-io.h

Exposes functions for translating between Lua tables and document trees.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-constants.h

Exposes function for setting-up interface constants in the extension environment.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-em-parser.h

Exposes interface between core Emblem parser and extension space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-events.h

Exposes functions for issuing typesetting events to extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua.c

Provides functions for executing evaluation-passes on document trees.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-lib-load.h

Exposes function to load standard Lua libraries into extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-pointers.h

This module lacks a documentation header.

Source file

This module does not contain any documented interface items.

style.h

Exposes function for importing stylesheets from extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

logs/

This directory holds code which is responsible for logging-output. It also provides an interface between its logging functions and extension-space.

ext-log.h

Exposes functions to make core logging functions available to extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

logs.h

Exposes logging functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

fini_logs

Finalise logging.

void fini_logs(void);

init_logs

Initialise logging.

  • Param args: Parsed command-line arguments
void init_logs(Args* args);

log_debug

Write a debug message to stderr.

  • Param format: debug message format (printf)
  • Param ...: Possible printf arguments
void log_debug(const char* restrict format, ...) __attribute__((format(printf, 1, 2)));

log_err

Write an error stderr.

  • Param format: Error format (printf)
  • Param ...: Possible printf arguments
void log_err(const char* restrict format, ...) __attribute__((cold)) __attribute__((format(printf, 1, 2)));

log_err_at

Write an error stderr referencing a source location.

  • Param loc: The source location to reference
  • Param format: Error format (printf)
  • Param ...: Possible printf arguments
void log_err_at(Location* loc, const char* restrict format, ...) __attribute__((cold))

log_info

Write information to stderr.

  • Param format: Information format (printf)
  • Param ...: Possible printf arguments
void log_info(const char* restrict format, ...) __attribute__((format(printf, 1, 2)));

log_warn

Write a warning to stderr.

  • Param format: Warning format (printf)
  • Param ...: Possible printf arguments
int log_warn(const char* restrict format, ...) __attribute__((format(printf, 1, 2)));

log_warn_at

Write a warning to stderr referencing a source location.

  • Param loc: The source location to reference
  • Param format: Warning format (printf)
  • Param ...: Possible printf arguments
int log_warn_at(Location* loc, const char* restrict format, ...);

vlog_debug

Write a debug message to stderr, using a va_list of format-arguments.

  • Param format: debug message format (printf)
  • Param ...: Possible printf arguments
void vlog_debug(const char* restrict format, va_list va);

vlog_err

Write an error stderr, using a va_list of format-arguments.

  • Param format: Error format (printf)
  • Param ...: Possible printf arguments
void vlog_err(const char* restrict format, va_list va);

vlog_err_at

Write an error stderr referencing a source location, using a va_list of format-arguments.

  • Param loc: The source location to reference
  • Param format: Error format (printf)
  • Param ...: Possible printf arguments
void vlog_err_at(Location* loc, const char* restrict format, va_list va);

vlog_info

Write information to stderr, using a va_list of format-arguments.

  • Param format: Information format (printf)
  • Param ...: Possible printf arguments
void vlog_info(const char* restrict format, va_list va);

vlog_warn

Write a warning to stderr, using a va_list of format-arguments.

  • Param format: Warning format (printf)
  • Param ...: Possible printf arguments
int vlog_warn(const char* restrict format, va_list va);

vlog_warn_at

Write a warning to stderr referencing a source location, using a va_list of format-arguments.

  • Param loc: The source location to reference
  • Param format: Warning format (printf)
  • Param ...: Possible printf arguments
int vlog_warn_at(Location* loc, const char* restrict format, va_list va);

parser/

This directory is responsible for all parsing which occurs from within the core. It contains the Emblem parser and lexer specifications as well as code for input sanitisation and handling syntactic sugar.

parser.h

Exposes document parser at the topmost level.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

sanitise-word.h

Exposes word-sanitiser for the Emblem parser.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

sugar.h

Exposes functions to construct syntactic sugar calls.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

pp/

Holds useful definitions for the preprocessor.

assert.h

Preprocessor definitions for compile-time assertions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lambda.h

Provides functions and preprocessor definitions for lambdas (anonymous functions).

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

func_sig

A named function signature.

  • Param r: Return type of the lambda, cannot be void
  • Param n: Expression of the body of the lambda, must have non-void type
  • Param ps: Parameters of the lambda

Returns: The signature of a function-pointer of name n which takes ps and returns r

#define func_sig(r, n, ps) r(fun n) ps

func_type

A function type.

  • Param r: Return type of the function signature
  • Param ps: Parameters of the function

Returns: The type of a function-pointer which takes ps and returns r

#define func_type(r, ps) r(fun) ps

ilambda

Create an impure anonymous function.

  • Param r: Return type of the lambda expression
  • Param ps: Paramters of the lambda expression
  • Param b: Body of the lambda expression, must be surrounded by curly braces

Returns: A pointer to an anonymous function with parameters ps, return-type r and body b

#	define ilambda(r, ps, b)                                                                                          \

lambda

Create a pure anonymous function.

  • Param r: Return type of the lambda, cannot be void
  • Param ps: Parameters of the lambda
  • Param e: Expression of the body of the lambda, must have non-void type

Returns: A pointer to an anonymous function which takes ps and returns the value of e of type r

#	define lambda(r, ps, e)                                                                                           \

void

Lambda-friendly implementation of free.

  • Param p: Pointer to memory to free
extern void(fun freel)(void* p);

not_implemented.h

Preprocessor definitions for function-stubs to stymie compiler errors.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

NOT_IMPLEMENTED

Declare a function signature as not-implemented.

  • Param sig: A signature to mark as unimplemented

Returns: An implementation of the signature which prints that the function is missing before exiting unsuccessfully

#define NOT_IMPLEMENTED(sig)                                                                                           \

unused.h

Provides preprocessor definitions to declare variables as unused to stymie compiler warnings.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

UNUSED

Declare a variable as unused.

  • Param x: The name of the variable to declare unused

Returns: A statement without effect which makes the compiler believe that x is used

#define UNUSED(x) x = x

style/

This module handles the resolution and usage of styling information. Specifically, it is responsible for inputting, preprocessing, reading and applying style-sheets.

css.h

Exposes functions to handle styling and stylesheets.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

css-params.h

Exposes functions to handle CSS-environment parameters.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

preprocess-css.h

Exposes functions to call a preprocessor on CSS documents.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

typesetter/

This module is responsible for handling the typesetter. It governs both the typesetting loop and the internal typesetting engine.

typesetter.h

Provides an interface to call the typesetting loop.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

Module internal docs

This section details the internal documentation written in each core module, that is, documentation present in files *.c in in the repository.

data/

Defines the generic data structures used to represent internal data.

array.c

Implement fixed-length arrays structures.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

cmp.c

Implements comparator functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

CMP

Create a generic comparator function.

  • Param name: Name of the type
  • Param type: Type to compare

Returns: A function which compares two types

#	define CMP(name, type) Cmp cmp_##name##s(void* v1, void* v2) COMPARISON_BODY(type)

either.c

Provices an implementation of the Either data-type, which can encode values of two types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

hash.c

Provides hash functions for standard data types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

HASH_NUM

Construct a function which hashes a specified numeric type.

  • Param name: The name of the type to hash
  • Param type: The type of the values to hash

Returns: A function which hashes types

#define HASH_NUM(name, type)                                                                                           \

list-array-conversions.c

Provides conversoin functions between arrays and lists.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

list.c

Implements the list data-structure, a deque.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

locked.c

Provides a locking structure for accessing data-structures, designed to prevent race conditions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

map.c

Implements the map data structure.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

next_non_empty_bucket

Find the next non-empty bucket with an index strictly after a specified index.

  • Param map: Map to search
  • Param curr: Strict index lower bound

Returns: true iff a non-empty bucket at index > curr was found, else false

static bool next_non_empty_bucket(Map* map, unsigned int* curr);

pkcmp

Key comparator function between a kv pair and a specific key.

  • Param kcmp: Location of the key comparator function

Returns: A lambda function which compares its input v1 to the key of its input v2

#define pkcmp(kcmp) lambda(Cmp, (void* v1, void* v2), kcmp(v1, ((Pair*)v2)->p0))

maybe.c

Implements the Maybe data-structure, which can represent either a value or nothing.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

str.c

Implements the string data-structure.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

unit.c

Implements the Unit data type.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

doc-struct/

This directory contains modules used to define and handle document structure.

ast.c

Implements the document structure data types.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

discern-pars.c

Implements functions to automatically place paragraph nodes in a document.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

location.c

Implements the Location data-structure and useful functions for keeping track of locations in the document source.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

drivers/

This directory contains files used for interacting with output drivers. It is responsibly for both defining a set of core output drivers, and also interfacing with those defined in extension-space.

drivers.c

Handles the execution of output drivers both from the core and in extensions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

write-out.c

This module lacks a documentation header.

Source file

This module does not contain any documented interface items.

em.c

Insertion point for the ‘em’ binary, invokes all functionality used for typeestting documents.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

main

Entry point.

  • Param argc: Number of command-line arguments
  • Param argv: Command-line argument array

Returns: Program exit code

int main(int argc, char** argv)

ext/

This directory contains the code which manages and interacts with extension space. It allows the execution of arbitrary Lua code as the program executes and is the module primarily responsible for Emblem’s extensibility.

In the source code, the standard extension library is defined in the lib/ directory beneath this one.

debug.c

Implements basic functionality for debugging involving the Lua stack.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-env.c

Implements the Lua extension environment, loading libraries, extensions and pointers.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-loader.c

Implements the extension-loader.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

ext-params.c

Implements functions to handle extension-environment parameters.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-ast-io.c

Provides functions for translating from Lua tables to docuemnt-trees and vice-versa.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua.c

Provides functions for executing evaluation-passes on document trees.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-em-parser.c

Provides interface between core Emblem parser and extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-events.c

Implements callers for typesetting events for extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

lua-pointers.c

This module lacks a documentation header.

Source file

This module does not contain any documented interface items.

style.c

Implements function for loading stylesheets from extension-space.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

logs/

This directory holds code which is responsible for logging-output. It also provides an interface between its logging functions and extension-space.

ext-log.c

Implements the C-side interface between extension-space and logging functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

logs.c

Implements logging functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

LOG_X_CALL

Construct a call to the logging function at verbosity lvl, where v is the start of the formatting.

  • Param lvl: Verbosity level of the call
  • Param v: Name of the first format argument

Returns: A call to log_x with va_args handled

#define LOG_X_CALL(name, f)                                                                                            \

log_debug

Write a debug message to stderr.

  • Param format: debug message format (printf)
  • Param ...: Possible printf arguments
void log_debug(const char* restrict format, ...) { LOG_X_CALL(debug, format); }

log_err

Write an error stderr.

  • Param format: Error format (printf)
  • Param ...: Possible printf arguments
void log_err(const char* restrict format, ...) { LOG_X_CALL(err, format); }

log_info

Write information to stderr.

  • Param format: Information format (printf)
  • Param ...: Possible printf arguments
void log_info(const char* restrict format, ...) { LOG_X_CALL(info, format); }

log_warn

Write a warning to stderr.

  • Param format: Warning format (printf)
  • Param ...: Possible printf arguments
int log_warn(const char* restrict format, ...)

parser/

This directory is responsible for all parsing which occurs from within the core. It contains the Emblem parser and lexer specifications as well as code for input sanitisation and handling syntactic sugar.

parser.c

Implements the parser at the top-level (entire-document).

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

sanitise-word.c

Implements the word-sanitiser function for the Emblem parser.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

sugar.c

Implements functions to construct syntactic sugar functions.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

pp/

Holds useful definitions for the preprocessor.

lambda.c

Implementations of free functions as lambdas.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

style/

This module handles the resolution and usage of styling information. Specifically, it is responsible for inputting, preprocessing, reading and applying style-sheets.

css.c

Manages resolution of styles and the handling of stylesheets.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

css-params.c

Implements functions to handle CSS-environment parameters.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

preprocess-css.c

Provides an implementation for a CSS preprocessor using SCSS/SASS.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

typesetter/

This module is responsible for handling the typesetter. It governs both the typesetting loop and the internal typesetting engine.

typesetter.c

Implements the typesetting loop.

  • Author: Edward Jones
  • Date: 2021-09-17

Source file

This module does not contain any documented interface items.

License and Author

This project is maintained by Ed Jones and is licensed under the GNU General Public License version 3.