From 71fc54a96bf33dde7895ade0bd280887553125b0 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Thu, 29 Feb 2024 02:24:06 +0100 Subject: refactor(language): assignment and cast expression Also reorganizes operator names for easier future extension. --- subprojects/frontend/src/language/problem.grammar | 11 +- .../src/language/problemLanguageSupport.ts | 2 +- .../ProblemCrossrefProposalProvider.java | 15 + subprojects/language-model/problem.aird | 431 +++++++++++++++------ .../src/main/resources/model/problem.ecore | 15 +- .../src/main/resources/model/problem.genmodel | 15 +- .../java/tools/refinery/language/Problem.xtext | 31 +- .../resource/state/DerivedVariableComputer.java | 19 +- .../resource/state/ImplicitVariableScope.java | 18 +- .../language/scoping/ProblemScopeProvider.java | 30 +- 10 files changed, 404 insertions(+), 183 deletions(-) diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar index 32f76f6a..0f6ea3e1 100644 --- a/subprojects/frontend/src/language/problem.grammar +++ b/subprojects/frontend/src/language/problem.grammar @@ -9,6 +9,7 @@ @external prop implicitCompletion from './props' @precedence { + cast, prefix, exponential @right, multiplicative @left, @@ -16,6 +17,7 @@ range @left, lattice @left, comparison @left, + assignment, feature @cut } @@ -97,14 +99,17 @@ Parameter { Modality? RelationName? VariableName } // Being looser with token sequencing enables more consistent syntactic highlighting. Conjunction { ("," | NextConjunction[@dynamicPrecedence=-10] { Expr })+ } -Case { Conjunction ("->" Expr)? } +// Case { Conjunction ("->" Expr)? } OrOp { ";" } Expr { - UnaryExpr | BinaryExpr | Aggregation | VariableName | Atom | Constant | "(" Expr ")" + AssignmentExpr | UnaryExpr | BinaryExpr | CastExpr | Aggregation | + VariableName | Atom | Constant | "(" Expr ")" } +AssignmentExpr { !assignment VariableName kw<"is"> Expr } + BinaryExpr { Expr !comparison ComparisonOp Expr | Expr !lattice (LatticeMeet | "\\/") Expr | @@ -118,6 +123,8 @@ UnaryExpr { !prefix ("+" | "-" | "!" | kw<"count"> | Modality) Expr } +CastExpr { !cast Expr kw<"as"> DatatypeName } + Aggregation { AggregationOp "{" Expr "|" Expr "}" } diff --git a/subprojects/frontend/src/language/problemLanguageSupport.ts b/subprojects/frontend/src/language/problemLanguageSupport.ts index 9500fbf2..3d25d699 100644 --- a/subprojects/frontend/src/language/problemLanguageSupport.ts +++ b/subprojects/frontend/src/language/problemLanguageSupport.ts @@ -33,7 +33,7 @@ const parserWithMetadata = parser.configure({ 'default error contained containment': t.modifier, 'true false unknown error': t.keyword, 'may must current count': t.operatorKeyword, - 'sum prod min max in': t.operatorKeyword, + 'sum prod min max in is': t.operatorKeyword, // 'new delete': t.keyword, NotOp: t.operator, UnknownOp: t.operator, diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java index a09a475b..8b2542f3 100644 --- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java +++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java @@ -125,6 +125,13 @@ public class ProblemCrossrefProposalProvider extends IdeCrossrefProposalProvider return oppositeShouldBeVisible(candidateReferenceDeclaration, context); } + if (eReference.equals(ProblemPackage.Literals.VARIABLE_OR_NODE_EXPR__VARIABLE_OR_NODE)) { + var assignedVariable = getAssignedVariable(context.getCurrentModel()); + if (assignedVariable != null && Objects.equals(assignedVariable, candidate.getEObjectOrProxy())) { + return false; + } + } + var builtinSymbolsOption = desugarer.getBuiltinSymbols(context.getRootModel()); if (builtinSymbolsOption.isEmpty()) { return true; @@ -135,6 +142,14 @@ public class ProblemCrossrefProposalProvider extends IdeCrossrefProposalProvider candidateEObjectOrProxy); } + private VariableOrNode getAssignedVariable(EObject context) { + var assignmentExpr = EcoreUtil2.getContainerOfType(context, AssignmentExpr.class); + if (assignmentExpr.getLeft() instanceof VariableOrNodeExpr variableOrNodeExpr) { + return variableOrNodeExpr.getVariableOrNode(); + } + return null; + } + private boolean importedModuleShouldBeVisible(IEObjectDescription candidate, ContentAssistContext context) { var moduleKind = candidate.getUserData(ProblemResourceDescriptionStrategy.MODULE_KIND); if (!ModuleKind.MODULE.getName().equals(moduleKind)) { diff --git a/subprojects/language-model/problem.aird b/subprojects/language-model/problem.aird index 37516af1..c253facb 100644 --- a/subprojects/language-model/problem.aird +++ b/subprojects/language-model/problem.aird @@ -11,7 +11,7 @@ - + @@ -2699,7 +2699,7 @@ - + @@ -2708,7 +2708,7 @@ - + @@ -2717,7 +2717,7 @@ - + @@ -2768,19 +2768,11 @@ - - - - - - - - - + @@ -2798,7 +2790,7 @@ - + @@ -2858,7 +2850,7 @@ - + @@ -2871,7 +2863,7 @@ - + @@ -2884,7 +2876,7 @@ - + @@ -2897,7 +2889,7 @@ - + @@ -2915,7 +2907,7 @@ - + @@ -2928,7 +2920,7 @@ - + @@ -2994,7 +2986,7 @@ - + @@ -3025,7 +3017,7 @@ - + @@ -3034,7 +3026,7 @@ - + @@ -3081,16 +3073,7 @@ - - - - - - - - - - + @@ -3103,7 +3086,7 @@ - + @@ -3128,7 +3111,55 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3165,33 +3196,33 @@ - + - + - + - + - + - + - + - + @@ -3213,33 +3244,33 @@ - + - + - + - + - + - + - + - + @@ -3261,17 +3292,17 @@ - + - + - + - + @@ -3341,17 +3372,17 @@ - + - + - + @@ -3389,17 +3420,17 @@ - + - + - + - + @@ -3464,7 +3495,7 @@ - + @@ -3533,17 +3564,17 @@ - + - + - + - + @@ -3627,22 +3658,6 @@ - - - - - - - - - - - - - - - - @@ -3659,6 +3674,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3674,7 +3769,7 @@ - + KEEP_LOCATION @@ -3723,7 +3818,7 @@ - + KEEP_LOCATION @@ -3887,22 +3982,6 @@ - - - - - - - - - - - - - - - - @@ -4059,7 +4138,7 @@ - + KEEP_LOCATION @@ -4524,7 +4603,7 @@ - + KEEP_LOCATION @@ -4671,29 +4750,6 @@ - - - - KEEP_LOCATION - KEEP_SIZE - KEEP_RATIO - - - - - - - - - - - - italic - - - - - @@ -4768,6 +4824,129 @@ + + + + KEEP_LOCATION + KEEP_SIZE + KEEP_RATIO + + + + + + + + + + + + + + + + + + + + italic + + + + + + + + + KEEP_LOCATION + KEEP_SIZE + KEEP_RATIO + + + + + + + + + + + + + + + + + + + + + + + + + KEEP_LOCATION + KEEP_SIZE + KEEP_RATIO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + italic + + + + + + + + + KEEP_LOCATION + KEEP_SIZE + KEEP_RATIO + + + + + + + + + + + + italic + + + + + diff --git a/subprojects/language-model/src/main/resources/model/problem.ecore b/subprojects/language-model/src/main/resources/model/problem.ecore index bac409f9..eed134fd 100644 --- a/subprojects/language-model/src/main/resources/model/problem.ecore +++ b/subprojects/language-model/src/main/resources/model/problem.ecore @@ -199,8 +199,6 @@ - - @@ -249,7 +247,6 @@ - @@ -267,4 +264,16 @@ + + + + + + + + + + + + diff --git a/subprojects/language-model/src/main/resources/model/problem.genmodel b/subprojects/language-model/src/main/resources/model/problem.genmodel index 29df79cf..927ec609 100644 --- a/subprojects/language-model/src/main/resources/model/problem.genmodel +++ b/subprojects/language-model/src/main/resources/model/problem.genmodel @@ -51,8 +51,6 @@ - - @@ -69,6 +67,10 @@ + + + + @@ -226,7 +228,6 @@ - @@ -235,5 +236,13 @@ + + + + + + + + diff --git a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext index a2fea627..43351d3e 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext +++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext @@ -103,7 +103,10 @@ Parameter: // name=Identifier; Expr: - ComparisonExpr; + AssignmentExpr; + +AssignmentExpr returns Expr: + ComparisonExpr ({AssignmentExpr.left=current}"is" right=ComparisonExpr)*; enum ComparisonOp: LESS="<" | LESS_EQ="<=" | GREATER=">" | GREATER_EQ=">=" | EQ="==" | NOT_EQ="!=" | @@ -113,15 +116,16 @@ ComparisonExpr returns Expr: LatticeExpr ({ComparisonExpr.left=current} op=ComparisonOp right=LatticeExpr)*; -enum LatticeOp returns BinaryOp: +enum LatticeBinaryOp: MEET="/\\" | JOIN="\\/"; LatticeExpr returns Expr: - RangeExpr ({ArithmeticBinaryExpr.left=current} - op=LatticeOp right=RangeExpr)*; + RangeExpr ({LatticeBinaryExpr.left=current} + op=LatticeBinaryOp right=RangeExpr)*; RangeExpr returns Expr: - AdditiveExpr ({RangeExpr.left=current} ".." right=AdditiveExpr)*; + AdditiveExpr ({RangeExpr.left=current} ".." ("*" | right=AdditiveExpr))* | + {RangeExpr} "*" ".." ("*" | right=AdditiveExpr); enum AdditiveOp returns BinaryOp: ADD="+" | SUB="-"; @@ -145,8 +149,8 @@ ExponentialExpr returns Expr: op=ExponentialOp right=ExponentialExpr)?; UnaryExpr returns Expr: - ArithmeticUnaryExpr | ModalExpr | NegationExpr | CountExpr | AggregationExpr | - Atom | VariableOrNodeExpr | Constant | "(" Expr ")"; + ArithmeticUnaryExpr | ModalExpr | NegationExpr | + CountExpr | AggregationExpr | CastExpr; enum UnaryOp: PLUS="+" | MINUS="-"; @@ -170,7 +174,13 @@ enum AggregationOp: SUM="sum" | PROD="prod" | MIN="min" | MAX="max"; AggregationExpr: - op=AggregationOp "{" value=Expr "|" condition=Expr "}"; + op=AggregationOp "{" value=Expr "|" condition=ComparisonExpr "}"; + +CastExpr returns Expr: + CastExprBody ({CastExpr.body=current} "as" targetType=[Relation|QualifiedName])?; + +CastExprBody returns Expr: + Atom | VariableOrNodeExpr | Constant | "(" Expr ")"; Atom: relation=[Relation|QualifiedName] @@ -181,7 +191,7 @@ VariableOrNodeExpr: variableOrNode=[VariableOrNode|QualifiedName]; Constant: - RealConstant | IntConstant | InfConstant | StringConstant | LogicConstant; + RealConstant | IntConstant | StringConstant | LogicConstant; IntConstant: intValue=INT; @@ -189,9 +199,6 @@ IntConstant: RealConstant: realValue=Real; -InfConstant: - {InfConstant} "*"; - StringConstant: stringValue=STRING; diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java index f0baf35f..f096264b 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/state/DerivedVariableComputer.java @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ @@ -44,15 +44,14 @@ public class DerivedVariableComputer { knownVariables.add(name); } } - if (definition instanceof PredicateDefinition predicateDefinition) { - installDerivedPredicateDefinitionState(predicateDefinition, knownVariables); - } else if (definition instanceof FunctionDefinition functionDefinition) { - installDerivedFunctionDefinitionState(functionDefinition, knownVariables); - } else if (definition instanceof RuleDefinition ruleDefinition) { - installDerivedRuleDefinitionState(ruleDefinition, knownVariables); - } else { - throw new IllegalArgumentException("Unknown ParametricDefinition: " + definition); - } + switch (definition) { + case PredicateDefinition predicateDefinition -> + installDerivedPredicateDefinitionState(predicateDefinition, knownVariables); + case FunctionDefinition functionDefinition -> + installDerivedFunctionDefinitionState(functionDefinition, knownVariables); + case RuleDefinition ruleDefinition -> installDerivedRuleDefinitionState(ruleDefinition, knownVariables); + default -> throw new IllegalArgumentException("Unknown ParametricDefinition: " + definition); + } } protected void installDerivedPredicateDefinitionState(PredicateDefinition definition, Set knownVariables) { diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/state/ImplicitVariableScope.java b/subprojects/language/src/main/java/tools/refinery/language/resource/state/ImplicitVariableScope.java index e25887ad..c8e01724 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/resource/state/ImplicitVariableScope.java +++ b/subprojects/language/src/main/java/tools/refinery/language/resource/state/ImplicitVariableScope.java @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ @@ -16,10 +16,7 @@ import org.eclipse.xtext.scoping.IScopeProvider; import tools.refinery.language.model.problem.*; import tools.refinery.language.naming.NamingUtil; -import java.util.Deque; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public class ImplicitVariableScope { private final EObject root; @@ -71,13 +68,12 @@ public class ImplicitVariableScope { if ((hasKnownVariables && hasParent) || (!hasKnownVariables && !hasParent)) { throw new IllegalStateException("Either known variables or parent must be provided, but not both"); } - if (hasKnownVariables) { - return; - } - if (parent.knownVariables == null) { - throw new IllegalStateException("Parent scope must be processed before current scope"); + if (!hasKnownVariables) { + if (parent.knownVariables == null) { + throw new IllegalStateException("Parent scope must be processed before current scope"); + } + knownVariables = new HashSet<>(parent.knownVariables); } - knownVariables = new HashSet<>(parent.knownVariables); } private void processEObject(EObject eObject, IScopeProvider scopeProvider, LinkingHelper linkingHelper, diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java index a4437ba6..f83a7ebd 100644 --- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java +++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors + * SPDX-FileCopyrightText: 2021-2024 The Refinery Authors * * SPDX-License-Identifier: EPL-2.0 */ @@ -18,8 +18,8 @@ import org.eclipse.xtext.scoping.Scopes; import tools.refinery.language.model.problem.*; import tools.refinery.language.utils.ProblemDesugarer; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.LinkedHashSet; /** * This class contains custom scoping description. @@ -58,7 +58,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { } protected IScope getVariableScope(EObject context, IScope delegateScope) { - List variables = new ArrayList<>(); + Collection variables = new LinkedHashSet<>(); addSingletonVariableToScope(context, variables); EObject currentContext = context; while (currentContext != null && !(currentContext instanceof ParametricDefinition)) { @@ -73,7 +73,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { return Scopes.scopeFor(variables, parentScope); } - protected void addSingletonVariableToScope(EObject context, List variables) { + protected void addSingletonVariableToScope(EObject context, Collection variables) { if (context instanceof VariableOrNodeExpr expr) { Variable singletonVariable = expr.getSingletonVariable(); if (singletonVariable != null) { @@ -82,18 +82,21 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { } } - protected void addExistentiallyQualifiedVariableToScope(EObject currentContext, List variables) { - if (currentContext instanceof ExistentialQuantifier quantifier) { - variables.addAll(quantifier.getImplicitVariables()); - } else if (currentContext instanceof Match match) { - variables.addAll(match.getCondition().getImplicitVariables()); - } else if (currentContext instanceof Consequent consequent) { + protected void addExistentiallyQualifiedVariableToScope(EObject currentContext, Collection variables) { + switch (currentContext) { + case ExistentialQuantifier quantifier -> variables.addAll(quantifier.getImplicitVariables()); + case Match match -> variables.addAll(match.getCondition().getImplicitVariables()); + case Consequent consequent -> { for (var literal : consequent.getActions()) { if (literal instanceof NewAction newAction && newAction.getVariable() != null) { variables.add(newAction.getVariable()); } } } + default -> { + // Nothing to add. + } + } } protected IScope getOppositeScope(EObject context) { @@ -105,10 +108,7 @@ public class ProblemScopeProvider extends AbstractProblemScopeProvider { if (!(relation instanceof ClassDeclaration classDeclaration)) { return IScope.NULLSCOPE; } - var referenceDeclarations = classDeclaration.getFeatureDeclarations() - .stream() - .filter(ReferenceDeclaration.class::isInstance) - .toList(); + var referenceDeclarations = classDeclaration.getFeatureDeclarations(); return Scopes.scopeFor(referenceDeclarations); } } -- cgit v1.2.3-54-g00ecf