 (ns smallex.test.generators
+  (:refer-clojure :exclude [alias])
   (:require [simple-check.generators :as gen]
             [clojure.test :refer :all]
             [clojure.pprint :as pprint :refer [pprint]]))

  [or-op cat-op star-op plus-op opt-op not-op])

(def operation
  (gen/sized
   (fn [size]
     (let [op-generators (map #(gen/resize size %) all-op-generators)]
       (gen/one-of op-generators)))))

(defn ppm [obj]
  (let [orig-dispatch pprint/*print-pprint-dispatch*]

(defn use-alias [aliases]
  (gen/elements aliases))

(def collection-generators
  (map #(gen/resize 20 %) [string char-set]))

(declare operation)

(defn- operation-generator
  [{:keys [op max-args type-fn such-that]
    :or {max-args 4 such-that (constantly true)}}]
  (fn [alias-gen]
    (gen/sized
     (fn [size]
       (let [smaller-ops (gen/resize (dec size) (operation alias-gen))
             arg-gen (cond-> (conj collection-generators alias-gen)
                             (pos? size)
                             ;; v- hack to get more nested ops
                             (conj smaller-ops smaller-ops smaller-ops))]
         (->> (gen/vector (gen/one-of arg-gen) 1 max-args)
              (gen/fmap
               (fn [args]
                 (with-meta {:type :op, :value op, :args args}
                   {:result (type-fn (map #(-> % meta :result) args))})))
              (gen/such-that such-that)))))))

(def or-op
  (operation-generator
