mirror of
https://github.com/janet-lang/janet
synced 2024-12-24 23:40:27 +00:00
300 lines
8.8 KiB
Plaintext
300 lines
8.8 KiB
Plaintext
# Copyright (c) 2023 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)
|
|
|
|
# Set global variables to prevent some possible compiler optimizations
|
|
# that defeat point of the test
|
|
# 2771171
|
|
(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")
|
|
|
|
# McCarthy's 91 function
|
|
# 2771171
|
|
(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
|
|
# 23196ff
|
|
(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
|
|
# 911b0b1
|
|
(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")
|
|
|
|
# d6967a5
|
|
((fn []
|
|
(var accum 1)
|
|
(var counter 0)
|
|
(while (< counter 16)
|
|
(set accum (blshift accum 1))
|
|
(set counter (+ 1 counter)))
|
|
(assert (= accum 65536) "loop in closure")))
|
|
|
|
(var accum 1)
|
|
(var counter 0)
|
|
(while (< counter 16)
|
|
(set accum (blshift accum 1))
|
|
(set counter (+ 1 counter)))
|
|
(assert (= accum 65536) "loop globally")
|
|
|
|
# Fiber tests
|
|
# 21bd960
|
|
(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")
|
|
|
|
# Var arg tests
|
|
# f054586
|
|
(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
|
|
# d9f24ef
|
|
(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
|
|
# d9f24ef
|
|
#🐙🐙🐙🐙
|
|
|
|
(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")
|
|
|
|
# Test max triangle program
|
|
# c0e373f
|
|
# Find the maximum path from the top (root)
|
|
# of the triangle to the leaves of the triangle.
|
|
|
|
(defn myfold [xs ys]
|
|
(let [xs1 [;xs 0]
|
|
xs2 [0 ;xs]
|
|
m1 (map + xs1 ys)
|
|
m2 (map + xs2 ys)]
|
|
(map max m1 m2)))
|
|
|
|
(defn maxpath [t]
|
|
(extreme > (reduce myfold () t)))
|
|
|
|
# Test it
|
|
# Maximum path is 3 -> 10 -> 3 -> 9 for a total of 25
|
|
(def triangle '[
|
|
[3]
|
|
[7 10]
|
|
[4 3 7]
|
|
[8 9 1 3]
|
|
])
|
|
|
|
(assert (= (maxpath triangle) 25) `max triangle`)
|
|
|
|
# Large functions
|
|
# 6822400
|
|
(def manydefs (seq [i :range [0 300]]
|
|
(tuple 'def (gensym) (string "value_" i))))
|
|
(array/push manydefs (tuple * 10000 3 5 7 9))
|
|
(def f (compile ['do ;manydefs] (fiber/getenv (fiber/current))))
|
|
(assert (= (f) (* 10000 3 5 7 9)) "long function compilation")
|
|
|
|
# Closure in while loop
|
|
# abe7d59
|
|
(def closures (seq [i :range [0 5]] (fn [] i)))
|
|
(assert (= 0 ((get closures 0))) "closure in loop 0")
|
|
(assert (= 1 ((get closures 1))) "closure in loop 1")
|
|
(assert (= 2 ((get closures 2))) "closure in loop 2")
|
|
(assert (= 3 ((get closures 3))) "closure in loop 3")
|
|
(assert (= 4 ((get closures 4))) "closure in loop 4")
|
|
|
|
# Another regression test - no segfaults
|
|
# 6b4824c
|
|
(defn afn [x] x)
|
|
(var afn-var afn)
|
|
(var identity-var identity)
|
|
(var map-var map)
|
|
(var not-var not)
|
|
(assert (= 1 (try (afn-var) ([err] 1))) "bad arity 1")
|
|
(assert (= 4 (try ((fn [x y] (+ x y)) 1) ([_] 4))) "bad arity 2")
|
|
(assert (= 1 (try (identity-var) ([err] 1))) "bad arity 3")
|
|
(assert (= 1 (try (map-var) ([err] 1))) "bad arity 4")
|
|
(assert (= 1 (try (not-var) ([err] 1))) "bad arity 5")
|
|
|
|
# Detaching closure over non resumable fiber
|
|
# issue #317 - 7c4ffe9b9
|
|
(do
|
|
(defn f1
|
|
[a]
|
|
(defn f1 [] (++ (a 0)))
|
|
(defn f2 [] (++ (a 0)))
|
|
(error [f1 f2]))
|
|
(def [_ [f1 f2]] (protect (f1 @[0])))
|
|
# At time of writing, mark phase can detach closure envs.
|
|
(gccollect)
|
|
(assert (= 1 (f1)) "detach-non-resumable-closure 1")
|
|
(assert (= 2 (f2)) "detach-non-resumable-closure 2"))
|
|
|
|
# Dynamic defs
|
|
# ec65f03
|
|
(def staticdef1 0)
|
|
(defn staticdef1-inc [] (+ 1 staticdef1))
|
|
(assert (= 1 (staticdef1-inc)) "before redefinition without :redef")
|
|
(def staticdef1 1)
|
|
(assert (= 1 (staticdef1-inc)) "after redefinition without :redef")
|
|
(setdyn :redef true)
|
|
(def dynamicdef2 0)
|
|
(defn dynamicdef2-inc [] (+ 1 dynamicdef2))
|
|
(assert (= 1 (dynamicdef2-inc)) "before redefinition with dyn :redef")
|
|
(def dynamicdef2 1)
|
|
(assert (= 2 (dynamicdef2-inc)) "after redefinition with dyn :redef")
|
|
(setdyn :redef nil)
|
|
|
|
# missing symbols
|
|
# issue #914 - 1eb34989d
|
|
(defn lookup-symbol [sym] (defglobal sym 10) (dyn sym))
|
|
|
|
(setdyn :missing-symbol lookup-symbol)
|
|
|
|
(assert (= (eval-string "(+ a 5)") 15) "lookup missing symbol")
|
|
|
|
(setdyn :missing-symbol nil)
|
|
(setdyn 'a nil)
|
|
|
|
(assert-error "compile error" (eval-string "(+ a 5)"))
|
|
|
|
# 88813c4
|
|
(assert (deep= (in (disasm (defn a [] (def x 10) x)) :symbolmap)
|
|
@[[0 2 0 'a] [0 2 1 'x]])
|
|
"symbolmap when *debug* is true")
|
|
|
|
(defn a [arg]
|
|
(def x 10)
|
|
(do
|
|
(def y 20)
|
|
(def z 30)
|
|
(+ x y z)))
|
|
(def symbolslots (in (disasm a) :symbolslots))
|
|
(def f (asm (disasm a)))
|
|
(assert (deep= (in (disasm f) :symbolslots)
|
|
symbolslots)
|
|
"symbolslots survive disasm/asm")
|
|
|
|
(comment
|
|
(setdyn *debug* true)
|
|
(setdyn :pretty-format "%.40M")
|
|
(def f (fn [x] (fn [y] (+ x y))))
|
|
(assert (deep= (map last (in (disasm (f 10)) :symbolmap))
|
|
@['x 'y])
|
|
"symbolmap upvalues"))
|
|
|
|
(assert (deep= (in (disasm (defn a [arg]
|
|
(def x 10)
|
|
(do
|
|
(def y 20)
|
|
(def z 30)
|
|
(+ x y z)))) :symbolmap)
|
|
@[[0 6 0 'arg]
|
|
[0 6 1 'a]
|
|
[0 6 2 'x]
|
|
[1 6 3 'y]
|
|
[2 6 4 'z]])
|
|
"arg & inner symbolmap")
|
|
|
|
# 4782a76
|
|
(assert (= 10 (do (var x 10) (def y x) (++ x) y)) "no invalid aliasing")
|
|
|
|
(end-suite)
|
|
|