Skip to content

Commit

Permalink
Fix defines which contain own name freezing IDE
Browse files Browse the repository at this point in the history
Version 1.15
  • Loading branch information
Darkyenus committed Jan 18, 2017
1 parent d3640d2 commit 692d73c
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 17 deletions.
9 changes: 7 additions & 2 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@
<idea-version since-build="139.1117"/>
<depends>com.intellij.modules.lang</depends>

<version>1.14</version>
<version>1.15</version>
<change-notes><![CDATA[
<p>1.15</p>
<ul>
<li>Fix '#define's which contain their name freezing IDE</li>
</ul>
<p>1.14</p>
<ul>
<li>Allow custom highlighting for uniforms, varyings and attributes</li>
Expand Down Expand Up @@ -167,7 +172,7 @@
<errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
<fileTypeFactory implementation="glslplugin.GLSLSupportLoader"/>
<colorSettingsPage implementation="glslplugin.GLSLColorAndFontsPage"/>
<lang.syntaxHighlighterFactory key="GLSL" implementationClass="glslplugin.GLSLHighlighterFactory"/>
<lang.syntaxHighlighterFactory language="GLSL" implementationClass="glslplugin.GLSLHighlighterFactory"/>
<lang.braceMatcher language="GLSL" implementationClass="glslplugin.GLSLPairedBraceMatcher"/>
<lang.parserDefinition language="GLSL" implementationClass="glslplugin.lang.GLSLParserDefinition"/>
<lang.foldingBuilder language="GLSL" implementationClass="glslplugin.GLSLFoldingBuilder"/>
Expand Down
2 changes: 1 addition & 1 deletion src/glslplugin/lang/GLSLFileType.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
*/
public class GLSLFileType extends LanguageFileType {

public static final Set<String> EXTENSIONS = new HashSet<>();
public static final Set<String> EXTENSIONS = new HashSet<String>();

static {
EXTENSIONS.add("glsl");
Expand Down
4 changes: 2 additions & 2 deletions src/glslplugin/lang/parser/GLSLParsing.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<IElementType> definition = new ArrayList<IElementType>();
List<ForeignLeafType> definition = new ArrayList<ForeignLeafType>();
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();
}
Expand Down
23 changes: 16 additions & 7 deletions src/glslplugin/lang/parser/GLSLParsingBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -45,7 +46,7 @@ abstract class GLSLParsingBase {
*/
protected final GLSLPsiBuilderAdapter b;

protected Map<String, List<IElementType>> definitions = new HashMap<String, List<IElementType>>();
protected Map<String, List<ForeignLeafType>> definitions = new HashMap<String, List<ForeignLeafType>>();
protected Map<String, String> definitionTexts = new HashMap<String, String>();

GLSLParsingBase(PsiBuilder builder) {
Expand Down Expand Up @@ -79,12 +80,20 @@ public void advanceLexer(boolean checkForPreprocessor, boolean remapTokens){

public void advanceLexer_remapTokens(){
final String tokenText = getTokenText();
final List<IElementType> 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<ForeignLeafType> 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();
}
Expand All @@ -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);
}
}

Expand Down
39 changes: 34 additions & 5 deletions src/glslplugin/lang/parser/MultiRemapPsiBuilderAdapter.java
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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()) {
Expand All @@ -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<IElementType> types) {
public void remapCurrentToken(List<ForeignLeafType> remapToTypes, String remappedThrough) {
remapCurrentTokenAdvanceLexer();
waitingTokens.addAll(0, types);
final ArrayList<IElementType> tagged = new ArrayList<IElementType>(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());
Expand All @@ -98,9 +125,11 @@ protected class DelegateMarker extends com.intellij.lang.impl.DelegateMarker {

public DelegateMarker(Marker delegate) {
super(delegate);
//noinspection unchecked
rollbackWaitingTokens = (ArrayList<IElementType>) waitingTokens.clone();
}

@NotNull
@Override
public Marker precede() {
Marker precedent = super.precede();
Expand Down
39 changes: 39 additions & 0 deletions src/glslplugin/lang/parser/RedefinedTokenType.java
Original file line number Diff line number Diff line change
@@ -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)+")";
}
}

0 comments on commit 692d73c

Please sign in to comment.