diff options
Diffstat (limited to 'rba.tool.editor/src/rba/tool/editor/scoping')
8 files changed, 309 insertions, 0 deletions
diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/IExpressionScope.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/IExpressionScope.xtend new file mode 100644 index 0000000..12f7ca4 --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/IExpressionScope.xtend @@ -0,0 +1,22 @@ +package rba.tool.editor.scoping + +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.scoping.IScope + +interface IExpressionScope { + + enum Anchor { + UNKNOWN, + CONSTRAINT + } + + def IScope getFeatureScope(EObject model, IExpressionScope.Anchor anchor); + + IExpressionScope NULL = new NullExpressionScope(); + + class NullExpressionScope implements IExpressionScope { + override getFeatureScope(EObject model, IExpressionScope.Anchor anchor) { + return IScope.NULLSCOPE; + } + } +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelExpressionScope.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelExpressionScope.xtend new file mode 100644 index 0000000..90bdf3b --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelExpressionScope.xtend @@ -0,0 +1,22 @@ +package rba.tool.editor.scoping + +import com.google.inject.Inject +import com.google.inject.Singleton +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.scoping.IScope +import rba.tool.editor.scoping.internal.RBAModelMemberFieldScopes +import rba.tool.editor.scoping.internal.RBAModelMemberOperationScopes + +@Singleton +class RBAModelExpressionScope implements IExpressionScope { + + @Inject private RBAModelMemberFieldScopes filedScopeCreator; + @Inject private RBAModelMemberOperationScopes operationScopeCreator; + + override getFeatureScope(EObject model, IExpressionScope.Anchor anchor) { + var IScope result = filedScopeCreator.createFeatureScope(model); + result = operationScopeCreator.createFeatureScope(model, anchor, result); + return result; + } + +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelImportedNamespaceAwareLocalScopeProvider.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelImportedNamespaceAwareLocalScopeProvider.xtend new file mode 100644 index 0000000..3dad349 --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelImportedNamespaceAwareLocalScopeProvider.xtend @@ -0,0 +1,42 @@ +package rba.tool.editor.scoping + +import java.util.Iterator +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.xtext.resource.IEObjectDescription +import org.eclipse.xtext.scoping.Scopes +import org.eclipse.xtext.scoping.impl.ImportedNamespaceAwareLocalScopeProvider +import org.eclipse.xtext.scoping.impl.MultimapBasedSelectable +import org.eclipse.xtext.xbase.lib.Functions.Function1 +import rba.core.RBACorePackage +import rba.core.Variable + +class RBAModelImportedNamespaceAwareLocalScopeProvider extends ImportedNamespaceAwareLocalScopeProvider { + + private Function1<? super IEObjectDescription, Boolean> variableFilter = [ description | + description.EClass !== RBACorePackage.Literals.VARIABLE + ]; + + override protected getResourceScope(Resource res, EReference reference) { + val context = res.getContents().get(0); + var globalScope = getGlobalScope(res, reference, variableFilter); + val normalizers = getImplicitImports(isIgnoreCase(reference)); + if(!normalizers.isEmpty()) { + globalScope = createImportScope(globalScope, normalizers, null, reference.getEReferenceType(), isIgnoreCase(reference)); + } + return getResourceScope(globalScope, context, reference); + } + + override protected internalGetAllDescriptions(Resource resource) { + val allContents = new Iterable<EObject>() { + override Iterator<EObject> iterator() { + return EcoreUtil.getAllContents(resource, false).filter(c|!(c instanceof Variable)); + } + }; + val allDescriptions = Scopes.scopedElementsFor(allContents, qualifiedNameProvider); + return new MultimapBasedSelectable(allDescriptions); + } + +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelScopeProvider.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelScopeProvider.xtend new file mode 100644 index 0000000..8fe190f --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/RBAModelScopeProvider.xtend @@ -0,0 +1,85 @@ +/* + * generated by Xtext 2.12.0 + */ +package rba.tool.editor.scoping + +import java.util.ArrayList +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EReference +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import rba.core.AbstractProperty +import rba.core.ComplexExpression +import rba.core.Content +import rba.core.ContentState +import rba.core.Expression +import rba.core.LambdaExpression +import rba.core.ObjectReference +import rba.core.RBACorePackage +import rba.core.Scene +import rba.core.State +import rba.tool.editor.rbaEditorModel.MemberFeatureReference + +/** + * This class contains custom scoping description. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#scoping + * on how and when to use it. + */ +class RBAModelScopeProvider extends AbstractRBAModelScopeProvider { + + override getScope(EObject context, EReference reference) { + val scope = super.getScope(context, reference); + + if(reference == RBACorePackage.Literals.OBJECT_REFERENCE__REF_OBJECT) { + if(context instanceof MemberFeatureReference) { + var Expression expression = (context as MemberFeatureReference).operand.get(0); + if(expression !== null) { + if(!(expression instanceof ObjectReference)) { + return IScope.NULLSCOPE; + } + val rootElement = (expression as ObjectReference).refObject; + if(rootElement instanceof Scene) { + val candidates = EcoreUtil2.getAllContentsOfType(rootElement, AbstractProperty); + return Scopes.scopeFor(candidates); + } else if(rootElement instanceof Content) { + val candidates = #[ContentState].map(clazz|EcoreUtil2.getAllContentsOfType(rootElement, clazz).filter(c|c.eContainer === rootElement)).flatten; + return Scopes.scopeFor(candidates); + } else if(rootElement instanceof State) { + val candidates = EcoreUtil2.getAllContentsOfType(rootElement, State).filter(c|c.eContainer === rootElement); + return Scopes.scopeFor(candidates); + } + } + } else if(context instanceof ObjectReference) { + val candidates = EcoreUtil2.getAllContainers(context).filter(Expression).map [ container | + val list = new ArrayList<EObject>(); + if(container instanceof LambdaExpression) { + val lambda = container as LambdaExpression; + if(lambda.x !== null) + list.add(lambda.x); + if(lambda.letStatements !== null && lambda.letStatements.size > 0) + list.addAll(lambda.letStatements.map(l|l.variable)); + if(lambda.bodyText !== null && lambda.bodyText.letStatements !== null && lambda.bodyText.letStatements.size > 0) + list.addAll(lambda.bodyText.letStatements.map(l|l.variable)); + } else if(container instanceof ComplexExpression) { + val complex = container as ComplexExpression; + if(complex.letStatements !== null && complex.letStatements.size > 0) + list.addAll(complex.letStatements.map(l|l.variable)); + } else { + if(container.letStatements !== null && container.letStatements.size > 0) + list.addAll(container.letStatements.map(l|l.variable)); + } + return list; + ].flatten + + if(candidates.size > 0) { + return Scopes.scopeFor(candidates, scope); + } + } + } + + return scope; + } + +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/internal/IMemberFeatureScopes.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/internal/IMemberFeatureScopes.xtend new file mode 100644 index 0000000..5d6bba7 --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/internal/IMemberFeatureScopes.xtend @@ -0,0 +1,12 @@ +package rba.tool.editor.scoping.internal + +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.scoping.IScope +import rba.tool.editor.scoping.IExpressionScope + +interface IMemberFeatureScopes { + + def IScope createFeatureScope(EObject model); + + def IScope createFeatureScope(EObject model, IExpressionScope.Anchor anchor, IScope outer); +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberFieldScopes.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberFieldScopes.xtend new file mode 100644 index 0000000..a2c9b6f --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberFieldScopes.xtend @@ -0,0 +1,31 @@ +package rba.tool.editor.scoping.internal + +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.Scopes +import rba.core.AbstractProperty +import rba.core.Content +import rba.core.ContentState +import rba.core.Scene +import rba.core.State +import rba.tool.editor.scoping.IExpressionScope + +class RBAModelMemberFieldScopes implements IMemberFeatureScopes { + + override createFeatureScope(EObject model) { + createFeatureScope(model, IExpressionScope.Anchor.UNKNOWN, IScope.NULLSCOPE); + } + + override createFeatureScope(EObject model, IExpressionScope.Anchor anchor, IScope outer) { + if (model instanceof Scene) { + return Scopes.scopeFor(EcoreUtil2.getAllContentsOfType(model, AbstractProperty), outer); + } else if (model instanceof Content) { + return Scopes.scopeFor(EcoreUtil2.getAllContentsOfType(model, ContentState), outer); + } else if (model instanceof State) { + return Scopes.scopeFor(EcoreUtil2.getAllContentsOfType(model, State), outer); + } else { + return outer; + } + } +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationRegistry.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationRegistry.xtend new file mode 100644 index 0000000..b641362 --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationRegistry.xtend @@ -0,0 +1,68 @@ +package rba.tool.editor.scoping.internal + +import com.google.inject.Inject +import com.google.inject.Singleton +import java.util.Collections +import java.util.Map +import java.util.Set +import java.util.regex.Matcher +import java.util.regex.Pattern +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.GrammarUtil +import org.eclipse.xtext.IGrammarAccess +import org.eclipse.xtext.Keyword +import org.eclipse.xtext.generator.parser.antlr.FirstSetComputer +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.resource.IEObjectDescription +import rba.core.ExpressionType +import rba.core.Operator +import rba.core.RuleObject +import rba.tool.editor.resource.RBAModelEObjectDescription +import rba.tool.editor.scoping.IExpressionScope + +@Singleton +class RBAModelMemberOperationRegistry { + + private static Map<String, String> EMPTY_USERDATA = Collections.<String, String>emptyMap(); + private static Pattern pattern = Pattern.compile("^ConfigurationParserRule_([A-Za-z]+)OperatorFor([A-Za-z]+)$"); + private static String DESCRIPTION_KEY = "%s_%s"; + private static String QUALIFIED_NAME = "%s()"; + + private final Map<String, Set<IEObjectDescription>> operations = newLinkedHashMap(); + + @Inject + public new(IGrammarAccess grammarAccess) { + registerOperations(grammarAccess); + } + + def protected void registerOperations(IGrammarAccess grammarAccess) { + val multipleOperandParserRule = GrammarUtil.findRuleForName(grammarAccess.getGrammar(), "ConfigurationParserRule_OperatorWithMultipleOperand"); + val multipleOperandConfiguration = FirstSetComputer.getFirstSet(multipleOperandParserRule.alternatives).filter(Keyword).toList; + val allConfigurations = GrammarUtil.allRules(grammarAccess.getGrammar()).filter(r|pattern.matcher(r.name).find); + for (configuration : allConfigurations) { + val Matcher matcher = pattern.matcher(configuration.name); + if (matcher.find) { + val descriptionKey = String.format(DESCRIPTION_KEY, matcher.group(1), matcher.group(2)).toUpperCase; + val descriptionEntries = newHashSet(); + val keywords = FirstSetComputer.getFirstSet(configuration.alternatives).filter(Keyword); + for (keyword : keywords) { + descriptionEntries.add( + new RBAModelEObjectDescription(QualifiedName.create(String.format(QUALIFIED_NAME, keyword.value)), null, EMPTY_USERDATA, + #[if (multipleOperandConfiguration.contains(keyword)) -1 else 0, -50])); + } + operations.put(descriptionKey, descriptionEntries); + } + } + } + + def public Set<IEObjectDescription> getOperations(EObject model, IExpressionScope.Anchor anchor) { + var ExpressionType expressionType = ExpressionType.BOOLEAN; + if (model instanceof RuleObject) { + expressionType = (model as RuleObject).expressionType; + } else if (model instanceof Operator) { + expressionType = (model as Operator).underlyingType; + } + return operations.get(String.format(DESCRIPTION_KEY, expressionType.getName(), anchor.name)); + } + +} diff --git a/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationScopes.xtend b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationScopes.xtend new file mode 100644 index 0000000..da833ec --- /dev/null +++ b/rba.tool.editor/src/rba/tool/editor/scoping/internal/RBAModelMemberOperationScopes.xtend @@ -0,0 +1,27 @@ +package rba.tool.editor.scoping.internal + +import com.google.inject.Inject +import org.eclipse.emf.ecore.EObject +import org.eclipse.xtext.scoping.IScope +import org.eclipse.xtext.scoping.impl.SimpleScope +import rba.tool.editor.scoping.IExpressionScope + +class RBAModelMemberOperationScopes implements IMemberFeatureScopes { + + private RBAModelMemberOperationRegistry operationRegistry; + + @Inject + new(RBAModelMemberOperationRegistry operationRegistry) { + this.operationRegistry = operationRegistry; + } + + override createFeatureScope(EObject model) { + return createFeatureScope(model, IExpressionScope.Anchor.UNKNOWN, IScope.NULLSCOPE); + } + + override createFeatureScope(EObject model, IExpressionScope.Anchor anchor, IScope outer) { + val descriptions = operationRegistry.getOperations(model, anchor); + return new SimpleScope(outer, descriptions ?: newHashSet()); + } + +} |