void whatever() {
// ...
val parser = new MyParser
val parse = parser.parse(input)
if (parse successful) {
semanticAnalysis(parse)
}
}
void semanticAnalysis(parse: DontKnowTheCorrectType) {
// ...
}
我必须给形式参数parse
提供什么类型的?将鼠标悬停在parse
内的whatever
说val parse: parser.ParseResult[parsing.Program]
,但当然不能用作semanticAnalysis
的参数类型,因为局部变量parse
不是在那里。
答案 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)
}
}