Harbinger Template

Introduction

Harbinger template is a quirky, efficient, flexible, fun* and concise templating language. The primary design goal is to write as much human readable data as possible using as few keystrokes as possible given a large volume of input text. Everything else, including legibility, is of secondary concern.

This document describes the specification of the Harbinger Template language Version 0.1.

Terminology

The terms “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

This document uses EBNF syntax.

The term "templating engine" in this document is used to refer to the software translating the harbinger code to the result.

The term "template" is used for the original harbinger code from which the result is generated.

Basic Concepts

Basic Definitions

Character

Character defines any unicode character.

character ::= (* See EBNF 6.2 *) terminal character

New-Line

New Line is the Unicode codepoint U+000A (\n).

new-line ::= ? IS0 6429 character Line Feed ?

Space

New Line is the Unicode codepoint U+0020 ( ).

space ::= ' '

Non-space

Non-space characters include each character except space.

non-space ::= character - space

Octothorpe

Octothorpe is the Unicode codepoint U+0023 (#).

octothorpe ::= '#'

Lines

The most fundamental building block of a Harbinger template is the line. Each line of a valid Harbinger input is defined as a list of non-newline characters. Each line is separated from the next with a New line character.

line ::= {character - new-line} [new-line]

Line-type

Each line MUST be parsed separately by the templating engine, and the characters until the first space of the line mark the line type.

line-type ::= {character-space};
line ::= line-type {character - new-line} [new-line] (* Equivalent to the definition above *)

Example:

# The following line has line type aaa
aaa bb ccc

The line type determines how the line SHALL be parsed. For each line type the templating engine must first check the most recent type definition of the line type. If no type definition is found, the templating engine MUST use the type definition default and pass the entire line to it. If no default type definition exists, the templating engine MUST default to concatenating the current line to the result as a string.

If during the processing of the line an exception occurs, the templating engine MUST exit with an error.

Harbinger-command

Every line consisting of an octothorpe (#) followed by a non-space character and any number of other non-new-line characters is reserved for Harbinger template internal use. Such lines are referred to as Harbinger commands.

harbinger-command ::= octothorpe, (character - space), {character - new-line}, [new-line]

Comment

Every line consisting of an octothorpe (#) followed by a space character and any number of other non-new-line characters is considered a comment.

comment ::= octothorpe, (space), {character - new-line}, [new-line]

Example:

# This is a comment

Harbinger commands

#exec

The #exec command is used to run user-defined code in a user-defined language. The syntax of #exec is the literal #exec, followed by a space, followed by exec-options that determine properties of the code to be run.

exec-options ::= lang-option
exec-command ::='#exec', space, [exec-options]

Exec block

Any lines following a #exec command become part of exec block, until an #end command is encountered.

exec-block = exec-command, {line - end-command}, end-command

Lines that are parts of the exec block MUST be parsed by the templating engine in the language selected in the lang-option of the definition. If the parameter is not set, the language in the most recent #use command MUST be used. If no #use command has so far been used in the input, the templating engine MUST default to js.

Inside the exec block, the user MAY supply code in the language defined, according to the language specification of the selected language. This code MUST have access to the following parameters in its language:

Any changes the code makes to the tmp and res variables MUST be retained for the next line being parsed.

Example

Template:

#exec lang=js
res=`foobar`
#end

Output:

foobar

#define

The #define command is used to determine user-defined line types. In case multiple definitions exist for the same type, each definition is valid until a new one is encountered. Afterwards the new definition will be valid. The syntax of #define commands is the command #define followed by the line-type to be defined (or the string default to define the style to be used for lines that do not match any type definitions), followed by define-options that determine properties of the type definition.

definte-options ::= lang-option
define-command ::='#define', space, (line-type | 'default'), space, [define-options], new-line

Type definition block

Any lines following a #define command become part of the definition of the type, until an #end command is encountered.

define-block = define-command, {line - end-command}, end-command

Lines that are parts of the type definition MUST be parsed by the templating engine in the language selected in the lang-option of the definition. If the parameter is not set, the language in the most recent #use command MUST be used. If no #use command has so far been used in the input, the templating engine MUST default to js.

Inside the type definition block, the user MAY supply code in the language defined, according to the language specification of the selected language. This code MUST have access to the following parameters in its language:

Any changes the code makes to the tmp and res variables MUST be retained for the next line being parsed.

Example

Template:

#define uppercase lang=js
res+=line.toUpperCase()+'\n'
#end
uppercase foo

Output:

FOO

#use

The #use command defines which language to use for subsequent #exec and #define commands. The syntax of the #use command is the literal #use followed by a space, followed by a lang-option.

'#use', lang-option, [new-line]

#end

The #end command is used to mark the end of #exec and #define blocks. The syntax of the #use command is the literal #end. Any characters after the #end statement must be ignored by the templating engine.

'#end', {character - new-line}, [new-line]

#include

Include commands are optional commands to be supported by templating engines that have access to the file system or internet resources. Include statements can be used to include the contents of a file on disk or a remote server into the current template file. Templating engines that support this feature MUST treat this command as if the contents of the file being referenced were in its place. Templating engines MUST also provide the included lines to other blocks in the lines field. If the URL being included is identical to the URL of the currently parsed file, templating engines MUST exit with an error. The syntax of include statements is the literal #include followed by a space followed by the URL of the file to be included.

'#include', space, url (* see RFC 1738 *)

Example:

Input: foo.harb

#define foo
res += 'abc'
#end
foo

bar.harb

#define bar
res += 'def'
#end
#define foo
res += 'xyz'
#end
foo
#include file://foo.harb
bar
foo

Output:

xyz
abc
def
abc

Harbinger command options

lang-option

The lang-option defines the language in which the exec block shall be parsed. Templating engines MUST support Javascript (js) for exec blocks, and they MAY support additional languages. In the case additional languages are supported, the language code used as the extension of the file of the specified language MUST be used in the lang-option parameter.

language ::= js | ? additional language extensions ?
lang-option ::= 'lang=', language

End of file

If an end of file is encountered, the Templating engine MUST stop processing and output the current string representation of the res variable to the output. If an #end tag is missing for an opened #define or #exec block, the templating engine MAY exit with an error, OR insert the tag and print a warning before exiting.