命名参数列表解析之前的位置 [英] Positional before Named argument list parsing

查看:97
本文介绍了命名参数列表解析之前的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

How would you do that in the parser combinators

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

推荐答案

好的,这是思维方法

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))))

这篇关于命名参数列表解析之前的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