zevv / npeg

PEGs for Nim, another take
MIT License
330 stars 22 forks source link

push() captures broken? #50

Closed zevv closed 1 year ago

zevv commented 1 year ago

From EyeCon on IRC:

import std/[strformat, strutils]
import npeg

let tmp = "Z1Z + A1A / B1B + -C1C"

let parser = peg "exp":
  code <- >(?'-' * Alpha * Alnum[2..4]):
    push("Cod " & $1)

  parenExp <- ( "(" * exp * ")" ) ^ 0          

  prefix <- code | parenExp                    

  infix <- >{'/'} * exp ^ 1 | >{'+'} * exp ^ 2: 
    push("Opr " & $1)                           

  exp <- prefix * *infix                        

echo parser.match(tmp.replace(" ", "")).captures
zevv commented 1 year ago

I just took the time to look into this, and I believe that push() is just fine. Your above grammar needs some reworking though; for example the infix rule has two captures, but the push() there only consumes the first using $1.

Let me know if you still need help building your parser, if not I'll close this ticket in a few days.

EyeCon commented 1 year ago

I don't understand, there's an "or" (|) in the line you are talking about, so I thought that is just one capture performed in one of the two alternative ways?

In any case, it does work exactly like that, just without push, like:

import std/[strformat, strutils]
import npeg

let tmp = "Z1Z + A1A / B1B + -C1C"
var cap: seq[string]

let parser = peg "exp":
  code <- >(?'-' * Alpha * Alnum[2..4]):
    cap.add("Cod " & $1)
  parenExp <- ( "(" * exp * ")" ) ^ 0
  prefix <- code | parenExp
  infix <- (>{'/'} * exp ^ 1) | (>{'+'} * exp ^ 2):
    cap.add("Opr " & $1)
  exp <- prefix * *infix
discard parser.match(tmp.replace(" ", ""))
echo cap

# As expected:
# @["Cod Z1Z", "Cod A1A", "Opr +", "Cod B1B", "Cod -C1C", "Opr +", "Opr /"]