Metadata
Number: |
GEP-2 |
Title: |
AST Builder Support |
Version: |
1 |
Type: |
Feature |
Target: |
1.7 |
Status: |
Draft |
Leader: |
|
Created: |
2009-04-01 |
Last modification: |
2009-04-01 |
Abstract
Groovy 1.6 introduced the ability to perform local and global AST (Abstract Syntax Tree) transformations, allowing users to read and modify the AST of Groovy code as it is being compiled. Reading information in the AST is relatively easy in Groovy. The core library provides a strongly typed visitor called GroovyCodeVisitor. Nodes can be read and modified using the API provided through the subtypes of ASTNode. Writing new AST nodes is not as simple. The AST generated from source is not always obvious, and using constructor calls to generate trees of nodes can be verbose. This GEP proposes an ASTBuilder object that allows users to easily create AST.
The ASTBuilder object allows AST to be created from Strings containing Groovy source code, from a closure containing Groovy source, and from a closure containing an AST creation DSL.
Approach
ASTNode from String
The simplest approach to an AST Builder is an API that takes a String and returns ASTNode.
- phase property tells the builder from which phase to return AST
- returnScriptBodyOnly property tells the builder to discard any generated top level ClassNode elements
- source property is the String to use as input
The above example produces the following AST:
Issues
- Is there a logical default on which CompilePhase is used? Providing a default clean up the API for the common case.
- Compiling a code snippet typically results in the meaningful AST being wrapped in 2 levels of BlockStatement. Should we provide a way to discard the top level BlockStatement? A way to discard both? Manually discarding the topmost BlockStatement would be repetitive but not unbearable.
- Compiling a code snippet typically results in a Script subclass being generated. Should we provide a way to discard this? A "returnScriptBodyOnly" property on the builder could be used to discard the Script ClassNode. Supporting this property would mean that build() sometimes returns an ASTNode and sometimes returns a List<ASTNode>. Are covariant return types acceptable?
- Is some sort of AST Template needed? Consider the following example:
ASTNode from Code Block
ASTNode from psuedo-specification
Alternatives
Template Haskell and Boo provide a special syntax for AST building statements. Quasi-quote (or Oxford quotes) can be used to trigger an AST building operation:
Those languages also supply a splice operator $(...) to turn AST back into code.
References
Mailing-list discussions
JIRA issues
- Pending
Useful links
- Boo Meta Methods
- Template Haskell in Wikipedia
- Template Haskell Home Page
- "First Stab at Template Haskell" Blog Post
Reference Implementation
Pending...
