Fork me on GitHub
#malli
<
2022-05-24
>
Ben Sless06:05:19

I'm trying to have mutual recursion with regex schemas and failing pitifully. Any tips?

Ben Sless06:05:03

In this example:

(defn char-range
  [from+to]
  (let [from (long (first from+to))
        to (long (second from+to))]
    (m/-simple-schema
     {:type ::char-range
      :pred (fn [x] (<= from (long x) to))})))

(defn char-seq
  [cs]
  (into [:cat] (mapv (fn [c] [:= c]) cs)))

(m/parse
 (m/schema
  [:schema
   {:registry
    {::digit (char-range "09")
     ::lower-case (char-range "az")
     ::upper-case (char-range "AZ")
     ::letter [:alt ::lower-case ::upper-case]
     ::number [:+ ::digit]
     ::var [:cat ::upper-case [:* ::lower-case]]
     ::boolean [:altn [:true (char-seq "true")] [:false (char-seq "false")]]
     ::atom [:cat ::lower-case [:* ::letter]]
     ::term [:altn
             [:equality [:schema [:ref ::equality]]]
             [:atom ::atom]
             [:var ::var]
             [:number ::number]
             [:boolean ::boolean]
             #_[:structure ::structure]
             #_[:list ::list]
             #_[:string ::string]]
     ::equality [:cat ::var (char-seq " = ") ::term]
     }}
   ::equality])
 (seq "X = Y"))
::equality succeeds but ::term doesn't

jprudent07:05:24

I'm not sure why but I also find out that you can't have :ref in seqexp. Is that your problem ?

jprudent07:05:22

Is it going in a stackoverflow if you remove it ?

jprudent07:05:11

maybe try :orn instead of :altn

Ben Sless09:05:28

That doesn't work

Ben Sless09:05:16

for some reason you also can't wrap the ::term in ::equality with [:schema [:ref ,,]]

Alexis Schad18:05:00

What doesn't succeed? What do you expect?

Alexis Schad18:05:57

I got [[\X []] [\space \= \space] [:var [\Y []]]]

Ben Sless19:05:41

Try replacing ::equality schema with ::term

Alexis Schad20:05:49

I think it's because in ::term you altn only the \space and not the whole input seq. It tries to match \space and don't find any entry. I'll try to add an entry to check that

Alexis Schad20:05:36

(m/parse
 (m/schema
  [:schema
   {:registry
    {::digit (char-range "09")
     ::lower-case (char-range "az")
     ::upper-case (char-range "AZ")
     ::letter [:alt ::lower-case ::upper-case]
     ::number [:+ ::digit]
     ::var [:cat ::upper-case [:* ::lower-case]]
     ::boolean [:altn [:true (char-seq "true")] [:false (char-seq "false")]]
     ::atom [:cat ::lower-case [:* ::letter]]
     ::term [:* [:altn
                 [:equality [:schema [:ref ::equality]]]
                 [:atom ::atom]
                 [:var ::var]
                 [:number ::number]
                 [:boolean ::boolean]
                 [:space [:cat [:= \space]]]
                 [:equals [:cat [:= \=]]]
                 #_[:structure ::structure]
                 #_[:list ::list]
                 #_[:string ::string]]]
     ::equality [:cat ::var (char-seq " = ") ::term]}}
   ::term])
 (seq "X = Y"))
This "works" => [[:var [\X []]] [:space [\space]] [:equals [\=]] [:space [\space]] [:var [\Y []]]]

Ben Sless02:05:13

Well, you changed the semantics of the parser. An "equals" is defined in the bnf as "atom = term"

Ben Sless02:05:40

I don't want to do extra parsing afterwards

Ben Sless02:05:36

”X = Y” should be tagged as an equality term

Alexis Schad07:05:06

I know, that's why I put " around works. I was trying to explain the reason why it doesn't work. Btw you can’t do recursive seqexp in malli actually. If you want to exclusively use Malli to parse, you can replace the ref to ::term with a [:* any?] and call the parser again on that. You can also create your own schema but it’s harder I think.

Ben Sless08:05:13

Why can't I have recursive seqex schemas, though?

Alexis Schad08:05:14

Don't know, not a malli expert. But I think it's due to technical limitation. Malli explicitely prevent it with ::potentially-recursive-seqex error, though it is theorically possible.

👍 1
escherize05:05:08

There’s more info here in this discussion: https://github.com/metosin/malli/pull/317