2011-02-08 12 views
8

così ho qualcosa di simile a questo:come fare Scala parser sicuro

class MyParser extends JavaTokenParsers { 
    var m = new HashMap[String,String] 
    def store = ("var" ~> ident "=") ~ ident ^^ { 
     case k ~ v => m += k -> v 
    } 
    def stored_val = ident ^^ { 
     case k => m(k) 
    } 
} 

E il mio problema è che quello che voglio fare è avere il parser stored_val fallire in modo che altri parser hanno la possibilità di abbinare il ingresso. Ma quello che succede ora è che la mappa getta quando non riesce a trovare il valore.

ho cercato attuazione stored_val come questo:

def stored_val = ident => { 
    case k => if (m.contains(k)) m(k) else failure("identifier not found") 
} 

Ma il problema è che il fallimento restituisce Parser [Niente] che è un tipo diverso rispetto a String.

+1

Ho esattamente lo stesso problema e voglio fallire in modo esplicito il parser. Come si suppone che il fallimento venga usato se il suo tipo Nothing non è compatibile con qualcosa? – hotzen

risposta

3

Se si desidera controllare il contenuto dei caratteri oltre la regex, è possibile controllare StandardTokenParser. In particolare,

def elem (kind: String, p: (Elem) ⇒ Boolean) : Parser[Elem] 

Un parser corrispondenti elementi di input che soddisfano un dato predicato elem(kind, p) riesce se l'ingresso inizia con un elemento per il quale e'p(e) è vero.

Edit: Per esempi di standard Token Parser, controlla l'articolo di Jim McBeath su Scala Parser Combinators. Ho apportato una rapida modifica al primo esempio per dimostrare elem. E 'un semplice parser che richiede solo somma di numeri dispari:

import scala.util.parsing.combinator.syntactical._ 
import scala.util.parsing.combinator._ 

trait Expression 
case class EConstant(value: Int) extends Expression 
case class EAdd(lhs: Expression, rhs: Expression) extends Expression 

object ExpressionParser extends StandardTokenParsers { 
    lexical.delimiters ++= List("+") 

    def oddValue = elem("odd", { x => x.toString.toInt % 2 == 1 }) ^^ { 
    x => EConstant(x.toString.toInt) } 
    def value = numericLit ^^ { x => EConstant(x.toInt) } 

    def sum = oddValue ~ "+" ~ oddValue ^^ { case left ~ "+" ~ right => 
      EAdd(left, right) } 

    def expr = (sum | value) 

    def parse(s:String) = { 
    val tokens = new lexical.Scanner(s) 
    phrase(expr)(tokens) 
    } 

    def apply(s:String): Expression = parse(s) match { 
    case Success(tree, _) => tree 
    case e: NoSuccess => 
     throw new IllegalArgumentException("Bad syntax: "+s) 
    } 
} 

Salva quanto sopra come ExpressionParser.scala e caricarlo nella REPL come segue:

scala> :l ExpressionParser.scala  
Loading ExpressionParser.scala... 
import scala.util.parsing.combinator.syntactical._ 
import scala.util.parsing.combinator._ 
defined trait Expression 
defined class EConstant 
defined class EAdd 
defined module ExpressionParser 

scala> ExpressionParser("2 + 2") 
java.lang.IllegalArgumentException: Bad syntax: 2 + 2 
    at ExpressionParser$.apply(<console>:42) 
    at .<init>(<console>:24) 
    at .<clinit>(<console>) 
    at RequestResult$.<init>(<console>:9) 
    at RequestResult$.<clinit>(<console>) 
    at RequestResult$scala_repl_result(<console>) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
    at scala.util.con... 
scala> ExpressionParser("1 + 1") 
res3: Expression = EAdd(EConstant(1),EConstant(1)) 
+0

@Kevin ha detto: ho visto quel metodo, ma non ero esattamente sicuro di come usarlo. Puoi fornire un piccolo esempio? Essenzialmente voglio che il mio predicato restituisca true se m.contains (k) == true. – jjnguy

+0

Ho visto quel metodo, ma non ero esattamente sicuro di come usarlo. Puoi fornire un piccolo esempio? Essenzialmente voglio che il mio predicato restituisca true se m.contains (k) == true. –

8

È possibile utilizzare il ^? Combinator che accetta una funzione parziale (Scaladoc):

def stored_val: Parser[String] = ident ^? { 
    case k if m.contains(k) => m(k) 
} 

ho spinto un full example con tests a Github.

Problemi correlati