aboutsummaryrefslogtreecommitdiff
path: root/src/lang/interpreter.clj
diff options
context:
space:
mode:
authorEduardo Julian2014-11-26 19:26:22 -0400
committerEduardo Julian2014-11-26 19:26:22 -0400
commita96bb768a5f02c2dc9c0de1e50dc14376d2e7f35 (patch)
tree2387d0bf4cf171475f0f564c9006e0546bac48e3 /src/lang/interpreter.clj
parent5bf50ef978eb88e2e61c40f3bb0fea523115e770 (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.clj98
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)))
+
+
)