Considerably improved REPL, with better parse error handling
This commit is contained in:
parent
609e2c3a6e
commit
526b71bce7
17
README.md
17
README.md
|
@ -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
|
||||||
|
|
|
@ -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}})
|
||||||
|
|
|
@ -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))))))
|
||||||
|
|
|
@ -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))))
|
||||||
|
|
Loading…
Reference in a new issue