Macro tips - vilinski/nemerle GitHub Wiki

Some quick notes about using macros and quotations. This should really be merged with macros' documentation page, but it will wait, because our parsetree structure is going to be changed soon and this will also impact quotations (simplyfiy them) a lot.

Quotations

For best reference of how to write quotations, take a look at algorithm used to translate them in the sources. This code is quite self explaining (at least if you just need to know how to write quotations).

Match cases

So first, why can't I write

 <[ | Some (x) => x ]> 

Unfortunately

 | Some (x) => x 

is a match case, not an expression, and standard quotation is used by default for expressions. To make a quoted match case, you must simply add the case: target to the quotation. So it would finally look like

 <[ case: | Some (x) => x ]> 

Unfortunately parsetree is not yet unified enough to look very consistent and try statement use different syntax for quotations. You write

 <[ try $body catch { $exn : $exn_ty => $handler } ]> 

This quotation allows only one handler in catch, but you can nest others in body of try block.

Compiler API available from macros

Macros are arbitrary functions and they can reference any external classes. It is sometimes also useful to use Nemerle compiler API from withing a macro. It is usually done using two methods

  • Using static helper functions from Nemerle.Compiler namespace
  • Using the instance of typer to make more advanced things, like typing some code fragment, asking for defined local variables in current scope, etc.
The second operation requires obtaining an instance of Nemerle.Compiler.Typer within a macro. Actually, every macro has it as a hidden parameter (we just didn't want to pollute macros syntax with this parameter, because it is rarely used) and it can be obtained using Nemerle.Macros.ImplicitCTX () function (it is a macro returning the hidden parameter).

Consider following code:

macro PrintVisibleLocalVariables(msg)
{
  def typer = Nemerle.Macros.ImplicitCTX();
  
  when (typer.IsMainPass)
  {
    Message.Hint("");
    Message.Hint($"Variables in $msg");
    Message.Hint($"$(msg.Location)");

    def locals = typer.LocalContext.GetLocals();
    mutable count = 0;

    foreach ((name : Nemerle.Compiler.Parsetree.Name, _value : Nemerle.Compiler.LocalValue) in locals)
    {
      Message.Hint($"   Variable: '$(name.Id)'");
      count++;
    }

    Message.Hint($"In this location $count variable(s) are visible.");
  }
  
  <[ () ]>
}

...

mutable x = 0;
PrintVisibleLocalVariables("some location");
This code print:
Main.n(18,5):Warning: hint: Variables in "some location"
Main.n(18,5):Warning: hint: Main.n:18:32:18:46: 
Main.n(18,5):Warning: hint:    Variable: 'x'
Main.n(18,5):Warning: hint: In this location 1 variable(s) are visible.

This is the way how you can get some compiler's internals for your own usage. Feel free to ask for new useful methods to be created in compiler if you need them.

⚠️ **GitHub.com Fallback** ⚠️