2012-02-18 91 views
0

我正在用Groovy開發一個不錯的小DSL。groovy命令表達式如何做嵌套表達式?

我真的很喜歡高階函數的Command Expression。

很少的代碼,我可以這樣做:

timerange = from today to tomorrow 

這其實是

timerange = from(today).to(tomorrow) 

,但現在我願意做這樣的事情:

difference = difference from today to tomorrow 

這將導致像這樣:

difference = difference(from(today).to(event.start)) 

我總是得到錯誤:

No such property: from for class: Script1.

下面是測試類主要方法。第三個斷言失敗:

任何人都可以告訴我一個例子如何做到這一點?

 
import groovy.time.DatumDependentDuration 

/** 
* Created by IntelliJ IDEA. 
* User: nils 
* Date: 2/18/12 
* Time: 4:41 PM 
*/ 
class SimpleTest { 

    def static today = new Date(); 
    def static tomorrow = new Date() + 1; 

    def loadDSL(Closure cl) { 

     cl.delegate = this 
     return cl() 

    } 

    def toMethod = { date -> 
     [to: { timeThing -> 
      if (timeThing instanceof Date) { 
       use(groovy.time.TimeCategory) { 
        (date..timeThing) //return Range 
       } 
      } 
     }] 
    } 

    def from(Date date) { 
     toMethod(date) 
    } 

    def difference(Range range) { 
     range.size() //for the sake of simplicity 
    } 

    static void eval(dslContent, assertion) { 
     SimpleTest runner = new SimpleTest() 
     def dsl = """ 
     run { 
     ${dslContent} 
     } 
    """ 

     def binding = new Binding() 
     binding.run = { Closure cl -> runner.loadDSL(cl) } 

     binding.today = today; 
     binding.tomorrow = tomorrow; 

     GroovyShell shell = new GroovyShell(binding) 
     shell.evaluate(dsl) 
     assert binding.variables.x == assertion 

    } 

    static void main(String[] args) { 
     eval("x = from today to tomorrow", (today..tomorrow)) 
     eval("x = difference(from(today).to(tomorrow))", 2) 
     eval("x = difference from today to tomorrow ", 2) 

    } 

} 

這下面是完整的例外:

 
Exception in thread "main" groovy.lang.MissingPropertyException: No such property: from for class: Script1 
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50) 
    at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231) 
    at Script1$_run_closure1.doCall(Script1.groovy:3) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) 
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141) 
    at Script1$_run_closure1.doCall(Script1.groovy) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) 
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112) 
    at SimpleTest.loadDSL(SimpleTest.groovy:17) 
    at SimpleTest$loadDSL.call(Unknown Source) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42) 
    at SimpleTest$loadDSL.call(Unknown Source) 
    at SimpleTest$_eval_closure2.doCall(SimpleTest.groovy:48) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90) 
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233) 
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:272) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883) 
    at groovy.lang.MetaClassImpl.invokePropertyOrMissing(MetaClassImpl.java:1099) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1055) 
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:883) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:66) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141) 
    at Script1.run(Script1.groovy:2) 
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:580) 
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:618) 
    at groovy.lang.GroovyShell.evaluate(GroovyShell.java:589) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrap.invoke(PogoMetaMethodSite.java:247) 
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:64) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116) 
    at SimpleTest.eval(SimpleTest.groovy:54) 
    at SimpleTest$eval.callStatic(Unknown Source) 
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:50) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:157) 
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:169) 
    at SimpleTest.main(SimpleTest.groovy:62) 

回答

1

如果您添加一個getDifference方法返回範圍內,你可以在你的表達的末尾調用difference,但除此之外,常規不會解析difference from start to enddifference(from(start).to(end)),而是difference(from).start(to).end

​​

和一個小變化,你的測試:

static void main(String[] args) { 
     eval("x = from today to tomorrow", (today..tomorrow)) 
     eval("x = difference(from(today).to(tomorrow))", 2) 
     eval("x = from today to tomorrow difference", 2) 

    } 

兩年半來晚了?

+0

大聲笑,這是從一個時間,當我認爲DSL可以完全人類可讀的任何人。但是我錯了。 – 2014-10-13 06:51:27

+0

這不會對我有用,因爲「單詞序列」必須像英語一樣...... – 2014-10-13 07:59:38

+0

我想你會需要去爲你自己的antlr。但即使如此,你可能正在尋找[自然語言解析器](http://nlp.stanford.edu/software/lex-parser.shtml) – Will 2014-10-13 12:59:48