package org.absmodels.abs.plugin.editor.reconciling;
import static org.absmodels.abs.plugin.util.Constants.PARSE_MARKER_TYPE;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collections;
import java.util.List;
import org.absmodels.abs.plugin.builder.AbsNature;
import org.absmodels.abs.plugin.editor.ABSEditor;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import abs.frontend.ast.CompilationUnit;
import abs.frontend.parser.Main;
import abs.frontend.parser.ParserError;
/**
* parses an Abs document when the user stops typing
* notifies the outline and updates error markers accordingly
*/
public class ABSReconcilingStrategy implements IReconcilingStrategy {
private IDocument document;
private ABSEditor editor;
private Main absParser;
public ABSReconcilingStrategy(ABSEditor editor) {
this.editor = editor;
editor.setReconciler(this);
absParser = new Main();
absParser.setAllowIncompleteExpr(true);
absParser.setTypeChecking(false);
}
@Override
public void setDocument(IDocument document) {
this.document = document;
}
@Override
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
reconcile();
}
@Override
public void reconcile(IRegion partition) {
reconcile();
}
private void reconcile() {
reconcile(editor.getAbsNature(), true);
}
public synchronized CompilationUnit reconcile(AbsNature nature, boolean withTypechecks) {
CompilationUnit compilationUnit = parseDocument();
if (nature == null) {
setParseErrorMarkers(compilationUnit.getParserErrors());
editor.onCompilationUnitChange(compilationUnit);
return compilationUnit;
}
if (compilationUnit.getParserErrors() == null) {
compilationUnit.setParserErrors(Collections.<ParserError>emptyList());
}
setParseErrorMarkers(compilationUnit.getParserErrors());
AbsModelManager manager = nature.getModelManager();
manager.updateModel(compilationUnit, withTypechecks);
editor.onCompilationUnitChange(manager.getCompilationUnit(editor.getAbsoluteFilePath()));
return compilationUnit;
}
private CompilationUnit parseDocument() {
String code = document.get();
CompilationUnit compilationUnit = parse(code);
if (compilationUnit == null || compilationUnit.getNumModuleDecl() + compilationUnit.getNumFeatureDecl() == 0) {
// if compilation was not successful, try inserting a semicolon
try {
// add semicolon to end of current line and try to parse again
int caretPos = editor.getCaretPos();
IRegion lineInfo = document.getLineInformationOfOffset(caretPos);
int endOfLine = lineInfo.getOffset() + lineInfo.getLength();
code = document.get(0, endOfLine) + ";" + document.get(endOfLine, document.getLength() - endOfLine);
System.out.println(code);
CompilationUnit compilationUnit2 = parse(code);
if (compilationUnit2 != null && compilationUnit2.getNumModuleDecl() + compilationUnit2.getNumFeatureDecl() > 0) {
// compilationUnit2 has better results, so use it
compilationUnit = compilationUnit2;
}
} catch (BadLocationException e) {
e.printStackTrace();
}
}
return compilationUnit;
}
private void setParseErrorMarkers(List<ParserError> parserErrors) {
IResource r = editor.getResource();
try {
r.deleteMarkers(PARSE_MARKER_TYPE, true, IResource.DEPTH_ZERO);
for (ParserError err : parserErrors) {
AbsNature.addMarker(r, err);
}
} catch (CoreException e) {
e.printStackTrace();
}
}
private CompilationUnit parse(String code) {
try {
return absParser.parseUnit(editor.getFile(), code, new StringReader(code));
} catch (IOException e) {
return new CompilationUnit();
}
}
}