Re: How to work with the tree produced by (ice-9 peg)'s match-pattern?

Zelphir Kaltstahl <[email protected]>
Newsgroups gmane.lisp.guile.user
Message-ID <[email protected]>
On 04.12.24 13:06, Tomas Volf wrote:
> Hi :)
>
> I recently discovered the (ice-9 peg) module, and it seems really
> useful.  However I have to admit I struggle a bit with processing the
> tree produced by it.
>
> Let me put forward an example:
>
> --8<---------------cut here---------------start------------->8---
> (use-modules (ice-9 peg))
>
> (define-peg-pattern Opt body
>    (and Name Space (+ (and Enum Space)) Default))
>
> (define-peg-pattern Name all
>    (+ Alpha))
> (define-peg-pattern Enum all
>    (+ Alpha))
> (define-peg-pattern Default all
>    (and (ignore "(default: ") (* Alpha) (ignore ")")))
>
> (define-peg-pattern Alpha body
>    (range #\a #\z))
> (define-peg-pattern Space none
>    " ")
> --8<---------------cut here---------------end--------------->8---
>
> Now I can feed it few strings to get the parsed trees:
>
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> (peg:tree (match-pattern Opt "name a b c (default: a)"))
> $11 = ((Name "name") ((Enum "a") (Enum "b") (Enum "c")) (Default "a"))
> scheme@(guile-user)> (peg:tree (match-pattern Opt "name a b c (default: )"))
> $12 = ((Name "name") ((Enum "a") (Enum "b") (Enum "c")) Default)
> scheme@(guile-user)> (peg:tree (match-pattern Opt "name a (default: a)"))
> $13 = ((Name "name") (Enum "a") (Default "a"))
> scheme@(guile-user)> (peg:tree (match-pattern Opt "name a (default: )"))
> $14 = ((Name "name") (Enum "a") Default)
> --8<---------------cut here---------------end--------------->8---
>
> What we see here is that it produces trees in 4 different "shapes",
> depending on the input string.  And I am unsure how to reasonably
> process them.
>
> My current approach looks like:
>
> --8<---------------cut here---------------start------------->8---
> (define process-tree
>    (match-lambda
>      ((('Name name) (('Enum enum) ...) ('Default def))
>       (pk name enum def))
>      ((('Name name) ('Enum enum) ... ('Default def))
>       (pk name enum def))
>      ((('Name name) (('Enum enum) ...) 'Default)
>       (pk name enum #f))
>      ((('Name name) ('Enum enum) ... 'Default)
>       (pk name enum #f))))
> --8<---------------cut here---------------end--------------->8---
>
> Which *does* work:
>
> --8<---------------cut here---------------start------------->8---
> scheme@(guile-user)> (for-each process-tree (list $11 $12 $13 $14))
>
> ;;; ("name" ("a" "b" "c") "a")
>
> ;;; ("name" ("a" "b" "c") #f)
>
> ;;; ("name" ("a") "a")
>
> ;;; ("name" ("a") #f)
> --8<---------------cut here---------------end--------------->8---
>
> However it is very repetitive and the code is pretty hard to work with.
> (Real code even has few more branches.)  And I am not sure how to do a
> better job at this.
>
> It would really simplify things if I would be able to *always* have a
> list of 'Enum, even when there is just a single one.  Same for default.
> I tried keyword-flatten, but probably I just do not understand how to
> use it.  Or maybe (ice-9 match) is just a wrong tool here?
>
> Would someone be able to provide general guidance how to approach this,
> or at least recommend some projects using (ice-9 peg) that I could
> study?
>
> Thanks and have a nice day,
> Tomas

Hello Tomas,

Without getting into the details, perhaps my peg utils module could be useful 
for you:

https://codeberg.org/ZelphirKaltstahl/advent-of-code-2024/src/commit/3f64ee60297ccc89085c9425522bd8b8e83fe99d/utils/peg-tree-utils.scm 


Best regards, Zelphir

-- 
repositories:https://notabug.org/ZelphirKaltstahl,https://codeberg.org/ZelphirKaltstahl
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.