Commit 7468ae5a authored by Johannes Roith's avatar Johannes Roith

- Add debugger matching code.

- Add first parts of "Rename Symbol" feature
- Add some helpers.
parent f55bfdad
......@@ -17,6 +17,7 @@ local.properties
# generated files
CupParser/src/de/in/tum/www2/cup/internal/Lexer.java
CupParser/src/de/in/tum/www2/cup/internal/Parser.java
CupParser/src/de/in/tum/www2/cup/internal/sym.java
# External tool builders
.externalToolBuilders/
......
......@@ -211,6 +211,18 @@ action code {:
parserResult.precedences.add(p);
}
private boolean WITH_DEBUGGING_SYMBOLS = true;
private int cur_debug_id = 0;
public int get_new_debug_id() {
return cur_debug_id++;
}
public String attach_debug_symbol(int id, String code) {
if (!WITH_DEBUGGING_SYMBOLS)
return code;
return "//@@CUPBDG" + id + "\n" + code;
}
:};
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
......@@ -727,8 +739,10 @@ start_spec ::=
add_rhs_part(add_lab(new symbol_part(start_nt), "start_val"));
add_rhs_part(new symbol_part(terminal_shared.getEOF()));
if (!context.getXmlActions()) add_rhs_part(new action_part("RESULT = start_val;"));
context.start_production =
new production(context, non_terminal_shared.getSTART_nt(), rhs_parts, rhs_pos);
production p = new production(context, non_terminal_shared.getSTART_nt(), rhs_parts, rhs_pos);
//p.index();
context.start_production = p;
new_rhs();
//jrTODO: position, start symbol?, side effects?
......@@ -845,6 +859,8 @@ rhs ::=
p = new production(context, lhs_nt, rhs_parts, rhs_pos);
}
// p.index();
/* if we have no start non-terminal declared and this is
the first production, make its lhs nt the start_nt
and build a special start production for it. */
......@@ -890,8 +906,10 @@ rhs ::=
/* build the production */
production p = new production(context, lhs_nt, rhs_parts, rhs_pos);
RESULT = new ProductionRight(ast_get_rhs_parts_copy(),
Range.fromLocations(pplxleft, pplxright));
RESULT = new ProductionRight(p.index(),
p.get_embedded_actions(),
ast_get_rhs_parts_copy(),
Range.fromLocations(pplxleft, pplxright));
/* if we have no start non-terminal declared and this is
......@@ -960,8 +978,10 @@ prod_part ::=
CODE_STRING : code_str
{:
/* add a new production part */
add_rhs_part(new action_part(code_str));
ast_add_rhs_part(new ActionCodeBlock(code_str,
int debug_id = get_new_debug_id();
add_rhs_part(new action_part(attach_debug_symbol(debug_id, code_str)));
ast_add_rhs_part(new ActionCodeBlock(debug_id, code_str,
Range.fromLocations(code_strxleft, code_strxright)
)); // jrTODO: positions
:}
......
......@@ -17,13 +17,10 @@ public class FindNextCodeBlockLineVisitor extends Visitor<Object>
}
private void doCheck(AbstractNode node) {
if (node == null)
return;
int blockLine = node.getBegin().getLine();
if (result != -1)
if (node == null || result != -1)
return;
int blockLine = node.getBegin().getLine();
if (line >= blockLine && line <= node.getEnd().getLine()) {
result = line;
return;
......
package de.in.tum.www2.cup.analysis;
import java.util.List;
import de.in.tum.www2.cup.Position;
import de.in.tum.www2.cup.Range;
import de.in.tum.www2.cup.ast.*;
public class GetDebuggerMappingVisitor extends Visitor<Object>
{
class Mapping {
public int caseIndex;
}
private int[] lines;
private List<Mapping> mappings;
public List<Mapping> getMappings() {
return mappings;
}
public GetDebuggerMappingVisitor(int[] lines) {
this.lines = lines;
}
// TODO: - find matching action block.
// - get parent (ProductionRight) node
// - return case label hint.
}
......@@ -6,9 +6,15 @@ import de.in.tum.www2.cup.analysis.AbstractVisitor;
public class ActionCodeBlock extends CodeBlock
implements IProductionRightPart
{
private int debugId;
public int getDebugId() {
return debugId;
}
public ActionCodeBlock(String blob, Range range) {
public ActionCodeBlock(int debugId, String blob, Range range) {
super(blob, range);
this.debugId = debugId;
}
@Override
......
......@@ -2,10 +2,12 @@ package de.in.tum.www2.cup.ast;
import java.util.*;
import de.in.tum.www2.cup.CupContext;
import de.in.tum.www2.cup.Declarations;
import de.in.tum.www2.cup.analysis.AbstractVisitor;
import de.in.tum.www2.cup.analysis.DeclarationsExtractorVisitor;
import de.in.tum.www2.cup.analysis.RefResolutionVisitor;
import de.in.tum.www2.cup.internal.production;
public class ParserResult extends AbstractNode {
......@@ -47,7 +49,11 @@ public class ParserResult extends AbstractNode {
RefResolutionVisitor resRefVisitor = new RefResolutionVisitor();
this.accept(resRefVisitor, null);
}
public ProductionRight getMatchingProductonRight(CupContext context, production p) {
throw new RuntimeException("not yet implemented.");
}
@Override
public <T> void accept(AbstractVisitor<T> visitor, T data) {
T childArg = visitor.preVisit(this, data);
......
......@@ -3,18 +3,46 @@ package de.in.tum.www2.cup.ast;
import java.util.List;
import de.in.tum.www2.cup.analysis.AbstractVisitor;
import de.in.tum.www2.cup.internal.production;
import de.in.tum.www2.cup.CupContext;
import de.in.tum.www2.cup.Range;
public class ProductionRight extends AbstractNode {
private List<IProductionRightPart> lst;
private int index;
private List<Integer> extractedActionProductions;
public List<IProductionRightPart> getList() {
return lst;
}
public ProductionRight(List<IProductionRightPart> lst, Range range) {
// We store the index that is used by the (lowercase)
// production class to identify productions.
// This should allow us to match productions and also
// for dealing with the generated debugger code.
public int getIndex() {
return index;
}
public List<Integer> getExtractedActionProductions() {
return extractedActionProductions;
}
public boolean wasEmbeddedActionMoved() {
return extractedActionProductions != null;
}
public production getMatchingInternal(CupContext context, int index) {
return production.getShared(context).find(index);
}
public ProductionRight(int index,
List<Integer> extractedActionProductions,
List<IProductionRightPart> lst, Range range) {
super(range);
this.index = index;
this.extractedActionProductions = extractedActionProductions;
this.lst = lst;
if (lst != null) {
for (IProductionRightPart prp : lst)
......@@ -62,6 +90,17 @@ public class ProductionRight extends AbstractNode {
@Override
protected void putDescription(StringBuilder builder) {
int lsize = lst.size();
builder.append("\n");
builder.append("(index : ");
builder.append(index);
if (wasEmbeddedActionMoved()) {
builder.append(" -> ");
for (int item : extractedActionProductions) {
builder.append(item);
builder.append(", ");
}
}
builder.append (")");
builder.append("\n");
for (int i=0; i < lsize; i++) {
builder.append(" ");
......
......@@ -3,6 +3,7 @@ package de.in.tum.www2.cup.internal;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.ArrayList;
import de.in.tum.www2.cup.CupContext;
import de.in.tum.www2.cup.internal.non_terminal.non_terminal_shared;
......@@ -343,6 +344,14 @@ public class production {
/** Index number of the production. */
public int index() {return _index;}
private ArrayList<Integer> _embedded_actions = null;
// CupPlugin : we need this for the debugger
public ArrayList<Integer> get_embedded_actions () {
return _embedded_actions;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
/** Count of number of reductions using this production. */
......@@ -611,11 +620,13 @@ public class production {
production new_prod;
String declare_str;
int lastLocation = -1;
ArrayList<Integer> eais = null;
/* walk over the production and process each action */
for (int act_loc = 0; act_loc < rhs_length(); act_loc++)
if (rhs(act_loc).is_action())
{
if (eais == null)
eais = new ArrayList<Integer> ();
declare_str = declare_labels(
_rhs, act_loc, "");
......@@ -627,10 +638,13 @@ public class production {
new_prod = new action_production(context, this, new_nt, null, 0,
declare_str + ((action_part)rhs(act_loc)).code_string(), (lastLocation==-1)?-1:(act_loc-lastLocation));
eais.add(new_prod.index());
/* replace the action with the generated non terminal */
_rhs[act_loc] = new symbol_part(new_nt);
lastLocation = act_loc;
}
_embedded_actions = eais;
}
/*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
......
package de.tum.in.www2.cupplugin;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.text.BadLocationException;
......@@ -14,6 +17,7 @@ import de.in.tum.www2.cup.Position;
import de.in.tum.www2.cup.Range;
import de.in.tum.www2.cup.ast.ParserResult;
import de.tum.in.www2.cupplugin.editors.CupTextEditor;
import de.tum.in.www2.cupplugin.editors.MultiPageEditor;
import de.tum.in.www2.cupplugin.model.Model;
public final class PluginUtility {
......@@ -55,6 +59,16 @@ public final class PluginUtility {
}
}
public static CupTextEditor getEditorFromEvent(ExecutionEvent event)
throws ExecutionException
{
MultiPageEditor mpe = (MultiPageEditor) HandlerUtil.getActiveEditorChecked(event);
if (mpe == null)
return null;
return mpe.getEditor();
}
/**
* Find the generated file that matches our cup file.
* @param cupFile The original cup file.
......@@ -68,7 +82,7 @@ public final class PluginUtility {
String name = cupFile.getName();
// TODO: we should probably look for Parser.java or
// a file witht the class name as defined in the grammar instead.
// a file with the class name as defined in the grammar instead.
String withoutExt = name;
String ext = cupFile.getFileExtension();
......
......@@ -27,16 +27,12 @@ public class OpenDeclarationHandler extends AbstractHandler {
// that IHasDefinitionReference -> IHasDeclarationReference
// an getDefinition() -> getDeclaration()
MultiPageEditor mpe = (MultiPageEditor) HandlerUtil.getActiveEditorChecked(event);
CupTextEditor editor = mpe.getEditor();
CupTextEditor editor = PluginUtility.getEditorFromEvent(event);
Range range = PluginUtility.getRangeFromSelection(editor);
if (range == null)
return null;
IDocument doc = editor.getDocumentProvider().getDocument(editor.getEditorInput());
Model model = Model.getInstanceForDocument(doc);
ParserResult result = model.getAstModel();
ParserResult result = editor.getModel().getAstModel();
if (result != null) {
result.resolveReferences();
......
......@@ -29,9 +29,8 @@ public class OpenDefinitionHandler extends AbstractHandler {
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
MultiPageEditor mpe = (MultiPageEditor) HandlerUtil.getActiveEditorChecked(event);
CupTextEditor editor = mpe.getEditor();
CupTextEditor editor = PluginUtility.getEditorFromEvent(event);
Range range = PluginUtility.getRangeFromSelection(editor);
if (range == null)
return null;
......
......@@ -3,15 +3,134 @@ package de.tum.in.www2.cupplugin.commands;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import de.in.tum.www2.cup.Range;
import de.in.tum.www2.cup.analysis.FindAtPositionVisitor;
import de.in.tum.www2.cup.ast.AbstractNode;
import de.in.tum.www2.cup.ast.Name;
import de.in.tum.www2.cup.ast.ParserResult;
import de.tum.in.www2.cupplugin.PluginUtility;
import de.tum.in.www2.cupplugin.editors.CupTextEditor;
import de.tum.in.www2.cupplugin.editors.MultiPageEditor;
public class RenameSymbolHandler extends AbstractHandler {
static class RenameDialog extends TitleAreaDialog {
private Text newNameControl;
private String oldName;
private String newName;
public String getNewName() {
return newName;
}
public RenameDialog(String oldName, Shell parentShell) {
super(parentShell);
this.oldName = oldName;
}
@Override
public void create() {
super.create();
setTitle("Rename Symbol");
setMessage("Rename Terminals and Non-Terminals ...",
IMessageProvider.INFORMATION);
}
@Override
protected void okPressed() {
newName = newNameControl.getText();
super.okPressed();
}
@Override
protected Control createDialogArea(Composite parent) {
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout(2, false);
container
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
container.setLayout(layout);
Label lbtLastName = new Label(container, SWT.NONE);
lbtLastName.setText("Old name:");
GridData dataLastName = new GridData();
dataLastName.grabExcessHorizontalSpace = true;
dataLastName.horizontalAlignment = GridData.FILL;
Label dummy = new Label(container, SWT.BORDER);
dummy.setText(oldName);
dummy.setLayoutData(dataLastName);
Label lbtFirstName = new Label(container, SWT.NONE);
lbtFirstName.setText("New name:");
GridData dataFirstName = new GridData();
dataFirstName.grabExcessHorizontalSpace = true;
dataFirstName.horizontalAlignment = GridData.FILL;
newNameControl = new Text(container, SWT.BORDER);
newNameControl.setLayoutData(dataFirstName);
return area;
}
@Override
protected boolean isResizable() {
return true;
}
}
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
PluginUtility.showMessage("RenameSymbolHandler command called!");
Shell activeShell = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getShell();
CupTextEditor editor = PluginUtility.getEditorFromEvent(event);
Range range = PluginUtility.getRangeFromSelection(editor);
if (range == null)
return null;
ParserResult result = editor.getModel().getAstModel();
if (result == null)
return null;
FindAtPositionVisitor pf = new FindAtPositionVisitor(range.getBegin());
result.accept(pf, null);
AbstractNode node = pf.getResult();
if (node != null && node instanceof Name) {
Name nameNode = (Name) node;
String oldName = nameNode.name;
RenameDialog renameDialog = new RenameDialog(oldName, activeShell);
renameDialog.create();
if (renameDialog.open() == Window.OK) {
// visitor: make editings while traversing tree.
IDocument doc = editor.getDocument();
doc.set(renameDialog.getNewName());
}
}
return null;
}
......
package de.tum.in.www2.cupplugin.debug;
import java.util.List;
public interface IDebugLineMatcher {
/**
*
* @param indexes A list of debug ids in the original CUP file.
* @return A list of matching line numbers in the generated file.
*/
List<Integer> debuggerFindCase(List<Integer> indexes);
}
package de.tum.in.www2.cupplugin.debug;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class SimpleDebugLineMatcher implements IDebugLineMatcher {
private static final String DEBUG_SYMBOL_PREFIX = "//@@CUPDBG";
private static final int OFFSET = 2;
private BufferedReader reader;
public SimpleDebugLineMatcher (BufferedReader reader) {
this.reader = reader;
}
public List<Integer> debuggerFindCase(List<Integer> debugIds) {
if (debugIds == null)
return null;
HashMap<Integer,Integer> found = new HashMap<Integer,Integer> ();
List<Integer> result = new ArrayList<Integer>();
try {
int lineNum = -1;
String line = null;
while ((line = reader.readLine()) != null) {
lineNum++;
for (int debugId : debugIds) {
if (line.endsWith(DEBUG_SYMBOL_PREFIX + debugId)) {
found.put(debugId, lineNum + OFFSET);
continue;
}
}
}
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i=0; i < debugIds.size(); i++)
if (found.containsKey(debugIds.get(i)))
result.add(found.get(debugIds.get(i)));
else
result.add(-1);
return result;
}
}
......@@ -10,8 +10,10 @@ import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.IFontProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.jface.viewers.TreeViewer;
......@@ -39,6 +41,7 @@ public class CupContentOutlinePage extends ContentOutlinePage implements
private CupTextEditor editor;
private IDocument doc;
private TreeViewer viewer;
private boolean suppressOnSelection;
public CupContentOutlinePage(CupTextEditor editor) {
this.editor = editor;
......@@ -53,16 +56,34 @@ public class CupContentOutlinePage extends ContentOutlinePage implements
super.dispose();
};
// TODO: we could potentially do this in the background, but
// it's probably not worth it.
private boolean doJumpToPosition (OutlineEntry node, Position pos) {
List<OutlineEntry> children = node.getChildren();
if (!node.isFolder() && children.size() == 0) {
Range range = node.getRange();
if (range.contains(pos)) {
ISelection selection = new StructuredSelection(node);
suppressOnSelection = true;
viewer.setSelection(selection, true);
suppressOnSelection = false;
return true;
}
} else {
for (OutlineEntry e : children)
if (e != null)
if (doJumpToPosition(e, pos))
return true;
}
return false;
}
public void jumpToPosition(Position pos) {
if (viewer == null)
if (viewer == null || pos == null)
return;
OutlineEntry root = (OutlineEntry) viewer.getInput();
if (root != null) {
// viewer.setSelection(selection);
}
if (root != null)
doJumpToPosition(root, pos);
}
@Override
......@@ -73,6 +94,9 @@ public class CupContentOutlinePage extends ContentOutlinePage implements
@Override
public void selectionChanged(SelectionChangedEvent event) {
if (suppressOnSelection)
return;
TreeSelection sel = (TreeSelection) event.getSelection();
OutlineEntry entry = (OutlineEntry) sel.getFirstElement();
if (entry == null)
......
......@@ -20,6 +20,7 @@ import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import de.in.tum.www2.cup.Position;
import de.in.tum.www2.cup.ast.ParserResult;
import de.tum.in.www2.cupplugin.controller.Controller;
import de.tum.in.www2.cupplugin.model.Model;
......@@ -66,6 +67,14 @@ public class CupTextEditor extends TextEditor {
// java_cup.Lexer = new java_cup.Lexer(arg0, f);
}
public Model getModel() {
return Model.getInstanceForDocument(getDocument());
}
public IDocument getDocument() {
return getDocumentProvider().getDocument(getEditorInput());
}
// adapted from http://javadude.googlecode.com/svn/trunk/com.javadude.antxr.eclipse.ui/src/com/javadude/antxr/eclipse/ui/editor/AntxrEditor.java
public Position getCursorPos() {
int caret = -1;
......@@ -79,14 +88,14 @@ public class CupTextEditor extends TextEditor {
IDocument document = sourceViewer.getDocument();
if (document != null) {
try {
line = document.getLineOfOffset(caret) + 1;
column = caret - document.getLineOfOffset(caret); // TODO: off by one?
line = document.getLineOfOffset(caret);
column = caret - document.getLineOffset(line) + 1;
} catch (BadLocationException e) {
// ignore
}
}
}
return new Position(line, column, caret);
return new Position(line+1, column+1, caret);
}
@Override
......
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