Scala解析器和隐式有序转换

时间:2012-10-03 15:47:19

标签: parsing scala implicit-conversion

下面的解析器组合器片段演示了使用>来概括二元比较操作的目标,例如Ordered[T]Gt似乎在AST级别实现了这一点,但我在扩展这个概念时遇到了麻烦。

intGt解析器可以工作但是可以围绕Ordered[T]推广它,这样我们就不需要为floatGt编写第二个解析器(因此对于所有支持的可订购的解析器)类型*所有支持的操作 - 不,谢谢)。

object DSL extends JavaTokenParsers {
  // AST
  abstract class Expr[+T] { def eval: T }
  case class Literal[T](t: T) extends Expr[T] { def eval = t }
  case class Gt[T <% Ordered[T]](l: Expr[T], r: Expr[T]) extends Expr[Boolean] {
    def eval = l.eval > r.eval // view-bound implicitly wraps eval result as Ordered[T]
  }

  // Parsers
  lazy val intExpr: Parser[Expr[Int]] = wholeNumber ^^ { case x => Literal(x.toInt) }
  lazy val floatExpr: Parser[Expr[Float]] = decimalNumber ^^ { case x => Literal(x.toFloat) }
  lazy val intGt: Parser[Expr[Boolean]] = intExpr ~ (">" ~> intExpr) ^^ { case l ~ r => Gt(l, r) }
}

1 个答案:

答案 0 :(得分:0)

我尝试过玩耍,这是我能够想到的最好的时间:

import scala.util.parsing.combinator.JavaTokenParsers

object DSL extends JavaTokenParsers {
  // AST
  abstract class Expr[+T] { def eval: T }
  case class Literal[T](t: T) extends Expr[T] { def eval = t }
  case class BinOp[T,U](
    val l : Expr[T],
    val r : Expr[T],
    val evalOp : (T, T) => U) extends Expr[U] {

    def eval = evalOp(l.eval, r.eval)
  }

  case class OrderOp[O <% Ordered[O]](symbol : String, op : (O, O) => Boolean)

  def gtOp[O <% Ordered[O]] = OrderOp[O](">", _ > _)
  def gteOp[O <% Ordered[O]] = OrderOp[O](">=", _ >= _)
  def ltOp[O <% Ordered[O]] = OrderOp[O]("<", _ < _)
  def lteOp[O <% Ordered[O]] = OrderOp[O]("<=", _ <= _)
  def eqOp[O <% Ordered[O]] = OrderOp[O]("==", _.compareTo(_) == 0)

  def ops[O <% Ordered[O]] = 
    Seq(gtOp[O], gteOp[O], ltOp[O], lteOp[O], eqOp[O])

  def orderExpr[O <% Ordered[O]](
    subExpr : Parser[Expr[O]], 
    orderOp : OrderOp[O]) 
    : Parser[Expr[Boolean]] =
      subExpr ~ (orderOp.symbol ~> subExpr) ^^ 
        { case l ~ r => BinOp(l, r, orderOp.op) }

  // Parsers
  lazy val intExpr: Parser[Expr[Int]] = 
    wholeNumber ^^ { case x => Literal(x.toInt) }

  lazy val floatExpr: Parser[Expr[Float]] =
    decimalNumber ^^ { case x => Literal(x.toFloat) }

  lazy val intOrderOps : Parser[Expr[Boolean]] = 
    ops[Int].map(orderExpr(intExpr, _)).reduce(_ | _)

  lazy val floatOrderOps : Parser[Expr[Boolean]] =
    ops[Float].map(orderExpr(floatExpr, _)).reduce(_ | _)
}

基本上,我定义了一个与表示字符串相关的小案例类OrderOp 对将评估该操作的函数的排序操作。然后我定义了一个函数ops,它能够为给定的Seq[OrderOp]类型创建所有此类排序操作的Orderable。然后可以使用orderExpr将这些操作转换为解析器,它使用子表达式解析器和操作。这将映射到int和float类型的所有排序操作。

这种方法存在一些问题:

  • 对于所有二进制操作,AST类型层次结构中只有一个节点类型。如果您所做的只是进行评估,这不是问题,但如果您曾想进行重写操作(例如消除明显的重言式或矛盾),那么使用BinOp的当前定义就没有足够的信息来执行此操作。 / LI>
  • 我仍然需要为每种不同的类型映射orderExpr。可能有办法解决这个问题,但我没时间了。
  • orderExpr期望使用相同的解析器解析左右子表达式。