[prev in list] [next in list] [prev in thread] [next in thread]
List: groovy-dev
Subject: Re: [groovy-dev] State of the macros
From: <cedric.champeau () gmail ! com>
Date: 2014-10-20 17:57:48
Message-ID: 54454D1C.4080400 () gmail ! com
[Download RAW message or body]
It's a bit soon to talk about limitations, but I expect problems with
generics, as well as the syntax to transform statements (it is easy to
transform an expression into another expression,but transforming a
statement is more complex).
On 17/10/2014 19:34, ngalarneau@ABINITIO.COM wrote:
> Cedric,
>
> That looks exciting!
>
> What limitations do you foresee?
>
>
> Neil
>
>
>
>
> From: Cédric Champeau <cedric.champeau@gmail.com>
> To: dev@groovy.codehaus.org,
> Date: 10/17/2014 12:43 PM
> Subject: Re: [groovy-dev] State of the macros
> ------------------------------------------------------------------------
>
>
>
> So here is the update for the end of the week. I worked with Sergei on
> improving the macro system on two aspects:
>
> 1. being able to generate classes with macros
> 2. providing an AST matcher
>
> I think 2 is very important if we want to simplify AST xforms.
> Basically, if you need an AST transform to trigger on a specific
> condition (like matching a method call of a certain form), it can be
> very complicated and require a lot of boilerplate code. So the idea
> would be to provide AST matching, where you would describe what you
> look for, and the matching engine would return the list of AST nodes
> that match. The good news is that I have a prototype working, and you
> can already take a look at some code samples here:
> _https://github.com/melix/groovy-core/blob/d42fd1b39c5c421daf6cacb45403f8dcb06f8f12/ \
> subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35_
>
> The API is far from being final, and as an example, I wrote an example
> that illustrates what it could, in the end, look like:
>
> def ast = macro {
>
> println((a*b)+(a*c))
>
> }
>
> use(ASTMatcher) {
>
> def pattern = macro {
>
> (a*b)+(a*c)
>
> }
>
> def replacement = macro {
>
> a*(b+c)
>
> }
>
> def result = ast.replace(pattern).with(replacement)
>
> def expected = macro {
>
> println (a*(b+c))
>
> }
>
> assert result.matches(expected)
>
> }
>
>
>
> What do you think?
>
> Last but not least, the more I work with macros, the less I feed the
> need for the global AST transformation. I think annotating the code
> that uses the "macro" block with a local AST xform would be enough.
> Thoughts?
>
>
> On 07/10/2014 19:46, Sergei Egorov wrote:
> Great brief, Cedric!
>
> I'm here and ready to discuss both features.
>
> Just want to add few things:
>
> * MacroGroovy already can be used inside @Macro methods
> * The reason why I'm created @Macro extension methods (MEMs) is
> simple: I decided to extract code base from MacroGroovy, because
> it can be used outside of "AST nodes generation" context.
> * MEMs are implemented with Global AST transformation with method
> call scanning, and it costs. But, there are already almost the
> same transformation called AstBuilderTransformation. Most
> important, it can be replaced with @Macro method with
> backward compatibility. So, it's not about new global xform. Just
> rethinking of old one.
>
>
>
>
>
> On Tue, Oct 7, 2014 at 8:20 PM, Cédric Champeau
> <_cedric.champeau@gmail.com_ <mailto:cedric.champeau@gmail.com>> wrote:
> Hi everyone,
>
> You may know that we have long been complaining about the complexity
> of AST transformations in Groovy. There are a very powerful tool, but
> it is still a bit complex to handle. In Groovy 2.4, we planned to
> integrate work from Sergei Egorov (@bsideup) that he called "Groovy
> macros". Basically the idea is to have a simple way to replace classic
> method class into more complex expressions. In this email, I'll try to
> summarize the project and give some ideas about the orientations we
> want for the Groovy language. In the end, your opinion matters so
> please feel free to comment.
>
> First of all, Sergei actually worked on two "macro" projects. The
> first one consists of a "macro" block that can be illustrated by this:
> *def *someVariable = *new *VariableExpression(*"someVariable"*);
>
> ReturnStatement result = macro {
> *return new *NonExistingClass($v{someVariable});
> }
>
> As you can see, it is some kind of "super AstBuilder" which is capable
> of handling variables/expressions from an external context thanks to
> proper escaping with $v. This macro code is primarily aimed at being
> used inside AST transformation themselves, and dramatically reduce the
> amount of code required to generate an AST tree. An advantage of those
> macro blocks is that if you use them in AST transformations, you're
> actually not limited to expressions. You can generate anything, as
> long as what is inside the macro { ... } block is supported by the
> Groovy syntax. A drawback of the current implementation is that it
> uses a global AST transformation. So as soon as you have the macro
> project on classpath, every single method call corresponding to
> "macro" will be interpreted as a macro block. There are multiple
> disadvantages of global AST transformations. First of all, they are,
> as the name says, global, meaning that they apply independently on
> *every* class being compiled by Groovy. This also means that the
> transformation is run even if you know the code you write is not using
> it. In particular, we need to inspect the full AST, in-depth, to find
> potential method calls named "macro" even if there's not a single one
> in the code (because you will only know once you have visited the full
> AST). In short, a global AST transformation has a clear performance
> impact, because it is executed independently of the context. For the
> macro stuff, an easy workaround would be to transform the global AST
> transformation into a local one. For example, an AST transformation
> using the macro system could declare it by annotating with
> @EnableMacros. I think it is reasonable, since it is very unlikely
> that you would use the macro { ... } stuff in regular code. The macro
> block is indeed useful, but in the end, it is limited to writing other
> AST transformations that would be either global or local. In short,
> the current macro { ... } block is useful for AST transformation
> designers, but cannot be used by "regular" Groovy users to define new
> language constructs.
>
> In answer to that problem, Sergei worked on a second implementation of
> macros named @Macro. The idea is both simple and elegant. Just like
> you can define extension methods in Groovy (see
> _http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules_),
> you can write a macro like this:
>
> *public class *TestMacroMethods {
>
> @Macro
> *public static *Expression safe(MacroContext macroContext,
> MethodCallExpression callExpression) {
> *return */ternaryX/(
> /notNullX/(callExpression.getObjectExpression()),
> callExpression,
> /constX/(*null*)
> );
> }
> }
>
> and for this to work, TestMacroMethods needs to be declared as a
> regular Groovy extension module. In that case, *any* code using "safe"
> would be transformed, so:
>
> safe(x.foo()).bar()
>
> will be expanded *at compile time* into x.foo?x.foo().bar():null
>
> A more interesting example with pattern matching can be found here:
> _https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java_
>
> An important thing to understand is that the @Macro annotation is
> *not* an AST transformation. Instead, it's a marker annotation which
> is looked up at compile time, for each method call. So for each method
> call of the AST, we try to find if an extension method node of the
> same name exists, is annotated with @Macro and takes MacroContext as
> the first argument and in that case, the original method call is
> transformed thanks to the extension method at compile time. The code
> of the macro itself is regular AST transformation code. It does *not*
> use the macro stuff from the first implementation, hence doesn't
> simplify writing xforms. On the other hand, it greatly simplifies the
> availability of transforms by making them writable as simple extension
> methods, without the need of ceremony (annotations). It is actually
> very cool, but it comes at a price. Performance wise, it is still a
> global AST transformation, but worse, for each and every call, it
> implies finding an extension method node. It can (and will) cost a
> lot, but we can improve the situation by introducing specific caches.
> Moreover, it also implies that the sole fact of adding a macro "jar"
> on classpath could potentially affect the semantics of your program:
> if a method call in your code matches the name of a macro method call,
> then it would be applied at compile time. Of course, one could argue
> that it is already the case for extension modules, but the risk is
> lower: for extension modules, the only cases of conflicts is when the
> receiver of the message matches the class of the extension module. For
> @Macro, any method call on "implicit this" would be matched. This
> draws the point of whether the @Macro stuff should also be combined
> with a @UseMacro local AST transformation, in order to avoid the
> problem of the global one.
>
> If we do, then definitely, the performance issue is not one anymore,
> because only marked code would be transformed. On the other hand, we
> introduce ceremony again, which would mean that we loose the benefit
> of extension methods being transparently visible. In the case of the
> pattern matching stuff, this would mean that you would have to
> explicitly annotate your code to enable the feature. Is it a problem?
> I'm not sure actually. Also it's worth noting that the global AST
> transformation issue is less of a problem if you have lots of macros
> on classpath, because a single transformation would apply them all in
> a single pass.
>
> Last but not least, my feeling is that what we need is something in
> between the first macro implementation and the second one. In
> particular, I would like to be able to write the @Macro method body
> using those macro { ... } blocks. It makes a lot of sense to me. Next,
> I wouldn't like to be limited to expressions. I think a macro should
> be able to produce any AST node. This implies expressions, but also
> statements or even full methods.
>
> I gave an example a little contrived, I admit, to Sergei, which is,
> imagine that I want to generate two methods with the same body, but
> accepting two different argument types. Then I could write a macro
> that generates the method:
>
> @Macro MethodNode createMultiply(MacroContext ctx, ClassNode argType) {
> macro {
> _argType_ multByTwo(_argType_ x) { 2 }
> }
> }
>
> Then in a class I could write:
>
> class Calculator {
> createMultiply int
> createMultiply double
> }
>
> Of course, this wouldn't compile because the grammar wouldn't allow
> defining a method in a closure (in the macro block), and it would not
> recognize the createMultiply calls directly in the class body, but I
> kind of like the idea of a macro system that just allows expanding and
> reasoning at the AST level anywhere, because it lets us create new
> language constructs.
>
> In any case, let us know what you think, what you expect from a macro
> system in Groovy. We have very good starting points, let's make it
> rock solid :-)
> --
> Cédric Champeau
> SpringSource - Pivotal
> _http://twitter.com/CedricChampeau_
> _http://melix.github.io/blog_
> _http://spring.io/__http://www.gopivotal.com/_
>
>
>
>
> --
> Best regards,
> Sergei Egorov
>
>
> --
> Cédric Champeau
> SpringSource - Pivotal
> _http://twitter.com/CedricChampeau_
> _http://melix.github.io/blog_
> _http://spring.io/__http://www.gopivotal.com/_
>
>
>
>
> NOTICE /from Ab Initio: This email (including any attachments) may
> contain information that is subject to confidentiality obligations or
> is legally privileged, and sender does not waive confidentiality or
> privilege. If received in error, please notify the sender, delete this
> email, and make no further use, disclosure, or distribution. /
--
Cédric Champeau
SpringSource - Pivotal
http://twitter.com/CedricChampeau
http://melix.github.io/blog
http://spring.io/ http://www.gopivotal.com/
[Attachment #3 (text/html)]
<html>
<head>
<meta content="text/html; charset=windows-1252"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">It's a bit soon to talk about
limitations, but I expect problems with generics, as well as the
syntax to transform statements (it is easy to transform an
expression into another expression,but transforming a statement is
more complex).<br>
<br>
On 17/10/2014 19:34, <a class="moz-txt-link-abbreviated" \
href="mailto:ngalarneau@ABINITIO.COM">ngalarneau@ABINITIO.COM</a> wrote:<br> </div>
<blockquote
cite="mid:OFBB777D6B.77E00EEE-ON85257D74.005FF70F-85257D74.006081D7@abinitio.com"
type="cite"><font face="sans-serif" size="2">Cedric,</font>
<br>
<br>
<font face="sans-serif" size="2">That looks exciting!</font>
<br>
<br>
<font face="sans-serif" size="2">What limitations do you foresee?</font>
<br>
<br>
<br>
<font face="sans-serif" size="2">Neil</font>
<br>
<br>
<br>
<br>
<br>
<font color="#5f5f5f" face="sans-serif" size="1">From:
</font><font face="sans-serif" size="1">Cédric Champeau
<a class="moz-txt-link-rfc2396E" \
href="mailto:cedric.champeau@gmail.com"><cedric.champeau@gmail.com></a></font> \
<br> <font color="#5f5f5f" face="sans-serif" size="1">To:
</font><font face="sans-serif" size="1"><a class="moz-txt-link-abbreviated" \
href="mailto:dev@groovy.codehaus.org">dev@groovy.codehaus.org</a>, </font>
<br>
<font color="#5f5f5f" face="sans-serif" size="1">Date:
</font><font face="sans-serif" size="1">10/17/2014 12:43 PM</font>
<br>
<font color="#5f5f5f" face="sans-serif" size="1">Subject:
</font><font face="sans-serif" size="1">Re: [groovy-dev]
State of the macros</font>
<br>
<hr noshade="noshade">
<br>
<br>
<br>
<font size="3">So here is the update for the end of the week. I
worked
with Sergei on improving the macro system on two aspects:<br>
<br>
1. being able to generate classes with macros<br>
2. providing an AST matcher<br>
<br>
I think 2 is very important if we want to simplify AST xforms.
Basically,
if you need an AST transform to trigger on a specific condition
(like matching
a method call of a certain form), it can be very complicated and
require
a lot of boilerplate code. So the idea would be to provide AST
matching,
where you would describe what you look for, and the matching
engine would
return the list of AST nodes that match. The good news is that I
have a
prototype working, and you can already take a look at some code
samples
here: </font><a moz-do-not-send="true"
href="https://github.com/melix/groovy-core/blob/d42fd1b39c5c421daf6cacb45403f8dcb06f8f \
12/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35"><font
color="blue" size="3"><u>https://github.com/melix/groovy-core/blob/d42fd1b39c5c421da \
f6cacb45403f8dcb06f8f12/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/matcher/ASTMatcherTest.groovy#L35</u></font></a><font
size="3"><br>
<br>
The API is far from being final, and as an example, I wrote an
example
that illustrates what it could, in the end, look like:<br>
</font>
<br>
<tt><font size="3">def ast = macro {<br>
</font></tt>
<br>
<tt><font size="3">
println((a*b)+(a*c))<br>
</font></tt>
<br>
<tt><font size="3"> }<br>
</font></tt>
<br>
<tt><font size="3"> use(ASTMatcher)
{<br>
</font></tt>
<br>
<tt><font size="3">
def pattern = macro {<br>
</font></tt>
<br>
<tt><font size="3">
(a*b)+(a*c)<br>
</font></tt>
<br>
<tt><font size="3">
}<br>
</font></tt>
<br>
<tt><font size="3">
def replacement = macro {<br>
</font></tt>
<br>
<tt><font size="3">
a*(b+c)<br>
</font></tt>
<br>
<tt><font size="3">
}<br>
</font></tt>
<br>
<tt><font size="3">
def result = ast.replace(pattern).with(replacement)<br>
</font></tt>
<br>
<tt><font size="3">
def expected = macro {<br>
</font></tt>
<br>
<tt><font size="3">
println (a*(b+c))<br>
</font></tt>
<br>
<tt><font size="3">
}<br>
</font></tt>
<br>
<tt><font size="3">
assert result.matches(expected)<br>
</font></tt>
<br>
<tt><font size="3"> }<br>
</font></tt>
<br>
<font size="3"><br>
<br>
What do you think?<br>
<br>
Last but not least, the more I work with macros, the less I feed
the need
for the global AST transformation. I think annotating the code
that uses
the "macro" block with a local AST xform would be enough.
Thoughts?<br>
<br>
<br>
On 07/10/2014 19:46, Sergei Egorov wrote:</font>
<br>
<font size="3">Great brief, Cedric! </font>
<br>
<br>
<font size="3">I'm here and ready to discuss both features. </font>
<br>
<br>
<font size="3">Just want to add few things:</font>
<ul>
<li><font size="3">MacroGroovy already can be used inside @Macro
methods</font>
</li>
<li><font size="3">The reason why I'm created @Macro extension
methods (MEMs)
is simple: I decided to extract code base from MacroGroovy,
because it
can be used outside of "AST nodes generation" context. </font>
</li>
<li><font size="3">MEMs are implemented with Global AST
transformation with
method call scanning, and it costs. But, there are already
almost the same
transformation called AstBuilderTransformation. Most
important, it can
be replaced with @Macro method with backward compatibility.
So, it's
not about new global xform. Just rethinking of old one. </font></li>
</ul>
<br>
<br>
<br>
<br>
<font size="3">On Tue, Oct 7, 2014 at 8:20 PM, Cédric Champeau
<</font><a moz-do-not-send="true"
href="mailto:cedric.champeau@gmail.com" target="_blank"><font
color="blue" size="3"><u>cedric.champeau@gmail.com</u></font></a><font
size="3">>
wrote:</font>
<br>
<font size="3">Hi everyone,<br>
<br>
You may know that we have long been complaining about the
complexity of
AST transformations in Groovy. There are a very powerful tool,
but it is
still a bit complex to handle. In Groovy 2.4, we planned to
integrate work
from Sergei Egorov (@bsideup) that he called "Groovy macros".
Basically the idea is to have a simple way to replace classic
method class
into more complex expressions. In this email, I'll try to
summarize the
project and give some ideas about the orientations we want for
the Groovy
language. In the end, your opinion matters so please feel free
to comment.<br>
<br>
First of all, Sergei actually worked on two "macro" projects.
The first one consists of a "macro" block that can be
illustrated
by this:</font>
<br>
<font color="#000061" face="Source Code Pro" size="2"><b>def </b></font><font
color="#000080" face="Source Code Pro" size="2">someVariable
</font><font face="Source Code Pro" size="2">= </font><font
color="#000061" face="Source Code Pro" size="2"><b>new
</b></font><font face="Source Code Pro" \
size="2">VariableExpression(</font><font
color="#008000" face="Source Code Pro" \
size="2"><b>"someVariable"</b></font><font face="Source Code Pro" size="2">);<br>
<br>
ReturnStatement </font><font color="#000080" face="Source Code
Pro" size="2">result
</font><font face="Source Code Pro" size="2">= macro {<br>
</font><font color="#000061" face="Source Code Pro" size="2"><b>return
new
</b></font><font face="Source Code Pro" \
size="2">NonExistingClass($v{</font><font
color="#000080" face="Source Code Pro" size="2">someVariable</font><font
face="Source Code Pro" size="2">});<br>
}<br>
</font>
<br>
<font size="3">As you can see, it is some kind of "super
AstBuilder"
which is capable of handling variables/expressions from an
external context
thanks to proper escaping with $v. This macro code is primarily
aimed at
being used inside AST transformation themselves, and
dramatically reduce
the amount of code required to generate an AST tree. An
advantage of those
macro blocks is that if you use them in AST transformations,
you're actually
not limited to expressions. You can generate anything, as long
as what
is inside the macro { ... } block is supported by the Groovy
syntax. A
drawback of the current implementation is that it uses a global
AST transformation.
So as soon as you have the macro project on classpath, every
single method
call corresponding to "macro" will be interpreted as a macro
block. There are multiple disadvantages of global AST
transformations.
First of all, they are, as the name says, global, meaning that
they apply
independently on *every* class being compiled by Groovy. This
also means
that the transformation is run even if you know the code you
write is not
using it. In particular, we need to inspect the full AST,
in-depth, to
find potential method calls named "macro" even if there's not
a single one in the code (because you will only know once you
have visited
the full AST). In short, a global AST transformation has a clear
performance
impact, because it is executed independently of the context. For
the macro
stuff, an easy workaround would be to transform the global AST
transformation
into a local one. For example, an AST transformation using the
macro system
could declare it by annotating with @EnableMacros. I think it is
reasonable,
since it is very unlikely that you would use the macro { ... }
stuff in
regular code. The macro block is indeed useful, but in the end,
it is limited
to writing other AST transformations that would be either global
or local.
In short, the current macro { ... } block is useful for AST
transformation
designers, but cannot be used by "regular" Groovy users to
define
new language constructs.<br>
<br>
In answer to that problem, Sergei worked on a second
implementation of
macros named @Macro. The idea is both simple and elegant. Just
like you
can define extension methods in Groovy (see </font><a
moz-do-not-send="true"
href="http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules"
target="_blank"><font color="blue" \
size="3"><u>http://docs.groovy-lang.org/2.3.7/html/documentation/#_extension_modules</u></font></a><font
size="3">),
you can write a macro like this:<br>
</font>
<br>
<font color="#000080" face="Source Code Pro" size="2"><b>public
class </b></font><font face="Source Code Pro" size="2">TestMacroMethods
{<br>
<br>
</font><font color="#808000" face="Source Code Pro" size="2">@Macro<br>
</font><font color="#000080" face="Source Code Pro" size="2"><b>public
static
</b></font><font face="Source Code Pro" size="2">Expression
safe(MacroContext
macroContext, MethodCallExpression callExpression) {<br>
</font><font color="#000080" face="Source Code Pro"
size="2"><b>return
</b></font><font face="Source Code Pro" size="2"><i>ternaryX</i>(<br>
<i>notNullX</i>(callExpression.getObjectExpression()),<br>
callExpression,<br>
<i>constX</i>(</font><font color="#000080"
face="Source Code Pro" size="2"><b>null</b></font><font
face="Source Code Pro" size="2">)<br>
);<br>
}<br>
}</font><font face="Source Code Pro" size="6"><br>
</font>
<br>
<font size="3">and for this to work, TestMacroMethods needs to be
declared
as a regular Groovy extension module. In that case, *any* code
using "safe"
would be transformed, so:<br>
<br>
safe(x.foo()).bar()<br>
<br>
will be expanded *at compile time* into x.foo?x.foo().bar():null<br>
<br>
A more interesting example with pattern matching can be found
here: </font><a moz-do-not-send="true"
href="https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java"
target="_blank"><font color="blue" \
size="3"><u>https://github.com/bsideup/groovy-pattern-match/blob/master/src/main/java/ru/trylogic/groovy/pattern/PatternMatchingMacroMethods.java</u></font></a><font
size="3"><br>
<br>
An important thing to understand is that the @Macro annotation
is *not*
an AST transformation. Instead, it's a marker annotation which
is looked
up at compile time, for each method call. So for each method
call of the
AST, we try to find if an extension method node of the same name
exists,
is annotated with @Macro and takes MacroContext as the first
argument and
in that case, the original method call is transformed thanks to
the extension
method at compile time. The code of the macro itself is regular
AST transformation
code. It does *not* use the macro stuff from the first
implementation,
hence doesn't simplify writing xforms. On the other hand, it
greatly simplifies
the availability of transforms by making them writable as simple
extension
methods, without the need of ceremony (annotations). It is
actually very
cool, but it comes at a price. Performance wise, it is still a
global AST
transformation, but worse, for each and every call, it implies
finding
an extension method node. It can (and will) cost a lot, but we
can improve
the situation by introducing specific caches. Moreover, it also
implies
that the sole fact of adding a macro "jar" on classpath could
potentially affect the semantics of your program: if a method
call in your
code matches the name of a macro method call, then it would be
applied
at compile time. Of course, one could argue that it is already
the case
for extension modules, but the risk is lower: for extension
modules, the
only cases of conflicts is when the receiver of the message
matches the
class of the extension module. For @Macro, any method call on
"implicit
this" would be matched. This draws the point of whether the
@Macro
stuff should also be combined with a @UseMacro local AST
transformation,
in order to avoid the problem of the global one.<br>
<br>
If we do, then definitely, the performance issue is not one
anymore, because
only marked code would be transformed. On the other hand, we
introduce
ceremony again, which would mean that we loose the benefit of
extension
methods being transparently visible. In the case of the pattern
matching
stuff, this would mean that you would have to explicitly
annotate your
code to enable the feature. Is it a problem? I'm not sure
actually. Also
it's worth noting that the global AST transformation issue is
less of a
problem if you have lots of macros on classpath, because a
single transformation
would apply them all in a single pass.<br>
<br>
Last but not least, my feeling is that what we need is something
in between
the first macro implementation and the second one. In
particular, I would
like to be able to write the @Macro method body using those
macro { ...
} blocks. It makes a lot of sense to me. Next, I wouldn't like
to be limited
to expressions. I think a macro should be able to produce any
AST node.
This implies expressions, but also statements or even full
methods.<br>
<br>
I gave an example a little contrived, I admit, to Sergei, which
is, imagine
that I want to generate two methods with the same body, but
accepting two
different argument types. Then I could write a macro that
generates the
method:<br>
<br>
@Macro MethodNode createMultiply(MacroContext ctx, ClassNode
argType) {<br>
macro {<br>
_argType_ multByTwo(_argType_ x) {
2 }<br>
}<br>
}<br>
<br>
Then in a class I could write:<br>
<br>
class Calculator {<br>
createMultiply int<br>
createMultiply double<br>
}<br>
<br>
Of course, this wouldn't compile because the grammar wouldn't
allow defining
a method in a closure (in the macro block), and it would not
recognize
the createMultiply calls directly in the class body, but I kind
of like
the idea of a macro system that just allows expanding and
reasoning at
the AST level anywhere, because it lets us create new language
constructs.<br>
<br>
In any case, let us know what you think, what you expect from a
macro system
in Groovy. We have very good starting points, let's make it rock
solid
:-)</font>
<br>
<tt><font color="#8f8f8f" size="3">-- <br>
Cédric Champeau<br>
SpringSource - Pivotal<br>
</font></tt><a moz-do-not-send="true"
href="http://twitter.com/CedricChampeau" target="_blank"><tt><font
color="blue" \
size="3"><u>http://twitter.com/CedricChampeau</u></font></tt></a><tt><font \
color="#8f8f8f" size="3"><br> </font></tt><a moz-do-not-send="true"
href="http://melix.github.io/blog" target="_blank"><tt><font
color="blue" \
size="3"><u>http://melix.github.io/blog</u></font></tt></a><tt><font color="#8f8f8f" \
size="3"><br> </font></tt><a moz-do-not-send="true" href="http://spring.io/"
target="_blank"><tt><font color="blue" \
size="3"><u>http://spring.io/</u></font></tt></a><tt><font color="#8f8f8f" size="3">
</font></tt><a moz-do-not-send="true"
href="http://www.gopivotal.com/" target="_blank"><tt><font
color="blue" \
size="3"><u>http://www.gopivotal.com/</u></font></tt></a><tt><font color="#8f8f8f" \
size="3"><br> </font></tt>
<br>
<font size="3"><br>
</font>
<br>
<br>
<font size="3">-- </font>
<br>
<font size="3">Best regards, </font>
<br>
<font size="3">Sergei Egorov</font>
<br>
<font size="3"><br>
</font>
<br>
<tt><font size="3">-- <br>
Cédric Champeau<br>
SpringSource - Pivotal<br>
</font></tt><a moz-do-not-send="true"
href="http://twitter.com/CedricChampeau"><tt><font color="blue"
size="3"><u>http://twitter.com/CedricChampeau</u></font></tt></a><tt><font
size="3"><br>
</font></tt><a moz-do-not-send="true"
href="http://melix.github.io/blog"><tt><font color="blue"
size="3"><u>http://melix.github.io/blog</u></font></tt></a><tt><font
size="3"><br>
</font></tt><a moz-do-not-send="true" href="http://spring.io/"><tt><font
color="blue" size="3"><u>http://spring.io/</u></font></tt></a><tt><font
size="3">
</font></tt><a moz-do-not-send="true"
href="http://www.gopivotal.com/"><tt><font color="blue" \
size="3"><u>http://www.gopivotal.com/</u></font></tt></a><tt><font size="3"><br>
</font></tt>
<br>
<font face="sans-serif" size="2"><br>
<br>
</font><font face="Times New Roman" size="3"><br>
NOTICE <i>from Ab Initio: This email (including any
attachments) may contain
information that is subject to confidentiality obligations or
is legally
privileged, and sender does not waive confidentiality or
privilege. If
received in error, please notify the sender, delete this
email, and make
no further use, disclosure, or distribution. </i></font>
</blockquote>
<br>
<br>
<pre class="moz-signature" cols="72">--
Cédric Champeau
SpringSource - Pivotal
<a class="moz-txt-link-freetext" \
href="http://twitter.com/CedricChampeau">http://twitter.com/CedricChampeau</a> <a \
class="moz-txt-link-freetext" \
href="http://melix.github.io/blog">http://melix.github.io/blog</a> <a \
class="moz-txt-link-freetext" href="http://spring.io/">http://spring.io/</a> <a \
class="moz-txt-link-freetext" \
href="http://www.gopivotal.com/">http://www.gopivotal.com/</a> </pre>
</body>
</html>
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic