2013-07-03 14 views
6

Chciałbym zaimplementować analizator składni dla określonego języka za pomocą łączników Scala Parser. Jednak oprogramowanie, które skompiluje ten język, nie implementuje całej funkcjonalności języka, więc chciałbym zawodzić, jeśli te funkcje są używane. Starałem się wykuć mały przykład poniżej:Błędy i niepowodzenia w łącznikach Scala Parser Kombinatory

object TestFail extends JavaTokenParsers { 
    def test: Parser[String] = 
    "hello" ~ "world" ^^ { case _ => ??? } | 
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" } 
} 

tj parser powiedzie na „Hello” + jakiś identyfikator, ale nie powiedzie się, jeśli identyfikator jest „świat”. Widzę, że istnieją parsery fail() i err() w klasie Parsers, ale nie mogę wymyślić, jak z nich korzystać, ponieważ zwracają Parser [Nothing] zamiast String. Dokumentacja nie wydaje się pokrywać takim przypadku należy ...

Odpowiedz

7

W tym przypadku chcesz err, nie failure, ponieważ jeżeli pierwszy parser w alternatywy nie będzie po prostu przejść do drugiego, który nie jest tym, czego chcieć.

Innym problemem jest to, że ^^ jest odpowiednikiem map, ale chcesz flatMap, ponieważ err("whatever") jest Parser[Nothing], a nie Nothing. Można użyć metody flatMap na Parser, ale w tym kontekście jest to bardziej idiomatyczne używać (całkowicie równoważny) >> operator:

object TestFail extends JavaTokenParsers { 
    def test: Parser[String] = 
    "hello" ~> "world" >> (x => err(s"Can't say hello to the $x!")) | 
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" } 
} 

Albo trochę prościej:

object TestFail extends JavaTokenParsers { 
    def test: Parser[String] = 
    "hello" ~ "world" ~> err(s"Can't say hello to the world!") | 
    "hello" ~ ident ^^ { case "hello" ~ id => s"hi, $id" } 
} 

Albo podejście powinno rób co chcesz.

+0

To jest dokładnie to, czego szukasz. Czy operatorzy >>, ~> (i <~) są udokumentowani gdzieś (poza Scaladoc, który nie był dla mnie wystarczająco szczegółowy)? – scand1sk

+0

@ scand1sk: Zobacz dokumentację w klasie ['Parsers # Parser'] (http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.Parsers$Parser). – senia

+1

Chyba "cześć" ~ "świat" >> "to literówka, powinno być" "witaj" ~> "świat" >> "aby użyć' $ x'. – senia

3

Można użyć ^? metody:

object TestFail extends JavaTokenParsers { 
    def test: Parser[String] = 
    "hello" ~> ident ^? (
     { case id if id != "world" => s"hi, $id" }, 
     s => s"Should not use '$s' here." 
) 
} 
+0

Niestety, to rozwiązanie byłoby zbyt uciążliwe w moim projekcie globalnego parsera ... – scand1sk

+0

@ scand1sk: '>>' jest najlepszym rozwiązaniem w twoim przypadku. Ale '^?' Pozwala ci użyć metody dodawania takiej jak ta: 'case _ ~ id, jeśli isValidId (id) =>'. – senia

Powiązane problemy