Skip to content

Commit

Permalink
Generator: introduce "exact-types" option
Browse files Browse the repository at this point in the history
  • Loading branch information
gregsh committed Apr 22, 2018
1 parent a2b344f commit b4a5c1f
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 19 deletions.
9 changes: 7 additions & 2 deletions resources/messages/attributeDescriptions/generate.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@
<td>Types: token type constants case option</td>
</tr>
<tr>
<td>tokenAccessors</td>
<td>exact-types</td>
<td>all | <b>no</b> | tokens, elements, stubs</td>
<td>Token and element types constants exact type</td>
</tr>
<tr>
<td>token-accessors</td>
<td>yes, <b>no</b></td>
<td>PSI: generate token getters</td>
</tr>
Expand All @@ -65,7 +70,7 @@
<td>Parser: local variables style</td>
</tr>
<tr>
<td>firstCheck</td>
<td>first-check</td>
<td>positive number, <b>2</b></td>
<td>Parser: generate FIRST-based look-ahead optimization</td>
</tr>
Expand Down
14 changes: 8 additions & 6 deletions src/org/intellij/grammar/generator/GenOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class GenOptions {
public final Pattern generateRootRules;
public final boolean generateTokenTypes;
public final boolean generateElementTypes;
public final String generateExactTypes;
public final boolean generateExtendedPin;
public final boolean generatePsi;
public final boolean generatePsiFactory;
Expand All @@ -50,15 +51,16 @@ public class GenOptions {
public GenOptions(BnfFile myFile) {
Map<String, String> genOptions = getRootAttribute(myFile, KnownAttribute.GENERATE).asMap();
names = Names.forName(genOptions.get("names"));
generatePsi = getGenerateOption(myFile, KnownAttribute.GENERATE_PSI, genOptions.get("psi"));
generatePsi = getGenerateOption(myFile, KnownAttribute.GENERATE_PSI, genOptions, "psi");
generatePsiFactory = !"no".equals(genOptions.get("psi-factory"));
generatePsiClassesMap = "yes".equals(genOptions.get("psi-classes-map"));
generateTokenTypes = getGenerateOption(myFile, KnownAttribute.GENERATE_TOKENS, genOptions.get("tokens"));
generateTokenTypes = getGenerateOption(myFile, KnownAttribute.GENERATE_TOKENS, genOptions, "tokens");
generateElementTypes = !"no".equals(genOptions.get("elements"));
generateFirstCheck = getGenerateOption(myFile, KnownAttribute.GENERATE_FIRST_CHECK, genOptions.get("firstCheck"));
generateExtendedPin = getGenerateOption(myFile, KnownAttribute.EXTENDED_PIN, genOptions.get("extendedPin"));
generateTokenAccessors = getGenerateOption(myFile, KnownAttribute.GENERATE_TOKEN_ACCESSORS, genOptions.get("tokenAccessors"));
generateTokenAccessorsSet = genOptions.containsKey("tokenAccessors");
generateExactTypes = StringUtil.notNullize(genOptions.get("exact-types"));
generateFirstCheck = getGenerateOption(myFile, KnownAttribute.GENERATE_FIRST_CHECK, genOptions, "first-check", "firstCheck");
generateExtendedPin = getGenerateOption(myFile, KnownAttribute.EXTENDED_PIN, genOptions, "extended-pin", "extendedPin");
generateTokenAccessors = getGenerateOption(myFile, KnownAttribute.GENERATE_TOKEN_ACCESSORS, genOptions, "token-accessors", "tokenAccessors");
generateTokenAccessorsSet = genOptions.containsKey("token-accessors") || genOptions.containsKey("tokenAccessors");
generateRootRules = PatternUtil.compileSafe(genOptions.get("root-rules"), null);
generateVisitor = !"no".equals(genOptions.get("visitor"));
visitorValue = "void".equals(genOptions.get("visitor-value")) ? null : StringUtil.nullize(genOptions.get("visitor-value"));
Expand Down
36 changes: 26 additions & 10 deletions src/org/intellij/grammar/generator/ParserGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package org.intellij.grammar.generator;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Trinity;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
Expand Down Expand Up @@ -1348,17 +1348,26 @@ private void generateElementTypesHolder(String className, Map<String, BnfRule> s
imports.add(PSI_ELEMENT_CLASS);
imports.add(AST_NODE_CLASS);
}
Map<String, Couple<String>> compositeToClassAndFactoryMap = new THashMap<>();
boolean useExactElements = "all".equals(G.generateExactTypes) || G.generateExactTypes.contains("elements");
boolean useExactStubs = G.generateExactTypes.contains("stubs");
boolean useExactTokens = "all".equals(G.generateExactTypes) || G.generateExactTypes.contains("tokens");

Map<String, Trinity<String, String, RuleInfo>> compositeToClassAndFactoryMap = new THashMap<>();
for (String elementType : sortedCompositeTypes.keySet()) {
BnfRule rule = sortedCompositeTypes.get(elementType);
RuleInfo ruleInfo = ruleInfo(rule);
String elementTypeClass = getAttribute(rule, KnownAttribute.ELEMENT_TYPE_CLASS);
String elementTypeFactory = getAttribute(rule, KnownAttribute.ELEMENT_TYPE_FACTORY);
compositeToClassAndFactoryMap.put(elementType, Couple.of(elementTypeClass, elementTypeFactory));
compositeToClassAndFactoryMap.put(elementType, Trinity.create(elementTypeClass, elementTypeFactory, ruleInfo));
if (elementTypeFactory != null) {
imports.add(StringUtil.getPackageName(elementTypeFactory));
}
else {
ContainerUtil.addIfNotNull(imports, elementTypeClass);
if (useExactStubs && ruleInfo.stub != null) {
imports.add(ISTUBELEMENTTYPE_CLASS);
imports.add(ruleInfo.intfClass);
}
}
}
if (tokenTypeFactory != null) {
Expand All @@ -1384,28 +1393,35 @@ private void generateElementTypesHolder(String className, Map<String, BnfRule> s
generateClassHeader(className, imports, "", Java.INTERFACE);
if (G.generateElementTypes) {
for (String elementType : sortedCompositeTypes.keySet()) {
Couple<String> pair = compositeToClassAndFactoryMap.get(elementType);
String exactType = null;
Trinity<String, String, RuleInfo> info = compositeToClassAndFactoryMap.get(elementType);
String elementCreateCall;
if (pair.second == null) {
elementCreateCall = "new " + StringUtil.getShortName(pair.first);
if (info.second == null) {
elementCreateCall = "new " + (exactType = myShortener.fun(info.first));
}
else {
elementCreateCall = myShortener.fun(StringUtil.getPackageName(pair.second)) + "." + StringUtil.getShortName(pair.second);
elementCreateCall = myShortener.fun(StringUtil.getPackageName(info.second)) + "." + StringUtil.getShortName(info.second);
}
String fieldType = ObjectUtils.notNull(
useExactElements ? exactType :
useExactStubs && info.third.stub != null ? "IStubElementType<?, " + myShortener.fun(info.third.intfClass) + ">" :
"IElementType");
String callFix = elementCreateCall.equals("new IElementType") ? ", null" : "";
out("IElementType " + elementType + " = " + elementCreateCall + "(\"" + elementType + "\"" + callFix + ");");
out(fieldType + " " + elementType + " = " + elementCreateCall + "(\"" + elementType + "\"" + callFix + ");");
}
}
if (G.generateTokenTypes) {
newLine();
String exactType = null;
Map<String, String> sortedTokens = ContainerUtil.newTreeMap();
String tokenCreateCall;
if (tokenTypeFactory == null) {
tokenCreateCall = "new " + StringUtil.getShortName(tokenTypeClass);
tokenCreateCall = "new " + (exactType = myShortener.fun(tokenTypeClass));
}
else {
tokenCreateCall = myShortener.fun(StringUtil.getPackageName(tokenTypeFactory)) + "." + StringUtil.getShortName(tokenTypeFactory);
}
String fieldType = ObjectUtils.notNull(useExactTokens ? exactType : null, "IElementType");
for (String tokenText : mySimpleTokens.keySet()) {
String tokenName = ObjectUtils.chooseNotNull(mySimpleTokens.get(tokenText), tokenText);
if (isIgnoredWhitespaceToken(tokenName, tokenText)) continue;
Expand All @@ -1414,7 +1430,7 @@ private void generateElementTypesHolder(String className, Map<String, BnfRule> s
for (String tokenType : sortedTokens.keySet()) {
String callFix = tokenCreateCall.equals("new IElementType") ? ", null" : "";
String tokenString = sortedTokens.get(tokenType);
out("IElementType " + tokenType + " = " + tokenCreateCall + "(\"" + StringUtil.escapeStringCharacters(tokenString) + "\""+callFix+");");
out(fieldType + " " + tokenType + " = " + tokenCreateCall + "(\"" + StringUtil.escapeStringCharacters(tokenString) + "\""+callFix+");");
}
}
if (G.generatePsi && G.generatePsiClassesMap) {
Expand Down
4 changes: 3 additions & 1 deletion src/org/intellij/grammar/generator/ParserGeneratorUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ public static <T extends Enum<T>> T enumFromString(@Nullable String value, @NotN
}
}

public static <T> T getGenerateOption(@NotNull PsiElement node, @NotNull KnownAttribute<T> attribute, @Nullable String currentValue) {
public static <T> T getGenerateOption(@NotNull PsiElement node, @NotNull KnownAttribute<T> attribute,
@NotNull Map<String, String> genOptions, String... genOptionKeys) {
String currentValue = JBIterable.of(genOptionKeys).map(genOptions::get).filter(Objects::nonNull).first();
if (attribute.getDefaultValue() instanceof Boolean) {
if ("yes".equals(currentValue)) return (T)Boolean.TRUE;
if ("no".equals(currentValue)) return (T)Boolean.FALSE;
Expand Down

0 comments on commit b4a5c1f

Please sign in to comment.