/* * Copyright 2009-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.groovy.antlr; import groovyjarjarantlr.RecognitionException; import groovyjarjarantlr.TokenStreamException; import groovyjarjarantlr.TokenStreamIOException; import groovyjarjarantlr.TokenStreamRecognitionException; import java.io.Reader; import java.util.Collections; import java.util.List; import java.util.Map; import org.codehaus.groovy.antlr.parser.GroovyLexer; import org.codehaus.groovy.antlr.parser.GroovyRecognizer; import org.codehaus.groovy.control.CompilationFailedException; import org.codehaus.groovy.control.SourceUnit; import org.codehaus.groovy.syntax.SyntaxException; /** * Parser plugin using grammar which has error recovery enabled/implemented in * select places. * * @author empovazan */ public class ErrorRecoveredCSTParserPlugin extends AntlrParserPlugin { private final ICSTReporter reporter; ErrorRecoveredCSTParserPlugin(ICSTReporter reporter) { this.reporter = reporter; } @Override public void transformCSTIntoAST(final SourceUnit sourceUnit, Reader reader, SourceBuffer sourceBuffer) throws CompilationFailedException { super.ast = null; setController(sourceUnit); // GRECLIPSE-805 Support for unicode escape sequences UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader, sourceBuffer); GroovyLexer lexer = new GroovyLexer(new UnicodeLexerSharedInputState(unicodeReader)); unicodeReader.setLexer(lexer); GroovyRecognizer parser = GroovyRecognizer.make(lexer); parser.setSourceBuffer(sourceBuffer); super.tokenNames = parser.getTokenNames(); parser.setFilename(sourceUnit.getName()); // start parsing at the compilationUnit rule try { parser.compilationUnit(); configureLocationSupport(sourceBuffer); } catch (TokenStreamRecognitionException tsre) { configureLocationSupport(sourceBuffer); RecognitionException e = tsre.recog; SyntaxException se = new SyntaxException(e.getMessage(), e, e.getLine(), e.getColumn()); se.setFatal(true); sourceUnit.addError(se); } catch (RecognitionException e) { configureLocationSupport(sourceBuffer); // sometimes the line/column is after the end of the file // why is this? Fix if possible int origLine = e.getLine(); int origColumn = e.getColumn(); int[] newInts = fixLineColumn(origLine, origColumn); int newLine = newInts[0]; int newColumn = newInts[1]; SyntaxException se = new SyntaxException(e.getMessage(), e, newLine, newColumn); se.setFatal(true); sourceUnit.addError(se); } catch (TokenStreamException e) { configureLocationSupport(sourceBuffer); boolean handled = false; if (e instanceof TokenStreamIOException) { // GRECLIPSE-896: "Did not find four digit hex character code. line: 1 col:7" String m = e.getMessage(); if (m != null && m.startsWith("Did not find four digit hex character code.")) { try { int linepos = m.indexOf("line:"); int colpos = m.indexOf("col:"); int line = Integer.valueOf(m.substring(linepos + 5, colpos).trim()); int col = Integer.valueOf(m.substring(colpos + 4).trim()); SyntaxException se = new SyntaxException(e.getMessage(), e, line, col); se.setFatal(true); sourceUnit.addError(se); handled = true; } catch (Throwable t) { System.err.println(m); t.printStackTrace(); } } } if (!handled) { sourceUnit.addException(e); } } super.ast = parser.getAST(); sourceUnit.setComments(parser.getComments()); reportCST(sourceUnit, parser); } private void reportCST(final SourceUnit sourceUnit, final GroovyRecognizer parser) { final List errorList = parser.getErrorList(); final GroovySourceAST cst = (GroovySourceAST) parser.getAST(); if (reporter != null) { if (cst != null) reporter.generatedCST(sourceUnit.getName(), cst); if (errorList.size() != 0) // Unmodifiable necessary? reporter.reportErrors(sourceUnit.getName(), Collections.unmodifiableList(errorList)); } else { // report directly on the SourceUnit for (Map<String, Object> error : (List<Map<String, Object>>) errorList) { // sometimes the line/column is after the end of the file // why is this? Fix if possible int origLine = ((Integer) error.get("line")).intValue(); int origColumn = ((Integer) error.get("column")).intValue(); int[] newInts = fixLineColumn(origLine, origColumn); int newLine = newInts[0]; int newColumn = newInts[1]; SyntaxException se = new SyntaxException((String) error.get("error"), newLine, newColumn); sourceUnit.addError(se); } } } /* * Fix the column so that it is not past the end of the file */ private int[] fixLineColumn(int origLine, int origColumn) { if (locations.isPopulated()) { int offset = locations.findOffset(origLine, origColumn); if (offset >= locations.getEnd() - 1) { return locations.getRowCol(locations.getEnd() - 1); } } return new int[] {origLine, origColumn}; } }