/mast

A simple DSL for defining abstract syntax trees in Nim

Primary LanguageNim

mast

Testing

A simple DSL for defining abstract syntax trees in Nim.

This project was directly inspired by the breeze library.

Overview

This library provides another way to write Nim macros more closely following the output of treeRepr.

Showcase

Please see tests for examples of most features. This section provides an incomplete summary of the core functionality.

Basic example

The following is an example usage:

import mast

macro makeMain(say: static string) =
  ast:
    ProcDef:
      `main`
      Empty
      Empty
      FormalParams:
        Empty
      Empty
      Empty
      StmtList:
        Command:
          `echo`
          "Hello macro!"
        Command:
          `echo`
          (lit say)

makeMain "Hello world!"
# `makeMain` expands to:
proc main() =
  echo "Hello macro!"
  echo "Hello world!"

Notice that most elements in the AST definition correspond to their nnk* NimNode counterparts. Exceptions to this pattern are the following:

  • Identifiers which are enclosed in backticks ("`")
  • Literals which are simply specified in the AST definition as-is
  • External expressions which are embedded in the AST by enclosing them in parentheses

Identifiers

Under the hood mast uses the fmt macro to parse identifier names. This means that identifier names can be composed using the following syntax:

let i = 1
let newIdent = ast`ident{i}` # generates `Ident "ident1"`

Bound symbols can be specified by using the sym macro:

let boundSym = ast (sym someDeclaredSymbol)

Lastly, new symbols can be generated using the following syntax:

let genSymed = ast (sym Proc`someProcSymbol`)

The Proc symbol here corresponds to nskProc, and the symbol inside the backticks can be interpolated in the same way as identifiers.

Installing

The package can be installed by following the nimble instructions here.

Usage

Simply import mast into your module to start using it.

Contributing

This project is maintained during my free time, and serves as a tool for a game engine I am writing after work hours. Contributions are welcome, and I will merge them immediately if they serve to keep the project robust, simple, and maintainable.

Cheers and happy coding! 🍺