Macro functions in 2016.8.2

In addition to macro constants now we have more powerful macro functions (or procedural macros). Macro functions receive a list of tokens and output a string which will be pasted into code at compile time.

TheoryMacro function definition is similar to macro constants one:

name @(| ...body... |)

The only difference you should use parenthesis around markers. Here a marker is first character after opening parentheses (I prefer `|`). Same marker should be used to close macro body with closing parenthesis right after it.@`:

@(| ...another_body... |)

To call macro function use it's name with parenthesis as with usual functions:

name(...arguments...)

However macro function is different because you can pass arbitrary code to it. This code will be transformed into list of tokens (table) before passing to your macro function.For example `print(1 + 2)` code in

func(print(1 + 2))

will be transformed into

{"print", "(", "01", "+", "02", ")"}

For convenience tokens can be divided into 3 groups: identifiers, strings and numbers. Look at 1st character of token (with `string.sub`): strings always start with `"` (double quote), numbers start with `0` (zero) and all others are identifiers.Macro functions receive token list as `...`. You can look at received tokens inside macro function simply printing them with for-loop:

for k,v inpairs(...)doprint(k,v)

PracticeLet's write most simple macro function. We will transform `print` function into macro function to turn off all `print` calls:

print@(|return""|)

Every following `print` call after this definition will be transformed into nothing! This is handy if you often use print function for logging.Now little more complex function. It receives any code and pastes it as it is. It is useless but good for demonstration purposes.

paste @(|returntable.concat(..., " ")|)

It receives table of tokens (`...`), we concatenate them with spaces (`" "`) in between and return resulting string. Why do we use spaces in `table.concat`? Because otherwise a mess will be pasted. Each token is a string and if you pass something like `while a > b do print(a) end` and concatenate it without spaces then you get `whilea>bdoprint(a)end` which is invalid code. Add `paste` call:

paste(if1>0thenprint"1 is bigger than 0"end)

`if 1 > 0 then print "1 is bigger than 0" end` line will be pasted into resulting code and executed and you will see `1 is bigger than 0` in console.