Strict mode now works...

This commit is contained in:
Simon Brooke 2019-08-20 10:38:51 +01:00
parent 75bf19e38e
commit fe6fba87e0
5 changed files with 62 additions and 12 deletions

View file

@ -19,8 +19,8 @@
be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things." be Lisp 1.5's EQuivalent of `SETQ`), possibly by other things."
(atom NIL)) (atom NIL))
(def ^:dynamic *trace?* (def ^:dynamic *options*
"Whether or not to trace `EVAL`." "Command line options from invocation."
false) false)
(defn NULL (defn NULL
@ -304,7 +304,8 @@
See page 13 of the Lisp 1.5 Programmers Manual." See page 13 of the Lisp 1.5 Programmers Manual."
[expr env] [expr env]
(cond (cond
*trace?* (traced-eval expr env) (true? (:trace *options*))
(traced-eval expr env)
(= (=
(ATOM? expr) 'T) (ATOM? expr) 'T)
(CDR (ASSOC expr env)) (CDR (ASSOC expr env))

View file

@ -1,5 +1,5 @@
(ns beowulf.core (ns beowulf.core
(:require [beowulf.bootstrap :refer [EVAL oblist *trace?*]] (:require [beowulf.bootstrap :refer [EVAL oblist *options*]]
[beowulf.read :refer [READ]] [beowulf.read :refer [READ]]
[clojure.java.io :as io] [clojure.java.io :as io]
[clojure.pprint :refer [pprint]] [clojure.pprint :refer [pprint]]
@ -40,6 +40,7 @@
data data
(case (:cause data) (case (:cause data)
:parse-failure (println (:failure data)) :parse-failure (println (:failure data))
:strict nil ;; the message, which has already been printed, is enough.
:quit (throw e) :quit (throw e)
;; default ;; default
(pprint data)))))) (pprint data))))))
@ -60,7 +61,7 @@
(if (:errors args) (if (:errors args)
(apply str (interpose "; " (:errors args)))) (apply str (interpose "; " (:errors args))))
"\nSprecan 'quit' tó laéfan\n")) "\nSprecan 'quit' tó laéfan\n"))
(binding [*trace?* (true? (:trace (:options args)))] (binding [*options* (:options args)]
(try (try
(repl (str (:prompt (:options args)) " ")) (repl (str (:prompt (:options args)) " "))
(catch (catch

View file

@ -1,5 +1,6 @@
(ns beowulf.read (ns beowulf.read
(:require [clojure.math.numeric-tower :refer [expt]] (:require [beowulf.bootstrap :refer [*options*]]
[clojure.math.numeric-tower :refer [expt]]
[clojure.string :refer [starts-with? upper-case]] [clojure.string :refer [starts-with? upper-case]]
[instaparse.core :as i] [instaparse.core :as i]
[beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]])) [beowulf.cons-cell :refer [make-beowulf-list make-cons-cell NIL]]))
@ -24,7 +25,7 @@
;; mexprs. I'm pretty clear that Lisp 1.5 could never read these, ;; mexprs. I'm pretty clear that Lisp 1.5 could never read these,
;; but it's a convenience. ;; but it's a convenience.
"mexpr := λexpr | fncall | defn | cond | mvar; "mexpr := λexpr | fncall | defn | cond | mvar | mexpr comment;
λexpr := λ lsqb bindings semi-colon body rsqb; λexpr := λ lsqb bindings semi-colon body rsqb;
λ := '; λ := ';
bindings := lsqb args rsqb; bindings := lsqb args rsqb;
@ -41,9 +42,12 @@
mvar := #'[a-z]+'; mvar := #'[a-z]+';
semi-colon := ';';" semi-colon := ';';"
;; comments. I'm pretty confident Lisp 1.5 did NOT have these.
"comment := opt-space <';;'> #'[^\\n\\r]*';"
;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro, ;; sexprs. Note it's not clear to me whether Lisp 1.5 had the quote macro,
;; but I've included it on the basis that it can do little harm. ;; but I've included it on the basis that it can do little harm.
"sexpr := quoted-expr | atom | number | dotted-pair | list; "sexpr := quoted-expr | atom | number | dotted-pair | list | sexpr comment;
list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal; list := lpar sexpr rpar | lpar (sexpr sep)* rpar | lpar (sexpr sep)* dot-terminal;
dotted-pair := lpar dot-terminal ; dotted-pair := lpar dot-terminal ;
dot := '.'; dot := '.';
@ -95,6 +99,11 @@
(= context :mexpr) (= context :mexpr)
[:quoted-expr p] [:quoted-expr p]
p) p)
:comment (if
(:strict *options*)
(throw
(ex-info "Cannot parse comments in strict mode"
{:cause :strict})))
:dotted-pair (if :dotted-pair (if
(= context :mexpr) (= context :mexpr)
[:fncall [:fncall
@ -103,7 +112,12 @@
(simplify (nth p 1) context) (simplify (nth p 1) context)
(simplify (nth p 2) context)]] (simplify (nth p 2) context)]]
(map simplify p)) (map simplify p))
:mexpr (simplify (second p) :mexpr) :mexpr (if
(:strict *options*)
(throw
(ex-info "Cannot parse meta expressions in strict mode"
{:cause :strict}))
(simplify (second p) :mexpr))
:list (if :list (if
(= context :mexpr) (= context :mexpr)
[:fncall [:fncall
@ -115,7 +129,6 @@
p))) p)))
;; # From Lisp 1.5 Programmers Manual, page 10 ;; # From Lisp 1.5 Programmers Manual, page 10
;; Note that I've retyped much of this, since copy/pasting out of PDF is less ;; Note that I've retyped much of this, since copy/pasting out of PDF is less
;; than reliable. Any typos are mine. Quote starts [[ ;; than reliable. Any typos are mine. Quote starts [[

View file

@ -1,6 +1,7 @@
(ns beowulf.mexpr-test (ns beowulf.mexpr-test
(:require [clojure.test :refer :all] (:require [clojure.test :refer :all]
[beowulf.read :refer [parse simplify generate]])) [beowulf.bootstrap :refer [*options*]]
[beowulf.read :refer [parse simplify generate gsp]]))
;; These tests are taken generally from the examples on page 10 of ;; These tests are taken generally from the examples on page 10 of
;; Lisp 1.5 Programmers Manual: ;; Lisp 1.5 Programmers Manual:
@ -64,3 +65,10 @@
(parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))] (parse "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))]
(is (= actual expected))))) (is (= actual expected)))))
(deftest strict-tests
(testing "Strict feature"
(binding [*options* {:strict true}]
(is (thrown-with-msg?
Exception
#"Cannot parse meta expressions in strict mode"
(gsp "label[ff;λ[[x];[atom[x]->x; T->ff[car[x]]]]]"))))))

