From b7db563dc425dbf90e42b1c69fb4d52c41a18503 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Mon, 28 Jun 2021 02:45:33 +0200 Subject: Add scoping tests and simplify implicit nodes * Do not export implicit nodes to the global scope * Enum literals must not be quoted * Plan for the future: unify quoted nodes from the global scope in post-processing --- .../viatra/solver/language/GenerateProblem.mwe2 | 4 +- .../eclipse/viatra/solver/language/Problem.xtext | 7 +- .../language/generator/ProblemGenerator.java | 30 +++++++ .../language/generator/ProblemGenerator.xtend | 25 ------ .../resource/ProblemDerivedStateComputer.java | 36 +++++---- .../ProblemResourceDescriptionStrategy.java | 94 +++++++++++++--------- .../language/scoping/ProblemScopeProvider.java | 18 ++++- 7 files changed, 122 insertions(+), 92 deletions(-) create mode 100644 language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.java delete mode 100644 language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend (limited to 'language/src/main/java/org') diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 b/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 index a63681c8..da5e95a4 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 +++ b/language/src/main/java/org/eclipse/viatra/solver/language/GenerateProblem.mwe2 @@ -43,9 +43,7 @@ Workflow { validator = { generateDeprecationValidation = true } - generator = { - generateXtendStub = true - } + generator = null junitSupport = { junitVersion = "5" } diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext b/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext index 7e253ef5..495f50e4 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext +++ b/language/src/main/java/org/eclipse/viatra/solver/language/Problem.xtext @@ -22,7 +22,7 @@ EnumDeclaration: ("{" (literals+=EnumLiteral ("," literals+=EnumLiteral)* ("," | ";")?)? "}" | "."); EnumLiteral returns Node: - name=QuotedOrUnquotedId; + name=Identifier; ReferenceDeclaration: (containment?="contains" | "refers")? @@ -129,11 +129,8 @@ ExactMultiplicity: UpperBound returns ecore::EInt: INT | "*"; -QuotedOrUnquotedId: - QUOTED_ID | Identifier; - QualifiedName hidden(): - QUOTED_ID | Identifier ("::" Identifier)* ("::" QUOTED_ID)?; + QUOTED_ID | Identifier ("::" Identifier)*; Identifier: ID | "true" | "false" | "e" | "E"; diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.java b/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.java new file mode 100644 index 00000000..b6ea3553 --- /dev/null +++ b/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.java @@ -0,0 +1,30 @@ +/* + * generated by Xtext 2.26.0.M1 + */ +package org.eclipse.viatra.solver.language.generator; + +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.xtext.generator.AbstractGenerator; +import org.eclipse.xtext.generator.IFileSystemAccess2; +import org.eclipse.xtext.generator.IGeneratorContext; + +/** + * Generates code from your model files on save. + * + * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation + */ +public class ProblemGenerator extends AbstractGenerator { + + @Override + public void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { +// Iterator filtered = Iterators.filter(resource.getAllContents(), Greeting.class); +// Iterator names = Iterators.transform(filtered, new Function() { +// +// @Override +// public String apply(Greeting greeting) { +// return greeting.getName(); +// } +// }); +// fsa.generateFile("greetings.txt", "People to greet: " + IteratorExtensions.join(names, ", ")); + } +} diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend b/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend deleted file mode 100644 index 0930f244..00000000 --- a/language/src/main/java/org/eclipse/viatra/solver/language/generator/ProblemGenerator.xtend +++ /dev/null @@ -1,25 +0,0 @@ -/* - * generated by Xtext 2.25.0 - */ -package org.eclipse.viatra.solver.language.generator - -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.xtext.generator.AbstractGenerator -import org.eclipse.xtext.generator.IFileSystemAccess2 -import org.eclipse.xtext.generator.IGeneratorContext - -/** - * Generates code from your model files on save. - * - * See https://www.eclipse.org/Xtext/documentation/303_runtime_concepts.html#code-generation - */ -class ProblemGenerator extends AbstractGenerator { - - override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { -// fsa.generateFile('greetings.txt', 'People to greet: ' + -// resource.allContents -// .filter(Greeting) -// .map[name] -// .join(', ')) - } -} diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java index fc03fa87..56d8ad71 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemDerivedStateComputer.java @@ -73,13 +73,14 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { protected void installDerivedProblemState(Problem problem, boolean preLinkingPhase) { installNewNodes(problem); - if (!preLinkingPhase) { - installDerivedNodes(problem); - for (Statement statement : problem.getStatements()) { - if (statement instanceof PredicateDefinition) { - PredicateDefinition definition = (PredicateDefinition) statement; - installDerivedPredicateDefinitionState(definition); - } + if (preLinkingPhase) { + return; + } + Set nodeNames = installDerivedNodes(problem); + for (Statement statement : problem.getStatements()) { + if (statement instanceof PredicateDefinition) { + PredicateDefinition definition = (PredicateDefinition) statement; + installDerivedPredicateDefinitionState(definition, nodeNames); } } } @@ -88,7 +89,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { for (Statement statement : problem.getStatements()) { if (statement instanceof ClassDeclaration) { ClassDeclaration declaration = (ClassDeclaration) statement; - if (!declaration.isAbstract()) { + if (!declaration.isAbstract() && declaration.getNewNode() == null) { Node newNode = createNode(NEW_NODE); declaration.setNewNode(newNode); } @@ -96,7 +97,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { } } - protected void installDerivedNodes(Problem problem) { + protected Set installDerivedNodes(Problem problem) { IScope nodeScope = scopeProvider.getScope(problem, ProblemPackage.Literals.ASSERTION__ARGUMENTS); Set nodeNames = new HashSet<>(); for (Statement statement : problem.getStatements()) { @@ -142,6 +143,7 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { Node graphNode = createNode(nodeName); grapNodes.add(graphNode); } + return nodeNames; } private void addNodeNames(Set nodeNames, IScope nodeScope, EObject eObject, EStructuralFeature feature, @@ -165,16 +167,17 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { return node; } - protected void installDerivedPredicateDefinitionState(PredicateDefinition definition) { - Set parameterNames = new HashSet<>(); + protected void installDerivedPredicateDefinitionState(PredicateDefinition definition, Set nodeNames) { + Set knownVariables = new HashSet<>(); + knownVariables.addAll(nodeNames); for (Parameter parameter : definition.getParameters()) { String name = parameter.getName(); if (name != null) { - parameterNames.add(name); + knownVariables.add(name); } } for (Conjunction body : definition.getBodies()) { - installDeriveConjunctionState(body, parameterNames); + installDeriveConjunctionState(body, knownVariables); } } @@ -271,10 +274,9 @@ public class ProblemDerivedStateComputer implements IDerivedStateComputer { protected void discardDerivedProblemState(Problem problem) { problem.getNodes().clear(); for (Statement statement : problem.getStatements()) { - if (statement instanceof ClassDeclaration) { - ClassDeclaration classDeclaration = (ClassDeclaration) statement; - classDeclaration.setNewNode(null); - } else if (statement instanceof PredicateDefinition) { + // We deliberately don't clean up {@link ClassDeclaration#getNewNode()} nodes, + // because they have already been exported to the Xtext index. + if (statement instanceof PredicateDefinition) { PredicateDefinition definition = (PredicateDefinition) statement; for (Conjunction body : definition.getBodies()) { body.getImplicitVariables().clear(); diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java index edb25a1c..4d932a92 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java +++ b/language/src/main/java/org/eclipse/viatra/solver/language/resource/ProblemResourceDescriptionStrategy.java @@ -24,56 +24,70 @@ public class ProblemResourceDescriptionStrategy extends DefaultResourceDescripti @Override public boolean createEObjectDescriptions(EObject eObject, IAcceptor acceptor) { - if (eObject instanceof Variable) { + if (!shouldExport(eObject)) { return false; } - if (eObject instanceof NamedElement) { - NamedElement namedElement = (NamedElement) eObject; - String name = namedElement.getName(); - if (name == null || name.isEmpty()) { - return true; - } - Problem problem = EcoreUtil2.getContainerOfType(namedElement, Problem.class); - QualifiedName problemQualifiedName = null; - if (problem != null) { - String problemName = problem.getName(); - if (problemName != null && !problemName.isEmpty()) { - problemQualifiedName = qualifiedNameConverter.toQualifiedName(problemName); - } - } - QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(namedElement.getName()); - boolean nameExported; - if (shouldExportSimpleName(namedElement)) { - acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); - nameExported = true; - } else { - nameExported = false; + if (!(eObject instanceof NamedElement)) { + return true; + } + NamedElement namedElement = (NamedElement) eObject; + String name = namedElement.getName(); + if (name == null || name.isEmpty()) { + return true; + } + Problem problem = EcoreUtil2.getContainerOfType(namedElement, Problem.class); + QualifiedName problemQualifiedName = null; + if (problem != null) { + String problemName = problem.getName(); + if (problemName != null && !problemName.isEmpty()) { + problemQualifiedName = qualifiedNameConverter.toQualifiedName(problemName); } - EObject parent = namedElement.eContainer(); - while (parent != null && parent != problem) { - if (parent instanceof NamedElement) { - NamedElement namedParent = (NamedElement) parent; - String parentName = namedParent.getName(); - if (parentName != null || !name.isEmpty()) { - QualifiedName parentQualifiedName = qualifiedNameConverter.toQualifiedName(parentName); - qualifiedName = parentQualifiedName.append(qualifiedName); - if (shouldExportSimpleName(parent)) { - acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); - nameExported = true; - } else { - nameExported = false; - } + } + QualifiedName qualifiedName = qualifiedNameConverter.toQualifiedName(namedElement.getName()); + boolean nameExported; + if (shouldExportSimpleName(namedElement)) { + acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); + nameExported = true; + } else { + nameExported = false; + } + EObject parent = namedElement.eContainer(); + while (parent != null && parent != problem) { + if (parent instanceof NamedElement) { + NamedElement namedParent = (NamedElement) parent; + String parentName = namedParent.getName(); + if (parentName != null || !name.isEmpty()) { + QualifiedName parentQualifiedName = qualifiedNameConverter.toQualifiedName(parentName); + qualifiedName = parentQualifiedName.append(qualifiedName); + if (shouldExportSimpleName(namedParent)) { + acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); + nameExported = true; + } else { + nameExported = false; } } - parent = parent.eContainer(); - } - if (!nameExported) { - acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); } + parent = parent.eContainer(); + } + if (!nameExported) { + acceptEObjectDescription(namedElement, problemQualifiedName, qualifiedName, acceptor); } return true; } + protected boolean shouldExport(EObject eObject) { + if (eObject instanceof Variable) { + // Variables are always private to the containing predicate definition. + return false; + } + if (eObject instanceof Node) { + Node node = (Node) eObject; + // Only enum literals and new nodes are visible across problem files. + return ProblemUtil.isEnumLiteral(node) || ProblemUtil.isNewNode(node); + } + return true; + } + protected boolean shouldExportSimpleName(EObject eObject) { if (eObject instanceof Node) { return !ProblemUtil.isNewNode((Node) eObject); diff --git a/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java index 3748e81d..597085a8 100644 --- a/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java +++ b/language/src/main/java/org/eclipse/viatra/solver/language/scoping/ProblemScopeProvider.java @@ -13,6 +13,7 @@ import org.eclipse.viatra.solver.language.ProblemUtil; import org.eclipse.viatra.solver.language.model.problem.ClassDeclaration; import org.eclipse.viatra.solver.language.model.problem.ExistentialQuantifier; import org.eclipse.viatra.solver.language.model.problem.PredicateDefinition; +import org.eclipse.viatra.solver.language.model.problem.Problem; import org.eclipse.viatra.solver.language.model.problem.ProblemPackage; import org.eclipse.viatra.solver.language.model.problem.ReferenceDeclaration; import org.eclipse.viatra.solver.language.model.problem.Relation; @@ -34,14 +35,27 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { @Override public IScope getScope(EObject context, EReference reference) { IScope scope = super.getScope(context, reference); + if (reference == ProblemPackage.Literals.NODE_ASSERTION_ARGUMENT__NODE + || reference == ProblemPackage.Literals.NODE_VALUE_ASSERTION__NODE) { + return getNodesScope(context, scope); + } if (reference == ProblemPackage.Literals.VARIABLE_OR_NODE_ARGUMENT__VARIABLE_OR_NODE) { return getVariableScope(context, scope); - } else if (reference == ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE) { + } + if (reference == ProblemPackage.Literals.REFERENCE_DECLARATION__OPPOSITE) { return getOppositeScope(context, scope); } return scope; } + protected IScope getNodesScope(EObject context, IScope delegateScope) { + Problem problem = EcoreUtil2.getContainerOfType(context, Problem.class); + if (problem == null) { + return delegateScope; + } + return Scopes.scopeFor(problem.getNodes(), delegateScope); + } + protected IScope getVariableScope(EObject context, IScope delegateScope) { List variables = new ArrayList<>(); EObject currentContext = context; @@ -63,7 +77,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { PredicateDefinition definition = (PredicateDefinition) currentContext; variables.addAll(definition.getParameters()); } - return Scopes.scopeFor(variables, delegateScope); + return Scopes.scopeFor(variables, getNodesScope(context, delegateScope)); } protected IScope getOppositeScope(EObject context, IScope delegateScope) { -- cgit v1.2.3-70-g09d2