1
0
mirror of https://github.com/janet-lang/janet synced 2024-09-28 15:08:40 +00:00

Change primary looping macro to 'loop' instead of 'for'.

This commit is contained in:
Calvin Rose 2018-05-23 22:08:36 -04:00
parent 644219a8a5
commit b09bf72490
9 changed files with 163 additions and 84 deletions

View File

@ -1,16 +1,13 @@
(import examples.iterators :as "")
(defn sum3 (defn sum3
"Solve the 3SUM problem in O(n^2) time." "Solve the 3SUM problem in O(n^2) time."
[s] [s]
(def tab @{}) (def tab @{})
(def solutions @{}) (def solutions @{})
(def len (length s)) (def len (length s))
(for [k 0 len] (loop [k :range [0 len]]
(put tab (get s k) k)) (put tab (get s k) k))
(for [i 0 len] (loop [i :range [0 len], j :range [0 len]]
(for [j 0 len]
(def k (get tab (- 0 (get s i) (get s j)))) (def k (get tab (- 0 (get s i) (get s j))))
(when (and k (not= k i) (not= k j) (not= i j)) (when (and k (not= k i) (not= k j) (not= i j))
(put solutions {i true j true k true} true)))) (put solutions {i true j true k true} true)))
(iter2array (map (fn [x] (iter2array (keys x))) (keys solutions)))) (map keys (keys solution)))

View File

