Для 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.