awwx.ws

Creating a parser combinator library to parse JSON

Prev: seqContentsNext: many1, implemented

many

I’m not sure how to implement many, so I’ll start with something simpler. optional matches zero or one things:

(def optional (parser)
  (fn (p)
    (iflet (p2 r) (parser p)
      ...)))

If the match succeeds, then I’ll want to return what the parser returned. Since I’m working towards many, and I’ll want many to return a list of the return values for each time the parser matches, I’ll have optional return a list of the one return value:

(def optional (parser)
  (fn (p)
    (iflet (p2 r) (parser p)
      (return p2 (list r))
      ...)))

If the parser doesn’t match, then the optional still succeeds, since it matches zero or one things, so I’ll have it return the empty list:

(def optional (parser)
  (fn (p)
    (iflet (p2 r) (parser p)
      (return p2 (list r))
      (return p nil))))
arc> (show-parse (optional json-number-char) "123")
returning: (#\1) remaining: 23
nil
arc> (show-parse (optional json-number-char) "a123")
returning: nil remaining: a123
nil

So many is like optional, except that it applies the parser to the input over and over again until finally the match fails:

(def many (parser)
  (fn (p)
    ((afn (p a)
       (iflet (s2 r) (parser p)
         (self s2 (cons r a))
         (return p rev.a)))
     p nil)))
arc> (show-parse (many json-number-char) "abc")
returning: nil remaining: abc
nil
arc> (show-parse (many json-number-char) "1abc")
returning: (#\1) remaining: abc
nil
arc> (show-parse (many json-number-char) "12abc")
returning: (#\1 #\2) remaining: abc
nil
arc> (show-parse (many json-number-char) "123abc")
returning: (#\1 #\2 #\3) remaining: abc
nil

Prev: seqContentsNext: many1, implemented


Questions? Comments? Email me andrew.wilcox [at] gmail.com