mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Change primary looping macro to 'loop' instead of 'for'.
This commit is contained in:
		| @@ -1,16 +1,13 @@ | ||||
| (import examples.iterators :as "") | ||||
|  | ||||
| (defn sum3 | ||||
|  "Solve the 3SUM problem in O(n^2) time." | ||||
|  [s] | ||||
|  (def tab @{}) | ||||
|  (def solutions @{}) | ||||
|  (def len (length s)) | ||||
|  (for [k 0 len] | ||||
|  (loop [k :range [0 len]] | ||||
|   (put tab (get s k) k)) | ||||
|  (for [i 0 len] | ||||
|   (for [j 0 len] | ||||
|  (loop [i :range [0 len], j :range [0 len]] | ||||
|    (def k (get tab (- 0 (get s i) (get s j)))) | ||||
|    (when (and k (not= k i) (not= k j) (not= i j)) | ||||
|     (put solutions {i true j true k true} true)))) | ||||
|  (iter2array (map (fn [x] (iter2array (keys x))) (keys solutions)))) | ||||
|     (put solutions {i true j true k true} true))) | ||||
|  (map keys (keys solution))) | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| (defn fizzbuzz | ||||
|  "Prints the fizzbuzz problem." | ||||
|  [] | ||||
|  (for [i 1 101] | ||||
|  (loop [i :range [1 101]] | ||||
|   (let [fizz (zero? (% i 3)) | ||||
|         buzz (zero? (% i 5))] | ||||
|     (print (cond | ||||
|   | ||||
| @@ -4,7 +4,8 @@ | ||||
|  "Get the number of occurences of each value in a indexed structure." | ||||
|  [ind] | ||||
|  (def freqs @{}) | ||||
|  (each (fn [x]  | ||||
|     (let [n (get freqs x)] | ||||
|      (put freqs x (if n (+ 1 n) 1)))) ind) | ||||
|  (loop  | ||||
|    [x :in ind] | ||||
|    (def n (get freqs x)) | ||||
|    (put freqs x (if n (+ 1 n) 1))) | ||||
|  freqs) | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| # Prints hello | ||||
|  | ||||
| (import examples.3sum) | ||||
|  | ||||
| (print "hello, world!") | ||||
|   | ||||
| @@ -4,10 +4,10 @@ | ||||
|  "Returns a list of prime numbers less than n." | ||||
|  [n] | ||||
|  (def list @[]) | ||||
|  (for [i 2 n] | ||||
|  (loop [i :range [2 n]] | ||||
|   (var isprime? true) | ||||
|   (def len (length list)) | ||||
|   (for [j 0 len] | ||||
|   (loop [j :range [0 len]] | ||||
|    (def trial (get list j)) | ||||
|    (if (zero? (% i trial)) (:= isprime? false))) | ||||
|   (if isprime? (array.push list i))) | ||||
|   | ||||
| @@ -218,18 +218,63 @@ value." | ||||
|   (array.concat accum body) | ||||
|   (apply1 tuple accum)) | ||||
|  | ||||
| (defmacro loop | ||||
|   "A general purpose loop macro." | ||||
|   [head & body] | ||||
|   (def head1 (ast.unwrap1 head)) | ||||
|   (def len (length head1)) | ||||
|   (defn doone | ||||
|     [i] | ||||
|     (if (>= i len) | ||||
|       (tuple.prepend body 'do) | ||||
|       (do | ||||
|         (def bindings (get head1 i)) | ||||
|         (def verb (ast.unwrap1 (get head1 (+ i 1)))) | ||||
|         (def object (ast.unwrap1 (get head1 (+ i 2)))) | ||||
|         (switch verb | ||||
|           :range (do | ||||
|                  (def [start end _inc] (ast.unwrap1 object)) | ||||
|                  (def inc (if _inc _inc 1)) | ||||
|                  (def endsym (gensym)) | ||||
|                  (tuple 'do | ||||
|                         (tuple 'var bindings start) | ||||
|                         (tuple 'def endsym end) | ||||
|                         (tuple 'while (tuple < bindings endsym) | ||||
|                                (doone (+ i 3)) | ||||
|                                (tuple ':= bindings (tuple + bindings inc))))) | ||||
|           :keys (do | ||||
|                   (def $dict (gensym "dict")) | ||||
|                   (tuple 'do | ||||
|                          (tuple 'def $dict object) | ||||
|                          (tuple 'var bindings (tuple next $dict nil)) | ||||
|                          (tuple 'while (tuple not= nil bindings) | ||||
|                                 (doone (+ i 3)) | ||||
|                                 (tuple ':= bindings (tuple next $dict bindings))))) | ||||
|           :in (do | ||||
|                 (def $len (gensym "len")) | ||||
|                 (def $i (gensym "i")) | ||||
|                 (def $indexed (gensym "indexed")) | ||||
|                 (tuple 'do | ||||
|                        (tuple 'def $indexed object) | ||||
|                        (tuple 'def $len (tuple length $indexed)) | ||||
|                        (tuple 'var $i 0) | ||||
|                        (tuple 'while (tuple < $i $len) | ||||
|                               (tuple 'def bindings (tuple get $indexed $i)) | ||||
|                               (doone (+ i 3)) | ||||
|                               (tuple ':= $i (tuple + 1 $i))))) | ||||
|           (error ("unexpected loop verb: " verb)))))) | ||||
|   (doone 0)) | ||||
|  | ||||
| (defmacro for | ||||
|  "An imperative for loop over an integer range. Use with caution and discretion." | ||||
|  [head & body] | ||||
|   (def [sym start end _inc] (ast.unwrap1 head)) | ||||
|   (def inc (if _inc _inc 1)) | ||||
|   (def endsym (gensym)) | ||||
|   "Similar to loop, but accumulates the loop body into an array and returns that." | ||||
|   [head & body] | ||||
|   (def $accum (gensym "accum")) | ||||
|   (tuple 'do | ||||
|     (tuple 'var sym start) | ||||
|     (tuple 'def endsym end) | ||||
|     (tuple 'while (tuple < sym endsym) | ||||
|      (tuple.prepend body 'do) | ||||
|      (tuple ':= sym (tuple + sym inc))))) | ||||
|          (tuple 'def $accum @[]) | ||||
|          (tuple 'loop head  | ||||
|            (tuple array.push $accum | ||||
|                 (tuple.prepend body 'do))) | ||||
|          $accum)) | ||||
|  | ||||
| (defmacro and | ||||
|  "Evaluates to the last argument if all preceding elements are true, otherwise | ||||
| @@ -332,7 +377,7 @@ Returns nil if args is empty." | ||||
|  (def len (length args)) | ||||
|  (when (pos? len) | ||||
|   (var ret (get args 0)) | ||||
|   (for [i 0 len] | ||||
|   (loop [i :range [0 len]] | ||||
|    (def v (get args i)) | ||||
|    (if (order v ret) (:= ret v))) | ||||
|   ret)) | ||||
| @@ -356,7 +401,7 @@ Returns nil if args is empty." | ||||
|    [a lo hi by] | ||||
|    (def pivot (get a hi)) | ||||
|    (var i lo) | ||||
|    (for [j lo hi] | ||||
|    (loop [j :range [lo hi]] | ||||
|     (def aj (get a j)) | ||||
|     (when (by aj pivot) | ||||
|      (def ai (get a i)) | ||||
| @@ -391,8 +436,8 @@ Returns nil if args is empty." | ||||
| an indexed type (array, tuple) with a function to produce a value." | ||||
|  [f init ind] | ||||
|  (var res init) | ||||
|  (for [i 0 (length ind)] | ||||
|   (:= res (f res (get ind i)))) | ||||
|  (loop [x :in ind] | ||||
|   (:= res (f res x))) | ||||
|  res) | ||||
|  | ||||
| (defn map | ||||
| @@ -402,19 +447,19 @@ the same type as the input sequence." | ||||
|  (def ninds (length inds)) | ||||
|  (if (= 0 ninds) (error "expected at least 1 indexed collection.")) | ||||
|  (var limit (length (get inds 0))) | ||||
|  (for [i 0 ninds] | ||||
|  (loop [i :range [0 ninds]] | ||||
|   (def l (length (get inds i))) | ||||
|   (if (< l limit) (:= limit l))) | ||||
|  (def [i1 i2 i3 i4] inds) | ||||
|  (def res (array.new limit)) | ||||
|  (switch ninds | ||||
|   1 (for [i 0 limit] (array.push res (f (get i1 i)))) | ||||
|   2 (for [i 0 limit] (array.push res (f (get i1 i) (get i2 i)))) | ||||
|   3 (for [i 0 limit] (array.push res (f (get i1 i) (get i2 i) (get i3 i)))) | ||||
|   4 (for [i 0 limit] (array.push res (f (get i1 i) (get i2 i) (get i3 i) (get i4 i)))) | ||||
|   (for [i 0 limit] | ||||
|   1 (loop [i :range [0 limit]] (array.push res (f (get i1 i)))) | ||||
|   2 (loop [i :range [0 limit]] (array.push res (f (get i1 i) (get i2 i)))) | ||||
|   3 (loop [i :range [0 limit]] (array.push res (f (get i1 i) (get i2 i) (get i3 i)))) | ||||
|   4 (loop [i :range [0 limit]] (array.push res (f (get i1 i) (get i2 i) (get i3 i) (get i4 i)))) | ||||
|   (loop [i :range [0 limit]] | ||||
|    (def args (array.new ninds)) | ||||
|    (for [j 0 ninds] (array.push args (get (get inds j) i))) | ||||
|    (loop [j :range [0 ninds]] (array.push args (get (get inds j) i))) | ||||
|    (array.push res (apply1 f args)))) | ||||
|  res) | ||||
|  | ||||
| @@ -425,18 +470,18 @@ return a new indexed type." | ||||
|  (def ninds (length inds)) | ||||
|  (if (= 0 ninds) (error "expected at least 1 indexed collection.")) | ||||
|  (var limit (length (get inds 0))) | ||||
|  (for [i 0 ninds] | ||||
|  (loop [i :range [0 ninds]] | ||||
|   (def l (length (get inds i))) | ||||
|   (if (< l limit) (:= limit l))) | ||||
|  (def [i1 i2 i3 i4] inds) | ||||
|  (switch ninds | ||||
|   1 (for [i 0 limit] (f (get i1 i))) | ||||
|   2 (for [i 0 limit] (f (get i1 i) (get i2 i))) | ||||
|   3 (for [i 0 limit] (f (get i1 i) (get i2 i) (get i3 i))) | ||||
|   4 (for [i 0 limit] (f (get i1 i) (get i2 i) (get i3 i) (get i4 i))) | ||||
|   (for [i 0 limit] | ||||
|   1 (loop [i :range [0 limit]] (f (get i1 i))) | ||||
|   2 (loop [i :range [0 limit]] (f (get i1 i) (get i2 i))) | ||||
|   3 (loop [i :range [0 limit]] (f (get i1 i) (get i2 i) (get i3 i))) | ||||
|   4 (loop [i :range [0 limit]] (f (get i1 i) (get i2 i) (get i3 i) (get i4 i))) | ||||
|   (loop [i :range [0 limit]] | ||||
|    (def args (array.new ninds)) | ||||
|    (for [j 0 ninds] (array.push args (get (get inds j) i))) | ||||
|    (loop [j :range [0 ninds]] (array.push args (get (get inds j) i))) | ||||
|    (apply1 f args)))) | ||||
|  | ||||
| (defn mapcat | ||||
| @@ -445,8 +490,8 @@ use array to concatenate the results. Returns the same | ||||
| type as the input sequence." | ||||
|  [f ind t] | ||||
|  (def res @[]) | ||||
|  (for [i 0 (length ind)] | ||||
|   (array.concat res (f (get ind i)))) | ||||
|  (loop [x :in ind] | ||||
|   (array.concat res (f x))) | ||||
|  (if (= :tuple (type (or t ind))) | ||||
|   (apply1 tuple res) | ||||
|   res)) | ||||
| @@ -455,10 +500,8 @@ type as the input sequence." | ||||
|  "Given a predicate, take only elements from an array or tuple for | ||||
| which (pred element) is truthy. Returns the same type as the input sequence." | ||||
|  [pred ind t] | ||||
|  (def len (length ind)) | ||||
|  (def res (array.new len)) | ||||
|  (for [i 0 len] | ||||
|   (def item (get ind i)) | ||||
|  (def res @[]) | ||||
|  (loop [item :in ind] | ||||
|   (if (pred item) | ||||
|    (array.push res item))) | ||||
|  (if (= :tuple (type (or t ind))) | ||||
| @@ -469,7 +512,7 @@ which (pred element) is truthy. Returns the same type as the input sequence." | ||||
|   "Create an array of values [0, n)." | ||||
|   [n] | ||||
|   (def arr (array.new n)) | ||||
|   (for [i 0 n] (put arr i i)) | ||||
|   (loop [i :range [0 n]] (put arr i i)) | ||||
|   arr) | ||||
|  | ||||
| (defn find-index | ||||
| @@ -521,19 +564,18 @@ the predicate, and abort on first failure." | ||||
|  | ||||
| (defn juxt* | ||||
|   [& funs] | ||||
|   (def len (length funs)) | ||||
|   (fn [& args] | ||||
|    (def ret @[]) | ||||
|    (for [i 0 len] | ||||
|     (array.push ret (apply1 (get funs i) args))) | ||||
|    (loop [f :in funs] | ||||
|     (array.push ret (apply1 f args))) | ||||
|    (apply1 tuple ret))) | ||||
|  | ||||
| (defmacro juxt | ||||
|  [& funs] | ||||
|  (def parts @['tuple]) | ||||
|  (def $args (gensym)) | ||||
|  (for [i 0 (length funs)] | ||||
|   (array.push parts (tuple apply1 (get funs i) $args))) | ||||
|  (loop [f :in funs] | ||||
|   (array.push parts (tuple apply1 f $args))) | ||||
|  (tuple 'fn (tuple '& $args) (apply1 tuple parts))) | ||||
|  | ||||
| (defmacro -> | ||||
| @@ -611,7 +653,7 @@ in the same manner, and so on. Useful for expressing pipelines of data." | ||||
|   (def lk (length keys)) | ||||
|   (def lv (length vals)) | ||||
|   (def len (if (< lk lv) lk lv)) | ||||
|   (for [i 0 len] | ||||
|   (loop [i :range [0 len]] | ||||
|    (put res (get keys i) (get vals i))) | ||||
|   (if (= :struct t) | ||||
|     (table.to-struct res) | ||||
| @@ -631,18 +673,15 @@ in the same manner, and so on. Useful for expressing pipelines of data." | ||||
|    collection" | ||||
|   [& colls] | ||||
|   (def container @{}) | ||||
|   (for [i 0 (length colls)] | ||||
|    (def c (get colls i)) | ||||
|    (var key (next c nil)) | ||||
|    (while (not= nil key) | ||||
|      (put container key (get c key)) | ||||
|      (:= key (next c key)))) | ||||
|   (loop [c :in colls | ||||
|         key :keys c] | ||||
|        (put container key (get c key))) | ||||
|   (if (table? (get colls 0)) container (table.to-struct container))) | ||||
|  | ||||
| (defn keys | ||||
|  "Get the keys of an associative data structure." | ||||
|  [x] | ||||
|  (def arr @[]) | ||||
|  (def arr (array.new (length x))) | ||||
|  (var k (next x nil)) | ||||
|  (while (not= nil k) | ||||
|   (array.push arr k) | ||||
| @@ -652,7 +691,7 @@ in the same manner, and so on. Useful for expressing pipelines of data." | ||||
| (defn values | ||||
|  "Get the values of an associative data structure." | ||||
|  [x] | ||||
|  (def arr @[]) | ||||
|  (def arr (array.new (length x))) | ||||
|  (var k (next x nil)) | ||||
|  (while (not= nil k) | ||||
|   (array.push arr (get x k)) | ||||
| @@ -662,7 +701,7 @@ in the same manner, and so on. Useful for expressing pipelines of data." | ||||
| (defn pairs | ||||
|  "Get the values of an associative data structure." | ||||
|  [x] | ||||
|  (def arr @[]) | ||||
|  (def arr (array.new (length x))) | ||||
|  (var k (next x nil)) | ||||
|  (while (not= nil k) | ||||
|   (array.push arr (tuple k (get x k))) | ||||
| @@ -706,12 +745,12 @@ to call on any table. Does not print table prototype information." | ||||
|    (def len (length y)) | ||||
|    (if (< len 5) | ||||
|     (do | ||||
|      (for [i 0 len] | ||||
|      (loop [i :range [0 len]] | ||||
|       (when (not= i 0) (buffer.push-string buf " ")) | ||||
|       (recur (get y i)))) | ||||
|     (do | ||||
|       (buffer.push-string indent "  ") | ||||
|       (for [i 0 len] | ||||
|       (loop [i :range [0 len]] | ||||
|        (when (not= i len) (buffer.push-string buf indent)) | ||||
|        (recur (get y i))) | ||||
|       (buffer.popn indent 2) | ||||
| @@ -719,9 +758,7 @@ to call on any table. Does not print table prototype information." | ||||
|  | ||||
|   (defn pp-dict-nested [y] | ||||
|    (buffer.push-string indent "  ") | ||||
|    (def ps (sort (pairs y))) | ||||
|    (for [i 0 (length ps)] | ||||
|     (def [k v] (get ps i)) | ||||
|    (loop [[k v] :in (sort (pairs y))] | ||||
|     (buffer.push-string buf indent) | ||||
|     (recur k) | ||||
|     (buffer.push-string buf " ") | ||||
| @@ -730,10 +767,9 @@ to call on any table. Does not print table prototype information." | ||||
|    (buffer.push-string buf indent)) | ||||
|  | ||||
|   (defn pp-dict-simple [y] | ||||
|    (def ps (sort (pairs y))) | ||||
|    (for [i 0 (length ps)] | ||||
|     (def [k v] (get ps i)) | ||||
|     (if (pos? i) (buffer.push-string buf " ")) | ||||
|    (var i -1) | ||||
|    (loop [[k v] :in (sort (pairs y))] | ||||
|     (if (pos? (++ i)) (buffer.push-string buf " ")) | ||||
|     (recur k) | ||||
|     (buffer.push-string buf " ") | ||||
|     (recur v))) | ||||
| @@ -772,11 +808,7 @@ to call on any table. Does not print table prototype information." | ||||
|  [x] | ||||
|  | ||||
|  (defn doarray [a] | ||||
|   (def len (length a)) | ||||
|   (def newa @[]) | ||||
|   (for [i 0 len] | ||||
|    (array.push newa (macroexpand-1 (get a i)))) | ||||
|   newa) | ||||
|    (map macroexpand-1 a)) | ||||
|  | ||||
|  (defn dotable [t] | ||||
|   (def newt @{}) | ||||
| @@ -891,7 +923,7 @@ onvalue." | ||||
|       (buffer.clear buf) | ||||
|       (chunks buf p) | ||||
|       (:= len (length buf)) | ||||
|       (for [i 0 len] | ||||
|       (loop [i :range [0 len]] | ||||
|         (fiber.yield (get buf i)))) | ||||
|    0)) | ||||
|  | ||||
| @@ -943,15 +975,13 @@ onvalue." | ||||
|    (pp x)) | ||||
|  (when f | ||||
|   (def st (fiber.stack f)) | ||||
|   (def len (length st)) | ||||
|   (for [i 0 len] | ||||
|    (def { | ||||
|   (loop [{ | ||||
|     :function func | ||||
|     :tail tail | ||||
|     :pc pc | ||||
|     :c c | ||||
|     :name name | ||||
|    } (get st i)) | ||||
|    } :in st] | ||||
|    (file.write stdout "  in") | ||||
|    (when c (file.write stdout " cfunction")) | ||||
|    (when name (file.write stdout (string " " name))) | ||||
| @@ -1067,7 +1097,8 @@ returned from compiling and running the file." | ||||
|  (while k | ||||
|   (def v (get newenv k)) | ||||
|   (when (not (get v :private)) | ||||
|    (put env (symbol prefix k) v)) | ||||
|     (def newv (table.setproto @{:private true} v)) | ||||
|    (put env (symbol prefix k) newv)) | ||||
|   (:= k (next newenv k)))) | ||||
|  | ||||
| (defmacro import [path & args] | ||||
|   | ||||
| @@ -830,7 +830,6 @@ recur: | ||||
|                                     DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x); | ||||
|                                     dst_gcunlock(lock); | ||||
|                                     if (status != DST_SIGNAL_OK) { | ||||
|                                         printf("Status: %d\n", status); | ||||
|                                         const uint8_t *es = dst_formatc("error in macro expansion: %V", x); | ||||
|                                         dstc_error(c, ast, es); | ||||
|                                     } | ||||
|   | ||||
| @@ -885,6 +885,47 @@ static int cfun_checkset(DstArgs args) { | ||||
|     DST_RETURN_TRUE(args); | ||||
| } | ||||
|  | ||||
| static int cfun_join(DstArgs args) { | ||||
|     const Dst *parts; | ||||
|     const uint8_t *joiner; | ||||
|     uint8_t *buf, *out; | ||||
|     int32_t joinerlen, partslen, finallen, i; | ||||
|     DST_MINARITY(args, 1); | ||||
|     DST_MAXARITY(args, 2); | ||||
|     DST_ARG_INDEXED(parts, partslen, args, 0); | ||||
|     if (args.n == 2) { | ||||
|         DST_ARG_BYTES(joiner, joinerlen, args, 1); | ||||
|     } else { | ||||
|         joiner = NULL; | ||||
|         joinerlen = 0; | ||||
|     } | ||||
|     /* Check args */ | ||||
|     finallen = 0; | ||||
|     for (i = 0; i < partslen; i++) { | ||||
|         const uint8_t *chunk; | ||||
|         int32_t chunklen = 0; | ||||
|         if (!dst_chararray_view(parts[i], &chunk, &chunklen)) { | ||||
|             DST_THROW(args, "expected string|symbol|buffer"); | ||||
|         } | ||||
|         if (i) finallen += joinerlen; | ||||
|         finallen += chunklen; | ||||
|     } | ||||
|     out = buf = dst_string_begin(finallen); | ||||
|     for (i = 0; i < partslen; i++) { | ||||
|         const uint8_t *chunk = NULL; | ||||
|         int32_t chunklen = 0; | ||||
|         if (i) { | ||||
|             memcpy(out, joiner, joinerlen); | ||||
|             out += joinerlen; | ||||
|         } | ||||
|         dst_chararray_view(parts[i], &chunk, &chunklen); | ||||
|         memcpy(out, chunk, chunklen); | ||||
|         out += chunklen; | ||||
|     } | ||||
|     DST_RETURN_STRING(args, dst_string_end(buf)); | ||||
|  | ||||
| } | ||||
|  | ||||
| static const DstReg cfuns[] = { | ||||
|     {"string.slice", cfun_slice}, | ||||
|     {"string.repeat", cfun_repeat}, | ||||
| @@ -899,6 +940,7 @@ static const DstReg cfuns[] = { | ||||
|     {"string.replace-all", cfun_replaceall}, | ||||
|     {"string.split", cfun_split}, | ||||
|     {"string.check-set", cfun_checkset}, | ||||
|     {"string.join", cfun_join}, | ||||
|     {NULL, NULL} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -274,6 +274,13 @@ int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at); | ||||
|     }\ | ||||
| } while (0) | ||||
|  | ||||
| #define DST_ARG_INDEXED(DESTVALS, DESTLEN, A, N) do {\ | ||||
|     if ((A).n <= (N)) return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\ | ||||
|     if (!dst_seq_view((A).v[(N)], &(DESTVALS), &(DESTLEN))) {\ | ||||
|         return dst_typemany_err(A, N, DST_TFLAG_INDEXED);\ | ||||
|     }\ | ||||
| } while (0) | ||||
|  | ||||
| #define _DST_ARG(TYPE, NAME, DEST, A, N) do { \ | ||||
|     DST_CHECK(A, N, TYPE);\ | ||||
|     DEST = dst_unwrap_##NAME((A).v[(N)]); \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose