diff --git a/deps.edn b/deps.edn index f36c04a..8a9e05d 100644 --- a/deps.edn +++ b/deps.edn @@ -2,4 +2,9 @@ :deps {org.clojure/clojure {:mvn/version "1.11.3"}} :aliases {:test {:extra-paths ["test"] :extra-deps {lambdaisland/kaocha {:mvn/version "1.88.1376"}} - :main-opts ["-m" "kaocha.runner"]}}} + :main-opts ["-m" "kaocha.runner"]} + :doc-gen {:extra-deps {marginalia/marginalia {:mvn/version "0.9.2"}} + :main-opts ["-m" "marginalia.main" + "-n" "Aurelio" + "-f" "index.html" + "src"]}}} diff --git a/docs/01-why.org b/docs/01-why.org index e246905..0e4dbb7 100644 --- a/docs/01-why.org +++ b/docs/01-why.org @@ -52,39 +52,44 @@ mock ::= endpoint* And this is what it looks in Aurelio syntax: #+begin_src clojure - {;; yaml - :indent [:+ [:| ["\t" " "]]] - :seqb [:| [#block "-" #flow "["]] - :seqe [:| [#block :empty #flow "]"]] - :mapb [:| [#block :empty #flow "{"]] - :mape [:| [#block :empty #flow "}"]] - :multiline #block [:| "|" ">"] - - ;; mock - :method [:| ["GET" "HEAD" "POST" "PUT" "DELETE" - "CONNECT" "OPTIONS" "TRACE"]] - :path [:+ "/" :string] - :header [:string ":" :string] - :response [:mapb [:ul - [:? "status" ":" [:... [200 400]]] - [:? "headers" ":" :mapb [:+ header] :mape] - ["body" ":" [:? :multiline] :string]] - :mape] - :webhook [:mapb [:ul - [:? "sleep-time" ":" :int] - [:? "if" ":" :string] - ["url" ":" :string] - ["method" ":" :method] - ["body" ":" [:? :multiline] :string]] - :mape] - :endpoint [:seqb "endpoint" - :mapb [:ul - [:? "method" ":" :method] - ["path" ":" :path] - ["response" ":" :response] - ["webhook" ":" :webhook]] - :mape :seqe] - :mock [:* :endpoint]} + {;; yaml + :indent [:seq+ [:or \tab \space]] + :seqb [:or \- \[] + :seqe [:or :empty \]] + :mapb [:or :empty \{] + :mape [:or :empty \}] + :quote [:opt [:or \' \"]] + :string [:quote :str :quote] + :multiline [:or \| \>] + + ;; mock + :method [:or "GET" "HEAD" "POST" "PUT" "DELETE" "CONNECT" "OPTIONS" "TRACE"] + :path [:seq+ \/ :string] + :header [:string \: :string] + :response [:mapb + [:useq + [:opt "status" \: [:range ["200" "400"]]] + [:opt "headers" \: :mapb [:seq+ :header] :mape] + "body" ":" [:opt :multiline] :string] + :mape] + :webhook [:mapb + [:useq + [:opt "sleep-time" \: :int] + [:opt "if" \: :string] + ["url" \: :string] + ["method" \: :method] + ["body" \: [:opt :multiline] :string]] + :mape] + :endpoint [:seqb "endpoint" + :mapb + [:useq + [:? "method" \: :method] + ["path" \: :path] + ["response" \: :response] + ["webhook" \: :webhook]] + :mape + :seqe] + :mock [:seq* :endpoint]} #+end_src The last one will be the one considered when parsing a given arg. diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..0aebdde --- /dev/null +++ b/docs/index.html @@ -0,0 +1,3084 @@ + +
Aurelio+ | (this space intentionally left almost blank) |
| + | (ns aurelio.core) |
| + | (defn -main + [& _args] + (prn "hello world")) |
| + | (ns aurelio.grammar) |
Returns a predicate function that compares given character
+ | (defn build-char-p + [^Character c1] + (fn [^Character c2] + (= (int c1) (int c2)))) |
Returns a predicate function that compares given string
+ | (defn build-str-p + [^String s1] + (fn [^String s2] + (= s1 s2))) |
Returns a predicate function that tests given list of
+ | (defn build-or-p + ([] + (throw (Exception. "`or` predicate has no inner predicates."))) + ([& predicates] + (fn [expr] + ((complement not-any?) #(% expr) predicates)))) |
Returns a predicate function that tests whether any other
+character exists inbetween
| (defn build-range-p + [start end] + (fn [c] + (<= (int start) (int c) (int end)))) |
Returns a predicate function that tests given | (defn build-seq*-p + [predicate] + (fn [exprs] + (every? #(predicate %) (filter some? (seq exprs))))) |
Returns a predicate function that tests given | (defn build-seq+-p + [predicate] + (fn [exprs] + (and (some? (seq exprs)) ((build-seq*-p predicate) exprs)))) |
Returns a predicate function that tests given | (defn build-opt-p + [predicate] + (fn [& expr] + (or (empty? expr) (predicate (first expr))))) |
| + | (defn build-useq-p + ([] + (throw (Exception. "`useq` predicate has no predicates."))) + ([& predicates] + (fn [exprs] + ;; compare non-optionals with predicate count + (if (not= (count (remove #(when (seq? %) + (not= (first %) :opt)) + exprs)) + (count predicates)) + (throw (Exception. "expression count != predicate count")) + (let [preds-or-p (apply build-or-p predicates)] + (map #(preds-or-p %) exprs)))))) |
((build-useq-p (build-char-p \c) (build-char-p \t)) [\t \t]) + | |
| + | (def predicate-builders
+ {:or build-or-p
+ :range build-range-p
+ :seq* build-seq*-p
+ :seq+ build-seq+-p
+ :opt build-seq*-p
+ :useq build-useq-p}) |
Given a list of A symbol reference is a
| (defn- sort-sym-refs
+ [exprs]
+ (reduce
+ (fn [acc expr]
+ (->> (flatten expr)
+ ;; retrieve symbol references
+ (filter #(and (keyword? %) (nil? (get predicate-builders %))))
+ ;; count symrefs by parent
+ (reduce #(update-in %1 [%2] (fnil inc 0)) {})
+ ;; count all unique symrefs
+ (reduce-kv
+ (fn [sym-acc wsym wsym-count]
+ (update-in sym-acc [wsym] (fnil (partial + wsym-count) 0)))
+ acc)
+ (sort-by val >)
+ (into {})))
+ {} exprs)) |
| + | (comment
+ (sort-sym-refs [[:a :b [:or :d :d]]
+ [:b [:seq+ :d :d]]])
+ ;; => {:d 4, :b 2, :a 1}
+ ) |
Given a See also: | (defn order-syms-by-dep
+ [grammar]
+ (let [sym-refs (sort-sym-refs (vals grammar))]
+ (->> grammar
+ (sort-by #(get sym-refs (key %) 0) >)
+ (into {})))) |
Builds a list of predicates, corresponding to each expression in given | (defn build-expr-p + [expr] + (if (empty? expr) + (throw (Exception. "an empty expression is invalid.")) + (let [pred-keyword (first expr) + pred-builder (get predicate-builders pred-keyword)] + (if (and (keyword? pred-keyword) (some? pred-builder)) + (try + (->> (build-expr-p (rest expr)) + (apply pred-builder)) + (catch Exception e + (throw (Exception. (str "failed to build predicate `" + pred-keyword "`\n" + (.getMessage e)))))) + (map + (fn [inner-expr] + (cond-> inner-expr + (char? inner-expr) build-char-p + (string? inner-expr) build-str-p + (keyword? inner-expr) identity + (vector? inner-expr) build-expr-p)) + expr))))) |
| + | (def base-grammar
+ {:ws [\space]
+ :nl [\n]
+ :empty []}) |
| + | (defn build
+ [user-grammar]
+ (let [grammar (order-syms-by-dep (merge base-grammar user-grammar))]
+ (reduce-kv
+ (fn [gr sym expr]
+ (assoc gr sym (build-expr-p expr)))
+ {} grammar))) |