如何将ParseResults传递给其他方法?

时间:2012-08-21 09:33:57

标签: scala types parameters parser-combinators

void whatever() {
  // ...
  val parser = new MyParser
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

void semanticAnalysis(parse: DontKnowTheCorrectType) {
  // ...
}

我必须给形式参数parse提供什么类型的?将鼠标悬停在parse内的whateverval parse: parser.ParseResult[parsing.Program],但当然不能用作semanticAnalysis的参数类型,因为局部变量parse不是在那里。

4 个答案:

答案 0 :(得分:3)

解析结果是与路径相关的类型,因为它们是此特定解析器的结果,并且无法保证它们是兼容的。

这就是为什么解析器通常不会按照您使用它的方式实例化(new MyParser),而是object

object MyParser extends RegexParsers { 
   def statements : Parser[List[Statement]] = // ...
} 

def handleResult(res: MyParser.ParseResult[List[Statement]]) = { // ... } 

val res = MyParser.parseAll(MyParser.statements, "/* */")

如果您需要更多动态行为(或者需要并发解析,parser combinators aren't thread-safe,ouch),您只需要在任何想要使用其结果的地方保持解析器对象的可访问性(和稳定性)。

可悲的是,将解析器及其结果传递到一起并非易事,因为您遇到了依赖方法类型的禁止,例如:

  def fun(p: scala.util.parsing.combinator.Parsers, res: p.ParseResult[_]) = {}

不会编译(“非法依赖方法类型”),但如果必须,有办法解决这个问题,比如this question的答案。

答案 1 :(得分:1)

您应该能够将semanticAnalysis定义为:

def semanticAnalysis(parse: MyParser#ParseResult[parsing.Program]) = {
  ...
}

请注意使用#代替.作为类型。还有更多详细信息about type projections here,但基本上,parser.ParseResult对于每个parser都有所不同,而MyParser#ParseResult对于所有parser个实例都是相同的。

但是,正如themel所说,您应该使用object代替class

答案 2 :(得分:0)

您可以这样重写:

def whatever() {
  // ...
  val parser = new MyParser
  def semanticAnalysis(parse: parser.ParseResult) {
    // ...
  }
  val parse = parser.parse(input)
  if (parse successful) {
    semanticAnalysis(parse)
  }
}

如果你从多个地方调用它,那么可能是这样:

  class SemanticAnalysis(parser: Parser) {
    def apply(parse: parser.ParseResult) {
      // ...
    }
  }

然后

  if (parse successful) {
    new SemanticAnalysis(parser)(parse)
  }

答案 3 :(得分:0)

当我需要在程序的其他部分使用解析器组合器的结果时,我从路径依赖的ParseResult中提取成功结果或错误消息,并将数据放入一个独立的类型中。它比我喜欢的更冗长,但我想让combinator实例保持解析器的实现细节。

sealed abstract class Result[+T]
case class Success[T](result: T) extends Result[T]
case class Failure(msg: String) extends Result[Nothing]
case class Error(msg: String) extends Result[Nothing]

/** Parse the package declarations in the file. */
def parse(file: String): Result[List[Package]] = {
  val stream = ... // open the file...
  val parser = new MyParser
  val result = parser.parseAll(parser.packages, stream)   
  stream.close()
  result match {
    case parser.Success(packages, _) => Success(packages)
    case parser.Failure(msg, _) => Failure(msg)
    case parser.Error(msg, _) => Error(msg)
  }
}