mirror of
https://github.com/janet-lang/janet
synced 2025-01-12 08:30:26 +00:00
Change primary looping macro to 'loop' instead of 'for'.
This commit is contained in:
parent
644219a8a5
commit
b09bf72490
@ -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)]); \
|
||||
|
Loading…
Reference in New Issue
Block a user