Skip to content

Commit 56ef4ca

Browse files
committed
FullForm Viewer, test-cases for parsing
1 parent 8676ce3 commit 56ef4ca

27 files changed

Lines changed: 559 additions & 8 deletions

resources/META-INF/plugin.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,5 +151,9 @@
151151

152152
<add-to-group group-id="MainMenu" anchor="after" relative-to-action="ToolsMenu"/>
153153
</group>
154+
<action id="MathematicaFullFormViewer" class="de.halirutan.mathematica.actions.MathematicaFullFormViewer" text="View FullForm" description="Show the estimated FullForm of the selected expression">
155+
<add-to-group group-id="MathematicaMenu" anchor="last"/>
156+
<keyboard-shortcut keymap="$default" first-keystroke="shift ctrl E"/>
157+
</action>
154158
</actions>
155159
</idea-plugin>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2017 Patrick Scheibe
3+
* Permission is hereby granted, free of charge, to any person obtaining a copy
4+
* of this software and associated documentation files (the "Software"), to deal
5+
* in the Software without restriction, including without limitation the rights
6+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the Software is
8+
* furnished to do so, subject to the following conditions:
9+
*
10+
* The above copyright notice and this permission notice shall be included in
11+
* all copies or substantial portions of the Software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
* THE SOFTWARE.
20+
*/
21+
22+
package de.halirutan.mathematica.actions;
23+
24+
import com.intellij.ide.scratch.ScratchRootType;
25+
import com.intellij.openapi.actionSystem.AnAction;
26+
import com.intellij.openapi.actionSystem.AnActionEvent;
27+
import com.intellij.openapi.actionSystem.CommonDataKeys;
28+
import com.intellij.openapi.command.CommandProcessor;
29+
import com.intellij.openapi.command.WriteCommandAction;
30+
import com.intellij.openapi.editor.Editor;
31+
import com.intellij.openapi.editor.SelectionModel;
32+
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
33+
import com.intellij.openapi.project.Project;
34+
import com.intellij.openapi.vfs.VirtualFile;
35+
import com.intellij.psi.PsiElement;
36+
import com.intellij.psi.PsiFile;
37+
import com.intellij.psi.PsiManager;
38+
import com.intellij.psi.codeStyle.CodeStyleManager;
39+
import de.halirutan.mathematica.file.MathematicaFileType;
40+
import de.halirutan.mathematica.lang.MathematicaLanguage;
41+
import de.halirutan.mathematica.lang.psi.util.MathematicaFullFormCreator;
42+
import de.halirutan.mathematica.lang.psi.util.MathematicaPsiElementFactory;
43+
44+
/**
45+
* @author patrick (03.09.17).
46+
*/
47+
public class MathematicaFullFormViewer extends AnAction {
48+
49+
@Override
50+
public void actionPerformed(AnActionEvent e) {
51+
final Editor editor = e.getData(CommonDataKeys.EDITOR);
52+
final Project project = e.getProject();
53+
assert project != null;
54+
final FileEditorManagerEx editorManagerEx = FileEditorManagerEx.getInstanceEx(project);
55+
final VirtualFile currentFile = editorManagerEx.getCurrentFile();
56+
if (currentFile != null && currentFile.getFileType().equals(MathematicaFileType.INSTANCE)) {
57+
MathematicaFullFormCreator fullFormCreator = new MathematicaFullFormCreator();
58+
PsiElement expression = null;
59+
if (editor != null) {
60+
final SelectionModel selectionModel = editor.getSelectionModel();
61+
if (selectionModel.hasSelection()) {
62+
final String selectedText = selectionModel.getSelectedText();
63+
if (selectedText != null) {
64+
MathematicaPsiElementFactory factory = new MathematicaPsiElementFactory(project);
65+
expression = factory.createDummyFile(selectedText);
66+
}
67+
} else {
68+
final PsiFile psiFile = PsiManager.getInstance(project).findFile(currentFile);
69+
if (psiFile != null) {
70+
expression = psiFile;
71+
}
72+
}
73+
}
74+
75+
if (expression != null) {
76+
String fullForm = fullFormCreator.getFullForm(expression);
77+
78+
final VirtualFile scratchFile = ScratchRootType.getInstance().createScratchFile(project, "FullForm.m", MathematicaLanguage.INSTANCE,
79+
fullForm);
80+
if (scratchFile != null) {
81+
editorManagerEx.openFile(scratchFile, true);
82+
WriteCommandAction.runWriteCommandAction(project,
83+
() -> {
84+
final PsiFile file = PsiManager.getInstance(project).findFile(scratchFile);
85+
assert file != null;
86+
CodeStyleManager.getInstance(project).reformat(file);
87+
}
88+
);
89+
}
90+
}
91+
92+
}
93+
}
94+
}
95+

