1

GroovyソースファイルでClojure正規表現を実行して、個々の関数を解析しようとしています。

// gremlin.groovy

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

def clear() {
  g.clear()
}

これは私がClojureで使用しているパターンです:

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

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

(re-seq pattern source)

ただし、これは最初の行を取得するだけであり、複数行の機能は取得しません。

4

3 に答える 3

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
}

これにより、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 ) ) ) )

Clojureのjava相互運用機能とgroovy-alljarファイルでも同じことができるはずです。


編集

もう少し情報を得るには、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
}

プリントアウト:

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 ) ) ) )

明らかに、このCode:セクションは結合された行だけなので、groovyに貼り付けても機能しない可能性がありますが、元のコードのアイデアが得られます...

于 2012-05-09T11:27:43.233 に答える
3

それはあなたの正規表現であり、Clojureではありません。一致するように要求しdef、次に何でも、次に閉じ中括弧と等しくない1文字を要求します。そのcharはどこにあってもかまいません。あなたが達成したいのはこれです:(?sm)def.*?^}

于 2012-05-09T10:33:40.383 に答える
2

短い答え

(re-seq (Pattern/compile "(?m)^def.*[^}]" Pattern/MULTILINE) source)

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.htmlから

デフォルトでは、正規表現^と$は行末記号を無視し、入力シーケンス全体の最初と最後でのみ一致します。MULTILINEモードがアクティブになっている場合、^は入力の開始時と、入力の終了時を除く任意のラインターミネータの後に一致します。MULTILINEモードの場合、$はラインターミネータの直前または入力シーケンスの終わりに一致します。

あなたはパスインできる必要があります

Pattern.MULTILINE

パターンがコンパイルされるとき。しかし、re-seqにはこれに対するオプションがないため、これを正しく機能させるには、おそらくJava相互運用機能にドロップダウンする必要がありますか?理想的には、Clojureの土地でこれを指定できるはずです... :(

更新:実際、それはそれほど悪いことではありません。正規表現にリテラル式を使用する代わりに、パターンにJava相互運用機能を使用するだけです。代わりに使用してください(re-seq (Pattern/compile "(?m)^def.*[^}]" Pattern/MULTILINE) source)(java.util.regex.Patternをインポートしたと仮定します)。私はこれをテストしていませんが、それでうまくいくと思います。

于 2012-05-09T11:06:59.333 に答える