groovy dsl - 是中缀运算符吗?

时间:2014-03-13 19:06:42

标签: groovy dsl

是否可以在Groovy中使用中缀运算符创建dsl?

我已经研究过构建器模式,invokeMethod,propertyInvoke和MetaClass,我只能看到如何使用它来创建使用前缀运算符的树结构(波兰表示法)。我想要做的是使用具有绑定优先级规则的中缀运算符构建树结构。

例如:如果此伪代码的计算结果为8:

add(2,multiply(3, 2))

我想表达为:

2 add 3 multiply 2

其中multiply比add更紧密地绑定。我使用算术就是一个例子 - 我的应用程序是完全不同的。

我不想写和支持我自己的解析器,所以我希望groovy有这个机制???

编辑:在搜索解决方案时,我发现这是可能的并且在Scala中有很好的文档记录(参见第33章:Martin Odersky在Scala编程中的组合解析器)。

1 个答案:

答案 0 :(得分:1)

我看到你在Scala中找到了答案,但无论如何,在Groovy中,虽然它需要点(或AST自动插入它),但是执行命令树并不困难:

更新:添加了floatNode方法,其优先级基于precedence列表。优先级较高的节点" float"向上:

class Operation {

  static final precedence = ['minus', 'add', 'multiply', 'divide']

  def left, right, method
  Operation parent

  def invokeMethod(String method, args) {
    def o = new Operation(
      parent: this, left: right, method: method, right: args[0])

    this.floatNode(o)
  }

  def floatNode(Operation op) {
    if (op.hasHigherPrecedenceThan(this)) {
      op.parent = this.parent
      this.parent = op
      if (op.parent) { this.parent = op.parent.floatNode(op) }
      return this
    }
    else {
      return op
    }
  }

  def hasHigherPrecedenceThan(Operation o) {
    return precedence.indexOf(this.method) > precedence.indexOf(o.method)
  }

  String toString() { "Operation($left $method $right, parent=$parent)" }
}

测试:

Integer.metaClass.invokeMethod = { String method, args ->
  new Operation(parent: null, method: method, left: delegate, right: args.head())
}


a = 2.add 3 multiply 4 minus 5 divide 6 add 7 

println a

println将输出:

Operation(3 minus 5, 
    parent=Operation(5 add 7, 
        parent=Operation(2 add 3, 
            parent=Operation(3 multiply 4, 
                parent=Operation(5 divide 6, parent=null)))))