66 lines
2.8 KiB
Clojure
66 lines
2.8 KiB
Clojure
(ns ^{:doc "Display parse errors in a format which makes it easy for the user
|
|
to see where the error occurred."
|
|
:author "Simon Brooke"}
|
|
mw-parser.errors)
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;
|
|
;; This program is free software; you can redistribute it and/or
|
|
;; modify it under the terms of the GNU General Public License
|
|
;; as published by the Free Software Foundation; either version 2
|
|
;; of the License, or (at your option) any later version.
|
|
;;
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
;;
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program; if not, write to the Free Software
|
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
;; USA.
|
|
;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
;; error thrown when an attempt is made to set a reserved property
|
|
(def reserved-properties-error
|
|
"The properties 'x' and 'y' of a cell are reserved and should not be set in rule actions")
|
|
;; error thrown when a rule cannot be parsed. Slots are for
|
|
;; (1) rule text
|
|
;; (2) cursor showing where in the rule text the error occurred
|
|
;; (3) the reason for the error
|
|
(def bad-parse-error "I did not understand:\n '%s'\n %s\n %s")
|
|
|
|
(defn- explain-parse-error-reason
|
|
"Attempt to explain the reason for the parse error."
|
|
[reason]
|
|
(str "Expecting one of (" (apply str (map #(str (:expecting %) " ") reason)) ")"))
|
|
|
|
(defn- parser-error-to-map
|
|
[parser-error]
|
|
(let [m (reduce (fn [map item](merge map {(first item)(second item)})) {} parser-error)
|
|
reason (map
|
|
#(reduce (fn [map item] (merge {(first item) (second item)} map)) {} %)
|
|
(:reason m))]
|
|
(merge m {:reason reason})))
|
|
|
|
(defn throw-parse-exception
|
|
"Construct a helpful error message from this `parser-error`, and throw an exception with that message."
|
|
[parser-error]
|
|
(assert (coll? parser-error) "Expected a paser error structure?")
|
|
(let
|
|
[
|
|
;; the error structure is a list, such that each element is a list of two items, and
|
|
;; the first element in each sublist is a keyword. Easier to work with it as a map
|
|
error-map (parser-error-to-map parser-error)
|
|
text (:text error-map)
|
|
reason (explain-parse-error-reason (:reason error-map))
|
|
;; rules have only one line, by definition; we're interested in the column
|
|
column (if (:column error-map)(:column error-map) 0)
|
|
;; create a cursor to point to that column
|
|
cursor (apply str (reverse (conj (repeat column " ") "^")))
|
|
message (format bad-parse-error text cursor reason)
|
|
]
|
|
(throw (Exception. message))))
|