【问题标题】:Getting info on Groovy functions (name, signature, body code)获取有关 Groovy 函数的信息(名称、签名、正文代码)
【发布时间】:2012-06-18 19:06:41
【问题描述】:

我有一个 Groovy 文件,其中包含一堆简单的函数,如下所示:

// useful functions
def myFunc1(String arg) {
    println("Hello " + arg)
}

def myFunc2(String arg) {
    println("Goodbye " + arg)
}

我想从这里获得:

  • 方法名
  • 论据
  • 函数的主体代码

(都是简单的字符串,我还不需要运行任何东西。)

我正要使用一些正则表达式,但由于我使用的是 JVM 语言 (Scala),我想我也许可以使用一些 Groovy 编译器的东西来以一种“更好”的方式来做这件事。

似乎有很多关于动态加载 Groovy 代码并运行它的信息,但关于自省源代码的信息却不多。有什么想法吗?

(如果以“不错”的方式失败,我也会接受一些 Scala-foo 以简洁的方式解析信息。)

【问题讨论】:

    标签: parsing scala reflection groovy


    【解决方案1】:

    这很有效,并演示了在 AST 中查找每个重要节点所需的令牌类型。希望这是有道理的...通过使用大量的 Groovy 动态,我希望我没有让移植到 Scala 变得太难:-(

    import org.codehaus.groovy.antlr.*
    import org.codehaus.groovy.antlr.parser.*
    import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.*
    
    def code = '''
    // useful functions
    def myFunc1(String arg) {
        println("Hello " + arg)
    }
    
    def myFunc2(arg, int arg2) {
        println("Goodbye " + arg)
    }
    
    public String stringify( int a ) {
      "$a"
    }
    '''
    
    def lines = code.split( '\n' )
    
    // Generate a GroovyRecognizer, compile an AST and assign it to 'ast'
    def ast = new SourceBuffer().with { buff ->
      new UnicodeEscapingReader( new StringReader( code ), buff ).with { read ->
        read.lexer = new GroovyLexer( read )
        GroovyRecognizer.make( read.lexer ).with { parser ->
          parser.sourceBuffer = buff
          parser.compilationUnit()
          parser.AST
        }
      }
    }
    
    // Walks the ast looking for types
    def findByPath( ast, types, multiple=false ) {
      [types.take( 1 )[ 0 ],types.drop(1)].with { head, tail ->
        if( tail ) {
          findByPath( ast*.childrenOfType( head ).flatten(), tail, multiple )
        }
        else {
          ast*.childrenOfType( head ).with { ret ->
            multiple ? ret[ 0 ] : ret.head()[0]
          }
        }
      }
    }
    
    // Walk through the returned ast
    while( ast ) {
      def methodModifier = findByPath( ast, [ MODIFIERS   ] ).firstChild?.toStringTree() ?: 'public'
      def returnType     = findByPath( ast, [ TYPE, IDENT ] ) ?: 'Object'
      def methodName     = findByPath( ast, [ IDENT       ] )
      def body           = findByPath( ast, [ SLIST ] )
      def parameters     = findByPath( ast, [ PARAMETERS, PARAMETER_DEF ], true ).collect { param ->
        [ type: findByPath( param, [ TYPE ] ).firstChild?.toStringTree() ?: 'Object',
          name: findByPath( param, [ IDENT ] ) ]
      }
    
      def (y1,y2,x1,x2) = [ body.line - 1, body.lineLast - 1, body.column - 1, body.columnLast ]
      // Grab the text from the original string
      def snip = [  lines[ y1 ].drop( x1 ),                // First line prefix stripped
                   *lines[ (y1+1)..<y2 ],                  // Mid lines
                    lines[ y2 ].take( x2 ) ].join( '\n' )  // End line suffix stripped
    
      println '------------------------------'
      println "modifier: $methodModifier"
      println "returns:  $returnType"
      println "name:     $methodName"
      println "params:   $parameters"
      println "$snip\n"
    
      // Step to next branch and repeat
      ast = ast.nextSibling
    }
    

    打印出来:

    ------------------------------
    modifier: public
    returns:  Object
    name:     myFunc1
    params:   [[type:String, name:arg]]
    {
        println("Hello " + arg)
    }
    
    ------------------------------
    modifier: public
    returns:  Object
    name:     myFunc2
    params:   [[type:Object, name:arg], [type:int, name:arg2]]
    {
        println("Goodbye " + arg)
    }
    
    ------------------------------
    modifier: public
    returns:  String
    name:     stringify
    params:   [[type:int, name:a]]
    {
      "$a"
    }
    

    希望它有所帮助,或为您指明正确的方向:-)

    【讨论】:

    • 感谢蒂姆,这非常有帮助!当我稍微完善一下时,我会用 Scala 翻译更新我的问题。
    • 如果这些方法在 groovy 类中,我需要做哪些更改?
    • @tim_yates 这是一个很好的例子。谢谢你。如果我想在方法中获取方法调用怎么办?假设 myFunc1 调用 myFunc2。
    猜你喜欢
    • 2012-03-21
    • 2023-04-02
    • 2013-08-07
    • 2010-12-21
    • 2012-10-18
    • 2020-11-20
    • 2021-12-06
    • 1970-01-01
    • 2016-06-13
    相关资源
    最近更新 更多