All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.xtext.GrammarUtil Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2008, 2009 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;

import static com.google.common.collect.Iterables.*;
import static com.google.common.collect.Sets.*;
import static org.eclipse.emf.ecore.util.EcoreUtil.*;
import static org.eclipse.xtext.EcoreUtil2.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.xtext.nodemodel.BidiIterator;
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.util.Pair;
import org.eclipse.xtext.util.Strings;
import org.eclipse.xtext.util.Tuples;
import org.eclipse.xtext.xtext.CurrentTypeFinder;

import com.google.common.base.Function;
import com.google.common.base.Predicate;

/**
 * @author Jan Koehnlein
 * @author Sven Efftinge
 * @author Heiko Behrens
 * @author Sebastian Zarnekow
 */
public class GrammarUtil {

	public static String getClasspathRelativePathToXmi(Grammar grammar) {
		return getLanguageId(grammar).replace('.', '/') + ".xmi";
	}
	
	/**
	 * @since 2.4
	 */
	public static String getClasspathRelativePathToBinGrammar(Grammar grammar) {
		return getLanguageId(grammar).replace('.', '/') + ".xtextbin";
	}

	public static String getLanguageId(Grammar g) {
		return g.getName();
	}

	public static String getName(Grammar g) {
		if (Strings.isEmpty(g.getName()))
			return null;
		String[] splitted = g.getName().split("\\.");
		return splitted[splitted.length - 1];
	}

	public static String getNamespace(Grammar g) {
		if (Strings.isEmpty(g.getName()))
			return null;
		String[] splitted = g.getName().split("\\.");
		return Strings.concat(".", Arrays.asList(splitted), 1);
	}

	public static Grammar getGrammar(EObject grammarElement) {
		EObject root = getRootContainer(grammarElement);
		if (root instanceof Grammar) {
			return (Grammar) root;
		}
		return null;
	}

	public static AbstractRule containingRule(EObject e) {
		return getContainerOfType(e, AbstractRule.class);
	}

	public static ParserRule containingParserRule(EObject e) {
		return getContainerOfType(e, ParserRule.class);
	}

	public static EnumRule containingEnumRule(EObject e) {
		return getContainerOfType(e, EnumRule.class);
	}

	public static Assignment containingAssignment(EObject e) {
		return getContainerOfType(e, Assignment.class);
	}

	public static Group containingGroup(EObject e) {
		return getContainerOfType(e, Group.class);
	}

	public static UnorderedGroup containingUnorderedGroup(EObject e) {
		return getContainerOfType(e, UnorderedGroup.class);
	}

	public static CrossReference containingCrossReference(EObject e) {
		return getContainerOfType(e, CrossReference.class);
	}

	public static List containedActions(EObject e) {
		List allContentsOfType = getAllContentsOfType(e, Action.class);
		return allContentsOfType;
	}

	public static List containedRuleCalls(EObject e) {
		return getAllContentsOfType(e, RuleCall.class);
	}

	public static List containedAssignments(EObject e) {
		return getAllContentsOfType(e, Assignment.class);
	}

	public static List containedKeywords(EObject e) {
		return getAllContentsOfType(e, Keyword.class);
	}

	public static List containedAbstractElements(EObject e) {
		return getAllContentsOfType(e, AbstractElement.class);
	}

