0

你将如何在解析器组合器中做到这一点

def namedAfterPos[P, N](pos: Parser[P], nmd: Parser[N], sep: Parser[_] = ",") = ???

List("a", "a,a,a", "a,a,a=b,a=b", "a=b, a=b") map (_ parseWith namedAfterPos("a", "a=b")) map {case Success(res, _) => res}
val Failure("positional is not expected after named", pos) = "a,a=b,a" parseWith namedAfterPos("a", "a=b")
4

1 回答 1

0

好的,这是思维方式

scala> def namedAfterPos[P, N](pos: Parser[P], nmd: Parser[N], sep: Parser[_] = ",") = {

  // NB! http://stackoverflow.com/q/38041980/6267925 disucsses that that defining type 
  // aliases for result type is a bad programming practice that we use! Nevertheless,
  // define result type -- first comes the list of positional params, second - named.
  type Res = (List[P], List[N]); // named and positional have different types

  def namedOrPositional(positional: Boolean, acc: Res): Parser[Res] = {

    // once association accepted, we'll try the comma and go for next or exit
    def recur(positional: Boolean, acc: Res) =
       (sep flatMap {_ => namedOrPositional(positional, acc)}) | success(acc); 

    // named association should always be acceptable - stop accepting positionals when found
    (nmd flatMap {n => recur(false, acc match {case (p,nn)=> (p, n :: nn)})}) | 

    // if named failed - we have positional arg
    (pos flatMap {p => 

      // proceed if positionals are still accepted
      if (positional) recur(true, acc match {case (pp, n) => (p :: pp, n)}) 

      // if they are not - report parsing failure
      else failure("positional is not expected after named")})
  };

  namedOrPositional(true, (Nil, Nil)) // start collecting the args
} 

defined function namedAfterPos
scala> List("a", "a,a,a", "a,a,a=b,a=b", "a=b, a=b") map (
    _ p namedAfterPos("a", "a=b")) map {case Success(res, _) => res} 
res67: List[(List[P], List[N])] = List((List(a), List()), (List(a, a, a), List()), (List(a, a), List(a=b, a=b)), (List(), List(a=b, a=b)))
val Failure("positional is not expected after named", pos) = "a,a=b,a" p namedAfterPos("a", "a=b") 
pos: Input = scala.util.parsing.input.CharSequenceReader@1726cd4

// named param is usually has a form of identifier "=" expr and positionals are expressions
scala> def paredArgList[K,V](name: Parser[K] = identifier, value: Parser[V] = expr) = 
  pared(namedAfterPos(value, name ~ ("=" ~> value) map {case n~v => (n,v)}))  
defined function paredArgList
scala> List("a+b-1", "b=1+1", "a,a+1", "b=3+1,c=c+1", "1,b=g+g,d=123,bd=123+1") map ("(" + _ + ")" p paredArgList()) map {case Success(res, _) => res} 
res70: List[(List[P], List[N])] = List((List(a + b - 1), List()), (List(), List((b,1 + 1))), (List(a + 1, a), List()), (List(), List((c,c + 1), (b,3 + 1))), (List(1), List((bd,123 + 1), (d,123), (b,g + g))))
于 2016-06-26T10:51:45.657 回答