1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-23 13:43:16 +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
"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)))

View File

@ -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

View File

@ -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)

View File

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

View File

@ -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)))

View File

@ -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]

View File

@ -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);
}

View File

@ -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}
};

View File

@ -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)]); \