You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by mariogarcia <gi...@git.apache.org> on 2016/10/06 09:00:08 UTC

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

GitHub user mariogarcia opened a pull request:

    https://github.com/apache/groovy/pull/439

    WIP Add groovy-macro docs

    **WIP**
    
    This is a **Working In Progress** because:
    
    **Failing Tests**
    
    There are 2 tests that started failing once I added the `groovy-macro` dependencies in specs:
    
    - `org.codehaus.groovy.classgen.asm.sc.bugs.Groovy7316Bug > testTypeCheckingBypassUsingExplicitTypeHint`
    
    - `org.codehaus.groovy.classgen.asm.sc.bugs.Groovy6757Bug > testExplicitTypeHint`
    
    **Questions**
    
    - Apart from that, there're a lot of licenses added I don't know where they came from. Should I exclude them from the PR ?
    
    **Feedback**
    
    Of course, need to know if the docs are ok, or not. Even if the PR is rejected I'd be happy if at least part of them help to the macros documentation.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/mariogarcia/groovy documentation_ast

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/groovy/pull/439.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #439
    
----
commit f496bb17d9735e7ad598307695581d6ef4d97270
Author: Mario Garcia <ma...@gmail.com>
Date:   2016-08-13T11:03:30Z

    WIP Add groovy-macro docs

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523862
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523004
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512007
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    --- End diff --
    
    looks like with the use of macros. => simplifies with the use of macros:


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82519129
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    +
    +First we create the `@Joking` annotation that only can be applied to methods:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingannotation,indent=0]
    +----
    +
    +Then the transformation, that only applies an instance of `org.codehaus.groovy.ast.ClassCodeExpressionTransformer`
    +to all the expressions within the method code block.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingtransformation,indent=0]
    +----
    +<1> Get the method's code statement and apply the expression transformer
    +
    +And then is when the **ASTMatcher** is used to apply the transformation only to those expressions matching
    --- End diff --
    
    And then => And this


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523161
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    +**getMethodCount()** and **getFieldCount()** which return how many methods and fields has the class respectively. Here
    +is the marker annotation.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticsannotation,indent=0]
    +----
    +
    +And the AST transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticstransformation,indent=0]
    +----
    +
    +<1> Creating a template class
    +<2> Adding template class methods to the annotated class
    +<3> Passing the reference class
    +<4> Extracting reference class method count value expression
    +<5> Extracting reference class field count value expression
    +<6> Building the **getMethodCount()** method using reference's method count value expression
    +<7> Building the **getFieldCount()** method using reference's field count value expression
    +
    +Basically we've created the **Statistics** class as a template to avoid writing low level AST API, then we
    +copied methods created in the template class to their final destination.
    +
    +NOTE: Types inside the `MacroClass` implementation should be resolved inside, that's why I had to write
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82511934
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    --- End diff --
    
    I think 'Abstract Syntax Tree' is more common than _source_ tree.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512035
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    --- End diff --
    
    this signatures => these signatures


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523891
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    +
    +First we create the `@Joking` annotation that only can be applied to methods:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingannotation,indent=0]
    +----
    +
    +Then the transformation, that only applies an instance of `org.codehaus.groovy.ast.ClassCodeExpressionTransformer`
    +to all the expressions within the method code block.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingtransformation,indent=0]
    +----
    +<1> Get the method's code statement and apply the expression transformer
    +
    +And then is when the **ASTMatcher** is used to apply the transformation only to those expressions matching
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512060
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    --- End diff --
    
    in any statement => in a statement


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512057
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    --- End diff --
    
    and the expression returned => and returning the expression


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522870
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82528217
  
    --- Diff: build.gradle ---
    @@ -238,6 +239,7 @@ dependencies {
     
         testCompile project(':groovy-ant')
         testCompile project(':groovy-test')
    +    testCompile project(':groovy-macro')
    --- End diff --
    
    @paulk-asert let me know if you'll find anything!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523102
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    +**getMethodCount()** and **getFieldCount()** which return how many methods and fields has the class respectively. Here
    +is the marker annotation.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticsannotation,indent=0]
    +----
    +
    +And the AST transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticstransformation,indent=0]
    +----
    +
    +<1> Creating a template class
    +<2> Adding template class methods to the annotated class
    +<3> Passing the reference class
    +<4> Extracting reference class method count value expression
    +<5> Extracting reference class field count value expression
    +<6> Building the **getMethodCount()** method using reference's method count value expression
    +<7> Building the **getFieldCount()** method using reference's field count value expression
    +
    +Basically we've created the **Statistics** class as a template to avoid writing low level AST API, then we
    +copied methods created in the template class to their final destination.
    +
    +NOTE: Types inside the `MacroClass` implementation should be resolved inside, that's why I had to write
    +`java.lang.Integer` instead of simply writing `Integer`.
    +
    +IMPORTANT: Notice that we'are using `@CompileDynamic`. That's because the way we use `MacroClass` is like we
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82380664
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherTestingTest.groovy ---
    @@ -0,0 +1,123 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileDynamic
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassNode
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.Parameter
    +import org.codehaus.groovy.ast.expr.BinaryExpression
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.ast.stmt.BlockStatement
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.macro.transform.MacroClass
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE
    +import static org.codehaus.groovy.ast.tools.GeneralUtils.*
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherTestingTest extends GroovyTestCase {
    +
    +    // tag::testexpression[]
    +    void testTestingSumExpression() {
    +        use(ASTMatcher) {                 // <1>
    +            TwiceASTTransformation sample = new TwiceASTTransformation()
    +            Expression referenceNode = macro {
    +                a + a                     // <2>
    +            }.withConstraints {           // <3>
    +                placeholder 'a'           // <4>
    +            }
    +
    +            assert sample
    +                .sumExpression
    +                .matches(referenceNode)   // <5>
    +        }
    +    }
    +    // end::testexpression[]
    +
    +    // tag::executiontesting[]
    +    void testASTBehavior() {
    +        assertScript '''
    +        package metaprogramming
    +
    +        @Twice
    +        class AAA {
    +
    +        }
    +
    +        assert new AAA().giveMeTwo(1) == 2
    +        '''
    +    }
    +    // end::executiontesting[]
    +}
    +
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.TYPE])
    +@GroovyASTTransformationClass(["metaprogramming.TwiceASTTransformation"])
    +@interface Twice { }
    +
    +// tag::twiceasttransformation[]
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class TwiceASTTransformation extends AbstractASTTransformation {
    +
    +    static final String VAR_X = 'x'
    +
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        ClassNode classNode = (ClassNode) nodes[1]
    +        MethodNode giveMeTwo = getTemplateClass(sumExpression)
    +            .methods
    +            .find { it.name == 'giveMeTwo' }
    --- End diff --
    
    can be replaced with `getTemplateClass(sumExpression).getDeclaredMethods('giveMeTwo').first()`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512190
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    --- End diff --
    
    such a method, a field... ? => such as a method, a field, and so on?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523855
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82379792
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    +        this.sourceUnit = sourceUnit1
    +    }
    +
    +    @Override
    +    Expression transform(Expression exp) {
    --- End diff --
    
    this is just.... brilliant :D awesome example! :+1:


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512201
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    +**getMethodCount()** and **getFieldCount()** which return how many methods and fields has the class respectively. Here
    --- End diff --
    
    has the class => within the class


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523575
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit) {
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82503510
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    +        this.sourceUnit = sourceUnit1
    +    }
    +
    +    @Override
    +    Expression transform(Expression exp) {
    +        Expression ref = macro { 1 + 1 }     // <1>
    +
    +        if (ASTMatcher.matches(ref, exp)) {  // <2>
    --- End diff --
    
    sure, nothing to do with the documentation, just wanted to mention it :)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82503484
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherTestingTest.groovy ---
    @@ -0,0 +1,123 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileDynamic
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassNode
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.Parameter
    +import org.codehaus.groovy.ast.expr.BinaryExpression
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.ast.stmt.BlockStatement
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.macro.transform.MacroClass
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE
    +import static org.codehaus.groovy.ast.tools.GeneralUtils.*
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherTestingTest extends GroovyTestCase {
    +
    +    // tag::testexpression[]
    +    void testTestingSumExpression() {
    +        use(ASTMatcher) {                 // <1>
    +            TwiceASTTransformation sample = new TwiceASTTransformation()
    +            Expression referenceNode = macro {
    +                a + a                     // <2>
    +            }.withConstraints {           // <3>
    +                placeholder 'a'           // <4>
    +            }
    +
    +            assert sample
    +                .sumExpression
    +                .matches(referenceNode)   // <5>
    +        }
    +    }
    +    // end::testexpression[]
    +
    +    // tag::executiontesting[]
    +    void testASTBehavior() {
    +        assertScript '''
    +        package metaprogramming
    +
    +        @Twice
    +        class AAA {
    +
    +        }
    +
    +        assert new AAA().giveMeTwo(1) == 2
    +        '''
    +    }
    +    // end::executiontesting[]
    +}
    +
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.TYPE])
    +@GroovyASTTransformationClass(["metaprogramming.TwiceASTTransformation"])
    +@interface Twice { }
    +
    +// tag::twiceasttransformation[]
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class TwiceASTTransformation extends AbstractASTTransformation {
    +
    +    static final String VAR_X = 'x'
    +
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        ClassNode classNode = (ClassNode) nodes[1]
    +        MethodNode giveMeTwo = getTemplateClass(sumExpression)
    +            .methods
    +            .find { it.name == 'giveMeTwo' }
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512068
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    --- End diff --
    
    the MD5 the value => the MD5 value


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522959
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523879
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    +**getMethodCount()** and **getFieldCount()** which return how many methods and fields has the class respectively. Here
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82519232
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    --- End diff --
    
    I'd probably replace all of the `Created by dev on <_date_>` lines with a one line description of the test or just remove the comment.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523894
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523878
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523893
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    +
    +First we create the `@Joking` annotation that only can be applied to methods:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingannotation,indent=0]
    +----
    +
    +Then the transformation, that only applies an instance of `org.codehaus.groovy.ast.ClassCodeExpressionTransformer`
    +to all the expressions within the method code block.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingtransformation,indent=0]
    +----
    +<1> Get the method's code statement and apply the expression transformer
    +
    +And then is when the **ASTMatcher** is used to apply the transformation only to those expressions matching
    +the expression `1 + 1`.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingexpressiontransformer,indent=0]
    +----
    +<1> Builds the expression used as reference pattern
    +<2> Checks the current expression evaluated matches the reference expression
    +<3> If it matches then replaces the current expression with the expression built with `macro`
    +
    +Then you could test the implementation as follows:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingexample,indent=0]
    +----
    +
    +**Unit testing AST transforms**
    +
    +Normally we test AST transformations just checking that the final use of the transformation does what we expect. But
    +it would be great if we could have an easy way to check, for example, that the nodes the transformation adds are what
    +we expected from the beginning.
    +
    +The following transformation adds a new method `giveMeTwo` to an annotated class.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherTestingTest.groovy[tags=twiceasttransformation,indent=0]
    +----
    +<1> Adding the method to the annotated class
    +<2> Building a binary expression. The binary expression uses the same variable expression in both
    +sides of the `+` token (check `varX` method at **org.codehaus.groovy.ast.tool.GeneralUtils**).
    +<3> Builds a new **ClassNode** with a method called `giveMeTwo` which returns the result of an expression
    +passed as parameter.
    +
    +Now instead of creating a test executing the transformation over a given sample code. I would like to check that
    +the construction of the binary expression is donde properly:
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512182
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    --- End diff --
    
    earlier the => earlier, the


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82532133
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherTestingTest.groovy ---
    @@ -0,0 +1,123 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileDynamic
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassNode
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.Parameter
    +import org.codehaus.groovy.ast.expr.BinaryExpression
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.ast.stmt.BlockStatement
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.macro.transform.MacroClass
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE
    +import static org.codehaus.groovy.ast.tools.GeneralUtils.*
    +
    +/**
    + * Created by dev on 6/30/16.
    --- End diff --
    
    still 4 of these left


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82502595
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherTestingTest.groovy ---
    @@ -0,0 +1,123 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileDynamic
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassNode
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.Parameter
    +import org.codehaus.groovy.ast.expr.BinaryExpression
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.ast.stmt.BlockStatement
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.macro.transform.MacroClass
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE
    +import static org.codehaus.groovy.ast.tools.GeneralUtils.*
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherTestingTest extends GroovyTestCase {
    +
    +    // tag::testexpression[]
    +    void testTestingSumExpression() {
    +        use(ASTMatcher) {                 // <1>
    +            TwiceASTTransformation sample = new TwiceASTTransformation()
    +            Expression referenceNode = macro {
    +                a + a                     // <2>
    +            }.withConstraints {           // <3>
    +                placeholder 'a'           // <4>
    +            }
    +
    +            assert sample
    +                .sumExpression
    +                .matches(referenceNode)   // <5>
    +        }
    +    }
    +    // end::testexpression[]
    +
    +    // tag::executiontesting[]
    +    void testASTBehavior() {
    +        assertScript '''
    +        package metaprogramming
    +
    +        @Twice
    +        class AAA {
    +
    +        }
    +
    +        assert new AAA().giveMeTwo(1) == 2
    +        '''
    +    }
    +    // end::executiontesting[]
    +}
    +
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.TYPE])
    +@GroovyASTTransformationClass(["metaprogramming.TwiceASTTransformation"])
    +@interface Twice { }
    +
    +// tag::twiceasttransformation[]
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class TwiceASTTransformation extends AbstractASTTransformation {
    +
    +    static final String VAR_X = 'x'
    +
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        ClassNode classNode = (ClassNode) nodes[1]
    +        MethodNode giveMeTwo = getTemplateClass(sumExpression)
    +            .methods
    +            .find { it.name == 'giveMeTwo' }
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523865
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523848
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523189
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    +
    +First we create the `@Joking` annotation that only can be applied to methods:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingannotation,indent=0]
    +----
    +
    +Then the transformation, that only applies an instance of `org.codehaus.groovy.ast.ClassCodeExpressionTransformer`
    +to all the expressions within the method code block.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy[tags=jokingtransformation,indent=0]
    +----
    +<1> Get the method's code statement and apply the expression transformer
    +
    +And then is when the **ASTMatcher** is used to apply the transformation only to those expressions matching
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512083
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    --- End diff --
    
    whether add => add any


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523131
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522904
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82511988
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    --- End diff --
    
    it's => is


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: Add groovy-macro docs

Posted by asfgit <gi...@git.apache.org>.
Github user asfgit closed the pull request at:

    https://github.com/apache/groovy/pull/439


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512093
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    --- End diff --
    
    at SEMANTIC_ANALYSIS => at the SEMANTIC_ANALYSIS phase


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522744
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82519117
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit) {
    --- End diff --
    
    The name `ConvertToOne` is in some sense irrelevant but perhaps `ConvertToThree` or `ConvertOnePlusOneTo3` would be better?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523850
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512017
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    --- End diff --
    
    Although `macro` => Although the `macro`
    create an => create a


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523847
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523537
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82519042
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    --- End diff --
    
    I => we


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523854
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82502579
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    +        this.sourceUnit = sourceUnit1
    +    }
    +
    +    @Override
    +    Expression transform(Expression exp) {
    +        Expression ref = macro { 1 + 1 }     // <1>
    +
    +        if (ASTMatcher.matches(ref, exp)) {  // <2>
    --- End diff --
    
    True. But why not simply overloading `matches` to receive a `Closure` ?
    
    `exp.matches { 1 + 1 }`


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522830
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522915
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523026
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by jwagenleitner <gi...@git.apache.org>.
Github user jwagenleitner commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r83145776
  
    --- Diff: build.gradle ---
    @@ -238,6 +239,7 @@ dependencies {
     
         testCompile project(':groovy-ant')
         testCompile project(':groovy-test')
    +    testCompile project(':groovy-macro')
    --- End diff --
    
    PR #441 has been merged.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523226
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    --- End diff --
    
    :+1: I'll remove the comment


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82379710
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    --- End diff --
    
    Minor cosmetics: `sourceUnit1` -> `sourceUnit` ? 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82511972
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    --- End diff --
    
    lets => let's (by 2 cases)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523839
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82512196
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    --- End diff --
    
    class it => class, it


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523852
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523856
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82532117
  
    --- Diff: src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy ---
    @@ -0,0 +1,96 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import org.codehaus.groovy.ast.*
    +import org.codehaus.groovy.ast.expr.VariableExpression
    +import org.codehaus.groovy.ast.stmt.BlockStatement
    +import org.codehaus.groovy.ast.tools.GeneralUtils
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + *
    + */
    --- End diff --
    
    can go too


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82503479
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by bsideup <gi...@git.apache.org>.
Github user bsideup commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82380154
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit1) {
    +        this.sourceUnit = sourceUnit1
    +    }
    +
    +    @Override
    +    Expression transform(Expression exp) {
    +        Expression ref = macro { 1 + 1 }     // <1>
    +
    +        if (ASTMatcher.matches(ref, exp)) {  // <2>
    --- End diff --
    
    Now I feel maybe we should implement `exp.matches(macro { 1 + 1 })`, or even `exp.matchesMacro { 1 + 1 }`, feels a bit more groovier :)


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523881
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    +**getMethodCount()** and **getFieldCount()** which return how many methods and fields has the class respectively. Here
    +is the marker annotation.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticsannotation,indent=0]
    +----
    +
    +And the AST transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroClassTest.groovy[tags=statisticstransformation,indent=0]
    +----
    +
    +<1> Creating a template class
    +<2> Adding template class methods to the annotated class
    +<3> Passing the reference class
    +<4> Extracting reference class method count value expression
    +<5> Extracting reference class field count value expression
    +<6> Building the **getMethodCount()** method using reference's method count value expression
    +<7> Building the **getFieldCount()** method using reference's field count value expression
    +
    +Basically we've created the **Statistics** class as a template to avoid writing low level AST API, then we
    +copied methods created in the template class to their final destination.
    +
    +NOTE: Types inside the `MacroClass` implementation should be resolved inside, that's why I had to write
    +`java.lang.Integer` instead of simply writing `Integer`.
    +
    +IMPORTANT: Notice that we'are using `@CompileDynamic`. That's because the way we use `MacroClass` is like we
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523888
  
    --- Diff: src/spec/test/metaprogramming/ASTMatcherFilteringTest.groovy ---
    @@ -0,0 +1,103 @@
    +/*
    + *  Licensed to the Apache Software Foundation (ASF) under one
    + *  or more contributor license agreements.  See the NOTICE file
    + *  distributed with this work for additional information
    + *  regarding copyright ownership.  The ASF licenses this file
    + *  to you under the Apache License, Version 2.0 (the
    + *  "License"); you may not use this file except in compliance
    + *  with the License.  You may obtain a copy of the License at
    + *
    + *    http://www.apache.org/licenses/LICENSE-2.0
    + *
    + *  Unless required by applicable law or agreed to in writing,
    + *  software distributed under the License is distributed on an
    + *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    + *  KIND, either express or implied.  See the License for the
    + *  specific language governing permissions and limitations
    + *  under the License.
    + */
    +
    +package metaprogramming
    +
    +import groovy.transform.CompileStatic
    +import org.codehaus.groovy.ast.ASTNode
    +import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
    +import org.codehaus.groovy.ast.MethodNode
    +import org.codehaus.groovy.ast.expr.Expression
    +import org.codehaus.groovy.control.CompilePhase
    +import org.codehaus.groovy.control.SourceUnit
    +import org.codehaus.groovy.macro.matcher.ASTMatcher
    +import org.codehaus.groovy.transform.AbstractASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformation
    +import org.codehaus.groovy.transform.GroovyASTTransformationClass
    +
    +import java.lang.annotation.ElementType
    +import java.lang.annotation.Retention
    +import java.lang.annotation.RetentionPolicy
    +import java.lang.annotation.Target
    +
    +/**
    + * Created by dev on 6/30/16.
    + */
    +class ASTMatcherFilteringTest extends GroovyTestCase {
    +
    +    void testFilteringNodes() {
    +        assertScript '''
    +        // tag::jokingexample[]
    +        package metaprogramming
    +
    +        class Something {
    +            @Joking
    +            Integer getResult() {
    +                return 1 + 1
    +            }
    +        }
    +
    +        assert new Something().result == 3
    +        // end::jokingexample[]
    +        '''
    +    }
    +}
    +
    +// tag::jokingannotation[]
    +@Retention(RetentionPolicy.SOURCE)
    +@Target([ElementType.METHOD])
    +@GroovyASTTransformationClass(["metaprogramming.JokingASTTransformation"])
    +@interface Joking { }
    +// end::jokingannotation[]
    +
    +// tag::jokingtransformation[]
    +@CompileStatic
    +@GroovyASTTransformation(phase = CompilePhase.INSTRUCTION_SELECTION)
    +class JokingASTTransformation extends AbstractASTTransformation {
    +    @Override
    +    void visit(ASTNode[] nodes, SourceUnit source) {
    +        MethodNode methodNode = (MethodNode) nodes[1]
    +
    +        methodNode
    +            .getCode()
    +            .visit(new ConvertToOne(source))  // <1>
    +    }
    +}
    +// end::jokingtransformation[]
    +
    +// tag::jokingexpressiontransformer[]
    +class ConvertToOne extends ClassCodeExpressionTransformer {
    +    SourceUnit sourceUnit
    +
    +    ConvertToOne(SourceUnit sourceUnit) {
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523885
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    +transformation has built the expected AST node.
    +
    +**Filtering nodes**
    +
    +For instance if you would like to apply a given transformation only to a specific set of AST nodes, you could
    +use **ASTMatcher** to filter these nodes. The following example shows how to transform a given expression to
    +another. Using **ASTMatcher** it looks for a specific expression `1 + 1` and it transforms it to `3`. That's why
    +I called it the `@Joking` example.
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523842
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522995
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82511943
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    --- End diff --
    
    having translate => having to translate


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522775
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523074
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    +
    +`org.codehaus.groovy.macro.transform.MacroClass` can be used to create **classes** (ClassNode instances) in our
    +transformations the same way we created statements and expressions with the `macro` method before.
    +
    +The next example is a local transformation `@Statistics`. When applied to a given class it will add two methods
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82522972
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523034
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5annotation,indent=0]
    +----
    +
    +And the transformation:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroVariableSubstitutionTest.groovy[tags=md5transformation,indent=0]
    +----
    +
    +<1> We need a reference to a variable expression
    +<2> If using a class outside the standard packages we should whether add needed imports or use the qualified name. When
    +using the qualified named of a given static method you need to make sure it's resolved in the proper compile phase. In
    +this particular case we're instructing the macro to resolve it at SEMANTIC_ANALYSIS, which is the first compile phase
    +with type information.
    +<3> In order to substitute any `expression` inside the macro we need to use the `$v` method. `$v` receives a closure as an
    +argument, and the closure is only allowed to substitute expressions, meaning classes inheriting
    +`org.codehaus.groovy.ast.expr.Expression`.
    +
    +===== MacroClass
    +
    +As we mentioned earlier the `macro` method is only capable of producing `statements` and `expressions`. But what if we
    +want to produce other types of nodes, such a method, a field... ?
    --- End diff --
    
    :+1: 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by mariogarcia <gi...@git.apache.org>.
Github user mariogarcia commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82523858
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2829,6 +2829,153 @@ to use the Groovy Console, in particular the AST browser tool, to gain knowledge
     resource for learning is the https://github.com/apache/groovy/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
     test suite.
     
    +==== Macros
    +
    +===== Introduction
    +
    +Until version 2.5.0, when developing AST transformations, developers should have a deep knowledge about how the AST
    +(Abstract source tree) was built by the compiler in order to know how to add new expressions or statements during
    +compile time.
    +
    +Although the use of `org.codehaus.groovy.ast.tool.GeneralUtils` static methods could mitigate the burden of creating
    +expressions and statements, it's still a low-level way of writing those AST nodes directly.
    +We needed something to abstract us from writing the AST directly and that's exactly what Groovy macros were made for.
    +They allow you to add code during compile time directly, without having translate the code you had in mind to the
    +`org.codehaus.groovy.ast.*` node related classes.
    +
    +===== Statements and expressions
    +
    +Lets see an example, lets create a local AST transformation. `@AddMessageMethod`. When applied to a given class it
    +will add a new method called `getMessage` to that class. The method will return "42". The annotation it's pretty
    +straight forward:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodannotation,indent=0]
    +----
    +
    +How would look like the AST transformation without the use of a macro:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=addmethodtransformationwithoutmacro,indent=0]
    +----
    +
    +<1> Create a return statement
    +<2> Create a constant expression "42"
    +<3> Adding the code to the new method
    +<4> Adding the new method to the annotated class
    +
    +If you're not used to the AST API, that definitely doesn't look like the code you had in mind. Now look how the
    +previous code looks like with the use of macros.
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroStatementTest.groovy[tags=basicWithMacro,indent=0]
    +----
    +
    +<1> Much simpler. You wanted to add a return statement that returned "42" and that's exactly what you can read inside
    +the `macro` utility method. Your plain code will be translated for you to a `org.codehaus.groovy.ast.stmt.ReturnStatement`
    +<2> Adding the return statement to the new method
    +<3> Adding the new code to the annotated class
    +
    +Although `macro` method is used in this example to create an **statement** the `macro` method could also be used to create
    +**expressions** as well, it depends on which `macro` signature you use:
    +
    +- `macro(Closure)`: Create a given statement with the code inside the closure.
    +- `macro(Boolean,Closure)`: if **true** wrap expressions inside the closure inside an statement, if **false** then return
    +an expression
    +- `macro(CompilePhase, Closure)`: Create a given statement with the code inside the closure in a specific compile phase
    +- `macro(CompilePhase, Boolean, Closure)`: Create an statement or an expression (true == statement, false == expression)
    +in a specific compilation phase.
    +
    +NOTE: All this signatures can be found at `org.codehaus.groovy.macro.runtime.MacroGroovyMethods`
    +
    +Sometimes we could be only interested in creating a given expression, not the whole statement, in order to do that we
    +should use any of the `macro` invocations with a boolean parameter:
    +
    +[source,groovy]
    +----
    +include::{projectdir}/src/spec/test/metaprogramming/MacroExpressionTest.groovy[tags=addgettwotransformation,indent=0]
    +----
    +
    +<1> We're telling macro not to wrap the expression in any statement, we're only interested in the expression
    +<2> Assigning the expression
    +<3> Creating a `ReturnStatement` using a method from `GeneralUtils` and the expression returned
    +<4> Adding the code to the new method
    +<5> Adding the method to the class
    +
    +===== Variable substitution
    +
    +Macros are great but we can't create anything useful or reusable if our macros couldn't receive parameters or resolve
    +surrounding variables.
    +
    +In the following example we're creating an AST transformation `@MD5` that when applied to a given String field will
    +add a method returning the MD5 the value of that field.
    --- End diff --
    
    Changed!


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] groovy pull request #439: WIP Add groovy-macro docs

Posted by paulk-asert <gi...@git.apache.org>.
Github user paulk-asert commented on a diff in the pull request:

    https://github.com/apache/groovy/pull/439#discussion_r82518998
  
    --- Diff: src/spec/doc/core-metaprogramming.adoc ---
    @@ -2868,6 +3015,90 @@ The difference is that when you use `assertScript`, the code in the `assertScrip
     unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
     the breakpoint is going to be hit.
     
    +===== ASTMatcher
    +
    +Sometimes you may want to make assertions over AST nodes whether to filter those nodes, or to make sure a given
    --- End diff --
    
    nodes whether to filter those nodes => nodes; perhaps to filter the nodes


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---