1

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

我现在正在尝试为词法分析器的输出编写一个解析器,但我遇到了一个非常令人困惑的问题。解析器很乐意隐式转换我的案例对象,但如果我什至尝试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]

我怎样才能解决这个问题?

4

2 回答 2

2

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

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

在这里,您提供了解析器所需内容的描述(用于错误消息)以及以IDs 作为域的部分函数。您也可以使用acceptIfxiefei 在对您的答案的评论中提供的版本。


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

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

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

另请注意,这里发生的事情并不是严格的cast。该Parsers特征具有具有以下签名的方法:

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

当你写这个:

def doesWork: Parser[Token] = PERIOD

您正在尝试键入 an Elemas a ,然后隐式转换开始(有关隐式转换的更多信息,请参见规范Parser[Elem]的第 7.3 节)。另一方面,当你写这个时:

def doesNotWork: Parser[Token] = ID

您正在尝试将ID伴随对象(具有 type ID.type,not IDor Token,因此 not Elem)键入为 a Parser[Elem],并且没有使这成为可能的隐式转换。

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

逐案继承具有潜在的危险错误,这些错误不太可能被修复。

于 2012-11-29T04:13:55.600 回答
0

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

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

def nowWorks = id

我暂时不会接受这个作为答案,以允许某人提供比这更优雅的解决方案。这对我的口味来说看起来有点乱,我敢肯定,更习惯于函数式编程方法的人会将它变成优雅的单线。

于 2012-11-29T04:42:51.960 回答