diff --git a/foo.ld b/foo.ld new file mode 100644 index 0000000..2a2d08c --- /dev/null +++ b/foo.ld @@ -0,0 +1 @@ +:foo \ No newline at end of file diff --git a/sandbox.ld b/sandbox.ld new file mode 100644 index 0000000..b168e9b --- /dev/null +++ b/sandbox.ld @@ -0,0 +1,3 @@ +import "foo.ld" as foo + +print ("Hello, world!", foo) \ No newline at end of file diff --git a/src/ludus/core.clj b/src/ludus/core.clj index 5ebf00c..dc65914 100644 --- a/src/ludus/core.clj +++ b/src/ludus/core.clj @@ -1,37 +1,39 @@ (ns ludus.core "A tree-walk interpreter for the Ludus language." (:require - [ludus.scanner :as scanner] - [ludus.parser :as parser] - [ludus.interpreter :as interpreter] - [ludus.show :as show] - [clojure.pprint :as pp] - [ludus.loader :as loader] - [ludus.repl :as repl]) + [ludus.scanner :as scanner] + ;[ludus.parser :as parser] + [ludus.parser-new :as p] + [ludus.grammar :as g] + [ludus.interpreter :as interpreter] + [ludus.show :as show] + [clojure.pprint :as pp] + [ludus.loader :as loader] + [ludus.repl :as repl]) (:gen-class)) (defn- run [file source] -(comment (let [scanned (scanner/scan source)] + (let [scanned (scanner/scan source)] (if (not-empty (:errors scanned)) (do (println "I found some scanning errors!") (pp/pprint (:errors scanned)) (System/exit 65)) - (let [parsed (parser/parse scanned)] - (if (not-empty (:errors parsed)) + (let [parsed (p/apply-parser g/script (:tokens scanned))] + (if (p/fail? parsed) (do (println "I found some parsing errors!") - (pp/pprint (:errors parsed)) + (println p/err-msg parsed) (System/exit 66)) - (let [interpreted (interpreter/interpret parsed file)] + (let [interpreted (interpreter/interpret source file parsed)] (println (show/show interpreted)) - (System/exit 0)))))))) + (System/exit 0))))))) (defn -main [& args] -(comment (cond + (cond (= (count args) 1) (let [file (first args) source (loader/load-import file)] (run file source)) - :else (repl/launch)))) \ No newline at end of file + :else (repl/launch))) \ No newline at end of file diff --git a/src/ludus/interpreter.clj b/src/ludus/interpreter.clj index cf2ac8c..e06a80d 100644 --- a/src/ludus/interpreter.clj +++ b/src/ludus/interpreter.clj @@ -11,8 +11,8 @@ [ludus.loader :as loader] [ludus.token :as token] [ludus.process :as process] - [clojure.pprint :as pp] - [clojure.set])) + [clojure.set] + [clojure.string])) (def ^:dynamic self @process/current-pid) @@ -301,7 +301,7 @@ :struct-pattern (match-struct pattern value ctx-vol) - (throw (ex-info "Unknown pattern on line " {:pattern pattern :value value}))))) + (throw (ex-info "Unknown pattern on line " {:ast pattern :value value}))))) (defn- update-ctx [ctx new-ctx] (merge ctx new-ctx)) @@ -607,9 +607,15 @@ (if (::loader/error (ex-data e)) (throw (ex-info (ex-message e) {:ast ast})) (throw e)))) - result (-> source (scanner/scan) (parser/parse) (interpret-file path))] - (vswap! ctx update-ctx {name result}) - result + parsed (->> source (scanner/scan) :tokens (p/apply-parser g/script))] + (if (p/fail? parsed) + (throw (ex-info + (str "Parse error in file " path "\n" + (p/err-msg parsed)) + {:ast ast})) + (let [interpret-result (interpret-file source path parsed)] + (vswap! ctx update-ctx {name interpret-result}) + interpret-result)) )))) (defn- interpret-ref [ast ctx] @@ -883,35 +889,42 @@ :dict (interpret-dict ast ctx) :struct-literal - (let [members (:members ast)] (interpret-struct ast ctx)) + (interpret-struct ast ctx) - (throw (ex-info "Unknown AST node type" {:ast ast})))) + (throw (ex-info (str "Unknown AST node type: " (:type ast)) {:ast ast})))) + +(defn get-line [source line] + (if line + (let [lines (clojure.string/split source #"\n")] + (clojure.string/trim (nth lines (dec line)))))) ;; TODO: update this to use new parser pipeline & new AST representation -(defn interpret-file [parsed file] +(defn interpret-file [source path parsed] (try - (let [base-ctx (volatile! (merge {:file file} prelude/prelude process/process))] - (interpret-ast (::parser/ast parsed) base-ctx)) + (let [base-ctx (volatile! {::parent (volatile! prelude/prelude) :file path})] + (interpret-ast parsed base-ctx)) (catch clojure.lang.ExceptionInfo e - (println "Ludus panicked in" file) - (println "On line" (get-in (ex-data e) [:ast :token ::token/line])) + (println "Ludus panicked in" path) + (println "On line" (get-in (ex-data e) [:ast :token :line])) + (println ">>> " (get-line source (get-in (ex-data e) [:ast :token :line]))) (println (ex-message e)) (System/exit 67)))) ;; TODO: update this to use new parser pipeline & new AST representation -(defn interpret [parsed file] +(defn interpret [source path parsed] (try - (let [base-ctx (volatile! (merge {:file file} prelude/prelude process/process)) + (let [base-ctx (volatile! {::parent (volatile! prelude/prelude) :file path}) process (process/new-process)] (process/start-vm) (with-bindings {#'self (:pid @process)} - (let [result (interpret-ast (::parser/ast parsed) {::parent base-ctx})] + (let [result (interpret-ast parsed base-ctx)] (swap! process #(assoc % :status :dead)) (process/stop-vm) result))) (catch clojure.lang.ExceptionInfo e - (println "Ludus panicked in" file) - (println "On line" (get-in (ex-data e) [:ast :token ::token/line])) + (println "Ludus panicked in" path) + (println "On line" (get-in (ex-data e) [:ast :token :line])) + (println ">>> " (get-line source (get-in (ex-data e) [:ast :token :line]))) (println (ex-message e)) (System/exit 67)))) @@ -927,10 +940,11 @@ result))) (catch clojure.lang.ExceptionInfo e (process/stop-vm) - (println "Ludus panicked!") - (println "On line" (get-in (ex-data e) [:ast :token :line])) + (println "Ludus panicked on line " (get-in (ex-data e) [:ast :token :line])) + (println "> " (get-in (ex-data e) [:ast :token])) (println (ex-message e)) - (pp/pprint (ex-data e))))) + ;(pp/pprint (ex-data e)) + ))) ;; TODO: update this to use new parser pipeline & new AST representation (defn interpret-repl @@ -941,7 +955,7 @@ (try (process/start-vm) (with-bindings {#'self pid} - (let [result (interpret-ast (::parser/ast parsed) ctx)] + (let [result (interpret-ast parsed ctx)] {:result result :ctx ctx :pid pid})) (catch clojure.lang.ExceptionInfo e (println "Ludus panicked!") @@ -952,7 +966,7 @@ (try (process/start-vm) (with-bindings {#'self pid} - (let [result (interpret-ast (::parser/ast parsed) ctx)] + (let [result (interpret-ast parsed ctx)] {:result result :ctx ctx :pid pid})) (catch clojure.lang.ExceptionInfo e (println "Ludus panicked!") @@ -961,11 +975,9 @@ ))))) -(do +(comment (def source " - let xs = [1, 2, 3] - let ys = #{:a 1, :b 2} - get (:c, ys) + let 2 = 1 ") (println "") diff --git a/src/ludus/prelude.clj b/src/ludus/prelude.clj index b21d07f..d4f8337 100644 --- a/src/ludus/prelude.clj +++ b/src/ludus/prelude.clj @@ -2,7 +2,8 @@ (:require [ludus.data :as data] [ludus.show :as show] - [ludus.draw :as d])) + ;[ludus.draw :as d] + )) ;; TODO: make eq, and, or special forms that short-circuit ;; Right now, they evaluate all their args @@ -102,10 +103,6 @@ (get map key default) default)))}) -(def draw {:name "draw" - ::data/type ::data/clj - :body d/ludus-draw}) - (def first- {:name "first" ::data/type ::data/clj :body (fn [v] (second v))}) @@ -191,7 +188,6 @@ "assoc" assoc- "conj" conj- "get" get- - "draw" draw "type" type- "clj" clj "first" first- diff --git a/src/ludus/repl.clj b/src/ludus/repl.clj index 6b5fcd1..6455f48 100644 --- a/src/ludus/repl.clj +++ b/src/ludus/repl.clj @@ -1,12 +1,15 @@ (ns ludus.repl (:require [ludus.scanner :as scanner] - [ludus.parser :as parser] + ;[ludus.parser :as parser] + [ludus.parser-new :as p] + [ludus.grammar :as g] [ludus.interpreter :as interpreter] [ludus.prelude :as prelude] [ludus.show :as show] [ludus.data :as data] - [ludus.process :as process])) + ;[ludus.process :as process] + )) (declare repl-prelude new-session) @@ -20,7 +23,7 @@ (println "\nGoodbye!") (System/exit 0)) -(def base-ctx (merge prelude/prelude process/process +(def base-ctx (merge prelude/prelude ;process/process {::repl true "repl" {::data/struct true @@ -91,20 +94,27 @@ (= "" input) (recur) :else - (let [parsed (-> input (scanner/scan) (parser/parse)) - {result :result ctx :ctx pid- :pid} - (if pid - (interpreter/interpret-repl parsed orig-ctx pid) - (interpreter/interpret-repl parsed orig-ctx))] - (if (= result ::interpreter/error) - (recur) + (let [parsed (->> input + (scanner/scan) + :tokens + (p/apply-parser g/script))] + (if (= :err (:status parsed)) (do - (println (show/show result)) - (when (not (= @ctx @orig-ctx)) - (swap! session-atom #(assoc % :ctx ctx))) - (when (not (= pid pid-)) - (swap! session-atom #(assoc % :pid pid-))) - (recur)))))))) + (println (p/err-msg parsed)) + (recur)) + (let [{result :result ctx :ctx pid- :pid} + (if pid + (interpreter/interpret-repl parsed orig-ctx pid) + (interpreter/interpret-repl parsed orig-ctx))] + (if (= result :error) + (recur) + (do + (println (show/show result)) + (when (not (= @ctx @orig-ctx)) + (swap! session-atom #(assoc % :ctx ctx))) + (when (not (= pid pid-)) + (swap! session-atom #(assoc % :pid pid-))) + (recur)))))))))) (defn launch [] (println "Welcome to Ludus (v. 0.1.0-alpha)")