Skip to content

Commit f4cde10

Browse files
Roman Gonzalez & Tatsuhiro Ujihisaroman
authored andcommitted
Migration to protocol-monads
1 parent e0bb563 commit f4cde10

File tree

10 files changed

+265
-234
lines changed

10 files changed

+265
-234
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/pom.xml
2+
/pom.xml.asc
23
*jar
34
/lib
45
/classes

project.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
:license {:name "Eclipse Public License"
77
:url "http://www.eclipse.org/legal/epl-v10.html"}
88
:dependencies [[org.clojure/clojure "1.5.1"]
9-
[org.clojure/algo.monads "0.1.4"]]
9+
[net.clojure/monads "1.0.3-SNAPSHOT"]
10+
[org.clojure/algo.monads "0.1.4"]
11+
]
1012
:dev-dependencies [[lein-autodoc "0.9.0"]
1113
[marginalia "0.7.0-SNAPSHOT"]
1214
[lein-marginalia "0.7.0-SNAPSHOT"]])

src/zetta/combinators.clj

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
(ns zetta.combinators
22
(:refer-clojure :exclude [replicate])
3-
(:require [clojure.core :as core])
4-
(:use [clojure.algo.monads :only [m-seq]])
5-
3+
(:require [clojure.core :as core]
4+
[monads.core :as monad])
65
(:use zetta.core))
76

87
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -40,8 +39,7 @@
4039
(defn replicate
4140
"Apply the given parser 'p' 'n' times, returning every result."
4241
[n p]
43-
(with-parser
44-
(m-seq (core/replicate n p))))
42+
(monad/seq (core/replicate n p)))
4543

4644
(defn option
4745
"Applies parser p to the input, if p fails then default-val is returned."
@@ -94,4 +92,3 @@
9492
"Skip one or more applications of parser p."
9593
[p]
9694
(*> p (skip-many p)))
97-

src/zetta/core.clj

Lines changed: 80 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
(ns zetta.core
2-
(:use [clojure.algo.monads
3-
:only
4-
[defmonad defmonadfn domonad with-monad m-seq]]))
2+
(:require [monads.macros :as monad-macro])
3+
(:require [monads.core :as monad]
4+
[clojure.algo.monads
5+
:refer
6+
[defmonad defmonadfn domonad with-monad m-seq]])
7+
^:clj (:import [clojure.lang IFn]))
58

69
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
710
;;
@@ -99,6 +102,45 @@
99102
[input0 more0 input1 more1 f]
100103
(f (concat input0 input1) (concat-more more0 more1)))
101104

