2012-12-08 4 views
5

Mein aktuelles Arbeitsprojekt ermöglicht die Auswertung von benutzerdefinierten Ausdrücken in bestimmten Kontexten, um den Workflow zu erweitern und zu beeinflussen. Diese Ausdrücke sind die üblichen logischen f. Um es für Nicht-Programmierer etwas schmackhaft zu machen, möchte ich ihnen die Möglichkeit geben, Literaloperatoren zu verwenden (z. B. und, oder statt &, |,!).Verwenden Sie literale Operatoren (zB "und", "oder") in Groovy-Ausdrücken?

Eine einfache Suche & Ersetzen ist nicht ausreichend, da die Daten diese Wörter in Anführungszeichen enthalten und einen Parser erstellen können, obwohl machbar, möglicherweise nicht die eleganteste und effizienteste Lösung.

Um die Frage klar zu machen: Gibt es in Groovy eine Möglichkeit, den Benutzern zu erlauben

x > 10 and y = 20 or not z 

aber haben Groovy, es zu schreiben zu bewerten, als ob es:

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

Danke.

+3

Ich denke, du wirst deinen eigenen Parser schreiben müssen –

+0

Mit '&' und '|' meinst du '&&' und '||'? Oder meinst du wirklich die bitweisen Operatoren? – Will

+0

@WillP Meine schlechte, ich meinte die logischen. Ich habe die Frage geklärt. – wishihadabettername

Antwort

0

Die GDK Tacks auf and() und or() Methoden zu Boolean. Wenn Sie eine Methode wie

geliefert
Boolean not(Boolean b) {return !b} 

Sie so etwas wie

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

schreiben konnte ich nicht sicher bin, das ist besonders einfach zu schreiben, though.

+0

Danke, aber in der Tat wäre es überhaupt nicht einfacher. – wishihadabettername

1

Wenn Sie Operatoren wie > und = für die facelets artigen gt und eq tauschen bzw. ich denke, Ihr Fall machbar sein kann, obwohl es viel Aufwand erfordert:

x gt 10 and y eq 20 or not z 

beschließt, :

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

Und das wird die Hölle zu analysieren.

Der Weg @ Brian Henry vorgeschlagen ist der einfachste Weg, obwohl nicht benutzerfreundlich, da es die Parens und Punkte benötigt.

Nun, da wir die Operatoren austauschen können, könnten Sie versuchen, die Integer.call abzufangen, um Ausdrücke zu starten. Die fehlenden Eigenschaften in einem Skript, das in Operationen aufgelöst wird, können das Problem mit neuen Keywords lösen. Dann können Sie Ausdrücke erstellen und sie in einer Liste speichern, indem Sie sie am Ende des Skripts ausführen. Es ist noch nicht fertig, aber ich kam mit dieser:

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

, die eine Ausnahme geben, aufgrund der not() Teil nicht umgesetzt werden, aber es kann zwei Instruction Objekte bauen, bevor ein Fehler:

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

Nicht sicher, ob es das wert ist.

+0

Dank Will, es ist tatsächlich zu viel Arbeit für diesen speziellen Fall – wishihadabettername

4

Neuere Versionen von Groovy Unterstützung Command chains, so ist es in der Tat möglich, dies zu schreiben:

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

Das Wort „berechnen“ hier ist beliebig, aber es kann nicht verzichtet werden, weil es das erste „Verb“ in der ist Befehlskette. Alles, was wechselt zwischen Verb und Substantiv folgt:

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

Eine Befehlskette wird wie folgt zusammengestellt:

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

so das obige Beispiel wird kompiliert:

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

Es gibt viele Möglichkeiten um dies zu implementieren. Hier ist nur ein kurzer & schmutzig Proof of Concept, die nicht Operatorpräzedenz nicht implementiert, unter anderem:

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 } 

Sie Befehlsketten von sich selbst (als Top-Level-Anweisungen) verwenden können, oder auf die rechte Seite Seite eines Zuweisungsoperators (lokale Variable oder Eigenschaftszuweisung), aber nicht innerhalb anderer Ausdrücke.

Verwandte Themen