mirror of
https://github.com/janet-lang/janet
synced 2024-11-17 22:24:49 +00:00
6e38bf1578
We did not allow arbitrary utf8 to be printed with %j, even though the parser allows. Thos changes uses the existing built in utf8 detectiotion to exclude only unprintable symbols from the docstring.
423 lines
15 KiB
Clojure
423 lines
15 KiB
Clojure
# Copyright (c) 2021 Calvin Rose
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to
|
|
# deal in the Software without restriction, including without limitation the
|
|
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
# sell copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
# IN THE SOFTWARE.
|
|
|
|
(import ./helper :prefix "" :exit true)
|
|
(start-suite 0)
|
|
|
|
(assert (= 10 (+ 1 2 3 4)) "addition")
|
|
(assert (= -8 (- 1 2 3 4)) "subtraction")
|
|
(assert (= 24 (* 1 2 3 4)) "multiplication")
|
|
(assert (= 4 (blshift 1 2)) "left shift")
|
|
(assert (= 1 (brshift 4 2)) "right shift")
|
|
(assert (< 1 2 3 4 5 6) "less than integers")
|
|
(assert (< 1.0 2.0 3.0 4.0 5.0 6.0) "less than reals")
|
|
(assert (> 6 5 4 3 2 1) "greater than integers")
|
|
(assert (> 6.0 5.0 4.0 3.0 2.0 1.0) "greater than reals")
|
|
(assert (<= 1 2 3 3 4 5 6) "less than or equal to integers")
|
|
(assert (<= 1.0 2.0 3.0 3.0 4.0 5.0 6.0) "less than or equal to reals")
|
|
(assert (>= 6 5 4 4 3 2 1) "greater than or equal to integers")
|
|
(assert (>= 6.0 5.0 4.0 4.0 3.0 2.0 1.0) "greater than or equal to reals")
|
|
(assert (= 7 (% 20 13)) "modulo 1")
|
|
(assert (= -7 (% -20 13)) "modulo 2")
|
|
|
|
(assert (< 1.0 nil false true
|
|
(fiber/new (fn [] 1))
|
|
"hi"
|
|
(quote hello)
|
|
:hello
|
|
(array 1 2 3)
|
|
(tuple 1 2 3)
|
|
(table "a" "b" "c" "d")
|
|
(struct 1 2 3 4)
|
|
(buffer "hi")
|
|
(fn [x] (+ x x))
|
|
print) "type ordering")
|
|
|
|
(assert (= (string (buffer "123" "456")) (string @"123456")) "buffer literal")
|
|
(assert (= (get {} 1) nil) "get nil from empty struct")
|
|
(assert (= (get @{} 1) nil) "get nil from empty table")
|
|
(assert (= (get {:boop :bap} :boop) :bap) "get non nil from struct")
|
|
(assert (= (get @{:boop :bap} :boop) :bap) "get non nil from table")
|
|
(assert (= (get @"\0" 0) 0) "get non nil from buffer")
|
|
(assert (= (get @"\0" 1) nil) "get nil from buffer oob")
|
|
(assert (put @{} :boop :bap) "can add to empty table")
|
|
(assert (put @{1 3} :boop :bap) "can add to non-empty table")
|
|
|
|
(assert (not false) "false literal")
|
|
(assert true "true literal")
|
|
(assert (not nil) "nil literal")
|
|
(assert (= 7 (bor 3 4)) "bit or")
|
|
(assert (= 0 (band 3 4)) "bit and")
|
|
(assert (= 0xFF (bxor 0x0F 0xF0)) "bit xor")
|
|
(assert (= 0xF0 (bxor 0xFF 0x0F)) "bit xor 2")
|
|
|
|
# Set global variables to prevent some possible compiler optimizations that defeat point of the test
|
|
(var zero 0)
|
|
(var one 1)
|
|
(var two 2)
|
|
(var three 3)
|
|
(var plus +)
|
|
(assert (= 22 (plus one (plus 1 2 two) (plus 8 (plus zero 1) 4 three))) "nested function calls")
|
|
|
|
# String literals
|
|
(assert (= "abcd" "\x61\x62\x63\x64") "hex escapes")
|
|
(assert (= "\e" "\x1B") "escape character")
|
|
(assert (= "\x09" "\t") "tab character")
|
|
|
|
# McCarthy's 91 function
|
|
(var f91 nil)
|
|
(set f91 (fn [n] (if (> n 100) (- n 10) (f91 (f91 (+ n 11))))))
|
|
(assert (= 91 (f91 10)) "f91(10) = 91")
|
|
(assert (= 91 (f91 11)) "f91(11) = 91")
|
|
(assert (= 91 (f91 20)) "f91(20) = 91")
|
|
(assert (= 91 (f91 31)) "f91(31) = 91")
|
|
(assert (= 91 (f91 100)) "f91(100) = 91")
|
|
(assert (= 91 (f91 101)) "f91(101) = 91")
|
|
(assert (= 92 (f91 102)) "f91(102) = 92")
|
|
(assert (= 93 (f91 103)) "f91(103) = 93")
|
|
(assert (= 94 (f91 104)) "f91(104) = 94")
|
|
|
|
# Fibonacci
|
|
(def fib (do (var fib nil) (set fib (fn [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
|
|
(def fib2 (fn fib2 [n] (if (< n 2) n (+ (fib2 (- n 1)) (fib2 (- n 2))))))
|
|
|
|
(assert (= (fib 0) (fib2 0) 0) "fib(0)")
|
|
(assert (= (fib 1) (fib2 1) 1) "fib(1)")
|
|
(assert (= (fib 2) (fib2 2) 1) "fib(2)")
|
|
(assert (= (fib 3) (fib2 3) 2) "fib(3)")
|
|
(assert (= (fib 4) (fib2 4) 3) "fib(4)")
|
|
(assert (= (fib 5) (fib2 5) 5) "fib(5)")
|
|
(assert (= (fib 6) (fib2 6) 8) "fib(6)")
|
|
(assert (= (fib 7) (fib2 7) 13) "fib(7)")
|
|
(assert (= (fib 8) (fib2 8) 21) "fib(8)")
|
|
(assert (= (fib 9) (fib2 9) 34) "fib(9)")
|
|
(assert (= (fib 10) (fib2 10) 55) "fib(10)")
|
|
|
|
# Closure in non function scope
|
|
(def outerfun (fn [x y]
|
|
(def c (do
|
|
(def someval (+ 10 y))
|
|
(def ctemp (if x (fn [] someval) (fn [] y)))
|
|
ctemp
|
|
))
|
|
(+ 1 2 3 4 5 6 7)
|
|
c))
|
|
|
|
(assert (= ((outerfun 1 2)) 12) "inner closure 1")
|
|
(assert (= ((outerfun nil 2)) 2) "inner closure 2")
|
|
(assert (= ((outerfun false 3)) 3) "inner closure 3")
|
|
|
|
(assert (= '(1 2 3) (quote (1 2 3)) (tuple 1 2 3)) "quote shorthand")
|
|
|
|
((fn []
|
|
(var accum 1)
|
|
(var count 0)
|
|
(while (< count 16)
|
|
(set accum (blshift accum 1))
|
|
(set count (+ 1 count)))
|
|
(assert (= accum 65536) "loop in closure")))
|
|
|
|
(var accum 1)
|
|
(var count 0)
|
|
(while (< count 16)
|
|
(set accum (blshift accum 1))
|
|
(set count (+ 1 count)))
|
|
(assert (= accum 65536) "loop globally")
|
|
|
|
(assert (= (struct 1 2 3 4 5 6 7 8) (struct 7 8 5 6 3 4 1 2)) "struct order does not matter 1")
|
|
(assert (= (struct
|
|
:apple 1
|
|
6 :bork
|
|
'(1 2 3) 5)
|
|
(struct
|
|
6 :bork
|
|
'(1 2 3) 5
|
|
:apple 1)) "struct order does not matter 2")
|
|
|
|
# Symbol function
|
|
|
|
(assert (= (symbol "abc" 1 2 3) 'abc123) "symbol function")
|
|
|
|
# Fiber tests
|
|
|
|
(def afiber (fiber/new (fn []
|
|
(def x (yield))
|
|
(error (string "hello, " x))) :ye))
|
|
|
|
(resume afiber) # first resume to prime
|
|
(def afiber-result (resume afiber "world!"))
|
|
|
|
(assert (= afiber-result "hello, world!") "fiber error result")
|
|
(assert (= (fiber/status afiber) :error) "fiber error status")
|
|
|
|
# yield tests
|
|
|
|
(def t (fiber/new (fn [&] (yield 1) (yield 2) 3)))
|
|
|
|
(assert (= 1 (resume t)) "initial transfer to new fiber")
|
|
(assert (= 2 (resume t)) "second transfer to fiber")
|
|
(assert (= 3 (resume t)) "return from fiber")
|
|
(assert (= (fiber/status t) :dead) "finished fiber is dead")
|
|
|
|
# Var arg tests
|
|
|
|
(def vargf (fn [more] (apply + more)))
|
|
|
|
(assert (= 0 (vargf @[])) "var arg no arguments")
|
|
(assert (= 1 (vargf @[1])) "var arg no packed arguments")
|
|
(assert (= 3 (vargf @[1 2])) "var arg tuple size 1")
|
|
(assert (= 10 (vargf @[1 2 3 4])) "var arg tuple size 2, 2 normal args")
|
|
(assert (= 110 (vargf @[1 2 3 4 10 10 10 10 10 10 10 10 10 10])) "var arg large tuple")
|
|
|
|
# Higher order functions
|
|
|
|
(def compose (fn [f g] (fn [& xs] (f (apply g xs)))))
|
|
|
|
(def -+ (compose - +))
|
|
(def +- (compose + -))
|
|
|
|
(assert (= (-+ 1 2 3 4) -10) "compose - +")
|
|
(assert (= (+- 1 2 3 4) -8) "compose + -")
|
|
(assert (= ((compose -+ +-) 1 2 3 4) 8) "compose -+ +-")
|
|
(assert (= ((compose +- -+) 1 2 3 4) 10) "compose +- -+")
|
|
|
|
# UTF-8
|
|
|
|
#🐙🐙🐙🐙
|
|
|
|
(defn foo [Θa Θb Θc] 0)
|
|
(def 🦊 :fox)
|
|
(def 🐮 :cow)
|
|
(assert (= (string "🐼" 🦊 🐮) "🐼foxcow") "emojis 🙉 :)")
|
|
(assert (not= 🦊 "🦊") "utf8 strings are not symbols and vice versa")
|
|
(assert (= "\U01F637" "😷") "unicode escape 1")
|
|
(assert (= "\u2623" "\U002623" "☣") "unicode escape 2")
|
|
(assert (= "\u24c2" "\U0024c2" "Ⓜ") "unicode escape 3")
|
|
(assert (= "\u0061" "a") "unicode escape 4")
|
|
|
|
# Symbols with @ character
|
|
|
|
(def @ 1)
|
|
(assert (= @ 1) "@ symbol")
|
|
(def @-- 2)
|
|
(assert (= @-- 2) "@-- symbol")
|
|
(def @hey 3)
|
|
(assert (= @hey 3) "@hey symbol")
|
|
|
|
# Merge sort
|
|
|
|
# Imperative (and verbose) merge sort merge
|
|
(defn merge
|
|
[xs ys]
|
|
(def ret @[])
|
|
(def xlen (length xs))
|
|
(def ylen (length ys))
|
|
(var i 0)
|
|
(var j 0)
|
|
# Main merge
|
|
(while (if (< i xlen) (< j ylen))
|
|
(def xi (get xs i))
|
|
(def yj (get ys j))
|
|
(if (< xi yj)
|
|
(do (array/push ret xi) (set i (+ i 1)))
|
|
(do (array/push ret yj) (set j (+ j 1)))))
|
|
# Push rest of xs
|
|
(while (< i xlen)
|
|
(def xi (get xs i))
|
|
(array/push ret xi)
|
|
(set i (+ i 1)))
|
|
# Push rest of ys
|
|
(while (< j ylen)
|
|
(def yj (get ys j))
|
|
(array/push ret yj)
|
|
(set j (+ j 1)))
|
|
ret)
|
|
|
|
(assert (apply <= (merge @[1 3 5] @[2 4 6])) "merge sort merge 1")
|
|
(assert (apply <= (merge @[1 2 3] @[4 5 6])) "merge sort merge 2")
|
|
(assert (apply <= (merge @[1 3 5] @[2 4 6 6 6 9])) "merge sort merge 3")
|
|
(assert (apply <= (merge '(1 3 5) @[2 4 6 6 6 9])) "merge sort merge 4")
|
|
|
|
(assert (deep= @[1 2 3 4 5] (sort @[5 3 4 1 2])) "sort 1")
|
|
(assert (deep= @[{:a 1} {:a 4} {:a 7}] (sort-by |($ :a) @[{:a 4} {:a 7} {:a 1}])) "sort 2")
|
|
(assert (deep= @[1 2 3 4 5] (sorted [5 3 4 1 2])) "sort 3")
|
|
(assert (deep= @[{:a 1} {:a 4} {:a 7}] (sorted-by |($ :a) [{:a 4} {:a 7} {:a 1}])) "sort 4")
|
|
|
|
# Gensym tests
|
|
|
|
(assert (not= (gensym) (gensym)) "two gensyms not equal")
|
|
((fn []
|
|
(def syms (table))
|
|
(var count 0)
|
|
(while (< count 128)
|
|
(put syms (gensym) true)
|
|
(set count (+ 1 count)))
|
|
(assert (= (length syms) 128) "many symbols")))
|
|
|
|
# Let
|
|
|
|
(assert (= (let [a 1 b 2] (+ a b)) 3) "simple let")
|
|
(assert (= (let [[a b] @[1 2]] (+ a b)) 3) "destructured let")
|
|
(assert (= (let [[a [c d] b] @[1 (tuple 4 3) 2]] (+ a b c d)) 10) "double destructured let")
|
|
|
|
# Macros
|
|
|
|
(defn dub [x] (+ x x))
|
|
(assert (= 2 (dub 1)) "defn macro")
|
|
(do
|
|
(defn trip [x] (+ x x x))
|
|
(assert (= 3 (trip 1)) "defn macro triple"))
|
|
(do
|
|
(var i 0)
|
|
(when true
|
|
(++ i)
|
|
(++ i)
|
|
(++ i)
|
|
(++ i)
|
|
(++ i)
|
|
(++ i))
|
|
(assert (= i 6) "when macro"))
|
|
|
|
# Denormal tables and structs
|
|
|
|
(assert (= (length {1 2 nil 3}) 1) "nil key struct literal")
|
|
(assert (= (length @{1 2 nil 3}) 1) "nil key table literal")
|
|
(assert (= (length (struct 1 2 nil 3)) 1) "nil key struct ctor")
|
|
(assert (= (length (table 1 2 nil 3)) 1) "nil key table ctor")
|
|
|
|
(assert (= (length (struct (/ 0 0) 2 1 3)) 1) "nan key struct ctor")
|
|
(assert (= (length (table (/ 0 0) 2 1 3)) 1) "nan key table ctor")
|
|
(assert (= (length {1 2 nil 3}) 1) "nan key struct literal")
|
|
(assert (= (length @{1 2 nil 3}) 1) "nan key table literal")
|
|
|
|
(assert (= (length (struct 2 1 3 nil)) 1) "nil value struct ctor")
|
|
(assert (= (length (table 2 1 3 nil)) 1) "nil value table ctor")
|
|
(assert (= (length {1 2 3 nil}) 1) "nil value struct literal")
|
|
(assert (= (length @{1 2 3 nil}) 1) "nil value table literal")
|
|
|
|
# Regression Test
|
|
(assert (= 1 (((compile '(fn [] 1) @{})))) "regression test")
|
|
|
|
# Regression Test #137
|
|
(def [a b c] (range 10))
|
|
(assert (= a 0) "regression #137 (1)")
|
|
(assert (= b 1) "regression #137 (2)")
|
|
(assert (= c 2) "regression #137 (3)")
|
|
|
|
(var [x y z] (range 10))
|
|
(assert (= x 0) "regression #137 (4)")
|
|
(assert (= y 1) "regression #137 (5)")
|
|
(assert (= z 2) "regression #137 (6)")
|
|
|
|
(assert (= true ;(map truthy? [0 "" true @{} {} [] '()])) "truthy values")
|
|
(assert (= false ;(map truthy? [nil false])) "non-truthy values")
|
|
|
|
# Struct and Table duplicate elements
|
|
(assert (= {:a 3 :b 2} {:a 1 :b 2 :a 3}) "struct literal duplicate keys")
|
|
(assert (= {:a 3 :b 2} (struct :a 1 :b 2 :a 3)) "struct constructor duplicate keys")
|
|
(assert (deep= @{:a 3 :b 2} @{:a 1 :b 2 :a 3}) "table literal duplicate keys")
|
|
(assert (deep= @{:a 3 :b 2} (table :a 1 :b 2 :a 3)) "table constructor duplicate keys")
|
|
|
|
## Polymorphic comparison -- Issue #272
|
|
|
|
# confirm polymorphic comparison delegation to primitive comparators:
|
|
(assert (= 0 (cmp 3 3)) "compare-primitive integers (1)")
|
|
(assert (= -1 (cmp 3 5)) "compare-primitive integers (2)")
|
|
(assert (= 1 (cmp "foo" "bar")) "compare-primitive strings")
|
|
(assert (= 0 (compare 1 1)) "compare integers (1)")
|
|
(assert (= -1 (compare 1 2)) "compare integers (2)")
|
|
(assert (= 1 (compare "foo" "bar")) "compare strings (1)")
|
|
|
|
(assert (compare< 1 2 3 4 5 6) "compare less than integers")
|
|
(assert (not (compare> 1 2 3 4 5 6)) "compare not greater than integers")
|
|
(assert (compare< 1.0 2.0 3.0 4.0 5.0 6.0) "compare less than reals")
|
|
(assert (compare> 6 5 4 3 2 1) "compare greater than integers")
|
|
(assert (compare> 6.0 5.0 4.0 3.0 2.0 1.0) "compare greater than reals")
|
|
(assert (not (compare< 6.0 5.0 4.0 3.0 2.0 1.0)) "compare less than reals")
|
|
(assert (compare<= 1 2 3 3 4 5 6) "compare less than or equal to integers")
|
|
(assert (compare<= 1.0 2.0 3.0 3.0 4.0 5.0 6.0) "compare less than or equal to reals")
|
|
(assert (compare>= 6 5 4 4 3 2 1) "compare greater than or equal to integers")
|
|
(assert (compare>= 6.0 5.0 4.0 4.0 3.0 2.0 1.0) "compare greater than or equal to reals")
|
|
(assert (compare< 1.0 nil false true
|
|
(fiber/new (fn [] 1))
|
|
"hi"
|
|
(quote hello)
|
|
:hello
|
|
(array 1 2 3)
|
|
(tuple 1 2 3)
|
|
(table "a" "b" "c" "d")
|
|
(struct 1 2 3 4)
|
|
(buffer "hi")
|
|
(fn [x] (+ x x))
|
|
print) "compare type ordering")
|
|
|
|
# test polymorphic compare with 'objects' (table/setproto)
|
|
(def mynum
|
|
@{:type :mynum :v 0 :compare
|
|
(fn [self other]
|
|
(case (type other)
|
|
:number (cmp (self :v) other)
|
|
:table (when (= (get other :type) :mynum)
|
|
(cmp (self :v) (other :v)))))})
|
|
|
|
(let [n3 (table/setproto @{:v 3} mynum)]
|
|
(assert (= 0 (compare 3 n3)) "compare num to object (1)")
|
|
(assert (= -1 (compare n3 4)) "compare object to num (2)")
|
|
(assert (= 1 (compare (table/setproto @{:v 4} mynum) n3)) "compare object to object")
|
|
(assert (compare< 2 n3 4) "compare< poly")
|
|
(assert (compare> 4 n3 2) "compare> poly")
|
|
(assert (compare<= 2 3 n3 4) "compare<= poly")
|
|
(assert (compare= 3 n3 (table/setproto @{:v 3} mynum)) "compare= poly")
|
|
(assert (deep= (sorted @[4 5 n3 2] compare<) @[2 n3 4 5]) "polymorphic sort"))
|
|
|
|
(let [MAX_INT_64_STRING "9223372036854775807"
|
|
MAX_UINT_64_STRING "18446744073709551615"
|
|
MAX_INT_IN_DBL_STRING "9007199254740991"
|
|
NAN (math/log -1)
|
|
INF (/ 1 0)
|
|
MINUS_INF (/ -1 0)
|
|
compare-poly-tests
|
|
[[(int/s64 3) (int/u64 3) 0]
|
|
[(int/s64 -3) (int/u64 3) -1]
|
|
[(int/s64 3) (int/u64 2) 1]
|
|
[(int/s64 3) 3 0] [(int/s64 3) 4 -1] [(int/s64 3) -9 1]
|
|
[(int/u64 3) 3 0] [(int/u64 3) 4 -1] [(int/u64 3) -9 1]
|
|
[3 (int/s64 3) 0] [3 (int/s64 4) -1] [3 (int/s64 -5) 1]
|
|
[3 (int/u64 3) 0] [3 (int/u64 4) -1] [3 (int/u64 2) 1]
|
|
[(int/s64 MAX_INT_64_STRING) (int/u64 MAX_UINT_64_STRING) -1]
|
|
[(int/s64 MAX_INT_IN_DBL_STRING) (scan-number MAX_INT_IN_DBL_STRING) 0]
|
|
[(int/u64 MAX_INT_IN_DBL_STRING) (scan-number MAX_INT_IN_DBL_STRING) 0]
|
|
[(+ 1 (int/u64 MAX_INT_IN_DBL_STRING)) (scan-number MAX_INT_IN_DBL_STRING) 1]
|
|
[(int/s64 0) INF -1] [(int/u64 0) INF -1]
|
|
[MINUS_INF (int/u64 0) -1] [MINUS_INF (int/s64 0) -1]
|
|
[(int/s64 1) NAN 0] [NAN (int/u64 1) 0]]]
|
|
(each [x y c] compare-poly-tests
|
|
(assert (= c (compare x y)) (string/format "compare polymorphic %q %q %d" x y c))))
|
|
|
|
(assert (= nil (any? [])) "any? 1")
|
|
(assert (= nil (any? [false nil])) "any? 2")
|
|
(assert (= nil (any? [nil false])) "any? 3")
|
|
(assert (= 1 (any? [1])) "any? 4")
|
|
(assert (nan? (any? [nil math/nan nil])) "any? 5")
|
|
(assert (= true (any? [nil nil false nil nil true nil nil nil nil false :a nil])) "any? 6")
|
|
|
|
(end-suite)
|
|
|