如何匹配Clojure中的多行正则表达式来解析Groovy源文件?

esp*_*eed 1 java regex groovy clojure

我正在尝试在Groovy源文件上运行Clojure正则表达式来解析各个函数.

// gremlin.groovy

def warm_cache() {
  for (vertex in g.getVertices()) {
    vertex.getOutEdges()
  }
}

def clear() {
  g.clear()
}
Run Code Online (Sandbox Code Playgroud)

这是我在Clojure中使用的模式:

(def source (read-file "gremlin.groovy"))

(def pattern #"(?m)^def.*[^}]")   

(re-seq pattern source)
Run Code Online (Sandbox Code Playgroud)

然而,它只抓住了第一行,而不是多线功能.

tim*_*tes 6

作为演示如何从中获取AST GroovyRecognizer并避免尝试使用正则表达式解析语言的演示,您可以在Groovy中执行此操作:

import org.codehaus.groovy.antlr.*
import org.codehaus.groovy.antlr.parser.*

def code = '''
// gremlin.groovy

def warm_cache() {
  for (vertex in g.getVertices()) {
    vertex.getOutEdges()
  }
}

def clear() {
  g.clear()
}
'''


def ast = new GroovyRecognizer( new GroovyLexer( new StringReader( code ) ).plumb() ).with { p ->
  p.compilationUnit()
  p.AST
}


while( ast ) {
  println ast.toStringTree()
  ast = ast.nextSibling
}
Run Code Online (Sandbox Code Playgroud)

这会为AST中的每个GroovySourceAST节点输出AST,为您提供(对于此示例):

 ( METHOD_DEF MODIFIERS TYPE warm_cache PARAMETERS ( { ( for ( in vertex ( ( ( . g getVertices ) ELIST ) ) ( { ( EXPR ( ( ( . vertex getOutEdges ) ELIST ) ) ) ) ) )
 ( METHOD_DEF MODIFIERS TYPE clear PARAMETERS ( { ( EXPR ( ( ( . g clear ) ELIST ) ) ) )
Run Code Online (Sandbox Code Playgroud)

您应该可以使用Clojure的java interop和groovy-all jar文件执行相同的操作


编辑

要获得更多信息,您只需要深入了解AST并稍微操作输入脚本.将while上面代码中的循环更改为:

while( ast ) {
  if( ast.type == GroovyTokenTypes.METHOD_DEF ) {
    println """Lines $ast.line to $ast.lineLast
              |  Name:  $ast.firstChild.nextSibling.nextSibling.text
              |  Code:  ${code.split('\n')[ (ast.line-1)..<ast.lineLast ]*.trim().join( ' ' )}
              |   AST:  ${ast.toStringTree()}""".stripMargin()
  }
  ast = ast.nextSibling
}
Run Code Online (Sandbox Code Playgroud)

打印出来:

Lines 4 to 8
  Name:  warm_cache
  Code:  def warm_cache() { for (vertex in g.getVertices()) { vertex.getOutEdges() } }
   AST:   ( METHOD_DEF MODIFIERS TYPE warm_cache PARAMETERS ( { ( for ( in vertex ( ( ( . g getVertices ) ELIST ) ) ( { ( EXPR ( ( ( . vertex getOutEdges ) ELIST ) ) ) ) ) )
Lines 10 to 12
  Name:  clear
  Code:  def clear() { g.clear() }
   AST:   ( METHOD_DEF MODIFIERS TYPE clear PARAMETERS ( { ( EXPR ( ( ( . g clear ) ELIST ) ) ) )
Run Code Online (Sandbox Code Playgroud)

显然,该Code:部分只是连接在一起的线条,所以如果粘贴回groovy可能不起作用,但它们会让你了解原始代码......