@ -3,7 +3,7 @@
(defn fizzbuzz (defn fizzbuzz
"Prints the fizzbuzz problem." "Prints the fizzbuzz problem."
[] []
(for [i 1 101] (loop [i :range [1 101]]
(let [fizz (zero? (% i 3)) (let [fizz (zero? (% i 3))
buzz (zero? (% i 5))] buzz (zero? (% i 5))]
(print (cond (print (cond

View File

@ -4,7 +4,8 @@
"Get the number of occurences of each value in a indexed structure." "Get the number of occurences of each value in a indexed structure."
[ind] [ind]
(def freqs @{}) (def freqs @{})
(each (fn [x] (loop
(let [n (get freqs x)] [x :in ind]
(put freqs x (if n (+ 1 n) 1)))) ind) (def n (get freqs x))
(put freqs x (if n (+ 1 n) 1)))
freqs) freqs)

View File

@ -1,3 +1,5 @@
# Prints hello # Prints hello
(import examples.3sum)
(print "hello, world!") (print "hello, world!")

View File

@ -4,10 +4,10 @@
"Returns a list of prime numbers less than n." "Returns a list of prime numbers less than n."
[n] [n]
(def list @[]) (def list @[])
(for [i 2 n] (loop [i :range [2 n]]
(var isprime? true) (var isprime? true)
(def len (length list)) (def len (length list))
(for [j 0 len] (loop [j :range [0 len]]
(def trial (get list j)) (def trial (get list j))
(if (zero? (% i trial)) (:= isprime? false))) (if (zero? (% i trial)) (:= isprime? false)))
(if isprime? (array.push list i))) (if isprime? (array.push list i)))

View File

@ -218,18 +218,63 @@ value."
(array.concat accum body) (array.concat accum body)
(apply1 tuple accum)) (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 (defmacro for
"An imperative for loop over an integer range. Use with caution and discretion." "Similar to loop, but accumulates the loop body into an array and returns that."
[head & body] [head & body]
(def [sym start end _inc] (ast.unwrap1 head)) (def $accum (gensym "accum"))
(def inc (if _inc _inc 1))
(def endsym (gensym))
(tuple 'do (tuple 'do
(tuple 'var sym start) (tuple 'def $accum @[])
(tuple 'def endsym end) (tuple 'loop head
(tuple 'while (tuple < sym endsym) (tuple array.push $accum
(tuple.prepend body 'do) (tuple.prepend body 'do)))
(tuple ':= sym (tuple + sym inc))))) $accum))
(defmacro and (defmacro and
"Evaluates to the last argument if all preceding elements are true, otherwise "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)) (def len (length args))
(when (pos? len) (when (pos? len)
(var ret (get args 0)) (var ret (get args 0))
(for [i 0 len] (loop [i :range [0 len]]
(def v (get args i)) (def v (get args i))
(if (order v ret) (:= ret v))) (if (order v ret) (:= ret v)))
ret)) ret))
@ -356,7 +401,7 @@ Returns nil if args is empty."
[a lo hi by] [a lo hi by]
(def pivot (get a hi)) (def pivot (get a hi))
(var i lo) (var i lo)
(for [j lo hi] (loop [j :range [lo hi]]
(def aj (get a j)) (def aj (get a j))
(when (by aj pivot) (when (by aj pivot)
(def ai (get a i)) (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." an indexed type (array, tuple) with a function to produce a value."
[f init ind] [f init ind]
(var res init) (var res init)
(for [i 0 (length ind)] (loop [x :in ind]
(:= res (f res (get ind i)))) (:= res (f res x)))
res) res)
(defn map (defn map
@ -402,19 +447,19 @@ the same type as the input sequence."
(def ninds (length inds)) (def ninds (length inds))
(if (= 0 ninds) (error "expected at least 1 indexed collection.")) (if (= 0 ninds) (error "expected at least 1 indexed collection."))
(var limit (length (get inds 0))) (var limit (length (get inds 0)))
(for [i 0 ninds] (loop [i :range [0 ninds]]
(def l (length (get inds i))) (def l (length (get inds i)))
(if (< l limit) (:= limit l))) (if (< l limit) (:= limit l)))
(def [i1 i2 i3 i4] inds) (def [i1 i2 i3 i4] inds)
(def res (array.new limit)) (def res (array.new limit))
(switch ninds (switch ninds
1 (for [i 0 limit] (array.push res (f (get i1 i)))) 1 (loop [i :range [0 limit]] (array.push res (f (get i1 i))))
2 (for [i 0 limit] (array.push res (f (get i1 i) (get i2 i)))) 2 (loop [i :range [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)))) 3 (loop [i :range [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)))) 4 (loop [i :range [0 limit]] (array.push res (f (get i1 i) (get i2 i) (get i3 i) (get i4 i))))
(for [i 0 limit] (loop [i :range [0 limit]]
(def args (array.new ninds)) (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)))) (array.push res (apply1 f args))))
res) res)
@ -425,18 +470,18 @@ return a new indexed type."
(def ninds (length inds)) (def ninds (length inds))
(if (= 0 ninds) (error "expected at least 1 indexed collection.")) (if (= 0 ninds) (error "expected at least 1 indexed collection."))
(var limit (length (get inds 0))) (var limit (length (get inds 0)))
(for [i 0 ninds] (loop [i :range [0 ninds]]
(def l (length (get inds i))) (def l (length (get inds i)))
(if (< l limit) (:= limit l))) (if (< l limit) (:= limit l)))
(def [i1 i2 i3 i4] inds) (def [i1 i2 i3 i4] inds)
(switch ninds (switch ninds
1 (for [i 0 limit] (f (get i1 i))) 1 (loop [i :range [0 limit]] (f (get i1 i)))
2 (for [i 0 limit] (f (get i1 i) (get i2 i))) 2 (loop [i :range [0 limit]] (f (get i1 i) (get i2 i)))
3 (for [i 0 limit] (f (get i1 i) (get i2 i) (get i3 i))) 3 (loop [i :range [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))) 4 (loop [i :range [0 limit]] (f (get i1 i) (get i2 i) (get i3 i) (get i4 i)))
(for [i 0 limit] (loop [i :range [0 limit]]
(def args (array.new ninds)) (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)))) (apply1 f args))))
(defn mapcat (defn mapcat
@ -445,8 +490,8 @@ use array to concatenate the results. Returns the same
type as the input sequence." type as the input sequence."
[f ind t] [f ind t]
(def res @[]) (def res @[])
(for [i 0 (length ind)] (loop [x :in ind]
(array.concat res (f (get ind i)))) (array.concat res (f x)))
(if (= :tuple (type (or t ind))) (if (= :tuple (type (or t ind)))
(apply1 tuple res) (apply1 tuple res)
res)) res))
@ -455,10 +500,8 @@ type as the input sequence."
"Given a predicate, take only elements from an array or tuple for "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." which (pred element) is truthy. Returns the same type as the input sequence."
[pred ind t] [pred ind t]
(def len (length ind)) (def res @[])
(def res (array.new len)) (loop [item :in ind]
(for [i 0 len]
(def item (get ind i))
(if (pred item) (if (pred item)
(array.push res item))) (array.push res item)))
(if (= :tuple (type (or t ind))) (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)." "Create an array of values [0, n)."
[n] [n]
(def arr (array.new n)) (def arr (array.new n))
(for [i 0 n] (put arr i i)) (loop [i :range [0 n]] (put arr i i))
arr) arr)
(defn find-index (defn find-index
@ -521,19 +564,18 @@ the predicate, and abort on first failure."
(defn juxt* (defn juxt*
[& funs] [& funs]
(def len (length funs))
(fn [& args] (fn [& args]
(def ret @[]) (def ret @[])
(for [i 0 len] (loop [f :in funs]
(array.push ret (apply1 (get funs i) args))) (array.push ret (apply1 f args)))
(apply1 tuple ret))) (apply1 tuple ret)))
(defmacro juxt (defmacro juxt
[& funs] [& funs]
(def parts @['tuple]) (def parts @['tuple])
(def $args (gensym)) (def $args (gensym))
(for [i 0 (length funs)] (loop [f :in funs]
(array.push parts (tuple apply1 (get funs i) $args))) (array.push parts (tuple apply1 f $args)))
(tuple 'fn (tuple '& $args) (apply1 tuple parts))) (tuple 'fn (tuple '& $args) (apply1 tuple parts)))
(defmacro -> (defmacro ->
@ -611,7 +653,7 @@ in the same manner, and so on. Useful for expressing pipelines of data."
(def lk (length keys)) (def lk (length keys))
(def lv (length vals)) (def lv (length vals))
(def len (if (< lk lv) lk lv)) (def len (if (< lk lv) lk lv))
(for [i 0 len] (loop [i :range [0 len]]
(put res (get keys i) (get vals i))) (put res (get keys i) (get vals i)))
(if (= :struct t) (if (= :struct t)
(table.to-struct res) (table.to-struct res)
@ -631,18 +673,15 @@ in the same manner, and so on. Useful for expressing pipelines of data."
collection" collection"
[& colls] [& colls]
(def container @{}) (def container @{})
(for [i 0 (length colls)] (loop [c :in colls
(def c (get colls i)) key :keys c]
(var key (next c nil)) (put container key (get c key)))
(while (not= nil key)
(put container key (get c key))
(:= key (next c key))))
(if (table? (get colls 0)) container (table.to-struct container))) (if (table? (get colls 0)) container (table.to-struct container)))
(defn keys (defn keys
"Get the keys of an associative data structure." "Get the keys of an associative data structure."
[x] [x]
(def arr @[]) (def arr (array.new (length x)))
(var k (next x nil)) (var k (next x nil))
(while (not= nil k) (while (not= nil k)
(array.push arr k) (array.push arr k)
@ -652,7 +691,7 @@ in the same manner, and so on. Useful for expressing pipelines of data."
(defn values (defn values
"Get the values of an associative data structure." "Get the values of an associative data structure."
[x] [x]
(def arr @[]) (def arr (array.new (length x)))
(var k (next x nil)) (var k (next x nil))
(while (not= nil k) (while (not= nil k)
(array.push arr (get x 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 (defn pairs
"Get the values of an associative data structure." "Get the values of an associative data structure."
[x] [x]
(def arr @[]) (def arr (array.new (length x)))
(var k (next x nil)) (var k (next x nil))
(while (not= nil k) (while (not= nil k)
(array.push arr (tuple k (get x 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)) (def len (length y))
(if (< len 5) (if (< len 5)
(do (do
(for [i 0 len] (loop [i :range [0 len]]
(when (not= i 0) (buffer.push-string buf " ")) (when (not= i 0) (buffer.push-string buf " "))
(recur (get y i)))) (recur (get y i))))
(do (do
(buffer.push-string indent " ") (buffer.push-string indent " ")
(for [i 0 len] (loop [i :range [0 len]]
(when (not= i len) (buffer.push-string buf indent)) (when (not= i len) (buffer.push-string buf indent))
(recur (get y i))) (recur (get y i)))
(buffer.popn indent 2) (buffer.popn indent 2)
@ -719,9 +758,7 @@ to call on any table. Does not print table prototype information."
(defn pp-dict-nested [y] (defn pp-dict-nested [y]
(buffer.push-string indent " ") (buffer.push-string indent " ")
(def ps (sort (pairs y))) (loop [[k v] :in (sort (pairs y))]
(for [i 0 (length ps)]
(def [k v] (get ps i))
(buffer.push-string buf indent) (buffer.push-string buf indent)
(recur k) (recur k)
(buffer.push-string buf " ") (buffer.push-string buf " ")
@ -730,10 +767,9 @@ to call on any table. Does not print table prototype information."
(buffer.push-string buf indent)) (buffer.push-string buf indent))
(defn pp-dict-simple [y] (defn pp-dict-simple [y]
(def ps (sort (pairs y))) (var i -1)
(for [i 0 (length ps)] (loop [[k v] :in (sort (pairs y))]
(def [k v] (get ps i)) (if (pos? (++ i)) (buffer.push-string buf " "))
(if (pos? i) (buffer.push-string buf " "))
(recur k) (recur k)
(buffer.push-string buf " ") (buffer.push-string buf " ")
(recur v))) (recur v)))
@ -772,11 +808,7 @@ to call on any table. Does not print table prototype information."
[x] [x]
(defn doarray [a] (defn doarray [a]
(def len (length a)) (map macroexpand-1 a))
(def newa @[])
(for [i 0 len]
(array.push newa (macroexpand-1 (get a i))))
newa)
(defn dotable [t] (defn dotable [t]
(def newt @{}) (def newt @{})
@ -891,7 +923,7 @@ onvalue."
(buffer.clear buf) (buffer.clear buf)
(chunks buf p) (chunks buf p)
(:= len (length buf)) (:= len (length buf))
(for [i 0 len] (loop [i :range [0 len]]
(fiber.yield (get buf i)))) (fiber.yield (get buf i))))
0)) 0))
@ -943,15 +975,13 @@ onvalue."
(pp x)) (pp x))
(when f (when f
(def st (fiber.stack f)) (def st (fiber.stack f))
(def len (length st)) (loop [{
(for [i 0 len]
(def {
:function func :function func
:tail tail :tail tail
:pc pc :pc pc
:c c :c c
:name name :name name
} (get st i)) } :in st]
(file.write stdout " in") (file.write stdout " in")
(when c (file.write stdout " cfunction")) (when c (file.write stdout " cfunction"))
(when name (file.write stdout (string " " name))) (when name (file.write stdout (string " " name)))
@ -1067,7 +1097,8 @@ returned from compiling and running the file."
(while k (while k
(def v (get newenv k)) (def v (get newenv k))
(when (not (get v :private)) (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)))) (:= k (next newenv k))))
(defmacro import [path & args] (defmacro import [path & args]

View File

@ -830,7 +830,6 @@ recur:
DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x); DstSignal status = dst_call(f, dst_tuple_length(tup) - 1, tup + 1, &x);
dst_gcunlock(lock); dst_gcunlock(lock);
if (status != DST_SIGNAL_OK) { if (status != DST_SIGNAL_OK) {
printf("Status: %d\n", status);
const uint8_t *es = dst_formatc("error in macro expansion: %V", x); const uint8_t *es = dst_formatc("error in macro expansion: %V", x);
dstc_error(c, ast, es); dstc_error(c, ast, es);
} }

View File

@ -885,6 +885,47 @@ static int cfun_checkset(DstArgs args) {
DST_RETURN_TRUE(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[] = { static const DstReg cfuns[] = {
{"string.slice", cfun_slice}, {"string.slice", cfun_slice},
{"string.repeat", cfun_repeat}, {"string.repeat", cfun_repeat},
@ -899,6 +940,7 @@ static const DstReg cfuns[] = {
{"string.replace-all", cfun_replaceall}, {"string.replace-all", cfun_replaceall},
{"string.split", cfun_split}, {"string.split", cfun_split},
{"string.check-set", cfun_checkset}, {"string.check-set", cfun_checkset},
{"string.join", cfun_join},
{NULL, NULL} {NULL, NULL}
}; };

View File

@ -274,6 +274,13 @@ int dst_typeabstract_err(DstArgs args, int32_t n, const DstAbstractType *at);
}\ }\
} while (0) } 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 { \ #define _DST_ARG(TYPE, NAME, DEST, A, N) do { \
DST_CHECK(A, N, TYPE);\ DST_CHECK(A, N, TYPE);\
DEST = dst_unwrap_##NAME((A).v[(N)]); \ DEST = dst_unwrap_##NAME((A).v[(N)]); \