diff options
author | Eduardo Julian | 2014-11-26 19:26:22 -0400 |
---|---|---|
committer | Eduardo Julian | 2014-11-26 19:26:22 -0400 |
commit | a96bb768a5f02c2dc9c0de1e50dc14376d2e7f35 (patch) | |
tree | 2387d0bf4cf171475f0f564c9006e0546bac48e3 /src/lang/interpreter.clj | |
parent | 5bf50ef978eb88e2e61c40f3bb0fea523115e770 (diff) |
+ Can now define functions.
% However, they currently access Clojure's environment, instead of the interpreter's.
Diffstat (limited to 'src/lang/interpreter.clj')
-rw-r--r-- | src/lang/interpreter.clj | 98 |
1 files changed, 75 insertions, 23 deletions
diff --git a/src/lang/interpreter.clj b/src/lang/interpreter.clj index e79ec44d0..19fe71106 100644 --- a/src/lang/interpreter.clj +++ b/src/lang/interpreter.clj @@ -1,15 +1,24 @@ (ns lang.interpreter - (:refer-clojure :exclude [eval resolve]) + (:refer-clojure :exclude [eval resolve -' *']) (:require [clojure.core.match :refer [match]] (lang [util :as &util :refer [exec return* return fail fail* repeat-m try-m try-all-m map-m apply-m]] [parser :as &parser] - [lexer :as &lexer]) - :reload)) + [lexer :as &lexer] + [compiler :as &compiler]) + :reload) + ) (declare eval-form) +;; (defonce _init_ +;; (do (alter-var-root #'clojure.core/prn +;; (constantly #(.println System/out (apply pr-str %&)))))) + +(def <=' (fn [x] (fn [y] (<= x y)))) +(def -' (fn [x] (fn [y] (- x y)))) + ;; [Utils] (def ^:private +state+ {:globals {"*" (fn [x] (fn [y] (* x y)))} @@ -19,25 +28,42 @@ (defn wrap [x] (update-in +state+ [:forms] conj x)) +(defn wrap-in [state x] + (assoc state :forms (list x))) + (defn resolve [ident] (fn [state] + ;; (prn 'resolve ident (get-in state [:globals ident]) (get-in state [:globals])) (if-let [value (get-in state [:globals ident])] (return* state value) (fail* (str "Unrecognized identifier: " ident))))) +(defn define [name value] + (fn [state] + ;; (prn 'define name value (assoc-in state [:globals name] value)) + (return* (assoc-in state [:globals name] value) nil))) + (defn fn-call [f args] - (return (reduce #(%1 %2) f args))) + ;; (prn 'fn-call/call f args (first args) (second args)) + ;; (prn 'fn-call/output* (f (first args))) + ;; (prn 'fn-call/output* ((f (first args)) (second args))) + (let [output (reduce #(%1 %2) f args)] + ;; (prn 'fn-call/output output) + (return output))) (defmacro ^:private defeval [name match return] `(def ~name (fn [state#] - (let [token# (first (:forms state#))] - ;; (prn '~name token#) - (match token# + (let [~'*token* (first (:forms state#))] + ;; (prn '~name ~'*token*) + ;; (prn '~name state#) + (match ~'*token* ~match - (~return (update-in state# [:forms] rest)) + (let [output# (~return (update-in state# [:forms] rest))] + ;; (prn "output#" output#) + output#) _# - (fail* (str "Unknown syntax: " (pr-str token#)))))))) + (fail* (str "Unknown syntax: " (pr-str ~'*token*)))))))) (defeval eval-ident [::&parser/ident ?ident] @@ -49,16 +75,34 @@ (defeval eval-def [::&parser/def ?form ?body] - (match ?form - [::&parser/fn-call ?name ?args] - (exec [=body (apply-m eval-form (wrap ?body)) - =args (map-m (fn [arg] (apply-m eval-form (wrap arg))) - ?args)] - (return `(fn ~(vec =args) ~=body))))) + (exec [;; :let [_ (prn 'eval-defdata ?form ?cases)] + =value (apply-m &compiler/compile-form (wrap *token*)) + ;; :let [_ (prn 'eval-def 'DONE =value)] + :let [=name (match ?form + [::&parser/fn-call [::&parser/ident ?name] ?args] + ?name) + =value* (clojure.core/eval =value) + ;; _ (prn '=value* =value*) + ] + ] + (define =name =value*))) + +(defeval eval-defdata + [::&parser/defdata ?form & ?cases] + (exec [;; :let [_ (prn 'eval-defdata ?form ?cases)] + _ (apply-m &compiler/compile-form (wrap `[::&parser/defdata ~?form ~@?cases])) + ;; :let [_ (prn 'eval-defdata 'DONE)] + ] + (return nil))) + +;; [:lang.parser/defdata [:lang.parser/fn-call [:lang.parser/ident "List"] ([:lang.parser/ident "x"])] +;; ([:lang.parser/tagged "Nil" [:lang.parser/tuple ()]] +;; [:lang.parser/tagged "Cons" [:lang.parser/tuple ([:lang.parser/ident "x"] [:lang.parser/fn-call [:lang.parser/ident "List"] ([:lang.parser/ident "x"])])]])] (defeval eval-fn-call [::&parser/fn-call ?fn ?args] - (exec [=fn (apply-m eval-form (wrap ?fn)) + (exec [state &util/get-state + =fn (apply-m eval-form (wrap-in state ?fn)) =args (map-m (fn [arg] (apply-m eval-form (wrap arg))) ?args)] (fn-call =fn =args))) @@ -67,6 +111,7 @@ (try-all-m [eval-ident eval-int eval-def + eval-defdata eval-fn-call])) ;; [::def [::fn-call [::ident "**"] ([::ident "base"] [::ident "exp"])] @@ -75,11 +120,11 @@ ;; [::fn-call [::ident "repeat"] ([::ident "exp"] ;; [::ident "base"])])]] -(defn eval [state] - (match (eval-form state) - [::&util/ok [?state ?datum]] +(defn eval [text] + (match ((repeat-m eval-form) text) + [::&util/ok [?state ?forms]] (if (empty? (:forms ?state)) - ?datum + ?forms (assert false (str "Unconsumed input: " ?state))) [::&util/failure ?message] @@ -88,9 +133,14 @@ (comment (let [source-code (slurp "src/example/test1.lang") tokens (&lexer/lex source-code) - syntax (&parser/parse (list tokens))] - ;; (prn 'syntax syntax) - (eval (update-in +state+ [:forms] concat (list syntax)))) + _ (prn 'tokens tokens) + syntax (&parser/parse tokens) + _ (prn 'syntax syntax)] + (eval (update-in +state+ [:forms] concat syntax))) + + + + ;; (clojure.core/fn [base exp] (fold * 1 (repeat exp base))) @@ -112,4 +162,6 @@ ;; (def (** base exp) ;; (fold * 1 (repeat exp base))) + + ) |