mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 01:37:19 +00:00
b6175e4296
These functions are designed to make it easier to properly preserve the sourcemap and tuple type in macros. This commit also modifies the threading macros to make use of these functions.
257 lines
9.4 KiB
Plaintext
257 lines
9.4 KiB
Plaintext
# Copyright (c) 2023 Calvin Rose & contributors
|
|
#
|
|
# 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 10)
|
|
|
|
# index-of
|
|
(assert (= nil (index-of 10 [])) "index-of 1")
|
|
(assert (= nil (index-of 10 [1 2 3])) "index-of 2")
|
|
(assert (= 1 (index-of 2 [1 2 3])) "index-of 3")
|
|
(assert (= 0 (index-of :a [:a :b :c])) "index-of 4")
|
|
(assert (= nil (index-of :a {})) "index-of 5")
|
|
(assert (= :a (index-of :A {:a :A :b :B})) "index-of 6")
|
|
(assert (= :a (index-of :A @{:a :A :b :B})) "index-of 7")
|
|
(assert (= 0 (index-of (chr "a") "abc")) "index-of 8")
|
|
(assert (= nil (index-of (chr "a") "")) "index-of 9")
|
|
(assert (= nil (index-of 10 @[])) "index-of 10")
|
|
(assert (= nil (index-of 10 @[1 2 3])) "index-of 11")
|
|
|
|
# Regression
|
|
(assert (= {:x 10} (|(let [x $] ~{:x ,x}) 10)) "issue 463")
|
|
|
|
# macex testing
|
|
(assert (deep= (macex1 '~{1 2 3 4}) '~{1 2 3 4}) "macex1 qq struct")
|
|
(assert (deep= (macex1 '~@{1 2 3 4}) '~@{1 2 3 4}) "macex1 qq table")
|
|
(assert (deep= (macex1 '~(1 2 3 4)) '~[1 2 3 4]) "macex1 qq tuple")
|
|
(assert (= :brackets (tuple/type (1 (macex1 '~[1 2 3 4])))) "macex1 qq bracket tuple")
|
|
(assert (deep= (macex1 '~@[1 2 3 4 ,blah]) '~@[1 2 3 4 ,blah]) "macex1 qq array")
|
|
|
|
# Sourcemaps in threading macros
|
|
(defn check-threading [macro expansion]
|
|
(def expanded (macex1 (tuple macro 0 '(x) '(y))))
|
|
(assert (= expanded expansion) (string macro " expansion value"))
|
|
(def smap-x (tuple/sourcemap (get expanded 1)))
|
|
(def smap-y (tuple/sourcemap expanded))
|
|
(def line first)
|
|
(defn column [t] (t 1))
|
|
(assert (not= smap-x [-1 -1]) (string macro " x sourcemap existence"))
|
|
(assert (not= smap-y [-1 -1]) (string macro " y sourcemap existence"))
|
|
(assert (or (< (line smap-x) (line smap-y))
|
|
(and (= (line smap-x) (line smap-y))
|
|
(< (column smap-x) (column smap-y))))
|
|
(string macro " relation between x and y sourcemap")))
|
|
|
|
(check-threading '-> '(y (x 0)))
|
|
(check-threading '->> '(y (x 0)))
|
|
|
|
# keep-syntax
|
|
(let [brak '[1 2 3]
|
|
par '(1 2 3)]
|
|
|
|
(tuple/setmap brak 2 1)
|
|
|
|
(assert (deep= (keep-syntax brak @[1 2 3]) @[1 2 3]) "keep-syntax brackets ignore array")
|
|
(assert (= (keep-syntax! brak @[1 2 3]) '[1 2 3]) "keep-syntax! brackets replace array")
|
|
|
|
(assert (= (keep-syntax! par (map inc @[1 2 3])) '(2 3 4)) "keep-syntax! parens coerce array")
|
|
(assert (not= (keep-syntax! brak @[1 2 3]) '(1 2 3)) "keep-syntax! brackets not parens")
|
|
(assert (not= (keep-syntax! par @[1 2 3]) '[1 2 3]) "keep-syntax! parens not brackets")
|
|
(assert (= (tuple/sourcemap brak)
|
|
(tuple/sourcemap (keep-syntax! brak @[1 2 3]))) "keep-syntax! brackets source map")
|
|
|
|
(keep-syntax par brak)
|
|
(assert (not= (tuple/sourcemap brak) (tuple/sourcemap par)) "keep-syntax no mutate")
|
|
(assert (= (keep-syntax 1 brak) brak) "keep-syntax brackets ignore type"))
|
|
|
|
# Cancel test
|
|
(def f (fiber/new (fn [&] (yield 1) (yield 2) (yield 3) 4) :yti))
|
|
(assert (= 1 (resume f)) "cancel resume 1")
|
|
(assert (= 2 (resume f)) "cancel resume 2")
|
|
(assert (= :hi (cancel f :hi)) "cancel resume 3")
|
|
(assert (= :error (fiber/status f)) "cancel resume 4")
|
|
|
|
# Curenv
|
|
(assert (= (curenv) (curenv 0)) "curenv 1")
|
|
(assert (= (table/getproto (curenv)) (curenv 1)) "curenv 2")
|
|
(assert (= nil (curenv 1000000)) "curenv 3")
|
|
(assert (= root-env (curenv 1)) "curenv 4")
|
|
|
|
# Import macro test
|
|
(assert-no-error "import macro 1" (macex '(import a :as b :fresh maybe)))
|
|
(assert (deep= ~(,import* "a" :as "b" :fresh maybe) (macex '(import a :as b :fresh maybe))) "import macro 2")
|
|
|
|
# #477 walk preserving bracket type
|
|
(assert (= :brackets (tuple/type (postwalk identity '[]))) "walk square brackets 1")
|
|
(assert (= :brackets (tuple/type (walk identity '[]))) "walk square brackets 2")
|
|
|
|
# # off by 1 error in inttypes
|
|
(assert (= (int/s64 "-0x8000_0000_0000_0000") (+ (int/s64 "0x7FFF_FFFF_FFFF_FFFF") 1)) "int types wrap around")
|
|
|
|
#
|
|
# Longstring indentation
|
|
#
|
|
|
|
(defn reindent
|
|
"Reindent a the contents of a longstring as the Janet parser would.
|
|
This include removing leading and trailing newlines."
|
|
[text indent]
|
|
|
|
# Detect minimum indent
|
|
(var rewrite true)
|
|
(each index (string/find-all "\n" text)
|
|
(for i (+ index 1) (+ index indent 1)
|
|
(case (get text i)
|
|
nil (break)
|
|
(chr "\n") (break)
|
|
(chr " ") nil
|
|
(set rewrite false))))
|
|
|
|
# Only re-indent if no dedented characters.
|
|
(def str
|
|
(if rewrite
|
|
(peg/replace-all ~(* "\n" (between 0 ,indent " ")) "\n" text)
|
|
text))
|
|
|
|
(def first-nl (= (chr "\n") (first str)))
|
|
(def last-nl (= (chr "\n") (last str)))
|
|
(string/slice str (if first-nl 1 0) (if last-nl -2)))
|
|
|
|
(defn reindent-reference
|
|
"Same as reindent but use parser functionality. Useful for validating conformance."
|
|
[text indent]
|
|
(if (empty? text) (break text))
|
|
(def source-code
|
|
(string (string/repeat " " indent) "``````"
|
|
text
|
|
"``````"))
|
|
(parse source-code))
|
|
|
|
(var indent-counter 0)
|
|
(defn check-indent
|
|
[text indent]
|
|
(++ indent-counter)
|
|
(let [a (reindent text indent)
|
|
b (reindent-reference text indent)]
|
|
(assert (= a b) (string "indent " indent-counter " (indent=" indent ")"))))
|
|
|
|
(check-indent "" 0)
|
|
(check-indent "\n" 0)
|
|
(check-indent "\n" 1)
|
|
(check-indent "\n\n" 0)
|
|
(check-indent "\n\n" 1)
|
|
(check-indent "\nHello, world!" 0)
|
|
(check-indent "\nHello, world!" 1)
|
|
(check-indent "Hello, world!" 0)
|
|
(check-indent "Hello, world!" 1)
|
|
(check-indent "\n Hello, world!" 4)
|
|
(check-indent "\n Hello, world!\n" 4)
|
|
(check-indent "\n Hello, world!\n " 4)
|
|
(check-indent "\n Hello, world!\n " 4)
|
|
(check-indent "\n Hello, world!\n dedented text\n " 4)
|
|
(check-indent "\n Hello, world!\n indented text\n " 4)
|
|
|
|
# String bugs
|
|
(assert (deep= (string/find-all "qq" "qqq") @[0 1]) "string/find-all 1")
|
|
(assert (deep= (string/find-all "q" "qqq") @[0 1 2]) "string/find-all 2")
|
|
(assert (deep= (string/split "qq" "1qqqqz") @["1" "" "z"]) "string/split 1")
|
|
(assert (deep= (string/split "aa" "aaa") @["" "a"]) "string/split 2")
|
|
|
|
# Comparisons
|
|
(assert (> 1e23 100) "less than immediate 1")
|
|
(assert (> 1e23 1000) "less than immediate 2")
|
|
(assert (< 100 1e23) "greater than immediate 1")
|
|
(assert (< 1000 1e23) "greater than immediate 2")
|
|
|
|
# os/execute with environment variables
|
|
(assert (= 0 (os/execute [(dyn :executable) "-e" "(+ 1 2 3)"] :pe (merge (os/environ) {"HELLO" "WORLD"}))) "os/execute with env")
|
|
|
|
# Regression #638
|
|
(compwhen
|
|
(dyn 'ev/go)
|
|
(assert
|
|
(= [true :caught]
|
|
(protect
|
|
(try
|
|
(do
|
|
(ev/sleep 0)
|
|
(with-dyns []
|
|
(ev/sleep 0)
|
|
(error "oops")))
|
|
([err] :caught))))
|
|
"regression #638"))
|
|
|
|
|
|
# Struct prototypes
|
|
(def x (struct/with-proto {1 2 3 4} 5 6))
|
|
(def y (-> x marshal unmarshal))
|
|
(def z {1 2 3 4})
|
|
(assert (= 2 (get x 1)) "struct get proto value 1")
|
|
(assert (= 4 (get x 3)) "struct get proto value 2")
|
|
(assert (= 6 (get x 5)) "struct get proto value 3")
|
|
(assert (= x y) "struct proto marshal equality 1")
|
|
(assert (= (getproto x) (getproto y)) "struct proto marshal equality 2")
|
|
(assert (= 0 (cmp x y)) "struct proto comparison 1")
|
|
(assert (= 0 (cmp (getproto x) (getproto y))) "struct proto comparison 2")
|
|
(assert (not= (cmp x z) 0) "struct proto comparison 3")
|
|
(assert (not= (cmp y z) 0) "struct proto comparison 4")
|
|
(assert (not= x z) "struct proto comparison 5")
|
|
(assert (not= y z) "struct proto comparison 6")
|
|
(assert (= (x 5) 6) "struct proto get 1")
|
|
(assert (= (y 5) 6) "struct proto get 1")
|
|
(assert (deep= x y) "struct proto deep= 1")
|
|
(assert (deep-not= x z) "struct proto deep= 2")
|
|
(assert (deep-not= y z) "struct proto deep= 3")
|
|
|
|
# Issue #751
|
|
(def t {:side false})
|
|
(assert (nil? (get-in t [:side :note])) "get-in with false value")
|
|
(assert (= (get-in t [:side :note] "dflt") "dflt")
|
|
"get-in with false value and default")
|
|
|
|
(assert (= (math/gcd 462 1071) 21) "math/gcd 1")
|
|
(assert (= (math/lcm 462 1071) 23562) "math/lcm 1")
|
|
|
|
# Evaluate stream with `dofile`
|
|
(def [r w] (os/pipe))
|
|
(:write w "(setdyn :x 10)")
|
|
(:close w)
|
|
(def stream-env (dofile r))
|
|
(assert (= (stream-env :x) 10) "dofile stream 1")
|
|
|
|
# Issue #861 - should be valgrind clean
|
|
(def step1 "(a b c d)\n")
|
|
(def step2 "(a b)\n")
|
|
(def p1 (parser/new))
|
|
(parser/state p1)
|
|
(parser/consume p1 step1)
|
|
(loop [v :iterate (parser/produce p1)])
|
|
(parser/state p1)
|
|
(def p2 (parser/clone p1))
|
|
(parser/state p2)
|
|
(parser/consume p2 step2)
|
|
(loop [v :iterate (parser/produce p2)])
|
|
(parser/state p2)
|
|
|
|
# Check missing struct proto bug.
|
|
(assert (struct/getproto (struct/with-proto {:a 1} :b 2 :c nil)) "missing struct proto")
|
|
|
|
(end-suite)
|