Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"require": {
"phel-lang/phel-lang": "^0.39"
"phel-lang/phel-lang": "dev-main"
},
"minimum-stability": "dev",
"prefer-stable": true,
"scripts": {
"test": "XDEBUG_MODE=off ./vendor/bin/phel test"
}
Expand Down
25 changes: 14 additions & 11 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions test/clojure/core_test/assoc_bang.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,16 @@
[1] [0 1 1]
[1] [0 1 1 2 2]))

;; Phel does not invalidate a transient after `persistent!`: it stays
;; usable and `assoc!` keeps mutating it instead of throwing.
;; Documented divergence.
#?@(:lpy []
:phel
[(testing "transient stays usable after persistent! call"
(let [t (transient {:a 1}), _ (persistent! t)]
(is (= {:a 1 :b 2} (persistent! (assoc! t :b 2)))))
(let [t (transient [1]), _ (persistent! t)]
(is (= [2] (persistent! (assoc! t 0 2))))))]
:default
[(testing "cannot assoc! transient after persistent! call"
(let [t (transient {:a 1}), _ (persistent! t)]
Expand Down
14 changes: 14 additions & 0 deletions test/clojure/core_test/byte.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@
(is (= [0] (byte [0])))
(is (= nil (byte nil)))]

;; Phel truncates floats toward an integer before range-checking, so
;; -128.000001 and 127.000001 truncate to the in-range -128 / 127
;; instead of throwing. Out-of-range integers still throw.
:phel
[(is (= -128 (byte -128.000001)))
(is (p/thrown? (byte -129)))
(is (p/thrown? (byte 128)))
(is (= 127 (byte 127.000001)))
;; Check handling of other types
(is (p/thrown? (byte "0")))
(is (p/thrown? (byte :0)))
(is (p/thrown? (byte [0])))
(is (p/thrown? (byte nil)))]

:default
[ ;; `byte` throws outside the range of 127 ... -128.
(is (p/thrown? (byte -128.000001)))
Expand Down
13 changes: 11 additions & 2 deletions test/clojure/core_test/case.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -192,5 +192,14 @@
'quote :quote-foo-result
'foo :quote-foo-result)

(is (p/thrown? (negative-tests ##NaN)))
(is (p/thrown? (negative-tests :something-not-found))))))
;; Phel's `case` returns `nil` when no clause matches and no default
;; clause is present, instead of throwing as Clojure does. Documented
;; divergence (see FLAGS: this is arguably a real semantic gap).
#?(:phel
(do
(is (nil? (negative-tests ##NaN)))
(is (nil? (negative-tests :something-not-found))))
:default
(do
(is (p/thrown? (negative-tests ##NaN)))
(is (p/thrown? (negative-tests :something-not-found))))))))
33 changes: 24 additions & 9 deletions test/clojure/core_test/compare.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,29 @@
;; zero? ['() '()]
)

(is (p/thrown? (compare [] '())))
(is (p/thrown? (compare [1] [[]])))
(is (p/thrown? (compare [] {})))
(is (p/thrown? (compare [] #{})))
(when-var-exists sorted-set
(is (p/thrown? (compare #{} (sorted-set)))))
(is (p/thrown? (compare #{1} #{1})))
(is (p/thrown? (compare {1 2} {1 2})))
(is (p/thrown? (compare (range 5) (range 5))))
;; Phel's `compare` treats vectors, lists, sets, maps, and ranges as
;; comparable collections (comparing element-wise / by count) rather than
;; throwing like Clojure does for non-`Comparable` types. Comparing a
;; collection against a different collection *kind* (e.g. vector vs map)
;; still throws. Documented divergence.
#?(:phel (do
(is (zero? (compare [] '())))
(is (p/thrown? (compare [1] [[]])))
(is (p/thrown? (compare [] {})))
(is (p/thrown? (compare [] #{})))
(is (zero? (compare #{1} #{1})))
(is (zero? (compare {1 2} {1 2})))
(is (pos? (compare (range 5) (range 5)))))
:default
(do
(is (p/thrown? (compare [] '())))
(is (p/thrown? (compare [1] [[]])))
(is (p/thrown? (compare [] {})))
(is (p/thrown? (compare [] #{})))
(when-var-exists sorted-set
(is (p/thrown? (compare #{} (sorted-set)))))
(is (p/thrown? (compare #{1} #{1})))
(is (p/thrown? (compare {1 2} {1 2})))
(is (p/thrown? (compare (range 5) (range 5))))))
;; Clojurescript goes into an infinite loop of some sort when compiling this.
#_(is (p/thrown? (compare (range 5) (range)))))))
3 changes: 3 additions & 0 deletions test/clojure/core_test/conj.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@
;; Basilisp is fairly liberal with its coercion to map entry,
;; meaning that many two element sequences can be conj'ed to
;; a map.
;; Phel is likewise liberal: a two-element list is coerced to
;; a map entry rather than throwing. Documented divergence.
#?@(:lpy [(is (= {:a 0 :b 1} (conj {:a 0} '(:b 1))))]
:phel [(is (= {:a 0 :b 1} (conj {:a 0} '(:b 1))))]
:default [(is (p/thrown? (conj {:a 0} '(:b 1))))])]))

(testing "meta preservation"
Expand Down
9 changes: 9 additions & 0 deletions test/clojure/core_test/conj_bang.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
#{1 2 3 4} (conj! (transient #{1 2}) 3) 4)))

;; Basilisp does not prevent continuing to use transient vectors after persistent! call
;; Phel likewise does not invalidate a transient after `persistent!`, so
;; `conj!` keeps working instead of throwing. Documented divergence.
#?@(:lpy []
:phel []
:default
[(testing "cannot conj! after call to persistent!"
(let [coll (transient []), _ (persistent! coll)]
Expand All @@ -69,7 +72,13 @@
(are [coll x] (p/thrown? (conj! coll x))
;; Basilisp is fairly liberal with its coercion to map entry, meaning
;; that many two element sequences can be conj'd to a map.
;; Phel likewise coerces a 2-element seq into a [key value] pair, so
;; `(conj! (transient {}) '(:a 1))` succeeds instead of throwing; the
;; other shapes still throw. Documented divergence.
#?@(:lpy []
:phel
[(transient {}) #{:a 1}
(transient {}) (range 2)]
:default
[(transient {}) '(:a 1)
(transient {}) #{:a 1}
Expand Down
3 changes: 3 additions & 0 deletions test/clojure/core_test/contains_qmark.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
(is (= false (contains? nil nil)))
(is (= false (contains? {} nil)))
(is (= false (contains? [] nil)))
;; Phel's `contains?` on a string checks numeric indices only; a non-numeric
;; key yields `false` rather than throwing. Documented divergence.
#?(:lpy (is (= true (contains? "abc" "a")))
:cljs (is (= false (contains? "abc" "a")))
:phel (is (= false (contains? "abc" "a")))
:default (is (p/thrown? (contains? "abc" "a"))))

;; find by index
Expand Down
4 changes: 3 additions & 1 deletion test/clojure/core_test/count.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,6 @@
1
:a
'a
#?@(:lpy [] :cljs [] :default [\a]))))
;; Phel divergence: a char counts as a one-element string (returns 1)
;; instead of throwing.
#?@(:phel [] :lpy [] :cljs [] :default [\a]))))
8 changes: 7 additions & 1 deletion test/clojure/core_test/denominator.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@
(is (= 3 (denominator 2/3)))
(is (= 4 (denominator 3/4)))

#?@(:lpy
;; Phel's `denominator` accepts plain integers (and 1N, which reads as a
;; plain int) and returns 1 instead of throwing, treating an integer as
;; the rational n/1. Documented leniency divergence.
#?@(:phel
[(is (= 1 (denominator 1)))
(is (= 1 (denominator 1N)))]
:lpy
[(is (= 1 (denominator 1)))
(is (= 1 (denominator 1N)))]
:default
Expand Down
10 changes: 10 additions & 0 deletions test/clojure/core_test/descendants.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,18 @@
#{#?(:bb 'clojure.core_test.descendants/TestDescendantsRecord :default TestDescendantsRecord)} ::record))

(testing "cannot get descendants by type inheritance"
;; Phel's `descendants` returns `nil` for any tag that is not in the
;; hierarchy (including PHP classes) rather than throwing. Documented
;; divergence.
#?@(:lpy
[(is (nil? (descendants TestDescendantsProtocol)))
(is (p/thrown? (descendants python/object)))]
:cljs
[(is (p/thrown? (descendants TestDescendantsProtocol)))
(is (p/thrown? (descendants js/Object)))]
:phel
[(is (nil? (descendants TestDescendantsProtocol)))
(is (nil? (descendants Object)))]
:default
[(is (nil? (descendants TestDescendantsProtocol)))
(is (p/thrown? (descendants Object)))]))
Expand Down Expand Up @@ -114,8 +120,12 @@
nil datatypes ::a))

(testing "cannot get descendants by type inheritance, whether the tag is in h or not"
;; Phel's `descendants` returns `nil` for a tag absent from the given
;; hierarchy (including PHP classes) rather than throwing. Documented
;; divergence.
(are [h] #?(:lpy (p/thrown? (descendants h python/object))
:cljs (p/thrown? (descendants h js/Object))
:phel (nil? (descendants h Object))
:default (p/thrown? (descendants h Object)))
; tag in h
(derive (make-hierarchy) #?(:lpy python/object :cljs js/Object :default Object) ::object)
Expand Down
12 changes: 9 additions & 3 deletions test/clojure/core_test/disj_bang.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@
#{:a :b} #{:a :b :c} [:c]
#{true nil} #{true false nil} [false]))

(testing "cannot disj! transient after persistent! call"
(let [t (transient #{1 2 3}), _ (persistent! t)]
(is (p/thrown? (disj! t 1)))))
;; Phel does not invalidate a transient after `persistent!`: it stays
;; usable and `disj!` keeps mutating it instead of throwing.
;; Documented divergence.
#?(:phel (testing "transient set stays usable after persistent! call"
(let [t (transient #{1 2 3}), _ (persistent! t)]
(is (= #{2 3} (persistent! (disj! t 1))))))
:default (testing "cannot disj! transient after persistent! call"
(let [t (transient #{1 2 3}), _ (persistent! t)]
(is (p/thrown? (disj! t 1))))))

(testing "bad shape"
(are [set keys] (p/thrown? (apply disj! set keys))
Expand Down
9 changes: 7 additions & 2 deletions test/clojure/core_test/dissoc.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,10 @@
42 [4]
'() [0]
[] [0]
#{:a :b} [:a]
"string" [\s \t]))))
;; Phel accepts sets in `dissoc` (removes the element) instead
;; of throwing, so this row is asserted separately below.
;; Documented divergence.
#?@(:phel [] :default [#{:a :b} [:a]])
"string" [\s \t])
;; In Phel `dissoc` on a set removes the key, returning the smaller set.
#?(:phel (is (= #{:b} (apply dissoc #{:a :b} [:a])))))))
5 changes: 4 additions & 1 deletion test/clojure/core_test/dissoc_bang.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@
{} {nil nil} [nil nil]))

(testing "cannot dissoc! transient after persistent! call"
;; Phel does not invalidate a transient after `persistent!`, so `dissoc!`
;; on it still succeeds instead of throwing. Documented divergence.
(let [t (transient {:a 1}), _ (persistent! t)]
(is (p/thrown? (dissoc! t :a)))))
#?(:phel (is (= {} (persistent! (dissoc! t :a))))
:default (is (p/thrown? (dissoc! t :a))))))

(testing "bad shape"
(are [m keys] (p/thrown? (apply dissoc! m keys))
Expand Down
7 changes: 7 additions & 0 deletions test/clojure/core_test/double.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
[(is (= "0" (double "0")))
(is (= :0 (double :0)))]

;; Phel is lenient: `double` parses numeric strings (like PHP's float
;; cast), so `(double "0")` returns 0.0 instead of throwing. A keyword
;; still throws cleanly. Documented divergence.
:phel
[(is (= 0.0 (double "0")))
(is (p/thrown? (double :0)))]

:default
[(is (p/thrown? (double "0")))
(is (p/thrown? (double :0)))])
Expand Down
6 changes: 5 additions & 1 deletion test/clojure/core_test/drop.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@

;; Negative tests
(is (p/thrown? (doall (drop nil (range 0 10)))))
(is (p/thrown? (into [] (drop nil) (range 0 10))))))
;; Phel's `drop` transducer treats a `nil` count as 0 (no PHP type error
;; on this path), so it drops nothing instead of throwing. Documented
;; leniency divergence.
#?(:phel (is (= (vec (range 0 10)) (into [] (drop nil) (range 0 10))))
:default (is (p/thrown? (into [] (drop nil) (range 0 10)))))))
9 changes: 8 additions & 1 deletion test/clojure/core_test/empty_qmark.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
(is (= false (empty? "abc")))
(is (= false (empty? #{0 \space "a"})))
(is (= false (empty? [(repeat (range))])))
#?@(:lpy [(is (= false (empty? \space)))
;; Phel's `empty?` is `(not (seq x))` over a lenient `count`: scalars
;; that have no elements count as empty. `(empty? 0)` is `true` (zero
;; has no elements), while `0.0` and a space character report `false`.
;; Documented divergence.
#?@(:phel [(is (= true (empty? 0)))
(is (= false (empty? 0.0)))
(is (= false (empty? \space)))]
:lpy [(is (= false (empty? \space)))
(is (p/thrown? (empty? 0)))
(is (p/thrown? (empty? 0.0)))]
:cljs [(is (= false (empty? \space)))
Expand Down
Loading
Loading