Что сломается, когда я заменю все ExpressionStatements во время пользовательской компиляции? - PullRequest
0 голосов
/ 19 октября 2018

Для DSL, над которым я работаю, я планирую преобразовать все верхние уровни ExpressionStatement s в MethodCallExpression.Например, я хочу, чтобы пользователь DSL мог просто что-то печатать в кавычках, а DSL будет делать с ним что-то общее, общее в домене.

Я написал небольшой тест (ниже), которыйпреобразует ExpressionStatement с в println MethodCallExpression с, и результат выглядит приятным - он не печатает никаких строк, которые я бы ожидал напечатать, и не мешает возвращать строки из методов, замыканий и т. д.

Но что еще я мог сломать, что я не проверяю?

import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.control.customizers.CompilationCustomizer 
import org.codehaus.groovy.classgen.GeneratorContext
import org.codehaus.groovy.ast.ClassNode
import org.codehaus.groovy.control.CompilerConfiguration

import org.codehaus.groovy.ast.expr.VariableExpression                          
import org.codehaus.groovy.ast.expr.MethodCallExpression                          
import org.codehaus.groovy.ast.expr.ArgumentListExpression                          
import org.codehaus.groovy.ast.stmt.ExpressionStatement 

class myTransform extends CompilationCustomizer {

    public myTransform(CompilePhase p) { super(p) }

    public void call (SourceUnit source, GeneratorContext context, ClassNode classNode) {

        def statements = source.getAST().classes[0].methods[1].code.statements

        statements.eachWithIndex { stmt, n ->
            try {
                if (stmt in ExpressionStatement && stmt.expression.type.typeClass in [String, GString]) {
                    statements[n] = new ExpressionStatement(
                        new MethodCallExpression(
                            new VariableExpression("this"),
                            "println",
                            new ArgumentListExpression([stmt.expression])
                        )
                    )
                }
            } catch (Error e) { }
        } 

    }
}   


new GroovyShell(
    getClass().classLoader, 
    new CompilerConfiguration().addCompilationCustomizers( new myTransform(CompilePhase.SEMANTIC_ANALYSIS))
).evaluate '''
    "Print me 1"
    "${"And " + "me 2"}"
    "${3}"
    "nope" + "not this time"
    class Foo { static String getFooString(String s) { "Foo" } }
    Foo.getFooString("no")
    public String getBar() { "Bar" }
    getBar()
    "getBar" ()
    println "Print me only once 4"
    def a = "nope"
    a
    def c = { String s -> "blah" ; s.toUpperCase() }
    c ( "out" )
    try { "nil" } catch (any) { "nil" } finally { "nil" }
    switch ("nada") { case "nada": "nada" }
    123
    new Foo() // TODO: throws an Error in the Transform, how to avoid it other than catching and ignoring it?
    return "Return me, don't print me."
'''

GroovyConsole Вывод:

Print me 1
And me 2
3
Print me only once 4
Result: Return me, don't print me.
...