2013-07-03 10 views
6

Vorrei implementare un parser per alcune lingue definite utilizzando Scala Parser Combinators. Tuttavia, il software che compilerà la lingua non implementa tutte le funzionalità della lingua, quindi mi piacerebbe fallire se si utilizzano queste funzionalità. Ho cercato di creare un piccolo esempio di seguito:Errori e malfunzionamenti in Parser Combinators di Scala

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

cioè il parser riesce a "ciao" + un identificativo, ma non riesce se l'identificatore è "mondo". Vedo che esistono parser fail() ed err() nella classe Parsers, ma non riesco a capire come usarli, poiché restituiscono Parser [Nothing] al posto di una stringa. La documentazione non sembra coprire questo caso d'uso ...

risposta

7

In questo caso si vuole err, non failure, dal momento che se il primo parser in una disgiunzione non ti basta passare alla seconda, che non è quello che volere.

L'altra questione è che ^^ è l'equivalente di map, ma si desidera flatMap, dal momento che è un err("whatever")Parser[Nothing], non un Nothing. È possibile utilizzare il metodo flatMap su Parser, ma in questo contesto è più idiomatico per utilizzare il (completamente equivalente) >> 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" } 
} 

Oppure, un po 'più semplice:

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" } 
} 

Entrambi gli approcci dovrebbero Fai quello che vuoi.

+0

E 'esattamente quello che stavo cercando. Gli operatori >>, ~> (e <~) sono documentati da qualche parte (al di fuori dello Scaladoc che non era abbastanza dettagliato per me)? – scand1sk

+0

@ scand1sk: vedere la classe ['Parsers # Parser'] (http://www.scala-lang.org/api/current/index.html#scala.util.parsing.combinator.Parsers$Parser) per la documentazione. – senia

+1

Immagino '" ciao "~" mondo ">>' è un refuso, ci dovrebbe essere '" ciao "~>" mondo ">>' per usare '$ x'. – senia

3

È possibile utilizzare ^? metodo:

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

Sfortunatamente, questa soluzione sarebbe troppo ingombrante nel mio progetto di parser globale ... – scand1sk

+0

@ scand1sk: '>>' è la soluzione migliore nel tuo caso. Ma '^?' Ti permette di usare un metodo di aggiunta come questo: 'caso _ ~ id se isValidId (id) =>'. – senia

Problemi correlati