Commit aa0bd9f6 authored by Johannes Roith's avatar Johannes Roith

Implement LocationPatcher. This fixes most of the problems with the editor.

parent 86c008d2
......@@ -665,7 +665,7 @@ terminal_list ::= terminal_list:lst COMMA terminal_id:trm
{:
Range range = new Range(Position.fromLocation(trmxleft),
Position.fromLocation(trmxright));
((List<Terminal>) lst).add(new Terminal(new Name (trm, range), range));
((List<Terminal>) lst).add(new Terminal(new Name (trm, range), (Range) range.clone()));
RESULT = lst;
:}
|
......@@ -674,7 +674,7 @@ terminal_list ::= terminal_list:lst COMMA terminal_id:trm
Range range = new Range(Position.fromLocation(trmxleft),
Position.fromLocation(trmxright));
List<Terminal> lst = new ArrayList<Terminal>();
lst.add(new Terminal(new Name (trm, range), range));
lst.add(new Terminal(new Name (trm, range), (Range) range.clone()));
RESULT = lst;
:}
;
......@@ -735,7 +735,7 @@ start_spec ::=
Range innerRange = new Range(Position.fromLocation(start_namexleft),
Position.fromLocation(start_namexright));
parserResult.startWith = new StartWith(new NonTerminal (
new Name (start_name, innerRange), innerRange), range);
new Name (start_name, innerRange), (Range) innerRange.clone()), range);
}
:}
|
......@@ -951,9 +951,9 @@ prod_part ::=
Range range = new Range (Position.fromLocation(symidxleft),
Position.fromLocation(symidxright));
if (labid == null)
ref = new ProductionSymbolRef(new Name(symid, range), range);
ref = new ProductionSymbolRef(new Name(symid, range), (Range) range.clone());
else
ref = new LabeledProductionSymbolRef(new Name(symid, range), labid, range);
ref = new LabeledProductionSymbolRef(new Name(symid, range), labid, (Range) range.clone());
ast_add_rhs_part(ref);
}
:}
......@@ -1071,7 +1071,7 @@ new_term_id ::=
Range range = new Range(Position.fromLocation(term_idxleft),
Position.fromLocation(term_idxright));
RESULT = new Terminal(new Name(term_id, range), range);
RESULT = new Terminal(new Name(term_id, range), (Range) range.clone());
}
:}
......@@ -1108,7 +1108,7 @@ new_non_term_id ::=
// jrTODO: non_term_id vs. multipart_name
Range range = new Range(Position.fromLocation(non_term_idxleft),
Position.fromLocation(non_term_idxright));
RESULT = new NonTerminal(new Name(non_term_id, range), range);
RESULT = new NonTerminal(new Name(non_term_id, range), (Range) range.clone());
}
:}
;
......
......@@ -25,12 +25,6 @@ class Demo
// System.out.println(res);
System.out.println("\nLocationPatchVisitor:");
long ms = System.currentTimeMillis();
LocationPatchVisitor locVisitor = new LocationPatchVisitor(new Position(0,0,0), 0, 0);
res.accept(locVisitor, null);
System.out.println("millis: " + (System.currentTimeMillis() - ms));
System.out.println("\nDeclarationVisitor:");
Declarations oldDecl = null;
......
......@@ -11,12 +11,23 @@ public class Position {
public int getLine() { return line; }
public int getColumn() { return column; }
public int getOffsetFromStart() { return offsetFromStart; }
public void move(int diffLines, int diffColumns, int diffOffset) {
this.line += diffLines;
this.column += diffColumns;
this.offsetFromStart += diffOffset;
}
public Position(int line, int column, int offsetFromStart) {
this.line = line;
this.column = column;
this.offsetFromStart = offsetFromStart;
}
@Override
public Object clone() {
return new Position(line, column, offsetFromStart);
}
@Override
public String toString() {
......@@ -24,6 +35,8 @@ public class Position {
builder.append(line);
builder.append("/");
builder.append(column);
builder.append("/");
builder.append(offsetFromStart);
return builder.toString();
}
......@@ -35,6 +48,10 @@ public class Position {
builder.append(column);
return builder.toString();
}
public static Position fromOffset(int offset) {
return new Position(-1, -1, offset);
}
public static Position fromLocation(Location loc) {
return new Position(loc.getLine(),
......
......@@ -13,11 +13,29 @@ public class Range {
public Position getEnd() {
return end;
}
public int getLength() {
if (begin == null
|| end == null
|| begin.getOffsetFromStart() < 0
|| end.getOffsetFromStart() < 0)
{
return 0;
}
return end.getOffsetFromStart() - begin.getOffsetFromStart();
}
public Range(Position begin, Position end) {
this.begin = begin;
this.end = end;
}
@Override
public Object clone() {
return new Range(
(begin != null) ? (Position) begin.clone() : null,
(end != null) ? (Position) end.clone() : null);
}
public boolean contains(Position pos) {
return contains(pos, 0);
......@@ -26,26 +44,36 @@ public class Range {
public boolean contains(Position pos, int removedLength) {
if (pos == null || begin == null || end == null)
return false;
if (pos.getLine() >= begin.getLine() && pos.getLine() <= end.getLine()) {
if (pos.getLine() == begin.getLine()
&& pos.getColumn() < begin.getColumn())
return false;
// we are certainly past the start.
if (pos.getLine() < 0 || pos.getColumn() < 0) {
// do an offset-based comparison.
if (pos.getOffsetFromStart() >= begin.getOffsetFromStart() &&
pos.getOffsetFromStart() <= end.getOffsetFromStart())
return true;
return false;
} else {
// do a line-based comparison.
if (pos.getLine() >= begin.getLine() && pos.getLine() <= end.getLine()) {
if (pos.getLine() == begin.getLine()
&& pos.getColumn() < begin.getColumn())
return false;
// we are certainly past the start.
if (pos.getLine() == end.getLine()
&& pos.getColumn() > end.getColumn())
return false;
// we are certainly not past the end.
if (pos.getLine() == end.getLine()
&& pos.getColumn() > end.getColumn())
return false;
// we are certainly not past the end.
if (removedLength == 0) {
return true;
} else {
throw new RuntimeException("not implemented!");
// TODO: we really should check, that the amount of code
// remove is not too much.
// return true;
if (removedLength == 0) {
return true;
} else {
throw new RuntimeException("not implemented!");
// TODO: we really should check, that the amount of code
// remove is not too much.
// return true;
}
}
}
return false;
......
......@@ -4,7 +4,7 @@ import de.in.tum.www2.cup.Position;
import de.in.tum.www2.cup.Range;
import de.in.tum.www2.cup.ast.*;
public class FindAtPositionVisitor extends Visitor<Object>
public class FindAtPositionVisitor extends WildcardVisitor<Object>
{
private AbstractNode result;
private Position pos;
......@@ -20,36 +20,43 @@ public class FindAtPositionVisitor extends Visitor<Object>
this.pos = pos;
}
// TODO: does not work for all elements, yet ...
private void updateIfMatch(AbstractNode node) {
Range range = node.getRange();
if (range == null)
private void updateIfNewAndMatch(AbstractNode node) {
if (result != null || node == null || node.getRange() == null)
return;
if (range.contains(pos)) {
if (node.getRange().contains(pos))
result = node;
}
}
/*
@Override
public void postVisit (ActionCodeBlock node, Object data) {
if (node == null)
return;
updateIfMatch(node);
updateIfNewAndMatch(node);
}
@Override
public void postVisit (SpecialCodeBlock node, Object data) {
if (node == null)
return;
updateIfMatch(node);
updateIfNewAndMatch(node);
}
@Override
public void postVisit (Name node, Object data) {
if (node == null)
return;
updateIfMatch(node);
updateIfNewAndMatch(node);
}
*/
@Override
public Object preVisitWildcard(AbstractNode node, Object data) {
return null;
}
@Override
public void postVisitWildcard(AbstractNode node, Object data) {
updateIfNewAndMatch(node);
}
}
......@@ -5,68 +5,38 @@ import de.in.tum.www2.cup.ast.*;
public class LocationPatchVisitor extends WildcardVisitor<Object>
{
private boolean foundLocation;
private Position oldRemovedFrom;
private int oldRemovedLength;
private int newLength;
// TODO: in case we are already past the position, we could really
// cancel early, if the pattern would support it.
private int fixAfterOffset;
private int diffLines;
private int diffColumns;
private int diffOffset;
public LocationPatchVisitor(int fixAfterOffset,
int diffLines, int diffColumns, int diffOffset) {
this.fixAfterOffset = fixAfterOffset;
this.diffLines = diffLines;
this.diffColumns = diffColumns;
this.diffOffset = diffOffset;
}
// TODO: this still can't deal with new/removed lines!
public LocationPatchVisitor(Position oldRemovedFrom, int oldRemovedLength, int newLength) {
this.oldRemovedFrom = oldRemovedFrom;
this.oldRemovedLength = oldRemovedLength;
this.newLength = newLength;
private void fixPosition(String comment, AbstractNode node, Position pos) {
if (pos != null && pos.getOffsetFromStart() > fixAfterOffset) {
System.out.print("fixing " + comment + "..." + node.getClass().getName() + " from " + pos);
pos.move(diffLines, diffColumns, diffOffset);
System.out.println(" to " + pos);
}
}
@Override
public Object preVisitWildcard(AbstractNode node, Object data) {
if (foundLocation) {
// we are now processing an object that comes after the patch point.
}
return data;
}
@Override
public void postVisitWildcard(AbstractNode node, Object data) {
}
// TODO: first, assume there is no new line.
// TODO: for special nodes:
// - check if the edited location falls within the correct part of the range.
// - if so: check if the edit completes a close-symbol.
// - if not: perform the edit and update the end-range(s).
// - set a flag, so all future visited nodes push their locations forward,
// if they are on the same line.
@Override
public void postVisit (ActionCodeBlock node, Object data) {
if (!foundLocation) {
// try to detect, we the edit happens in here.
// TODO: ensure the range is the correct one!
}
}
@Override
public void postVisit (SpecialCodeBlock node, Object data) {
if (!foundLocation) {
if (node.getRange().contains(oldRemovedFrom, oldRemovedLength)) {
// we found our change point.
foundLocation = true;
// now, let's patch our own object, first.
// -> update string.
// -> update all locations.
// next, all objects visited from here must be patched.
}
if (node != null) {
fixPosition("begin", node, node.getBegin());
fixPosition("end", node, node.getEnd());
}
}
}
package de.tum.in.www2.cupplugin.controller;
import java.awt.Event;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
......@@ -10,6 +12,7 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITypedRegion;
......@@ -108,11 +111,13 @@ public class DocumentDidChangeJob extends Job {
jobs.remove(JobsToDo.locationPatch);
}
if (jobs.contains(JobsToDo.locationPatch)) {
LocationPatchJob locPatch = new LocationPatchJob();
// TODO: the location patcher need to always run, even when only comments or
// new lines were edited.
// if (jobs.contains(JobsToDo.locationPatch)) {
LocationPatchJob locPatch = new LocationPatchJob(documentEvents);
locPatch.setSystem(true);
locPatch.schedule();
}
// }
IFile file = ((FileEditorInput) myEditor.getEditorInput()).getFile();
CupEditorErrorReporter errorReporter = new CupEditorErrorReporter(file);
......@@ -132,10 +137,7 @@ public class DocumentDidChangeJob extends Job {
e.printStackTrace();
}
// errorReporter.pushToUIThread();
// TODO
// errorReporter.pushToUIThread();
errorReporter.pushToUIThread();
if (result != null) {
// System.out.println(result.toString());
......@@ -174,7 +176,7 @@ public class DocumentDidChangeJob extends Job {
// errorReporter.pushToUIThread();
if (lalrResult != null) {
LaLrResultJob resultLaLrModelJob = new LaLrResultJob(
LaLrResultJob resultLaLrModelJob = new LaLrResultJob(myEditor,
lalrResult, revNumber, context);
resultLaLrModelJob.setSystem(true);
resultLaLrModelJob.schedule();
......@@ -188,6 +190,9 @@ public class DocumentDidChangeJob extends Job {
return Status.CANCEL_STATUS;
}
}
errorReporter.pushToUIThread();
System.out.println(jobs);
......@@ -203,7 +208,7 @@ public class DocumentDidChangeJob extends Job {
return Status.OK_STATUS;
}
class CallbackJob extends UIJob {
static class CallbackJob extends UIJob {
CupTextEditor myEditor = null;
public CallbackJob(CupTextEditor editor) {
......@@ -246,48 +251,53 @@ public class DocumentDidChangeJob extends Job {
}
}
class LaLrResultJob extends UIJob {
LALRResult lalrResult;
long lalrResulRevisionNumber;
CupContext lalrContext;
public LaLrResultJob(LALRResult result, long revisionNumber,
CupContext context) {
super("LaLr Result UI Job");
this.lalrResult = result;
this.lalrResulRevisionNumber = revisionNumber;
this.lalrContext = context;
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
IDocumentProvider provider = myEditor.getDocumentProvider();
if (provider != null) {
IDocument document = provider.getDocument(myEditor
.getEditorInput());
if (document != null) {
Model model = Model.getInstanceForDocument(document);
model.setLaLrResultModel(this.lalrResult,
lalrResulRevisionNumber, lalrContext);
return Status.OK_STATUS;
}
}
return Status.CANCEL_STATUS;
}
}
class LocationPatchJob extends UIJob {
public LocationPatchJob() {
private List<DocumentEvent> documentEvents;
// TODO: can we be sure that we are the only one accessing the documentEvents list?
public LocationPatchJob(List<DocumentEvent> documentEvents) {
super("Location Patch Job");
this.documentEvents = new ArrayList<DocumentEvent> (documentEvents);
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
/*
System.out.println("RUNNING LocationPatchJob: ");
// TODO: combine consecutive 1-character insert events.
for (DocumentEvent event : documentEvents) {
System.out.println("PROCESSING DocumentEvent: ");
System.out.println(" Offset: " + event.getOffset());
System.out.println(" Replaced: " + event.getLength());
System.out.println(" New: " + event.getText().length());
IDocument document = event.getDocument();
try {
int offset = event.getOffset();
int startLineNumber = document.getLineOfOffset(offset);
// TODO: wrong! must take removed text into account.
int startColumn = offset - document.getLineOffset(event.getText().length());
Position start = new Position(startLineNumber+1, startColumn+1, offset+1);
// updating the offsets is easy
// how do we update the lines correctly?
// how do we find out how many lines have been removed?
} catch (BadLocationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// event.getDocument().
}
// TODO: location Patch verifizieren
Position oldRemovedFrom = null;
int oldRemovedLength = 0;
......@@ -299,6 +309,8 @@ public class DocumentDidChangeJob extends Job {
else {
System.out.println("ERROR: Can't run LocationPatchVisitor!");
}
*/
return Status.OK_STATUS;
}
......
......@@ -127,8 +127,7 @@ public class Debugger {
*/
public int getNextCodeBlockForLineBreakpoint(int line) {
Model m = Model.getInstanceForDocument(myEditor.getDocumentProvider()
.getDocument(myEditor.getEditorInput()));
Model m = Model.getInstanceForDocument(myEditor.getDocument());
ParserResult astModel = m.getAstModel();
if (astModel == null)
return line;
......
package de.tum.in.www2.cupplugin.editors;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import de.in.tum.www2.cup.ast.Name;
import de.in.tum.www2.cup.Position;
import de.in.tum.www2.cup.analysis.LocationPatchVisitor;
import de.in.tum.www2.cup.ast.ParserResult;
import de.tum.in.www2.cupplugin.controller.Controller;
import de.tum.in.www2.cupplugin.model.Model;
import de.tum.in.www2.cupplugin.GeneratedFileLocator;
import de.tum.in.www2.cupplugin.PluginUtility;
class CTEDocumentListener implements IDocumentListener {
private IFile file;
private GeneratedFileLocator gfl;
public CTEDocumentListener(IFile file) {
this.file = file;
gfl = new GeneratedFileLocator();
// TODO: remove !!!
System.out.println("Checking for matching generated file: ");
IFile generated = PluginUtility.findGenerated(file);
if (generated != null) {
System.out.println("found matching file!");
System.out.println(generated);
try {
// TODO: only delete the markers we have set ourselves!
IMarker[] oldMarkers = generated.findMarkers("org.eclipse.debug.core.breakpointMarker", false, 10);
for (IMarker m : oldMarkers)
m.delete();
IMarker marker = generated.createMarker("org.eclipse.debug.core.breakpointMarker");
marker.setAttribute(IMarker.LINE_NUMBER, 10);
} catch (CoreException e) {
e.printStackTrace();
}
} else {
System.out.println("did not find matching file!");
}
public CTEDocumentListener() {
}
private int linesRemoved = 0;
private int removedLastLineColumns = 0;
public void documentAboutToBeChanged(DocumentEvent event) {
IDocument document = event.getDocument();
try {
int offset = event.getOffset();
int startLineNumber = document.getLineOfOffset(offset);
int endOffset = offset + event.getLength();
int endLineNumber = document.getLineOfOffset(endOffset);
linesRemoved = endLineNumber - startLineNumber;
removedLastLineColumns = endOffset
- document.getLineOffset(endLineNumber);
} catch (BadLocationException e) {
e.printStackTrace();
}
return;
}
private void patchModel(DocumentEvent event) {
IDocument document = event.getDocument();
Model model = Model.getInstanceForDocument(document);
if (model == null)
return;
ParserResult ast = model.getAstModel();
if (ast == null)
return;
int offset = event.getOffset();
int linesAdded = 0;
int addedLastLineColumns = 0;
try {
int startLineNumber = document.getLineOfOffset(offset);
int endOffset = offset + event.getText().length();
int endLineNumber = document.getLineOfOffset(endOffset);
addedLastLineColumns = endOffset
- document.getLineOffset(endLineNumber);
linesAdded = endLineNumber - startLineNumber;
System.out.println("PROCESSING DocumentEvent: ");
System.out.println(" Offset: " + offset);
System.out.println(" Replaced: " + event.getLength());
System.out.println(" New: " + event.getText().length());
System.out.println(" linesRemoved: " + linesRemoved);
System.out.println(" linesAdded: " + linesAdded);
} catch (BadLocationException e) {
e.printStackTrace();
}
// NOTE: we do not try to fix the replaced part.
int fixAfterOffset = offset + event.getLength();
int diffOffset = event.getText().length() - event.getLength();
int diffLines = linesAdded - linesRemoved;
int diffColumns = addedLastLineColumns - removedLastLineColumns;
System.out.println(" fixAfterOffset: " + fixAfterOffset);
System.out.println(" diffOffset: " + diffOffset);
System.out.println(" diffLines: " + diffLines);
System.out.println(" diffColumns: " + diffColumns);
LocationPatchVisitor visitor = new LocationPatchVisitor(fixAfterOffset,
diffLines, diffColumns, diffOffset);
ast.accept(visitor, null);
}
public void documentChanged(DocumentEvent event) {
patchModel(event);
IDocument doc = event.getDocument();
ParserResult result = Model.getInstanceForDocument(doc).getAstModel();
IFile generated = gfl.find(file, result);
if (generated == null)
System.out.println("could not find generated file!");
else
System.out.println("generated: " + generated.getName());
//System.out.println("starting job chain"); // Log message TODO: DELETE!
Controller controller = Controller.getInstance(doc);
// System.out.println("starting job chain"); // Log message TODO:
// DELETE!
Controller controller = Controller.getInstance(event.getDocument());
controller.notifyChange(event);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment