Skip to content

Commit

Permalink
implement transform function; alpha release
Browse files Browse the repository at this point in the history
  • Loading branch information
tiye committed May 5, 2020
1 parent 2e69007 commit 5f28d50
Show file tree
Hide file tree
Showing 7 changed files with 1,051 additions and 323 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ Lilac parser

> A toy combinator parser with better failure reasons.
Demo of `(def a (add 1 2))` http://repo.mvc-works.org/lilac-parser/
Demo of `(def a (add 1 2))` or `{"json": [1, 2]` http://repo.mvc-works.org/lilac-parser/

### Usage

[![Clojars Project](https://img.shields.io/clojars/v/mvc-works/lilac-parser.svg)](https://clojars.org/mvc-works/lilac-parser)

```edn
[mvc-works/lilac-parser "0.0.2-a1"]
[mvc-works/lilac-parser "0.0.2-a2"]
```

```clojure
Expand Down
1,218 changes: 951 additions & 267 deletions calcit.cirru

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mvc-works/lilac-parser",
"version": "0.0.2-a1",
"version": "0.0.2-a2",
"description": "Toy parser in cljs",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion release.edn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{:version "0.0.2-a1"
{:version "0.0.2-a2"
:group-id "mvc-works"
:artifact-id "lilac-parser"
:skip-tag true
Expand Down
2 changes: 1 addition & 1 deletion src/lilac_parser/comp/container.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
(<> (:value node) (merge style-label {:background-color (hsl 200 80 70)})))
(if (:ok? node)
(<>
(:value node)
(pr-str (:value node))
(merge style-label {:background-color (hsl 200 80 80), :font-size 10})))
(<>
(->> (:rest node) (take 10) (string/join ""))
Expand Down
109 changes: 71 additions & 38 deletions src/lilac_parser/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,47 @@

(declare parse-combine)

(defn combine+ [xs] {:parser-node :combine, :items xs})
(defn combine+
([xs] (combine+ xs identity))
([xs transform] {:parser-node :combine, :items xs, :transform transform}))

(defn indent+ [] {:parser-node :indent})
(defn indent+
([] (indent+ identity))
([transform] {:parser-node :indent, :transform transform}))

(defn interleave+ [x y] {:parser-node :interleave, :x x, :y y})
(defn interleave+
([x y] (interleave+ x y identity))
([x y transform] {:parser-node :interleave, :x x, :y y, :transform transform}))

(defn is+ [x] {:parser-node :is, :item x})
(defn is+
([x] (is+ x identity))
([x transform] {:parser-node :is, :item x, :transform transform}))

(defn many+ [item] {:parser-node :many, :item item})

(defn one-of+ [xs]
(when (and dev? (not (or (string? xs) (set? xs))))
(println "Unexpected argument passed to one-of+ :" xs))
{:parser-node :one-of, :items xs})

(defn optional+ [x] {:parser-node :optional, :item x})

(defn or+ [xs]
(when (and dev? (not (sequential? xs))) (println "Expected argument passed to or+ :" xs))
{:parser-node :or, :items xs})

(defn other-than+ [items]
(when (and dev? (not (or (string? items) (set? items))))
(println "Unexpected parameter passed to other-than+ :" items))
{:parser-node :other-than, :items items})
(defn one-of+
([xs] (one-of+ xs identity))
([xs transform]
(when (and dev? (not (or (string? xs) (set? xs))))
(println "Unexpected argument passed to one-of+ :" xs))
{:parser-node :one-of, :items xs, :transform transform}))

(defn optional+
([x] (optional+ x identity))
([x transform] {:parser-node :optional, :item x, :transform transform}))

(defn or+
([xs] (or+ xs identity))
([xs transform]
(when (and dev? (not (sequential? xs))) (println "Expected argument passed to or+ :" xs))
{:parser-node :or, :items xs, :transform transform}))

(defn other-than+
([items] (other-than+ items identity))
([items transform]
(when (and dev? (not (or (string? items) (set? items))))
(println "Unexpected parameter passed to other-than+ :" items))
{:parser-node :other-than, :items items, :transform transform}))

(defn seq-strip-beginning [xs ys]
(cond
Expand All @@ -55,18 +71,26 @@
:else {:ok? false, :message "not matching", :xs xs, :ys ys}))

(defn parse-is [xs rule]
(let [item (:item rule), strip-result (seq-strip-beginning xs (string/split item ""))]
(let [item (:item rule)
transform (:transform rule)
strip-result (seq-strip-beginning xs (string/split item ""))]
(if (:ok? strip-result)
{:ok? true, :value item, :rest (:rest strip-result), :parser-node :is}
{:ok? true,
:value (if (some? transform) (transform item) item),
:rest (:rest strip-result),
:parser-node :is}
{:ok? false,
:message (str "failed to match " item " in " (take 10 xs) "...."),
:parser-node :is,
:rest xs})))

(defn parse-one-of [xs rule]
(let [items (:items rule)]
(let [items (:items rule), transform (:transform rule)]
(if (if (string? items) (string/includes? items (first xs)) (contains? items (first xs)))
{:ok? true, :value (first xs), :rest (rest xs), :parser-node :one-of}
{:ok? true,
:value (let [v (first xs)] (if (some? transform) (transform v) v)),
:rest (rest xs),
:parser-node :one-of}
{:ok? false, :message "not in list", :parser-node :one-of, :rest xs})))

(defn parse-other-than [xs rule]
Expand All @@ -75,29 +99,32 @@
:message "Unexpected EOF in other-than+ rule",
:parser-node :other-than,
:rest xs}
(let [items (:items rule), x0 (first xs)]
(let [items (:items rule), transform (:transform rule), x0 (first xs)]
(if (if (string? items) (string/includes? items x0) (contains? items x0))
{:ok? false,
:message (str (pr-str x0) "is in not expected item in other-than+"),
:parser-node :other-than,
:rest xs}
{:ok? true, :value x0, :rest (rest xs), :parser-node :other-than}))))
{:ok? true,
:value (if (some? transform) (transform x0) x0),
:rest (rest xs),
:parser-node :other-than}))))

(defn parse-some [xs0 rule]
(let [item (:item rule)]
(let [item (:item rule), transform (:transform rule)]
(loop [acc [], xs xs0]
(let [result (parse-lilac xs item)]
(if (:ok? result)
(recur (conj acc result) (:rest result))
{:ok? true,
:value (map :value acc),
:value (let [v (map :value acc)] (if (some? transform) (transform v) v)),
:rest xs,
:parser-node :some,
:results acc,
:peek-result result})))))

(defn parse-or [xs rule]
(let [items (:items rule)]
(let [items (:items rule), transform (:transform rule)]
(loop [rules items, failures []]
(if (empty? rules)
{:ok? false,
Expand All @@ -108,24 +135,24 @@
(let [result (parse-lilac xs (first rules))]
(if (:ok? result)
{:ok? true,
:value (:value result),
:value (let [v (:value result)] (if (some? transform) (transform v) v)),
:rest (:rest result),
:parser-node :or,
:result result}
(recur (rest rules) (conj failures result))))))))

(defn parse-optional [xs rule]
(let [item (:item rule), result (parse-lilac xs item)]
(let [item (:item rule), transform (:transform rule), result (parse-lilac xs item)]
(if (:ok? result)
{:ok? true,
:value (:value result),
:value (let [v (:value result)] (if (some? transform) (transform v) v)),
:rest (:rest result),
:parser-node :optional,
:result result}
{:ok? true, :value nil, :result result, :parser-node :optional, :rest xs})))

(defn parse-many [xs0 rule]
(let [item (:item rule)]
(let [item (:item rule), transform (:transform rule)]
(loop [acc [], xs xs0]
(let [result (parse-lilac xs item)]
(if (:ok? result)
Expand All @@ -137,7 +164,7 @@
:peek-result result,
:rest xs}
{:ok? true,
:value (map :value acc),
:value (let [v (map :value acc)] (if (some? transform) (transform v) v)),
:rest xs,
:parser-node :many,
:results acc,
Expand All @@ -159,7 +186,7 @@
(do (js/console.warn "Unknown node" rule) nil)))

(defn parse-interleave [xs0 rule]
(let [x0 (:x rule), y0 (:y rule)]
(let [x0 (:x rule), y0 (:y rule), transform (:transform rule)]
(loop [acc [], xs xs0, x x0, y y0]
(let [result (parse-lilac xs x)]
(if (:ok? result)
Expand All @@ -171,7 +198,7 @@
:peek-result result,
:rest xs}
{:ok? true,
:value (map :value acc),
:value (let [v (map :value acc)] (if (some? transform) (transform v) v)),
:rest xs,
:parser-node :interleave,
:results acc,
Expand All @@ -196,7 +223,7 @@
:rest xs})))

(defn parse-combine [xs0 rule]
(let [items (:items rule)]
(let [items (:items rule), transform (:transform rule)]
(loop [acc [], xs xs0, ys items]
(cond
(and (empty? xs) (not (empty? ys)))
Expand All @@ -206,7 +233,11 @@
:results acc,
:rest xs}
(empty? ys)
{:ok? true, :value (map :value acc), :rest xs, :parser-node :combine, :results acc}
{:ok? true,
:value (let [v (map :value acc)] (if (some? transform) (transform v) v)),
:rest xs,
:parser-node :combine,
:results acc}
:else
(let [result (parse-lilac xs (first ys))]
(if (:ok? result)
Expand All @@ -218,6 +249,8 @@
:previous-results acc,
:rest xs}))))))

(defn some+ [x] {:parser-node :some, :item x})
(defn some+
([x] (some+ x identity))
([x transform] {:parser-node :some, :item x, :transform transform}))

(defn unindent+ [] {:parser-node :unindent})
37 changes: 24 additions & 13 deletions src/lilac_parser/demo/json.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,39 @@
one-of+
some+
or+
defparser]]))
defparser]]
[clojure.string :as string]))

(declare value-parser+)

(declare array-parser+)

(declare object-parser+)

(def boolean-parser (or+ [(is+ "true") (is+ "false")]))
(def boolean-parser
(or+ [(is+ "true") (is+ "false")] (fn [x] (if (= x "true") true false))))

(def space-parser (some+ (is+ " ")))
(def space-parser (some+ (is+ " ") (fn [x] nil)))

(def comma-parser (combine+ [space-parser (is+ ",") space-parser]))
(def comma-parser (combine+ [space-parser (is+ ",") space-parser] (fn [x] nil)))

(def digit-parser (one-of+ "1234567890"))

(def nil-parser (or+ [(is+ "null") (is+ "undefined")]))
(def nil-parser (or+ [(is+ "null") (is+ "undefined")] (fn [x] nil)))

(def number-parser
(combine+
[(optional+ (is+ "-"))
(many+ digit-parser)
(optional+ (combine+ [(is+ ".") (many+ digit-parser)]))]))
(optional+ (combine+ [(is+ ".") (many+ digit-parser)]))]
(fn [xs] (js/Number (string/join "" (nth xs 1))))))

(def string-parser
(combine+
[(is+ "\"")
(some+ (or+ [(other-than+ "\"\\") (is+ "\\\"") (is+ "\\\\") (is+ "\\n")]))
(is+ "\"")]))
(is+ "\"")]
(fn [xs] (string/join "" (nth xs 1)))))

(defparser
value-parser+
Expand All @@ -54,16 +58,23 @@
identity
(combine+
[(is+ "{")
(some+
(optional+
(interleave+
(combine+ [string-parser space-parser (is+ ":") space-parser (value-parser+)])
comma-parser))
(is+ "}")]))
(combine+
[string-parser space-parser (is+ ":") space-parser (value-parser+)]
(fn [xs] [(nth xs 0) (nth xs 4)]))
comma-parser
(fn [xs] (take-nth 2 xs))))
(is+ "}")]
(fn [xs] (into {} (nth xs 1)))))

(defparser
array-parser+
()
identity
(combine+ [(is+ "[") (some+ (interleave+ (value-parser+) comma-parser)) (is+ "]")]))
(fn [x] (vec (first (nth x 1))))
(combine+
[(is+ "[")
(some+ (interleave+ (value-parser+) comma-parser (fn [xs] (take-nth 2 xs))))
(is+ "]")]))

(def demo-parser (many+ (other-than+ "abc")))

0 comments on commit 5f28d50

Please sign in to comment.