2016-11-04 24 views
0

在SBT插件,我想写与接受并解析函数的名称及其参数选项卡完成解析器:NoSuchElementException异常在SBT相关的语法分析

case class Param(name : String, tpe : String) // tpe is for param type 
case class Func(name : String, params : immutable.Seq[Param]) 

def funcAndParamsParser(funcs : immutable.Set[Func]) : Parser[(Func,immutable.Seq[String])] = ??? 

要实现这一点,我打破它的问题分解成件:

def funcParser(funcs : immutable.Set[Func]) : Parser[Func] = { 
    val funcsByName = funcs.map(func => (func.name, func)).toMap 
    NotSpace.examples(funcsByName.keySet).map(funcsByName) 
} 

def paramParser(param : Param) : Parser[String] = { 
    NotSpace.examples(s"<${param.name}, of type ${param.tpe}>") 
} 

def paramsParser(params : immutable.Seq[Param]) : Parser[immutable.Seq[String]] = { 
    params.map(paramParser).foldLeft(success(immutable.Seq.empty[String])){ 
    (nascent, next) => nascent.flatMap(partial => Space ~> next.map(str => partial :+ str)) 
    } 
} 

最后,我可以实现的主要事件:

def funcAndParamsParser(funcs : immutable.Set[Func]) : Parser[(Func,immutable.Seq[String])] = { 
    funcParser(funcs).flatMap(func => paramsParser(func.params).map(seq => (func, seq))) 
} 

所有的辅助解析器都能正常工作,但最终的组合funcAndParamsParser(...)失败,出现NoSuchElementException

val func0 = Func("move", Param("x", "Int") :: Param("y", "Int") :: Nil) 
val func1 = Func("fill", Param("color", "Color") :: Nil) 
val testParser = Space ~> funcAndParamsParser(immutable.Set(func0, func1)) 

当我嵌入这个解析器在InputTask调用testParser.parsed,它那种似乎工作。在任务名称后输入<space>,然后输入<tab>,我得到期望的函数列表(尽管忽略了第二个参数的示例标签填充为move)。

> tmpTestDynamicParser 
fill <color, of type Color> move <x, of type Int> 

但是,解析器总是最终失败。如果我输入的内容应是一个有效的输入:

> tmpTestDynamicParser move 3 5 

或者,如果我键入部分输入,然后标签:

> tmpTestDynamicParser mo 

我得到一个高深莫测的例外:

