There are two tools in Metalua which you should consider, either to use directly or as a source of inspiration.
First, the pattern matching extension:
match data with
| { name, x, y } -> return { sprite = '/img/'..name, x=x, y=y }
| { name} ->
local filename = '/img/'..name
local x, y = getDimensionsFromExternalTool(filename)
return { sprite = filename, x=x, y=y }
| _ -> error "invalid pattern"
end
- Patterns can be arbitrarily complicated, with nested structures, hash-parts in the tables, etc.
- Every variable appearing in the pattern is automatically bound to the matching sub-part of `data`.
- Multiple occurrences constraints are handled (`{x=a, y=a}` will only match if `data.x==data.y`).
- Multiple patterns are legal as long as they capture the same variables (`{x=a}|{y=a}` is a legal pattern, `{x=a}|{y=b}` is not). `_` is treated as a special case, is doesn't bind anything.
- You can add arbitrary guards with "if", e.g. `| { name, x, y } if name:find '.png$' ->`
- `...` can be used to match lists of arbitrary size, and captures the extra elements as expected.
It makes data destructuring and transformation code very declarative and readable. ML-family languages, whose designs are primarily optimized to write ML-family language compilers, use it with unanimous success.
Second, the TreeQuery DSL. It's clearly optimized to handle ASTs, since that's what Metalua does the most, but it's a rather nice way to describe complex tree traversals. For instance, I wrote this yesterday, to detect all global variables in an AST semantically, rather than by grepping bytecode dumps:
-- Complete sample available at:
-- https://github.com/fab13n/metalua-compiler/blob/master/samples/globals.lua
local Q = require 'metalua.treequery' -- AST queries
local globals = { }
local function log_global(id, ...) [...snip, irrelevant...] end
Q(ast) -- globals are...
:filter 'Id' -- ...nodes with tag 'Id'...
:filter_not (Q.is_binder) -- ...which are not local binders...
:filter_not (Q.get_binder) -- ...and aren't bound;
:foreach (log_global) -- log each of them in `globals`.
Notice that contrary to pattern matching, TreeQuery is a Lua DSL, you can use it from a plain Lua source file.
I've been working on turning Metalua into a (couple of) proper rock(s), the parser is already available as metalua-parser, and the compiler is almost ready, and in practice is available at
https://github.com/fab13n/metalua-compiler.