hmacro
A kinda-terrible macro expander originally written in Haskell, but later rewritten in Rust.
Build
You can build this with Cargo, just run cargo build.
You can also install it with cargo install.
Invoking from the command line
Usage:
hmacro [OPTIONS] <filename>
`-v', `--version' - Print a version message, then exit
`-h', `--help' - Print a help message, then exit
`--license' - Display information about hmacro's license
`-Dmacro=exp' - Predefines a new macro, named `macro', that expands
to `exp'.
You can pass a list of filenames to hmacro.
They will each be expanded separately and the results concatenated.
Example CLI invocations
hmacro foo.hm
Expands foo.hm, then prints the result to stdout.
Source file format
hmacro works similarly to m4 or the C preprocessor.
It takes some text containing macros and definitions of those macros, and then expands those macros as desired and outputs the result.
Macros generally follow the vaguely-EBNF-style format below. Anything enclosed in / characters is a regular expression.
text ::= { textelem }
textelem ::= macro | scope | /[^\\]/ | "\\" | "\{" | "\}"
macro ::= '\' name { scope } | def | include
name ::= /[a-zA-Z\-_][a-zA-Z0-9\-_]*/
scope ::= '{' text '}'
Practically, hmacro source consists of macros and scopes.
Any macros defined inside a scope are no longer valid once outside of that scope, however, any scopes defined inside a scope inherit macros defined in scopes above that scope.
Scopes are delineated with curly braces, {}.
Curly braces can be escaped with \{ and \}.
A macro looks something like \name, where name is a name that must start with an alphabetic character, -, or _, and must consist only of alphanumeric characters, as well as - or _.
The \ character can be escaped with \\.
If a macro is immediately followed by one or more scopes, those scopes are considered arguments to that macro and are available to it when it expands.
Some macros are predefined as follows:
\def{name}{expansion}Defines a new macro callednamethat expands toexpansion.expansionconsists of text interspersed with macro arguments. A macro argument is of form$num, wherenumis the number of the argument.$1is the first argument,$2is the second, and so on. If a$character is followed by a numeric character, and you do not want either to be treated as specifying an argument, escape the$with\$123.\include{filename}Expands to the text offilename. The file itself will be processed for hmacro scopes and macros. Any macros that are not within a scope will be defined. Recursive includes are not allowed.\incldefs{filename}Expands to nothing, but any macros in the filefilenamethat are outside of a scope will be defined after this macro is called.\cat{arg1}{arg2}...{argn}Concatenates all arguments provided without expanding any of them.