5

私の現在の作業プロジェクトでは、ワークフローを拡張して影響を与える方法として、ユーザー提供の式を特定のコンテキストで評価できます。これらの式は通常の論理式 f. プログラマーではない人にも少し受け入れやすくするために、リテラル演算子 (&、|、! の代わりに and、or など) を使用するオプションを提供したいと思います。

データには引用符で囲まれたこれらの単語が含まれている可能性があり、パーサーを構築することは可能ですが、最もエレガントで効率的なソリューションではない可能性があるため、単純な検索と置換では不十分です。

質問を明確にするために: Groovy でユーザーが書き込みできるようにする方法はありますか?

x > 10 and y = 20 or not z 

しかし、Groovy に次のように評価させます。

x > 10 && y == 20 || !z

ありがとうございました。

4

3 に答える 3

4

Groovy の最近のバージョンはコマンド チェーンをサポートしているため、実際に次のように記述できます。

compute x > 10 and y == 20 or not(z)

ここでの「compute」という単語は任意ですが、コマンド チェーンの最初の「動詞」であるため、省略できません。後に続くものはすべて、動詞と名詞を交互に繰り返します。

 compute  x > 10  and  y == 20  or   not(z)
 ───┬───  ──┬───  ─┬─  ───┬───  ─┬─  ──┬───
   verb    noun   verb   noun   verb  noun

コマンド チェーンは次のようにコンパイルされます。

verb(noun).verb(noun).verb(noun)...

したがって、上記の例は次のようにコンパイルされます。

compute(x > 10).and(y == 20).or(not(z))

これを実装するには多くの方法があります。これは、特に演算子の優先順位を実装していない、簡単で汚い概念の証明です。

class Compute {
    private value
    Compute(boolean v) { value = v }
    def or (boolean w) { value = value || w; this }
    def and(boolean w) { value = value && w; this }
    String  toString() { value }
}

def compute(v) { new Compute(v) }
def not(boolean v) { !v }

コマンド チェーンは、単独で (最上位ステートメントとして)、または代入演算子の右側 (ローカル変数またはプロパティの代入) で使用できますが、他の式内では使用できません。

于 2016-05-04T23:35:22.087 に答える
1

>とのような演算子を=フェイスレットのようなgteqにそれぞれ交換できる場合、多くの労力が必要になりますが、あなたのケースは実行可能であると思います。

x gt 10 and y eq 20 or not z 

次のように解決されます。

x(gt).10(and).y(eq).20(or).not(z)

そして、これを解析するのは地獄です。

@Brian Henry が提案した方法は、括弧とドットが必要なため、ユーザーフレンドリーではありませんが、最も簡単な方法です。

演算子を交換できることを考えると、Integer.call式を開始するためにインターセプトを試みることができます。スクリプトに不足しているプロパティを操作に解決することで、新しいキーワードの問題を解決できます。次に、式を作成してリストに保存し、スクリプトの最後で実行できます。それは終わっていませんが、私はこれと一緒に来ました:

// the operators that can be used in the script
enum Operation { eq, and, gt, not }

// every unresolved variable here will try to be resolved as an Operation
def propertyMissing(String property) { Operation.find { it.name() == property} }

// a class to contain what should be executed in the end of the script
@groovy.transform.ToString 
class Instruction { def left; Operation operation; def right }

// a class to handle the next allowed tokens
class Expression {
  Closure handler; Instruction instruction
  def methodMissing(String method, args) {
    println "method=$method, args=$args"
    handler method, args
  }
}

// a list to contain the instructions that will need to be parsed
def instructions = []

// the start of the whole mess: an integer will get this called
Integer.metaClass {
  call = { Operation op ->
    instruction = new Instruction(operation: op, left: delegate)
    instructions << instruction
    new Expression(
      instruction: instruction,
      handler:{ String method, args -> 
        instruction.right = method.toInteger()
        println instructions
        this
      })
  }
}

x = 12
y = 19
z = false

x gt 10 and y eq 20 or not z 

パーツが実装されていないため、例外が発生しますが、not()失敗する前に 2 つの命令オブジェクトを構築できます。

[Instruction(12, gt, 10), Instruction(19, eq, 20)]

それだけの価値があるかどうかはわかりません。

于 2012-12-09T01:34:38.883 に答える
0

GDKはブール値に取り組みand()or()メソッドを使用します。次のようなメソッドを提供した場合

Boolean not(Boolean b) {return !b}

あなたは次のようなものを書くことができます

(x > 10).and(y == 20).or(not(4 == 1)) 

でも、それが特に書きやすいかどうかはわかりません。

于 2012-12-08T19:13:57.017 に答える