sweet.js

Is it possible to make a sweet.js macro `m` expand to the symbol `m`?


Suppose there's a function somewhere called m, which is invoked like this

//foo.js
m("foo")

I have a sweet.js macro that defines a macro called m which is meant to take foo.js and expand m (basically to run the function at compile time)

In some cases I want to not expand m, because unlike macros, functions can be passed around as first class citizens

doSomething(m) //don't want to expand this as a macro

If I don't have a case that covers this scenario in the macro, sweet.js complains, so I need to have a catch-all rule that just expands to the same symbol.

macro m {
  //simplification to demonstrate a case that recursively expand macro
  case { _ ( $foo, $bar) } => { return #{m($foo)} }
  //does syntax unwrapping in real case
  case { _ ( $foo ) } => { return #{$foo} }

  //**this tries to recursively expand `m`, which is not what I want**
  case { _ } => { return #{m} } 
}

How do I make the m macro expand to the m function, given that other cases of the macro do need to recursively expand m as a macro?


Solution

  • You'll want to let bind the macro:

    let m = macro {
      case { _ ( $foo, $bar) } => { return #{$foo} }
      case { _ ( $foo ) } => { return #{$foo} }
    
      // `m` is bound to the surrounding scope, not the macro
      case { _ } => { return #{m} }
    }
    

    Edit:

    Sorry, didn't read your question fully the first time :)

    Here's a better solution, you just need to split it out into two different macros, one that can do the actual recursive work and another to handle the non-recursive base case:

    function m() {}
    macro m_impl {
      case { _ ( $foo, $bar) } => { return #{m_impl($foo)} }
      case { _ ( $foo ) } => { return #{$foo} }
    }
    
    let m = macro {
      case { _ ($foo, $bar) } => { return #{m_impl($foo, $bar)} } 
      case { _ } => { return #{m} } 
    }
    
    m (100, 200);
    doSomething(m)