2018-03-16 03:27:44 +00:00
|
|
|
# Bootstrap the dst environment
|
|
|
|
# Copyright 2018 (C) Calvin Rose
|
2018-01-31 22:39:18 +00:00
|
|
|
|
2018-03-13 20:40:56 +00:00
|
|
|
(def defn :macro
|
2018-03-12 04:26:13 +00:00
|
|
|
"Define a function"
|
|
|
|
(fn [name & more]
|
|
|
|
(def fstart (fn recur [i]
|
|
|
|
(def ith (ast-unwrap1 (get more i)))
|
|
|
|
(def t (type ith))
|
|
|
|
(def tuple? (= t :tuple))
|
|
|
|
(def array? (= t :array))
|
|
|
|
(if (if tuple? tuple? array?) i (recur (+ i 1)))))
|
|
|
|
(def start (fstart 0))
|
|
|
|
(def fnbody (tuple-prepend (tuple-prepend (tuple-slice more start) name) 'fn))
|
|
|
|
(def formargs (array-concat ['def name] (array-slice more 0 start) [fnbody]))
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple formargs)))
|
2018-03-12 04:26:13 +00:00
|
|
|
|
2018-03-13 20:40:56 +00:00
|
|
|
(def defmacro :macro
|
2018-03-12 04:26:13 +00:00
|
|
|
"Define a macro."
|
|
|
|
(do
|
|
|
|
(def defn* (get (get _env 'defn) 'value))
|
|
|
|
(fn [name & more]
|
2018-03-13 20:40:56 +00:00
|
|
|
(def args (array-concat [] name :macro more))
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 defn* args))))
|
2018-01-31 22:39:18 +00:00
|
|
|
|
2018-03-16 03:27:44 +00:00
|
|
|
(defmacro defmacro-
|
|
|
|
"Define a private macro that will not be exported."
|
|
|
|
[name & more]
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple (array-concat
|
2018-03-16 03:27:44 +00:00
|
|
|
['defmacro name :private] more)))
|
|
|
|
|
2018-03-12 04:57:13 +00:00
|
|
|
(defmacro defn-
|
|
|
|
"Define a private function that will not be exported."
|
|
|
|
[name & more]
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple (array-concat
|
2018-03-13 20:40:56 +00:00
|
|
|
['defn name :private] more)))
|
2018-03-12 04:57:13 +00:00
|
|
|
|
2018-03-15 01:46:56 +00:00
|
|
|
(defn even? [x] (== 0 (% x 2)))
|
|
|
|
(defn odd? [x] (== 1 (% x 2)))
|
|
|
|
(defn nil? [x] (= x nil))
|
|
|
|
(defn zero? [x] (== x 0))
|
2018-03-16 03:27:44 +00:00
|
|
|
(defn pos? [x] (> x 0))
|
|
|
|
(defn neg? [x] (< x 0))
|
2018-03-15 01:46:56 +00:00
|
|
|
(defn one? [x] (== x 1))
|
|
|
|
(defn inc [x] (+ x 1))
|
|
|
|
(defn dec [x] (- x 1))
|
2018-03-15 21:19:31 +00:00
|
|
|
(def atomic? (do
|
|
|
|
(def non-atomic-types {
|
|
|
|
:array true
|
|
|
|
:tuple true
|
|
|
|
:table true
|
|
|
|
:struct true
|
|
|
|
})
|
|
|
|
(fn [x] (not (get non-atomic-types (type x))))))
|
2018-03-15 01:46:56 +00:00
|
|
|
|
2018-03-16 22:31:03 +00:00
|
|
|
# C style macros for imperative sugar
|
|
|
|
(defmacro ++ [x] (tuple ':= x (tuple + x 1)))
|
|
|
|
(defmacro -- [x] (tuple ':= x (tuple - x 1)))
|
|
|
|
(defmacro += [x n] (tuple ':= x (tuple + x n)))
|
|
|
|
(defmacro -= [x n] (tuple ':= x (tuple - x n)))
|
|
|
|
(defmacro *= [x n] (tuple ':= x (tuple * x n)))
|
|
|
|
(defmacro /= [x n] (tuple ':= x (tuple / x n)))
|
|
|
|
(defmacro %= [x n] (tuple ':= x (tuple % x n)))
|
|
|
|
(defmacro &= [x n] (tuple ':= x (tuple & x n)))
|
|
|
|
(defmacro |= [x n] (tuple ':= x (tuple | x n)))
|
|
|
|
(defmacro ^= [x n] (tuple ':= x (tuple ^ x n)))
|
|
|
|
(defmacro >>= [x n] (tuple ':= x (tuple >> x n)))
|
|
|
|
(defmacro <<= [x n] (tuple ':= x (tuple << x n)))
|
|
|
|
(defmacro >>>= [x n] (tuple ':= x (tuple >>> x n)))
|
|
|
|
|
2018-03-12 06:06:51 +00:00
|
|
|
(defmacro comment
|
|
|
|
"Ignores the body of the comment."
|
|
|
|
[])
|
|
|
|
|
2018-01-31 22:39:18 +00:00
|
|
|
(defmacro when
|
2018-03-12 06:06:51 +00:00
|
|
|
"Evaluates the body when the condition is true. Otherwise returns nil."
|
2018-01-31 22:39:18 +00:00
|
|
|
[cond & body]
|
|
|
|
(tuple 'if cond (tuple-prepend body 'do)))
|
|
|
|
|
2018-03-12 04:26:13 +00:00
|
|
|
(defmacro cond
|
2018-03-12 06:06:51 +00:00
|
|
|
"Evaluates conditions sequentially until the first true condition
|
|
|
|
is found, and then executes the corresponding body. If there are an
|
|
|
|
odd number of forms, the last expression is executed if no forms
|
|
|
|
are matched. If there are no matches, return nil."
|
2018-03-12 04:26:13 +00:00
|
|
|
[& pairs]
|
|
|
|
(defn aux [i]
|
|
|
|
(def restlen (- (length pairs) i))
|
|
|
|
(if (= restlen 0) nil
|
|
|
|
(if (= restlen 1) (get pairs i)
|
|
|
|
(tuple 'if (get pairs i)
|
|
|
|
(get pairs (+ i 1))
|
|
|
|
(aux (+ i 2))))))
|
|
|
|
(aux 0))
|
|
|
|
|
2018-03-16 17:40:10 +00:00
|
|
|
(defn doc*
|
|
|
|
[env sym]
|
|
|
|
(def x (get env sym))
|
2018-03-12 04:26:13 +00:00
|
|
|
(if (not x)
|
|
|
|
(print "symbol " x " not found.")
|
|
|
|
(do
|
|
|
|
(def d (get x 'doc))
|
|
|
|
(print "\n" (if d d "no documentation found.") "\n"))))
|
|
|
|
|
2018-03-16 17:40:10 +00:00
|
|
|
(defmacro doc
|
|
|
|
"Shows documentation for the given symbol."
|
|
|
|
[sym]
|
2018-03-16 19:58:11 +00:00
|
|
|
(tuple doc* '_env (tuple 'quote sym)))
|
2018-03-16 17:40:10 +00:00
|
|
|
|
2018-03-16 19:45:24 +00:00
|
|
|
(def apply
|
|
|
|
(fn [f & args]
|
|
|
|
(def last (- (length args) 1))
|
|
|
|
(apply1 f (array-concat (array-slice args 0 -2) (get args last)))))
|
|
|
|
|
2018-03-12 04:26:13 +00:00
|
|
|
(defmacro select
|
2018-03-12 06:06:51 +00:00
|
|
|
"Select the body that equals the dispatch value. When pairs
|
|
|
|
has an odd number of arguments, the last is the default expression.
|
|
|
|
If no match is found, returns nil"
|
2018-03-12 04:26:13 +00:00
|
|
|
[dispatch & pairs]
|
|
|
|
(def sym (gensym))
|
|
|
|
(defn aux [i]
|
|
|
|
(def restlen (- (length pairs) i))
|
|
|
|
(if (= restlen 0) nil
|
|
|
|
(if (= restlen 1) (get pairs i)
|
|
|
|
(tuple 'if (tuple = sym (get pairs i))
|
|
|
|
(get pairs (+ i 1))
|
|
|
|
(aux (+ i 2))))))
|
|
|
|
(tuple 'do
|
|
|
|
(tuple 'def sym dispatch)
|
|
|
|
(aux 0)))
|
|
|
|
|
2018-03-15 01:46:56 +00:00
|
|
|
(defmacro and [& forms]
|
|
|
|
(def len (length forms))
|
|
|
|
(if (= len 0) true ((fn aux [i]
|
|
|
|
(cond
|
|
|
|
(>= (inc i) len) (get forms i)
|
|
|
|
(tuple 'if (get forms i) (aux (inc i)) false))) 0)))
|
|
|
|
|
|
|
|
(defmacro or [& forms]
|
|
|
|
(def len (length forms))
|
|
|
|
(if (= len 0) false ((fn aux [i]
|
|
|
|
(cond
|
|
|
|
(>= (inc i) len) (get forms i)
|
|
|
|
(tuple 'if (get forms i) true (aux (inc i))))) 0)))
|
2018-02-07 18:19:34 +00:00
|
|
|
|
2018-03-12 04:57:13 +00:00
|
|
|
(defn identity
|
2018-03-12 06:06:51 +00:00
|
|
|
"A function that returns its first argument."
|
2018-03-12 04:57:13 +00:00
|
|
|
[x] x)
|
2018-02-07 05:44:51 +00:00
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(def iter (do
|
|
|
|
(defn array-iter [x]
|
2018-01-31 22:39:18 +00:00
|
|
|
(def len (length x))
|
|
|
|
(var i 0)
|
|
|
|
{
|
|
|
|
:more (fn [] (< i len))
|
|
|
|
:next (fn []
|
|
|
|
(def ret (get x i))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= i (+ i 1))
|
2018-01-31 22:39:18 +00:00
|
|
|
ret)
|
|
|
|
})
|
2018-03-15 21:19:31 +00:00
|
|
|
(def iters {
|
|
|
|
:array array-iter
|
|
|
|
:tuple array-iter
|
2018-03-16 17:40:10 +00:00
|
|
|
:struct identity})
|
2018-01-31 22:39:18 +00:00
|
|
|
(fn [x]
|
2018-03-15 21:19:31 +00:00
|
|
|
(def makei (get iters (type x)))
|
|
|
|
(if makei (makei x) (error "expected sequence")))))
|
2018-01-31 22:39:18 +00:00
|
|
|
|
2018-03-16 17:40:10 +00:00
|
|
|
(defn range2 [bottom top]
|
|
|
|
(var i bottom)
|
2018-01-31 22:39:18 +00:00
|
|
|
{
|
|
|
|
:more (fn [] (< i top))
|
|
|
|
:next (fn []
|
|
|
|
(def ret i)
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= i (+ i 1))
|
2018-01-31 22:39:18 +00:00
|
|
|
ret)
|
|
|
|
})
|
|
|
|
|
2018-03-16 17:40:10 +00:00
|
|
|
(defn range [top] (range2 0 top))
|
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn doiter [itr]
|
|
|
|
(def {:more more :next next} (iter itr))
|
2018-03-12 04:26:13 +00:00
|
|
|
(while (more) (next)))
|
2018-01-31 22:39:18 +00:00
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn foreach [itr f]
|
|
|
|
(def {:more more :next next} (iter itr))
|
2018-03-14 03:39:49 +00:00
|
|
|
(while (more) (f (next))))
|
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn iter2array [itr]
|
|
|
|
(def {:more more :next next} (iter itr))
|
2018-03-15 01:46:56 +00:00
|
|
|
(def a [])
|
|
|
|
(while (more) (array-push a (next)))
|
|
|
|
a)
|
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn map [f itr]
|
|
|
|
(def {:more more :next next} (iter itr))
|
2018-03-12 04:26:13 +00:00
|
|
|
{:more more :next (fn [] (f (next)))})
|
2018-01-31 22:39:18 +00:00
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn reduce [f start itr]
|
|
|
|
(def itr (iter itr))
|
|
|
|
(def {:more more :next next} itr)
|
2018-03-12 04:26:13 +00:00
|
|
|
(if (more)
|
2018-03-15 21:19:31 +00:00
|
|
|
(reduce f (f start (next)) itr)
|
2018-03-12 04:26:13 +00:00
|
|
|
start))
|
2018-03-11 20:30:38 +00:00
|
|
|
|
2018-03-15 21:19:31 +00:00
|
|
|
(defn filter [pred itr]
|
|
|
|
(def itr (iter itr))
|
|
|
|
(def {:more more :next next} itr)
|
2018-03-13 20:40:56 +00:00
|
|
|
(var alive true)
|
|
|
|
(var temp nil)
|
|
|
|
(var isnew true)
|
|
|
|
(defn nextgood []
|
|
|
|
(if alive
|
|
|
|
(if (more)
|
|
|
|
(do
|
|
|
|
(def n (next))
|
|
|
|
(if (pred n) n (nextgood)))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= alive false))))
|
|
|
|
(defn nnext [] (def ret temp) (:= temp (nextgood)) ret)
|
|
|
|
(defn nmore [] (when isnew (:= isnew false) (nnext)) alive)
|
2018-03-13 20:40:56 +00:00
|
|
|
{:more nmore :next nnext})
|
|
|
|
|
2018-03-11 20:30:38 +00:00
|
|
|
(defmacro let [bindings & body]
|
|
|
|
(def head (ast-unwrap1 bindings))
|
|
|
|
(when (odd? (length head)) (error "expected even number of bindings to let"))
|
2018-03-12 04:26:13 +00:00
|
|
|
(def len (length head))
|
|
|
|
(var [i accum] [0 ['do]])
|
|
|
|
(while (< i len)
|
2018-03-11 20:30:38 +00:00
|
|
|
(array-push accum (tuple 'def
|
|
|
|
(get head i)
|
2018-03-12 04:26:13 +00:00
|
|
|
(get head (+ 1 i))))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= i (+ i 2)))
|
2018-03-11 20:30:38 +00:00
|
|
|
(array-push accum (tuple-prepend body 'do))
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple accum))
|
2018-02-03 22:22:04 +00:00
|
|
|
|
2018-02-06 15:31:42 +00:00
|
|
|
(defn pairs [x]
|
|
|
|
(var lastkey (next x nil))
|
|
|
|
{
|
|
|
|
:more (fn [] lastkey)
|
|
|
|
:next (fn []
|
|
|
|
(def ret (tuple lastkey (get x lastkey)))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= lastkey (next x lastkey))
|
2018-02-06 15:31:42 +00:00
|
|
|
ret)
|
|
|
|
})
|
|
|
|
|
|
|
|
(defn keys [x]
|
|
|
|
(var lastkey (next x nil))
|
|
|
|
{
|
|
|
|
:more (fn [] lastkey)
|
|
|
|
:next (fn []
|
|
|
|
(def ret lastkey)
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= lastkey (next x lastkey))
|
2018-02-06 15:31:42 +00:00
|
|
|
ret)
|
|
|
|
})
|
|
|
|
|
|
|
|
(defn values [x]
|
|
|
|
(var lastkey (next x nil))
|
|
|
|
{
|
|
|
|
:more (fn [] lastkey)
|
|
|
|
:next (fn []
|
|
|
|
(def ret (get x lastkey))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= lastkey (next x lastkey))
|
2018-02-06 15:31:42 +00:00
|
|
|
ret)
|
|
|
|
})
|
2018-02-07 05:44:51 +00:00
|
|
|
|
2018-03-12 04:26:13 +00:00
|
|
|
(defmacro for [head & body]
|
|
|
|
(def head (ast-unwrap1 head))
|
|
|
|
(def sym (get head 0))
|
|
|
|
(def start (get head 1))
|
|
|
|
(def end (get head 2))
|
|
|
|
(def _inc (get head 3))
|
|
|
|
(def inc (if _inc _inc 1))
|
|
|
|
(def endsym (gensym))
|
|
|
|
(tuple 'do
|
|
|
|
(tuple 'var sym start)
|
|
|
|
(tuple 'def endsym end)
|
|
|
|
(tuple 'while (tuple '< sym endsym)
|
|
|
|
(tuple-prepend body 'do)
|
2018-03-16 22:15:34 +00:00
|
|
|
(tuple ':= sym (tuple '+ sym inc)))))
|
2018-02-07 05:44:51 +00:00
|
|
|
|
2018-03-12 16:47:05 +00:00
|
|
|
(defmacro ->
|
|
|
|
[x & forms]
|
|
|
|
(defn fop [last nextform]
|
|
|
|
(def n (ast-unwrap1 nextform))
|
|
|
|
(def [h t] (if (= :tuple (type n))
|
|
|
|
[(get n 0) (array-slice n 1)]
|
|
|
|
[n []]))
|
|
|
|
(def parts (array-concat [h last] t))
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple parts))
|
2018-03-12 16:47:05 +00:00
|
|
|
(reduce fop x forms))
|
|
|
|
|
|
|
|
(defmacro ->>
|
|
|
|
[x & forms]
|
|
|
|
(defn fop [last nextform]
|
|
|
|
(def n (ast-unwrap1 nextform))
|
|
|
|
(def [h t] (if (= :tuple (type n))
|
|
|
|
[(get n 0) (array-slice n 1)]
|
|
|
|
[n []]))
|
2018-03-13 20:40:56 +00:00
|
|
|
(def parts (array-concat [h] t [last]))
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple parts))
|
2018-03-12 16:47:05 +00:00
|
|
|
(reduce fop x forms))
|
|
|
|
|
2018-03-14 23:08:00 +00:00
|
|
|
# Start pretty printer
|
|
|
|
(def pp (do
|
|
|
|
(defn- pp-seq [pp seen buf a start end]
|
|
|
|
(if (get seen a)
|
|
|
|
(buffer-push-string buf "<cycle>")
|
|
|
|
(do
|
|
|
|
(put seen a true)
|
|
|
|
(def len (length a))
|
|
|
|
(buffer-push-string buf start)
|
|
|
|
(for [i 0 len]
|
|
|
|
(when (not= i 0) (buffer-push-string buf " "))
|
|
|
|
(pp seen buf (get a i)))
|
|
|
|
(buffer-push-string buf end)))
|
|
|
|
buf)
|
|
|
|
|
|
|
|
(defn- pp-dict [pp seen buf a start end]
|
|
|
|
(if (get seen a)
|
|
|
|
(buffer-push-string buf "<cycle>")
|
|
|
|
(do
|
|
|
|
(put seen a true)
|
|
|
|
(var k (next a nil))
|
|
|
|
(buffer-push-string buf start)
|
|
|
|
(while k
|
|
|
|
(def v (get a k))
|
|
|
|
(pp seen buf k)
|
|
|
|
(buffer-push-string buf " ")
|
|
|
|
(pp seen buf v)
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= k (next a k))
|
2018-03-14 23:08:00 +00:00
|
|
|
(when k (buffer-push-string buf " ")))
|
|
|
|
(buffer-push-string buf end)))
|
|
|
|
buf)
|
|
|
|
|
|
|
|
(def printers :private {
|
|
|
|
:array (fn [pp seen buf x] (pp-seq pp seen buf x "[" "]"))
|
|
|
|
:tuple (fn [pp seen buf x] (pp-seq pp seen buf x "(" ")"))
|
|
|
|
:table (fn [pp seen buf x] (pp-dict pp seen buf x "@{" "}"))
|
|
|
|
:struct (fn [pp seen buf x] (pp-dict pp seen buf x "{" "}"))
|
|
|
|
})
|
|
|
|
|
|
|
|
(defn- default_printer [pp seen buf x]
|
|
|
|
(buffer-push-string buf (describe x))
|
|
|
|
buf)
|
|
|
|
|
|
|
|
(defn- pp1 [seen buf x]
|
|
|
|
(def pmaybe (get printers (type x)))
|
|
|
|
(def p (if pmaybe pmaybe default_printer))
|
|
|
|
(p pp1 seen buf x))
|
|
|
|
|
|
|
|
(fn [x] (print (pp1 @{} @"" x)))))
|
|
|
|
# End pretty printer
|
|
|
|
|
2018-03-15 01:46:56 +00:00
|
|
|
(defn unique [s]
|
|
|
|
(def tab @{})
|
2018-03-15 21:19:31 +00:00
|
|
|
(foreach s (fn [x] (put tab x true)))
|
2018-03-15 01:46:56 +00:00
|
|
|
(keys tab))
|
|
|
|
|
2018-03-16 18:34:48 +00:00
|
|
|
(defn make-env [parent safe]
|
2018-03-13 20:40:56 +00:00
|
|
|
(def parent (if parent parent _env))
|
|
|
|
(def newenv (setproto @{} parent))
|
2018-03-16 18:34:48 +00:00
|
|
|
(if (not safe)
|
|
|
|
(put newenv '_env @{'value newenv}))
|
2018-03-13 20:40:56 +00:00
|
|
|
newenv)
|
2018-03-15 21:19:31 +00:00
|
|
|
|
2018-03-12 04:26:13 +00:00
|
|
|
(def run-context
|
2018-03-12 06:06:51 +00:00
|
|
|
"Run a context. This evaluates expressions of dst in an environment,
|
|
|
|
and is encapsulates the parsing, compilation, and evaluation of dst.
|
|
|
|
env is the environment to evaluate the code in, chunks is a function
|
|
|
|
that returns strings or buffers of source code (from a repl, file,
|
|
|
|
network connection, etc. onvalue and onerr are callbacks that are
|
|
|
|
invoked when a result is returned and when an error is produced,
|
|
|
|
respectively.
|
2018-03-12 04:26:13 +00:00
|
|
|
|
2018-03-12 06:06:51 +00:00
|
|
|
This function can be used to implemement a repl very easily, simply
|
|
|
|
pass a function that reads line from stdin to chunks, and print to
|
|
|
|
onvalue."
|
2018-03-12 04:26:13 +00:00
|
|
|
(do
|
|
|
|
(defn val-stream [chunks onerr]
|
|
|
|
(var going true)
|
2018-03-13 17:31:25 +00:00
|
|
|
# Stream of characters
|
2018-03-12 04:26:13 +00:00
|
|
|
(def chars (fiber (fn []
|
2018-02-07 05:44:51 +00:00
|
|
|
(def buf @"")
|
|
|
|
(var len 1)
|
|
|
|
(while (< 0 len)
|
|
|
|
(buffer-clear buf)
|
2018-03-12 04:26:13 +00:00
|
|
|
(chunks buf)
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= len (length buf))
|
2018-02-07 05:44:51 +00:00
|
|
|
(for [i 0 len]
|
2018-03-11 19:35:23 +00:00
|
|
|
(yield (get buf i))))
|
|
|
|
0)))
|
2018-03-12 04:26:13 +00:00
|
|
|
(var temp nil)
|
|
|
|
(var tempval nil)
|
2018-03-13 17:31:25 +00:00
|
|
|
# Stream of values
|
2018-03-12 04:26:13 +00:00
|
|
|
(def f (fiber (fn []
|
2018-02-12 16:49:10 +00:00
|
|
|
(def p (parser 1))
|
2018-03-11 19:35:23 +00:00
|
|
|
(while going
|
2018-03-12 04:26:13 +00:00
|
|
|
(select (parser-status p)
|
|
|
|
:full (yield (parser-produce p))
|
|
|
|
:error (onerr "parse" (parser-error p))
|
|
|
|
(select (fiber-status chars)
|
|
|
|
:new (parser-byte p (resume chars))
|
|
|
|
:pending (parser-byte p (resume chars))
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= going false))))
|
2018-03-16 19:45:24 +00:00
|
|
|
(when (not= :root (parser-status p))
|
|
|
|
(onerr "parse" "unexpected end of source"))
|
|
|
|
nil)))
|
2018-03-12 04:26:13 +00:00
|
|
|
(defn more [] (if temp true
|
|
|
|
(do
|
2018-03-16 22:15:34 +00:00
|
|
|
(:= temp true)
|
|
|
|
(:= tempval (resume f))
|
2018-03-12 04:26:13 +00:00
|
|
|
going)))
|
|
|
|
(defn next [] (if temp
|
2018-03-16 22:15:34 +00:00
|
|
|
(do (:= temp nil) tempval)
|
2018-03-12 04:26:13 +00:00
|
|
|
(resume f)))
|
|
|
|
{:more more :next next})
|
|
|
|
(fn [env chunks onvalue onerr]
|
|
|
|
(defn doone [source]
|
|
|
|
(def f (fiber (fn []
|
|
|
|
(def res (compile source env))
|
|
|
|
(if (= (type res) :function)
|
|
|
|
(res)
|
|
|
|
(onerr "compile" (get res :error))))))
|
|
|
|
(def res (resume f))
|
|
|
|
(if (= (fiber-status f) :error)
|
|
|
|
(onerr "runtime" res)
|
|
|
|
(onvalue res)))
|
2018-03-15 21:19:31 +00:00
|
|
|
(foreach (val-stream chunks onerr) doone)
|
2018-03-12 04:26:13 +00:00
|
|
|
env)))
|
|
|
|
|
|
|
|
(def require (do
|
|
|
|
(def cache @{})
|
|
|
|
(def loading @{})
|
|
|
|
(fn [path]
|
|
|
|
(when (get loading path)
|
|
|
|
(error (string "circular dependency: module " path " is loading")))
|
|
|
|
(def check (get cache path))
|
|
|
|
(if check check (do
|
|
|
|
(def newenv (make-env))
|
|
|
|
(put cache path newenv)
|
|
|
|
(put loading path true)
|
|
|
|
(def f (file-open path))
|
|
|
|
(defn chunks [buf] (file-read f 1024 buf))
|
|
|
|
(run-context newenv chunks identity
|
|
|
|
(fn [t x] (print (string t " error: " x))))
|
|
|
|
(file-close f)
|
|
|
|
(put loading path nil)
|
|
|
|
newenv)))))
|
|
|
|
|
2018-03-16 17:40:10 +00:00
|
|
|
(defn import* [env path & args]
|
|
|
|
(def newenv (require path))
|
2018-03-12 04:26:13 +00:00
|
|
|
(def {
|
|
|
|
:prefix prefix
|
2018-03-16 19:45:24 +00:00
|
|
|
} (apply1 table args))
|
2018-03-16 17:40:10 +00:00
|
|
|
(foreach (pairs newenv) (fn [[k v]]
|
2018-03-13 20:40:56 +00:00
|
|
|
(when (not (get v :private))
|
2018-03-16 17:40:10 +00:00
|
|
|
(put env (symbol (if prefix prefix "") k) v)))))
|
|
|
|
|
|
|
|
(defmacro import [path & args]
|
2018-03-16 19:45:24 +00:00
|
|
|
(apply1 tuple (array-concat [import* '_env path] args)))
|
2018-03-12 04:26:13 +00:00
|
|
|
|
2018-03-14 03:39:49 +00:00
|
|
|
(defn repl [getchunk]
|
2018-03-12 04:26:13 +00:00
|
|
|
(def newenv (make-env))
|
|
|
|
(defn chunks [buf]
|
2018-03-14 14:54:29 +00:00
|
|
|
(file-write stdout "> ")
|
2018-03-13 17:31:25 +00:00
|
|
|
(file-flush stdout)
|
2018-02-07 05:44:51 +00:00
|
|
|
(file-read stdin :line buf))
|
2018-03-12 04:26:13 +00:00
|
|
|
(defn onvalue [x]
|
|
|
|
(put newenv '_ @{'value x})
|
2018-03-14 23:08:00 +00:00
|
|
|
(pp x))
|
2018-03-14 03:39:49 +00:00
|
|
|
(run-context newenv (if getchunk getchunk chunks) onvalue
|
2018-03-12 04:26:13 +00:00
|
|
|
(fn [t x] (print (string t " error: " x)))))
|