Skip to content
Tim Disney edited this page Aug 28, 2013 · 2 revisions

Procedural Macros (aka syntax-case)

The new procedural macros let us define our macros using JavaScript.

macro m {
    case {_ ($x) } => {
        console.log("I'm in ur macros!");
        return #{ $x }
    }
}
m (42)
// ---> expands to
42 // logs: I'm in ur macros!

Changes from old design:

  • The pattern is now wrapped in a curly brace to prevent ambiguity. Previously case $x => ... would match m 42 but now this is an error. Instead do case {_ $x } => ....
  • Also the macro name is being matched as the first pattern and the wildcard pattern _ has been added so you can ignore it if you want.
  • The template form #{...} has been added. Any bound pattern variables that are in scope are replaced with their match.
  • Cases are matched in-order. Previously they were being matched by length first.
  • The ... pattern now matches zero or more. Previously it was one or more.

Primitives

For constructing new syntax objects we have the following primitive functions that are in scope inside a procedural macro. These loosely correspond to Scheme's datum->syntax but because JS has different token types we need the different functions. The first argument to each of these functions is used to construct the token and the context is taken from the optional second argument.

makeValue :: (Any, Null or Syntax) -> Syntax
    BooleanLiteral
    NullLiteral
    NumericLiteral
    StringLiteral

makeRegex :: (Str, Str, Null or Syntax) -> Syntax
    RegexLiteral
    // the second argument here is the flags for the regex

makeIdent :: (Str, Null or Syntax) -> Syntax
    Identifier

makeKeyword :: (Str, Null or Syntax) -> Syntax
    Keyword

makePunc :: (Str, Null or Syntax) -> Syntax
    Punctuator

makeDelim :: (Str, [...Syntax], Null or Syntax) -> Syntax
    Delimiter

The makeDelim function is a little odd but to make a delimiter syntax object we can't just pass it literally. So we say what type it is with the first param ("{}", "[]", or "()"), its children syntax objects with the second, and the context with the third. Eg: makeDelimiter("{}", [makeValue(42, null)], null).

To unwrap the syntax object we have the wonderfully named unwrapSyntax (similar to Scheme's syntax-e):

unwrapSyntax :: (Syntax) -> Any

This gives either a flat value (like a number) or a delimiter token with unwrapped syntax objects inside.

Clone this wiki locally