使用解析器组合器构造类型检查解析器

时间:2013-04-16 12:59:48

标签: scala generics casting parser-combinators

目前,我正在尝试解析Scala中的Reader[Token]。因此,我想在解析步骤中检查Token是否是特定类的元素(例如AToken)。 我可以使用以下代码轻松完成:

def aToken = acceptIf(_.isInstanceOf[AToken])("Token " + _ + " is not of type AToken")
  ^^ { _.asInstanceOf[AToken] }  

这完全没问题。但我有几种类型需要检查。因此,对于每种类型,我都需要再次将上述内容写入上面。 所以我想要一些抽象的acceptIfInstanceOf[T]方法,它会自动(神奇地?)为类型T创建一个方法。

我目前的解决方案仍然分为两步:

def acceptIfInstanceOf[T](implicit m: Manifest[T]) : Parser[Elem] =
  acceptIf(_.getClass == m.runtimeClass)("" + _ + " is not of type " + m)
def aToken = acceptIfInstanceOf[AToken] ^^ { _.asInstanceOf[AToken] }

这也有效,但我想摆脱aToken中的函数应用程序,并将其直接包含在acceptIfInstanceOf中。 可悲的是,这不起作用:

def acceptIfInstanceOf[T](implicit m: Manifest[T]) : Parser[T] =
  acceptIf(_.getClass == m.runtimeClass)("" + _ + " is not of type " + m)
  ^^ { m.runtimeClass.cast(_) }

我从Scala编译器收到以下错误消息:

scala: type mismatch;
found   : _$1 where type _$1
required: T
def acceptIfInstanceOf[T](implicit m: Manifest[T]): Parser[T] =
  acceptIf(_.getClass == m.runtimeClass)("" + _ + " is not of type " + m)
  ^^ { m.runtimeClass.cast(_) }
                          ^

有人知道是否以及如何构建这样的东西? 谢谢!

1 个答案:

答案 0 :(得分:1)

使用_.asInstaceOf[T]代替m.runtimeClass.cast(_)huynhjl解决了最初的问题:

def acceptIfInstanceOf[T](implicit m: Manifest[T]) : Parser[T] =
  acceptIf(_.getClass == m.runtimeClass)("" + _ + " is not of type " + m)
  ^^ { _.asInstanceOf[T] }

但是,检查_.getClass == m.runtimeClass显然忽略了_.isInstanceOf包含的所有子类型语义 - 只是因为我们检查了两个Class对象的相等性。

如果我想维护isInstanceOf的语义,我必须使用以下测试:

reflect.ClassManifest.singleType(_) <:< m

但由于这在2.10中已弃用,我将Manifest替换为TypeTag并立即使用以下内容:

def acceptIfInstanceOf[T](implicit tag: TypeTag[T]): Parser[T] =
  acceptIf(currentMirror.reflect(_).symbol.toType <:< typeOf[T])
  ("" + _ + " is not of type " + tag.tpe)
  ^^ { _.asInstanceOf[T] }

我在Stack Overflow上从another question获得了上述解决方案。