diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/IndentationAwareUiTestLanguageParser.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/IndentationAwareUiTestLanguageParser.java index 015f8a96d..4f8cd2a5c 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/IndentationAwareUiTestLanguageParser.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/IndentationAwareUiTestLanguageParser.java @@ -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 mappings; + + @Inject + public NameMappings(IndentationAwareUiTestLanguageGrammarAccess grammarAccess) { + ImmutableMap.Builder 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 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 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() { - 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; + } } diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialContentAssistTestLanguageParser.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialContentAssistTestLanguageParser.java index 48f726a4c..46c67e485 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialContentAssistTestLanguageParser.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialContentAssistTestLanguageParser.java @@ -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 mappings; + + @Inject + public NameMappings(PartialContentAssistTestLanguageGrammarAccess grammarAccess) { + ImmutableMap.Builder 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 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 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() { - 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; + } } diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialSerializationTestLanguageParser.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialSerializationTestLanguageParser.java index 710239796..7dfcdcf74 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialSerializationTestLanguageParser.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/PartialSerializationTestLanguageParser.java @@ -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 mappings; + + @Inject + public NameMappings(PartialSerializationTestLanguageGrammarAccess grammarAccess) { + ImmutableMap.Builder 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 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 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() { - 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; + } } diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/TestLanguageParser.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/TestLanguageParser.java index ce2f2ca29..b2b8feeac 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/TestLanguageParser.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/ide/contentassist/antlr/TestLanguageParser.java @@ -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 mappings; + + @Inject + public NameMappings(TestLanguageGrammarAccess grammarAccess) { + ImmutableMap.Builder 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 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 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() { - 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; + } } diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/serializer/PartialSerializationTestLanguageSyntacticSequencer.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/serializer/PartialSerializationTestLanguageSyntacticSequencer.java index a35f7c3f4..f618fce29 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/serializer/PartialSerializationTestLanguageSyntacticSequencer.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/serializer/PartialSerializationTestLanguageSyntacticSequencer.java @@ -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 nodes) { @@ -90,7 +88,7 @@ public class PartialSerializationTestLanguageSyntacticSequencer extends Abstract /** * Ambiguous syntax: - * ';' | ('{' '}') + * ('{' '}') | ';' * * This ambiguous syntax occurs at: * (rule start) '#1' 'refs'? (ambiguity) (rule start) diff --git a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/services/IndentationAwareUiTestLanguageGrammarAccess.java b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/services/IndentationAwareUiTestLanguageGrammarAccess.java index caf312650..57d65f68e 100644 --- a/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/services/IndentationAwareUiTestLanguageGrammarAccess.java +++ b/org.eclipse.xtext.ide.tests/testlang-src-gen/org/eclipse/xtext/ide/tests/testlanguage/services/IndentationAwareUiTestLanguageGrammarAccess.java @@ -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; diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractContentAssistParser.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractContentAssistParser.java index 82177f95e..e78e48610 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractContentAssistParser.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractContentAssistParser.java @@ -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 + implements IContentAssistParser, IPartialEditingContentAssistParser { @Inject @Named(LexerIdeBindings.CONTENT_ASSIST) private Provider 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 getFollowElements(FollowElement element) { - if (element.getLookAhead() <= 1) - throw new IllegalArgumentException("lookahead may not be less than or equal to 1"); - Collection result = new ArrayList(); - 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 elements = getFollowElements(parser, elementToParse, ruleNames, i); - result.addAll(elements); - } - } - } - return result; - } - /** - * @since 2.14 - */ - protected ObservableXtextTokenStream setTokensFromFollowElement(AbstractInternalContentAssistParser parser, - FollowElement element) { - final Iterator 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 getFollowElements( - final AbstractInternalContentAssistParser parser, - final AbstractElement elementToParse, - String[] ruleNames, - final int startIndex) { - try { - EofListener listener = createEofListener(parser, elementToParse); - int i = startIndex; - Collection 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 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 getElementsToParse(FollowElement element) { - return getElementsToParse(element.getGrammarElement(), element.getHandledUnorderedGroupElements()); - } - - protected abstract AbstractInternalContentAssistParser createParser(); - - protected Collection getFollowElements(AbstractInternalContentAssistParser parser) { - return getFollowElements(parser, entryRule); - } - - protected Collection getFollowElements(AbstractInternalContentAssistParser parser, - AbstractRule rule) { - String ruleName = ruleNames.getAntlrRuleName(rule); - return getFollowElements(parser, ruleName); - } - - protected Collection 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 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; - } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractPartialContentAssistParser.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractPartialContentAssistParser.java index 529b4e89f..3c7ae4e75 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractPartialContentAssistParser.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/AbstractPartialContentAssistParser.java @@ -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 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 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 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 null - */ - protected String getReplacement(ICompositeNode node) { - return null; - } - - protected Collection 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); - } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseContentAssistParser.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseContentAssistParser.java index 2784bf21a..1078b4f10 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseContentAssistParser.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseContentAssistParser.java @@ -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, LATerminal extends ILookAheadTerminal, InternalParser extends BaseInternalContentAssistParser> { + @Inject private Provider 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 getFollowElements(FE element) { + if (element.getLookAhead() <= 1) + throw new IllegalArgumentException("lookahead may not be less than or equal to 1"); + Collection result = new ArrayList(); + 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 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 iter = element.getLookAheadTerminals().iterator(); + LookAheadBasedTokenSource tokenSource = new LookAheadBasedTokenSource(iter); + ObservableXtextTokenStream tokens = createObservableTokenStream(tokenSource, parser); + parser.setTokenStream(tokens); + return tokens; + } + + /** + * @since 2.14 + */ + protected Collection getFollowElements(final InternalParser parser, final AbstractElement elementToParse, + String[] ruleNames, final int startIndex) { + try { + EofListener listener = createEofListener(parser, elementToParse); + int i = startIndex; + Collection 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 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 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 getFollowElements(InternalParser parser) { + return getFollowElements(parser, entryRule); + } + + protected Collection getFollowElements(InternalParser parser, AbstractRule rule) { + String ruleName = ruleNames.getAntlrRuleName(rule); + return getFollowElements(parser, ruleName); + } + + protected Collection 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 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 getElementsToParse(AbstractElement root, List handledUnorderedGroupElements) { + protected Collection getElementsToParse(AbstractElement root, + List handledUnorderedGroupElements) { if (root instanceof UnorderedGroup) { if (handledUnorderedGroupElements.isEmpty()) return ((CompoundElement) root).getElements(); List 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 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 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 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 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 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 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 null + */ + protected String getReplacement(ICompositeNode node) { + return null; + } + + protected Collection 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); + } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseFollowElement.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseFollowElement.java new file mode 100644 index 000000000..6ecc74558 --- /dev/null +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/BaseFollowElement.java @@ -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 { + + private AbstractElement currentGrammarElement; + private List trace; + private List localTrace; + private int lookAhead; + private List paramStack; + private List lookAheadTerminals; + private List handledUnorderedGroupElements; + + public AbstractElement getGrammarElement() { + return currentGrammarElement; + } + + public void setGrammarElement(AbstractElement grammarElement) { + this.currentGrammarElement = grammarElement; + } + + public List getTrace() { + return trace; + } + + public void setTrace(List trace) { + this.trace = trace; + } + + public int getLookAhead() { + return lookAhead; + } + + public void setLookAhead(int lookAhead) { + this.lookAhead = lookAhead; + } + + public List getParamStack() { + return paramStack; + } + + public void setParamStack(List paramStack) { + this.paramStack = paramStack; + } + + public List getLookAheadTerminals() { + return lookAheadTerminals; + } + + public void setLookAheadTerminals(List lookAheadTerminals) { + this.lookAheadTerminals = lookAheadTerminals; + } + + public void setLocalTrace(List localTrace) { + this.localTrace = localTrace; + } + + public List getLocalTrace() { + return localTrace; + } + + public void setHandledUnorderedGroupElements(List handledUnorderedGroupElements) { + this.handledUnorderedGroupElements = handledUnorderedGroupElements; + } + + public List 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(); + } + +} \ No newline at end of file diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/EofListener.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/EofListener.java index 9e2d52bd9..ab5f6b5c8 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/EofListener.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/EofListener.java @@ -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; } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/FollowElement.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/FollowElement.java index 34abea217..c489e7eca 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/FollowElement.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/FollowElement.java @@ -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 trace; - private List localTrace; - private int lookAhead; - private List paramStack; - private List lookAheadTerminals; - private List handledUnorderedGroupElements; - - public AbstractElement getGrammarElement() { - return currentGrammarElement; - } - - public void setGrammarElement(AbstractElement grammarElement) { - this.currentGrammarElement = grammarElement; - } - - public List getTrace() { - return trace; - } - - public void setTrace(List trace) { - this.trace = trace; - } - - public int getLookAhead() { - return lookAhead; - } - - public void setLookAhead(int lookAhead) { - this.lookAhead = lookAhead; - } - - /** - * @since 2.9 - */ - public List getParamStack() { - return paramStack; - } - - /** - * @since 2.9 - */ - public void setParamStack(List paramStack) { - this.paramStack = paramStack; - } - - public List getLookAheadTerminals() { - return lookAheadTerminals; - } - - public void setLookAheadTerminals(List lookAheadTerminals) { - this.lookAheadTerminals = lookAheadTerminals; - } - - public void setLocalTrace(List localTrace) { - this.localTrace = localTrace; - } - - public List getLocalTrace() { - return localTrace; - } - - public void setHandledUnorderedGroupElements(List handledUnorderedGroupElements) { - this.handledUnorderedGroupElements = handledUnorderedGroupElements; - } - - public List 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 { } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/ILookAheadTerminal.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/ILookAheadTerminal.java new file mode 100644 index 000000000..b050d4bcc --- /dev/null +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/ILookAheadTerminal.java @@ -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(); + +} diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadBasedTokenSource.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadBasedTokenSource.java index 1ad609123..521d091ba 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadBasedTokenSource.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadBasedTokenSource.java @@ -17,16 +17,16 @@ import org.antlr.runtime.TokenSource; * @since 2.14 */ public class LookAheadBasedTokenSource implements TokenSource { - private final Iterator iter; + private final Iterator iter; - protected LookAheadBasedTokenSource(Iterator iter) { + protected LookAheadBasedTokenSource(Iterator 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; diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadTerminal.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadTerminal.java index 4d7680b4b..184bbaf92 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadTerminal.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/LookAheadTerminal.java @@ -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; } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractFollowElementFactory.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractFollowElementFactory.java new file mode 100644 index 000000000..bf19ffe66 --- /dev/null +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractFollowElementFactory.java @@ -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, LookAheadTerminal extends ILookAheadTerminal> { + + private static final Logger logger = Logger.getLogger(AbstractFollowElementFactory.class); + + private final BaseInternalContentAssistParser parser; + + protected AbstractFollowElementFactory(BaseInternalContentAssistParser 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 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 alreadyHandled = Lists.newArrayList(Iterators.filter(parser.indexToHandledElements.get(index).iterator(), AbstractElement.class)); + result.setHandledUnorderedGroupElements(alreadyHandled); + } else { + result.setHandledUnorderedGroupElements(Collections.emptyList()); + } + } + if (logger.isDebugEnabled()) { + logger.debug("FollowElement is: " + current); + logger.debug("=================================="); + } + return result; + } + +} diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractInternalContentAssistParser.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractInternalContentAssistParser.java index 017464185..30bc9c5d7 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractInternalContentAssistParser.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/AbstractInternalContentAssistParser.java @@ -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 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 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 alreadyHandled = Lists.newArrayList(Iterators.filter(indexToHandledElements.get(index).iterator(), AbstractElement.class)); - result.setHandledUnorderedGroupElements(alreadyHandled); - } else { - result.setHandledUnorderedGroupElements(Collections.emptyList()); - } - } - if (logger.isDebugEnabled()) { - logger.debug("FollowElement is: " + current); - logger.debug("=================================="); - } - return result; + protected class DefaultFollowElementFactory extends AbstractFollowElementFactory 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 { } - protected final List grammarElements; - protected final List localTrace; - protected final List paramStack; - protected final List grammarElementsWithParams; - protected int stackSize; - protected final Set followElements; - protected ObservableXtextTokenStream.StreamListener delegate; - protected List 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 indexToHandledElements; - protected IUnorderedGroupHelper unorderedGroupHelper; - protected IFollowElementFactory followElementFactory = new DefaultFollowElementFactory(); - public AbstractInternalContentAssistParser(TokenStream input, RecognizerSharedState state) { super(input, state); - this.grammarElements = new ArrayList(); - this.localTrace = new ArrayList(); - this.paramStack = new ArrayList(); - this.grammarElementsWithParams = new ArrayList(); - this.followElements = new LinkedHashSetWithoutNull(); } public AbstractInternalContentAssistParser(TokenStream input) { super(input); - this.grammarElements = new ArrayList(); - this.localTrace = new ArrayList(); - this.followElements = new LinkedHashSetWithoutNull(); - this.paramStack = new ArrayList(); - this.grammarElementsWithParams = new ArrayList(); } - /** - * 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 traceAfterFirstOccurrence = localTrace.subList(idx + 1, localTrace.size()); - int secondIdx = traceAfterFirstOccurrence.indexOf(grammarElement); - if (secondIdx >= 0 && secondIdx != traceAfterFirstOccurrence.size() - 1) { - List firstRun = localTrace.subList(idx, idx + 1 + secondIdx); - List 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.StreamAdapter { } + + protected StreamAdapter delegate(BaseInternalContentAssistParser.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 getLast(List list) { - return list.get(list.size() - 1); - } - - private T removeLast(List 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 getFollowElements() { - if (logger.isDebugEnabled()) { - logger.debug("getFollowElements()"); - } - return followElements; - } - - @Override - public Map getTokenDefMap() { - String[] names = getTokenNames(); - Map 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 getGrammarElements() { - return grammarElements; - } - - public List getLocalTrace() { - return localTrace; - } - - public List 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; - } } diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/BaseInternalContentAssistParser.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/BaseInternalContentAssistParser.java new file mode 100644 index 000000000..cec72019a --- /dev/null +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/BaseInternalContentAssistParser.java @@ -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, LookAheadTerminal extends ILookAheadTerminal> + extends Parser implements ObservableXtextTokenStream.StreamListener, ITokenDefProvider { + + public interface RecoveryListener { + void beginErrorRecovery(); + + void endErrorRecovery(); + } + + public interface IFollowElementFactory, LookAheadTerminal extends ILookAheadTerminal> { + FollowElement createFollowElement(AbstractElement current, int lookAhead); + } + + protected final List grammarElements; + protected final List localTrace; + protected final List paramStack; + protected final List grammarElementsWithParams; + protected int stackSize; + protected final Set followElements; + protected ObservableXtextTokenStream.StreamListener delegate; + protected List 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 indexToHandledElements; + protected IUnorderedGroupHelper unorderedGroupHelper; + protected IFollowElementFactory followElementFactory = newFollowElementFactory(); + + public BaseInternalContentAssistParser(TokenStream input, RecognizerSharedState state) { + super(input, state); + this.grammarElements = new ArrayList(); + this.localTrace = new ArrayList(); + this.paramStack = new ArrayList(); + this.grammarElementsWithParams = new ArrayList(); + this.followElements = new LinkedHashSetWithoutNull(); + } + + public BaseInternalContentAssistParser(TokenStream input) { + super(input); + this.grammarElements = new ArrayList(); + this.localTrace = new ArrayList(); + this.followElements = new LinkedHashSetWithoutNull(); + this.paramStack = new ArrayList(); + this.grammarElementsWithParams = new ArrayList(); + } + + protected abstract IFollowElementFactory 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 traceAfterFirstOccurrence = localTrace.subList(idx + 1, localTrace.size()); + int secondIdx = traceAfterFirstOccurrence.indexOf(grammarElement); + if (secondIdx >= 0 && secondIdx != traceAfterFirstOccurrence.size() - 1) { + List firstRun = localTrace.subList(idx, idx + 1 + secondIdx); + List 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 getLast(List list) { + return list.get(list.size() - 1); + } + + private T removeLast(List 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 followElementFactory; + private AbstractElement recovered; + { + followElementFactory = BaseInternalContentAssistParser.this.followElementFactory; + BaseInternalContentAssistParser.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; + } + } + + }; + } + + 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 getFollowElements() { + return followElements; + } + + @Override + public Map getTokenDefMap() { + String[] names = getTokenNames(); + Map 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 getGrammarElements() { + return grammarElements; + } + + public List getLocalTrace() { + return localTrace; + } + + public List 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; + } + + +} diff --git a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/DFA.java b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/DFA.java index e549d24a8..36af526fc 100644 --- a/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/DFA.java +++ b/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/editor/contentassist/antlr/internal/DFA.java @@ -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() { diff --git a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/ServerLauncher.java b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/ServerLauncher.java index 7478e9b8a..cff7f4f7a 100644 --- a/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/ServerLauncher.java +++ b/org.eclipse.xtext.ide/xtend-gen/org/eclipse/xtext/ide/server/ServerLauncher.java @@ -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).getInstance(ServerLauncher.class); launcher.start(launchArgs); diff --git a/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java b/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java index 828597110..8a7be3e3c 100644 --- a/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java +++ b/org.eclipse.xtext.testing/xtend-gen/org/eclipse/xtext/testing/AbstractLanguageServerTest.java @@ -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 _bind = it.bind(RequestManager.class); _bind.toInstance(new RequestManager() { @Override diff --git a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java index 5206d324a..ea42d9645 100644 --- a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java +++ b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorLanguage.java @@ -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; } diff --git a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorTemplates.java b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorTemplates.java index b59ac3ff5..3a9049161 100644 --- a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorTemplates.java +++ b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/XtextGeneratorTemplates.java @@ -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"); diff --git a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/idea/IdeaPluginGenerator.java b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/idea/IdeaPluginGenerator.java index 9af7d606e..907ce6f07 100644 --- a/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/idea/IdeaPluginGenerator.java +++ b/org.eclipse.xtext.xtext.generator/xtend-gen/org/eclipse/xtext/xtext/generator/idea/IdeaPluginGenerator.java @@ -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);");