diff --git a/.gitignore b/.gitignore index 07869df..c27d6a7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -target/ +target/stale +target/js +target/classes classes/ checkouts/ profiles.clj diff --git a/prelude.ld b/prelude.ld deleted file mode 100644 index 6dd47e2..0000000 --- a/prelude.ld +++ /dev/null @@ -1,64 +0,0 @@ -& this file, uniquely, gets `base` loaded. See src/ludus/base.cljc for exports - -fn first { - "Returns the first element of a list or tuple." - (xs as :list) -> extern (:first, xs) - (xs as :tuple) -> extern (:second, xs) -} - -fn nth { - "Returns the element at index n of a list or tuple. Zero-indexed: the first element is at index 0." - (xs as :list, n as :number) -> extern (:nth, xs, n) - (xs as :tuple, n as :number) -> extern (:nth, xs, extern (:inc, n)) -} - -fn count { - "Returns the number of elements in a list or tuple." - (xs as :list) -> extern (count, xs) - (xs as :tuple) -> extern (:dec, extern (:count, xs)) -} - -fn list { - "Takes a tuple, and returns it as a list." - (xs as :tuple) -> extern (:into, [], extern (:rest, xs)) -} - -fn fold { - "Folds a collection." - (f as :function, xs as :list) -> extern (:reduce, f, xs) - (f as :function, root, xs as :list) -> extern (:reduce, f, root, xs) -} - -fn conj { - "Adds an element to a list. Short for conjoin." - () -> [] - (xs as :list) -> xs - (xs as :list, x) -> extern (:conj, xs, x) - & (xs, x, ...ys) -> extern (:conj, xs, x, ...ys) -} - -fn ludus/add { - "Adds numbers." - () -> 0 - (x as :number) -> x - (x as :number, y as :number) -> add (x, y) - (x as :number, y as :number, ...zs) -> fold (ludus/add, add (x, y), zs) -} - -ns math { - :add ludus/add -} - -print ("From Prelude, hello.") - -ns prelude { - first - nth - conj - fold - list -} - -print (prelude) - -prelude \ No newline at end of file diff --git a/src/ludus/base.cljc b/src/ludus/base.cljc index d2c96e7..d45cbd0 100644 --- a/src/ludus/base.cljc +++ b/src/ludus/base.cljc @@ -63,9 +63,9 @@ ::data/type ::data/clj :body dec}) -(def ld-not {:name "not" - ::data/type ::data/clj - :body not}) +(def not- {:name "not" + ::data/type ::data/clj + :body not}) (def panic! {:name "panic!" ::data/type ::data/clj @@ -118,10 +118,6 @@ (get map key default) default)))}) -(def first- {:name "first" - ::data/type ::data/clj - :body (fn [v] (second v))}) - (def rest- {:name "rest" ::data/type ::data/clj :body (fn [v] @@ -129,17 +125,7 @@ (def nth- {:name "nth" ::data/type ::data/clj - :body (fn - ([i, xs] - (cond - (> 0 i) nil - (contains? xs (inc i)) (nth xs (inc i)) - :else nil)) - ([i, xs, default] - (cond - (> 0 i) default - (contains? xs (inc i)) (nth xs (inc i)) - :else default)))}) + :body nth}) (def types { :keyword @@ -160,6 +146,12 @@ :cljs js/Number ) + :integer + #?( + :clj java.lang.Integer + :cljs js/Number + ) + :string #?( :clj java.lang.String @@ -202,6 +194,8 @@ (= (:double types) t) :number + (= (:integer types) t) :number + (= (:string types) t) :string (= (:boolean types) t) :boolean @@ -220,6 +214,7 @@ ::data/ns :ns) (::data/dict value) :dict (::data/struct value) :struct + (::data/ref value) :ref :else :none )))) @@ -255,35 +250,73 @@ (def count- {:name "count" ::data/type ::data/clj - :body (fn [xs] (dec (count xs)))}) + :body count}) + +(def into- {:name "into" + ::data/type ::data/clj + :body into}) + +(def to_vec {:name "to_vec" + ::data/type ::data.clj + :body (fn [xs] (into [] xs))}) + +(def fold {:name "fold" + ::data/type ::data/clj + :body reduce}) + +(def map- {:name "map" + ::data/type ::data/clj + :body map}) + +(def prn- {:name "raw" + ::data/type ::data/clj + :body println}) + +(def concat- {:name "concat" + ::data/type ::data/clj + :body (fn [xs ys] + (if (= ::data/list (first xs)) + (into [::data/list] (concat (rest xs) (rest ys))) + (into #{} (concat xs ys))))}) + +(def str- {:name "str" + ::data/type ::data/clj + :body str}) (def base { - "id" id - "eq" eq - "add" add - "print" print- - "sub" sub - "mult" mult - "div" div - "gt" gt - "gte" gte - "lt" lt - "lte" lte - "inc" inc- - "dec" dec- - "not" not - "show" show - "deref" deref- - "set!" set!- - "and" and- - "or" or- - "assoc" assoc- - "conj" conj- - "get" get- - "type" type- - "extern" extern - "first" first- - "rest" rest- - "nth" nth- - "count" count- + :id id + :eq eq + :add add + :print print- + :sub sub + :mult mult + :div div + :gt gt + :gte gte + :lt lt + :lte lte + :inc inc- + :dec dec- + :not not- + :show show + :deref deref- + :set! set!- + :and and- + :or or- + :assoc assoc- + :conj conj- + :get get- + :type type- + :extern extern + :rest rest- + :nth nth- + :count count- + :into into- + :to_vec to_vec + :fold fold + :map map + :panic! panic! + :prn prn- + :concat concat- + :str str- }) \ No newline at end of file diff --git a/src/ludus/interpreter.cljc b/src/ludus/interpreter.cljc index 5f3dfbe..ae2e35f 100644 --- a/src/ludus/interpreter.cljc +++ b/src/ludus/interpreter.cljc @@ -19,8 +19,8 @@ ;; that's for later, tho (defn- ludus-resolve [key ctx-vol] (let [ctx @ctx-vol] - (println "Resolving " key) - (println "Current context: " (keys ctx)) + ;(println "Resolving " key " in context " (keys ctx)) + ;(println "Current context: " (keys ctx)) ;(println "Parent context: " (keys (if (::parent ctx) (deref (::parent ctx)) {}))) (if (contains? ctx key) (get ctx key) @@ -473,7 +473,7 @@ (interpret-ast body fn-ctx))) (recur (first clauses) (rest clauses)))) - (throw (ex-info "Match Error: No match found" {:ast (:ast lfn)}))))) + (throw (ex-info (str "Match Error: No match found for " (show/show args) " in function " (:name lfn)) {:ast (:ast lfn)}))))) (keyword? lfn) (if (= 2 (count args)) @@ -488,7 +488,7 @@ (kw target))) (throw (ex-info "Called keywords take a single argument" {:ast lfn}))) - :else (throw (ex-info "I don't know how to call that" {:ast lfn})))) + :else (throw (ex-info (str "I don't know how to call " (show/show lfn)) {:ast lfn})))) (defn- interpret-args [args ctx] ;(println "interpreting arg" args) @@ -873,7 +873,7 @@ (def ludus-prelude (let [scanned (scanner/scan prelude/prelude) parsed (p/apply-parser g/script (:tokens scanned)) - base-ctx (volatile! {::parent (volatile! base/base)}) + base-ctx (volatile! {::parent (volatile! {"base" base/base})}) interpreted (interpret-ast parsed base-ctx) namespace (dissoc interpreted ::data/type ::data/name ::data/struct) context (ns->ctx namespace)] diff --git a/src/ludus/prelude.clj b/src/ludus/prelude.clj deleted file mode 100644 index 2747865..0000000 --- a/src/ludus/prelude.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns ludus.prelude) - -(def prelude (slurp "prelude.ld")) \ No newline at end of file diff --git a/src/ludus/prelude.cljc b/src/ludus/prelude.cljc new file mode 100644 index 0000000..9d9fb43 --- /dev/null +++ b/src/ludus/prelude.cljc @@ -0,0 +1,9 @@ +(ns ludus.prelude + #?(:cljs (:require [shadow.resource :as r])) + ) + +(def prelude + #?( + :clj (slurp "src/ludus/prelude.ld") + :cljs (r/inline "prelude.ld") + )) \ No newline at end of file diff --git a/src/ludus/prelude.ld b/src/ludus/prelude.ld new file mode 100644 index 0000000..5a9a375 --- /dev/null +++ b/src/ludus/prelude.ld @@ -0,0 +1,158 @@ +& this file, uniquely, gets `base` loaded as context. See src/ludus/base.cljc for exports + +fn rest { + "Returns all but the first element of a list, as a list." + (xs as :list) -> base :rest (xs) +} + +fn inc { + "Increments a number." + (x as :number) -> base :inc (x) +} + +fn dec { + "Decrements a number." + (x as :number) -> base :dec (x) + (x) -> report (x) +} + +fn nth { + "Returns the element at index n of a list or tuple. Zero-indexed: the first element is at index 0." + (xs as :list, n as :number) -> base :nth (xs, inc(n)) + (xs as :tuple, n as :number) -> base :nth (xs, inc (n)) +} + +fn first { + "Returns the first element of a list or tuple." + (xs) -> nth (xs, 0) +} + +fn second { + "Returns the second element of a list or tuple." + (xs) -> nth (xs, 1) +} + +fn count { + "Returns the number of elements in a collection (including string)." + (xs as :list) -> dec (base :count (report(xs))) + (xs as :tuple) -> dec (base :count (xs)) + (xs as :dict) -> base :count (xs) + (xs as :string) -> base :count (xs) + (xs as :set) -> base :count (xs) + (xs as :struct) -> dec (base :count (xs)) +} + +fn list { + "Takes a tuple, and returns it as a list." + (xs as :tuple) -> base :into ([], base :rest (xs)) +} + +fn fold { + "Folds a list." + (f as :fn, xs as :list) -> fold (f, xs, f ()) + (f as :fn, xs as :list, root) -> loop (root, first (xs), rest (xs)) with { + (prev, curr, []) -> f (prev, curr) + (prev, curr, remaining) -> recur ( + f (prev, curr) + first (remaining) + rest (remaining) + ) + } +} + +fn map { + "Maps over a list." + (f as :fn, xs) -> { + fn mapper (prev, curr) -> conj (prev, f (curr)) + fold (mapper, xs, []) + } +} + +fn conj { + "Adds an element to a list or set. Short for conjoin." + () -> [] + (xs as :list) -> xs + (xs as :list, x) -> base :conj (xs, x) + (xs as :set) -> xs + (xs as :set, x) -> base :conj (xs, x) +} + +fn add { + "Adds numbers." + () -> 0 + (x as :number) -> x + (x as :number, y as :number) -> base :add (x, y) + (x as :number, y as :number, ...zs) -> fold (base :add, add (x, y), zs) +} + +fn print { + "Sends a text representation of a Ludus value to stdout." + (x) -> base :print (x) +} + +fn show { + "Returns a text representation of a Ludus value as a string." + (x) -> base :show (x) +} + +fn type { + "Returns a keyword representing the type of the value passed in." + (x) -> base :type (x) +} + +fn prn { + "Prints the underlying Clojure data structure of a Ludus value." + (x) -> base :prn (x) +} + +fn concat { + "Combines two lists, strings, or sets." + (x as :string, y as :string) -> base :str (x, y) + (xs as :list, ys as :list) -> base :concat (xs, ys) + (xs as :set, ys as :set) -> base :concat (xs, ys) + (xs, ys, ...zs) -> fold (concat, zs, concat(xs, ys)) +} + +fn report { + "Prints a value, then returns it." + (x) -> { + print (x) + x + } + (msg as :string, x) -> print (concat (msg, show (x))) +} + +fn deref { + "Resolves a ref into a value." + (r as :ref) -> base :deref (r) +} + +fn set! { + "Sets the value of a ref." + (r as :ref, value) -> base :set! (r, value) +} + +ns prelude { + first + second + rest + nth + count + conj + fold + map + list + inc + dec + add + print + show + prn + type + report + concat + deref + set! +} + +prelude \ No newline at end of file diff --git a/src/ludus/web.cljs b/src/ludus/web.cljs index 70e772e..0907701 100644 --- a/src/ludus/web.cljs +++ b/src/ludus/web.cljs @@ -35,6 +35,10 @@ (js/fill 155)) (js/ellipse js/mouseX js/mouseY 80 80)) -(doto js/window - (o/set "setup" setup) - (o/set "draw" draw)) \ No newline at end of file +(defn init [] + (doto js/window + (o/set "setup" setup) + (o/set "draw" draw))) + +(o/set js/window "ludus_init" init) +