	public static List containedCrossReferences(EObject e) {
		return getAllContentsOfType(e, CrossReference.class);
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean containsAssignedAction(ParserRule rule) {
		TreeIterator ti = rule.eAllContents();
		while (ti.hasNext()) {
			EObject obj = ti.next();
			if (obj instanceof Action && ((Action) obj).getFeature() != null)
				return true;
		}
		return false;
	}

	public static List elementsBeforeThisInContainingGroup(AbstractElement _this) {
		Group g = containingGroup(_this);
		List result = new ArrayList();
		for (AbstractElement ae : g.getElements()) {
			if (ae == _this || eAllContentsAsList(ae).contains(_this)) {
				return result;
			}
			result.add(ae);
		}
		return result;
	}

	public static boolean isParserRuleCall(EObject grammarElement) {
		if (grammarElement instanceof RuleCall) {
			AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
			return calledRule != null && calledRule instanceof ParserRule;
		}
		return false;
	}

	public static boolean isEObjectRuleCall(EObject grammarElement) {
		if (grammarElement instanceof RuleCall) {
			AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
			return calledRule != null && calledRule instanceof ParserRule
					&& calledRule.getType().getClassifier() instanceof EClass;
		}
		return false;
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean isEObjectRule(EObject grammarElement) {
		return grammarElement instanceof ParserRule
				&& ((ParserRule) grammarElement).getType().getClassifier() instanceof EClass;
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean isUnassignedParserRuleCall(EObject ele) {
		if (!isParserRuleCall(ele))
			return false;
		return GrammarUtil.containingAssignment(ele) == null;
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean isUnassignedEObjectRuleCall(EObject ele) {
		if (!isEObjectRuleCall(ele))
			return false;
		return GrammarUtil.containingAssignment(ele) == null;
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean isAssignedEObjectRuleCall(EObject ele) {
		if (!isEObjectRuleCall(ele))
			return false;
		return GrammarUtil.containingAssignment(ele) != null;
	}

	public static boolean isDatatypeRuleCall(EObject grammarElement) {
		if (grammarElement instanceof RuleCall) {
			AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
			return calledRule != null && calledRule instanceof ParserRule
					&& calledRule.getType().getClassifier() instanceof EDataType;
		}
		return false;
	}
	
	public static boolean isEnumRuleCall(EObject grammarElement) {
		if (grammarElement instanceof RuleCall) {
			AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
			return calledRule != null && calledRule instanceof EnumRule;
		}
		return false;
	}
	
	/**
	 * @since 2.0
	 */
	public static boolean isTerminalRuleCall(EObject grammarElement) {
		if (grammarElement instanceof RuleCall) {
			AbstractRule calledRule = ((RuleCall) grammarElement).getRule();
			return calledRule != null && calledRule instanceof TerminalRule;
		}
		return false;
	}

	public static AbstractRule findRuleForName(Grammar grammar, String ruleName) {
		if (ruleName == null)
			return null;
		List rules = allRules(grammar);
		for (AbstractRule abstractRule : rules) {
			if (ruleName.equals(abstractRule.getName())) {
				return abstractRule;
			}
		}
		return null;
	}

	public static List allUsedGrammars(Grammar grammar) {
		List grammars = new ArrayList();
		collectAllUsedGrammars(grammars, grammar);
		return grammars;
	}

	private static void collectAllUsedGrammars(List grammars, Grammar grammar) {
		grammars.addAll(grammar.getUsedGrammars());
		for (Grammar g : grammar.getUsedGrammars())
			collectAllUsedGrammars(grammars, g);
	}

	public static List allRules(Grammar grammar) {
		final List result = new ArrayList();
		final Set names = new HashSet();
		final Set grammars = new HashSet();
		collectAllRules(grammar, result, grammars, names);
		return result;
	}

	private static void collectAllRules(Grammar grammar, List result, Set visitedGrammars,
			Set knownRulenames) {
		if (!visitedGrammars.add(grammar))
			return;

		for (AbstractRule rule : grammar.getRules()) {
			if (knownRulenames.add(rule.getName())) {
				result.add(rule);
			}
		}

		for (Grammar usedGrammar : grammar.getUsedGrammars()) {
			collectAllRules(usedGrammar, result, visitedGrammars, knownRulenames);
		}
	}

	public static List allParserRules(Grammar _this) {
		return typeSelect(allRules(_this), ParserRule.class);
	}

	public static List allEnumRules(Grammar _this) {
		return typeSelect(allRules(_this), EnumRule.class);
	}

	public static List allTerminalRules(Grammar _this) {
		return typeSelect(allRules(_this), TerminalRule.class);
	}

	public static List allMetamodelDeclarations(Grammar grammar) {
		final List result = new ArrayList();
		final Set> pairs = new HashSet>();
		final Set grammars = new HashSet();
		collectAllMetamodelDeclarations(grammar, result, pairs, grammars);
		return result;
	}

	private static void collectAllMetamodelDeclarations(Grammar grammar, List result,
			Set> knownAliases, Set visitedGrammars) {
		if (!visitedGrammars.add(grammar))
			return;

		for (AbstractMetamodelDeclaration decl : grammar.getMetamodelDeclarations()) {
			if (decl.getEPackage() == null)
				result.add(decl);
			else if (knownAliases.add(getURIAliasPair(decl))) {
				result.add(decl);
			}
		}
		for (Grammar usedGrammar : grammar.getUsedGrammars())
			collectAllMetamodelDeclarations(usedGrammar, result, knownAliases, visitedGrammars);
	}

	private static Pair getURIAliasPair(AbstractMetamodelDeclaration decl) {
		return Tuples.create(decl.getEPackage().getNsURI(), Strings.emptyIfNull(decl.getAlias()));
	}

	public static String getTypeRefName(TypeRef typeRef) {
		if (typeRef.getClassifier() != null)
			return typeRef.getClassifier().getName();
		final ICompositeNode node = NodeModelUtils.getNode(typeRef);
		if (node != null) {
			final BidiIterator leafNodes = node.getAsTreeIterable().iterator();
			while (leafNodes.hasPrevious()) {
				INode previous = leafNodes.previous();
				if (previous instanceof ILeafNode && !((ILeafNode) previous).isHidden())
					return previous.getText();
			}
		}
		return null;
	}

	public static boolean isAssigned(EObject e) {
		return containingAssignment(e) != null;
	}
	
	public static boolean isAssignedAction(EObject e) {
		return e instanceof Action && ((Action) e).getFeature() != null;
	}
	
	public static boolean isUnassignedAction(EObject e) {
		return e instanceof Action && ((Action) e).getFeature() == null;
	}

	public static Set getAllKeywords(Grammar g) {
		Set kws = new HashSet();
		List rules = allParserRules(g);
		for (ParserRule parserRule : rules) {
			List list = typeSelect(eAllContentsAsList(parserRule), Keyword.class);
			for (Keyword keyword : list) {
				kws.add(keyword.getValue());
			}
		}
		List enumRules = allEnumRules(g);
		for (EnumRule enumRule : enumRules) {
			List list = typeSelect(eAllContentsAsList(enumRule), Keyword.class);
			for (Keyword keyword : list) {
				kws.add(keyword.getValue());
			}
		}
		return kws;
	}

	public static boolean isBooleanAssignment(Assignment a) {
		return "?=".equals(a.getOperator());
	}

	public static boolean isSingleAssignment(Assignment a) {
		return "=".equals(a.getOperator());
	}

	public static boolean isMultipleAssignment(Assignment a) {
		return "+=".equals(a.getOperator());
	}

	public static boolean isMultipleAssignment(Action a) {
		return "+=".equals(a.getOperator());
	}

	public static boolean isOptionalCardinality(AbstractElement e) {
		return e.getCardinality() != null && (e.getCardinality().equals("?") || e.getCardinality().equals("*"));
	}

	public static boolean isMultipleCardinality(AbstractElement e) {
		return isOneOrMoreCardinality(e) || isAnyCardinality(e);
	}

	public static boolean isOneOrMoreCardinality(AbstractElement e) {
		return e.getCardinality() != null && (e.getCardinality().equals("+"));
	}

	public static boolean isAnyCardinality(AbstractElement e) {
		return e.getCardinality() != null && (e.getCardinality().equals("*"));
	}

	public static boolean isDatatypeRule(ParserRule parserRule) {
		return parserRule.getType() != null && parserRule.getType().getClassifier() instanceof EDataType;
	}

	public static boolean isDatatypeRule(AbstractRule abstractRule) {
		return abstractRule instanceof ParserRule && isDatatypeRule((ParserRule) abstractRule);
	}

	// TODO replace me by compiled grammar model
	public static EReference getReference(CrossReference ref, EClass referenceOwner) {
		final String feature = GrammarUtil.containingAssignment(ref).getFeature();
		EStructuralFeature result = referenceOwner.getEStructuralFeature(feature);
		if (result instanceof EReference && !((EReference) result).isContainment())
			return (EReference) result;
		return null;
	}
	
	// TODO replace me by compiled grammar model
	public static EReference getReference(CrossReference crossRef) {
		EClassifier referenceOwner = findCurrentType(crossRef);
		if (referenceOwner instanceof EClass)
			return getReference(crossRef, (EClass) referenceOwner);
		return null;
	}

	public static EClassifier findCurrentType(final AbstractElement element) {
		return new CurrentTypeFinder().findCurrentTypeAfter(element);
	}

	public static Collection allEPackagesToValidate(final Grammar _this) {
		Iterable allTypeRefs = concat(transform(allParserRules(_this), new Function>() {
			public Iterable apply(ParserRule from) {
				return EcoreUtil2.eAllOfType(from, TypeRef.class);
			}
		}));
		return newLinkedHashSet(transform(filter(allTypeRefs, new Predicate() {
			public boolean apply(TypeRef input) {
				return !(input.eContainer() instanceof CrossReference) && input.getClassifier() instanceof EClass;
			}
		}), new Function() {
			public EPackage apply(TypeRef from) {
				return from.getClassifier().getEPackage();
			}
		}));
	}
	
	/**
	 * Find the datatype for EString which is referable from the given grammar.
	 * @since 2.1
	 */
	public static EDataType findEString(Grammar grammar) {
		EClassifier result = findEClassifierByName(grammar, EcorePackage.eNS_URI, EcorePackage.Literals.ESTRING.getName());
		if (result instanceof EDataType)
			return (EDataType) result;
		return null;
	}
	
	/**
	 * Find the datatype for EBoolean which is referable from the given grammar.
	 * @since 2.1
	 */
	public static EDataType findEBoolean(Grammar grammar) {
		EClassifier result = findEClassifierByName(grammar, EcorePackage.eNS_URI, EcorePackage.Literals.EBOOLEAN.getName());
		if (result instanceof EDataType)
			return (EDataType) result;
		return null;
	}
	
	/**
	 * Find the datatype for EBoolean which is referable from the given grammar.
	 * @since 2.1
	 */
	public static EClass findEObject(Grammar grammar) {
		EClassifier result = findEClassifierByName(grammar, EcorePackage.eNS_URI, EcorePackage.Literals.EOBJECT.getName());
		if (result instanceof EClass)
			return (EClass) result;
		return null;
	}
	
	private static EClassifier findEClassifierByName(Grammar grammar, String nsURI, String name) {
		if (grammar != null) {
			for(AbstractMetamodelDeclaration declaration: allMetamodelDeclarations(grammar)) {
				if (declaration instanceof ReferencedMetamodel) {
					EPackage referencedPackage = declaration.getEPackage();
					if (referencedPackage != null && !referencedPackage.eIsProxy()) {
						if (nsURI.equals(referencedPackage.getNsURI())) {
							EClassifier result = referencedPackage.getEClassifier(name);
							if (result != null)
								return result;
						}
					}
				}
			}
		}
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy