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
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?!!?!
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.
@ -24,6 +31,10 @@ Download from http://example.com/FIXME.
`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
The `Lisp 1.5 Programmer's Manual` is still

View file

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

View file

@ -1,15 +1,53 @@
(ns beowulf.core
(:require [beowulf.eval :refer [EVAL oblist]]
[beowulf.read :refer [READ]])
[beowulf.read :refer [READ]]
[clojure.pprint :refer [pprint]]
[environ.core :refer [env]])
(:gen-class))
(defn -main
(defn repl
"Read/eval/print loop."
[& args]
(println "Béowulf is mín nama")
[]
(loop []
(print ":: ")
(flush)
(let [input (READ)]
(println (str "> " (EVAL input @oblist)))
(recur))))
(try
(let [input (read-line)]
(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]*'")))
(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]
(simplify p :sexpr))
(if
(instance? instaparse.gll.Failure p)
(throw (ex-info "Parse error" {:cause :parse-failure :failure p}))
(simplify p :sexpr)))
([p context]
(if
(coll? p)
@ -274,5 +278,5 @@
`(generate (simplify (parse ~s))))
(defn READ
[]
(gsp (read-line)))
[input]
(gsp (or input (read-line))))