Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    zombiq
    @zombiq
    Thank you. I will spend more time trying, but at this moment:
    [error] ParserSpec.scala:24:51: No implicit view available from fastparse.package.P[Any] => fastparse.package.P[Unit].
    [error]       def addEnd[_: P, T](p: => P[T]): P[T] = P(p ~ End)
    [error]                                                 ^
    The test function definition with parser call and the parser definition are located in different scala objects
    bdanielby
    @bdanielby
    Here's a standalone test example:
    package learn
    import fastparse._, NoWhitespace._
    
    object AddEnd extends App {
      def addEnd[_: P, T](p: => P[T]): P[T] = P(p ~ End)
      def parseABC[_: P]: P[String] = P("abc".!)
      println(parse("abc", x => addEnd(parseABC(x))(x)))
    }
    bdanielby
    @bdanielby
    That works for me with Scala 2.12.10 and libraryDependencies += "com.lihaoyi" %% "fastparse" % "2.2.2"
    zombiq
    @zombiq
    I found the problem: missing import NoWhitespace (or implicit val/def whitespace) in the scope, where parse function is called.
    Thanks a lot!
    bdanielby
    @bdanielby
    Great!
    The error message pointed to ~ which handles whitespace and thus requires an implicit whitespace handler.
    zombiq
    @zombiq
    If there are three scopes (scala objects), one where the myParser is defined, second where addEnd is defined and the third, where parse is called, only the 3rd one import of implicit val whitespace applies?
    This would imply, that you cannot mix different whitespaces when composing complicated parser
    bdanielby
    @bdanielby
    I think the implicit at the call site (of ~) should apply. The implicit is in the signature of ~. https://github.com/lihaoyi/fastparse/blob/master/fastparse/src/fastparse/package.scala#L132
    Let's try it out.
    It works for me as expected:
    package learn
    import fastparse._
    
    object TryAddEnd extends App {
      import NoWhitespace._
    
      def parseABC[_: P]: P[String] = P("abc".!)
      println(parse("abc    ", x => AddEnd.addEnd(parseABC(x))(x)))
    }
    
    
    object AddEnd {
      //import NoWhitespace._
      import SingleLineWhitespace._
    
      def addEnd[_: P, T](p: => P[T]): P[T] = P(p ~ End)
    }
    If you exchange the two imports in AddEnd, a parse failure will result.
    zombiq
    @zombiq
    Perfect.. so you may mix whitespace handlers freely
    bdanielby
    @bdanielby
    Yes.
    So three implicits are involved, the one we named x above, which is ctx in https://github.com/lihaoyi/fastparse/blob/master/fastparse/src/fastparse/package.scala#L132 , the whitespace handler we discussed and some internal sequencer.
    But most combinators (and our parsers) need just one: ctx.
    Gabriel Díaz
    @gdiazlo_twitter
    hello, given a production like P(("(" ~ mySymbol ~/ myOtherP.rep(1) ~ ")")) how can I make this rule to fail if there is one myOtherP invalid, or how can make it continue to parse until the closing ) or fail, so the other branches could try? thanks!
    There is a simmilar question in an issue on github
    Gabriel Díaz
    @gdiazlo_twitter
    Seems a recursive approach works, instead of rep, I created a new production like def myPF = P( myP | myP myPF) and it seems work as expected, instead of the .rep macro
    bdanielby
    @bdanielby

    Hi @lihaoyi, I don't fully understand this paragraph in the fastparse documentation:

    Note that the function given to .flatMap is evaluated every time this parser is tried. You should be conscious of the cost of re-creating the resultant parser every time, since FastParse parsers are somewhat expensive to initialize despite being fast per-run. If possible, store the parsers somewhere before-hand or memo-ize/cache them to avoid initializing them wastefully."

    Does this affect all parser functions depending on parameters like

    def rightTag[_: P](s: String) = P( "</" ~ s.! ~ ">" )

    or just lambda-functions passed to flatMap?

    I mean, what is the difference between these two parser functions regarding the fastparse-initializaton:
    def leftTag[_: P] = P( "<" ~ (!">" ~ AnyChar).rep(1).! ~ ">" )
    
    def rightTag[_: P](s: String) = P( "</" ~ s.! ~ ">" )
    Aren't both of them initialized each time they're called?

    Or is this about the missing P(...) wrapper in a lambda-function as in

    leftTag.flatMap(s => rightTag(s))

    ?

    Li Haoyi
    @lihaoyi
    i think thst paragraph is out of date and no longer applies. It made sense for fastparse 1.x, it is no longer necessary for fastparse 2.x
    bdanielby
    @bdanielby
    Ah, thank you very much. That helped me a lot.
    I'm relieved :)
    Joerg von Roos
    @jvr-ks
    def replaceAllPattern[_: P]   ... catch something .!

    gives me back:
    Parsed.Success(value, successIndex)

    def replaceAllMultiPattern[_: P] = P(replaceAllPattern.rep(1))

    gives me back:
    Parsed.Success(Seq(value), successIndexMulti)
    but successIndexMulti is not a sequence, but an Int
    so the successIndex information of the individual catched parts is lost.
    How can I get the individual successIndex of the catched parts?

    Joerg von Roos
    @jvr-ks
    ~ Index ~ did it.
    Tim Pigden
    @TimPigden
    Hi there. I'm just looking at fastparse. Is there a dotty version likely? I'm not too concerned about performance - could one be achieved simply by hacking away the macros?
    Also, does it run with graalvm (not native)?
    Andrew Richards
    @ajrnz
    @TimPigden I was just thinking that myself. It seems like the logical first step. It seems to be mostly inlining anyway which is much easier/cleaner in scala3.
    Li Haoyi
    @lihaoyi
    It would likely be a workable port, but AFAIK nobody has completed it yet
    FastParse proper is only 3200 lines of code. It's not a huge library
    it took 900 commits and the better part of a decade to write that 3200 lines of code tho :P
    but that shouldn't affect how hard it is to port to scala3
    Tim Pigden
    @TimPigden

    can something like this be made to work:

      def string[_: P]: P[String] = P("\""~~/ CharsWhile(_ !='"',0).! ~~"\"")
    
      def stringNel[_: P]: P[NonEmptyList[String]] =(string ~ (comma ~ string).rep)
        .map(tup => NonEmptyList.of(tup._1, tup._2:_*))
    
      def pNel[_: P, T](inner: P[T]): P[NonEmptyList[T]] = (inner ~ (comma ~ inner).rep)
        .map(tup => NonEmptyList.of(tup._1, tup._2:_*))
    
      def pNelString[_: P]: P[NonEmptyList[String]] = pNel(string)
    // my tests this one passes
      def testStringNel = test("stringNel")(
        doTest(fastparse.parse(""""a","b"""", stringNel(_)), NonEmptyList.of("a", "b")))
    
    // but this fails with Nel of ("a") 
      def testPNel = test("stringNel")(
        doTest(fastparse.parse(""""a","b"""", pNelString(_)), NonEmptyList.of("a", "b")))

    I don't understand why the two are different. Can I pass a parser to another parser like this or should I be doing something else to get the same effect?

    Li Haoyi
    @lihaoyi
    @TimPigden you want inner: => P[T]
    it needs to be a by-name param, because parsers are side effecting methods rather than immutable values
    Tim Pigden
    @TimPigden
    Hi @lihaoyi ahah! Side-effects - life on the wild side. Thanks for the quick response, that seems to fix it
    Li Haoyi
    @lihaoyi
    yeah, the price we pay for performance :)
    Sakib Hadžiavdić
    @sake92
    Does anyone have code example for parsing string as Some()) ?
    notice the other closed brace inside
    should be Option[String] with a ")" inside
    cr1stianborta
    @cr1stianborta
    Hello. Is there a way to parse until the last occurrence of a char? Like, e.g., have have this string "a-b-c- d- ffff" and I want to remove the spaces only after the last "-". Any idea will be highly appreciated. Thank you!
    bdanielby
    @bdanielby
    Try this:
    def anyFollowedByMinus[_: P]: P[String] = P((CharsWhile(c => c != '-', 0) ~ "-").rep.!)
    bdanielby
    @bdanielby
    @sake92 What about this?
      def closingParen[_: P]: P[Option[String]] = P(")".!).map(s => Some(s))