From bec916111157c03ff17dbf174ba837f22255541e Mon Sep 17 00:00:00 2001 From: Bastien JANSEN Date: Mon, 3 Apr 2023 22:01:09 +0200 Subject: [PATCH] feat: allow retrieving rule element types by Context name instead of rule index (#26) --- .../parser/ANTLRParseTreeToPSIConverter.java | 12 +++++-- .../parser/ClassNameIElementTypeMapper.java | 32 +++++++++++++++++++ .../adaptor/parser/IElementTypeMapper.java | 16 ++++++++++ .../parser/RuleIndexIElementTypeMapper.java | 30 +++++++++++++++++ 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/antlr/intellij/adaptor/parser/ClassNameIElementTypeMapper.java create mode 100644 src/main/java/org/antlr/intellij/adaptor/parser/IElementTypeMapper.java create mode 100644 src/main/java/org/antlr/intellij/adaptor/parser/RuleIndexIElementTypeMapper.java diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java b/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java index b6421ab..eb76d8c 100644 --- a/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java +++ b/src/main/java/org/antlr/intellij/adaptor/parser/ANTLRParseTreeToPSIConverter.java @@ -36,16 +36,22 @@ public class ANTLRParseTreeToPSIConverter implements ParseTreeListener { protected final List tokenElementTypes; protected final List ruleElementTypes; + private final IElementTypeMapper elementTypeMapper; /** Map an error's start char index (usually start of a token) to the error object. */ protected Map tokenToErrorMap = new HashMap<>(); public ANTLRParseTreeToPSIConverter(Language language, Parser parser, PsiBuilder builder) { + this(language, parser, builder, new RuleIndexIElementTypeMapper(PSIElementTypeFactory.getRuleIElementTypes(language))); + } + + public ANTLRParseTreeToPSIConverter(Language language, Parser parser, PsiBuilder builder, IElementTypeMapper elementTypeMapper) { this.language = language; this.builder = builder; + this.elementTypeMapper = elementTypeMapper; this.tokenElementTypes = PSIElementTypeFactory.getTokenIElementTypes(language); - this.ruleElementTypes = PSIElementTypeFactory.getRuleIElementTypes(language); + this.ruleElementTypes = elementTypeMapper.getRuleElementTypes(); for (ANTLRErrorListener listener : parser.getErrorListeners()) { if (listener instanceof SyntaxErrorListener) { @@ -166,10 +172,10 @@ public void exitEveryRule(ParserRuleContext ctx) { if (error != null) { marker.error(error.getMessage()); } else { - marker.done(getRuleElementTypes().get(ctx.getRuleIndex())); + marker.done(elementTypeMapper.toIElementType(ctx)); } } else { - marker.done(getRuleElementTypes().get(ctx.getRuleIndex())); + marker.done(elementTypeMapper.toIElementType(ctx)); } } } diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/ClassNameIElementTypeMapper.java b/src/main/java/org/antlr/intellij/adaptor/parser/ClassNameIElementTypeMapper.java new file mode 100644 index 0000000..645895a --- /dev/null +++ b/src/main/java/org/antlr/intellij/adaptor/parser/ClassNameIElementTypeMapper.java @@ -0,0 +1,32 @@ +package org.antlr.intellij.adaptor.parser; + +import com.intellij.psi.tree.IElementType; +import org.antlr.intellij.adaptor.lexer.RuleIElementType; +import org.antlr.v4.runtime.ParserRuleContext; +import org.apache.commons.lang.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class ClassNameIElementTypeMapper implements IElementTypeMapper { + + private final Map elementTypes; + + public ClassNameIElementTypeMapper(List elementTypes) { + this.elementTypes = elementTypes.stream() + .collect(Collectors.toMap(RuleIElementType::getDebugName, el -> el)); + } + + @Override + public IElementType toIElementType(ParserRuleContext ctx) { + String elementTypeName = StringUtils.removeEnd(ctx.getClass().getSimpleName(), "Context"); + return elementTypes.get(elementTypeName); + } + + @Override + public List getRuleElementTypes() { + return new ArrayList<>(elementTypes.values()); + } +} diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/IElementTypeMapper.java b/src/main/java/org/antlr/intellij/adaptor/parser/IElementTypeMapper.java new file mode 100644 index 0000000..9d10cd6 --- /dev/null +++ b/src/main/java/org/antlr/intellij/adaptor/parser/IElementTypeMapper.java @@ -0,0 +1,16 @@ +package org.antlr.intellij.adaptor.parser; + +import com.intellij.psi.tree.IElementType; +import org.antlr.intellij.adaptor.lexer.RuleIElementType; +import org.antlr.v4.runtime.ParserRuleContext; + +import java.util.List; + +/** + * Maps a {@link org.antlr.v4.runtime.ParserRuleContext} to an {@link com.intellij.psi.tree.IElementType}. + */ +public interface IElementTypeMapper { + IElementType toIElementType(ParserRuleContext ctx); + + List getRuleElementTypes(); +} diff --git a/src/main/java/org/antlr/intellij/adaptor/parser/RuleIndexIElementTypeMapper.java b/src/main/java/org/antlr/intellij/adaptor/parser/RuleIndexIElementTypeMapper.java new file mode 100644 index 0000000..e30d7dc --- /dev/null +++ b/src/main/java/org/antlr/intellij/adaptor/parser/RuleIndexIElementTypeMapper.java @@ -0,0 +1,30 @@ +package org.antlr.intellij.adaptor.parser; + +import com.intellij.psi.tree.IElementType; +import org.antlr.intellij.adaptor.lexer.RuleIElementType; +import org.antlr.v4.runtime.ParserRuleContext; + +import java.util.List; + +/** + * Maps a {@link org.antlr.v4.runtime.ParserRuleContext} to an {@link com.intellij.psi.tree.IElementType} using + * a rule index. + */ +public class RuleIndexIElementTypeMapper implements IElementTypeMapper { + + private final List ruleElementTypes; + + public RuleIndexIElementTypeMapper(List elementTypes) { + this.ruleElementTypes = elementTypes; + } + + @Override + public IElementType toIElementType(ParserRuleContext ctx) { + return ruleElementTypes.get(ctx.getRuleIndex()); + } + + @Override + public List getRuleElementTypes() { + return ruleElementTypes; + } +}