;; Copyright (c) Russ Olsen, Nicola Mometto, Rich Hickey & contributors. ;; The use and distribution terms for this software are covered by the ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) ;; which can be found in the file epl-v10.html at the root of this distribution. ;; By using this software in any fashion, you are agreeing to be bound by ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. (ns cljs.tools.reader.impl.errors (:require [cljs.tools.reader.reader-types :as types] [clojure.string :as s] [cljs.tools.reader.impl.inspect :as i])) (defn- ex-details [rdr ex-type] (let [details {:type :reader-exception :ex-kind ex-type}] (if (types/indexing-reader? rdr) (assoc details :file (types/get-file-name rdr) :line (types/get-line-number rdr) :col (types/get-column-number rdr)) details))) (defn- throw-ex "Throw an ex-info error." [rdr ex-type & msg] (let [details (ex-details rdr ex-type) file (:file details) line (:line details) col (:col details) msg1 (if file (str file " ")) msg2 (if line (str "[line " line ", col " col "]")) msg3 (if (or msg1 msg2) " ") full-msg (apply str msg1 msg2 msg3 msg)] (throw (ex-info full-msg details)))) (defn reader-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :reader-error (apply str msgs))) (defn illegal-arg-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :illegal-argument (apply str msgs))) (defn eof-error "Throws an ExceptionInfo with the given message. If rdr is an IndexingReader, additional information about column and line number is provided" [rdr & msgs] (throw-ex rdr :eof (apply str msgs))) (defn throw-eof-delimited ([rdr kind column line] (throw-eof-delimited rdr kind line column nil)) ([rdr kind line column n] (eof-error rdr "Unexpected EOF while reading " (if n (str "item " n " of ")) (name kind) (if line (str ", starting at line " line " and column " column)) "."))) (defn throw-odd-map [rdr line col elements] (reader-error rdr "The map literal starting with " (i/inspect (first elements)) (if line (str " on line " line " column " col)) " contains " (count elements) " form(s). Map literals must contain an even number of forms.")) (defn throw-invalid-number [rdr token] (reader-error rdr "Invalid number: " token ".")) (defn throw-invalid-unicode-literal [rdr token] (throw (illegal-arg-error rdr "Invalid unicode literal: \\" token "."))) (defn throw-invalid-unicode-escape [rdr ch] (reader-error rdr "Invalid unicode escape: \\u" ch ".")) (defn throw-invalid [rdr kind token] (reader-error rdr "Invalid " (name kind) ": " token ".")) (defn throw-eof-at-start [rdr kind] (eof-error rdr "Unexpected EOF while reading start of " (name kind) ".")) (defn throw-bad-char [rdr kind ch] (reader-error rdr "Invalid character: " ch " found while reading " (name kind) ".")) (defn throw-eof-at-dispatch [rdr] (eof-error rdr "Unexpected EOF while reading dispatch character.")) (defn throw-bad-dispatch [rdr ch] (reader-error rdr "No dispatch macro for " ch ".")) (defn throw-unmatch-delimiter [rdr ch] (reader-error rdr "Unmatched delimiter " ch ".")) (defn throw-eof-reading [rdr kind & start] (let [init (case kind :regex "#\"" :string \")] (eof-error rdr "Unexpected EOF reading " (name kind) " starting " (apply str init start) "."))) (defn throw-no-dispatch [rdr ch] (throw-bad-dispatch rdr ch)) (defn throw-invalid-unicode-char[rdr token] (reader-error rdr "Invalid unicode character \\" token ".")) (defn throw-invalid-unicode-digit-in-token[rdr ch token] (illegal-arg-error rdr "Invalid digit " ch " in unicode character \\" token ".")) (defn throw-invalid-unicode-digit[rdr ch] (illegal-arg-error rdr "Invalid digit " ch " in unicode character.")) (defn throw-invalid-unicode-len[rdr actual expected] (illegal-arg-error rdr "Invalid unicode literal. Unicode literals should be " expected "characters long. " "value suppled is " actual "characters long.")) (defn throw-invalid-character-literal[rdr token] (reader-error rdr "Invalid character literal \\u" token ".")) (defn throw-invalid-octal-len[rdr token] (reader-error rdr "Invalid octal escape sequence in a character literal:" token ". Octal escape sequences must be 3 or fewer digits.")) (defn throw-bad-octal-number [rdr] (reader-error rdr "Octal escape sequence must be in range [0, 377].")) (defn throw-unsupported-character[rdr token] (reader-error rdr "Unsupported character: " token ".")) (defn throw-eof-in-character [rdr] (eof-error rdr "Unexpected EOF while reading character.")) (defn throw-bad-escape-char [rdr ch] (reader-error rdr "Unsupported escape character: \\" ch ".")) (defn throw-single-colon [rdr] (reader-error rdr "A single colon is not a valid keyword.")) (defn throw-bad-metadata [rdr x] (reader-error rdr "Metadata cannot be " (i/inspect x) ". Metadata must be a Symbol, Keyword, String or Map.")) (defn throw-bad-metadata-target [rdr target] (reader-error rdr "Metadata can not be applied to " (i/inspect target) ". " "Metadata can only be applied to IMetas.")) (defn throw-feature-not-keyword [rdr feature] (reader-error rdr "Feature cannot be " (i/inspect feature) " Features must be keywords.")) (defn throw-ns-map-no-map [rdr ns-name] (reader-error rdr "Namespaced map with namespace " ns-name " does not specify a map.")) (defn throw-bad-ns [rdr ns-name] (reader-error rdr "Invalid value used as namespace in namespaced map: " ns-name ".")) (defn throw-bad-reader-tag [rdr tag] (reader-error rdr "Invalid reader tag: " (i/inspect tag) ". Reader tags must be symbols.")) (defn throw-unknown-reader-tag [rdr tag] (reader-error rdr "No reader function for tag " (i/inspect tag) ".")) (defn- duplicate-keys-error [msg coll] (letfn [(duplicates [seq] (for [[id freq] (frequencies seq) :when (> freq 1)] id))] (let [dups (duplicates coll)] (apply str msg (when (> (count dups) 1) "s") ": " (interpose ", " dups))))) (defn throw-dup-keys [rdr kind ks] (reader-error rdr (duplicate-keys-error (str (s/capitalize (name kind)) " literal contains duplicate key") ks))) (defn throw-eof-error [rdr line] (if line (eof-error rdr "EOF while reading, starting at line " line ".") (eof-error rdr "EOF while reading.")))