Wire up repl & file interpreters.

This commit is contained in:
Scott Richmond 2023-06-01 15:06:33 -06:00
parent c179325719
commit 7c30b6259b
6 changed files with 88 additions and 64 deletions

1
foo.ld Normal file
View File

@ -0,0 +1 @@
:foo

3
sandbox.ld Normal file
View File

@ -0,0 +1,3 @@
import "foo.ld" as foo
print ("Hello, world!", foo)

View File

@ -1,37 +1,39 @@
(ns ludus.core (ns ludus.core
"A tree-walk interpreter for the Ludus language." "A tree-walk interpreter for the Ludus language."
(:require (:require
[ludus.scanner :as scanner] [ludus.scanner :as scanner]
[ludus.parser :as parser] ;[ludus.parser :as parser]
[ludus.interpreter :as interpreter] [ludus.parser-new :as p]
[ludus.show :as show] [ludus.grammar :as g]
[clojure.pprint :as pp] [ludus.interpreter :as interpreter]
[ludus.loader :as loader] [ludus.show :as show]
[ludus.repl :as repl]) [clojure.pprint :as pp]
[ludus.loader :as loader]
[ludus.repl :as repl])
(:gen-class)) (:gen-class))
(defn- run [file source] (defn- run [file source]
(comment (let [scanned (scanner/scan source)] (let [scanned (scanner/scan source)]
(if (not-empty (:errors scanned)) (if (not-empty (:errors scanned))
(do (do
(println "I found some scanning errors!") (println "I found some scanning errors!")
(pp/pprint (:errors scanned)) (pp/pprint (:errors scanned))
(System/exit 65)) (System/exit 65))
(let [parsed (parser/parse scanned)] (let [parsed (p/apply-parser g/script (:tokens scanned))]
(if (not-empty (:errors parsed)) (if (p/fail? parsed)
(do (do
(println "I found some parsing errors!") (println "I found some parsing errors!")
(pp/pprint (:errors parsed)) (println p/err-msg parsed)
(System/exit 66)) (System/exit 66))
(let [interpreted (interpreter/interpret parsed file)] (let [interpreted (interpreter/interpret source file parsed)]
(println (show/show interpreted)) (println (show/show interpreted))
(System/exit 0)))))))) (System/exit 0)))))))
(defn -main [& args] (defn -main [& args]
(comment (cond (cond
(= (count args) 1) (= (count args) 1)
(let [file (first args) (let [file (first args)
source (loader/load-import file)] source (loader/load-import file)]
(run file source)) (run file source))
:else (repl/launch)))) :else (repl/launch)))

View File

