{:spec/version "0.1"
 :language "hara-l0"
 :intentional-differences
 #{:no-iseq-requirement
   :no-ratios
   :ratio-free-unary-division
   :no-transducers
   :no-transduce
   :no-eduction
   :no-defstruct
   :no-deftype
   :no-defn-xt}
 :cases
 [{:id :reader/nil
   :class :reader
   :source "nil"
   :expect {:value nil :type :nil}}
  {:id :reader/bigint
   :class :reader
   :source "123N"
   :expect {:value "123" :type :big-integer :readable "123N"}}
  {:id :reader/bigdec
   :class :reader
   :source "123.45M"
   :expect {:value "123.45" :type :big-decimal :readable "123.45M"}}
  {:id :reader/quote
   :class :reader
   :source "'value"
   :expect {:form "(quote value)"}}
  {:id :reader/deref
   :class :reader
   :source "@value"
   :expect {:form "(deref value)"}}
  {:id :reader/discard
   :class :reader
   :source "#_ 2 1"
   :expect {:value 1 :type :integer}}
  {:id :compiler/arithmetic
   :class :compiler
   :source "(+ 19 23)"
   :expect {:value 42 :type :integer}}
  {:id :compiler/defn
   :class :compiler
   :source "(do (defn inc [x] (+ x 1)) (inc 41))"
   :expect {:value 42 :type :integer}}
  {:id :runtime/loop-recur
   :class :runtime
   :source "(loop [x 41] (if x (recur nil) 42))"
   :expect {:value 42 :type :integer}}
  {:id :runtime/letfn
   :class :runtime
   :source "(letfn [(fact [n] (if (= n 0) 1 (* n (fact (- n 1)))))] (fact 5))"
   :expect {:value 120 :type :integer}}
  {:id :runtime/cond
   :class :runtime
   :source "(cond (= 1 2) 0 (= 2 2) 42 :else 99)"
   :expect {:value 42 :type :integer}}
  {:id :runtime/threading
   :class :runtime
   :source "(->> 3 (+ 2) (* 3))"
   :expect {:value 15 :type :integer}}
  {:id :compiler/variadic-macro
   :class :compiler
   :source "(do (defmacro do-all [& forms] `(do ~@forms)) (do-all 1 2 3))"
   :expect {:value 3 :type :integer}}
  {:id :compiler/declare-private
   :class :compiler
   :source "(do (declare answer) (def answer 42) (defn- private-answer [] answer) (private-answer))"
   :expect {:value 42 :type :integer}}
  {:id :runtime/destructuring
   :class :runtime
   :source "(let [{:keys [age]} {:age 41}] (+ age 1))"
   :expect {:value 42 :type :integer}}
  {:id :runtime/metadata
   :class :runtime
   :source "(protocol-call ILookup lookup (protocol-call IObjType meta (protocol-call IObjType with-meta (Person \"Ada\") {:doc \"person\"})) :doc)"
   :setup "(defstruct Person [name])"
   :expect {:value "person" :type :string}}
  {:id :runtime/dynamic-binding
   :class :runtime
   :source "(binding [*answer* 42] *answer*)"
   :setup "(def ^:dynamic *answer* 1)"
   :expect {:value 42 :type :integer}}
  {:id :runtime/set-var-root
   :class :runtime
   :source "(do (def answer 1) (set! answer 42) answer)"
   :expect {:value 42 :type :integer}}
  {:id :iterator/core
   :class :iterator
   :source "(let [it (iter [1 2])] (iter-next it))"
   :expect {:value 1 :type :integer}}
  {:id :iterator/concat
   :class :iterator
   :source "(let [it (concat [1] [2])] (iter-next it) (iter-next it))"
   :expect {:value 2 :type :integer}}
  {:id :iterator/combinators
   :class :iterator
   :source "(let [it (iter-map (fn [x] (* x 2)) [1 2])] (iter-next it))"
   :expect {:value 2 :type :integer}}
  {:id :iterator/mutable-bytes
   :class :iterator
   :source "(let [ia (iter (array 1 2)) ib (iter (bytes 3 4))] (+ (iter-next ia) (iter-next ib)))"
   :expect {:value 4 :type :integer}}
  {:id :iterator/cycle-partition
   :class :iterator
   :source "(let [it (iter-cycle [1 2])] (+ (iter-next it) (iter-next it) (iter-next it) (nth (iter-next (iter-partition-pair [4 5])) 1)))"
   :expect {:value 9 :type :integer}}
  {:id :iterator/mapcat-keep
   :class :iterator
   :source "(let [it (iter-mapcat (fn [x] [x (+ x 10)]) [1 2])] (+ (iter-next it) (iter-next it) (iter-next it) (iter-next (iter-keep (fn [x] (if (= x 2) x nil)) [1 2 3]))))"
   :expect {:value 16 :type :integer}}
  {:id :function/apply
   :class :function
   :source "(defn sum3 [a b c] (+ a b c)) (apply sum3 1 [2 3])"
   :expect {:value 6 :type :integer}}
  {:id :module/resource
   :class :module
   :source "(load-resource \"hara/l0-resource.hal\")"
   :expect {:value 42 :type :integer}}
  {:id :module/refer
   :class :module
   :source "(require \"std/foundation.hal\" {:refer [inc]}) (inc 41)"
   :expect {:value 42 :type :integer}}
  {:id :module/refer-macros
   :class :module
   :source "(require \"hara/l0-macros.hal\" {:refer-macros [unless]}) (unless false 42)"
   :expect {:value 42 :type :integer}}
  {:id :module/core-bootstrap
   :class :module
   :source "(load-resource \"std/foundation.hal\") ((comp2 inc inc) 40)"
   :expect {:value 42 :type :integer}}
  {:id :module/core-collection-helpers
   :class :module
   :source "(load-resource \"std/foundation.hal\") (+ (first [1 2]) (second [2 3]) (first (rest [3 4])))"
   :expect {:value 8 :type :integer}}
  {:id :module/core-iterator-aliases
   :class :module
   :source "(load-resource \"std/foundation.hal\") (+ (first (map inc [3])) (iter-next (filter (fn [x] (= x 2)) [1 2])) (nth (iter-next (partition-pair [4 5])) 1))"
   :expect {:value 11 :type :integer}}
  {:id :module/core-predicate-reductions
   :class :module
   :source "(load-resource \"std/foundation.hal\") (+ (if (every? (fn [x] (> x 0)) [1 2]) 1 0) (if (any? (fn [x] (= x 2)) [1 2]) 2 0) (if (protocol-call IFind has? {:a nil} :a) 2 0))"
   :expect {:value 5 :type :integer}}
  {:id :module/core-nested-updates
   :class :module
   :source "(load-resource \"std/foundation.hal\") (get-in (update-in (assoc-in {} [:a :b] 2) [:a :b] + 2) [:a :b])"
   :expect {:value 4 :type :integer}}
  {:id :module/core-navigation
   :class :module
   :source "(load-resource \"std/foundation.hal\") (+ (last [1 2 3]) (first (vals {:a 1})) (if (protocol-call IFind has? {:a nil} :a) 1 0))"
   :expect {:value 5 :type :integer}}
  {:id :collection/ordinary-dissoc-navigation
   :class :collection
   :source "(+ (get (dissoc {:a 1 :b 2} :a) :b) (peek (pop '(1 2))))"
   :expect {:value 4 :type :integer}}
  {:id :module/core-generators
   :class :module
   :source "(load-resource \"std/foundation.hal\") (+ (iter-next (range 2 4)) (iter-next (iterate inc 4)) (iter-next (repeat 1 3)))"
   :expect {:value 9 :type :integer}}
  {:id :iterator/core-while-combinators
   :class :iterator
   :source "(load-resource \"std/foundation.hal\") (+ (iter-next (take-while (fn [x] (< x 3)) [1 2 3])) (iter-next (drop-while (fn [x] (< x 3)) [1 2 3])))"
   :expect {:value 4 :type :integer}}
  {:id :iterator/core-partition
   :class :iterator
   :source "(load-resource \"std/foundation.hal\") (+ (nth (iter-next (partition-all 2 [1 2 3])) 1) (nth (iter-next (partition 2 [1 2 3])) 0))"
   :expect {:value 3 :type :integer}}
  {:id :iterator/core-multi-map
   :class :iterator
   :source "(load-resource \"std/foundation.hal\") (+ (first (map + [1 2] [3 4])) (first (map + [1] [2 3])))"
   :expect {:value 7 :type :integer}}
  {:id :iterator/core-composition
   :class :iterator
   :source "(load-resource \"std/foundation.hal\") (+ (iter-next (interpose 0 [1 2])) (iter-next (interleave [1 2] [3 4])) (iter-next (iter-drop 1 (interleave [1 2] [3 4]))))"
   :expect {:value 5 :type :integer}}
  {:id :iterator/reduce
   :class :iterator
   :source "(+ (reduce + [1 2 3]) (reduce + 10 [1 2 3]))"
   :expect {:value 22 :type :integer}}
  {:id :iterator/comparison-functions
   :class :iterator
   :source "(+ (if (apply < [1 2 3]) 1 0) (if (apply = [4 4]) 2 0) (if (reduce not= [4 5]) 4 0))"
   :expect {:value 7 :type :integer}}
  {:id :module/classpath-require
   :class :module
   :source "(require \"std/foundation.hal\") ((comp2 inc inc) 40)"
   :expect {:value 42 :type :integer}}
  {:id :collection/bytes
   :class :collection
   :source "(protocol-call INth nth (bytes 1 2 -3) 2)"
   :expect {:value -3 :type :byte}}
  {:id :collection/core-functions
   :class :collection
   :source "(let [m (assoc {:a 1} :b 2)] (+ (count [1 2]) (get m :b) (nth [3 4] 1) (count (conj [5] 6))))"
   :expect {:value 10 :type :integer}}
  {:id :collection/nil-boundary
   :class :collection
   :source "(+ (count nil) (get nil :missing 7) (count (conj nil 1)) (count (cons 1 nil)))"
   :expect {:value 9 :type :integer}}
  {:id :mutable/array-set
   :class :runtime
   :source "(let [a (array 1 2)] (. a (set 1 7)) (. a (get 1)))"
   :expect {:value 7 :type :integer}}
  {:id :mutable/array-slice
   :class :runtime
   :source "(count (. (array 1 2 3) (slice 1 3)))"
   :expect {:value 2 :type :integer}}
  {:id :module/namespace-alias
   :class :module
   :source "(ns target) (def answer 42) (ns user) (alias t target) t/answer"
   :expect {:value 42 :type :integer}}
  {:id :module/namespace-refer
   :class :module
   :source "(ns target) (def answer 42) (ns user) (refer \"target\") answer"
   :expect {:value 42 :type :integer}}
  {:id :module/in-ns-use
   :class :module
   :source "(in-ns 'target) (def answer 42) (in-ns 'user) (use 'target) answer"
   :expect {:value 42 :type :integer}}
  {:id :numeric/compare
   :class :numeric
   :source "(< 1N 2N)"
   :expect {:value true :type :boolean}}
  {:id :numeric/mod
   :class :numeric
   :source "(mod 7 3)"
   :expect {:value 1 :type :integer}}
  {:id :numeric/negative-zero
   :class :numeric
   :source "(= -0.0 0.0)"
   :expect {:value true :type :boolean}}
  {:id :numeric/decimal-scale
   :class :numeric
   :source "(= 1.0M 1.00M)"
   :expect {:value true :type :boolean}}
  {:id :numeric/unary-division
   :class :numeric
   :source "(/ 2)"
   :expect {:value 0 :type :integer}}
  {:id :bytes/signed-unsigned
   :class :bytes
   :source "(+ (bytes/u8 -1) (bytes/s8 255))"
   :expect {:value 254 :type :integer}}
  {:id :bytes/ordinary-operations
   :class :bytes
   :source "(let [b (bytes 1 2)] (bytes/set b 0 9) (+ (bytes/count b) (bytes/get b 0)))"
   :expect {:value 11 :type :integer}}
  {:id :protocol/struct-extension
   :class :protocol
   :source "(protocol-call ICount count (Box 4))"
   :setup "(defstruct Box [size]) (extend-type Box ICount (count [self] (field self :size)))"
   :expect {:value 4 :type :integer}}
  {:id :protocol/multimethod
   :class :protocol
   :source "(defmulti kind (fn [x] (if (= x 1) :one :other))) (defmethod kind :one [x] \"one\") (defmethod kind :default [x] \"other\") (kind 2)"
   :expect {:value "other" :type :string}}
  {:id :interop/host-symbol-absent
   :class :interop
   :source "(host-symbol \"java.lang.String\")"
   :expect {:error :unbound-symbol
            :message "Unbound symbol: host-symbol"}}
  {:id :interop/host-get-absent
   :class :interop
   :source "(host-get nil \"value\")"
   :expect {:error :unbound-symbol
            :message "Unbound symbol: host-get"}}
  {:id :interop/host-call-absent
   :class :interop
   :source "(host-call nil \"value\")"
   :expect {:error :unbound-symbol
            :message "Unbound symbol: host-call"}}
  {:id :namespace/config-intrinsics-all
   :class :namespace
   :source "(ns app (:config {:intrinsics :all})) (bytes/count (str/encode \"x\"))"
   :expect {:value 1 :type :integer}}
  {:id :namespace/config-exclude-and-alias
   :class :namespace
   :source "(ns app (:config {:intrinsics {:exclude [bytes] :alias {string text}}})) (text/to-upper \"hara\")"
   :expect {:value "HARA" :type :string}}
  {:id :namespace/config-exclude-removes-alias
   :class :namespace
   :source "(ns app (:config {:intrinsics {:exclude [bytes]}})) (bytes/count (bytes 1))"
   :expect {:error :unbound-symbol
            :message "Unbound symbol: bytes/count"}}
  {:id :namespace/standalone-intrinsics-invalid
   :class :namespace
   :source "(ns app (:intrinsics :all))"
   :expect {:error :invalid-ns-clause
            :message ":intrinsics is valid only inside ns :config"}}
  {:id :namespace/standalone-builtins-invalid
   :class :namespace
   :source "(ns app (:builtins [inc]))"
   :expect {:error :invalid-ns-clause
            :message ":builtins is valid only inside ns :config"}}
  {:id :namespace/duplicate-config
   :class :namespace
   :source "(ns app (:config {}) (:config {}))"
   :expect {:error :invalid-ns-clause
            :message "ns accepts only one :config clause"}}
  {:id :namespace/unknown-config-key
   :class :namespace
   :source "(ns app (:config {:unexpected true}))"
   :expect {:error :invalid-ns-config
            :message "Unsupported :config option: :unexpected"}}
  {:id :namespace/unknown-intrinsics-option
   :class :namespace
   :source "(ns app (:config {:intrinsics {:unexpected true}}))"
   :expect {:error :invalid-ns-config
            :message "Unsupported :config :intrinsics option: :unexpected"}}
  {:id :namespace/unknown-intrinsic-library
   :class :namespace
   :source "(ns app (:config {:intrinsics {:exclude [unknown]}}))"
   :expect {:error :invalid-ns-config
            :message "Unknown intrinsic library"}}
  {:id :namespace/exclude-alias-conflict
   :class :namespace
   :source "(ns app (:config {:intrinsics {:exclude [bytes] :alias {bytes data}}}))"
   :expect {:error :invalid-ns-config
            :message "both excluded and aliased"}}
  {:id :namespace/alias-collision
   :class :namespace
   :source "(ns app (:config {:intrinsics {:alias {string data bytes data}}}))"
   :expect {:error :invalid-ns-config
            :message "Duplicate intrinsic alias target"}}
  {:id :namespace/blank-suppresses-referral
   :class :namespace
   :source "(ns app (:config {:blank true})) inc"
   :expect {:error :unbound-symbol
            :message "Unbound symbol: inc"}}
  {:id :namespace/blank-keeps-special-forms-and-aliases
   :class :namespace
   :source "(ns app (:config {:blank true})) (if true (bytes/count (str/encode \"xy\")) 0)"
   :expect {:value 2 :type :integer}}
  {:id :namespace/builtins-require-registered-exports
   :class :namespace
   :source "(ns app (:config {:builtins [inc]}))"
   :expect {:error :invalid-ns-config
            :message "No host builtins are registered for namespace: app"}}
  {:id :namespace/builtins-missing-export
   :class :namespace
   :source "(ns std.foundation (:config {:builtins [definitely-missing]}))"
   :expect {:error :invalid-ns-config
            :message "Missing builtin export: std.foundation/definitely-missing"}}
  {:id :namespace/builtins-activation-idempotent
   :class :namespace
   :source "(ns std.foundation (:config {:builtins [count]})) (std.foundation/count [41 42])"
   :expect {:value 2 :type :integer}}
  {:id :unsupported/ratio
   :class :unsupported
   :source "1/2"
   :expect {:error :ratio-not-supported
            :message "Ratios are not supported"}}]}
