|
5 | 5 | (java.util.concurrent ConcurrentHashMap) |
6 | 6 | (org.antlr.v4.runtime ANTLRErrorListener |
7 | 7 | CharStreams CommonTokenStream Lexer Parser |
8 | | - RecognitionException) |
| 8 | + ParserRuleContext RecognitionException Token) |
9 | 9 | (org.antlr.v4.runtime.tree ParseTree Tree))) |
10 | 10 |
|
11 | 11 | (def ^ConcurrentHashMap fast-keyword-cache |
|
132 | 132 | (.removeErrorListeners) |
133 | 133 | (.addErrorListener error-listener)) |
134 | 134 |
|
135 | | - parser (parser ap (CommonTokenStream. lexer)) |
| 135 | + token-stream (CommonTokenStream. lexer) |
| 136 | + parser (parser ap token-stream) |
136 | 137 | _ (doto parser |
137 | 138 | (.removeErrorListeners) |
138 | 139 | (.addErrorListener error-listener)) |
|
142 | 143 | (when-let [errors @error-listener] |
143 | 144 | (throw (parse-error errors tree))) |
144 | 145 |
|
| 146 | + ;; ANTLR's error recovery can silently produce a valid parse tree even when |
| 147 | + ;; there are unconsumed tokens (e.g. unbalanced braces). Detect this case by |
| 148 | + ;; checking that every non-EOF token was consumed by the document rule. |
| 149 | + (.fill token-stream) |
| 150 | + (let [tokens (.getTokens token-stream) |
| 151 | + n (count tokens) |
| 152 | + ;; tokens is [...real-tokens... EOF]; last-real-idx is the index of the |
| 153 | + ;; last non-EOF token (n-2), or -1 when the input is empty. |
| 154 | + last-real-idx (- n 2) |
| 155 | + stop-token (.getStop ^ParserRuleContext tree) |
| 156 | + stop-idx (if stop-token (.getTokenIndex ^Token stop-token) -1)] |
| 157 | + (when (< stop-idx last-real-idx) |
| 158 | + (let [first-unconsumed (.get token-stream (inc stop-idx)) |
| 159 | + line (.getLine ^Token first-unconsumed) |
| 160 | + col (inc (.getCharPositionInLine ^Token first-unconsumed))] |
| 161 | + (throw (parse-error [{:line line |
| 162 | + :char col |
| 163 | + :message (str "extraneous input '" |
| 164 | + (.getText ^Token first-unconsumed) |
| 165 | + "' expecting EOF")}] |
| 166 | + tree))))) |
| 167 | + |
145 | 168 | {:tree tree |
146 | 169 | :parser parser})) |
0 commit comments