www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ubermacros a la Nemerle

reply Andy Friesen <andy ikagames.com> writes:
Nemerle (http://nemerle.org) is a hybrid functional/imperative language 
that targets .NET.  It's a sort of melding of C# and ML.

What makes it stand out is its macro facilities, which more or less 
cover any sort of language extension that I can even imagine.

Nemerle macros effectively boil down to functions that are run by the 
compiler.  They accept parse trees as arguments, and return a parse tree 
  element which is injected into the code.  It is my understanding that 
Lisp macros work on the same principle, but this is the first time I've 
seen it in a form that doesn't seem magical. (maybe I just haven't read 
enough Lisp yet)

Currently, Nemerle macros are compiled into separate DLLs, which, while 
somewhat klunky, allows closed-source people to use them for libraries 
and such.  It also makes it abundantly clear when things are happening 
and what dependancies exist. (macros are needed by the compiler, not the 
resulting binary)

Hypothetical example:

     import std.compiler;

     Expression print(Expression args) {

         // would presumably raise a SyntaxError if 'args' is not an
         // argument list
         auto Expression[] argList = decomposeArgumentList(args);

         Expression[] result
         foreach (Expression arg; args) {

             // <[ stuff ]> is an Expression object representing the
             // enclosed hunk of code.

             // $arg is used to denote that the argument is inserted into
             // the block, as opposed to literally inserting the symbol
             // 'arg'.  Maybe there's a nicer looking alternative.
             result ~= <[ stdio.write($arg) ]>;
         }

         result ~= <[ stdio.write('\n') ]>;

         // Convert the Expression[] into a single { ... } block and 
return it.
         return composeBlock(result);
     }

This would expand the expression 'print(x,y,z,blah,"thing", 3.141596, 
2+4i)' to a {} block containing a bunch of of stdio.write() calls, 
ending with a newline.

Something tells me this is just a hair too ambitious for D 1.0, but it 
does look to be implementable enough, and has a pretty big impact on 
what can be conveniently expressed within the language. (if I'm reading 
the source correctly, almost all of Nemerle's syntax is implemented via 
its own macros)

Thoughts?

  -- andy
Jun 08 2004
next sibling parent "Ivan Senji" <ivan.senji public.srce.hr> writes:
Lately i have been trying to put my finger on a feature that would give
ability to generate code at compile time (inspired by VHDL's generate)
but i had no idea how this would work.But it could be a Very powerful
feature.

D 2.0?

"Andy Friesen" <andy ikagames.com> wrote in message
news:ca56h1$2k4h$1 digitaldaemon.com...
 Nemerle (http://nemerle.org) is a hybrid functional/imperative language
 that targets .NET.  It's a sort of melding of C# and ML.

 What makes it stand out is its macro facilities, which more or less
 cover any sort of language extension that I can even imagine.

 Nemerle macros effectively boil down to functions that are run by the
 compiler.  They accept parse trees as arguments, and return a parse tree
   element which is injected into the code.  It is my understanding that
 Lisp macros work on the same principle, but this is the first time I've
 seen it in a form that doesn't seem magical. (maybe I just haven't read
 enough Lisp yet)

 Currently, Nemerle macros are compiled into separate DLLs, which, while
 somewhat klunky, allows closed-source people to use them for libraries
 and such.  It also makes it abundantly clear when things are happening
 and what dependancies exist. (macros are needed by the compiler, not the
 resulting binary)

 Hypothetical example:

      import std.compiler;

      Expression print(Expression args) {

          // would presumably raise a SyntaxError if 'args' is not an
          // argument list
          auto Expression[] argList = decomposeArgumentList(args);

          Expression[] result
          foreach (Expression arg; args) {

              // <[ stuff ]> is an Expression object representing the
              // enclosed hunk of code.

              // $arg is used to denote that the argument is inserted into
              // the block, as opposed to literally inserting the symbol
              // 'arg'.  Maybe there's a nicer looking alternative.
              result ~= <[ stdio.write($arg) ]>;
          }

          result ~= <[ stdio.write('\n') ]>;

          // Convert the Expression[] into a single { ... } block and
 return it.
          return composeBlock(result);
      }

 This would expand the expression 'print(x,y,z,blah,"thing", 3.141596,
 2+4i)' to a {} block containing a bunch of of stdio.write() calls,
 ending with a newline.

 Something tells me this is just a hair too ambitious for D 1.0, but it
 does look to be implementable enough, and has a pretty big impact on
 what can be conveniently expressed within the language. (if I'm reading
 the source correctly, almost all of Nemerle's syntax is implemented via
 its own macros)

 Thoughts?

   -- andy

Jun 08 2004
prev sibling parent Brad Anderson <brad sankaty.dot.com> writes:
If it truly is like Lisp's macros, it would be a feature of D that not 
many languages have, and would truly be for power programmers. 
(According to Paul Graham).

If Walter implemented this, he would be able to point people to this 
capability and tell them to try it themselves instead of having them/us 
wait for a new release.

BA

Andy Friesen wrote:

 Nemerle (http://nemerle.org) is a hybrid functional/imperative language 
 that targets .NET.  It's a sort of melding of C# and ML.
 
 What makes it stand out is its macro facilities, which more or less 
 cover any sort of language extension that I can even imagine.
 
 Nemerle macros effectively boil down to functions that are run by the 
 compiler.  They accept parse trees as arguments, and return a parse tree 
  element which is injected into the code.  It is my understanding that 
 Lisp macros work on the same principle, but this is the first time I've 
 seen it in a form that doesn't seem magical. (maybe I just haven't read 
 enough Lisp yet)
 
 Currently, Nemerle macros are compiled into separate DLLs, which, while 
 somewhat klunky, allows closed-source people to use them for libraries 
 and such.  It also makes it abundantly clear when things are happening 
 and what dependancies exist. (macros are needed by the compiler, not the 
 resulting binary)
 
 Hypothetical example:
 
     import std.compiler;
 
     Expression print(Expression args) {
 
         // would presumably raise a SyntaxError if 'args' is not an
         // argument list
         auto Expression[] argList = decomposeArgumentList(args);
 
         Expression[] result
         foreach (Expression arg; args) {
 
             // <[ stuff ]> is an Expression object representing the
             // enclosed hunk of code.
 
             // $arg is used to denote that the argument is inserted into
             // the block, as opposed to literally inserting the symbol
             // 'arg'.  Maybe there's a nicer looking alternative.
             result ~= <[ stdio.write($arg) ]>;
         }
 
         result ~= <[ stdio.write('\n') ]>;
 
         // Convert the Expression[] into a single { ... } block and 
 return it.
         return composeBlock(result);
     }
 
 This would expand the expression 'print(x,y,z,blah,"thing", 3.141596, 
 2+4i)' to a {} block containing a bunch of of stdio.write() calls, 
 ending with a newline.
 
 Something tells me this is just a hair too ambitious for D 1.0, but it 
 does look to be implementable enough, and has a pretty big impact on 
 what can be conveniently expressed within the language. (if I'm reading 
 the source correctly, almost all of Nemerle's syntax is implemented via 
 its own macros)
 
 Thoughts?
 
  -- andy

Jun 08 2004