Scala 2.9:解析器子类不识别“Elem”覆盖?

时间:2012-11-29 03:16:12

标签: scala parser-combinators

我写了一个解析器来充当词法分析器。此词法分析器解析文件并返回一个标记列表,每个标记都是一个扩展共同特征的案例类或对象。

我现在正在尝试为词法分析器的输出编写一个解析器,但是我遇到了一个非常令人困惑的障碍。解析器很乐意隐式地转换我的case对象,但如果我甚至尝试手动调用apply(classHere),则会引发一个拟合。

以下是我的代码的简化版本:

// CODE
trait Token

case class StringWrapperIgnoresCase(val string: String) {
  private case class InnerWrapper(s: String)

  lazy val lower = string.toLowerCase

  override lazy val hashCode = InnerWrapper(lower).hashCode

  override def equals(that: Any) =
    that.isInstanceOf[StringWrapperIgnoresCase] &&
      lower == that.asInstanceOf[StringWrapperIgnoresCase].lower
}

case class ID(val text: String)
  extends StringWrapperIgnoresCase(text)
  with Token {
    override def toString = "ID(" + text + ")"
  }

case object PERIOD extends Token

object Parser extends Parsers {
  type Elem = Token

  def doesWork: Parser[Token] = PERIOD

  def doesNotWork: Parser[Token] = ID
}

编译器报告以下有关doesNotWork的消息:

// ERROR MESSAGE
type mismatch;  found   : alan.parser.ID.type (with underlying type object alan.parser.ID)  required: alan.parser.Parser.Parser[alan.parser.Token]

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

更新:我不清楚你的问题究竟是什么问题,但是现在你已经指定你想要一个与答案中任何ID匹配的解析器,这里有一个更惯用的解决方案:

val id: Parser[ID] = accept("ID", { case i: ID => i })

在这里,您已经提供了解析器想要的内容(用于错误消息)以及以ID为其域的部分函数的描述。您也可以使用xiefei在评论中提供的acceptIf版本。


当您引用没有参数列表的案例类(而不是案例对象)时,您将获得自动生成的伴随对象,该对象是类本身的实例。请考虑以下事项:

sealed trait Foo
case class Bar(i: Int) extends Foo
case object Baz extends Foo

现在Baz: Foo很好,但Bar: Foo会出现与您所看到的非常相似的错误。

另请注意,此处发生的事情并非严格施放Parsers特征具有以下签名的方法:

implicit def accept(e: Elem): Parser[Elem]

当你这样写:

def doesWork: Parser[Token] = PERIOD

您尝试将Elem键入为Parser[Elem],并且隐式转换会启动(有关隐式转换的详细信息,请参阅the spec的第7.3节)。当你写这篇文章时,另一方面:

def doesNotWork: Parser[Token] = ID

您尝试键入ID随播广告对象(其类型为ID.type,而不是IDToken,因此不是ElemParser[Elem],并且没有隐式转换可以实现这一点。

至少现在,你最好写出accept(PERIOD)accept(ID("whatever")),并且在你尝试编译代码时遵守以下说明的弃用警告:

  

案例到案例继承具有潜在的危险错误   不太可能被修复。

答案 1 :(得分:0)

使用TravisBrown和drstevens所说的,我已经为解析器添加了一个新的产品:

def id = {
  acceptIf(
    _ match {
      case ID(_) => true
      case _ => false
    }
  )("'ID(_)' expected but " + _ + " found")
}

def nowWorks = id

我暂不接受这个作为答案暂时允许某人提供比这更优雅的解决方案。这对我的口味来说看起来有些混乱,而且我确信更习惯于功能性编程方法的人会把它变成优雅的单行。