Considerably improved REPL, with better parse error handling

This commit is contained in:
Simon Brooke 2019-08-17 13:48:49 +01:00
parent 609e2c3a6e
commit 526b71bce7
4 changed files with 69 additions and 14 deletions

View file

@ -4,15 +4,22 @@ LISP 1.5 is to all Lisp dialects as Beowulf is to Emglish literature.
## What this is ## What this is
A work-in-progress towards an implementation of Lisp 1.5 in Clojure. A work-in-progress towards an implementation of Lisp 1.5 in Clojure. The
objective is to build a complete and accurate implementation of Lisp 1.5
as described in the manual, with, in so far as is possible, exactly the
same bahaviour; the only intended deviation is that the parser reads
'mexprs' (meta language expressions) as well as sexprs.
## BUT WHY?!!?! ## BUT WHY?!!?!
Because. Because.
Because Lisp is the only computer language worth learning, and if a thing is worth learning, it's worth learning properly; which means going back to the beginning and trying to understand that. Because Lisp is the only computer language worth learning, and if a thing
is worth learning, it's worth learning properly; which means going back to
the beginning and trying to understand that.
Because there is, so far as I know, no working implementation of Lisp 1.5 for modern machines. Because there is, so far as I know, no working implementation of Lisp 1.5
for modern machines.
Because I'm barking mad, and this is therapy. Because I'm barking mad, and this is therapy.
@ -24,6 +31,10 @@ Download from http://example.com/FIXME.
`java -jar beowulf-0.1.0-standalone.jar` `java -jar beowulf-0.1.0-standalone.jar`
This will start a Lisp 1.5 read/eval/print loop (REPL).
To end a session, type `quit` at the command prompt.
## Learning Lisp 1.5 ## Learning Lisp 1.5
The `Lisp 1.5 Programmer's Manual` is still The `Lisp 1.5 Programmer's Manual` is still

View file

@ -6,7 +6,9 @@
:dependencies [[org.clojure/clojure "1.10.0"] :dependencies [[org.clojure/clojure "1.10.0"]
[org.clojure/math.numeric-tower "0.0.4"] [org.clojure/math.numeric-tower "0.0.4"]
[org.clojure/tools.trace "0.7.10"] [org.clojure/tools.trace "0.7.10"]
[environ "1.1.0"]
[instaparse "1.4.10"]] [instaparse "1.4.10"]]
:main ^:skip-aot beowulf.core :main ^:skip-aot beowulf.core
:plugins [[lein-environ "1.1.0"]]
:target-path "target/%s" :target-path "target/%s"
:profiles {:uberjar {:aot :all}}) :profiles {:uberjar {:aot :all}})

View file

@ -1,15 +1,53 @@
(ns beowulf.core (ns beowulf.core
(:require [beowulf.eval :refer [EVAL oblist]] (:require [beowulf.eval :refer [EVAL oblist]]
[beowulf.read :refer [READ]]) [beowulf.read :refer [READ]]
[clojure.pprint :refer [pprint]]
[environ.core :refer [env]])
(:gen-class)) (:gen-class))
(defn -main (defn repl
"Read/eval/print loop." "Read/eval/print loop."
[& args] []
(println "Béowulf is mín nama")
(loop [] (loop []
(print ":: ") (print ":: ")
(flush) (flush)
(let [input (READ)] (try
(println (str "> " (EVAL input @oblist))) (let [input (read-line)]
(recur)))) (cond
(= input "quit") (throw (ex-info "Færwell!" {:cause :quit}))
input (println (str "> " (EVAL (READ input) @oblist)))
:else (println)))
(catch
Exception
e
(let [data (ex-data e)]
(if
data
(case (:cause data)
:parse-failure (println (:failure data))
:quit (throw e)
;; default
(pprint data))
(println (.getMessage e))))))
(recur)))
(defn -main
[& args]
(println
(str
"Hider wilcuman. Béowulf is mín nama\nSíðe "
(System/getProperty "beowulf.version")
"\n\n"))
(try
(repl)
(catch
Exception
e
(let [data (ex-data e)]
(if
data
(case (:cause data)
:quit (println (.getMessage e))
;; default
(pprint data))
(println e))))))

View file

@ -64,9 +64,13 @@
scale-factor := #'[0-9]*'"))) scale-factor := #'[0-9]*'")))
(defn simplify (defn simplify
"Simplify this parse tree `p`." "Simplify this parse tree `p`. If `p` is an instaparse failure object, throw
an `ex-info`, with `p` as the value of its `:failure` key."
([p] ([p]
(simplify p :sexpr)) (if
(instance? instaparse.gll.Failure p)
(throw (ex-info "Parse error" {:cause :parse-failure :failure p}))
(simplify p :sexpr)))
([p context] ([p context]
(if (if
(coll? p) (coll? p)
@ -274,5 +278,5 @@
`(generate (simplify (parse ~s)))) `(generate (simplify (parse ~s))))
(defn READ (defn READ
[] [input]
(gsp (read-line))) (gsp (or input (read-line))))