105+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
106+
;;
107+
;; ## Parser Monad implementation
108+
;;
109+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
110+
111+
(declare always)
112+
(declare bind-parsers)
113+
(declare fail-parser)
114+
(declare join-parsers)
115+
116+
(defrecord Parser [f]
117+
IFn
118+
;; (invoke [this_ a] (println "1) ERROR: " a))
119+
;; (invoke [this_ a b] (println "2)ERROR: " a b))
120+
;; (invoke [this_ a b c] (println "3) ERROR: " a b c))
121+
(invoke [this_ input0 more0 err-fn ok-fn]
122+
;; (println "4)" input0 more0 err-fn ok-fn)
123+
(f input0 more0 err-fn ok-fn))
124+
125+
^:clj
126+
(applyTo [this args] (clojure.lang.AFn/applyToHelper this args))
127+
128+
monad/Monad
129+
(do-result [self a]
130+
(always a))
131+
132+
(bind [self f]
133+
(bind-parsers self f))
134+
135+
monad/MonadZero
136+
(zero [_]
137+
(fail-parser "MonadZero/zero"))
138+
139+
(plus-step [self ps]
140+
(reduce join-parsers self ps)))
141+
142+
143+
102144
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
103145
;;
104146
;; ## Basic parsers primitives
@@ -120,15 +162,17 @@
120162
"Parser that will always fail, you may provide an error message msg that
121163
will be shown on the final result."
122164
[msg]
123-
(fn failed-parser [input0 more0 err-fn _ok-fn]
124-
#(err-fn input0 more0 [] (str "Failed reading: " msg))))
165+
(Parser.
166+
(fn failed-parser [input0 more0 err-fn _ok-fn]
167+
#(err-fn input0 more0 [] (str "Failed reading: " msg)))))
125168

126169
(defn always
127170
"Returns a parser that will always succeed, this parser will return the
128171
parameter given."
129172
[a]
130-
(fn new-parser [input0 more0 err-fn ok-fn]
131-
#(ok-fn input0 more0 a)))
173+
(Parser.
174+
(fn new-parser [input0 more0 _err-fn ok-fn]
175+
#(ok-fn input0 more0 a))))
132176

133177
(defn bind-parsers
134178
"Receives a parser and a continuation function, the result of the parser is
@@ -141,10 +185,11 @@
141185
(bind-parsers (char \\a) (fn [achr] (always \"hello\")))
142186
"
143187
[p f]
144-
(fn parser-continuation [input0 more0 err-fn ok-fn0]
145-
(letfn [
146-
(ok-fn [input1 more1 a] ((f a) input1 more1 err-fn ok-fn0))]
147-
(p input0 more0 err-fn ok-fn))))
188+
(Parser.
189+
(fn parser-continuation [input0 more0 err-fn ok-fn0]
190+
(letfn [(ok-fn [input1 more1 a]
191+
((f a) input1 more1 err-fn ok-fn0))]
192+
(p input0 more0 err-fn ok-fn)))))
148193

149194
(defn join-parsers
150195
"Merges two parsers together and returns a new parser that will execute
@@ -156,36 +201,23 @@
156201
(join-parsers (char \\a) (char \\b))
157202
"
158203
[p1 p2]
159-
(fn m-plus-parser [input0 more0 err-fn0 ok-fn]
160-
(letfn [
161-
(err-fn [input1 more1 _ _]
162-
(p2 input1 more1 err-fn0 ok-fn))]
163-
(p1 input0 more0 err-fn ok-fn))))
164-
165-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
166-
;;
167-
;; ## Parser Monad implementation
168-
;;
169-
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
170-
171-
(defmonad parser-m
172-
[ m-result (fn result-fn [a]
173-
(always a))
174-
175-
m-bind (fn bind-fn [p f]
176-
(bind-parsers p f))
177-
178-
m-zero (fail-parser "m-zero")
179-
180-
m-plus (fn m-plus-fn [p1 p2]
181-
(join-parsers p1 p2))])
204+
(Parser.
205+
(fn m-plus-parser [input0 more0 err-fn0 ok-fn]
206+
(letfn [
207+
(err-fn [input1 more1 _ _]
208+
(p2 input1 more1 err-fn0 ok-fn))]
209+
(p1 input0 more0 err-fn ok-fn)))))
182210

183211
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
184212
;;
185213
;; ## Parser building macros
186214
;;
187215
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
188216

217+
(def parser-monad always)
218+
(def dummy-parser (parser-monad nil))
219+
220+
;; TODO: How do we translate this to ProtocolMonads?
189221
(defmacro with-parser
190222
"Allows the use of monadic functions m-bind and m-result which are
191223
binded to the parser-m monad."
@@ -196,7 +228,7 @@
196228
"Allows the use of 'domonad' statements with the m-bind and m-result
197229
functions binded to the parser-m monad."
198230
[steps result]
199-
`(domonad parser-m ~steps ~result))
231+
`(monad-macro/do always ~steps ~result))
200232

201233
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
202234
;;
@@ -216,16 +248,17 @@
216248
[input0 _more0 result]
217249
(ResultDone. input0 result))
218250

219-
(defn prompt
251+
(def prompt
220252
"This is parser is used to return continuations (when there is not
221253
enough input available for the parser to either succeed or fail)."
222-
[input0 _more0 err-fn ok-fn]
223-
(with-meta
224-
(fn [new-input]
225-
(if (empty? new-input)
226-
(p-trampoline err-fn input0 complete)
227-
(p-trampoline ok-fn (concat input0 (seq new-input)) incomplete)))
228-
{:stop true}))
254+
(Parser.
255+
(fn prompt [input0 _more0 err-fn ok-fn]
256+
(with-meta
257+
(fn [new-input]
258+
(if (empty? new-input)
259+
(p-trampoline err-fn input0 complete)
260+
(p-trampoline ok-fn (concat input0 (seq new-input)) incomplete)))
261+
{:stop true}))))
229262

230263
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
231264
;;
@@ -302,9 +335,10 @@
302335
303336
Where `number` is a parser that will return a number from the parsed input."
304337
[f & more]
305-
(with-parser
306-
(m-bind (m-seq more) (fn [params]
307-
(m-result (apply f params))))))
338+
(bind-parsers
339+
(monad/seq always more)
340+
(fn [params]
341+
(always (apply f params)))))
308342

309343
(def <|>
310344
"Alias for join-parsers function."

src/zetta/parser/seq.clj

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
(:refer-clojure
33
:exclude [ensure get take take-while char some replicate])
44
(:require [clojure.core :as core]
5-
[clojure.string :as str])
6-
5+
[clojure.string :as str]
6+
[monads.core :as monad])
77
(:use zetta.core)
8-
(:use zetta.combinators))
8+
(:use zetta.combinators)
9+
(:import [zetta.core Parser]))
910

1011
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1112
;;
@@ -25,49 +26,53 @@
2526

2627
(def demand-input
2728
"Basic parser that will ensure the request of more input via a continuation."
28-
(fn [input0 more0 err-fn0 ok-fn0]
29-
(if (complete? more0)
30-
#(err-fn0 input0 more0 ["demand-input"] "not enough input")
31-
(letfn [
32-
(err-fn [input more]
33-
#(err-fn0 input more ["demand-input"] "not enough input"))
34-
(ok-fn [input more]
35-
#(ok-fn0 input more nil))]
36-
(prompt input0 more0 err-fn ok-fn)))))
29+
(Parser.
30+
(fn [input0 more0 err-fn0 ok-fn0]
31+
(if (complete? more0)
32+
#(err-fn0 input0 more0 ["demand-input"] "not enough input")
33+
(letfn [
34+
(err-fn [input more]
35+
#(err-fn0 input more ["demand-input"] "not enough input"))
36+
(ok-fn [input more]
37+
#(ok-fn0 input more nil))]
38+
(prompt input0 more0 err-fn ok-fn))))))
3739

3840
(def want-input?
3941
"Parser that returns `true` if any input is available either immediately or
4042
on demand, and `false` if the end of all input has been reached.
4143
4244
**WARNING**: This parser always succeeds."
43-
(fn [input0 more0 _err-fn ok-fn0]
44-
(cond
45+
(Parser.
46+
(fn [input0 more0 _err-fn ok-fn0]
47+
(cond
4548
(not (empty? input0)) #(ok-fn0 input0 more0 true)
4649
(complete? more0) #(ok-fn0 input0 more0 false)
4750
:else
48-
(letfn [(err-fn [input more] #(ok-fn0 input more false))
49-
(ok-fn [input more] #(ok-fn0 input more true))]
50-
(prompt input0 more0 err-fn ok-fn)))))
51+
(letfn [(err-fn [input more] #(ok-fn0 input more false))
52+
(ok-fn [input more] #(ok-fn0 input more true))]
53+
(prompt input0 more0 err-fn ok-fn))))))
5154

5255
(defn ensure
5356
"If at least `n` items of input are available, return the current input,
5457
otherwise fail."
5558
[n]
56-
(fn [input0 more0 err-fn ok-fn]
57-
(if (>= (count input0) n)
58-
#(ok-fn input0 more0 input0)
59-
(with-parser
60-
((>> demand-input (ensure n)) input0 more0 err-fn ok-fn)))))
59+
(Parser.
60+
(fn [input0 more0 err-fn ok-fn]
61+
(if (>= (count input0) n)
62+
#(ok-fn input0 more0 input0)
63+
((>> demand-input (ensure n)) input0 more0 err-fn ok-fn)))))
6164

6265
(def get
6366
"Returns the input given in the `zetta.core/parse` function."
64-
(fn [input0 more0 _err-fn ok-fn]
65-
#(ok-fn input0 more0 input0)))
67+
(Parser.
68+
(fn [input0 more0 _err-fn ok-fn]
69+
#(ok-fn input0 more0 input0))))
6670

6771
(defn put [s]
6872
"Sets a (possibly modified) input into the parser state."
69-
(fn [_input0 more0 _err-fn ok-fn]
70-
#(ok-fn s more0 nil)))
73+
(Parser.
74+
(fn [_input0 more0 _err-fn ok-fn]
75+
#(ok-fn s more0 nil))))
7176

7277
(defn satisfy?
7378
"Parser that succeeds for any item for which the predicate `pred` returns
@@ -172,7 +177,7 @@
172177
:then [result (take-while-loop (conj acc pre))]
173178
:else [result (always (conj acc pre))]
174179
]
175-
:else [result (m-result (conj acc pre))]]
180+
:else [result (monad/do-result dummy-parser (conj acc pre))]]
176181
result))]
177182
(<$> (comp #(apply core/concat %) core/reverse)
178183
(take-while-loop []))))
@@ -334,21 +339,22 @@
334339
(def end-of-input
335340
"Parser that matches only when the end-of-input has been reached, otherwise
336341
it fails. Returns a nil value."
337-
(fn [input0 more0 err-fn0 ok-fn0]
338-
(if (empty? input0)
339-
(if (complete? more0)
340-
#(ok-fn0 input0 more0 nil)
341-
(letfn [
342-
(err-fn [input1 more1 _ _]
343-
(add-parser-stream input0 more0 input1 more1
344-
(fn [input2 more2]
345-
(ok-fn0 input2 more2 nil))))
346-
(ok-fn [input1 more1 _]
347-
(add-parser-stream input0 more0 input1 more1
348-
(fn [input2 more2]
349-
(err-fn input2 more2 [] "end-of-input"))))]
350-
(demand-input input0 more0 err-fn ok-fn)))
351-
#(err-fn0 input0 more0 [] "end-of-input"))))
342+
(Parser.
343+
(fn [input0 more0 err-fn0 ok-fn0]
344+
(if (empty? input0)
345+
(if (complete? more0)
346+
#(ok-fn0 input0 more0 nil)
347+
(letfn [
348+
(err-fn [input1 more1 _ _]
349+
(add-parser-stream input0 more0 input1 more1
350+
(fn [input2 more2]
351+
(ok-fn0 input2 more2 nil))))
352+
(ok-fn [input1 more1 _]
353+
(add-parser-stream input0 more0 input1 more1
354+
(fn [input2 more2]
355+
(err-fn input2 more2 [] "end-of-input"))))]
356+
(demand-input input0 more0 err-fn ok-fn)))
357+
#(err-fn0 input0 more0 [] "end-of-input")))))
352358

353359
(def at-end?
354360
"Parser that never fails, it returns `true` when the end-of-input
@@ -360,5 +366,3 @@
360366
This parser returns a nil value."
361367
(<|> (*> (char \newline) (always nil))
362368
(*> (string "\r\n") (always nil))))
363-
364-

0 commit comments

Comments
 (0)