src/de/halirutan/mathematica/lang/psi/MathematicaVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import de.halirutan.mathematica.lang.psi.api.rules.RuleDelayed;
3939
import de.halirutan.mathematica.lang.psi.api.slots.Slot;
4040
import de.halirutan.mathematica.lang.psi.api.slots.SlotExpression;
41+
import de.halirutan.mathematica.lang.psi.api.string.MString;
4142

4243

4344
/**
@@ -169,6 +170,10 @@ public void visitList(MList mList) {
169170
visitElement(mList);
170171
}
171172

173+
public void visitString(MString mString) {
174+
visitElement(mString);
175+
}
176+
172177
public void visitStringifiedSymbol(StringifiedSymbol stringifiedSymbol) {
173178
visitElement(stringifiedSymbol);
174179
}

src/de/halirutan/mathematica/lang/psi/impl/NumberImpl.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
package de.halirutan.mathematica.lang.psi.impl;
2323

2424
import com.intellij.lang.ASTNode;
25+
import com.intellij.psi.PsiElementVisitor;
26+
import de.halirutan.mathematica.lang.psi.MathematicaVisitor;
2527
import de.halirutan.mathematica.lang.psi.api.Number;
2628
import org.jetbrains.annotations.NotNull;
2729

@@ -34,7 +36,17 @@ public NumberImpl(@NotNull ASTNode node) {
3436
}
3537

3638
@Override
37-
public String toString() {
38-
return "Number(" + getText() + ")";
39+
public void accept(@NotNull PsiElementVisitor visitor) {
40+
if (visitor instanceof MathematicaVisitor) {
41+
((MathematicaVisitor) visitor).visitNumber(this);
42+
} else {
43+
super.accept(visitor);
44+
}
3945
}
46+
47+
48+
// @Override
49+
// public String toString() {
50+
// return "Number(" + getText() + ")";
51+
// }
4052
}

src/de/halirutan/mathematica/lang/psi/impl/lists/MListImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,9 @@ public void accept(@NotNull PsiElementVisitor visitor) {
5454
public List<PsiElement> getListElements() {
5555
return Arrays.asList(getChildren());
5656
}
57+
58+
@Override
59+
public String toString() {
60+
return "List";
61+
}
5762
}

src/de/halirutan/mathematica/lang/psi/impl/string/StringImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323

2424
import com.intellij.lang.ASTNode;
2525
import com.intellij.psi.PsiElement;
26+
import com.intellij.psi.PsiElementVisitor;
2627
import com.intellij.psi.PsiFileFactory;
2728
import com.intellij.psi.PsiReference;
2829
import com.intellij.psi.impl.source.resolve.reference.ReferenceProvidersRegistry;
2930
import com.intellij.util.IncorrectOperationException;
3031
import de.halirutan.mathematica.file.MathematicaFileType;
3132
import de.halirutan.mathematica.lang.parsing.MathematicaElementTypes;
33+
import de.halirutan.mathematica.lang.psi.MathematicaVisitor;
3234
import de.halirutan.mathematica.lang.psi.api.string.MString;
3335
import de.halirutan.mathematica.lang.psi.impl.MathematicaPsiFileImpl;
3436
import de.halirutan.mathematica.lang.psi.impl.OperatorNameProviderImpl;
@@ -77,4 +79,14 @@ public PsiReference[] getReferences() {
7779
}
7880
return myReferences;
7981
}
82+
83+
@Override
84+
public void accept(@NotNull PsiElementVisitor visitor) {
85+
if (visitor instanceof MathematicaVisitor) {
86+
((MathematicaVisitor) visitor).visitString(this);
87+
} else {
88+
super.accept(visitor);
89+
}
90+
}
91+
8092
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Copyright (c) 2017 Patrick Scheibe
3+
* Permission is hereby granted, free of charge, to any person obtaining a copy
4+
* of this software and associated documentation files (the "Software"), to deal
5+
* in the Software without restriction, including without limitation the rights
6+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the Software is
8+
* furnished to do so, subject to the following conditions:
9+
*
10+
* The above copyright notice and this permission notice shall be included in
11+
* all copies or substantial portions of the Software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
* THE SOFTWARE.
20+
*/
21+
22+
package de.halirutan.mathematica.lang.psi.util;
23+
24+
import com.intellij.openapi.progress.ProgressIndicatorProvider;
25+
import com.intellij.psi.PsiComment;
26+
import com.intellij.psi.PsiElement;
27+
import com.intellij.psi.PsiFile;
28+
import com.intellij.psi.PsiWhiteSpace;
29+
import de.halirutan.mathematica.lang.psi.MathematicaRecursiveVisitor;
30+
import de.halirutan.mathematica.lang.psi.api.FunctionCall;
31+
import de.halirutan.mathematica.lang.psi.api.Number;
32+
import de.halirutan.mathematica.lang.psi.api.StringifiedSymbol;
33+
import de.halirutan.mathematica.lang.psi.api.Symbol;
34+
import de.halirutan.mathematica.lang.psi.api.pattern.Blank;
35+
import de.halirutan.mathematica.lang.psi.api.pattern.BlankNullSequence;
36+
import de.halirutan.mathematica.lang.psi.api.pattern.BlankSequence;
37+
import de.halirutan.mathematica.lang.psi.api.string.MString;
38+
import org.jetbrains.annotations.NotNull;
39+
40+
import java.util.List;
41+
42+
/**
43+
* @author patrick (03.09.17).
44+
*/
45+
public class MathematicaFullFormCreator extends MathematicaRecursiveVisitor {
46+
47+
private final StringBuilder myBuilder = new StringBuilder();
48+
private int myCharCount = 0;
49+
50+
@Override
51+
public void visitElement(PsiElement element) {
52+
ProgressIndicatorProvider.checkCanceled();
53+
if (element instanceof PsiWhiteSpace || element instanceof PsiComment) {
54+
return;
55+
}
56+
addContent(element);
57+
createEnclosedExpression(element.getChildren(), element.getTextLength() > 40 || myCharCount > 120);
58+
}
59+
60+
@Override
61+
public void visitFile(PsiFile file) {
62+
final PsiElement[] children = file.getChildren();
63+
for (PsiElement child : children) {
64+
child.accept(this);
65+
addLineFeed();
66+
addLineFeed();
67+
}
68+
}
69+
70+
@Override
71+
public void visitFunctionCall(FunctionCall functionCall) {
72+
functionCall.getHead().accept(this);
73+
final List<PsiElement> parameters = functionCall.getParameters();
74+
PsiElement[] parameterArray = parameters.toArray(new PsiElement[parameters.size()]);
75+
createEnclosedExpression(parameterArray, functionCall.getTextLength() > 30 || myCharCount > 120);
76+
}
77+
78+
@Override
79+
public void visitSymbol(Symbol symbol) {
80+
addContent(symbol.getText());
81+
}
82+
83+
@Override
84+
public void visitNumber(Number number) {
85+
addContent(number.getText());
86+
}
87+
88+
@Override
89+
public void visitString(MString mString) {
90+
addContent(mString.getText());
91+
}
92+
93+
@Override
94+
public void visitBlank(Blank blank) {
95+
visitBlankLikeElement(blank);
96+
}
97+
98+
@Override
99+
public void visitBlankSequence(BlankSequence blankSequence) {
100+
visitBlankLikeElement(blankSequence);
101+
}
102+
103+
@Override
104+
public void visitBlankNullSequence(BlankNullSequence blankNullSequence) {
105+
visitBlankLikeElement(blankNullSequence);
106+
}
107+
108+
private void visitBlankLikeElement(PsiElement blank) {
109+
if (blank instanceof Blank || blank instanceof BlankSequence || blank instanceof BlankNullSequence) {
110+
String head = blank.toString();
111+
final PsiElement[] children = blank.getChildren();
112+
if (children.length < 1 || children.length > 2) {
113+
return;
114+
}
115+
addContent("Pattern[");
116+
children[0].accept(this);
117+
if (children.length == 2) {
118+
addContent("," + head + "[");
119+
children[1].accept(this);
120+
addContent("]]");
121+
} else {
122+
addContent("," + head + "[]]");
123+
}
124+
}
125+
126+
}
127+
128+
@Override
129+
public void visitStringifiedSymbol(StringifiedSymbol stringifiedSymbol) {
130+
addContent("\"" + stringifiedSymbol.getText() + "\"");
131+
}
132+
133+
private void createEnclosedExpression(PsiElement[] elements, boolean makeLineBreak) {
134+
if (elements == null) {
135+
addContent("[]");
136+
} else {
137+
addContent("[");
138+
if (makeLineBreak) {
139+
addLineFeed();
140+
}
141+
myCharCount++;
142+
for (int i = 0; i < elements.length; i++) {
143+
if (elements[i] instanceof PsiWhiteSpace || elements[i] instanceof PsiComment) {
144+
continue;
145+
}
146+
elements[i].accept(this);
147+
if (i != elements.length - 1) {
148+
addContent(",");
149+
if (makeLineBreak) {
150+
addLineFeed();
151+
}
152+
}
153+
}
154+
if (makeLineBreak) {
155+
addLineFeed();
156+
}
157+
addContent("]");
158+
}
159+
}
160+
161+
private void addContent(@NotNull PsiElement element) {
162+
addContent(element.toString());
163+
}
164+
165+
private void addContent(@NotNull String content) {
166+
myBuilder.append(content);
167+
myCharCount += content.length();
168+
}
169+
170+
private void addLineFeed() {
171+
myBuilder.append("\n");
172+
myCharCount = 0;
173+
}
174+
175+
public String getFullForm(PsiElement element) {
176+
element.accept(this);
177+
return myBuilder.toString();
178+
}
179+
180+
181+
}

src/de/halirutan/mathematica/lang/psi/util/MathematicaPsiElementFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public MathematicaPsiElementFactory(final Project project) {
5252
* @return The newly created PsiFile with content code
5353
*/
5454
@NotNull
55-
private MathematicaPsiFile createDummyFile(@NotNull CharSequence code) {
55+
public MathematicaPsiFile createDummyFile(@NotNull CharSequence code) {
5656
final FileType type = MathematicaFileType.INSTANCE;
5757
return (MathematicaPsiFile) PsiFileFactory.getInstance(myProject).createFileFromText(DUMMY_FILE_NAME, type, code);
5858
}

testData/de/halirutan/mathematica/lang/parsing/Assignment.m

Whitespace-only changes.

testData/de/halirutan/mathematica/lang/parsing/Pattern.m

Whitespace-only changes.

0 commit comments

Comments
 (0)