В плагин 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, но я не понимаю, как исправить загадочное исключение, и, как правило, делаю все. Любая помощь будет принята с благодарностью.