View file

@ -2,7 +2,8 @@
(:require [clojure.math.numeric-tower :refer [abs]] (:require [clojure.math.numeric-tower :refer [abs]]
[clojure.test :refer :all] [clojure.test :refer :all]
[beowulf.cons-cell :refer :all] [beowulf.cons-cell :refer :all]
[beowulf.read :refer [parse simplify generate]])) [beowulf.bootstrap :refer [*options*]]
[beowulf.read :refer [parse simplify generate gsp]]))
;; broadly, sexprs should be homoiconic ;; broadly, sexprs should be homoiconic
@ -24,6 +25,32 @@
actual (generate (simplify (parse (str expected))))] actual (generate (simplify (parse (str expected))))]
(is (= actual expected))))) (is (= actual expected)))))
(deftest comment-tests
(testing "Reading comments"
(let [expected 'A
actual (gsp "A ;; comment")]
(is (= actual expected)))
(let [expected 10
actual (gsp "10 ;; comment")]
(is (= actual expected)))
(let [expected 2/5
actual (gsp "4E-1 ;; comment")]
(is (= actual expected)))
(let [expected "(A B C)"
actual (print-str (gsp "(A ;; comment
B C)"))]
(is (= actual expected)
"Really important that comments work inside lists"))
;; ;; TODO: Currently failing and I'm not sure why
;; (binding [*options* {:strict true}]
;; (is (thrown-with-msg?
;; Exception
;; #"Cannot parse comments in strict mode"
;; (gsp "(A ;; comment
;; B C)"))))
))
(deftest number-tests (deftest number-tests
(testing "Reading octal numbers" (testing "Reading octal numbers"
(let [expected 1 (let [expected 1