Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Performance enhancements and improvement of comments

* Add type annotations to some parsers
* Update the CHANGELOG
* Improve the documentation to be supported by Marginalia
  • Loading branch information...
commit d9fadb26971c9ca86251be2bca1cf06a7e4fc1e9 1 parent 6345b88
@roman roman authored
View
10 CHANGELOG
@@ -1,5 +1,9 @@
= Roman Gonzalez (No release date)
* Fix bug on the number parser, (wasn't parsing one digit numbers)
- * Reimplemented the many parser combinator to reduce StackOverflows
- * Added trampoline support to zetta-parser, hopefully this will avoid
- StackOverflows alltogether :-D
+ * Reimplemented the `many` parser combinator to reduce StackOverflows
+ * Reimplemented CPS functions to be executed using trampoline (massive
+ reduction of StackOverflow errors)
+ * Improved documentation of functions, added missing documentation in some
+ others
+ * Improved considerably the performance by adding type hints
+ * Added marginalia to the dev-dependencies
View
5 project.clj
@@ -1,7 +1,10 @@
(defproject org.van-clj/zetta-parser "0.0.3-SNAPSHOT"
:description "Powerful monadic parser combinator in Clojure (Haskell attoparsec's port)"
:author "Roman Gonzalez"
+ :warn-on-reflection true
:repositories { "sonatype" {:url "https://oss.sonatype.org/content/repositories/snapshots/"}}
:dependencies [[org.clojure/clojure "1.3.0"]
[org.clojure/algo.monads "0.1.3-20120206.105742-1"]]
- :dev-dependencies [[lein-autodoc "0.9.0"]])
+ :dev-dependencies [[lein-autodoc "0.9.0"]
+ [marginalia "0.7.0-SNAPSHOT"]
+ [lein-marginalia "0.7.0-SNAPSHOT"]])
View
22 src/zetta/combinators.clj
@@ -7,18 +7,18 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser combinators
+;; ## Parser combinators
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn <?>
"Allows to add an error message to a given parser p."
- [parser err-msg]
+ [p err-msg]
(fn [input0 more0 err-fn0 ok-fn]
(letfn [
(err-fn [input0 more0 errors msg]
#(err-fn0 input0 more0 (conj errors err-msg) msg))]
- (parser input0 more0 err-fn0 ok-fn))))
+ (p input0 more0 err-fn0 ok-fn))))
(defn many
"Applies zero or more times a parser p."
@@ -31,10 +31,10 @@
result (always (cons h t)) ]]
result))
-(defn choice [ps]
- "It will try to parse the input using each of the
- given parsers, it will halt on the first parser that
- successfuly parse the input."
+(defn choice
+ "Combinator that tries to parse the input using each of the given parsers,
+ it will halt on the first parser that can successfuly parse the input."
+ [ps]
(reduce <|> ps))
(defn replicate
@@ -44,8 +44,7 @@
(m-seq (core/replicate n p))))
(defn option
- "Applies parser p to the input, if p fails then default-val
- is returned."
+ "Applies parser p to the input, if p fails then default-val is returned."
[default-val p]
(<|> p (always default-val)))
@@ -55,6 +54,8 @@
(<$> cons p (many p)))
(defn around
+ "Combinator that will apply the parser 'content' in between the parser
+ 'sep.'"
[sep content]
(*> sep (<* content sep)))
@@ -76,8 +77,7 @@
(always [])))
(defn many-till
- "Applies the parser p zero or more times until the parser end
- is successful."
+ "Applies the parser p zero or more times until the parser end is successful."
[p end]
(<|> (*> end (always []))
(>>= p (fn [h]
View
164 src/zetta/core.clj
@@ -5,7 +5,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser result types
+;; ## Parser result types
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -14,7 +14,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser result query functions
+;; ## Parser result query functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -37,10 +37,16 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser more-input constants
+;; ## Parser more-input constants
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; This contants will serve as flags, and they will tell us if there is
+;; more possible input available to the parser, when parsers require more
+;; input and the `more` parameter has a value of complete, then the parser will
+;; fail, otherwise if the `more` parameter has a value of incomplete, a
+;; continuation function will be returned to continue the parsing.
+
(def
^{:doc "Constant value that indicates if the stream
of the parser is complete (no more input)."}
@@ -52,21 +58,35 @@
incomplete ::incomplete)
(defn complete?
- "Test if equal to the complete constant or not."
+ "Test More flag is equal to the complete constant or not."
[m] (= m complete))
(defn incomplete?
- "Test if equal to the incomplete constant or not."
+ "Test More flag is equal to the incomplete constant or not."
[m] (= m incomplete))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser Monad utility functions
+;; ## Parser utility functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defn- p-trampoline
+ "Exact copy of the `clojure.core/trampoline` function, however it checks if
+ the returned function has a :stop meta to return. This is used by the prompt
+ and parse functions."
+ ([f]
+ (let [ret (f)]
+ (if (and (fn? ret)
+ (-> ret meta :stop not))
+ (recur ret)
+ ret)))
+ ([f & args]
+ (p-trampoline #(apply f args))))
+
(defn- concat-more
- "Monoid mappend function for the More values complete and incomplete."
+ "Merges two More flag values ('complete' and 'incomplete') and returns a
+ new flag value."
[m1 m2]
(cond
(complete? m1) complete
@@ -74,11 +94,28 @@
:else incomplete))
(defn add-parser-stream
- "Concats the input and more flag from two different parsers and calls
+ "Concats the input and `more` flag from two different parsers and calls
the function f with the result."
[input0 more0 input1 more1 f]
(f (concat input0 input1) (concat-more more0 more1)))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; ## Basic parsers primitives
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+;; ### Parsers will be functions that receive 4 parameters:
+;;
+;; * `input`: The stream of characters (or items) we are actually parsing.
+;; * `more` flag: A flag that indicates if there is more input coming up or
+;; not.
+;; * `ok-fn`: A continuation function that will be executed when parsing
+;; has been executed without any failures.
+;; * `err-fn`: A continuation function that will be executed when an error
+;; had occured when parsing.
+
(defn fail-parser
"Parser that will always fail, you may provide an error message msg that
will be shown on the final result."
@@ -86,32 +123,39 @@
(fn failed-parser [input0 more0 err-fn _ok-fn]
#(err-fn input0 more0 [] (str "Failed reading: " msg))))
-(defn- p-trampoline
- "Exact copy of the `clojure.core/trampoline` function,
- however it checks if the returned function has a :stop
- meta to return. This is used by the prompt and
- the parse functions."
- ([f]
- (let [ret (f)]
- ;(println ret)
- (if (and (fn? ret)
- (-> ret meta :stop not))
- (recur ret)
- ret)))
- ([f & args]
- (p-trampoline #(apply f args))))
-
-(defn always [a]
+(defn always
+ "Returns a parser that will always succeed, this parser will return the
+ parameter given."
+ [a]
(fn new-parser [input0 more0 err-fn ok-fn]
#(ok-fn input0 more0 a)))
-(defn bind-parsers [p f]
+(defn bind-parsers
+ "Receives a parser and a continuation function, the result of the parser is
+ going to be given as a parameter to the f function, and this function should
+ return a new parser.
+
+ Example:
+
+ ; Everytime we parse an 'a' character and return a \"hello\" string
+ (bind-parsers (char \\a) (fn [achr] (always \"hello\")))
+ "
+ [p f]
(fn parser-continuation [input0 more0 err-fn ok-fn0]
(letfn [
(ok-fn [input1 more1 a] ((f a) input1 more1 err-fn ok-fn0))]
(p input0 more0 err-fn ok-fn))))
-(defn join-parsers [p1 p2]
+(defn join-parsers
+ "Merges two parsers together and returns a new parser that will execute
+ parser p1, in case this fails, it is going to execute parser p2.
+
+ Example:
+
+ ; Parses either the character a or the character b
+ (join-parsers (char \\a) (char \\b))
+ "
+ [p1 p2]
(fn m-plus-parser [input0 more0 err-fn0 ok-fn]
(letfn [
(err-fn [input1 more1 _ _]
@@ -120,7 +164,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser Monad implementation
+;; ## Parser Monad implementation
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -138,36 +182,42 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parser building macros
+;; ## Parser building macros
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro with-parser
- "Allows the use of monadic functions with the parser-m monad binded
- to m-bind and m-result."
+ "Allows the use of monadic functions m-bind and m-result which are
+ binded to the parser-m monad."
[& forms]
`(with-monad parser-m ~@forms))
(defmacro do-parser
- "Allows the use of monadic do statements with the parser-m monad binded
- to m-bind and m-result."
+ "Allows the use of 'domonad' statements with the m-bind and m-result
+ functions binded to the parser-m monad."
[steps result]
`(domonad parser-m ~steps ~result))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Continuation Results
+;; ## Continuation Results
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defn- failure-fn [input0 _more0 stack msg]
+(defn- failure-fn
+ "The initial `err-fn` for all parsers that are executed on the zetta-parser
+ library."
+ [input0 _more0 stack msg]
(ResultFailure. input0 stack msg))
-(defn- success-fn [input0 _more0 result]
+(defn- success-fn
+ "The initial `ok-fn` for all parsers that are executed on the zetta-parser
+ library."
+ [input0 _more0 result]
(ResultDone. input0 result))
(defn prompt
- "This is used for continuations of parsers (when there is not
+ "This is parser is used to return continuations (when there is not
enough input available for the parser to either succeed or fail)."
[input0 _more0 err-fn ok-fn]
(with-meta
@@ -179,22 +229,22 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Parsing functions
+;; ## Parsing functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn parse
- "Parses the given input with a parser, this may return a result that
- could either be a success, a failure , or a continuation that
+ "Uses the given parser to process the input, this function may return a
+ result that could either be a success, a failure, or a continuation that
will require more input in other to finish. The parser continuation
will halt as soon as an empty seq is given."
[parser input]
(p-trampoline parser (seq input) incomplete failure-fn success-fn))
(defn parse-once
- "Parses the given input with a parser, this may return a result that
+ "Uses the given parser to process the input, this may return a result that
could either be a success or failure result (All input must be available
- at once)."
+ at once when using this function)."
[parser input]
(let [result (parse parser input)]
(if (partial? result)
@@ -203,38 +253,38 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Monad & Applicative utility functions
+;; ## Monad & Applicative utility functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Haskell like operators
+;; ### Haskell's monad operators
(defn >>=
- "Equivalent to the m-bind function for monads."
+ "Alias for bind-parsers function."
[p f]
(bind-parsers p f))
-(defn- bind-ignore-step [mresult p1]
+(defn- bind-ignore-step
+ "Internal function used by the `>>` macro."
+ [mresult p1]
`(>>= ~mresult (fn [~'_]
~p1)))
(defmacro >>
- "Composes two or more monadic values returning the
- result of the last one."
+ "Composes two or more parsers returning the result of the rightmost one."
[& more]
(reduce bind-ignore-step more))
-;; Haskell Applicative operators
+;; ### Haskell's applicative operators
(defmacro *>
- "Composes two or more applicative functors, returning the
- result value of the last one."
+ "Composes two or more parsers, returning the result value of the rightmost
+ one."
[& more]
`(>> ~@more))
(defmacro <*
- "Composes two or more applicative functors, returning the
- result value of the first one."
+ "Composes two or more parsers, returning the result of the leftmost one."
[& more]
(let [step (first more)
steps (rest more)]
@@ -243,19 +293,19 @@
(always ~'result#))))))
(defn <$>
- "Maps the function f to the results of the given applicative functors,
- each applicative functor result value is going to be a parameter for
- function f.
+ "Maps the function f to the results of the given parsers, applicative
+ functor result is going to be a parameter for function f.
Example:
+
(<$> + number number)
- Where number is parser that will return a number from the input stream."
+ Where `number` is a parser that will return a number from the parsed input."
[f & more]
(with-parser
(m-bind (m-seq more) (fn [params]
(m-result (apply f params))))))
(def <|>
- "Equivalent to the m-plus function for monads."
+ "Alias for join-parsers function."
join-parsers)
View
147 src/zetta/parser/seq.clj
@@ -9,22 +9,22 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Utility Functions
+;; ## Utility Functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defn- span [pred xs]
+(defn- span
+ [pred xs]
((core/juxt #(core/take-while pred %) #(core/drop-while pred %)) xs))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Basic Parsers
+;; ## Basic Parsers
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(def demand-input
- "Basic parser that will ensure the request of more
- input via a continuation."
+ "Basic parser that will ensure the request of more input via a continuation."
(fn [input0 more0 err-fn0 ok-fn0]
(if (complete? more0)
#(err-fn0 input0 more0 ["demand-input"] "not enough input")
@@ -36,9 +36,10 @@
(prompt input0 more0 err-fn ok-fn)))))
(def want-input?
- "This parser always succeeds. It returns 'true' if any
- input is available either immediately or on demand, and
- 'false' if the end of all input has been reached."
+ "Parser that returns `true` if any input is available either immediately or
+ on demand, and `false` if the end of all input has been reached.
+
+ **WARNING**: This parser always succeeds."
(fn [input0 more0 _err-fn ok-fn0]
(cond
(not (empty? input0)) #(ok-fn0 input0 more0 true)
@@ -49,8 +50,8 @@
(prompt input0 more0 err-fn ok-fn)))))
(defn ensure
- "If at least 'n' items of input are available, return the current
- input, otherwise fail."
+ "If at least `n` items of input are available, return the current input,
+ otherwise fail."
[n]
(fn [input0 more0 err-fn ok-fn]
(if (>= (count input0) n)
@@ -59,17 +60,18 @@
((>> demand-input (ensure n)) input0 more0 err-fn ok-fn)))))
(def get
+ "Returns the input given in the `zetta.core/parse` function."
(fn [input0 more0 _err-fn ok-fn]
#(ok-fn input0 more0 input0)))
(defn put [s]
+ "Sets a (possibly modified) input into the parser state."
(fn [_input0 more0 _err-fn ok-fn]
#(ok-fn s more0 nil)))
(defn satisfy?
- "The parser 'satisfy pred' succeeds for any item for which the
- predicate 'pred' returns 'true'. Returns the item that is actually
- parsed."
+ "Parser that succeeds for any item for which the predicate `pred` returns
+ `true`. Returns the item that is actually parsed."
[pred]
(do-parser
[input (ensure 1)
@@ -84,8 +86,8 @@
item))
(defn skip
- "The parser 'skip pred' succeeds for any item for which the predicate
- 'pred' returns 'true'."
+ "Parser that succeeds for any item for which the predicate `pred`, returns
+ `nil`."
[pred]
(do-parser
[input (ensure 1)
@@ -95,8 +97,8 @@
nil))
(defn take-with
- "Matches 'n' items of input, but succeed only if the predicate
- 'pred' returns 'true' on the parsed input. The matched input is returned
+ "Parser that matches `n` items of input, but succeed only if the predicate
+ `pred` returns `true` on the parsed input. The matched input is returned
as a seq."
[n pred]
(do-parser
@@ -109,26 +111,27 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; High Level Parsers
+;; ## High Level Parsers
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn take
- "Matches exactly 'n' items from input. Returnes the matched input as a seq."
+ "Parser that matches exactly `n` items from input. Returnes the matched
+ input as a seq."
[n]
(take-with n (constantly true)))
(defn string
- "Parses a sequence of items that identically match
- a given string 's'. Returns the parsed string. This parser
- consumes no input if it fails (even with a partial match)."
- [s]
+ "Parses a sequence of items that identically match a given string `s`.
+ Returns the parsed string. This parser consumes no input if it fails (even
+ with a partial match)."
+ [#^java.lang.String s]
(let [ch-vec (vec s)]
(<$> str/join
(take-with (count s) #(= ch-vec %)))))
(defn skip-while
- "A parser that skips input for as long as 'pred' returns 'true'."
+ "Parser that skips input for as long as `pred` returns `true`."
[pred]
(let [skip-while-loop (do-parser
[input0 get
@@ -146,15 +149,15 @@
skip-while-loop))
(defn take-while
- "Matches input as long as pred returns 'true', and return
+ "Parser that matches input as long as pred returns `true`, and return
the consumed input as a seq.
- This parser does not fail. It will return an empty seq if the
- predicate returns 'false' on the first token of input.
+ This parser does not fail. It will return an empty seq if the predicate
+ returns `false` on the first token of input.
- Note: Because this parser does not fail, do not use it with
- combinators such as 'many', because such parsers loop until a
- failure occurs. Careless use will thus result in an infinite loop."
+ **WARNING**: Because this parser does not fail, do not use it with
+ combinators such as `many`, because such parsers loop until a failure
+ occurs. Careless use will thus result in an infinite loop."
[pred]
(letfn [
(take-while-loop [acc]
@@ -175,20 +178,20 @@
(take-while-loop []))))
(defn take-till
- "Matches input as long as 'pred' returns 'false'
- (i.e. until it returns 'true'), and returns the consumed input as a seq.
+ "Matches input as long as `pred` returns `false`
+ (i.e. until it returns `true`), and returns the consumed input as a seq.
- This parser does not fail. It will return an empty seq if the
- predicate returns 'true' on the first item from the input.
+ This parser does not fail. It will return an empty seq if the predicate
+ returns `true` on the first item from the input.
- Note: Because this parser does not fail, do not use it with
- combinators such as 'many', because such parsers loop until a
- failure occurs. Careless use will thus result in an infinite loop."
+ **WARNING**: Because this parser does not fail, do not use it with combinators
+ such as `many`, because such parsers loop until a failure occurs. Careless
+ use will thus result in an infinite loop."
[pred]
(take-while (complement pred)))
(def take-rest
- "Returns the rest of the seqs that are given to the parser,
+ "Parser that returns the rest of the seqs that are given to the parser,
the result will be a seqs of seqs where the number of seqs
from the first level will represent the number of times a
continuation was used to continue the parse process."
@@ -209,8 +212,8 @@
(take-rest-loop [])))
(defn take-while1
- "Matches input as long as pred returns 'true'. This parser returns
- the consumed input in a seq.
+ "Parser that matches input as long as pred returns `true`. This parser
+ returns the consumed input in a seq.
This parser will fail if a first match is not accomplished."
[pred]
@@ -231,14 +234,14 @@
result))
(def any-token
- "Matches any element from the input seq, it
- will return the parsed element from the seq."
+ "Parser that matches any element from the input seq, it will return the
+ parsed element from the seq."
(satisfy? (constantly true)))
(defn char
- "Matches only a token that is equal to character
- 'c', the character is returned."
- [c]
+ "Parser that matches only a token that is equal to character `c`, the
+ character is returned."
+ [#^java.lang.Character c]
(cond
(set? c)
(<?> (satisfy? #(contains? c %))
@@ -248,32 +251,32 @@
(str "failed parser char: " c))))
(def whitespace
- "Matches any character that is considered a whitespace,
- it uses 'Character/isWhitespace' internally. This parser
- returns the whitespace character."
- (satisfy? #(Character/isWhitespace %)))
+ "Parser that matches any character that is considered a whitespace, it uses
+ `Character/isWhitespace` internally. This parser returns the whitespace
+ character."
+ (satisfy? #(Character/isWhitespace #^java.lang.Character %)))
(def space
- "Matches any character that is equal to the character
- \\space. This parser returns the \\space character."
+ "Parser that matches any character that is equal to the character `\\space`.
+ This parser returns the `\\space` character."
(char \space))
(def spaces
- "Matches many spaces."
+ "Parser that matches many spaces. Returns a seq of space characters"
(many space))
(def skip-spaces
- "Skips many spaces."
+ "Parser that skips many spaces. Returns `nil`."
(skip-many space))
(def skip-whitespaces
- "Skips many whitespaces."
+ "Parser that skips many whitespaces. Returns `nil`."
(skip-many whitespace))
(defn not-char
- "Matches only a token that is not equal to character
- 'c', the character is returned."
- [c]
+ "Parser that matches only an item that is not equal to character `c`, the
+ item is returned."
+ [#^java.lang.Character c]
(cond
(set? c)
(<?> (satisfy? #(not (contains? c %)))
@@ -283,19 +286,21 @@
(str c))))
(def letter
- "Matches any character that is considered a letter,
- it uses 'Character/isLetter' internally. This parser will return
- the matched character."
- (satisfy? #(Character/isLetter %)))
+ "Parser that matches any character that is considered a letter, it uses
+ `Character/isLetter` internally. This parser will return the matched
+ character."
+
+ (satisfy? #(Character/isLetter ^java.lang.Character %)))
(def word
+ "Parser that matches a word, e.g `(many1 letter)`, returns the parsed word."
(<$> str/join (many1 letter)))
(def digit
- "Matches any character that is considered a digit, it uses
- 'Character/isDigit' internally. This parser will return the
- matched character."
- (satisfy? #(Character/isDigit %)))
+ "Parser that matches any character that is considered a digit, it uses
+ `Character/isDigit` internally. This parser will return the matched digit
+ character."
+ (satisfy? #(Character/isDigit #^java.lang.Character %)))
; Using the clojure LispReader, code found on stackoverflow
; http://stackoverflow.com/questions/2640169/whats-the-easiest-way-to-parse-numbers-in-clojure
@@ -321,14 +326,14 @@
(cons h t))))
(def number
- "Matches one or more digit characters and returns the number parsed
- in base 10."
+ "Parser that matches one or more digit characters and returns a number in
+ base 10."
(<$> (comp read-number str/join)
double-or-long))
(def end-of-input
- "Matches only when the end-of-input has been reached, otherwise
- it fails. This parser returns a nil value."
+ "Parser that matches only when the end-of-input has been reached, otherwise
+ it fails. Returns a nil value."
(fn [input0 more0 err-fn0 ok-fn0]
(if (empty? input0)
(if (complete? more0)
@@ -346,8 +351,8 @@
#(err-fn0 input0 more0 [] "end-of-input"))))
(def at-end?
- "Parser that never fails, it returns 'true' when the end-of-input
- is reached, 'false' otherwise."
+ "Parser that never fails, it returns `true` when the end-of-input
+ is reached, `false` otherwise."
(<$> not want-input?))
(def eol
View
50 src/zetta/parser/string.clj
@@ -8,70 +8,70 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; High Level Parsers
+;; ## High Level Parsers
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn take-with
- "Matches 'n' items of input, but succeed only if the predicate
- 'pred' returns 'true' on the parsed input. The matched input is returned
+ "Parser that matches `n` items of input, but succeed only if the predicate
+ `pred` returns `true` on the parsed input. The matched input is returned
as a string."
[n pred]
(<$> str/join
(pseq/take-with n pred)))
(defn take
- "Matches exactly 'n' items from input. Returnes the matched input as
- a string."
+ "Parser that matches exactly `n` items from input. Returnes the matched
+ input as a string."
[n]
(take-with n (constantly true)))
(defn string
- "Parses a sequence of items that identically match
- a given string 's'. Returns the parsed string. This parser
- consumes no input if it fails (even with a partial match)."
+ "Parses a sequence of items that identically match a given string `s`.
+ Returns the parsed string. This parser consumes no input if it fails (even
+ with a partial match)."
[s]
(take-with (count s) #(= s %)))
(defn take-while
- "Matches input as long as pred returns 'true', and return
+ "Parser that matches input as long as pred returns `true`, and return
the consumed input as a string.
- This parser does not fail. It will return an empty seq if the
- predicate returns 'false' on the first token of input.
+ This parser does not fail. It will return an empty seq if the predicate
+ returns `false` on the first token of input.
- Note: Because this parser does not fail, do not use it with
- combinators such as 'many', because such parsers loop until a
- failure occurs. Careless use will thus result in an infinite loop."
+ **WARNING**: Because this parser does not fail, do not use it with combinators
+ such as `many`, because such parsers loop until a failure occurs. Careless
+ use will thus result in an infinite loop."
[pred]
(<$> str/join
(pseq/take-while pred)))
(defn take-till
- "Matches input as long as 'pred' returns 'false'
- (i.e. until it returns 'true'), and returns the consumed input as a seq.
+ "Parser that matches input as long as `pred` returns `false` (i.e. until it
+ returns `true`), and returns the consumed input as a seq.
This parser does not fail. It will return an empty string if the
- predicate returns 'true' on the first item from the input.
+ predicate returns `true` on the first item from the input.
- Note: Because this parser does not fail, do not use it with
- combinators such as 'many', because such parsers loop until a
- failure occurs. Careless use will thus result in an infinite loop."
+ **WARNING**: Because this parser does not fail, do not use it with combinators
+ such as `many`, because such parsers loop until a failure occurs. Careless
+ use will thus result in an infinite loop."
[pred]
(take-while (complement pred)))
(def take-rest
- "Returns the rest of the seqs that are given to the parser,
- the result will be a seqs of strings where the number of seqs
+ "Parser that always success and returns the rest of the seqs that are given
+ to the parser, the result will be a seqs of strings where the number of seqs
from the first level will represent the number of times a
continuation was used to continue the parse process."
(<$> #(map str/join %) pseq/take-rest))
(defn take-while1
- "Matches input as long as pred returns 'true'. This parser returns
- the consumed input in a string.
+ "Parser that matches input as long as pred returns `true`. This parser
+ returns the consumed input in a string.
- This parser will fail if a first match is not accomplished."
+ This parser will fail if a first match is not accomplished."
[pred]
(<$> str/join (pseq/take-while1 pred)))
View
24 test/zetta/tests/parser/seq.clj
@@ -17,25 +17,29 @@
(is (failure? result))))
(deftest skip-test
- (let [result (parse-once (p/skip #(Character/isDigit %))
+ (let [result (parse-once (p/skip #(Character/isDigit ^java.lang.Character %))
"432")]
(is (nil? (:result result)))
(is (= [\3 \2] (:remainder result)))))
(deftest skip-no-initial-match-test
- (let [result (parse-once (p/skip #(Character/isDigit %))
+ (let [result (parse-once (p/skip #(Character/isDigit ^java.lang.Character %))
"hello")]
(is (failure? result))))
(deftest take-with-test
(let [result (parse-once
- (p/take-with 4 (partial every? #(Character/isDigit %)))
+ (p/take-with 4 (partial every?
+ #(Character/isDigit ^java.lang.Character %)))
"12345")]
(is (= [\1 \2 \3 \4] (:result result)))))
(deftest take-with-no-initial-match-test
(let [result (parse-once
- (p/take-with 4 (partial every? #(Character/isDigit %)))
+ (p/take-with 4
+ (partial every?
+ #(Character/isDigit
+ ^java.lang.Character %)))
"12ab3")]
(is (failure? result))))
@@ -70,28 +74,28 @@
(deftest skip-while-test
(let [result (parse-once
- (p/skip-while #(Character/isWhitespace %))
+ (p/skip-while #(Character/isWhitespace ^java.lang.Character %))
" \tanother test")]
(is (done? result))
(is (= (seq "another test") (:remainder result)))))
(deftest skip-while-no-initial-match-test
(let [result (parse-once
- (p/skip-while #(Character/isWhitespace %))
+ (p/skip-while #(Character/isWhitespace ^java.lang.Character %))
"another test")]
(is (done? result))
(is (= (seq "another test") (:remainder result)))))
(deftest take-while-test
(let [result (parse-once
- (p/take-while #(Character/isLetter %))
+ (p/take-while #(Character/isLetter ^java.lang.Character %))
"this is just a test")]
(is (= (seq "this") (:result result)))
(is (= (seq " is just a test") (:remainder result)))))
(deftest take-while-no-initial-match-test
(let [result (parse-once
- (p/take-while #(Character/isLetter %))
+ (p/take-while #(Character/isLetter ^java.lang.Character %))
" this is just a test")]
(is (done? result))
(is (= [] (:result result)))
@@ -120,14 +124,14 @@
(deftest take-while1-test
(let [result (parse-once
- (p/take-while1 #(Character/isLetter %))
+ (p/take-while1 #(Character/isLetter ^java.lang.Character %))
"this is just a test")]
(is (= (seq "this") (:result result)))
(is (= (seq " is just a test") (:remainder result)))))
(deftest take-while1-no-initial-match-test
(let [result (parse-once
- (p/take-while1 #(Character/isLetter %))
+ (p/take-while1 #(Character/isLetter ^java.lang.Character %))
" this is just a test")]
(is (failure? result))))
View
13 test/zetta/tests/parser/string.clj
@@ -6,13 +6,14 @@
(deftest take-with-test
(let [result (parse-once
- (p/take-with 4 (partial every? #(Character/isDigit %)))
+ (p/take-with 4 (partial
+ every? #(Character/isDigit ^java.lang.Character %)))
"12345")]
(is (= "1234" (:result result)))))
(deftest take-with-no-initial-match-test
(let [result (parse-once
- (p/take-with 4 (partial every? #(Character/isDigit %)))
+ (p/take-with 4 (partial every? #(Character/isDigit ^java.lang.Character %)))
"12ab3")]
(is (failure? result))))
@@ -30,14 +31,14 @@
(deftest take-while-test
(let [result (parse-once
- (p/take-while #(Character/isLetter %))
+ (p/take-while #(Character/isLetter ^java.lang.Character %))
"this is just a test")]
(is (= "this" (:result result)))
(is (= (seq " is just a test") (:remainder result)))))
(deftest take-while-no-initial-match-test
(let [result (parse-once
- (p/take-while #(Character/isLetter %))
+ (p/take-while #(Character/isLetter ^java.lang.Character %))
" this is just a test")]
(is (done? result))
(is (= "" (:result result)))
@@ -66,14 +67,14 @@
(deftest take-while1-test
(let [result (parse-once
- (p/take-while1 #(Character/isLetter %))
+ (p/take-while1 #(Character/isLetter ^java.lang.Character %))
"this is just a test")]
(is (= "this" (:result result)))
(is (= (seq " is just a test") (:remainder result)))))
(deftest take-while1-no-initial-match-test
(let [result (parse-once
- (p/take-while1 #(Character/isLetter %))
+ (p/take-while1 #(Character/isLetter ^java.lang.Character %))
" this is just a test")]
(is (failure? result))))
Please sign in to comment.
Something went wrong with that request. Please try again.