From 13e679cddefbef55cdb37205524de02b48890d75 Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez Date: Sun, 2 Jun 2019 15:35:54 +0200 Subject: [PATCH] lib/load-file-once: basic support for multiple imports --- lib/README.md | 12 +++++++--- lib/load-file-once.mal | 18 +++++++++++++++ lib/perf.mal | 3 ++- lib/test_cascade.mal | 3 ++- lib/threading.mal | 3 ++- tests/lib/load-file-once-inc.mal | 1 + tests/lib/load-file-once.mal | 38 ++++++++++++++++++++++++++++++++ tests/lib/memoize.mal | 6 ++--- tests/lib/pprint.mal | 3 ++- tests/lib/protocols.mal | 3 ++- tests/lib/reducers.mal | 3 ++- tests/lib/test_cascade.mal | 3 ++- tests/lib/threading.mal | 3 ++- tests/lib/trivial.mal | 3 ++- tests/perf1.mal | 7 +++--- tests/perf2.mal | 5 +++-- tests/perf3.mal | 7 +++--- 17 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 lib/load-file-once.mal create mode 100644 tests/lib/load-file-once-inc.mal create mode 100644 tests/lib/load-file-once.mal diff --git a/lib/README.md b/lib/README.md index b43a0826..f40bf654 100644 --- a/lib/README.md +++ b/lib/README.md @@ -17,9 +17,6 @@ However, here are some guidelines. is not possible, for example for macros, give them a name starting with an underscore. -- Support successive imports safely by giving the same definitions - again. - If a module provides tests, you may run against an implementation IMPL with these commands. ``` @@ -27,3 +24,12 @@ make IMPL^stepA cd tests python ../runtest.py lib/MODULE.mal ../IMPL/run ``` + +Users and implementors should use the following syntax in order to +ensure that the same file is only loaded once. + +``` +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/foo.mal") +(load-file-once "../lib/bar.mal") +``` diff --git a/lib/load-file-once.mal b/lib/load-file-once.mal new file mode 100644 index 00000000..0c0967b4 --- /dev/null +++ b/lib/load-file-once.mal @@ -0,0 +1,18 @@ +;; Like load-file, but will never load the same path twice. + +;; This file is normally loaded with `load-file`, so it needs a +;; different mechanism to neutralize multiple inclusions of +;; itself. Moreover, the file list should never be reset. + +(def! load-file-once + (try* + load-file-once + (catch* _ + (let* [seen (atom {"../lib/load-file-once.mal" nil})] + (fn* [filename] + (if (not (contains? @seen filename)) + (do + (swap! seen assoc filename nil) + (load-file filename)))))))) + +nil diff --git a/lib/perf.mal b/lib/perf.mal index 0025fee9..2bc8687b 100644 --- a/lib/perf.mal +++ b/lib/perf.mal @@ -1,6 +1,7 @@ ;; Mesure performances. -(load-file "../lib/trivial.mal") ; gensym inc +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/trivial.mal") ; gensym inc ;; Evaluate an expression, but report the time spent (defmacro! time diff --git a/lib/test_cascade.mal b/lib/test_cascade.mal index 6494c1f5..680206a9 100644 --- a/lib/test_cascade.mal +++ b/lib/test_cascade.mal @@ -1,6 +1,7 @@ ;; Iteration on evaluations interpreted as boolean values. -(load-file "../lib/trivial.mal") ; gensym +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/trivial.mal") ; gensym ;; `(cond test1 result1 test2 result2 .. testn resultn)` ;; is rewritten (in the step files) as diff --git a/lib/threading.mal b/lib/threading.mal index 580b2b5f..a9d60e60 100644 --- a/lib/threading.mal +++ b/lib/threading.mal @@ -1,6 +1,7 @@ ;; Composition of partially applied functions. -(load-file "../lib/reducers.mal") ; reduce +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/reducers.mal") ; reduce ;; Rewrite x (a a1 a2) .. (b b1 b2) as ;; (b (.. (a x a1 a2) ..) b1 b2) diff --git a/tests/lib/load-file-once-inc.mal b/tests/lib/load-file-once-inc.mal new file mode 100644 index 00000000..2f912a89 --- /dev/null +++ b/tests/lib/load-file-once-inc.mal @@ -0,0 +1 @@ +(swap! counter (fn* [x] (+ 1 x))) diff --git a/tests/lib/load-file-once.mal b/tests/lib/load-file-once.mal new file mode 100644 index 00000000..65e40a99 --- /dev/null +++ b/tests/lib/load-file-once.mal @@ -0,0 +1,38 @@ +(def! counter (atom 0)) +;=>(atom 0) + +;; The counter is increased by each `load-file`. +(load-file "../tests/lib/load-file-once-inc.mal") +;=>1 +(load-file "../tests/lib/load-file-once-inc.mal") +;=>2 + +;; load-file-once is available +(load-file "../lib/load-file-once.mal") +;=>nil + +;; First import actually calls `load-file`. +(load-file-once "../tests/lib/load-file-once-inc.mal") +;=>3 + +;; Later imports do nothing. +(load-file-once "../tests/lib/load-file-once-inc.mal") +;=>nil +@counter +;=>3 + +;; Loading the module twice does not reset its memory. +(load-file "../lib/load-file-once.mal") +;=>nil +(load-file-once "../tests/lib/load-file-once-inc.mal") +;=>nil +@counter +;=>3 + +;; even if done with itself +(load-file-once "../lib/load-file-once.mal") +;=>nil +(load-file-once "../tests/lib/load-file-once-inc.mal") +;=>nil +@counter +;=>3 diff --git a/tests/lib/memoize.mal b/tests/lib/memoize.mal index 50c31803..60fc43d2 100644 --- a/tests/lib/memoize.mal +++ b/tests/lib/memoize.mal @@ -1,6 +1,6 @@ -(load-file "../tests/computations.mal") -;=>nil -(load-file "../lib/memoize.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../tests/computations.mal") +(load-file-once "../lib/memoize.mal") ;=>nil (def! N 32) diff --git a/tests/lib/pprint.mal b/tests/lib/pprint.mal index 1a268f5c..457dd4d6 100644 --- a/tests/lib/pprint.mal +++ b/tests/lib/pprint.mal @@ -1,4 +1,5 @@ -(load-file "../lib/pprint.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/pprint.mal") ;=>nil (pprint '(7 8 9 "ten" [11 12 [13 14]] 15 16)) diff --git a/tests/lib/protocols.mal b/tests/lib/protocols.mal index 731b6833..819543d8 100644 --- a/tests/lib/protocols.mal +++ b/tests/lib/protocols.mal @@ -1,4 +1,5 @@ -(load-file "../lib/protocols.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/protocols.mal") ;=>nil ;; Testing find-type for normal objects. diff --git a/tests/lib/reducers.mal b/tests/lib/reducers.mal index 6bd4ee4c..9aa242da 100644 --- a/tests/lib/reducers.mal +++ b/tests/lib/reducers.mal @@ -1,4 +1,5 @@ -(load-file "../lib/reducers.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/reducers.mal") ;=>nil ;; Testing reduce diff --git a/tests/lib/test_cascade.mal b/tests/lib/test_cascade.mal index 6db6698e..95e4632a 100644 --- a/tests/lib/test_cascade.mal +++ b/tests/lib/test_cascade.mal @@ -1,4 +1,5 @@ -(load-file "../lib/test_cascade.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/test_cascade.mal") ;=>nil ;; Testing or diff --git a/tests/lib/threading.mal b/tests/lib/threading.mal index 2040ee22..9d3fe96e 100644 --- a/tests/lib/threading.mal +++ b/tests/lib/threading.mal @@ -1,4 +1,5 @@ -(load-file "../lib/threading.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/threading.mal") ;=>nil ;; Testing -> macro diff --git a/tests/lib/trivial.mal b/tests/lib/trivial.mal index d32ce313..1d9c7c0b 100644 --- a/tests/lib/trivial.mal +++ b/tests/lib/trivial.mal @@ -1,4 +1,5 @@ -(load-file "../lib/trivial.mal") +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/trivial.mal") ;=>nil (inc 12) diff --git a/tests/perf1.mal b/tests/perf1.mal index e73ed9ad..9d1db7cb 100644 --- a/tests/perf1.mal +++ b/tests/perf1.mal @@ -1,6 +1,7 @@ -(load-file "../lib/threading.mal") ; -> -(load-file "../lib/perf.mal") ; time -(load-file "../lib/test_cascade.mal") ; or +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/threading.mal") ; -> +(load-file-once "../lib/perf.mal") ; time +(load-file-once "../lib/test_cascade.mal") ; or ;;(prn "Start: basic macros performance test") diff --git a/tests/perf2.mal b/tests/perf2.mal index e2ca4d73..4f0bc6cc 100644 --- a/tests/perf2.mal +++ b/tests/perf2.mal @@ -1,5 +1,6 @@ -(load-file "../tests/computations.mal") ; fib sumdown -(load-file "../lib/perf.mal") ; time +(load-file "../lib/load-file-once.mal") +(load-file-once "../tests/computations.mal") ; fib sumdown +(load-file-once "../lib/perf.mal") ; time ;;(prn "Start: basic math/recursion test") diff --git a/tests/perf3.mal b/tests/perf3.mal index 2efbaf9a..da81f8de 100644 --- a/tests/perf3.mal +++ b/tests/perf3.mal @@ -1,6 +1,7 @@ -(load-file "../lib/threading.mal") ; -> -(load-file "../lib/perf.mal") ; run-fn-for -(load-file "../lib/test_cascade.mal") ; or +(load-file "../lib/load-file-once.mal") +(load-file-once "../lib/threading.mal") ; -> +(load-file-once "../lib/perf.mal") ; run-fn-for +(load-file-once "../lib/test_cascade.mal") ; or ;;(prn "Start: basic macros/atom test")