java.util.NoSuchElementException: key not found: m 
    at scala.collection.MapLike$class.default(MapLike.scala:228) 
    at scala.collection.AbstractMap.default(Map.scala:58) 
    at scala.collection.MapLike$class.apply(MapLike.scala:141) 
    at scala.collection.AbstractMap.apply(Map.scala:58) 
    at sbt.complete.Parser$Value.map(Parser.scala:161) 
    at sbt.complete.MapParser.resultEmpty$lzycompute(Parser.scala:704) 
    at sbt.complete.MapParser.resultEmpty(Parser.scala:704) 
    at sbt.complete.BindParser.derive(Parser.scala:694) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.ParserSeq$$anonfun$derive$6.apply(Parser.scala:676) 
    at sbt.complete.ParserSeq$$anonfun$derive$6.apply(Parser.scala:676) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) 
    at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244) 
    at scala.collection.immutable.List.foreach(List.scala:318) 
    at scala.collection.TraversableLike$class.map(TraversableLike.scala:244) 
    at scala.collection.AbstractTraversable.map(Traversable.scala:105) 
    at sbt.complete.ParserSeq.derive(Parser.scala:676) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.MapParser.derive(Parser.scala:705) 
    at sbt.complete.ParserMain$class.derive1(Parser.scala:454) 
    at sbt.complete.Parser$.derive1(Parser.scala:135) 
    at sbt.complete.ParserMain$$anonfun$apply$9.apply(Parser.scala:450) 
    at sbt.complete.ParserMain$$anonfun$apply$9.apply(Parser.scala:450) 
    at scala.collection.IndexedSeqOptimized$class.foldl(IndexedSeqOptimized.scala:51) 
    at scala.collection.IndexedSeqOptimized$class.foldLeft(IndexedSeqOptimized.scala:60) 
    at scala.collection.immutable.StringOps.foldLeft(StringOps.scala:31) 
    at scala.collection.TraversableOnce$class.$div$colon(TraversableOnce.scala:138) 
    at scala.collection.immutable.StringOps.$div$colon(StringOps.scala:31) 
    at sbt.complete.ParserMain$class.apply(Parser.scala:450) 
    at sbt.complete.Parser$.apply(Parser.scala:135) 
    at sbt.complete.ParserMain$class.completions(Parser.scala:464) 
    at sbt.complete.Parser$.completions(Parser.scala:135) 
    at sbt.complete.JLineCompletion$$anonfun$parserAsCompletor$1.apply(JLineCompletion.scala:52) 
    at sbt.complete.JLineCompletion$$anonfun$parserAsCompletor$1.apply(JLineCompletion.scala:52) 
    at sbt.complete.JLineCompletion$$anonfun$customCompletor$1$$anonfun$2.apply(JLineCompletion.scala:75) 
    at sbt.complete.JLineCompletion$$anonfun$customCompletor$1$$anonfun$2.apply(JLineCompletion.scala:75) 
    at sbt.complete.JLineCompletion$.complete(JLineCompletion.scala:94) 
    at sbt.complete.JLineCompletion$$anonfun$customCompletor$1.apply(JLineCompletion.scala:75) 
    at sbt.complete.JLineCompletion$$anonfun$customCompletor$1.apply(JLineCompletion.scala:74) 
    at sbt.complete.JLineCompletion$CustomHandler.complete(JLineCompletion.scala:30) 
    at jline.console.ConsoleReader.complete(ConsoleReader.java:3311) 
    at jline.console.ConsoleReader.readLine(ConsoleReader.java:2646) 
    at jline.console.ConsoleReader.readLine(ConsoleReader.java:2372) 
    at jline.console.ConsoleReader.readLine(ConsoleReader.java:2360) 
    at sbt.JLine.sbt$JLine$$readLineDirectRaw(LineReader.scala:42) 
    at sbt.JLine$$anonfun$readLineDirect$2.apply(LineReader.scala:34) 
    at sbt.JLine$$anonfun$readLineDirect$2.apply(LineReader.scala:34) 
    at sbt.Signals0.withHandler(Signal.scala:81) 
    at sbt.Signals$.withHandler(Signal.scala:11) 
    at sbt.JLine.readLineDirect(LineReader.scala:34) 
    at sbt.JLine.readLineWithHistory(LineReader.scala:27) 
    at sbt.JLine.sbt$JLine$$unsynchronizedReadLine(LineReader.scala:19) 
    at sbt.JLine$$anonfun$readLine$1.apply(LineReader.scala:16) 
    at sbt.JLine$$anonfun$readLine$1.apply(LineReader.scala:16) 
    at sbt.JLine$$anonfun$withJLine$1.apply(LineReader.scala:117) 
    at sbt.JLine$$anonfun$withJLine$1.apply(LineReader.scala:115) 
    at sbt.JLine$.withTerminal(LineReader.scala:89) 
    at sbt.JLine$.withJLine(LineReader.scala:115) 
    at sbt.JLine.readLine(LineReader.scala:16) 
    at sbt.BasicCommands$$anonfun$shell$1.apply(BasicCommands.scala:185) 
    at sbt.BasicCommands$$anonfun$shell$1.apply(BasicCommands.scala:181) 
    at sbt.Command$$anonfun$command$1$$anonfun$apply$1.apply(Command.scala:30) 
    at sbt.Command$$anonfun$command$1$$anonfun$apply$1.apply(Command.scala:30) 
    at sbt.Command$.process(Command.scala:93) 
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96) 
    at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:96) 
    at sbt.State$$anon$1.process(State.scala:184) 
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96) 
    at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:96) 
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17) 
    at sbt.MainLoop$.next(MainLoop.scala:96) 
    at sbt.MainLoop$.run(MainLoop.scala:89) 
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:68) 
    at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:63) 
    at sbt.Using.apply(Using.scala:24) 
    at sbt.MainLoop$.runWithNewLog(MainLoop.scala:63) 
    at sbt.MainLoop$.runAndClearLast(MainLoop.scala:46) 
    at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:30) 
    at sbt.MainLoop$.runLogged(MainLoop.scala:22) 
    at sbt.StandardMain$.runManaged(Main.scala:57) 
    at sbt.xMain.run(Main.scala:29) 
    at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:57) 
    at xsbt.boot.Launch$.withContextLoader(Launch.scala:77) 
    at xsbt.boot.Launch$.run(Launch.scala:57) 
    at xsbt.boot.Launch$$anonfun$explicit$1.apply(Launch.scala:45) 
    at xsbt.boot.Launch$.launch(Launch.scala:65) 
    at xsbt.boot.Launch$.apply(Launch.scala:16) 
    at xsbt.boot.Boot$.runImpl(Boot.scala:32) 
    at xsbt.boot.Boot$.main(Boot.scala:21) 
    at xsbt.boot.Boot.main(Boot.scala) 
^JException occurred while determining completions. 

这似乎它应该是SBT解析器的一个简单的用例,但是我对如何修复这个神秘的异常感到不知所措,并且通常会使其工作。任何帮助将不胜感激。

回答

0

好的。所以,我是个白痴。

的问题在这里:

def funcParser(funcs : immutable.Set[Func]) : Parser[Func] = { 
    val funcsByName = funcs.map(func => (func.name, func)).toMap 
    NotSpace.examples(funcsByName.keySet).map(funcsByName) 
} 

NotSpace可以产生不包含在钥匙funcsByName项目,挑起了NoSuchElementException时结果作为一个关键是Map成功的,有效的结果。解决方案是使用一系列字面解析器链接在一起|

def funcParser(funcs : immutable.Set[Func]) : Parser[Func] = { 
    val funcsByName = funcs.map(func => (func.name, func)).toMap 
    val baseParser = funcsByName.keySet.foldLeft(failure("not a function name") : Parser[String])((nascent, next) => nascent | literal(next)) 
    baseParser.map(processedNamesToFunctions) 
} 
相关问题