mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 16:28:56 +00:00
Merge pull request #572 from eclipse/sz_avoidDuplicatedCode
Avoid duplicated code in CA infrastructure
This commit is contained in:
commit
13051ddac6
24 changed files with 1605 additions and 1337 deletions
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.ide.contentassist.antlr;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.TokenSource;
|
||||
|
@ -19,11 +20,44 @@ import org.eclipse.xtext.ide.tests.testlanguage.services.IndentationAwareUiTestL
|
|||
|
||||
public class IndentationAwareUiTestLanguageParser extends AbstractContentAssistParser {
|
||||
|
||||
@Singleton
|
||||
public static final class NameMappings {
|
||||
|
||||
private final Map<AbstractElement, String> mappings;
|
||||
|
||||
@Inject
|
||||
public NameMappings(IndentationAwareUiTestLanguageGrammarAccess grammarAccess) {
|
||||
ImmutableMap.Builder<AbstractElement, String> builder = ImmutableMap.builder();
|
||||
init(builder, grammarAccess);
|
||||
this.mappings = builder.build();
|
||||
}
|
||||
|
||||
public String getRuleName(AbstractElement element) {
|
||||
return mappings.get(element);
|
||||
}
|
||||
|
||||
private static void init(ImmutableMap.Builder<AbstractElement, String> builder, IndentationAwareUiTestLanguageGrammarAccess grammarAccess) {
|
||||
builder.put(grammarAccess.getTreeAccess().getGroup(), "rule__Tree__Group__0");
|
||||
builder.put(grammarAccess.getTreeNodeAccess().getGroup(), "rule__TreeNode__Group__0");
|
||||
builder.put(grammarAccess.getTreeNodeAccess().getGroup_1(), "rule__TreeNode__Group_1__0");
|
||||
builder.put(grammarAccess.getOtherTreeNodeAccess().getGroup(), "rule__OtherTreeNode__Group__0");
|
||||
builder.put(grammarAccess.getChildListAccess().getGroup(), "rule__ChildList__Group__0");
|
||||
builder.put(grammarAccess.getTreeAccess().getNodesAssignment_1(), "rule__Tree__NodesAssignment_1");
|
||||
builder.put(grammarAccess.getTreeAccess().getMoreNodesAssignment_2(), "rule__Tree__MoreNodesAssignment_2");
|
||||
builder.put(grammarAccess.getTreeNodeAccess().getNameAssignment_0(), "rule__TreeNode__NameAssignment_0");
|
||||
builder.put(grammarAccess.getTreeNodeAccess().getChildrenAssignment_1_1(), "rule__TreeNode__ChildrenAssignment_1_1");
|
||||
builder.put(grammarAccess.getOtherTreeNodeAccess().getNameAssignment_0(), "rule__OtherTreeNode__NameAssignment_0");
|
||||
builder.put(grammarAccess.getOtherTreeNodeAccess().getChildListAssignment_1(), "rule__OtherTreeNode__ChildListAssignment_1");
|
||||
builder.put(grammarAccess.getChildListAccess().getChildrenAssignment_2(), "rule__ChildList__ChildrenAssignment_2");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private NameMappings nameMappings;
|
||||
|
||||
@Inject
|
||||
private IndentationAwareUiTestLanguageGrammarAccess grammarAccess;
|
||||
|
||||
private Map<AbstractElement, String> nameMappings;
|
||||
|
||||
@Override
|
||||
protected InternalIndentationAwareUiTestLanguageParser createParser() {
|
||||
InternalIndentationAwareUiTestLanguageParser result = new InternalIndentationAwareUiTestLanguageParser(null);
|
||||
|
@ -38,28 +72,9 @@ public class IndentationAwareUiTestLanguageParser extends AbstractContentAssistP
|
|||
|
||||
@Override
|
||||
protected String getRuleName(AbstractElement element) {
|
||||
if (nameMappings == null) {
|
||||
nameMappings = new HashMap<AbstractElement, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(grammarAccess.getTreeAccess().getGroup(), "rule__Tree__Group__0");
|
||||
put(grammarAccess.getTreeNodeAccess().getGroup(), "rule__TreeNode__Group__0");
|
||||
put(grammarAccess.getTreeNodeAccess().getGroup_1(), "rule__TreeNode__Group_1__0");
|
||||
put(grammarAccess.getOtherTreeNodeAccess().getGroup(), "rule__OtherTreeNode__Group__0");
|
||||
put(grammarAccess.getChildListAccess().getGroup(), "rule__ChildList__Group__0");
|
||||
put(grammarAccess.getTreeAccess().getNodesAssignment_1(), "rule__Tree__NodesAssignment_1");
|
||||
put(grammarAccess.getTreeAccess().getMoreNodesAssignment_2(), "rule__Tree__MoreNodesAssignment_2");
|
||||
put(grammarAccess.getTreeNodeAccess().getNameAssignment_0(), "rule__TreeNode__NameAssignment_0");
|
||||
put(grammarAccess.getTreeNodeAccess().getChildrenAssignment_1_1(), "rule__TreeNode__ChildrenAssignment_1_1");
|
||||
put(grammarAccess.getOtherTreeNodeAccess().getNameAssignment_0(), "rule__OtherTreeNode__NameAssignment_0");
|
||||
put(grammarAccess.getOtherTreeNodeAccess().getChildListAssignment_1(), "rule__OtherTreeNode__ChildListAssignment_1");
|
||||
put(grammarAccess.getChildListAccess().getChildrenAssignment_2(), "rule__ChildList__ChildrenAssignment_2");
|
||||
}
|
||||
};
|
||||
}
|
||||
return nameMappings.get(element);
|
||||
return nameMappings.getRuleName(element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getInitialHiddenTokens() {
|
||||
return new String[] { "RULE_WS", "RULE_ML_COMMENT", "RULE_SL_COMMENT" };
|
||||
|
@ -72,4 +87,12 @@ public class IndentationAwareUiTestLanguageParser extends AbstractContentAssistP
|
|||
public void setGrammarAccess(IndentationAwareUiTestLanguageGrammarAccess grammarAccess) {
|
||||
this.grammarAccess = grammarAccess;
|
||||
}
|
||||
|
||||
public NameMappings getNameMappings() {
|
||||
return nameMappings;
|
||||
}
|
||||
|
||||
public void setNameMappings(NameMappings nameMappings) {
|
||||
this.nameMappings = nameMappings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.ide.contentassist.antlr;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.AbstractPartialContentAssistParser;
|
||||
|
@ -17,11 +18,41 @@ import org.eclipse.xtext.ide.tests.testlanguage.services.PartialContentAssistTes
|
|||
|
||||
public class PartialContentAssistTestLanguageParser extends AbstractPartialContentAssistParser {
|
||||
|
||||
@Singleton
|
||||
public static final class NameMappings {
|
||||
|
||||
private final Map<AbstractElement, String> mappings;
|
||||
|
||||
@Inject
|
||||
public NameMappings(PartialContentAssistTestLanguageGrammarAccess grammarAccess) {
|
||||
ImmutableMap.Builder<AbstractElement, String> builder = ImmutableMap.builder();
|
||||
init(builder, grammarAccess);
|
||||
this.mappings = builder.build();
|
||||
}
|
||||
|
||||
public String getRuleName(AbstractElement element) {
|
||||
return mappings.get(element);
|
||||
}
|
||||
|
||||
private static void init(ImmutableMap.Builder<AbstractElement, String> builder, PartialContentAssistTestLanguageGrammarAccess grammarAccess) {
|
||||
builder.put(grammarAccess.getPropertyAccess().getTypeAlternatives_0_0(), "rule__Property__TypeAlternatives_0_0");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getGroup(), "rule__TypeDeclaration__Group__0");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getGroup_2(), "rule__TypeDeclaration__Group_2__0");
|
||||
builder.put(grammarAccess.getPropertyAccess().getGroup(), "rule__Property__Group__0");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getNameAssignment_1(), "rule__TypeDeclaration__NameAssignment_1");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getSuperTypeAssignment_2_1(), "rule__TypeDeclaration__SuperTypeAssignment_2_1");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getPropertiesAssignment_4(), "rule__TypeDeclaration__PropertiesAssignment_4");
|
||||
builder.put(grammarAccess.getPropertyAccess().getTypeAssignment_0(), "rule__Property__TypeAssignment_0");
|
||||
builder.put(grammarAccess.getPropertyAccess().getNameAssignment_1(), "rule__Property__NameAssignment_1");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private NameMappings nameMappings;
|
||||
|
||||
@Inject
|
||||
private PartialContentAssistTestLanguageGrammarAccess grammarAccess;
|
||||
|
||||
private Map<AbstractElement, String> nameMappings;
|
||||
|
||||
@Override
|
||||
protected InternalPartialContentAssistTestLanguageParser createParser() {
|
||||
InternalPartialContentAssistTestLanguageParser result = new InternalPartialContentAssistTestLanguageParser(null);
|
||||
|
@ -31,25 +62,9 @@ public class PartialContentAssistTestLanguageParser extends AbstractPartialConte
|
|||
|
||||
@Override
|
||||
protected String getRuleName(AbstractElement element) {
|
||||
if (nameMappings == null) {
|
||||
nameMappings = new HashMap<AbstractElement, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(grammarAccess.getPropertyAccess().getTypeAlternatives_0_0(), "rule__Property__TypeAlternatives_0_0");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getGroup(), "rule__TypeDeclaration__Group__0");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getGroup_2(), "rule__TypeDeclaration__Group_2__0");
|
||||
put(grammarAccess.getPropertyAccess().getGroup(), "rule__Property__Group__0");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getNameAssignment_1(), "rule__TypeDeclaration__NameAssignment_1");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getSuperTypeAssignment_2_1(), "rule__TypeDeclaration__SuperTypeAssignment_2_1");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getPropertiesAssignment_4(), "rule__TypeDeclaration__PropertiesAssignment_4");
|
||||
put(grammarAccess.getPropertyAccess().getTypeAssignment_0(), "rule__Property__TypeAssignment_0");
|
||||
put(grammarAccess.getPropertyAccess().getNameAssignment_1(), "rule__Property__NameAssignment_1");
|
||||
}
|
||||
};
|
||||
}
|
||||
return nameMappings.get(element);
|
||||
return nameMappings.getRuleName(element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getInitialHiddenTokens() {
|
||||
return new String[] { "RULE_WS", "RULE_ML_COMMENT", "RULE_SL_COMMENT" };
|
||||
|
@ -62,4 +77,12 @@ public class PartialContentAssistTestLanguageParser extends AbstractPartialConte
|
|||
public void setGrammarAccess(PartialContentAssistTestLanguageGrammarAccess grammarAccess) {
|
||||
this.grammarAccess = grammarAccess;
|
||||
}
|
||||
|
||||
public NameMappings getNameMappings() {
|
||||
return nameMappings;
|
||||
}
|
||||
|
||||
public void setNameMappings(NameMappings nameMappings) {
|
||||
this.nameMappings = nameMappings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.ide.contentassist.antlr;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.AbstractPartialContentAssistParser;
|
||||
|
@ -17,11 +18,73 @@ import org.eclipse.xtext.ide.tests.testlanguage.services.PartialSerializationTes
|
|||
|
||||
public class PartialSerializationTestLanguageParser extends AbstractPartialContentAssistParser {
|
||||
|
||||
@Singleton
|
||||
public static final class NameMappings {
|
||||
|
||||
private final Map<AbstractElement, String> mappings;
|
||||
|
||||
@Inject
|
||||
public NameMappings(PartialSerializationTestLanguageGrammarAccess grammarAccess) {
|
||||
ImmutableMap.Builder<AbstractElement, String> builder = ImmutableMap.builder();
|
||||
init(builder, grammarAccess);
|
||||
this.mappings = builder.build();
|
||||
}
|
||||
|
||||
public String getRuleName(AbstractElement element) {
|
||||
return mappings.get(element);
|
||||
}
|
||||
|
||||
private static void init(ImmutableMap.Builder<AbstractElement, String> builder, PartialSerializationTestLanguageGrammarAccess grammarAccess) {
|
||||
builder.put(grammarAccess.getModelAccess().getAlternatives(), "rule__Model__Alternatives");
|
||||
builder.put(grammarAccess.getNodeAccess().getAlternatives_4(), "rule__Node__Alternatives_4");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_0(), "rule__Model__Group_0__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_1(), "rule__Model__Group_1__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_2(), "rule__Model__Group_2__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_3(), "rule__Model__Group_3__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_4(), "rule__Model__Group_4__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_5(), "rule__Model__Group_5__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_6(), "rule__Model__Group_6__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_7(), "rule__Model__Group_7__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_8(), "rule__Model__Group_8__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_9(), "rule__Model__Group_9__0");
|
||||
builder.put(grammarAccess.getModelAccess().getGroup_10(), "rule__Model__Group_10__0");
|
||||
builder.put(grammarAccess.getOptionalValueAccess().getGroup(), "rule__OptionalValue__Group__0");
|
||||
builder.put(grammarAccess.getManyOptionalValuesAccess().getGroup(), "rule__ManyOptionalValues__Group__0");
|
||||
builder.put(grammarAccess.getOptionalChildAccess().getGroup(), "rule__OptionalChild__Group__0");
|
||||
builder.put(grammarAccess.getOptionalChildListAccess().getGroup(), "rule__OptionalChildList__Group__0");
|
||||
builder.put(grammarAccess.getImportAccess().getGroup(), "rule__Import__Group__0");
|
||||
builder.put(grammarAccess.getNodeAccess().getGroup(), "rule__Node__Group__0");
|
||||
builder.put(grammarAccess.getNodeAccess().getGroup_3(), "rule__Node__Group_3__0");
|
||||
builder.put(grammarAccess.getNodeAccess().getGroup_4_0(), "rule__Node__Group_4_0__0");
|
||||
builder.put(grammarAccess.getNodeAccess().getGroup_4_0_2(), "rule__Node__Group_4_0_2__0");
|
||||
builder.put(grammarAccess.getQualifiedNameAccess().getGroup(), "rule__QualifiedName__Group__0");
|
||||
builder.put(grammarAccess.getQualifiedNameAccess().getGroup_1(), "rule__QualifiedName__Group_1__0");
|
||||
builder.put(grammarAccess.getModelAccess().getClazzAssignment_9_1(), "rule__Model__ClazzAssignment_9_1");
|
||||
builder.put(grammarAccess.getMandatoryValueAccess().getNameAssignment(), "rule__MandatoryValue__NameAssignment");
|
||||
builder.put(grammarAccess.getOptionalValueAccess().getNameAssignment_2(), "rule__OptionalValue__NameAssignment_2");
|
||||
builder.put(grammarAccess.getManyOptionalValuesAccess().getNameAssignment_1(), "rule__ManyOptionalValues__NameAssignment_1");
|
||||
builder.put(grammarAccess.getManyMandatoryValuesAccess().getNameAssignment(), "rule__ManyMandatoryValues__NameAssignment");
|
||||
builder.put(grammarAccess.getMandatoryChildAccess().getChildAssignment(), "rule__MandatoryChild__ChildAssignment");
|
||||
builder.put(grammarAccess.getOptionalChildAccess().getChildAssignment_1(), "rule__OptionalChild__ChildAssignment_1");
|
||||
builder.put(grammarAccess.getMandatoryChildListAccess().getChildrenAssignment(), "rule__MandatoryChildList__ChildrenAssignment");
|
||||
builder.put(grammarAccess.getOptionalChildListAccess().getChildrenAssignment_1(), "rule__OptionalChildList__ChildrenAssignment_1");
|
||||
builder.put(grammarAccess.getImportAccess().getImportedNamespaceAssignment_1(), "rule__Import__ImportedNamespaceAssignment_1");
|
||||
builder.put(grammarAccess.getNodeAccess().getImportsAssignment_1(), "rule__Node__ImportsAssignment_1");
|
||||
builder.put(grammarAccess.getNodeAccess().getNameAssignment_2(), "rule__Node__NameAssignment_2");
|
||||
builder.put(grammarAccess.getNodeAccess().getRefsAssignment_3_1(), "rule__Node__RefsAssignment_3_1");
|
||||
builder.put(grammarAccess.getNodeAccess().getChildrenAssignment_4_0_1(), "rule__Node__ChildrenAssignment_4_0_1");
|
||||
builder.put(grammarAccess.getNodeAccess().getRefAssignment_4_0_2_1(), "rule__Node__RefAssignment_4_0_2_1");
|
||||
builder.put(grammarAccess.getEClassDeclAccess().getNameAssignment(), "rule__EClassDecl__NameAssignment");
|
||||
builder.put(grammarAccess.getEClassRefAccess().getRefAssignment(), "rule__EClassRef__RefAssignment");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private NameMappings nameMappings;
|
||||
|
||||
@Inject
|
||||
private PartialSerializationTestLanguageGrammarAccess grammarAccess;
|
||||
|
||||
private Map<AbstractElement, String> nameMappings;
|
||||
|
||||
@Override
|
||||
protected InternalPartialSerializationTestLanguageParser createParser() {
|
||||
InternalPartialSerializationTestLanguageParser result = new InternalPartialSerializationTestLanguageParser(null);
|
||||
|
@ -31,57 +94,9 @@ public class PartialSerializationTestLanguageParser extends AbstractPartialConte
|
|||
|
||||
@Override
|
||||
protected String getRuleName(AbstractElement element) {
|
||||
if (nameMappings == null) {
|
||||
nameMappings = new HashMap<AbstractElement, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(grammarAccess.getModelAccess().getAlternatives(), "rule__Model__Alternatives");
|
||||
put(grammarAccess.getNodeAccess().getAlternatives_4(), "rule__Node__Alternatives_4");
|
||||
put(grammarAccess.getModelAccess().getGroup_0(), "rule__Model__Group_0__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_1(), "rule__Model__Group_1__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_2(), "rule__Model__Group_2__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_3(), "rule__Model__Group_3__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_4(), "rule__Model__Group_4__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_5(), "rule__Model__Group_5__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_6(), "rule__Model__Group_6__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_7(), "rule__Model__Group_7__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_8(), "rule__Model__Group_8__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_9(), "rule__Model__Group_9__0");
|
||||
put(grammarAccess.getModelAccess().getGroup_10(), "rule__Model__Group_10__0");
|
||||
put(grammarAccess.getOptionalValueAccess().getGroup(), "rule__OptionalValue__Group__0");
|
||||
put(grammarAccess.getManyOptionalValuesAccess().getGroup(), "rule__ManyOptionalValues__Group__0");
|
||||
put(grammarAccess.getOptionalChildAccess().getGroup(), "rule__OptionalChild__Group__0");
|
||||
put(grammarAccess.getOptionalChildListAccess().getGroup(), "rule__OptionalChildList__Group__0");
|
||||
put(grammarAccess.getImportAccess().getGroup(), "rule__Import__Group__0");
|
||||
put(grammarAccess.getNodeAccess().getGroup(), "rule__Node__Group__0");
|
||||
put(grammarAccess.getNodeAccess().getGroup_3(), "rule__Node__Group_3__0");
|
||||
put(grammarAccess.getNodeAccess().getGroup_4_0(), "rule__Node__Group_4_0__0");
|
||||
put(grammarAccess.getNodeAccess().getGroup_4_0_2(), "rule__Node__Group_4_0_2__0");
|
||||
put(grammarAccess.getQualifiedNameAccess().getGroup(), "rule__QualifiedName__Group__0");
|
||||
put(grammarAccess.getQualifiedNameAccess().getGroup_1(), "rule__QualifiedName__Group_1__0");
|
||||
put(grammarAccess.getModelAccess().getClazzAssignment_9_1(), "rule__Model__ClazzAssignment_9_1");
|
||||
put(grammarAccess.getMandatoryValueAccess().getNameAssignment(), "rule__MandatoryValue__NameAssignment");
|
||||
put(grammarAccess.getOptionalValueAccess().getNameAssignment_2(), "rule__OptionalValue__NameAssignment_2");
|
||||
put(grammarAccess.getManyOptionalValuesAccess().getNameAssignment_1(), "rule__ManyOptionalValues__NameAssignment_1");
|
||||
put(grammarAccess.getManyMandatoryValuesAccess().getNameAssignment(), "rule__ManyMandatoryValues__NameAssignment");
|
||||
put(grammarAccess.getMandatoryChildAccess().getChildAssignment(), "rule__MandatoryChild__ChildAssignment");
|
||||
put(grammarAccess.getOptionalChildAccess().getChildAssignment_1(), "rule__OptionalChild__ChildAssignment_1");
|
||||
put(grammarAccess.getMandatoryChildListAccess().getChildrenAssignment(), "rule__MandatoryChildList__ChildrenAssignment");
|
||||
put(grammarAccess.getOptionalChildListAccess().getChildrenAssignment_1(), "rule__OptionalChildList__ChildrenAssignment_1");
|
||||
put(grammarAccess.getImportAccess().getImportedNamespaceAssignment_1(), "rule__Import__ImportedNamespaceAssignment_1");
|
||||
put(grammarAccess.getNodeAccess().getImportsAssignment_1(), "rule__Node__ImportsAssignment_1");
|
||||
put(grammarAccess.getNodeAccess().getNameAssignment_2(), "rule__Node__NameAssignment_2");
|
||||
put(grammarAccess.getNodeAccess().getRefsAssignment_3_1(), "rule__Node__RefsAssignment_3_1");
|
||||
put(grammarAccess.getNodeAccess().getChildrenAssignment_4_0_1(), "rule__Node__ChildrenAssignment_4_0_1");
|
||||
put(grammarAccess.getNodeAccess().getRefAssignment_4_0_2_1(), "rule__Node__RefAssignment_4_0_2_1");
|
||||
put(grammarAccess.getEClassDeclAccess().getNameAssignment(), "rule__EClassDecl__NameAssignment");
|
||||
put(grammarAccess.getEClassRefAccess().getRefAssignment(), "rule__EClassRef__RefAssignment");
|
||||
}
|
||||
};
|
||||
}
|
||||
return nameMappings.get(element);
|
||||
return nameMappings.getRuleName(element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getInitialHiddenTokens() {
|
||||
return new String[] { "RULE_WS", "RULE_ML_COMMENT", "RULE_SL_COMMENT" };
|
||||
|
@ -94,4 +109,12 @@ public class PartialSerializationTestLanguageParser extends AbstractPartialConte
|
|||
public void setGrammarAccess(PartialSerializationTestLanguageGrammarAccess grammarAccess) {
|
||||
this.grammarAccess = grammarAccess;
|
||||
}
|
||||
|
||||
public NameMappings getNameMappings() {
|
||||
return nameMappings;
|
||||
}
|
||||
|
||||
public void setNameMappings(NameMappings nameMappings) {
|
||||
this.nameMappings = nameMappings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@
|
|||
*/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.ide.contentassist.antlr;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.HashMap;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Map;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.AbstractContentAssistParser;
|
||||
|
@ -17,11 +18,67 @@ import org.eclipse.xtext.ide.tests.testlanguage.services.TestLanguageGrammarAcce
|
|||
|
||||
public class TestLanguageParser extends AbstractContentAssistParser {
|
||||
|
||||
@Singleton
|
||||
public static final class NameMappings {
|
||||
|
||||
private final Map<AbstractElement, String> mappings;
|
||||
|
||||
@Inject
|
||||
public NameMappings(TestLanguageGrammarAccess grammarAccess) {
|
||||
ImmutableMap.Builder<AbstractElement, String> builder = ImmutableMap.builder();
|
||||
init(builder, grammarAccess);
|
||||
this.mappings = builder.build();
|
||||
}
|
||||
|
||||
public String getRuleName(AbstractElement element) {
|
||||
return mappings.get(element);
|
||||
}
|
||||
|
||||
private static void init(ImmutableMap.Builder<AbstractElement, String> builder, TestLanguageGrammarAccess grammarAccess) {
|
||||
builder.put(grammarAccess.getMemberAccess().getAlternatives(), "rule__Member__Alternatives");
|
||||
builder.put(grammarAccess.getTypeAccess().getAlternatives_0(), "rule__Type__Alternatives_0");
|
||||
builder.put(grammarAccess.getPrimitiveTypeAccess().getNameAlternatives_0(), "rule__PrimitiveType__NameAlternatives_0");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getGroup(), "rule__TypeDeclaration__Group__0");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getGroup_2(), "rule__TypeDeclaration__Group_2__0");
|
||||
builder.put(grammarAccess.getPropertyAccess().getGroup(), "rule__Property__Group__0");
|
||||
builder.put(grammarAccess.getTypeAccess().getGroup(), "rule__Type__Group__0");
|
||||
builder.put(grammarAccess.getTypeAccess().getGroup_1(), "rule__Type__Group_1__0");
|
||||
builder.put(grammarAccess.getOperationAccess().getGroup(), "rule__Operation__Group__0");
|
||||
builder.put(grammarAccess.getOperationAccess().getGroup_4(), "rule__Operation__Group_4__0");
|
||||
builder.put(grammarAccess.getOperationAccess().getGroup_4_1(), "rule__Operation__Group_4_1__0");
|
||||
builder.put(grammarAccess.getOperationAccess().getGroup_6(), "rule__Operation__Group_6__0");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getGroup(), "rule__OperationCall__Group__0");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getGroup_2(), "rule__OperationCall__Group_2__0");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getGroup_2_1(), "rule__OperationCall__Group_2_1__0");
|
||||
builder.put(grammarAccess.getParameterAccess().getGroup(), "rule__Parameter__Group__0");
|
||||
builder.put(grammarAccess.getModelAccess().getTypesAssignment(), "rule__Model__TypesAssignment");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getNameAssignment_1(), "rule__TypeDeclaration__NameAssignment_1");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getSuperTypeAssignment_2_1(), "rule__TypeDeclaration__SuperTypeAssignment_2_1");
|
||||
builder.put(grammarAccess.getTypeDeclarationAccess().getMembersAssignment_4(), "rule__TypeDeclaration__MembersAssignment_4");
|
||||
builder.put(grammarAccess.getPropertyAccess().getTypeAssignment_0(), "rule__Property__TypeAssignment_0");
|
||||
builder.put(grammarAccess.getPropertyAccess().getNameAssignment_1(), "rule__Property__NameAssignment_1");
|
||||
builder.put(grammarAccess.getTypeAccess().getArrayDiemensionsAssignment_1_0(), "rule__Type__ArrayDiemensionsAssignment_1_0");
|
||||
builder.put(grammarAccess.getOperationAccess().getNameAssignment_2(), "rule__Operation__NameAssignment_2");
|
||||
builder.put(grammarAccess.getOperationAccess().getParamsAssignment_4_0(), "rule__Operation__ParamsAssignment_4_0");
|
||||
builder.put(grammarAccess.getOperationAccess().getParamsAssignment_4_1_1(), "rule__Operation__ParamsAssignment_4_1_1");
|
||||
builder.put(grammarAccess.getOperationAccess().getReturnTypeAssignment_6_1(), "rule__Operation__ReturnTypeAssignment_6_1");
|
||||
builder.put(grammarAccess.getOperationAccess().getOperationCallAssignment_8(), "rule__Operation__OperationCallAssignment_8");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getOperationAssignment_0(), "rule__OperationCall__OperationAssignment_0");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getParamsAssignment_2_0(), "rule__OperationCall__ParamsAssignment_2_0");
|
||||
builder.put(grammarAccess.getOperationCallAccess().getParamsAssignment_2_1_1(), "rule__OperationCall__ParamsAssignment_2_1_1");
|
||||
builder.put(grammarAccess.getParameterAccess().getNameAssignment_1(), "rule__Parameter__NameAssignment_1");
|
||||
builder.put(grammarAccess.getParameterAccess().getTypeAssignment_3(), "rule__Parameter__TypeAssignment_3");
|
||||
builder.put(grammarAccess.getTypeReferenceAccess().getTypeRefAssignment(), "rule__TypeReference__TypeRefAssignment");
|
||||
builder.put(grammarAccess.getPrimitiveTypeAccess().getNameAssignment(), "rule__PrimitiveType__NameAssignment");
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
private NameMappings nameMappings;
|
||||
|
||||
@Inject
|
||||
private TestLanguageGrammarAccess grammarAccess;
|
||||
|
||||
private Map<AbstractElement, String> nameMappings;
|
||||
|
||||
@Override
|
||||
protected InternalTestLanguageParser createParser() {
|
||||
InternalTestLanguageParser result = new InternalTestLanguageParser(null);
|
||||
|
@ -31,51 +88,9 @@ public class TestLanguageParser extends AbstractContentAssistParser {
|
|||
|
||||
@Override
|
||||
protected String getRuleName(AbstractElement element) {
|
||||
if (nameMappings == null) {
|
||||
nameMappings = new HashMap<AbstractElement, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(grammarAccess.getMemberAccess().getAlternatives(), "rule__Member__Alternatives");
|
||||
put(grammarAccess.getTypeAccess().getAlternatives_0(), "rule__Type__Alternatives_0");
|
||||
put(grammarAccess.getPrimitiveTypeAccess().getNameAlternatives_0(), "rule__PrimitiveType__NameAlternatives_0");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getGroup(), "rule__TypeDeclaration__Group__0");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getGroup_2(), "rule__TypeDeclaration__Group_2__0");
|
||||
put(grammarAccess.getPropertyAccess().getGroup(), "rule__Property__Group__0");
|
||||
put(grammarAccess.getTypeAccess().getGroup(), "rule__Type__Group__0");
|
||||
put(grammarAccess.getTypeAccess().getGroup_1(), "rule__Type__Group_1__0");
|
||||
put(grammarAccess.getOperationAccess().getGroup(), "rule__Operation__Group__0");
|
||||
put(grammarAccess.getOperationAccess().getGroup_4(), "rule__Operation__Group_4__0");
|
||||
put(grammarAccess.getOperationAccess().getGroup_4_1(), "rule__Operation__Group_4_1__0");
|
||||
put(grammarAccess.getOperationAccess().getGroup_6(), "rule__Operation__Group_6__0");
|
||||
put(grammarAccess.getOperationCallAccess().getGroup(), "rule__OperationCall__Group__0");
|
||||
put(grammarAccess.getOperationCallAccess().getGroup_2(), "rule__OperationCall__Group_2__0");
|
||||
put(grammarAccess.getOperationCallAccess().getGroup_2_1(), "rule__OperationCall__Group_2_1__0");
|
||||
put(grammarAccess.getParameterAccess().getGroup(), "rule__Parameter__Group__0");
|
||||
put(grammarAccess.getModelAccess().getTypesAssignment(), "rule__Model__TypesAssignment");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getNameAssignment_1(), "rule__TypeDeclaration__NameAssignment_1");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getSuperTypeAssignment_2_1(), "rule__TypeDeclaration__SuperTypeAssignment_2_1");
|
||||
put(grammarAccess.getTypeDeclarationAccess().getMembersAssignment_4(), "rule__TypeDeclaration__MembersAssignment_4");
|
||||
put(grammarAccess.getPropertyAccess().getTypeAssignment_0(), "rule__Property__TypeAssignment_0");
|
||||
put(grammarAccess.getPropertyAccess().getNameAssignment_1(), "rule__Property__NameAssignment_1");
|
||||
put(grammarAccess.getTypeAccess().getArrayDiemensionsAssignment_1_0(), "rule__Type__ArrayDiemensionsAssignment_1_0");
|
||||
put(grammarAccess.getOperationAccess().getNameAssignment_2(), "rule__Operation__NameAssignment_2");
|
||||
put(grammarAccess.getOperationAccess().getParamsAssignment_4_0(), "rule__Operation__ParamsAssignment_4_0");
|
||||
put(grammarAccess.getOperationAccess().getParamsAssignment_4_1_1(), "rule__Operation__ParamsAssignment_4_1_1");
|
||||
put(grammarAccess.getOperationAccess().getReturnTypeAssignment_6_1(), "rule__Operation__ReturnTypeAssignment_6_1");
|
||||
put(grammarAccess.getOperationAccess().getOperationCallAssignment_8(), "rule__Operation__OperationCallAssignment_8");
|
||||
put(grammarAccess.getOperationCallAccess().getOperationAssignment_0(), "rule__OperationCall__OperationAssignment_0");
|
||||
put(grammarAccess.getOperationCallAccess().getParamsAssignment_2_0(), "rule__OperationCall__ParamsAssignment_2_0");
|
||||
put(grammarAccess.getOperationCallAccess().getParamsAssignment_2_1_1(), "rule__OperationCall__ParamsAssignment_2_1_1");
|
||||
put(grammarAccess.getParameterAccess().getNameAssignment_1(), "rule__Parameter__NameAssignment_1");
|
||||
put(grammarAccess.getParameterAccess().getTypeAssignment_3(), "rule__Parameter__TypeAssignment_3");
|
||||
put(grammarAccess.getTypeReferenceAccess().getTypeRefAssignment(), "rule__TypeReference__TypeRefAssignment");
|
||||
put(grammarAccess.getPrimitiveTypeAccess().getNameAssignment(), "rule__PrimitiveType__NameAssignment");
|
||||
}
|
||||
};
|
||||
}
|
||||
return nameMappings.get(element);
|
||||
return nameMappings.getRuleName(element);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String[] getInitialHiddenTokens() {
|
||||
return new String[] { "RULE_WS", "RULE_ML_COMMENT", "RULE_SL_COMMENT" };
|
||||
|
@ -88,4 +103,12 @@ public class TestLanguageParser extends AbstractContentAssistParser {
|
|||
public void setGrammarAccess(TestLanguageGrammarAccess grammarAccess) {
|
||||
this.grammarAccess = grammarAccess;
|
||||
}
|
||||
|
||||
public NameMappings getNameMappings() {
|
||||
return nameMappings;
|
||||
}
|
||||
|
||||
public void setNameMappings(NameMappings nameMappings) {
|
||||
this.nameMappings = nameMappings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,17 +71,15 @@ public class PartialSerializationTestLanguageSyntacticSequencer extends Abstract
|
|||
* This ambiguous syntax occurs at:
|
||||
* (rule start) '#1' (ambiguity) '{' 'ref' ref=[Node|QualifiedName]
|
||||
* (rule start) '#1' (ambiguity) '{' children+=Node
|
||||
* (rule start) '#1' (ambiguity) (';' | ('{' '}')) (rule start)
|
||||
* (rule start) '#1' (ambiguity) (('{' '}') | ';') (rule start)
|
||||
* (rule start) (ambiguity) '{' 'ref' ref=[Node|QualifiedName]
|
||||
* (rule start) (ambiguity) '{' children+=Node
|
||||
* (rule start) (ambiguity) (('{' '}') | ';') (rule start)
|
||||
* imports+=Import (ambiguity) '{' 'ref' ref=[Node|QualifiedName]
|
||||
* imports+=Import (ambiguity) '{' children+=Node
|
||||
* imports+=Import (ambiguity) (';' | ('{' '}')) (rule end)
|
||||
* imports+=Import (ambiguity) (('{' '}') | ';') (rule end)
|
||||
* name=ID (ambiguity) '{' 'ref' ref=[Node|QualifiedName]
|
||||
* name=ID (ambiguity) '{' children+=Node
|
||||
* name=ID (ambiguity) (';' | ('{' '}')) (rule end)
|
||||
* name=ID (ambiguity) (('{' '}') | ';') (rule end)
|
||||
*/
|
||||
protected void emit_Node_RefsKeyword_3_0_q(EObject semanticObject, ISynNavigable transition, List<INode> nodes) {
|
||||
|
@ -90,7 +88,7 @@ public class PartialSerializationTestLanguageSyntacticSequencer extends Abstract
|
|||
|
||||
/**
|
||||
* Ambiguous syntax:
|
||||
* ';' | ('{' '}')
|
||||
* ('{' '}') | ';'
|
||||
*
|
||||
* This ambiguous syntax occurs at:
|
||||
* (rule start) '#1' 'refs'? (ambiguity) (rule start)
|
||||
|
|
|
@ -260,7 +260,8 @@ public class IndentationAwareUiTestLanguageGrammarAccess extends AbstractGrammar
|
|||
return getChildListAccess().getRule();
|
||||
}
|
||||
|
||||
//@ Override terminal SL_COMMENT:
|
||||
//@Override
|
||||
//terminal SL_COMMENT:
|
||||
// '//' !('\n' | '\r')*;
|
||||
public TerminalRule getSL_COMMENTRule() {
|
||||
return tSL_COMMENT;
|
||||
|
|
|
@ -7,30 +7,13 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.TokenSource;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.LexerIdeBindings;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.AbstractInternalContentAssistParser;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.InfiniteRecursion;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.Lexer;
|
||||
import org.eclipse.xtext.ide.editor.partialEditing.IPartialEditingContentAssistParser;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
import org.eclipse.xtext.xtext.RuleNames;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.name.Named;
|
||||
|
@ -38,217 +21,19 @@ import com.google.inject.name.Named;
|
|||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public abstract class AbstractContentAssistParser extends BaseContentAssistParser implements IContentAssistParser, IPartialEditingContentAssistParser {
|
||||
public abstract class AbstractContentAssistParser
|
||||
extends BaseContentAssistParser<FollowElement, LookAheadTerminal, AbstractInternalContentAssistParser>
|
||||
implements IContentAssistParser, IPartialEditingContentAssistParser {
|
||||
|
||||
@Inject
|
||||
@Named(LexerIdeBindings.CONTENT_ASSIST)
|
||||
private Provider<Lexer> lexerProvider;
|
||||
|
||||
@Inject
|
||||
private RuleNames ruleNames;
|
||||
|
||||
private AbstractRule entryRule;
|
||||
|
||||
@Inject
|
||||
private void initEntryRule(IGrammarAccess grammar) {
|
||||
initializeFor(grammar.getGrammar().getRules().get(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeFor(AbstractRule rule) {
|
||||
this.entryRule = rule;
|
||||
}
|
||||
|
||||
public AbstractRule getEntryRule() {
|
||||
return entryRule;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TokenSource createLexer(CharStream stream) {
|
||||
Lexer lexer = lexerProvider.get();
|
||||
lexer.setCharStream(stream);
|
||||
return lexer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<FollowElement> getFollowElements(FollowElement element) {
|
||||
if (element.getLookAhead() <= 1)
|
||||
throw new IllegalArgumentException("lookahead may not be less than or equal to 1");
|
||||
Collection<FollowElement> result = new ArrayList<FollowElement>();
|
||||
for(AbstractElement elementToParse: getElementsToParse(element)) {
|
||||
elementToParse = unwrapSingleElementGroups(elementToParse);
|
||||
String ruleName = getRuleName(elementToParse);
|
||||
String[][] allRuleNames = getRequiredRuleNames(ruleName, element.getParamStack(), elementToParse);
|
||||
for (String[] ruleNames: allRuleNames) {
|
||||
for(int i = 0; i < ruleNames.length; i++) {
|
||||
AbstractInternalContentAssistParser parser = createParser();
|
||||
parser.setUnorderedGroupHelper(createUnorderedGroupHelper());
|
||||
parser.getUnorderedGroupHelper().initializeWith(parser);
|
||||
ObservableXtextTokenStream tokens = setTokensFromFollowElement(parser, element);
|
||||
tokens.setListener(parser);
|
||||
parser.getGrammarElements().addAll(element.getTrace());
|
||||
parser.getGrammarElements().add(elementToParse);
|
||||
parser.getLocalTrace().addAll(element.getLocalTrace());
|
||||
parser.getLocalTrace().add(elementToParse);
|
||||
parser.getParamStack().addAll(element.getParamStack());
|
||||
if (elementToParse instanceof UnorderedGroup && element.getGrammarElement() == elementToParse) {
|
||||
UnorderedGroup group = (UnorderedGroup) elementToParse;
|
||||
IUnorderedGroupHelper helper = getInitializedUnorderedGroupHelper(element, parser, group);
|
||||
parser.setUnorderedGroupHelper(ignoreFirstEntrance(helper));
|
||||
}
|
||||
Collection<FollowElement> elements = getFollowElements(parser, elementToParse, ruleNames, i);
|
||||
result.addAll(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected ObservableXtextTokenStream setTokensFromFollowElement(AbstractInternalContentAssistParser parser,
|
||||
FollowElement element) {
|
||||
final Iterator<LookAheadTerminal> iter = element.getLookAheadTerminals().iterator();
|
||||
ObservableXtextTokenStream tokens = new ObservableXtextTokenStream(new LookAheadBasedTokenSource(iter), parser);
|
||||
parser.setTokenStream(tokens);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected IUnorderedGroupHelper getInitializedUnorderedGroupHelper(FollowElement element,
|
||||
AbstractInternalContentAssistParser parser, UnorderedGroup group) {
|
||||
final IUnorderedGroupHelper helper = parser.getUnorderedGroupHelper();
|
||||
helper.enter(group);
|
||||
for(AbstractElement consumed: element.getHandledUnorderedGroupElements()) {
|
||||
parser.before(consumed);
|
||||
helper.select(group, group.getElements().indexOf(consumed));
|
||||
helper.returnFromSelection(group);
|
||||
parser.after(consumed);
|
||||
}
|
||||
return helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Collection<FollowElement> getFollowElements(
|
||||
final AbstractInternalContentAssistParser parser,
|
||||
final AbstractElement elementToParse,
|
||||
String[] ruleNames,
|
||||
final int startIndex) {
|
||||
try {
|
||||
EofListener listener = createEofListener(parser, elementToParse);
|
||||
int i = startIndex;
|
||||
Collection<FollowElement> result = null;
|
||||
while(i < ruleNames.length && !listener.wasEof && listener.consumedSomething) {
|
||||
listener.reset();
|
||||
String ruleName = ruleNames[i];
|
||||
result = getFollowElements(parser, ruleName, true);
|
||||
if (i == ruleNames.length - 1 && !GrammarUtil.isMultipleCardinality(elementToParse)) {
|
||||
if (listener.consumedSomething || listener.announcedEofWithLA)
|
||||
return result;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (!listener.wasEof && ruleNames.length != 1)
|
||||
i++;
|
||||
if (ruleNames.length > 2)
|
||||
throw new IllegalArgumentException("The following lines assume that we have at most two rules to call.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected EofListener createEofListener(final AbstractInternalContentAssistParser parser,
|
||||
final AbstractElement elementToParse) {
|
||||
return new EofListener(parser, elementToParse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Set<FollowElement> getFollowElements(final AbstractInternalContentAssistParser parser, String ruleName, boolean swallowInfiniteRecursion)
|
||||
throws Exception {
|
||||
Method method = parser.getClass().getMethod(ruleName);
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(parser);
|
||||
} catch(InvocationTargetException targetException) {
|
||||
Throwable cause = targetException.getCause();
|
||||
if (cause instanceof InfiniteRecursion) {
|
||||
if (swallowInfiniteRecursion) {
|
||||
return parser.getFollowElements();
|
||||
} else {
|
||||
throw (InfiniteRecursion) cause;
|
||||
}
|
||||
}
|
||||
throw targetException;
|
||||
}
|
||||
return parser.getFollowElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Collection<AbstractElement> getElementsToParse(FollowElement element) {
|
||||
return getElementsToParse(element.getGrammarElement(), element.getHandledUnorderedGroupElements());
|
||||
}
|
||||
|
||||
protected abstract AbstractInternalContentAssistParser createParser();
|
||||
|
||||
protected Collection<FollowElement> getFollowElements(AbstractInternalContentAssistParser parser) {
|
||||
return getFollowElements(parser, entryRule);
|
||||
}
|
||||
|
||||
protected Collection<FollowElement> getFollowElements(AbstractInternalContentAssistParser parser,
|
||||
AbstractRule rule) {
|
||||
String ruleName = ruleNames.getAntlrRuleName(rule);
|
||||
return getFollowElements(parser, ruleName);
|
||||
}
|
||||
|
||||
protected Collection<FollowElement> getFollowElements(AbstractInternalContentAssistParser parser, String ruleName) {
|
||||
try {
|
||||
return getFollowElements(parser, ruleName, false);
|
||||
} catch (InfiniteRecursion e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String[] getInitialHiddenTokens();
|
||||
|
||||
@Override
|
||||
public Collection<FollowElement> getFollowElements(String input, boolean strict) {
|
||||
TokenSource tokenSource = createTokenSource(input);
|
||||
AbstractInternalContentAssistParser parser = createParser();
|
||||
parser.setStrict(strict);
|
||||
ObservableXtextTokenStream tokens = new ObservableXtextTokenStream(tokenSource, parser);
|
||||
tokens.setInitialHiddenTokens(getInitialHiddenTokens());
|
||||
parser.setTokenStream(tokens);
|
||||
IUnorderedGroupHelper helper = createUnorderedGroupHelper();
|
||||
parser.setUnorderedGroupHelper(helper);
|
||||
helper.initializeWith(parser);
|
||||
tokens.setListener(parser);
|
||||
try {
|
||||
return Lists.newArrayList(getFollowElements(parser));
|
||||
} catch(InfiniteRecursion infinite) {
|
||||
return Lists.newArrayList(parser.getFollowElements());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected RuleNames getRuleNames() {
|
||||
return ruleNames;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,26 +9,8 @@ package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.antlr.runtime.TokenSource;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.AbstractInternalContentAssistParser;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.InfiniteRecursion;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.ILeafNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
import org.eclipse.xtext.parser.IParseResult;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
import org.eclipse.xtext.xtext.RuleNames;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
|
@ -41,120 +23,9 @@ public abstract class AbstractPartialContentAssistParser extends AbstractContent
|
|||
@Inject
|
||||
private EntryPointFinder entryPointFinder;
|
||||
|
||||
@Inject
|
||||
private RuleNames ruleNames;
|
||||
|
||||
@Override
|
||||
public Collection<FollowElement> getFollowElements(IParseResult parseResult, int offset, boolean strict) {
|
||||
ICompositeNode entryPoint = entryPointFinder.findEntryPoint(parseResult, offset);
|
||||
if (entryPoint != null) {
|
||||
String parseMe = getTextToParse(parseResult, entryPoint, offset);
|
||||
TokenSource tokenSource = createTokenSource(parseMe);
|
||||
AbstractInternalContentAssistParser parser = createParser();
|
||||
parser.setStrict(strict);
|
||||
ObservableXtextTokenStream tokens = new ObservableXtextTokenStream(tokenSource, parser);
|
||||
tokens.setInitialHiddenTokens(getInitialHiddenTokens());
|
||||
parser.setTokenStream(tokens);
|
||||
IUnorderedGroupHelper helper = createUnorderedGroupHelper();
|
||||
parser.setUnorderedGroupHelper(helper);
|
||||
helper.initializeWith(parser);
|
||||
tokens.setListener(parser);
|
||||
try {
|
||||
Collection<FollowElement> followElements = getFollowElements(parser, getEntryGrammarElement(entryPoint));
|
||||
return Lists.newArrayList(followElements);
|
||||
} catch (InfiniteRecursion infinite) {
|
||||
return Lists.newArrayList(parser.getFollowElements());
|
||||
}
|
||||
} else {
|
||||
String text = parseResult.getRootNode().getText();
|
||||
String parseMe = text.substring(0, offset);
|
||||
initializeFor(NodeModelUtils.getEntryParserRule(parseResult.getRootNode()));
|
||||
Collection<FollowElement> followElements = getFollowElements(parseMe, strict);
|
||||
return followElements;
|
||||
}
|
||||
return getFollowElements(parseResult, entryPointFinder, offset, strict);
|
||||
}
|
||||
|
||||
protected AbstractElement getEntryGrammarElement(ICompositeNode entryPoint) {
|
||||
EObject grammarElement = entryPoint.getGrammarElement();
|
||||
if (grammarElement instanceof RuleCall) {
|
||||
AbstractRule rule = ((RuleCall) grammarElement).getRule();
|
||||
if (rule instanceof ParserRule) {
|
||||
if (!GrammarUtil.isMultipleCardinality(rule.getAlternatives())) {
|
||||
grammarElement = rule.getAlternatives();
|
||||
}
|
||||
}
|
||||
} else if (grammarElement instanceof ParserRule) {
|
||||
grammarElement = ((ParserRule) grammarElement).getAlternatives();
|
||||
} else if (grammarElement instanceof CrossReference) {
|
||||
grammarElement = GrammarUtil.containingAssignment(grammarElement);
|
||||
}
|
||||
AbstractElement result = (AbstractElement) grammarElement;
|
||||
if (result instanceof Action) {
|
||||
return getEntryGrammarElement((ICompositeNode) entryPoint.getFirstChild());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getTextToParse(IParseResult parseResult, ICompositeNode entryPoint, int offset) {
|
||||
StringBuilder result = new StringBuilder(offset - entryPoint.getTotalOffset());
|
||||
appendTextToParse(entryPoint, offset, false, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected boolean appendTextToParse(ICompositeNode node, int offset, boolean skipOptional, StringBuilder result) {
|
||||
for (INode child : node.getChildren()) {
|
||||
if (child instanceof ILeafNode) {
|
||||
String text = child.getText();
|
||||
if (child.getTotalEndOffset() >= offset) {
|
||||
String sub = text.substring(0, offset - child.getTotalOffset());
|
||||
result.append(sub);
|
||||
return true;
|
||||
} else {
|
||||
result.append(text);
|
||||
}
|
||||
} else {
|
||||
if (!skipOptional) {
|
||||
if (appendTextToParse((ICompositeNode) child, offset, child.getTotalEndOffset() < offset, result)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
String skippedAs = getReplacement((ICompositeNode) child);
|
||||
if (skippedAs != null) {
|
||||
result.append(skippedAs);
|
||||
} else {
|
||||
if (appendTextToParse((ICompositeNode) child, offset, true, result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a syntactically correct replacement for nodes whose real content does not need to be parsed.
|
||||
* @return the replacement or <code>null</code>
|
||||
*/
|
||||
protected String getReplacement(ICompositeNode node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Collection<FollowElement> getFollowElements(AbstractInternalContentAssistParser parser,
|
||||
AbstractElement entryPoint) {
|
||||
String ruleName = getRuleName(entryPoint);
|
||||
if (ruleName == null) {
|
||||
if (entryPoint instanceof RuleCall) {
|
||||
RuleCall call = (RuleCall) entryPoint;
|
||||
AbstractRule rule = call.getRule();
|
||||
if (rule instanceof ParserRule) {
|
||||
ruleName = ruleNames.getAntlrRuleName(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ruleName == null) {
|
||||
throw new IllegalStateException("entryPoint: " + entryPoint);
|
||||
}
|
||||
return getFollowElements(parser, ruleName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,51 +7,268 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.runtime.ANTLRStringStream;
|
||||
import org.antlr.runtime.CharStream;
|
||||
import org.antlr.runtime.TokenSource;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.AbstractRule;
|
||||
import org.eclipse.xtext.Action;
|
||||
import org.eclipse.xtext.Alternatives;
|
||||
import org.eclipse.xtext.CompoundElement;
|
||||
import org.eclipse.xtext.CrossReference;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.Group;
|
||||
import org.eclipse.xtext.IGrammarAccess;
|
||||
import org.eclipse.xtext.ParserRule;
|
||||
import org.eclipse.xtext.RuleCall;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.BaseInternalContentAssistParser;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.InfiniteRecursion;
|
||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
||||
import org.eclipse.xtext.nodemodel.ILeafNode;
|
||||
import org.eclipse.xtext.nodemodel.INode;
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
|
||||
import org.eclipse.xtext.parser.IParseResult;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
import org.eclipse.xtext.xtext.RuleNames;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
/**
|
||||
* Abstract base type for the {@link AbstractContentAssistParser} and the deprecated
|
||||
* equivalent in the xtext.ui bundle.
|
||||
* Abstract base type for the {@link AbstractContentAssistParser} and the deprecated equivalent in the xtext.ui bundle.
|
||||
*
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
* @since 2.14
|
||||
*/
|
||||
public abstract class BaseContentAssistParser {
|
||||
|
||||
public abstract class BaseContentAssistParser<FE extends BaseFollowElement<LATerminal>, LATerminal extends ILookAheadTerminal, InternalParser extends BaseInternalContentAssistParser<FE, LATerminal>> {
|
||||
|
||||
@Inject
|
||||
private Provider<IUnorderedGroupHelper> unorderedGroupHelper;
|
||||
|
||||
|
||||
@Inject
|
||||
private RequiredRuleNameComputer requiredRuleNameComputer;
|
||||
|
||||
|
||||
@Inject
|
||||
private RuleNames ruleNames;
|
||||
|
||||
private AbstractRule entryRule;
|
||||
|
||||
/**
|
||||
* Create a token source for the given input based on the bound lexer.
|
||||
*/
|
||||
protected TokenSource createTokenSource(String input) {
|
||||
return createLexer(new ANTLRStringStream(input));
|
||||
}
|
||||
|
||||
protected abstract TokenSource createLexer(CharStream stream);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the elementToParse or the innermost element if the elementToParse is
|
||||
* a (parameterized) group that contains only a single element.
|
||||
* Create a token source for the given input based on the bound lexer.
|
||||
*/
|
||||
protected abstract TokenSource createLexer(CharStream stream);
|
||||
|
||||
public Collection<FE> getFollowElements(FE element) {
|
||||
if (element.getLookAhead() <= 1)
|
||||
throw new IllegalArgumentException("lookahead may not be less than or equal to 1");
|
||||
Collection<FE> result = new ArrayList<FE>();
|
||||
for (AbstractElement elementToParse : getElementsToParse(element)) {
|
||||
elementToParse = unwrapSingleElementGroups(elementToParse);
|
||||
String ruleName = getRuleName(elementToParse);
|
||||
String[][] allRuleNames = getRequiredRuleNames(ruleName, element.getParamStack(), elementToParse);
|
||||
for (String[] ruleNames : allRuleNames) {
|
||||
for (int i = 0; i < ruleNames.length; i++) {
|
||||
InternalParser parser = createParser();
|
||||
parser.setUnorderedGroupHelper(createUnorderedGroupHelper());
|
||||
parser.getUnorderedGroupHelper().initializeWith(parser);
|
||||
ObservableXtextTokenStream tokens = setTokensFromFollowElement(parser, element);
|
||||
tokens.setListener(parser);
|
||||
parser.getGrammarElements().addAll(element.getTrace());
|
||||
parser.getGrammarElements().add(elementToParse);
|
||||
parser.getLocalTrace().addAll(element.getLocalTrace());
|
||||
parser.getLocalTrace().add(elementToParse);
|
||||
parser.getParamStack().addAll(element.getParamStack());
|
||||
if (elementToParse instanceof UnorderedGroup && element.getGrammarElement() == elementToParse) {
|
||||
UnorderedGroup group = (UnorderedGroup) elementToParse;
|
||||
IUnorderedGroupHelper helper = getInitializedUnorderedGroupHelper(element, parser, group);
|
||||
parser.setUnorderedGroupHelper(ignoreFirstEntrance(helper));
|
||||
}
|
||||
Collection<FE> elements = getFollowElements(parser, elementToParse, ruleNames, i);
|
||||
result.addAll(elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract InternalParser createParser();
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected ObservableXtextTokenStream setTokensFromFollowElement(InternalParser parser, FE element) {
|
||||
final Iterator<LATerminal> iter = element.getLookAheadTerminals().iterator();
|
||||
LookAheadBasedTokenSource tokenSource = new LookAheadBasedTokenSource(iter);
|
||||
ObservableXtextTokenStream tokens = createObservableTokenStream(tokenSource, parser);
|
||||
parser.setTokenStream(tokens);
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Collection<FE> getFollowElements(final InternalParser parser, final AbstractElement elementToParse,
|
||||
String[] ruleNames, final int startIndex) {
|
||||
try {
|
||||
EofListener listener = createEofListener(parser, elementToParse);
|
||||
int i = startIndex;
|
||||
Collection<FE> result = null;
|
||||
while (i < ruleNames.length && !listener.wasEof && listener.consumedSomething) {
|
||||
listener.reset();
|
||||
String ruleName = ruleNames[i];
|
||||
result = getFollowElements(parser, ruleName, true);
|
||||
if (i == ruleNames.length - 1 && !GrammarUtil.isMultipleCardinality(elementToParse)) {
|
||||
if (listener.consumedSomething || listener.announcedEofWithLA)
|
||||
return result;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (!listener.wasEof && ruleNames.length != 1)
|
||||
i++;
|
||||
if (ruleNames.length > 2)
|
||||
throw new IllegalArgumentException(
|
||||
"The following lines assume that we have at most two rules to call.");
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected EofListener createEofListener(final InternalParser parser, final AbstractElement elementToParse) {
|
||||
return new EofListener(parser, elementToParse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Set<FE> getFollowElements(final InternalParser parser, String ruleName, boolean swallowInfiniteRecursion)
|
||||
throws Exception {
|
||||
Method method = parser.getClass().getMethod(ruleName);
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(parser);
|
||||
} catch (InvocationTargetException targetException) {
|
||||
Throwable cause = targetException.getCause();
|
||||
if (cause instanceof InfiniteRecursion) {
|
||||
if (swallowInfiniteRecursion) {
|
||||
return parser.getFollowElements();
|
||||
} else {
|
||||
throw (InfiniteRecursion) cause;
|
||||
}
|
||||
}
|
||||
throw targetException;
|
||||
}
|
||||
return parser.getFollowElements();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected Collection<AbstractElement> getElementsToParse(FE element) {
|
||||
return getElementsToParse(element.getGrammarElement(), element.getHandledUnorderedGroupElements());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected ObservableXtextTokenStream createObservableTokenStream(LookAheadBasedTokenSource tokenSource,
|
||||
InternalParser parser) {
|
||||
return new ObservableXtextTokenStream(tokenSource, parser);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected IUnorderedGroupHelper getInitializedUnorderedGroupHelper(FE element, InternalParser parser,
|
||||
UnorderedGroup group) {
|
||||
final IUnorderedGroupHelper helper = parser.getUnorderedGroupHelper();
|
||||
helper.enter(group);
|
||||
for (AbstractElement consumed : element.getHandledUnorderedGroupElements()) {
|
||||
parser.before(consumed);
|
||||
helper.select(group, group.getElements().indexOf(consumed));
|
||||
helper.returnFromSelection(group);
|
||||
parser.after(consumed);
|
||||
}
|
||||
return helper;
|
||||
}
|
||||
|
||||
@Inject
|
||||
private void initEntryRule(IGrammarAccess grammar) {
|
||||
initializeFor(grammar.getGrammar().getRules().get(0));
|
||||
}
|
||||
|
||||
public void initializeFor(AbstractRule rule) {
|
||||
this.entryRule = rule;
|
||||
}
|
||||
|
||||
public AbstractRule getEntryRule() {
|
||||
return entryRule;
|
||||
}
|
||||
|
||||
protected Collection<FE> getFollowElements(InternalParser parser) {
|
||||
return getFollowElements(parser, entryRule);
|
||||
}
|
||||
|
||||
protected Collection<FE> getFollowElements(InternalParser parser, AbstractRule rule) {
|
||||
String ruleName = ruleNames.getAntlrRuleName(rule);
|
||||
return getFollowElements(parser, ruleName);
|
||||
}
|
||||
|
||||
protected Collection<FE> getFollowElements(InternalParser parser, String ruleName) {
|
||||
try {
|
||||
return getFollowElements(parser, ruleName, false);
|
||||
} catch (InfiniteRecursion e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract String[] getInitialHiddenTokens();
|
||||
|
||||
public Collection<FE> getFollowElements(String input, boolean strict) {
|
||||
TokenSource tokenSource = createTokenSource(input);
|
||||
InternalParser parser = createParser();
|
||||
parser.setStrict(strict);
|
||||
ObservableXtextTokenStream tokens = new ObservableXtextTokenStream(tokenSource, parser);
|
||||
tokens.setInitialHiddenTokens(getInitialHiddenTokens());
|
||||
parser.setTokenStream(tokens);
|
||||
IUnorderedGroupHelper helper = createUnorderedGroupHelper();
|
||||
parser.setUnorderedGroupHelper(helper);
|
||||
helper.initializeWith(parser);
|
||||
tokens.setListener(parser);
|
||||
try {
|
||||
return Lists.newArrayList(getFollowElements(parser));
|
||||
} catch (InfiniteRecursion infinite) {
|
||||
return Lists.newArrayList(parser.getFollowElements());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the elementToParse or the innermost element if the elementToParse is a (parameterized) group that
|
||||
* contains only a single element.
|
||||
*/
|
||||
protected AbstractElement unwrapSingleElementGroups(AbstractElement elementToParse) {
|
||||
if (elementToParse instanceof Group) {
|
||||
|
@ -62,18 +279,19 @@ public abstract class BaseContentAssistParser {
|
|||
}
|
||||
return elementToParse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the root element or its alternative branches if it is an {@link Alternatives} or an {@link UnorderedGroup}.
|
||||
* In case of an {@link UnorderedGroup} the result contains only the elements that are not yet processed up to the
|
||||
* relevant cursor position.
|
||||
* Returns the root element or its alternative branches if it is an {@link Alternatives} or an
|
||||
* {@link UnorderedGroup}. In case of an {@link UnorderedGroup} the result contains only the elements that are not
|
||||
* yet processed up to the relevant cursor position.
|
||||
*/
|
||||
protected Collection<AbstractElement> getElementsToParse(AbstractElement root, List<AbstractElement> handledUnorderedGroupElements) {
|
||||
protected Collection<AbstractElement> getElementsToParse(AbstractElement root,
|
||||
List<AbstractElement> handledUnorderedGroupElements) {
|
||||
if (root instanceof UnorderedGroup) {
|
||||
if (handledUnorderedGroupElements.isEmpty())
|
||||
return ((CompoundElement) root).getElements();
|
||||
List<AbstractElement> result = Lists.newArrayList(root);
|
||||
for(AbstractElement child: ((UnorderedGroup) root).getElements()) {
|
||||
for (AbstractElement child : ((UnorderedGroup) root).getElements()) {
|
||||
if (!handledUnorderedGroupElements.contains(child)) {
|
||||
result.add(child);
|
||||
}
|
||||
|
@ -82,14 +300,14 @@ public abstract class BaseContentAssistParser {
|
|||
}
|
||||
return getElementsToParse(root);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Factory method for the {@link IgnoreFirstEntranceUnorderedGroupHelper}.
|
||||
*/
|
||||
protected IUnorderedGroupHelper ignoreFirstEntrance(final IUnorderedGroupHelper helper) {
|
||||
return new IgnoreFirstEntranceUnorderedGroupHelper(helper);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the element itself or its components if it is an {@link Alternatives}.
|
||||
*/
|
||||
|
@ -98,25 +316,27 @@ public abstract class BaseContentAssistParser {
|
|||
return ((CompoundElement) root).getElements();
|
||||
return Collections.singleton(root);
|
||||
}
|
||||
|
||||
protected String[][] getRequiredRuleNames(String ruleName, List<Integer> paramStack, AbstractElement elementToParse) {
|
||||
return requiredRuleNameComputer.getRequiredRuleNames(new RequiredRuleNameComputer.Param(ruleName, paramStack, elementToParse) {
|
||||
@Override
|
||||
public String getBaseRuleName(AbstractElement element) {
|
||||
return getRuleName(element);
|
||||
}
|
||||
});
|
||||
|
||||
protected String[][] getRequiredRuleNames(String ruleName, List<Integer> paramStack,
|
||||
AbstractElement elementToParse) {
|
||||
return requiredRuleNameComputer
|
||||
.getRequiredRuleNames(new RequiredRuleNameComputer.Param(ruleName, paramStack, elementToParse) {
|
||||
@Override
|
||||
public String getBaseRuleName(AbstractElement element) {
|
||||
return getRuleName(element);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
protected abstract String getRuleName(AbstractElement element);
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link IUnorderedGroupHelper} that is not yet initialized.
|
||||
*/
|
||||
protected IUnorderedGroupHelper createUnorderedGroupHelper() {
|
||||
return getUnorderedGroupHelper().get();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public for testing purpose.
|
||||
*/
|
||||
|
@ -130,18 +350,139 @@ public abstract class BaseContentAssistParser {
|
|||
public Provider<IUnorderedGroupHelper> getUnorderedGroupHelper() {
|
||||
return unorderedGroupHelper;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public for testing purpose.
|
||||
*/
|
||||
public void setRequiredRuleNameComputer(RequiredRuleNameComputer requiredRuleNameComputer) {
|
||||
this.requiredRuleNameComputer = requiredRuleNameComputer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public for testing purpose.
|
||||
*/
|
||||
public RequiredRuleNameComputer getRequiredRuleNameComputer() {
|
||||
return requiredRuleNameComputer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.14
|
||||
*/
|
||||
protected RuleNames getRuleNames() {
|
||||
return ruleNames;
|
||||
}
|
||||
|
||||
public Collection<FE> getFollowElements(IParseResult parseResult, EntryPointFinder entryPointFinder, int offset,
|
||||
boolean strict) {
|
||||
ICompositeNode entryPoint = entryPointFinder.findEntryPoint(parseResult, offset);
|
||||
if (entryPoint != null) {
|
||||
String parseMe = getTextToParse(parseResult, entryPoint, offset);
|
||||
TokenSource tokenSource = createTokenSource(parseMe);
|
||||
InternalParser parser = createParser();
|
||||
parser.setStrict(strict);
|
||||
ObservableXtextTokenStream tokens = new ObservableXtextTokenStream(tokenSource, parser);
|
||||
tokens.setInitialHiddenTokens(getInitialHiddenTokens());
|
||||
parser.setTokenStream(tokens);
|
||||
IUnorderedGroupHelper helper = createUnorderedGroupHelper();
|
||||
parser.setUnorderedGroupHelper(helper);
|
||||
helper.initializeWith(parser);
|
||||
tokens.setListener(parser);
|
||||
try {
|
||||
Collection<FE> followElements = getFollowElements(parser, getEntryGrammarElement(entryPoint));
|
||||
return Lists.newArrayList(followElements);
|
||||
} catch (InfiniteRecursion infinite) {
|
||||
return Lists.newArrayList(parser.getFollowElements());
|
||||
}
|
||||
} else {
|
||||
String text = parseResult.getRootNode().getText();
|
||||
String parseMe = text.substring(0, offset);
|
||||
initializeFor(NodeModelUtils.getEntryParserRule(parseResult.getRootNode()));
|
||||
Collection<FE> followElements = getFollowElements(parseMe, strict);
|
||||
return followElements;
|
||||
}
|
||||
}
|
||||
|
||||
protected AbstractElement getEntryGrammarElement(ICompositeNode entryPoint) {
|
||||
EObject grammarElement = entryPoint.getGrammarElement();
|
||||
if (grammarElement instanceof RuleCall) {
|
||||
AbstractRule rule = ((RuleCall) grammarElement).getRule();
|
||||
if (rule instanceof ParserRule) {
|
||||
if (!GrammarUtil.isMultipleCardinality(rule.getAlternatives())) {
|
||||
grammarElement = rule.getAlternatives();
|
||||
}
|
||||
}
|
||||
} else if (grammarElement instanceof ParserRule) {
|
||||
grammarElement = ((ParserRule) grammarElement).getAlternatives();
|
||||
} else if (grammarElement instanceof CrossReference) {
|
||||
grammarElement = GrammarUtil.containingAssignment(grammarElement);
|
||||
}
|
||||
AbstractElement result = (AbstractElement) grammarElement;
|
||||
if (result instanceof Action) {
|
||||
return getEntryGrammarElement((ICompositeNode) entryPoint.getFirstChild());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getTextToParse(IParseResult parseResult, ICompositeNode entryPoint, int offset) {
|
||||
StringBuilder result = new StringBuilder(offset - entryPoint.getTotalOffset());
|
||||
appendTextToParse(entryPoint, offset, false, result);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected boolean appendTextToParse(ICompositeNode node, int offset, boolean skipOptional, StringBuilder result) {
|
||||
for (INode child : node.getChildren()) {
|
||||
if (child instanceof ILeafNode) {
|
||||
String text = child.getText();
|
||||
if (child.getTotalEndOffset() >= offset) {
|
||||
String sub = text.substring(0, offset - child.getTotalOffset());
|
||||
result.append(sub);
|
||||
return true;
|
||||
} else {
|
||||
result.append(text);
|
||||
}
|
||||
} else {
|
||||
if (!skipOptional) {
|
||||
if (appendTextToParse((ICompositeNode) child, offset, child.getTotalEndOffset() < offset, result)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
String skippedAs = getReplacement((ICompositeNode) child);
|
||||
if (skippedAs != null) {
|
||||
result.append(skippedAs);
|
||||
} else {
|
||||
if (appendTextToParse((ICompositeNode) child, offset, true, result)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a syntactically correct replacement for nodes whose real content does not need to be parsed.
|
||||
*
|
||||
* @return the replacement or <code>null</code>
|
||||
*/
|
||||
protected String getReplacement(ICompositeNode node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Collection<FE> getFollowElements(InternalParser parser, AbstractElement entryPoint) {
|
||||
String ruleName = getRuleName(entryPoint);
|
||||
if (ruleName == null) {
|
||||
if (entryPoint instanceof RuleCall) {
|
||||
RuleCall call = (RuleCall) entryPoint;
|
||||
AbstractRule rule = call.getRule();
|
||||
if (rule instanceof ParserRule) {
|
||||
ruleName = getRuleNames().getAntlrRuleName(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ruleName == null) {
|
||||
throw new IllegalStateException("entryPoint: " + entryPoint);
|
||||
}
|
||||
return getFollowElements(parser, ruleName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 itemis AG (http://www.itemis.de) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*
|
||||
* @since 2.14
|
||||
*/
|
||||
public class BaseFollowElement<LATerminal extends ILookAheadTerminal> {
|
||||
|
||||
private AbstractElement currentGrammarElement;
|
||||
private List<AbstractElement> trace;
|
||||
private List<AbstractElement> localTrace;
|
||||
private int lookAhead;
|
||||
private List<Integer> paramStack;
|
||||
private List<LATerminal> lookAheadTerminals;
|
||||
private List<AbstractElement> handledUnorderedGroupElements;
|
||||
|
||||
public AbstractElement getGrammarElement() {
|
||||
return currentGrammarElement;
|
||||
}
|
||||
|
||||
public void setGrammarElement(AbstractElement grammarElement) {
|
||||
this.currentGrammarElement = grammarElement;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getTrace() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
public void setTrace(List<AbstractElement> trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public int getLookAhead() {
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
public void setLookAhead(int lookAhead) {
|
||||
this.lookAhead = lookAhead;
|
||||
}
|
||||
|
||||
public List<Integer> getParamStack() {
|
||||
return paramStack;
|
||||
}
|
||||
|
||||
public void setParamStack(List<Integer> paramStack) {
|
||||
this.paramStack = paramStack;
|
||||
}
|
||||
|
||||
public List<LATerminal> getLookAheadTerminals() {
|
||||
return lookAheadTerminals;
|
||||
}
|
||||
|
||||
public void setLookAheadTerminals(List<LATerminal> lookAheadTerminals) {
|
||||
this.lookAheadTerminals = lookAheadTerminals;
|
||||
}
|
||||
|
||||
public void setLocalTrace(List<AbstractElement> localTrace) {
|
||||
this.localTrace = localTrace;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getLocalTrace() {
|
||||
return localTrace;
|
||||
}
|
||||
|
||||
public void setHandledUnorderedGroupElements(List<AbstractElement> handledUnorderedGroupElements) {
|
||||
this.handledUnorderedGroupElements = handledUnorderedGroupElements;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getHandledUnorderedGroupElements() {
|
||||
return handledUnorderedGroupElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((currentGrammarElement == null) ? 0 : currentGrammarElement.hashCode());
|
||||
result = prime * result + ((localTrace == null) ? 0 : localTrace.hashCode());
|
||||
result = prime * result + lookAhead;
|
||||
result = prime * result + ((paramStack == null) ? 0 : paramStack.hashCode());
|
||||
result = prime * result + ((lookAheadTerminals == null) ? 0 : lookAheadTerminals.hashCode());
|
||||
result = prime * result + ((trace == null) ? 0 : trace.hashCode());
|
||||
result = prime * result + ((handledUnorderedGroupElements == null) ? 0 : handledUnorderedGroupElements.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BaseFollowElement<?> other = (BaseFollowElement<?>) obj;
|
||||
if (currentGrammarElement == null) {
|
||||
if (other.currentGrammarElement != null)
|
||||
return false;
|
||||
}
|
||||
else if (!currentGrammarElement.equals(other.currentGrammarElement))
|
||||
return false;
|
||||
if (localTrace == null) {
|
||||
if (other.localTrace != null)
|
||||
return false;
|
||||
}
|
||||
else if (!localTrace.equals(other.localTrace))
|
||||
return false;
|
||||
if (lookAhead != other.lookAhead)
|
||||
return false;
|
||||
if (paramStack == null) {
|
||||
if (other.paramStack != null)
|
||||
return false;
|
||||
}
|
||||
else if (!paramStack.equals(other.paramStack))
|
||||
return false;
|
||||
if (lookAheadTerminals == null) {
|
||||
if (other.lookAheadTerminals != null)
|
||||
return false;
|
||||
}
|
||||
else if (!lookAheadTerminals.equals(other.lookAheadTerminals))
|
||||
return false;
|
||||
if (trace == null) {
|
||||
if (other.trace != null)
|
||||
return false;
|
||||
}
|
||||
else if (!trace.equals(other.trace))
|
||||
return false;
|
||||
if (handledUnorderedGroupElements == null) {
|
||||
if (other.handledUnorderedGroupElements != null)
|
||||
return false;
|
||||
}
|
||||
else if (!handledUnorderedGroupElements.equals(other.handledUnorderedGroupElements))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FollowElement: " + getGrammarElement() + " LA: " + getLookAhead();
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ import org.eclipse.xtext.AbstractElement;
|
|||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.ObservableXtextTokenStream.StreamListener;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.AbstractInternalContentAssistParser;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.internal.BaseInternalContentAssistParser;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
|
||||
/**
|
||||
|
@ -28,10 +29,10 @@ public class EofListener implements StreamListener, AbstractInternalContentAssis
|
|||
|
||||
public int startedErrorRecoveryAt;
|
||||
|
||||
private final AbstractInternalContentAssistParser parser;
|
||||
private final BaseInternalContentAssistParser<?, ?> parser;
|
||||
private final AbstractElement elementToParse;
|
||||
|
||||
protected EofListener(AbstractInternalContentAssistParser parser, AbstractElement elementToParse) {
|
||||
protected EofListener(BaseInternalContentAssistParser<?, ?> parser, AbstractElement elementToParse) {
|
||||
this.parser = parser;
|
||||
this.elementToParse = elementToParse;
|
||||
this.parserState = parser.getInternalRecognizerSharedState();
|
||||
|
@ -39,7 +40,7 @@ public class EofListener implements StreamListener, AbstractInternalContentAssis
|
|||
registerAsListenerAt(parser);
|
||||
}
|
||||
|
||||
protected void registerAsListenerAt(AbstractInternalContentAssistParser parser) {
|
||||
protected void registerAsListenerAt(BaseInternalContentAssistParser<?, ?> parser) {
|
||||
ObservableXtextTokenStream stream = (ObservableXtextTokenStream) parser.getTokenStream();
|
||||
stream.setListener(this);
|
||||
parser.setRecoveryListener(this);
|
||||
|
@ -105,7 +106,7 @@ public class EofListener implements StreamListener, AbstractInternalContentAssis
|
|||
return elementToParse;
|
||||
}
|
||||
|
||||
protected AbstractInternalContentAssistParser getParser() {
|
||||
protected BaseInternalContentAssistParser<?, ?> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,154 +7,10 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
|
||||
/**
|
||||
* Simple bean that reflects the current state, when the content assist parser
|
||||
* hit EOF.
|
||||
* @since 2.9
|
||||
*/
|
||||
public class FollowElement {
|
||||
|
||||
private AbstractElement currentGrammarElement;
|
||||
private List<AbstractElement> trace;
|
||||
private List<AbstractElement> localTrace;
|
||||
private int lookAhead;
|
||||
private List<Integer> paramStack;
|
||||
private List<LookAheadTerminal> lookAheadTerminals;
|
||||
private List<AbstractElement> handledUnorderedGroupElements;
|
||||
|
||||
public AbstractElement getGrammarElement() {
|
||||
return currentGrammarElement;
|
||||
}
|
||||
|
||||
public void setGrammarElement(AbstractElement grammarElement) {
|
||||
this.currentGrammarElement = grammarElement;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getTrace() {
|
||||
return trace;
|
||||
}
|
||||
|
||||
public void setTrace(List<AbstractElement> trace) {
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
public int getLookAhead() {
|
||||
return lookAhead;
|
||||
}
|
||||
|
||||
public void setLookAhead(int lookAhead) {
|
||||
this.lookAhead = lookAhead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public List<Integer> getParamStack() {
|
||||
return paramStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public void setParamStack(List<Integer> paramStack) {
|
||||
this.paramStack = paramStack;
|
||||
}
|
||||
|
||||
public List<LookAheadTerminal> getLookAheadTerminals() {
|
||||
return lookAheadTerminals;
|
||||
}
|
||||
|
||||
public void setLookAheadTerminals(List<LookAheadTerminal> lookAheadTerminals) {
|
||||
this.lookAheadTerminals = lookAheadTerminals;
|
||||
}
|
||||
|
||||
public void setLocalTrace(List<AbstractElement> localTrace) {
|
||||
this.localTrace = localTrace;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getLocalTrace() {
|
||||
return localTrace;
|
||||
}
|
||||
|
||||
public void setHandledUnorderedGroupElements(List<AbstractElement> handledUnorderedGroupElements) {
|
||||
this.handledUnorderedGroupElements = handledUnorderedGroupElements;
|
||||
}
|
||||
|
||||
public List<AbstractElement> getHandledUnorderedGroupElements() {
|
||||
return handledUnorderedGroupElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((currentGrammarElement == null) ? 0 : currentGrammarElement.hashCode());
|
||||
result = prime * result + ((localTrace == null) ? 0 : localTrace.hashCode());
|
||||
result = prime * result + lookAhead;
|
||||
result = prime * result + ((paramStack == null) ? 0 : paramStack.hashCode());
|
||||
result = prime * result + ((lookAheadTerminals == null) ? 0 : lookAheadTerminals.hashCode());
|
||||
result = prime * result + ((trace == null) ? 0 : trace.hashCode());
|
||||
result = prime * result + ((handledUnorderedGroupElements == null) ? 0 : handledUnorderedGroupElements.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
FollowElement other = (FollowElement) obj;
|
||||
if (currentGrammarElement == null) {
|
||||
if (other.currentGrammarElement != null)
|
||||
return false;
|
||||
}
|
||||
else if (!currentGrammarElement.equals(other.currentGrammarElement))
|
||||
return false;
|
||||
if (localTrace == null) {
|
||||
if (other.localTrace != null)
|
||||
return false;
|
||||
}
|
||||
else if (!localTrace.equals(other.localTrace))
|
||||
return false;
|
||||
if (lookAhead != other.lookAhead)
|
||||
return false;
|
||||
if (paramStack == null) {
|
||||
if (other.paramStack != null)
|
||||
return false;
|
||||
}
|
||||
else if (!paramStack.equals(other.paramStack))
|
||||
return false;
|
||||
if (lookAheadTerminals == null) {
|
||||
if (other.lookAheadTerminals != null)
|
||||
return false;
|
||||
}
|
||||
else if (!lookAheadTerminals.equals(other.lookAheadTerminals))
|
||||
return false;
|
||||
if (trace == null) {
|
||||
if (other.trace != null)
|
||||
return false;
|
||||
}
|
||||
else if (!trace.equals(other.trace))
|
||||
return false;
|
||||
if (handledUnorderedGroupElements == null) {
|
||||
if (other.handledUnorderedGroupElements != null)
|
||||
return false;
|
||||
}
|
||||
else if (!handledUnorderedGroupElements.equals(other.handledUnorderedGroupElements))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FollowElement: " + getGrammarElement() + " LA: " + getLookAhead();
|
||||
}
|
||||
|
||||
public class FollowElement extends BaseFollowElement<LookAheadTerminal> {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 itemis AG (http://www.itemis.eu) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*
|
||||
* @since 2.14
|
||||
*/
|
||||
public interface ILookAheadTerminal {
|
||||
|
||||
Token getToken();
|
||||
|
||||
}
|
|
@ -17,16 +17,16 @@ import org.antlr.runtime.TokenSource;
|
|||
* @since 2.14
|
||||
*/
|
||||
public class LookAheadBasedTokenSource implements TokenSource {
|
||||
private final Iterator<LookAheadTerminal> iter;
|
||||
private final Iterator<? extends ILookAheadTerminal> iter;
|
||||
|
||||
protected LookAheadBasedTokenSource(Iterator<LookAheadTerminal> iter) {
|
||||
protected LookAheadBasedTokenSource(Iterator<? extends ILookAheadTerminal> iter) {
|
||||
this.iter = iter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token nextToken() {
|
||||
if (iter.hasNext()) {
|
||||
LookAheadTerminal lookAhead = iter.next();
|
||||
ILookAheadTerminal lookAhead = iter.next();
|
||||
return lookAhead.getToken();
|
||||
}
|
||||
return Token.EOF_TOKEN;
|
||||
|
|
|
@ -13,12 +13,13 @@ import org.eclipse.xtext.AbstractElement;
|
|||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public abstract class LookAheadTerminal {
|
||||
public abstract class LookAheadTerminal implements ILookAheadTerminal {
|
||||
|
||||
private Token token;
|
||||
|
||||
public abstract boolean matches(AbstractElement element);
|
||||
|
||||
@Override
|
||||
public Token getToken() {
|
||||
return token;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 itemis AG (http://www.itemis.de) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr.internal;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.BaseFollowElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.ILookAheadTerminal;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
*
|
||||
* @since 2.14
|
||||
*/
|
||||
public abstract class AbstractFollowElementFactory<FollowElement extends BaseFollowElement<LookAheadTerminal>, LookAheadTerminal extends ILookAheadTerminal> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AbstractFollowElementFactory.class);
|
||||
|
||||
private final BaseInternalContentAssistParser<FollowElement, LookAheadTerminal> parser;
|
||||
|
||||
protected AbstractFollowElementFactory(BaseInternalContentAssistParser<FollowElement, LookAheadTerminal> parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
protected abstract FollowElement doCreateElement();
|
||||
|
||||
protected abstract LookAheadTerminal doCreateLookAheadTerminal(Token token);
|
||||
|
||||
public FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Creating FollowElement for: " + current);
|
||||
FollowElement result = doCreateElement();
|
||||
result.setLookAhead(lookAhead);
|
||||
if (lookAhead != 1) {
|
||||
int from = parser.input.index();
|
||||
int to = parser.input.size();
|
||||
if (parser.marked > 0) {
|
||||
from = parser.firstMarker;
|
||||
}
|
||||
List<LookAheadTerminal> lookAheadTerminals = Lists.newArrayListWithExpectedSize(to - from);
|
||||
for (int tokenIndex = from; tokenIndex < to; tokenIndex++) {
|
||||
Token token = parser.input.get(tokenIndex);
|
||||
|
||||
if (token != null) {
|
||||
LookAheadTerminal lookAheadTerminal = doCreateLookAheadTerminal(token);
|
||||
lookAheadTerminals.add(lookAheadTerminal);
|
||||
}
|
||||
}
|
||||
result.setLookAheadTerminals(lookAheadTerminals);
|
||||
result.setLookAhead(lookAheadTerminals.size() + 1);
|
||||
}
|
||||
result.setGrammarElement(current);
|
||||
result.setTrace(Lists.newArrayList(Iterators.filter(parser.grammarElements.iterator(), AbstractElement.class)));
|
||||
result.setLocalTrace(Lists.newArrayList(Iterators.filter(parser.localTrace.iterator(), AbstractElement.class)));
|
||||
result.setParamStack(Lists.newArrayList(parser.paramStack));
|
||||
if (current instanceof UnorderedGroup) {
|
||||
if (parser.indexToHandledElements != null) {
|
||||
int index = parser.grammarElements.lastIndexOf(current);
|
||||
List<AbstractElement> alreadyHandled = Lists.newArrayList(Iterators.filter(parser.indexToHandledElements.get(index).iterator(), AbstractElement.class));
|
||||
result.setHandledUnorderedGroupElements(alreadyHandled);
|
||||
} else {
|
||||
result.setHandledUnorderedGroupElements(Collections.<AbstractElement>emptyList());
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("FollowElement is: " + current);
|
||||
logger.debug("==================================");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,530 +7,116 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.runtime.BitSet;
|
||||
import org.antlr.runtime.DFA;
|
||||
import org.antlr.runtime.FailedPredicateException;
|
||||
import org.antlr.runtime.IntStream;
|
||||
import org.antlr.runtime.Parser;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.runtime.RecognizerSharedState;
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.TokenStream;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.FollowElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.LookAheadTerminal;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.LookAheadTerminalRuleCall;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.LookaheadKeyword;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.ObservableXtextTokenStream;
|
||||
import org.eclipse.xtext.parser.antlr.ITokenDefProvider;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
import org.eclipse.xtext.parser.antlr.TokenTool;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/*
|
||||
* Initially copied from org.eclipse.xtext.ui.editor.contentassist.antlr.internal.AbstractInternalContentAssistParser
|
||||
*/
|
||||
/**
|
||||
* @since 2.9
|
||||
*/
|
||||
public abstract class AbstractInternalContentAssistParser extends Parser implements
|
||||
ObservableXtextTokenStream.StreamListener, ITokenDefProvider {
|
||||
public abstract class AbstractInternalContentAssistParser extends BaseInternalContentAssistParser<FollowElement, LookAheadTerminal> implements
|
||||
ObservableXtextTokenStream.StreamListener {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AbstractInternalContentAssistParser.class);
|
||||
|
||||
protected class DefaultFollowElementFactory implements IFollowElementFactory {
|
||||
@Override
|
||||
public FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("Creating FollowElement for: " + current);
|
||||
FollowElement result = new FollowElement();
|
||||
result.setLookAhead(lookAhead);
|
||||
if (lookAhead != 1) {
|
||||
int from = input.index();
|
||||
int to = input.size();
|
||||
if (marked > 0) {
|
||||
from = firstMarker;
|
||||
}
|
||||
List<LookAheadTerminal> lookAheadTerminals = Lists.newArrayListWithExpectedSize(to - from);
|
||||
for (int tokenIndex = from; tokenIndex < to; tokenIndex++) {
|
||||
Token token = input.get(tokenIndex);
|
||||
|
||||
if (token != null) {
|
||||
LookAheadTerminal lookAheadTerminal = createLookAheadTerminal(token);
|
||||
lookAheadTerminals.add(lookAheadTerminal);
|
||||
}
|
||||
}
|
||||
result.setLookAheadTerminals(lookAheadTerminals);
|
||||
result.setLookAhead(lookAheadTerminals.size() + 1);
|
||||
}
|
||||
result.setGrammarElement(current);
|
||||
result.setTrace(Lists.newArrayList(Iterators.filter(grammarElements.iterator(), AbstractElement.class)));
|
||||
result.setLocalTrace(Lists.newArrayList(Iterators.filter(localTrace.iterator(), AbstractElement.class)));
|
||||
result.setParamStack(Lists.newArrayList(paramStack));
|
||||
if (current instanceof UnorderedGroup) {
|
||||
if (indexToHandledElements != null) {
|
||||
int index = grammarElements.lastIndexOf(current);
|
||||
List<AbstractElement> alreadyHandled = Lists.newArrayList(Iterators.filter(indexToHandledElements.get(index).iterator(), AbstractElement.class));
|
||||
result.setHandledUnorderedGroupElements(alreadyHandled);
|
||||
} else {
|
||||
result.setHandledUnorderedGroupElements(Collections.<AbstractElement>emptyList());
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("FollowElement is: " + current);
|
||||
logger.debug("==================================");
|
||||
}
|
||||
return result;
|
||||
protected class DefaultFollowElementFactory extends AbstractFollowElementFactory<FollowElement, LookAheadTerminal> implements IFollowElementFactory {
|
||||
|
||||
protected DefaultFollowElementFactory() {
|
||||
super(AbstractInternalContentAssistParser.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FollowElement doCreateElement() {
|
||||
return new FollowElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LookAheadTerminal doCreateLookAheadTerminal(Token token) {
|
||||
return createLookAheadTerminal(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public interface RecoveryListener {
|
||||
void beginErrorRecovery();
|
||||
void endErrorRecovery();
|
||||
public interface RecoveryListener extends BaseInternalContentAssistParser.RecoveryListener {
|
||||
}
|
||||
|
||||
interface IFollowElementFactory {
|
||||
FollowElement createFollowElement(AbstractElement current, int lookAhead);
|
||||
interface IFollowElementFactory extends BaseInternalContentAssistParser.IFollowElementFactory<FollowElement, LookAheadTerminal> {
|
||||
}
|
||||
|
||||
protected final List<EObject> grammarElements;
|
||||
protected final List<EObject> localTrace;
|
||||
protected final List<Integer> paramStack;
|
||||
protected final List<Integer> grammarElementsWithParams;
|
||||
protected int stackSize;
|
||||
protected final Set<FollowElement> followElements;
|
||||
protected ObservableXtextTokenStream.StreamListener delegate;
|
||||
protected List<TerminalRule> terminalRules;
|
||||
protected boolean mismatch;
|
||||
protected RecoveryListener recoveryListener;
|
||||
protected int lookAheadAddOn;
|
||||
protected int marked = 0;
|
||||
protected boolean resyncing = false;
|
||||
protected boolean strict = false;
|
||||
protected int wasErrorCount = -1;
|
||||
protected int predictionLevel = 0;
|
||||
protected int currentMarker;
|
||||
protected int firstMarker;
|
||||
protected boolean inMismatchIsUnwantedToken = false;
|
||||
protected boolean failedPredicateAtEOF = false;
|
||||
protected Multimap<Integer, AbstractElement> indexToHandledElements;
|
||||
protected IUnorderedGroupHelper unorderedGroupHelper;
|
||||
protected IFollowElementFactory followElementFactory = new DefaultFollowElementFactory();
|
||||
|
||||
public AbstractInternalContentAssistParser(TokenStream input, RecognizerSharedState state) {
|
||||
super(input, state);
|
||||
this.grammarElements = new ArrayList<EObject>();
|
||||
this.localTrace = new ArrayList<EObject>();
|
||||
this.paramStack = new ArrayList<Integer>();
|
||||
this.grammarElementsWithParams = new ArrayList<Integer>();
|
||||
this.followElements = new LinkedHashSetWithoutNull<FollowElement>();
|
||||
}
|
||||
|
||||
public AbstractInternalContentAssistParser(TokenStream input) {
|
||||
super(input);
|
||||
this.grammarElements = new ArrayList<EObject>();
|
||||
this.localTrace = new ArrayList<EObject>();
|
||||
this.followElements = new LinkedHashSetWithoutNull<FollowElement>();
|
||||
this.paramStack = new ArrayList<Integer>();
|
||||
this.grammarElementsWithParams = new ArrayList<Integer>();
|
||||
}
|
||||
|
||||
/**
|
||||
* When experiencing slow content assist, try to reduce the threshold.
|
||||
*/
|
||||
protected int getLookaheadThreshold() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void before(EObject grammarElement) {
|
||||
if (input.size() == input.index()) {
|
||||
int idx = localTrace.indexOf(grammarElement);
|
||||
// due to error recovery inconveniences we have to add some grammarElements
|
||||
// twice immediately after each other
|
||||
if (idx >= 0 && idx != localTrace.size() - 1) {
|
||||
List<EObject> traceAfterFirstOccurrence = localTrace.subList(idx + 1, localTrace.size());
|
||||
int secondIdx = traceAfterFirstOccurrence.indexOf(grammarElement);
|
||||
if (secondIdx >= 0 && secondIdx != traceAfterFirstOccurrence.size() - 1) {
|
||||
List<EObject> firstRun = localTrace.subList(idx, idx + 1 + secondIdx);
|
||||
List<EObject> secondRun = traceAfterFirstOccurrence.subList(secondIdx, traceAfterFirstOccurrence.size());
|
||||
if (firstRun.equals(secondRun)) {
|
||||
throw new InfiniteRecursion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
grammarElements.add(grammarElement);
|
||||
localTrace.add(grammarElement);
|
||||
}
|
||||
|
||||
public void before(EObject grammarElement, int paramConfig) {
|
||||
before(grammarElement);
|
||||
paramStack.add(paramConfig);
|
||||
grammarElementsWithParams.add(stackSize);
|
||||
@Override
|
||||
protected DefaultFollowElementFactory newFollowElementFactory() {
|
||||
return new DefaultFollowElementFactory();
|
||||
}
|
||||
|
||||
public void after(EObject grammarElement, int paramConfig) {
|
||||
int old = removeLast(paramStack);
|
||||
if (old != paramConfig) {
|
||||
throw new IllegalStateException(paramConfig + "!=" + old);
|
||||
}
|
||||
removeLast(grammarElementsWithParams);
|
||||
after(grammarElement);
|
||||
protected abstract class StreamAdapter extends BaseInternalContentAssistParser<FollowElement, LookAheadTerminal>.StreamAdapter {
|
||||
}
|
||||
|
||||
protected StreamAdapter delegate(BaseInternalContentAssistParser<FollowElement, LookAheadTerminal>.StreamAdapter delegate) {
|
||||
return new StreamAdapter() {
|
||||
|
||||
public void after(EObject grammarElement) {
|
||||
EObject foundGrammarElement = removeLast(grammarElements);
|
||||
if (grammarElement != foundGrammarElement)
|
||||
throw new IllegalStateException("expected element: '" + grammarElement + "', but was: '"
|
||||
+ foundGrammarElement + "'");
|
||||
if (grammarElement instanceof UnorderedGroup && indexToHandledElements != null) {
|
||||
indexToHandledElements.removeAll(grammarElements.size());
|
||||
} else if (!grammarElements.isEmpty()) {
|
||||
int index = grammarElements.size() - 1;
|
||||
if (grammarElements.get(index) instanceof UnorderedGroup) {
|
||||
if (indexToHandledElements == null) {
|
||||
indexToHandledElements = LinkedHashMultimap.create();
|
||||
}
|
||||
indexToHandledElements.put(index, (AbstractElement) grammarElement);
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
delegate.announceEof(lookAhead);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceConsume() {
|
||||
delegate.announceConsume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceMark(int marker) {
|
||||
delegate.announceMark(marker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceRewind(int marker) {
|
||||
delegate.announceRewind(marker);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recover(IntStream stream, RecognitionException ex) {
|
||||
if (recoveryListener != null)
|
||||
recoveryListener.beginErrorRecovery();
|
||||
removeUnexpectedElements();
|
||||
if (ex instanceof FailedPredicateException && ex.token.getType() == Token.EOF) {
|
||||
failedPredicateAtEOF = true;
|
||||
}
|
||||
super.recover(stream, ex);
|
||||
if (recoveryListener != null)
|
||||
recoveryListener.endErrorRecovery();
|
||||
}
|
||||
|
||||
private void removeUnexpectedElements() {
|
||||
int dropParamAt = -1;
|
||||
if (!grammarElementsWithParams.isEmpty()) {
|
||||
dropParamAt = getLast(grammarElementsWithParams);
|
||||
}
|
||||
while (stackSize < grammarElements.size()) {
|
||||
removeLast(grammarElements);
|
||||
if (dropParamAt == grammarElements.size()) {
|
||||
removeLast(paramStack);
|
||||
removeLast(grammarElementsWithParams);
|
||||
if (!grammarElementsWithParams.isEmpty()) {
|
||||
dropParamAt = getLast(grammarElementsWithParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getLast(List<T> list) {
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
private <T> T removeLast(List<T> list) {
|
||||
return list.remove(list.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitErrorMessage(String msg) {
|
||||
// don't call super, since it would do a plain vanilla
|
||||
// System.err.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
public RecognizerSharedState getInternalRecognizerSharedState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
protected abstract Grammar getGrammar();
|
||||
|
||||
protected int keepStackSize() {
|
||||
int result = stackSize;
|
||||
stackSize = grammarElements.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void restoreStackSize(int stackSize) {
|
||||
if (!isBacktracking()) {
|
||||
removeUnexpectedElements();
|
||||
this.stackSize = stackSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean isBacktracking() {
|
||||
return state.backtracking != 0;
|
||||
}
|
||||
|
||||
protected abstract class StreamAdapter implements ObservableXtextTokenStream.StreamListener {
|
||||
@Override
|
||||
public void announceConsume() {
|
||||
AbstractInternalContentAssistParser.this.announceConsume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceMark(int marker) {
|
||||
AbstractInternalContentAssistParser.this.announceMark(marker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceRewind(int marker) {
|
||||
AbstractInternalContentAssistParser.this.announceRewind(marker);
|
||||
}
|
||||
}
|
||||
|
||||
protected void selectEofStrategy(int lookAhead) {
|
||||
if (mismatch || !state.errorRecovery) {
|
||||
selectEofStrategy();
|
||||
} else if (strict && lookAhead == 1) {
|
||||
delegate = createNoOpStrategy();
|
||||
if (predictionLevel > 0) {
|
||||
delegate = createPredictionStrategy();
|
||||
}
|
||||
} else {
|
||||
selectEofStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
protected void selectEofStrategy() throws UnsupportedOperationException {
|
||||
if (mismatch) {
|
||||
delegate = createMismatchStrategy();
|
||||
} else if (!state.errorRecovery) {
|
||||
if (marked > 0 && state.syntaxErrors > 0 && state.lastErrorIndex >= firstMarker) {
|
||||
delegate = createNoOpStrategy();
|
||||
return;
|
||||
} else {
|
||||
delegate = createNotErrorRecoveryStrategy();
|
||||
}
|
||||
} else {
|
||||
delegate = createErrorRecoveryStrategy();
|
||||
}
|
||||
if (predictionLevel > 0) {
|
||||
delegate = createPredictionStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
protected StreamAdapter createNoOpStrategy() {
|
||||
return new StreamAdapter() {
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
}
|
||||
};
|
||||
return delegate(super.createNoOpStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StreamAdapter createPredictionStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private AbstractElement lastAddedElement;
|
||||
private AbstractElement globalLastAddedElement;
|
||||
private int lastKnownSyntaxErrors = Integer.MAX_VALUE;
|
||||
private boolean wasMismatch = false;
|
||||
private ObservableXtextTokenStream.StreamListener privateDelegate = delegate;
|
||||
private IFollowElementFactory followElementFactory;
|
||||
private AbstractElement recovered;
|
||||
{
|
||||
followElementFactory = AbstractInternalContentAssistParser.this.followElementFactory;
|
||||
AbstractInternalContentAssistParser.this.followElementFactory = new IFollowElementFactory() {
|
||||
|
||||
@Override
|
||||
public FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (lastKnownSyntaxErrors == Integer.MAX_VALUE || state.lastErrorIndex < 0) {
|
||||
FollowElement result = followElementFactory.createFollowElement(current, lookAhead);
|
||||
if (result != null) {
|
||||
globalLastAddedElement = result.getGrammarElement();
|
||||
if (lookAhead > 1 && isBacktracking() && lastKnownSyntaxErrors == Integer.MAX_VALUE) {
|
||||
lastKnownSyntaxErrors = state.syntaxErrors;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
try {
|
||||
if (predictionLevel == 0) {
|
||||
if (!wasMismatch && (!state.errorRecovery || !resyncing)) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null
|
||||
&& (lastAddedElement == null ||
|
||||
!EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
if (state.errorRecovery) {
|
||||
if (!failedPredicateAtEOF && (globalLastAddedElement != current && (globalLastAddedElement == null
|
||||
|| GrammarUtil.isOptionalCardinality(globalLastAddedElement)
|
||||
|| GrammarUtil.isOneOrMoreCardinality(globalLastAddedElement)))) {
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
} else {
|
||||
if (globalLastAddedElement != current && state.syntaxErrors <= lastKnownSyntaxErrors)
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mismatch && !wasMismatch && !failedPredicateAtEOF) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (recovered == null || recovered == current) {
|
||||
if (current != null
|
||||
&& (lastAddedElement == null ||
|
||||
!EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (globalLastAddedElement != getCurrentGrammarElement())
|
||||
privateDelegate.announceEof(lookAhead);
|
||||
}
|
||||
} finally {
|
||||
wasMismatch |= mismatch;
|
||||
if (getCurrentGrammarElement() != null && getCurrentGrammarElement() != globalLastAddedElement) {
|
||||
if (state.errorRecovery && recovered == null) {
|
||||
recovered = getCurrentGrammarElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createAndAddFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (marked > 0)
|
||||
lookAhead+=lookAheadAddOn;
|
||||
FollowElement followElement = followElementFactory.createFollowElement(current, lookAhead);
|
||||
if (followElement != null) {
|
||||
followElements.add(followElement);
|
||||
lastAddedElement = current;
|
||||
globalLastAddedElement = current;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
return delegate(super.createPredictionStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StreamAdapter createErrorRecoveryStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private AbstractElement lastAddedElement;
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null
|
||||
&& (lastAddedElement == null ||
|
||||
!EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
if (marked > 0)
|
||||
lookAhead+=lookAheadAddOn;
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
lastAddedElement = current;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
return delegate(super.createErrorRecoveryStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StreamAdapter createNotErrorRecoveryStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
if (!state.errorRecovery && !mismatch && ((!isBacktracking() || marked > 0) || wasErrorCount <= 0)) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null) {
|
||||
if (marked > 0)
|
||||
lookAhead+=lookAheadAddOn;
|
||||
if (lookAhead <= getLookaheadThreshold())
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
return delegate(super.createNotErrorRecoveryStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StreamAdapter createMismatchStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private boolean wasErrorRecovery = false;
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
wasErrorRecovery = wasErrorRecovery || state.errorRecovery;
|
||||
if (!wasErrorRecovery && !mismatch) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null) {
|
||||
if (marked > 0)
|
||||
lookAhead+=lookAheadAddOn;
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return delegate(super.createMismatchStrategy());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginResync() {
|
||||
resyncing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endResync() {
|
||||
resyncing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException {
|
||||
try {
|
||||
mismatch = true;
|
||||
return super.recoverFromMismatchedToken(input, ttype, follow);
|
||||
}
|
||||
finally {
|
||||
mismatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mismatchIsMissingToken(IntStream input, BitSet follow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected AbstractElement getCurrentGrammarElement() {
|
||||
for (int i = grammarElements.size() - 1; i >= 0; i--) {
|
||||
EObject result = grammarElements.get(i);
|
||||
if (result instanceof AbstractElement)
|
||||
return (AbstractElement) result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
return followElementFactory.createFollowElement(current, lookAhead);
|
||||
}
|
||||
|
||||
public LookAheadTerminal createLookAheadTerminal(Token token) {
|
||||
Grammar grammar = getGrammar();
|
||||
String tokenName = getTokenNames()[token.getType()];
|
||||
|
@ -556,181 +142,12 @@ public abstract class AbstractInternalContentAssistParser extends Parser impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reached Eof with LA " + lookAhead);
|
||||
logger.debug("Internal parser state is: ");
|
||||
logger.debug(" current: " + getCurrentGrammarElement());
|
||||
logger.debug(" failed: " + state.failed);
|
||||
logger.debug(" errorRecovery: " + state.errorRecovery);
|
||||
logger.debug(" resyncing: " + resyncing);
|
||||
logger.debug(" marked: " + marked);
|
||||
logger.debug(" firstMarker: " + firstMarker);
|
||||
logger.debug(" currentMarker: " + currentMarker);
|
||||
logger.debug(" lookAheadAddOn: " + lookAheadAddOn);
|
||||
logger.debug(" params: " + paramStack);
|
||||
logger.debug(" predictionLevel: " + predictionLevel);
|
||||
logger.debug(" stackSize: " + stackSize);
|
||||
logger.debug(" backtracking: " + state.backtracking);
|
||||
logger.debug(" syntaxErrors: " + state.syntaxErrors);
|
||||
logger.debug(" token: " + state.token);
|
||||
logger.debug("==================================");
|
||||
}
|
||||
if (delegate == null) {
|
||||
selectEofStrategy(lookAhead);
|
||||
if (strict) {
|
||||
wasErrorCount = state.syntaxErrors;
|
||||
}
|
||||
}
|
||||
if (inMismatchIsUnwantedToken)
|
||||
return;
|
||||
if (grammarElements.isEmpty() || delegate == null)
|
||||
return;
|
||||
if (strict) {
|
||||
if (wasErrorCount != state.syntaxErrors)
|
||||
return;
|
||||
}
|
||||
delegate.announceEof(lookAhead);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportError(RecognitionException e) {
|
||||
if (strict) {
|
||||
if ( state.errorRecovery ) {
|
||||
return;
|
||||
}
|
||||
if (e.index != input.size()) {
|
||||
// don't count errors at EOF in strict mode
|
||||
state.syntaxErrors++;
|
||||
}
|
||||
state.errorRecovery = true;
|
||||
} else {
|
||||
super.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceConsume() {
|
||||
if (marked <= 0)
|
||||
localTrace.clear();
|
||||
else
|
||||
lookAheadAddOn++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mismatchIsUnwantedToken(IntStream input, int ttype) {
|
||||
try {
|
||||
inMismatchIsUnwantedToken = true;
|
||||
boolean result = super.mismatchIsUnwantedToken(input, ttype);
|
||||
return result;
|
||||
} finally {
|
||||
inMismatchIsUnwantedToken = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceRewind(int marker) {
|
||||
int useLookAhead = -1;
|
||||
if (marker != 0 && delegate == null && strict && predictionLevel != 0 && lookAheadAddOn > 0 && state.syntaxErrors == 0
|
||||
&& input.index() == input.size()
|
||||
&& marker + lookAheadAddOn <= input.size()
|
||||
&& isBacktracking()) {
|
||||
useLookAhead = lookAheadAddOn;
|
||||
delegate = createNotErrorRecoveryStrategy();
|
||||
wasErrorCount = state.syntaxErrors;
|
||||
}
|
||||
currentMarker = marker;
|
||||
lookAheadAddOn = currentMarker - firstMarker;
|
||||
if (useLookAhead != -1 && useLookAhead + firstMarker >= input.index()) {
|
||||
announceEof(useLookAhead);
|
||||
}
|
||||
marked --;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceMark(int marker) {
|
||||
if (marked <= 0) {
|
||||
marked++;
|
||||
lookAheadAddOn = 0;
|
||||
currentMarker = marker;
|
||||
firstMarker = marker;
|
||||
} else {
|
||||
marked++;
|
||||
currentMarker = marker;
|
||||
}
|
||||
}
|
||||
|
||||
public void beginDFAPrediction() {
|
||||
predictionLevel++;
|
||||
}
|
||||
|
||||
public boolean isDFAPrediction() {
|
||||
return predictionLevel != 0;
|
||||
}
|
||||
|
||||
public void endDFAPrediction() {
|
||||
predictionLevel--;
|
||||
}
|
||||
|
||||
public Set<FollowElement> getFollowElements() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("getFollowElements()");
|
||||
}
|
||||
return followElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getTokenDefMap() {
|
||||
String[] names = getTokenNames();
|
||||
Map<Integer, String> result = Maps.newHashMapWithExpectedSize(names.length - Token.MIN_TOKEN_TYPE);
|
||||
for (int i = Token.MIN_TOKEN_TYPE; i < names.length; i++) {
|
||||
result.put(i, getValueForTokenName(names[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getValueForTokenName(String tokenName) {
|
||||
return tokenName;
|
||||
}
|
||||
|
||||
public List<EObject> getGrammarElements() {
|
||||
return grammarElements;
|
||||
}
|
||||
|
||||
public List<EObject> getLocalTrace() {
|
||||
return localTrace;
|
||||
}
|
||||
|
||||
public List<Integer> getParamStack() {
|
||||
return paramStack;
|
||||
}
|
||||
|
||||
public RecoveryListener getRecoveryListener() {
|
||||
return recoveryListener;
|
||||
return (RecoveryListener) super.getRecoveryListener();
|
||||
}
|
||||
|
||||
public void setRecoveryListener(RecoveryListener recoveryListener) {
|
||||
this.recoveryListener = recoveryListener;
|
||||
}
|
||||
|
||||
public void setUnorderedGroupHelper(IUnorderedGroupHelper unorderedGroupHelper) {
|
||||
this.unorderedGroupHelper = unorderedGroupHelper;
|
||||
}
|
||||
|
||||
public IUnorderedGroupHelper getUnorderedGroupHelper() {
|
||||
return unorderedGroupHelper;
|
||||
}
|
||||
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
protected static short[][] unpackEncodedStringArray(String[] arr) {
|
||||
int numStates = arr.length;
|
||||
short[][] result = new short[numStates][];
|
||||
for (int i = 0; i < numStates; i++) {
|
||||
result[i] = DFA.unpackEncodedString(arr[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,640 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 itemis AG (http://www.itemis.de) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.editor.contentassist.antlr.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.antlr.runtime.BitSet;
|
||||
import org.antlr.runtime.DFA;
|
||||
import org.antlr.runtime.FailedPredicateException;
|
||||
import org.antlr.runtime.IntStream;
|
||||
import org.antlr.runtime.Parser;
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.runtime.RecognizerSharedState;
|
||||
import org.antlr.runtime.Token;
|
||||
import org.antlr.runtime.TokenStream;
|
||||
import org.eclipse.emf.ecore.EObject;
|
||||
import org.eclipse.emf.ecore.util.EcoreUtil;
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
import org.eclipse.xtext.Grammar;
|
||||
import org.eclipse.xtext.GrammarUtil;
|
||||
import org.eclipse.xtext.TerminalRule;
|
||||
import org.eclipse.xtext.UnorderedGroup;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.BaseFollowElement;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.ILookAheadTerminal;
|
||||
import org.eclipse.xtext.ide.editor.contentassist.antlr.ObservableXtextTokenStream;
|
||||
import org.eclipse.xtext.parser.antlr.ITokenDefProvider;
|
||||
import org.eclipse.xtext.parser.antlr.IUnorderedGroupHelper;
|
||||
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* @author Sebastian Zarnekow - Initial contribution and API
|
||||
* @since 2.14
|
||||
*/
|
||||
public abstract class BaseInternalContentAssistParser<FollowElement extends BaseFollowElement<LookAheadTerminal>, LookAheadTerminal extends ILookAheadTerminal>
|
||||
extends Parser implements ObservableXtextTokenStream.StreamListener, ITokenDefProvider {
|
||||
|
||||
public interface RecoveryListener {
|
||||
void beginErrorRecovery();
|
||||
|
||||
void endErrorRecovery();
|
||||
}
|
||||
|
||||
public interface IFollowElementFactory<FollowElement extends BaseFollowElement<LookAheadTerminal>, LookAheadTerminal extends ILookAheadTerminal> {
|
||||
FollowElement createFollowElement(AbstractElement current, int lookAhead);
|
||||
}
|
||||
|
||||
protected final List<EObject> grammarElements;
|
||||
protected final List<EObject> localTrace;
|
||||
protected final List<Integer> paramStack;
|
||||
protected final List<Integer> grammarElementsWithParams;
|
||||
protected int stackSize;
|
||||
protected final Set<FollowElement> followElements;
|
||||
protected ObservableXtextTokenStream.StreamListener delegate;
|
||||
protected List<TerminalRule> terminalRules;
|
||||
protected boolean mismatch;
|
||||
protected RecoveryListener recoveryListener;
|
||||
protected int lookAheadAddOn;
|
||||
protected int marked = 0;
|
||||
protected boolean resyncing = false;
|
||||
protected boolean strict = false;
|
||||
protected int wasErrorCount = -1;
|
||||
protected int predictionLevel = 0;
|
||||
protected int currentMarker;
|
||||
protected int firstMarker;
|
||||
protected boolean inMismatchIsUnwantedToken = false;
|
||||
protected boolean failedPredicateAtEOF = false;
|
||||
protected Multimap<Integer, AbstractElement> indexToHandledElements;
|
||||
protected IUnorderedGroupHelper unorderedGroupHelper;
|
||||
protected IFollowElementFactory<FollowElement, LookAheadTerminal> followElementFactory = newFollowElementFactory();
|
||||
|
||||
public BaseInternalContentAssistParser(TokenStream input, RecognizerSharedState state) {
|
||||
super(input, state);
|
||||
this.grammarElements = new ArrayList<EObject>();
|
||||
this.localTrace = new ArrayList<EObject>();
|
||||
this.paramStack = new ArrayList<Integer>();
|
||||
this.grammarElementsWithParams = new ArrayList<Integer>();
|
||||
this.followElements = new LinkedHashSetWithoutNull<FollowElement>();
|
||||
}
|
||||
|
||||
public BaseInternalContentAssistParser(TokenStream input) {
|
||||
super(input);
|
||||
this.grammarElements = new ArrayList<EObject>();
|
||||
this.localTrace = new ArrayList<EObject>();
|
||||
this.followElements = new LinkedHashSetWithoutNull<FollowElement>();
|
||||
this.paramStack = new ArrayList<Integer>();
|
||||
this.grammarElementsWithParams = new ArrayList<Integer>();
|
||||
}
|
||||
|
||||
protected abstract IFollowElementFactory<FollowElement, LookAheadTerminal> newFollowElementFactory();
|
||||
|
||||
/**
|
||||
* When experiencing slow content assist, try to reduce the threshold.
|
||||
*/
|
||||
protected int getLookaheadThreshold() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void before(EObject grammarElement) {
|
||||
if (input.size() == input.index()) {
|
||||
int idx = localTrace.indexOf(grammarElement);
|
||||
// due to error recovery inconveniences we have to add some grammarElements
|
||||
// twice immediately after each other
|
||||
if (idx >= 0 && idx != localTrace.size() - 1) {
|
||||
List<EObject> traceAfterFirstOccurrence = localTrace.subList(idx + 1, localTrace.size());
|
||||
int secondIdx = traceAfterFirstOccurrence.indexOf(grammarElement);
|
||||
if (secondIdx >= 0 && secondIdx != traceAfterFirstOccurrence.size() - 1) {
|
||||
List<EObject> firstRun = localTrace.subList(idx, idx + 1 + secondIdx);
|
||||
List<EObject> secondRun = traceAfterFirstOccurrence.subList(secondIdx,
|
||||
traceAfterFirstOccurrence.size());
|
||||
if (firstRun.equals(secondRun)) {
|
||||
throw infiniteRecursion();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
grammarElements.add(grammarElement);
|
||||
localTrace.add(grammarElement);
|
||||
}
|
||||
|
||||
protected InfiniteRecursion infiniteRecursion() {
|
||||
return new InfiniteRecursion();
|
||||
}
|
||||
|
||||
public void before(EObject grammarElement, int paramConfig) {
|
||||
before(grammarElement);
|
||||
paramStack.add(paramConfig);
|
||||
grammarElementsWithParams.add(stackSize);
|
||||
}
|
||||
|
||||
public void after(EObject grammarElement, int paramConfig) {
|
||||
int old = removeLast(paramStack);
|
||||
if (old != paramConfig) {
|
||||
throw new IllegalStateException(paramConfig + "!=" + old);
|
||||
}
|
||||
removeLast(grammarElementsWithParams);
|
||||
after(grammarElement);
|
||||
}
|
||||
|
||||
public void after(EObject grammarElement) {
|
||||
EObject foundGrammarElement = removeLast(grammarElements);
|
||||
if (grammarElement != foundGrammarElement)
|
||||
throw new IllegalStateException(
|
||||
"expected element: '" + grammarElement + "', but was: '" + foundGrammarElement + "'");
|
||||
if (grammarElement instanceof UnorderedGroup && indexToHandledElements != null) {
|
||||
indexToHandledElements.removeAll(grammarElements.size());
|
||||
} else if (!grammarElements.isEmpty()) {
|
||||
int index = grammarElements.size() - 1;
|
||||
if (grammarElements.get(index) instanceof UnorderedGroup) {
|
||||
if (indexToHandledElements == null) {
|
||||
indexToHandledElements = LinkedHashMultimap.create();
|
||||
}
|
||||
indexToHandledElements.put(index, (AbstractElement) grammarElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recover(IntStream stream, RecognitionException ex) {
|
||||
if (recoveryListener != null)
|
||||
recoveryListener.beginErrorRecovery();
|
||||
removeUnexpectedElements();
|
||||
if (ex instanceof FailedPredicateException && ex.token.getType() == Token.EOF) {
|
||||
failedPredicateAtEOF = true;
|
||||
}
|
||||
super.recover(stream, ex);
|
||||
if (recoveryListener != null)
|
||||
recoveryListener.endErrorRecovery();
|
||||
}
|
||||
|
||||
private void removeUnexpectedElements() {
|
||||
int dropParamAt = -1;
|
||||
if (!grammarElementsWithParams.isEmpty()) {
|
||||
dropParamAt = getLast(grammarElementsWithParams);
|
||||
}
|
||||
while (stackSize < grammarElements.size()) {
|
||||
removeLast(grammarElements);
|
||||
if (dropParamAt == grammarElements.size()) {
|
||||
removeLast(paramStack);
|
||||
removeLast(grammarElementsWithParams);
|
||||
if (!grammarElementsWithParams.isEmpty()) {
|
||||
dropParamAt = getLast(grammarElementsWithParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getLast(List<T> list) {
|
||||
return list.get(list.size() - 1);
|
||||
}
|
||||
|
||||
private <T> T removeLast(List<T> list) {
|
||||
return list.remove(list.size() - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitErrorMessage(String msg) {
|
||||
// don't call super, since it would do a plain vanilla
|
||||
// System.err.println(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @nooverride This method is not intended to be re-implemented or extended by clients.
|
||||
* @noreference This method is not intended to be referenced by clients.
|
||||
*/
|
||||
public RecognizerSharedState getInternalRecognizerSharedState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
protected abstract Grammar getGrammar();
|
||||
|
||||
protected int keepStackSize() {
|
||||
int result = stackSize;
|
||||
stackSize = grammarElements.size();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void restoreStackSize(int stackSize) {
|
||||
if (!isBacktracking()) {
|
||||
removeUnexpectedElements();
|
||||
this.stackSize = stackSize;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isBacktracking() {
|
||||
return state.backtracking != 0;
|
||||
}
|
||||
|
||||
protected abstract class StreamAdapter implements ObservableXtextTokenStream.StreamListener {
|
||||
@Override
|
||||
public void announceConsume() {
|
||||
BaseInternalContentAssistParser.this.announceConsume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceMark(int marker) {
|
||||
BaseInternalContentAssistParser.this.announceMark(marker);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceRewind(int marker) {
|
||||
BaseInternalContentAssistParser.this.announceRewind(marker);
|
||||
}
|
||||
}
|
||||
|
||||
protected void selectEofStrategy(int lookAhead) {
|
||||
if (mismatch || !state.errorRecovery) {
|
||||
selectEofStrategy();
|
||||
} else if (strict && lookAhead == 1) {
|
||||
delegate = createNoOpStrategy();
|
||||
if (predictionLevel > 0) {
|
||||
delegate = createPredictionStrategy();
|
||||
}
|
||||
} else {
|
||||
selectEofStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
protected void selectEofStrategy() throws UnsupportedOperationException {
|
||||
if (mismatch) {
|
||||
delegate = createMismatchStrategy();
|
||||
} else if (!state.errorRecovery) {
|
||||
if (marked > 0 && state.syntaxErrors > 0 && state.lastErrorIndex >= firstMarker) {
|
||||
delegate = createNoOpStrategy();
|
||||
return;
|
||||
} else {
|
||||
delegate = createNotErrorRecoveryStrategy();
|
||||
}
|
||||
} else {
|
||||
delegate = createErrorRecoveryStrategy();
|
||||
}
|
||||
if (predictionLevel > 0) {
|
||||
delegate = createPredictionStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
protected StreamAdapter createNoOpStrategy() {
|
||||
return new StreamAdapter() {
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected StreamAdapter createPredictionStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private AbstractElement lastAddedElement;
|
||||
private AbstractElement globalLastAddedElement;
|
||||
private int lastKnownSyntaxErrors = Integer.MAX_VALUE;
|
||||
private boolean wasMismatch = false;
|
||||
private ObservableXtextTokenStream.StreamListener privateDelegate = delegate;
|
||||
private IFollowElementFactory<FollowElement, LookAheadTerminal> followElementFactory;
|
||||
private AbstractElement recovered;
|
||||
{
|
||||
followElementFactory = BaseInternalContentAssistParser.this.followElementFactory;
|
||||
BaseInternalContentAssistParser.this.followElementFactory = new IFollowElementFactory<FollowElement, LookAheadTerminal>() {
|
||||
|
||||
@Override
|
||||
public FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (lastKnownSyntaxErrors == Integer.MAX_VALUE || state.lastErrorIndex < 0) {
|
||||
FollowElement result = followElementFactory.createFollowElement(current, lookAhead);
|
||||
if (result != null) {
|
||||
globalLastAddedElement = result.getGrammarElement();
|
||||
if (lookAhead > 1 && isBacktracking() && lastKnownSyntaxErrors == Integer.MAX_VALUE) {
|
||||
lastKnownSyntaxErrors = state.syntaxErrors;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
try {
|
||||
if (predictionLevel == 0) {
|
||||
if (!wasMismatch && (!state.errorRecovery || !resyncing)) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null
|
||||
&& (lastAddedElement == null || !EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
if (state.errorRecovery) {
|
||||
if (!failedPredicateAtEOF
|
||||
&& (globalLastAddedElement != current && (globalLastAddedElement == null
|
||||
|| GrammarUtil.isOptionalCardinality(globalLastAddedElement)
|
||||
|| GrammarUtil.isOneOrMoreCardinality(globalLastAddedElement)))) {
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
} else {
|
||||
if (globalLastAddedElement != current
|
||||
&& state.syntaxErrors <= lastKnownSyntaxErrors)
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mismatch && !wasMismatch && !failedPredicateAtEOF) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (recovered == null || recovered == current) {
|
||||
if (current != null && (lastAddedElement == null
|
||||
|| !EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
createAndAddFollowElement(current, lookAhead);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (globalLastAddedElement != getCurrentGrammarElement())
|
||||
privateDelegate.announceEof(lookAhead);
|
||||
}
|
||||
} finally {
|
||||
wasMismatch |= mismatch;
|
||||
if (getCurrentGrammarElement() != null && getCurrentGrammarElement() != globalLastAddedElement) {
|
||||
if (state.errorRecovery && recovered == null) {
|
||||
recovered = getCurrentGrammarElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createAndAddFollowElement(AbstractElement current, int lookAhead) {
|
||||
if (marked > 0)
|
||||
lookAhead += lookAheadAddOn;
|
||||
FollowElement followElement = followElementFactory.createFollowElement(current, lookAhead);
|
||||
if (followElement != null) {
|
||||
followElements.add(followElement);
|
||||
lastAddedElement = current;
|
||||
globalLastAddedElement = current;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected StreamAdapter createErrorRecoveryStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private AbstractElement lastAddedElement;
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null && (lastAddedElement == null || !EcoreUtil.isAncestor(current, lastAddedElement))) {
|
||||
if (marked > 0)
|
||||
lookAhead += lookAheadAddOn;
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
lastAddedElement = current;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected StreamAdapter createNotErrorRecoveryStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
if (!state.errorRecovery && !mismatch && ((!isBacktracking() || marked > 0) || wasErrorCount <= 0)) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null) {
|
||||
if (marked > 0)
|
||||
lookAhead += lookAheadAddOn;
|
||||
if (lookAhead <= getLookaheadThreshold())
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected StreamAdapter createMismatchStrategy() {
|
||||
return new StreamAdapter() {
|
||||
|
||||
private boolean wasErrorRecovery = false;
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
wasErrorRecovery = wasErrorRecovery || state.errorRecovery;
|
||||
if (!wasErrorRecovery && !mismatch) {
|
||||
AbstractElement current = getCurrentGrammarElement();
|
||||
if (current != null) {
|
||||
if (marked > 0)
|
||||
lookAhead += lookAheadAddOn;
|
||||
followElements.add(createFollowElement(current, lookAhead));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginResync() {
|
||||
resyncing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endResync() {
|
||||
resyncing = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) throws RecognitionException {
|
||||
try {
|
||||
mismatch = true;
|
||||
return super.recoverFromMismatchedToken(input, ttype, follow);
|
||||
} finally {
|
||||
mismatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mismatchIsMissingToken(IntStream input, BitSet follow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected AbstractElement getCurrentGrammarElement() {
|
||||
for (int i = grammarElements.size() - 1; i >= 0; i--) {
|
||||
EObject result = grammarElements.get(i);
|
||||
if (result instanceof AbstractElement)
|
||||
return (AbstractElement) result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected FollowElement createFollowElement(AbstractElement current, int lookAhead) {
|
||||
return followElementFactory.createFollowElement(current, lookAhead);
|
||||
}
|
||||
|
||||
public abstract LookAheadTerminal createLookAheadTerminal(Token token);
|
||||
|
||||
@Override
|
||||
public void announceEof(int lookAhead) {
|
||||
if (delegate == null) {
|
||||
selectEofStrategy(lookAhead);
|
||||
if (strict) {
|
||||
wasErrorCount = state.syntaxErrors;
|
||||
}
|
||||
}
|
||||
if (inMismatchIsUnwantedToken)
|
||||
return;
|
||||
if (grammarElements.isEmpty() || delegate == null)
|
||||
return;
|
||||
if (strict) {
|
||||
if (wasErrorCount != state.syntaxErrors)
|
||||
return;
|
||||
}
|
||||
delegate.announceEof(lookAhead);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportError(RecognitionException e) {
|
||||
if (strict) {
|
||||
if (state.errorRecovery) {
|
||||
return;
|
||||
}
|
||||
if (e.index != input.size()) {
|
||||
// don't count errors at EOF in strict mode
|
||||
state.syntaxErrors++;
|
||||
}
|
||||
state.errorRecovery = true;
|
||||
} else {
|
||||
super.reportError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceConsume() {
|
||||
if (marked <= 0)
|
||||
localTrace.clear();
|
||||
else
|
||||
lookAheadAddOn++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mismatchIsUnwantedToken(IntStream input, int ttype) {
|
||||
try {
|
||||
inMismatchIsUnwantedToken = true;
|
||||
boolean result = super.mismatchIsUnwantedToken(input, ttype);
|
||||
return result;
|
||||
} finally {
|
||||
inMismatchIsUnwantedToken = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceRewind(int marker) {
|
||||
int useLookAhead = -1;
|
||||
if (marker != 0 && delegate == null && strict && predictionLevel != 0 && lookAheadAddOn > 0
|
||||
&& state.syntaxErrors == 0 && input.index() == input.size() && marker + lookAheadAddOn <= input.size()
|
||||
&& isBacktracking()) {
|
||||
useLookAhead = lookAheadAddOn;
|
||||
delegate = createNotErrorRecoveryStrategy();
|
||||
wasErrorCount = state.syntaxErrors;
|
||||
}
|
||||
currentMarker = marker;
|
||||
lookAheadAddOn = currentMarker - firstMarker;
|
||||
if (useLookAhead != -1 && useLookAhead + firstMarker >= input.index()) {
|
||||
announceEof(useLookAhead);
|
||||
}
|
||||
marked--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void announceMark(int marker) {
|
||||
if (marked <= 0) {
|
||||
marked++;
|
||||
lookAheadAddOn = 0;
|
||||
currentMarker = marker;
|
||||
firstMarker = marker;
|
||||
} else {
|
||||
marked++;
|
||||
currentMarker = marker;
|
||||
}
|
||||
}
|
||||
|
||||
public void beginDFAPrediction() {
|
||||
predictionLevel++;
|
||||
}
|
||||
|
||||
public boolean isDFAPrediction() {
|
||||
return predictionLevel != 0;
|
||||
}
|
||||
|
||||
public void endDFAPrediction() {
|
||||
predictionLevel--;
|
||||
}
|
||||
|
||||
public Set<FollowElement> getFollowElements() {
|
||||
return followElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, String> getTokenDefMap() {
|
||||
String[] names = getTokenNames();
|
||||
Map<Integer, String> result = Maps.newHashMapWithExpectedSize(names.length - Token.MIN_TOKEN_TYPE);
|
||||
for (int i = Token.MIN_TOKEN_TYPE; i < names.length; i++) {
|
||||
result.put(i, getValueForTokenName(names[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getValueForTokenName(String tokenName) {
|
||||
return tokenName;
|
||||
}
|
||||
|
||||
public List<EObject> getGrammarElements() {
|
||||
return grammarElements;
|
||||
}
|
||||
|
||||
public List<EObject> getLocalTrace() {
|
||||
return localTrace;
|
||||
}
|
||||
|
||||
public List<Integer> getParamStack() {
|
||||
return paramStack;
|
||||
}
|
||||
|
||||
public RecoveryListener getRecoveryListener() {
|
||||
return recoveryListener;
|
||||
}
|
||||
|
||||
public void setRecoveryListener(RecoveryListener recoveryListener) {
|
||||
this.recoveryListener = recoveryListener;
|
||||
}
|
||||
|
||||
public void setUnorderedGroupHelper(IUnorderedGroupHelper unorderedGroupHelper) {
|
||||
this.unorderedGroupHelper = unorderedGroupHelper;
|
||||
}
|
||||
|
||||
public IUnorderedGroupHelper getUnorderedGroupHelper() {
|
||||
return unorderedGroupHelper;
|
||||
}
|
||||
|
||||
public void setStrict(boolean strict) {
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
protected static short[][] unpackEncodedStringArray(String[] arr) {
|
||||
int numStates = arr.length;
|
||||
short[][] result = new short[numStates][];
|
||||
for (int i = 0; i < numStates; i++) {
|
||||
result[i] = DFA.unpackEncodedString(arr[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -29,8 +29,8 @@ public class DFA extends org.antlr.runtime.DFA {
|
|||
}
|
||||
}
|
||||
|
||||
protected AbstractInternalContentAssistParser getRecognizer() {
|
||||
return (AbstractInternalContentAssistParser) recognizer;
|
||||
protected BaseInternalContentAssistParser<?, ?> getRecognizer() {
|
||||
return (BaseInternalContentAssistParser<?, ?>) recognizer;
|
||||
}
|
||||
|
||||
protected IUnorderedGroupHelper getUnorderedGroupHelper() {
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.google.common.base.Objects;
|
|||
import com.google.common.io.ByteStreams;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Module;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
@ -47,7 +48,7 @@ public class ServerLauncher {
|
|||
ServerLauncher.launch(_name, args, _serverModule);
|
||||
}
|
||||
|
||||
public static void launch(final String prefix, final String[] args, final com.google.inject.Module... modules) {
|
||||
public static void launch(final String prefix, final String[] args, final Module... modules) {
|
||||
final LaunchArgs launchArgs = ServerLauncher.createLaunchArgs(prefix, args);
|
||||
final ServerLauncher launcher = Guice.createInjector(modules).<ServerLauncher>getInstance(ServerLauncher.class);
|
||||
launcher.start(launchArgs);
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.google.inject.Binder;
|
|||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.binder.AnnotatedBindingBuilder;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
|
@ -195,9 +196,9 @@ public abstract class AbstractLanguageServerTest implements Endpoint {
|
|||
}
|
||||
}
|
||||
|
||||
protected com.google.inject.Module getServerModule() {
|
||||
protected Module getServerModule() {
|
||||
ServerModule _serverModule = new ServerModule();
|
||||
final com.google.inject.Module _function = (Binder it) -> {
|
||||
final Module _function = (Binder it) -> {
|
||||
AnnotatedBindingBuilder<RequestManager> _bind = it.<RequestManager>bind(RequestManager.class);
|
||||
_bind.toInstance(new RequestManager() {
|
||||
@Override
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.google.common.collect.Lists;
|
|||
import com.google.inject.Binder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provider;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
@ -98,7 +99,7 @@ public class XtextGeneratorLanguage extends CompositeGeneratorFragment2 implemen
|
|||
private ResourceSet resourceSet;
|
||||
|
||||
@Accessors
|
||||
private com.google.inject.Module guiceModule = ((com.google.inject.Module) (Binder it) -> {
|
||||
private Module guiceModule = ((Module) (Binder it) -> {
|
||||
});
|
||||
|
||||
@Accessors
|
||||
|
@ -419,11 +420,11 @@ public class XtextGeneratorLanguage extends CompositeGeneratorFragment2 implemen
|
|||
}
|
||||
|
||||
@Pure
|
||||
public com.google.inject.Module getGuiceModule() {
|
||||
public Module getGuiceModule() {
|
||||
return this.guiceModule;
|
||||
}
|
||||
|
||||
public void setGuiceModule(final com.google.inject.Module guiceModule) {
|
||||
public void setGuiceModule(final Module guiceModule) {
|
||||
this.guiceModule = guiceModule;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.google.inject.Binder;
|
|||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Names;
|
||||
|
@ -1747,19 +1748,19 @@ public class XtextGeneratorTemplates {
|
|||
_builder.append("try {");
|
||||
_builder.newLine();
|
||||
_builder.append("\t\t\t");
|
||||
_builder.append(com.google.inject.Module.class, "\t\t\t");
|
||||
_builder.append(Module.class, "\t\t\t");
|
||||
_builder.append(" runtimeModule = getRuntimeModule(language);");
|
||||
_builder.newLineIfNotEmpty();
|
||||
_builder.append("\t\t\t");
|
||||
_builder.append(com.google.inject.Module.class, "\t\t\t");
|
||||
_builder.append(Module.class, "\t\t\t");
|
||||
_builder.append(" sharedStateModule = getSharedStateModule();");
|
||||
_builder.newLineIfNotEmpty();
|
||||
_builder.append("\t\t\t");
|
||||
_builder.append(com.google.inject.Module.class, "\t\t\t");
|
||||
_builder.append(Module.class, "\t\t\t");
|
||||
_builder.append(" uiModule = getUiModule(language);");
|
||||
_builder.newLineIfNotEmpty();
|
||||
_builder.append("\t\t\t");
|
||||
_builder.append(com.google.inject.Module.class, "\t\t\t");
|
||||
_builder.append(Module.class, "\t\t\t");
|
||||
_builder.append(" mergedModule = ");
|
||||
_builder.append(Modules2.class, "\t\t\t");
|
||||
_builder.append(".mixin(runtimeModule, sharedStateModule, uiModule);");
|
||||
|
@ -1791,7 +1792,7 @@ public class XtextGeneratorTemplates {
|
|||
_builder.newLine();
|
||||
_builder.append("\t");
|
||||
_builder.append("protected ");
|
||||
_builder.append(com.google.inject.Module.class, "\t");
|
||||
_builder.append(Module.class, "\t");
|
||||
_builder.append(" getRuntimeModule(String grammar) {");
|
||||
_builder.newLineIfNotEmpty();
|
||||
{
|
||||
|
@ -1824,7 +1825,7 @@ public class XtextGeneratorTemplates {
|
|||
_builder.newLine();
|
||||
_builder.append("\t");
|
||||
_builder.append("protected ");
|
||||
_builder.append(com.google.inject.Module.class, "\t");
|
||||
_builder.append(Module.class, "\t");
|
||||
_builder.append(" getUiModule(String grammar) {");
|
||||
_builder.newLineIfNotEmpty();
|
||||
{
|
||||
|
@ -1857,7 +1858,7 @@ public class XtextGeneratorTemplates {
|
|||
_builder.newLine();
|
||||
_builder.append("\t");
|
||||
_builder.append("protected ");
|
||||
_builder.append(com.google.inject.Module.class, "\t");
|
||||
_builder.append(Module.class, "\t");
|
||||
_builder.append(" getSharedStateModule() {");
|
||||
_builder.newLineIfNotEmpty();
|
||||
_builder.append("\t\t");
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.google.common.collect.Iterators;
|
|||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.name.Names;
|
||||
import java.io.InputStream;
|
||||
|
@ -1342,7 +1343,7 @@ public class IdeaPluginGenerator extends AbstractStubGeneratingFragment {
|
|||
_builder.append("();");
|
||||
_builder.newLineIfNotEmpty();
|
||||
_builder.append("\t\t");
|
||||
_builder.append(com.google.inject.Module.class, "\t\t");
|
||||
_builder.append(Module.class, "\t\t");
|
||||
_builder.append(" mergedModule = ");
|
||||
_builder.append(Modules2.class, "\t\t");
|
||||
_builder.append(".mixin(runtimeModule, ideaModule);");
|
||||
|
|
Loading…
Reference in a new issue