From 692d73c870cf2e9e6c4848683483278e7d0e944d Mon Sep 17 00:00:00 2001
From: Darkyenus
Date: Wed, 18 Jan 2017 23:22:54 +0100
Subject: [PATCH] Fix defines which contain own name freezing IDE
Version 1.15
---
META-INF/plugin.xml | 9 ++++-
src/glslplugin/lang/GLSLFileType.java | 2 +-
src/glslplugin/lang/parser/GLSLParsing.java | 4 +-
.../lang/parser/GLSLParsingBase.java | 23 +++++++----
.../parser/MultiRemapPsiBuilderAdapter.java | 39 ++++++++++++++++---
.../lang/parser/RedefinedTokenType.java | 39 +++++++++++++++++++
6 files changed, 99 insertions(+), 17 deletions(-)
create mode 100644 src/glslplugin/lang/parser/RedefinedTokenType.java
diff --git a/META-INF/plugin.xml b/META-INF/plugin.xml
index 3a1945f2..95cce0e1 100755
--- a/META-INF/plugin.xml
+++ b/META-INF/plugin.xml
@@ -27,8 +27,13 @@
com.intellij.modules.lang
- 1.14
+ 1.15
1.15
+
+ - Fix '#define's which contain their name freezing IDE
+
+
1.14
- Allow custom highlighting for uniforms, varyings and attributes
@@ -167,7 +172,7 @@
-
+
diff --git a/src/glslplugin/lang/GLSLFileType.java b/src/glslplugin/lang/GLSLFileType.java
index b107c80b..8d888a4f 100755
--- a/src/glslplugin/lang/GLSLFileType.java
+++ b/src/glslplugin/lang/GLSLFileType.java
@@ -35,7 +35,7 @@
*/
public class GLSLFileType extends LanguageFileType {
- public static final Set EXTENSIONS = new HashSet<>();
+ public static final Set EXTENSIONS = new HashSet();
static {
EXTENSIONS.add("glsl");
diff --git a/src/glslplugin/lang/parser/GLSLParsing.java b/src/glslplugin/lang/parser/GLSLParsing.java
index a0841475..e0dab9f8 100755
--- a/src/glslplugin/lang/parser/GLSLParsing.java
+++ b/src/glslplugin/lang/parser/GLSLParsing.java
@@ -94,13 +94,13 @@ protected final void parsePreprocessor() {
//Can use non-b b.advanceLexer here, to allow "nested" defines
b.advanceLexer();//Get past identifier
- List definition = new ArrayList();
+ List definition = new ArrayList();
StringBuilder definitionText = new StringBuilder();
while (b.getTokenType() != PREPROCESSOR_END && !b.eof()) {
//Suppressed warning that getTokenType/Text may be null, because it won't be (.eof() is checked).
//noinspection ConstantConditions
- definition.add(new ForeignLeafType(b.getTokenType(), b.getTokenText()));
+ definition.add(new RedefinedTokenType(b.getTokenType(), b.getTokenText(), b.getNamesThroughWhichThisTokenWasRedefined()));
definitionText.append(b.getTokenText()).append(' ');
b.advanceLexer();
}
diff --git a/src/glslplugin/lang/parser/GLSLParsingBase.java b/src/glslplugin/lang/parser/GLSLParsingBase.java
index 6ab98450..761989dc 100644
--- a/src/glslplugin/lang/parser/GLSLParsingBase.java
+++ b/src/glslplugin/lang/parser/GLSLParsingBase.java
@@ -19,6 +19,7 @@
package glslplugin.lang.parser;
+import com.intellij.lang.ForeignLeafType;
import com.intellij.lang.PsiBuilder;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
@@ -45,7 +46,7 @@ abstract class GLSLParsingBase {
*/
protected final GLSLPsiBuilderAdapter b;
- protected Map> definitions = new HashMap>();
+ protected Map> definitions = new HashMap>();
protected Map definitionTexts = new HashMap();
GLSLParsingBase(PsiBuilder builder) {
@@ -79,12 +80,20 @@ public void advanceLexer(boolean checkForPreprocessor, boolean remapTokens){
public void advanceLexer_remapTokens(){
final String tokenText = getTokenText();
- final List definition = definitions.get(tokenText);
+ final String[] namesThroughWhichThisTokenWasRedefined = getNamesThroughWhichThisTokenWasRedefined();
+ for (String name : namesThroughWhichThisTokenWasRedefined) {
+ if (name != null && name.equals(tokenText)) {
+ // Happens for #define name .*name.*
+ // We must not replace it with itself, as it would lead to much tears (and probably is't up to spec anyway)
+ return;
+ }
+ }
+ final List definition = definitions.get(tokenText);
if (definition != null) {
Marker macro = mark();
- remapCurrentTokenAdvanceLexer_redefineTokens = false;
- remapCurrentToken(definition);
- remapCurrentTokenAdvanceLexer_redefineTokens = true;
+ remapCurrentTokenAdvanceLexer_remapTokens = false;
+ remapCurrentToken(definition, tokenText); //This will advance the lexer which will eat the (real or substituted) token and replace it with redefinition
+ remapCurrentTokenAdvanceLexer_remapTokens = true;
macro.done(new RedefinedTokenElementType(definitionTexts.get(tokenText)));
advanceLexer_remapTokens();
}
@@ -94,11 +103,11 @@ public void advanceLexer_remapTokens(){
//Used in advanceLexer_remapTokens to not remap immediately after advancing in remapCurrentToken
//That prevents two redefined tokens merging together (second becomes child of first)
//I know that it sounds complicated, but you will have to trust me.
- private boolean remapCurrentTokenAdvanceLexer_redefineTokens = true;
+ private boolean remapCurrentTokenAdvanceLexer_remapTokens = true;
@Override
protected void remapCurrentTokenAdvanceLexer() {
- advanceLexer(false, remapCurrentTokenAdvanceLexer_redefineTokens);
+ advanceLexer(false, remapCurrentTokenAdvanceLexer_remapTokens);
}
}
diff --git a/src/glslplugin/lang/parser/MultiRemapPsiBuilderAdapter.java b/src/glslplugin/lang/parser/MultiRemapPsiBuilderAdapter.java
index aeebeb0a..6d24c83f 100644
--- a/src/glslplugin/lang/parser/MultiRemapPsiBuilderAdapter.java
+++ b/src/glslplugin/lang/parser/MultiRemapPsiBuilderAdapter.java
@@ -1,14 +1,15 @@
package glslplugin.lang.parser;
+import com.intellij.lang.ForeignLeafType;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.TokenWrapper;
import com.intellij.lang.impl.PsiBuilderAdapter;
import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
+import java.util.List;
/**
* A PsiBuilderAdapter in which each token can be remapped to an arbitrary number of tokens.
@@ -46,6 +47,19 @@ public String getTokenText() {
return "";
}
+ private static final String[] NO_NAMES = {};
+
+ @NotNull
+ public String[] getNamesThroughWhichThisTokenWasRedefined() {
+ if (waitingTokens.isEmpty()) return NO_NAMES;
+ final IElementType type = waitingTokens.get(0);
+ if (type instanceof RedefinedTokenType) {
+ return ((RedefinedTokenType) type).redefinedThrough;
+ } else {
+ return NO_NAMES;
+ }
+ }
+
@Override
public void advanceLexer() {
if (waitingTokens.isEmpty()) {
@@ -61,20 +75,33 @@ public void advanceLexer() {
}
}
+ /** @see #remapCurrentToken(List, String), does that but without redefining */
@Override
public void remapCurrentToken(IElementType type) {
- remapCurrentToken(Collections.singletonList(type));
+ remapCurrentTokenAdvanceLexer();
+ waitingTokens.add(0, type);
}
protected void remapCurrentTokenAdvanceLexer(){
advanceLexer();
}
- public void remapCurrentToken(Collection types) {
+ public void remapCurrentToken(List remapToTypes, String remappedThrough) {
remapCurrentTokenAdvanceLexer();
- waitingTokens.addAll(0, types);
+ final ArrayList tagged = new ArrayList(remapToTypes.size());
+ for (final ForeignLeafType type : remapToTypes) {
+ final IElementType taggedType;
+ if (type instanceof RedefinedTokenType) {
+ taggedType = ((RedefinedTokenType) type).redefineAlsoThrough(remappedThrough);
+ } else {
+ taggedType = new RedefinedTokenType(type, remappedThrough);
+ }
+ tagged.add(taggedType);
+ }
+ waitingTokens.addAll(0, tagged);
}
+ @NotNull
@Override
public Marker mark() {
return new DelegateMarker(super.mark());
@@ -98,9 +125,11 @@ protected class DelegateMarker extends com.intellij.lang.impl.DelegateMarker {
public DelegateMarker(Marker delegate) {
super(delegate);
+ //noinspection unchecked
rollbackWaitingTokens = (ArrayList) waitingTokens.clone();
}
+ @NotNull
@Override
public Marker precede() {
Marker precedent = super.precede();
diff --git a/src/glslplugin/lang/parser/RedefinedTokenType.java b/src/glslplugin/lang/parser/RedefinedTokenType.java
new file mode 100644
index 00000000..6b1cc43b
--- /dev/null
+++ b/src/glslplugin/lang/parser/RedefinedTokenType.java
@@ -0,0 +1,39 @@
+package glslplugin.lang.parser;
+
+import com.intellij.lang.ForeignLeafType;
+import com.intellij.psi.tree.IElementType;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+
+/**
+ *
+ */
+public class RedefinedTokenType extends ForeignLeafType {
+
+ /** Names of #defines through which this token was created.
+ * Used to break recursive definitions, eg. #define FOO FOO. */
+ public final String[] redefinedThrough;
+
+ public RedefinedTokenType(@NotNull ForeignLeafType delegate, String redefinedThrough) {
+ super(delegate.getDelegate(), delegate.getValue());
+ this.redefinedThrough = new String[]{redefinedThrough};
+ }
+
+ public RedefinedTokenType(@NotNull IElementType delegate, @NotNull CharSequence value, String[] redefinedThrough) {
+ super(delegate, value);
+ this.redefinedThrough = redefinedThrough;
+ }
+
+ public RedefinedTokenType redefineAlsoThrough(String name) {
+ final String[] through = new String[redefinedThrough.length + 1];
+ System.arraycopy(this.redefinedThrough, 0, through, 0, this.redefinedThrough.length);
+ through[this.redefinedThrough.length] = name;
+ return new RedefinedTokenType(getDelegate(), getValue(), through);
+ }
+
+ @Override
+ public String toString() {
+ return "RedefinedTokenType("+getDelegate()+", '"+getValue()+"', "+ Arrays.toString(redefinedThrough)+")";
+ }
+}