@ -11,8 +11,8 @@
[ludus.loader :as loader] [ludus.loader :as loader]
[ludus.token :as token] [ludus.token :as token]
[ludus.process :as process] [ludus.process :as process]
[clojure.pprint :as pp] [clojure.set]
[clojure.set])) [clojure.string]))
(def ^:dynamic self @process/current-pid) (def ^:dynamic self @process/current-pid)
@ -301,7 +301,7 @@
:struct-pattern (match-struct pattern value ctx-vol) :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] (defn- update-ctx [ctx new-ctx]
(merge ctx new-ctx)) (merge ctx new-ctx))
@ -607,9 +607,15 @@
(if (::loader/error (ex-data e)) (if (::loader/error (ex-data e))
(throw (ex-info (ex-message e) {:ast ast})) (throw (ex-info (ex-message e) {:ast ast}))
(throw e)))) (throw e))))
result (-> source (scanner/scan) (parser/parse) (interpret-file path))] parsed (->> source (scanner/scan) :tokens (p/apply-parser g/script))]
(vswap! ctx update-ctx {name result}) (if (p/fail? parsed)
result (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] (defn- interpret-ref [ast ctx]
@ -883,35 +889,42 @@
:dict (interpret-dict ast ctx) :dict (interpret-dict ast ctx)
:struct-literal :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 ;; TODO: update this to use new parser pipeline & new AST representation
(defn interpret-file [parsed file] (defn interpret-file [source path parsed]
(try (try
(let [base-ctx (volatile! (merge {:file file} prelude/prelude process/process))] (let [base-ctx (volatile! {::parent (volatile! prelude/prelude) :file path})]
(interpret-ast (::parser/ast parsed) base-ctx)) (interpret-ast parsed base-ctx))
(catch clojure.lang.ExceptionInfo e (catch clojure.lang.ExceptionInfo e
(println "Ludus panicked in" file) (println "Ludus panicked in" path)
(println "On line" (get-in (ex-data e) [:ast :token ::token/line])) (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)) (println (ex-message e))
(System/exit 67)))) (System/exit 67))))
;; TODO: update this to use new parser pipeline & new AST representation ;; TODO: update this to use new parser pipeline & new AST representation
(defn interpret [parsed file] (defn interpret [source path parsed]
(try (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 (process/new-process)]
(process/start-vm) (process/start-vm)
(with-bindings {#'self (:pid @process)} (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)) (swap! process #(assoc % :status :dead))
(process/stop-vm) (process/stop-vm)
result))) result)))
(catch clojure.lang.ExceptionInfo e (catch clojure.lang.ExceptionInfo e
(println "Ludus panicked in" file) (println "Ludus panicked in" path)
(println "On line" (get-in (ex-data e) [:ast :token ::token/line])) (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)) (println (ex-message e))
(System/exit 67)))) (System/exit 67))))
@ -927,10 +940,11 @@
result))) result)))
(catch clojure.lang.ExceptionInfo e (catch clojure.lang.ExceptionInfo e
(process/stop-vm) (process/stop-vm)
(println "Ludus panicked!") (println "Ludus panicked on line " (get-in (ex-data e) [:ast :token :line]))
(println "On line" (get-in (ex-data e) [:ast :token :line])) (println "> " (get-in (ex-data e) [:ast :token]))
(println (ex-message e)) (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 ;; TODO: update this to use new parser pipeline & new AST representation
(defn interpret-repl (defn interpret-repl
@ -941,7 +955,7 @@
(try (try
(process/start-vm) (process/start-vm)
(with-bindings {#'self pid} (with-bindings {#'self pid}
(let [result (interpret-ast (::parser/ast parsed) ctx)] (let [result (interpret-ast parsed ctx)]
{:result result :ctx ctx :pid pid})) {:result result :ctx ctx :pid pid}))
(catch clojure.lang.ExceptionInfo e (catch clojure.lang.ExceptionInfo e
(println "Ludus panicked!") (println "Ludus panicked!")
@ -952,7 +966,7 @@
(try (try
(process/start-vm) (process/start-vm)
(with-bindings {#'self pid} (with-bindings {#'self pid}
(let [result (interpret-ast (::parser/ast parsed) ctx)] (let [result (interpret-ast parsed ctx)]
{:result result :ctx ctx :pid pid})) {:result result :ctx ctx :pid pid}))
(catch clojure.lang.ExceptionInfo e (catch clojure.lang.ExceptionInfo e
(println "Ludus panicked!") (println "Ludus panicked!")
@ -961,11 +975,9 @@
))))) )))))
(do (comment
(def source " (def source "
let xs = [1, 2, 3] let 2 = 1
let ys = #{:a 1, :b 2}
get (:c, ys)
") ")
(println "") (println "")

View File

@ -2,7 +2,8 @@
(:require (:require
[ludus.data :as data] [ludus.data :as data]
[ludus.show :as show] [ludus.show :as show]
[ludus.draw :as d])) ;[ludus.draw :as d]
))
;; TODO: make eq, and, or special forms that short-circuit ;; TODO: make eq, and, or special forms that short-circuit
;; Right now, they evaluate all their args ;; Right now, they evaluate all their args
@ -102,10 +103,6 @@
(get map key default) (get map key default)
default)))}) default)))})
(def draw {:name "draw"
::data/type ::data/clj
:body d/ludus-draw})
(def first- {:name "first" (def first- {:name "first"
::data/type ::data/clj ::data/type ::data/clj
:body (fn [v] (second v))}) :body (fn [v] (second v))})
@ -191,7 +188,6 @@
"assoc" assoc- "assoc" assoc-
"conj" conj- "conj" conj-
"get" get- "get" get-
"draw" draw
"type" type- "type" type-
"clj" clj "clj" clj
"first" first- "first" first-

View File

@ -1,12 +1,15 @@
(ns ludus.repl (ns ludus.repl
(:require (:require
[ludus.scanner :as scanner] [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.interpreter :as interpreter]
[ludus.prelude :as prelude] [ludus.prelude :as prelude]
[ludus.show :as show] [ludus.show :as show]
[ludus.data :as data] [ludus.data :as data]
[ludus.process :as process])) ;[ludus.process :as process]
))
(declare repl-prelude new-session) (declare repl-prelude new-session)
@ -20,7 +23,7 @@
(println "\nGoodbye!") (println "\nGoodbye!")
(System/exit 0)) (System/exit 0))
(def base-ctx (merge prelude/prelude process/process (def base-ctx (merge prelude/prelude ;process/process
{::repl true {::repl true
"repl" "repl"
{::data/struct true {::data/struct true
@ -91,20 +94,27 @@
(= "" input) (recur) (= "" input) (recur)
:else :else
(let [parsed (-> input (scanner/scan) (parser/parse)) (let [parsed (->> input
{result :result ctx :ctx pid- :pid} (scanner/scan)
(if pid :tokens
(interpreter/interpret-repl parsed orig-ctx pid) (p/apply-parser g/script))]
(interpreter/interpret-repl parsed orig-ctx))] (if (= :err (:status parsed))
(if (= result ::interpreter/error)
(recur)
(do (do
(println (show/show result)) (println (p/err-msg parsed))
(when (not (= @ctx @orig-ctx)) (recur))
(swap! session-atom #(assoc % :ctx ctx))) (let [{result :result ctx :ctx pid- :pid}
(when (not (= pid pid-)) (if pid
(swap! session-atom #(assoc % :pid pid-))) (interpreter/interpret-repl parsed orig-ctx pid)
(recur)))))))) (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 [] (defn launch []
(println "Welcome to Ludus (v. 0.1.0-alpha)") (println "Welcome to Ludus (v. 0.1.0-alpha)")