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)+")"; + } +}