aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <marussy@mit.bme.hu>2023-06-18 18:04:43 +0200
committerLibravatar GitHub <noreply@github.com>2023-06-18 18:04:43 +0200
commita0619c0fbf1fab2304ca683343803d1f37c2ef7c (patch)
tree6d6e342b019a1f3ad0baae710cf520a5dffe4b9e /subprojects
parentMerge pull request #24 from kris7t/partial-interpretation (diff)
parentchore(deps): bump dependencies (diff)
downloadrefinery-a0619c0fbf1fab2304ca683343803d1f37c2ef7c.tar.gz
refinery-a0619c0fbf1fab2304ca683343803d1f37c2ef7c.tar.zst
refinery-a0619c0fbf1fab2304ca683343803d1f37c2ef7c.zip
Merge pull request #26 from kris7t/query-refactor
Query refactor
Diffstat (limited to 'subprojects')
-rw-r--r--subprojects/frontend/.eslintrc.cjs18
-rw-r--r--subprojects/frontend/assets-src/favicon.svg.license3
-rw-r--r--subprojects/frontend/assets-src/icon.svg.license3
-rw-r--r--subprojects/frontend/assets-src/mask-icon.svg.license3
-rw-r--r--subprojects/frontend/build.gradle131
-rw-r--r--subprojects/frontend/build.gradle.kts144
-rw-r--r--subprojects/frontend/config/backendConfigVitePlugin.ts6
-rw-r--r--subprojects/frontend/config/detectDevModeOptions.ts6
-rw-r--r--subprojects/frontend/config/eslintReport.cjs58
-rw-r--r--subprojects/frontend/config/fetchPackageMetadata.ts6
-rw-r--r--subprojects/frontend/config/manifest.ts8
-rw-r--r--subprojects/frontend/config/minifyHTMLVitePlugin.ts6
-rw-r--r--subprojects/frontend/config/preloadFontsVitePlugin.ts6
-rw-r--r--subprojects/frontend/index.html11
-rw-r--r--subprojects/frontend/package.json85
-rw-r--r--subprojects/frontend/prettier.config.cjs6
-rw-r--r--subprojects/frontend/public/apple-touch-icon.png.license3
-rw-r--r--subprojects/frontend/public/favicon-96x96.png.license3
-rw-r--r--subprojects/frontend/public/favicon.png.license3
-rw-r--r--subprojects/frontend/public/favicon.svg.license3
-rw-r--r--subprojects/frontend/public/icon-192x192.png.license3
-rw-r--r--subprojects/frontend/public/icon-512x512.png.license3
-rw-r--r--subprojects/frontend/public/icon-any.svg.license3
-rw-r--r--subprojects/frontend/public/mask-icon.svg.license3
-rw-r--r--subprojects/frontend/public/robots.txt4
-rw-r--r--subprojects/frontend/src/App.tsx6
-rw-r--r--subprojects/frontend/src/Loading.tsx6
-rw-r--r--subprojects/frontend/src/PWAStore.ts6
-rw-r--r--subprojects/frontend/src/Refinery.tsx6
-rw-r--r--subprojects/frontend/src/RootStore.ts6
-rw-r--r--subprojects/frontend/src/RootStoreProvider.tsx6
-rw-r--r--subprojects/frontend/src/ToggleDarkModeButton.tsx6
-rw-r--r--subprojects/frontend/src/TopBar.tsx6
-rw-r--r--subprojects/frontend/src/UpdateNotification.tsx6
-rw-r--r--subprojects/frontend/src/WindowControlsOverlayColor.tsx6
-rw-r--r--subprojects/frontend/src/editor/AnimatedButton.tsx6
-rw-r--r--subprojects/frontend/src/editor/ConnectButton.tsx6
-rw-r--r--subprojects/frontend/src/editor/ConnectionStatusNotification.tsx6
-rw-r--r--subprojects/frontend/src/editor/DiagnosticValue.ts6
-rw-r--r--subprojects/frontend/src/editor/EditorArea.tsx6
-rw-r--r--subprojects/frontend/src/editor/EditorButtons.tsx6
-rw-r--r--subprojects/frontend/src/editor/EditorPane.tsx6
-rw-r--r--subprojects/frontend/src/editor/EditorStore.ts6
-rw-r--r--subprojects/frontend/src/editor/EditorTheme.ts132
-rw-r--r--subprojects/frontend/src/editor/GenerateButton.tsx6
-rw-r--r--subprojects/frontend/src/editor/LintPanelStore.ts6
-rw-r--r--subprojects/frontend/src/editor/PanelStore.ts6
-rw-r--r--subprojects/frontend/src/editor/SearchPanel.ts6
-rw-r--r--subprojects/frontend/src/editor/SearchPanelPortal.tsx6
-rw-r--r--subprojects/frontend/src/editor/SearchPanelStore.ts6
-rw-r--r--subprojects/frontend/src/editor/SearchToolbar.tsx6
-rw-r--r--subprojects/frontend/src/editor/createEditorState.ts10
-rw-r--r--subprojects/frontend/src/editor/defineDecorationSetExtension.ts6
-rw-r--r--subprojects/frontend/src/editor/exposeDiagnostics.ts6
-rw-r--r--subprojects/frontend/src/editor/findOccurrences.ts6
-rw-r--r--subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts341
-rw-r--r--subprojects/frontend/src/editor/scrollbarViewPlugin.ts357
-rw-r--r--subprojects/frontend/src/editor/semanticHighlighting.ts6
-rw-r--r--subprojects/frontend/src/index.tsx6
-rw-r--r--subprojects/frontend/src/language/folding.ts6
-rw-r--r--subprojects/frontend/src/language/indentation.ts7
-rw-r--r--subprojects/frontend/src/language/problem.grammar6
-rw-r--r--subprojects/frontend/src/language/problemLanguageSupport.ts6
-rw-r--r--subprojects/frontend/src/language/props.ts6
-rw-r--r--subprojects/frontend/src/theme/ThemeProvider.tsx10
-rw-r--r--subprojects/frontend/src/theme/ThemeStore.ts6
-rw-r--r--subprojects/frontend/src/utils/CancelledError.ts6
-rw-r--r--subprojects/frontend/src/utils/PendingTask.ts6
-rw-r--r--subprojects/frontend/src/utils/PriorityMutex.ts6
-rw-r--r--subprojects/frontend/src/utils/TimeoutError.ts6
-rw-r--r--subprojects/frontend/src/utils/getLogger.ts6
-rw-r--r--subprojects/frontend/src/utils/useDelayedSnackbar.ts6
-rw-r--r--subprojects/frontend/src/xtext/BackendConfig.ts6
-rw-r--r--subprojects/frontend/src/xtext/ContentAssistService.ts6
-rw-r--r--subprojects/frontend/src/xtext/HighlightingService.ts6
-rw-r--r--subprojects/frontend/src/xtext/OccurrencesService.ts6
-rw-r--r--subprojects/frontend/src/xtext/UpdateService.ts6
-rw-r--r--subprojects/frontend/src/xtext/UpdateStateTracker.ts6
-rw-r--r--subprojects/frontend/src/xtext/ValidationService.ts6
-rw-r--r--subprojects/frontend/src/xtext/XtextClient.ts6
-rw-r--r--subprojects/frontend/src/xtext/XtextWebSocketClient.ts6
-rw-r--r--subprojects/frontend/src/xtext/fetchBackendConfig.ts6
-rw-r--r--subprojects/frontend/src/xtext/webSocketMachine.ts6
-rw-r--r--subprojects/frontend/src/xtext/xtextMessages.ts6
-rw-r--r--subprojects/frontend/src/xtext/xtextServiceResults.ts6
-rw-r--r--subprojects/frontend/tsconfig.base.json39
-rw-r--r--subprojects/frontend/tsconfig.json6
-rw-r--r--subprojects/frontend/tsconfig.node.json6
-rw-r--r--subprojects/frontend/tsconfig.shared.json9
-rw-r--r--subprojects/frontend/types/ImportMeta.d.ts7
-rw-r--r--subprojects/frontend/types/grammar.d.ts7
-rw-r--r--subprojects/frontend/types/node/@lezer-generator-rollup.d.ts7
-rw-r--r--subprojects/frontend/types/windowControlsOverlay.d.ts6
-rw-r--r--subprojects/frontend/vite.config.ts6
-rw-r--r--subprojects/language-ide/build.gradle18
-rw-r--r--subprojects/language-ide/build.gradle.kts18
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java6
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java6
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java5
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/ProblemCrossrefProposalProvider.java5
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java5
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java5
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java6
-rw-r--r--subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java5
-rw-r--r--subprojects/language-model/META-INF/MANIFEST.MF.license3
-rw-r--r--subprojects/language-model/build.gradle55
-rw-r--r--subprojects/language-model/build.gradle.kts65
-rw-r--r--subprojects/language-model/build.properties2
-rw-r--r--subprojects/language-model/plugin.properties2
-rw-r--r--subprojects/language-model/plugin.xml3
-rw-r--r--subprojects/language-model/problem.aird.license3
-rw-r--r--subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe25
-rw-r--r--subprojects/language-model/src/main/resources/model/problem.ecore.license3
-rw-r--r--subprojects/language-model/src/main/resources/model/problem.genmodel.license3
-rw-r--r--subprojects/language-semantics/build.gradle11
-rw-r--r--subprojects/language-semantics/build.gradle.kts17
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java9
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java5
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java5
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java5
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java5
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java5
-rw-r--r--subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java5
-rw-r--r--subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java5
-rw-r--r--subprojects/language-web/build.gradle87
-rw-r--r--subprojects/language-web/build.gradle.kts68
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java12
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java6
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java12
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java52
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java7
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java16
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java5
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java44
-rw-r--r--subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java5
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java60
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java9
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java5
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java5
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java24
-rw-r--r--subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java5
-rw-r--r--subprojects/language/build.gradle73
-rw-r--r--subprojects/language/build.gradle.kts101
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe221
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/Problem.xtext5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemScopeProvider.java6
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java5
-rw-r--r--subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java6
-rw-r--r--subprojects/language/src/main/resources/tools/refinery/language/builtin.problem3
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java5
-rw-r--r--subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java5
-rw-r--r--subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java5
-rw-r--r--subprojects/store-query-viatra/NOTICE.md87
-rw-r--r--subprojects/store-query-viatra/build.gradle16
-rw-r--r--subprojects/store-query-viatra/build.gradle.kts15
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java21
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java10
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java7
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java37
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java15
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java97
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java50
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java27
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java1
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java1
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java1
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java18
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java11
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java89
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java23
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java15
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java12
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java15
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java23
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java72
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java62
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java)11
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java43
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java5
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java)25
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java39
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java44
-rw-r--r--subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java (renamed from subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java)15
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java347
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java382
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java510
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java152
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java87
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java239
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java7
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java5
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java5
-rw-r--r--subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java5
-rw-r--r--subprojects/store-query/build.gradle9
-rw-r--r--subprojects/store-query/build.gradle.kts15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java27
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java12
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java11
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java7
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java)11
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java11
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java175
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java324
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java87
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java238
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java7
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java60
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java45
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java175
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java64
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java65
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java52
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java13
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java47
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java12
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java79
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java41
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java39
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java48
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java24
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java54
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java33
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java20
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java45
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java10
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java79
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java33
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java41
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java26
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java56
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java51
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java50
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java20
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java63
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java47
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java29
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java80
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java60
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java11
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java29
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java10
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java16
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java78
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java19
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java23
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java19
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java48
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java34
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java43
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java83
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java21
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java19
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java36
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java35
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java30
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java83
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java15
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java31
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java86
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java73
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java22
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java5
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java14
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java40
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java112
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java)9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java)17
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java)9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java36
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java105
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java)11
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java)9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java)9
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java20
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java19
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java (renamed from subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java)13
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java57
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java82
-rw-r--r--subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java23
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java (renamed from subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java)146
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java325
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java (renamed from subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java)65
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java112
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java428
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java88
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java94
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java97
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java75
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java259
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java238
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java (renamed from subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java)15
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java80
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java104
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java159
-rw-r--r--subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java102
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java41
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java32
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java7
-rw-r--r--subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java51
-rw-r--r--subprojects/store-reasoning/build.gradle7
-rw-r--r--subprojects/store-reasoning/build.gradle.kts13
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java24
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java14
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java7
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java7
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java18
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java38
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java15
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java16
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java12
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java14
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java10
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java12
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java (renamed from subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java)11
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java (renamed from subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java)11
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java5
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java9
-rw-r--r--subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java5
-rw-r--r--subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java5
-rw-r--r--subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java5
-rw-r--r--subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java5
-rw-r--r--subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java5
-rw-r--r--subprojects/store/build.gradle4
-rw-r--r--subprojects/store/build.gradle.kts10
-rw-r--r--subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java5
-rw-r--r--subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java45
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java97
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java33
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java19
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java16
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java14
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java79
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java9
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/Model.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java10
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java13
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java64
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java31
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java24
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java30
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java22
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java36
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java25
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java46
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java49
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java17
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java35
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java40
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java5
-rw-r--r--subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java29
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java5
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java5
630 files changed, 10643 insertions, 4969 deletions
diff --git a/subprojects/frontend/.eslintrc.cjs b/subprojects/frontend/.eslintrc.cjs
index 8a7b474a..25b86a83 100644
--- a/subprojects/frontend/.eslintrc.cjs
+++ b/subprojects/frontend/.eslintrc.cjs
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1const path = require('node:path'); 7const path = require('node:path');
2 8
3// Allow the Codium ESLint plugin to find `tsconfig.json` from the repository root. 9// Allow the Codium ESLint plugin to find `tsconfig.json` from the repository root.
@@ -43,6 +49,15 @@ module.exports = {
43 // In typescript, some class methods implementing an inderface do not use `this`: 49 // In typescript, some class methods implementing an inderface do not use `this`:
44 // https://github.com/typescript-eslint/typescript-eslint/issues/1103 50 // https://github.com/typescript-eslint/typescript-eslint/issues/1103
45 'class-methods-use-this': 'off', 51 'class-methods-use-this': 'off',
52 // Disable rules with a high performance cost.
53 // See https://typescript-eslint.io/linting/troubleshooting/performance-troubleshooting/
54 'import/default': 'off',
55 'import/extensions': 'off',
56 'import/named': 'off',
57 'import/namespace': 'off',
58 'import/no-named-as-default': 'off',
59 'import/no-named-as-default-member': 'off',
60 '@typescript-eslint/indent': 'off',
46 // Make sure every import can be resolved by `eslint-import-resolver-typescript`. 61 // Make sure every import can be resolved by `eslint-import-resolver-typescript`.
47 'import/no-unresolved': 'error', 62 'import/no-unresolved': 'error',
48 // Organize imports automatically. 63 // Organize imports automatically.
@@ -90,6 +105,7 @@ module.exports = {
90 files: [ 105 files: [
91 '.eslintrc.cjs', 106 '.eslintrc.cjs',
92 'config/*.ts', 107 'config/*.ts',
108 'config/*.cjs',
93 'prettier.config.cjs', 109 'prettier.config.cjs',
94 'vite.config.ts', 110 'vite.config.ts',
95 ], 111 ],
@@ -103,6 +119,8 @@ module.exports = {
103 'error', 119 'error',
104 { devDependencies: true }, 120 { devDependencies: true },
105 ], 121 ],
122 // Allow writing to the console in ad-hoc scripts.
123 'no-console': 'off',
106 // Access to the environment in configuration files. 124 // Access to the environment in configuration files.
107 'no-process-env': 'off', 125 'no-process-env': 'off',
108 }, 126 },
diff --git a/subprojects/frontend/assets-src/favicon.svg.license b/subprojects/frontend/assets-src/favicon.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/assets-src/favicon.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/assets-src/icon.svg.license b/subprojects/frontend/assets-src/icon.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/assets-src/icon.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/assets-src/mask-icon.svg.license b/subprojects/frontend/assets-src/mask-icon.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/assets-src/mask-icon.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/build.gradle b/subprojects/frontend/build.gradle
deleted file mode 100644
index 4cc2c5d7..00000000
--- a/subprojects/frontend/build.gradle
+++ /dev/null
@@ -1,131 +0,0 @@
1plugins {
2 id 'refinery-frontend-workspace'
3 id 'refinery-sonarqube'
4}
5
6import org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn
7
8def viteOutputDir = "${buildDir}/vite"
9def productionResources = file("${viteOutputDir}/production")
10
11frontend {
12 assembleScript = 'run build'
13}
14
15configurations {
16 productionAssets {
17 canBeConsumed = true
18 canBeResolved = false
19 }
20}
21
22def installFrontend = tasks.named('installFrontend')
23
24def sourcesWithoutTypegen = fileTree('src') {
25 exclude '**/*.typegen.ts'
26}
27
28def assembleFrontend = tasks.named('assembleFrontend')
29assembleFrontend.configure {
30 dependsOn generateXStateTypes
31 inputs.dir 'public'
32 inputs.files sourcesWithoutTypegen
33 inputs.file 'index.html'
34 inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts')
35 inputs.file rootProject.file('yarn.lock')
36 outputs.dir productionResources
37}
38
39artifacts {
40 productionAssets(productionResources) {
41 builtBy assembleFrontend
42 }
43}
44
45def generateXStateTypes = tasks.register('generateXStateTypes', RunYarn) {
46 dependsOn installFrontend
47 inputs.files sourcesWithoutTypegen
48 inputs.file 'package.json'
49 inputs.file rootProject.file('yarn.lock')
50 outputs.dir 'src'
51 script = 'run typegen'
52 description = 'Generate TypeScript typings for XState state machines.'
53}
54
55def typecheckFrontend = tasks.register('typecheckFrontend', RunYarn) {
56 dependsOn installFrontend
57 dependsOn generateXStateTypes
58 inputs.dir 'src'
59 inputs.dir 'types'
60 inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.node.json')
61 inputs.file rootProject.file('yarn.lock')
62 outputs.dir "${buildDir}/typescript"
63 script = 'run typecheck'
64 group = 'verification'
65 description = 'Check for TypeScript type errors.'
66}
67
68def lintFrontend = tasks.register('lintFrontend', RunYarn) {
69 dependsOn installFrontend
70 dependsOn generateXStateTypes
71 dependsOn typecheckFrontend
72 inputs.dir 'src'
73 inputs.dir 'types'
74 inputs.files('.eslintrc.cjs', 'prettier.config.cjs')
75 inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.node.json')
76 inputs.file rootProject.file('yarn.lock')
77 if (project.hasProperty('ci')) {
78 outputs.file "${buildDir}/eslint.json"
79 script = 'run lint:ci'
80 } else {
81 script = 'run lint'
82 }
83 group = 'verification'
84 description = 'Check for TypeScript lint errors and warnings.'
85}
86
87def prettier = tasks.register('fixFrontend', RunYarn) {
88 dependsOn installFrontend
89 dependsOn generateXStateTypes
90 dependsOn typecheckFrontend
91 inputs.dir 'src'
92 inputs.dir 'types'
93 inputs.files('.eslintrc.cjs', 'prettier.config.cjs')
94 inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.node.json')
95 inputs.file rootProject.file('yarn.lock')
96 script = 'run lint:fix'
97 group = 'verification'
98 description = 'Fix TypeScript lint errors and warnings.'
99}
100
101tasks.named('check') {
102 dependsOn(typecheckFrontend)
103 dependsOn(lintFrontend)
104}
105
106tasks.register('serveFrontend', RunYarn) {
107 dependsOn installFrontend
108 dependsOn generateXStateTypes
109 inputs.dir 'public'
110 inputs.files sourcesWithoutTypegen
111 inputs.file 'index.html'
112 inputs.files('package.json', 'tsconfig.json', 'tsconfig.base.json', 'vite.config.ts')
113 inputs.file rootProject.file('yarn.lock')
114 outputs.dir "${viteOutputDir}/development"
115 script = 'run serve'
116 group = 'run'
117 description = 'Start a Vite dev server with hot module replacement.'
118}
119
120tasks.named('clean') {
121 delete 'dev-dist'
122 delete fileTree('src') {
123 include '**/*.typegen.ts'
124 }
125}
126
127sonarqube.properties {
128 properties['sonar.sources'] = 'src'
129 property 'sonar.nodejs.executable', "${frontend.nodeInstallDirectory.get()}/bin/node"
130 property 'sonar.eslint.reportPaths', "${buildDir}/eslint.json"
131}
diff --git a/subprojects/frontend/build.gradle.kts b/subprojects/frontend/build.gradle.kts
new file mode 100644
index 00000000..d0839371
--- /dev/null
+++ b/subprojects/frontend/build.gradle.kts
@@ -0,0 +1,144 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn
8import tools.refinery.gradle.utils.SonarPropertiesUtils
9
10plugins {
11 id("tools.refinery.gradle.frontend-workspace")
12 id("tools.refinery.gradle.sonarqube")
13}
14
15frontend {
16 assembleScript.set("run build")
17}
18
19val viteOutputDir = "$buildDir/vite"
20
21val productionResources = file("$viteOutputDir/production")
22
23val productionAssets: Configuration by configurations.creating {
24 isCanBeConsumed = true
25 isCanBeResolved = false
26}
27
28val sourcesWithoutTypes = fileTree("src") {
29 exclude("**/*.typegen.ts")
30}
31
32val sourcesWithTypes: FileCollection = fileTree("src") + fileTree("types")
33
34val buildScripts: FileCollection = fileTree("config") + files(
35 ".eslintrc.cjs",
36 "prettier.config.cjs",
37 "vite.config.ts",
38)
39
40val installationState = files(
41 rootProject.file("yarn.lock"),
42 rootProject.file("package.json"),
43 "package.json",
44)
45
46val sharedConfigFiles: FileCollection = installationState + files(
47 "tsconfig.json",
48 "tsconfig.base.json",
49 "tsconfig.node.json",
50 "tsconfig.shared.json",
51)
52
53val assembleConfigFiles = sharedConfigFiles + file("vite.config.ts") + fileTree("config") {
54 include("**/*.ts")
55}
56
57val assembleSources = sourcesWithTypes + fileTree("public") + file("index.html")
58
59val assembleFiles = assembleSources + assembleConfigFiles
60
61val lintingFiles: FileCollection = sourcesWithTypes + buildScripts + sharedConfigFiles
62
63tasks {
64 val generateXStateTypes by registering(RunYarn::class) {
65 dependsOn(installFrontend)
66 inputs.files(sourcesWithoutTypes)
67 inputs.files(installationState)
68 outputs.dir("src")
69 script.set("run typegen")
70 description = "Generate TypeScript typings for XState state machines."
71 }
72
73 assembleFrontend {
74 dependsOn(generateXStateTypes)
75 inputs.files(assembleFiles)
76 outputs.dir(productionResources)
77 }
78
79
80 val typeCheckFrontend by registering(RunYarn::class) {
81 dependsOn(installFrontend)
82 dependsOn(generateXStateTypes)
83 inputs.files(lintingFiles)
84 outputs.dir("$buildDir/typescript")
85 script.set("run typecheck")
86 group = "verification"
87 description = "Check for TypeScript type errors."
88 }
89
90 val lintFrontend by registering(RunYarn::class) {
91 dependsOn(installFrontend)
92 dependsOn(generateXStateTypes)
93 dependsOn(typeCheckFrontend)
94 inputs.files(lintingFiles)
95 outputs.file("$buildDir/eslint.json")
96 script.set("run lint")
97 group = "verification"
98 description = "Check for TypeScript lint errors and warnings."
99 }
100
101 register<RunYarn>("fixFrontend") {
102 dependsOn(installFrontend)
103 dependsOn(generateXStateTypes)
104 dependsOn(typeCheckFrontend)
105 inputs.files(lintingFiles)
106 script.set("run lint:fix")
107 group = "verification"
108 description = "Fix TypeScript lint errors and warnings."
109 }
110
111 check {
112 dependsOn(typeCheckFrontend)
113 dependsOn(lintFrontend)
114 }
115
116 register<RunYarn>("serveFrontend") {
117 dependsOn(installFrontend)
118 dependsOn(generateXStateTypes)
119 inputs.files(assembleFiles)
120 outputs.dir("$viteOutputDir/development")
121 script.set("run serve")
122 group = "run"
123 description = "Start a Vite dev server with hot module replacement."
124 }
125
126 clean {
127 delete("dev-dist")
128 delete(fileTree("src") {
129 include("**/*.typegen.ts")
130 })
131 }
132}
133
134artifacts {
135 add("productionAssets", productionResources) {
136 builtBy(tasks.assembleFrontend)
137 }
138}
139
140sonarqube.properties {
141 SonarPropertiesUtils.addToList(properties, "sonar.sources", "src")
142 property("sonar.nodejs.executable", "${frontend.nodeInstallDirectory.get()}/bin/node")
143 property("sonar.eslint.reportPaths", "$buildDir/eslint.json")
144}
diff --git a/subprojects/frontend/config/backendConfigVitePlugin.ts b/subprojects/frontend/config/backendConfigVitePlugin.ts
index 7a6bc3db..3bffce3a 100644
--- a/subprojects/frontend/config/backendConfigVitePlugin.ts
+++ b/subprojects/frontend/config/backendConfigVitePlugin.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { PluginOption } from 'vite'; 7import type { PluginOption } from 'vite';
2 8
3import type BackendConfig from '../src/xtext/BackendConfig'; 9import type BackendConfig from '../src/xtext/BackendConfig';
diff --git a/subprojects/frontend/config/detectDevModeOptions.ts b/subprojects/frontend/config/detectDevModeOptions.ts
index b3696241..665204dc 100644
--- a/subprojects/frontend/config/detectDevModeOptions.ts
+++ b/subprojects/frontend/config/detectDevModeOptions.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { PluginOption, ServerOptions } from 'vite'; 7import type { PluginOption, ServerOptions } from 'vite';
2 8
3import backendConfigVitePlugin, { 9import backendConfigVitePlugin, {
diff --git a/subprojects/frontend/config/eslintReport.cjs b/subprojects/frontend/config/eslintReport.cjs
new file mode 100644
index 00000000..7c4b7bd6
--- /dev/null
+++ b/subprojects/frontend/config/eslintReport.cjs
@@ -0,0 +1,58 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7const { writeFile } = require('node:fs/promises');
8const path = require('node:path');
9const { Readable } = require('node:stream');
10const { pipeline } = require('node:stream/promises');
11
12const { ESLint } = require('eslint');
13
14const rootDir = path.join(__dirname, '..');
15
16/**
17 * Write ESLint report to console.
18 *
19 * @param cli {import('eslint').ESLint} The ESLint CLI.
20 * @param report {import('eslint').ESLint.LintResult[]} The ESLint report.
21 * @return {Promise<void>} A promise that resolves when the report is finished.
22 */
23async function reportToConsole(cli, report) {
24 const stylishFormatter = await cli.loadFormatter('stylish');
25 const output = new Readable();
26 output.push(await stylishFormatter.format(report));
27 output.push(null);
28 return pipeline(output, process.stdout);
29}
30
31/**
32 * Write ESLint report to the <code>build</code> directory.
33 *
34 * @param cli {import('eslint').ESLint} The ESLint CLI.
35 * @param report {import('eslint').ESLint.LintResult[]} The ESLint report.
36 * @return {Promise<void>} A promise that resolves when the report is finished.
37 */
38async function reportToJson(cli, report) {
39 const jsonFormatter = await cli.loadFormatter('json');
40 const json = await jsonFormatter.format(report);
41 const reportPath = path.join(rootDir, 'build', 'eslint.json');
42 return writeFile(reportPath, json, 'utf-8');
43}
44
45async function createReport() {
46 const cli = new ESLint({
47 useEslintrc: true,
48 cwd: rootDir,
49 });
50 const report = await cli.lintFiles('.');
51 await Promise.all([reportToConsole(cli, report), reportToJson(cli, report)]);
52
53 if (report.some((entry) => entry.errorCount > 0)) {
54 process.exitCode = 1;
55 }
56}
57
58createReport().catch(console.error);
diff --git a/subprojects/frontend/config/fetchPackageMetadata.ts b/subprojects/frontend/config/fetchPackageMetadata.ts
index 50807b03..02e16d57 100644
--- a/subprojects/frontend/config/fetchPackageMetadata.ts
+++ b/subprojects/frontend/config/fetchPackageMetadata.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { readFile } from 'node:fs/promises'; 7import { readFile } from 'node:fs/promises';
2import path from 'node:path'; 8import path from 'node:path';
3 9
diff --git a/subprojects/frontend/config/manifest.ts b/subprojects/frontend/config/manifest.ts
index 3cec777c..1822dc7c 100644
--- a/subprojects/frontend/config/manifest.ts
+++ b/subprojects/frontend/config/manifest.ts
@@ -1,10 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { ManifestOptions } from 'vite-plugin-pwa'; 7import type { ManifestOptions } from 'vite-plugin-pwa';
2 8
3const manifest: Partial<ManifestOptions> = { 9const manifest: Partial<ManifestOptions> = {
4 lang: 'en-US', 10 lang: 'en-US',
5 name: 'Refinery', 11 name: 'Refinery',
6 short_name: 'Refinery', 12 short_name: 'Refinery',
7 description: 'An efficient graph sovler for generating well-formed models', 13 description: 'An efficient graph solver for generating well-formed models',
8 theme_color: '#f5f5f5', 14 theme_color: '#f5f5f5',
9 display_override: ['window-controls-overlay'], 15 display_override: ['window-controls-overlay'],
10 display: 'standalone', 16 display: 'standalone',
diff --git a/subprojects/frontend/config/minifyHTMLVitePlugin.ts b/subprojects/frontend/config/minifyHTMLVitePlugin.ts
index 18336d4d..7c08c488 100644
--- a/subprojects/frontend/config/minifyHTMLVitePlugin.ts
+++ b/subprojects/frontend/config/minifyHTMLVitePlugin.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { minify, type Options as TerserOptions } from 'html-minifier-terser'; 7import { minify, type Options as TerserOptions } from 'html-minifier-terser';
2import type { PluginOption } from 'vite'; 8import type { PluginOption } from 'vite';
3 9
diff --git a/subprojects/frontend/config/preloadFontsVitePlugin.ts b/subprojects/frontend/config/preloadFontsVitePlugin.ts
index bc6f8eaf..5c04477a 100644
--- a/subprojects/frontend/config/preloadFontsVitePlugin.ts
+++ b/subprojects/frontend/config/preloadFontsVitePlugin.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import micromatch from 'micromatch'; 7import micromatch from 'micromatch';
2import type { PluginOption } from 'vite'; 8import type { PluginOption } from 'vite';
3 9
diff --git a/subprojects/frontend/index.html b/subprojects/frontend/index.html
index 8b6814eb..1bf3472e 100644
--- a/subprojects/frontend/index.html
+++ b/subprojects/frontend/index.html
@@ -1,4 +1,9 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<!--
3 SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
4
5 SPDX-License-Identifier: EPL-2.0
6-->
2<html lang="en-US"> 7<html lang="en-US">
3 <head> 8 <head>
4 <meta charset="utf-8"> 9 <meta charset="utf-8">
@@ -13,9 +18,9 @@
13 <meta name="theme-color" media="(prefers-color-scheme:light)" content="#f5f5f5"> 18 <meta name="theme-color" media="(prefers-color-scheme:light)" content="#f5f5f5">
14 <meta name="theme-color" media="(prefers-color-scheme:dark)" content="#21252b"> 19 <meta name="theme-color" media="(prefers-color-scheme:dark)" content="#21252b">
15 <style> 20 <style>
16 @import '@fontsource/inter/variable.css'; 21 @import '@fontsource-variable/inter/wght.css';
17 @import '@fontsource/jetbrains-mono/variable.css'; 22 @import '@fontsource-variable/jetbrains-mono/wght.css';
18 @import '@fontsource/jetbrains-mono/variable-italic.css'; 23 @import '@fontsource-variable/jetbrains-mono/wght-italic.css';
19 </style> 24 </style>
20 </head> 25 </head>
21 <body> 26 <body>
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json
index a761e74c..ba8a0a58 100644
--- a/subprojects/frontend/package.json
+++ b/subprojects/frontend/package.json
@@ -1,4 +1,9 @@
1{ 1{
2 "//": [
3 "SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>",
4 "",
5 "SPDX-License-Identifier: EPL-2.0"
6 ],
2 "name": "@refinery/frontend", 7 "name": "@refinery/frontend",
3 "version": "0.0.0", 8 "version": "0.0.0",
4 "description": "Web frontend for Refinery", 9 "description": "Web frontend for Refinery",
@@ -9,41 +14,40 @@
9 "serve": "cross-env MODE=development vite serve", 14 "serve": "cross-env MODE=development vite serve",
10 "typegen": "xstate typegen \"src/**/*.ts?(x)\"", 15 "typegen": "xstate typegen \"src/**/*.ts?(x)\"",
11 "typecheck": "tsc -p tsconfig.shared.json && tsc -p tsconfig.node.json && tsc -p tsconfig.json", 16 "typecheck": "tsc -p tsconfig.shared.json && tsc -p tsconfig.node.json && tsc -p tsconfig.json",
12 "lint": "eslint .", 17 "lint": "node config/eslintReport.cjs",
13 "lint:ci": "eslint -f json -o build/eslint.json .",
14 "lint:fix": "yarn run lint --fix" 18 "lint:fix": "yarn run lint --fix"
15 }, 19 },
16 "repository": { 20 "repository": {
17 "type": "git", 21 "type": "git",
18 "url": "git+https://github.com/graphs4value/refinery.git" 22 "url": "git+https://github.com/graphs4value/refinery.git"
19 }, 23 },
20 "author": "Refinery authors", 24 "author": "The Refinery Authors <https://refinery.tools/>",
21 "license": "EPL-2.0", 25 "license": "EPL-2.0",
22 "bugs": { 26 "bugs": {
23 "url": "https://github.com/graphs4value/issues" 27 "url": "https://github.com/graphs4value/refinery/issues"
24 }, 28 },
25 "homepage": "https://refinery.tools", 29 "homepage": "https://refinery.tools",
26 "dependencies": { 30 "dependencies": {
27 "@codemirror/autocomplete": "^6.4.2", 31 "@codemirror/autocomplete": "^6.8.0",
28 "@codemirror/commands": "^6.2.2", 32 "@codemirror/commands": "^6.2.4",
29 "@codemirror/language": "^6.6.0", 33 "@codemirror/language": "^6.8.0",
30 "@codemirror/lint": "^6.2.0", 34 "@codemirror/lint": "^6.2.2",
31 "@codemirror/search": "^6.3.0", 35 "@codemirror/search": "^6.5.0",
32 "@codemirror/state": "^6.2.0", 36 "@codemirror/state": "^6.2.1",
33 "@codemirror/view": "^6.9.3", 37 "@codemirror/view": "^6.13.2",
34 "@emotion/react": "^11.10.6", 38 "@emotion/react": "^11.11.1",
35 "@emotion/styled": "^11.10.6", 39 "@emotion/styled": "^11.11.0",
36 "@fontsource/inter": "^4.5.15", 40 "@fontsource-variable/inter": "^5.0.3",
37 "@fontsource/jetbrains-mono": "^4.5.12", 41 "@fontsource-variable/jetbrains-mono": "^5.0.3",
38 "@lezer/common": "^1.0.2", 42 "@lezer/common": "^1.0.3",
39 "@lezer/highlight": "^1.1.4", 43 "@lezer/highlight": "^1.1.6",
40 "@lezer/lr": "^1.3.3", 44 "@lezer/lr": "^1.3.6",
41 "@material-icons/svg": "^1.0.33", 45 "@material-icons/svg": "^1.0.33",
42 "@mui/icons-material": "5.11.11", 46 "@mui/icons-material": "5.11.16",
43 "@mui/material": "5.11.15", 47 "@mui/material": "5.13.5",
44 "@vitejs/plugin-react-swc": "^3.2.0", 48 "@vitejs/plugin-react-swc": "^3.3.2",
45 "ansi-styles": "^6.2.1", 49 "ansi-styles": "^6.2.1",
46 "csstype": "^3.1.1", 50 "csstype": "^3.1.2",
47 "escape-string-regexp": "^5.0.0", 51 "escape-string-regexp": "^5.0.0",
48 "lodash-es": "^4.17.21", 52 "lodash-es": "^4.17.21",
49 "loglevel": "^1.8.1", 53 "loglevel": "^1.8.1",
@@ -55,42 +59,41 @@
55 "notistack": "^3.0.1", 59 "notistack": "^3.0.1",
56 "react": "^18.2.0", 60 "react": "^18.2.0",
57 "react-dom": "^18.2.0", 61 "react-dom": "^18.2.0",
58 "xstate": "^4.37.1", 62 "xstate": "^4.37.2",
59 "zod": "^3.21.4" 63 "zod": "^3.21.4"
60 }, 64 },
61 "devDependencies": { 65 "devDependencies": {
62 "@lezer/generator": "^1.2.2", 66 "@lezer/generator": "^1.3.0",
63 "@tsconfig/strictest": "^2.0.0", 67 "@types/eslint": "^8.40.2",
64 "@types/eslint": "^8.37.0",
65 "@types/html-minifier-terser": "^7.0.0", 68 "@types/html-minifier-terser": "^7.0.0",
66 "@types/lodash-es": "^4.17.7", 69 "@types/lodash-es": "^4.17.7",
67 "@types/micromatch": "^4.0.2", 70 "@types/micromatch": "^4.0.2",
68 "@types/ms": "^0.7.31", 71 "@types/ms": "^0.7.31",
69 "@types/node": "^18.15.11", 72 "@types/node": "^18.16.18",
70 "@types/prettier": "^2.7.2", 73 "@types/prettier": "^2.7.3",
71 "@types/react": "^18.0.31", 74 "@types/react": "^18.2.12",
72 "@types/react-dom": "^18.0.11", 75 "@types/react-dom": "^18.2.5",
73 "@typescript-eslint/eslint-plugin": "^5.57.0", 76 "@typescript-eslint/eslint-plugin": "^5.59.11",
74 "@typescript-eslint/parser": "^5.57.0", 77 "@typescript-eslint/parser": "^5.59.11",
75 "@xstate/cli": "^0.4.2", 78 "@xstate/cli": "^0.5.1",
76 "cross-env": "^7.0.3", 79 "cross-env": "^7.0.3",
77 "eslint": "^8.37.0", 80 "eslint": "^8.43.0",
78 "eslint-config-airbnb": "^19.0.4", 81 "eslint-config-airbnb": "^19.0.4",
79 "eslint-config-airbnb-typescript": "^17.0.0", 82 "eslint-config-airbnb-typescript": "^17.0.0",
80 "eslint-config-prettier": "^8.8.0", 83 "eslint-config-prettier": "^8.8.0",
81 "eslint-import-resolver-typescript": "^3.5.4", 84 "eslint-import-resolver-typescript": "^3.5.5",
82 "eslint-plugin-import": "^2.27.5", 85 "eslint-plugin-import": "^2.27.5",
83 "eslint-plugin-jsx-a11y": "^6.7.1", 86 "eslint-plugin-jsx-a11y": "^6.7.1",
84 "eslint-plugin-mobx": "^0.0.9", 87 "eslint-plugin-mobx": "^0.0.9",
85 "eslint-plugin-prettier": "^4.2.1", 88 "eslint-plugin-prettier": "^4.2.1",
86 "eslint-plugin-react": "^7.32.2", 89 "eslint-plugin-react": "^7.32.2",
87 "eslint-plugin-react-hooks": "^4.6.0", 90 "eslint-plugin-react-hooks": "^4.6.0",
88 "html-minifier-terser": "^7.1.0", 91 "html-minifier-terser": "^7.2.0",
89 "micromatch": "^4.0.5", 92 "micromatch": "^4.0.5",
90 "prettier": "^2.8.7", 93 "prettier": "^2.8.8",
91 "typescript": "5.0.3", 94 "typescript": "5.1.3",
92 "vite": "^4.2.1", 95 "vite": "^4.3.9",
93 "vite-plugin-pwa": "^0.14.7", 96 "vite-plugin-pwa": "^0.16.4",
94 "workbox-window": "^6.5.4" 97 "workbox-window": "^7.0.0"
95 } 98 }
96} 99}
diff --git a/subprojects/frontend/prettier.config.cjs b/subprojects/frontend/prettier.config.cjs
index 75f5c54d..6f9ff7ad 100644
--- a/subprojects/frontend/prettier.config.cjs
+++ b/subprojects/frontend/prettier.config.cjs
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1/** @type {import('prettier').Config} */ 7/** @type {import('prettier').Config} */
2module.exports = { 8module.exports = {
3 singleQuote: true, 9 singleQuote: true,
diff --git a/subprojects/frontend/public/apple-touch-icon.png.license b/subprojects/frontend/public/apple-touch-icon.png.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/apple-touch-icon.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/favicon-96x96.png.license b/subprojects/frontend/public/favicon-96x96.png.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/favicon-96x96.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/favicon.png.license b/subprojects/frontend/public/favicon.png.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/favicon.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/favicon.svg.license b/subprojects/frontend/public/favicon.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/favicon.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/icon-192x192.png.license b/subprojects/frontend/public/icon-192x192.png.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/icon-192x192.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/icon-512x512.png.license b/subprojects/frontend/public/icon-512x512.png.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/icon-512x512.png.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/icon-any.svg.license b/subprojects/frontend/public/icon-any.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/icon-any.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/mask-icon.svg.license b/subprojects/frontend/public/mask-icon.svg.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/frontend/public/mask-icon.svg.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/frontend/public/robots.txt b/subprojects/frontend/public/robots.txt
index c2a49f4f..e7c73099 100644
--- a/subprojects/frontend/public/robots.txt
+++ b/subprojects/frontend/public/robots.txt
@@ -1,2 +1,6 @@
1# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2#
3# SPDX-License-Identifier: CC0-1.0
4
1User-agent: * 5User-agent: *
2Allow: / 6Allow: /
diff --git a/subprojects/frontend/src/App.tsx b/subprojects/frontend/src/App.tsx
index cd394345..7f242529 100644
--- a/subprojects/frontend/src/App.tsx
+++ b/subprojects/frontend/src/App.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Box from '@mui/material/Box'; 7import Box from '@mui/material/Box';
2import CssBaseline from '@mui/material/CssBaseline'; 8import CssBaseline from '@mui/material/CssBaseline';
3import { throttle } from 'lodash-es'; 9import { throttle } from 'lodash-es';
diff --git a/subprojects/frontend/src/Loading.tsx b/subprojects/frontend/src/Loading.tsx
index 489563e0..adee4f0e 100644
--- a/subprojects/frontend/src/Loading.tsx
+++ b/subprojects/frontend/src/Loading.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import CircularProgress from '@mui/material/CircularProgress'; 7import CircularProgress from '@mui/material/CircularProgress';
2import { styled } from '@mui/material/styles'; 8import { styled } from '@mui/material/styles';
3 9
diff --git a/subprojects/frontend/src/PWAStore.ts b/subprojects/frontend/src/PWAStore.ts
index e9f99e2a..a1b3ffd9 100644
--- a/subprojects/frontend/src/PWAStore.ts
+++ b/subprojects/frontend/src/PWAStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { makeAutoObservable, observable } from 'mobx'; 7import { makeAutoObservable, observable } from 'mobx';
2import ms from 'ms'; 8import ms from 'ms';
3// eslint-disable-next-line import/no-unresolved -- Importing virtual module. 9// eslint-disable-next-line import/no-unresolved -- Importing virtual module.
diff --git a/subprojects/frontend/src/Refinery.tsx b/subprojects/frontend/src/Refinery.tsx
index f0162349..b5ff94e1 100644
--- a/subprojects/frontend/src/Refinery.tsx
+++ b/subprojects/frontend/src/Refinery.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Grow from '@mui/material/Grow'; 7import Grow from '@mui/material/Grow';
2import Stack from '@mui/material/Stack'; 8import Stack from '@mui/material/Stack';
3import { SnackbarProvider } from 'notistack'; 9import { SnackbarProvider } from 'notistack';
diff --git a/subprojects/frontend/src/RootStore.ts b/subprojects/frontend/src/RootStore.ts
index 2e76d66d..b84c0ce0 100644
--- a/subprojects/frontend/src/RootStore.ts
+++ b/subprojects/frontend/src/RootStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { getLogger } from 'loglevel'; 7import { getLogger } from 'loglevel';
2import { makeAutoObservable, runInAction } from 'mobx'; 8import { makeAutoObservable, runInAction } from 'mobx';
3 9
diff --git a/subprojects/frontend/src/RootStoreProvider.tsx b/subprojects/frontend/src/RootStoreProvider.tsx
index 2c11a0f9..7cb89af1 100644
--- a/subprojects/frontend/src/RootStoreProvider.tsx
+++ b/subprojects/frontend/src/RootStoreProvider.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { type ReactNode, createContext, useContext } from 'react'; 7import { type ReactNode, createContext, useContext } from 'react';
2 8
3import type RootStore from './RootStore'; 9import type RootStore from './RootStore';
diff --git a/subprojects/frontend/src/ToggleDarkModeButton.tsx b/subprojects/frontend/src/ToggleDarkModeButton.tsx
index 59714f20..7a835e61 100644
--- a/subprojects/frontend/src/ToggleDarkModeButton.tsx
+++ b/subprojects/frontend/src/ToggleDarkModeButton.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import DarkModeIcon from '@mui/icons-material/DarkMode'; 7import DarkModeIcon from '@mui/icons-material/DarkMode';
2import LightModeIcon from '@mui/icons-material/LightMode'; 8import LightModeIcon from '@mui/icons-material/LightMode';
3import IconButton from '@mui/material/IconButton'; 9import IconButton from '@mui/material/IconButton';
diff --git a/subprojects/frontend/src/TopBar.tsx b/subprojects/frontend/src/TopBar.tsx
index 5a825512..f2542b14 100644
--- a/subprojects/frontend/src/TopBar.tsx
+++ b/subprojects/frontend/src/TopBar.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import GitHubIcon from '@mui/icons-material/GitHub'; 7import GitHubIcon from '@mui/icons-material/GitHub';
2import AppBar from '@mui/material/AppBar'; 8import AppBar from '@mui/material/AppBar';
3import Button from '@mui/material/Button'; 9import Button from '@mui/material/Button';
diff --git a/subprojects/frontend/src/UpdateNotification.tsx b/subprojects/frontend/src/UpdateNotification.tsx
index 5c8c2d01..d86c0703 100644
--- a/subprojects/frontend/src/UpdateNotification.tsx
+++ b/subprojects/frontend/src/UpdateNotification.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Button from '@mui/material/Button'; 7import Button from '@mui/material/Button';
2import { observer } from 'mobx-react-lite'; 8import { observer } from 'mobx-react-lite';
3import { useEffect } from 'react'; 9import { useEffect } from 'react';
diff --git a/subprojects/frontend/src/WindowControlsOverlayColor.tsx b/subprojects/frontend/src/WindowControlsOverlayColor.tsx
index 14eda566..cfa468ea 100644
--- a/subprojects/frontend/src/WindowControlsOverlayColor.tsx
+++ b/subprojects/frontend/src/WindowControlsOverlayColor.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { useTheme } from '@mui/material/styles'; 7import { useTheme } from '@mui/material/styles';
2import { useEffect } from 'react'; 8import { useEffect } from 'react';
3 9
diff --git a/subprojects/frontend/src/editor/AnimatedButton.tsx b/subprojects/frontend/src/editor/AnimatedButton.tsx
index f75d4617..dbbda618 100644
--- a/subprojects/frontend/src/editor/AnimatedButton.tsx
+++ b/subprojects/frontend/src/editor/AnimatedButton.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Box from '@mui/material/Box'; 7import Box from '@mui/material/Box';
2import Button from '@mui/material/Button'; 8import Button from '@mui/material/Button';
3import { styled, type SxProps, type Theme } from '@mui/material/styles'; 9import { styled, type SxProps, type Theme } from '@mui/material/styles';
diff --git a/subprojects/frontend/src/editor/ConnectButton.tsx b/subprojects/frontend/src/editor/ConnectButton.tsx
index e2d251f3..eed6fbc7 100644
--- a/subprojects/frontend/src/editor/ConnectButton.tsx
+++ b/subprojects/frontend/src/editor/ConnectButton.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import CloudIcon from '@mui/icons-material/Cloud'; 7import CloudIcon from '@mui/icons-material/Cloud';
2import CloudOffIcon from '@mui/icons-material/CloudOff'; 8import CloudOffIcon from '@mui/icons-material/CloudOff';
3import SyncIcon from '@mui/icons-material/Sync'; 9import SyncIcon from '@mui/icons-material/Sync';
diff --git a/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx b/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx
index 9b27f45c..b7b962ab 100644
--- a/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx
+++ b/subprojects/frontend/src/editor/ConnectionStatusNotification.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Button from '@mui/material/Button'; 7import Button from '@mui/material/Button';
2import { observer } from 'mobx-react-lite'; 8import { observer } from 'mobx-react-lite';
3import { useEffect } from 'react'; 9import { useEffect } from 'react';
diff --git a/subprojects/frontend/src/editor/DiagnosticValue.ts b/subprojects/frontend/src/editor/DiagnosticValue.ts
index b4e0b165..20478262 100644
--- a/subprojects/frontend/src/editor/DiagnosticValue.ts
+++ b/subprojects/frontend/src/editor/DiagnosticValue.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { Diagnostic } from '@codemirror/lint'; 7import type { Diagnostic } from '@codemirror/lint';
2import { RangeValue } from '@codemirror/state'; 8import { RangeValue } from '@codemirror/state';
3 9
diff --git a/subprojects/frontend/src/editor/EditorArea.tsx b/subprojects/frontend/src/editor/EditorArea.tsx
index cfb988b2..905fa2ec 100644
--- a/subprojects/frontend/src/editor/EditorArea.tsx
+++ b/subprojects/frontend/src/editor/EditorArea.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Box from '@mui/material/Box'; 7import Box from '@mui/material/Box';
2import { useTheme } from '@mui/material/styles'; 8import { useTheme } from '@mui/material/styles';
3import { observer } from 'mobx-react-lite'; 9import { observer } from 'mobx-react-lite';
diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx
index 53b06e23..9b187e5c 100644
--- a/subprojects/frontend/src/editor/EditorButtons.tsx
+++ b/subprojects/frontend/src/editor/EditorButtons.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { Diagnostic } from '@codemirror/lint'; 7import type { Diagnostic } from '@codemirror/lint';
2import CheckIcon from '@mui/icons-material/Check'; 8import CheckIcon from '@mui/icons-material/Check';
3import ErrorIcon from '@mui/icons-material/Error'; 9import ErrorIcon from '@mui/icons-material/Error';
diff --git a/subprojects/frontend/src/editor/EditorPane.tsx b/subprojects/frontend/src/editor/EditorPane.tsx
index f7f8241a..87f408fe 100644
--- a/subprojects/frontend/src/editor/EditorPane.tsx
+++ b/subprojects/frontend/src/editor/EditorPane.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Box from '@mui/material/Box'; 7import Box from '@mui/material/Box';
2import Skeleton from '@mui/material/Skeleton'; 8import Skeleton from '@mui/material/Skeleton';
3import Stack from '@mui/material/Stack'; 9import Stack from '@mui/material/Stack';
diff --git a/subprojects/frontend/src/editor/EditorStore.ts b/subprojects/frontend/src/editor/EditorStore.ts
index 0a0d885d..b98f085e 100644
--- a/subprojects/frontend/src/editor/EditorStore.ts
+++ b/subprojects/frontend/src/editor/EditorStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { 7import type {
2 CompletionContext, 8 CompletionContext,
3 CompletionResult, 9 CompletionResult,
diff --git a/subprojects/frontend/src/editor/EditorTheme.ts b/subprojects/frontend/src/editor/EditorTheme.ts
index 01b65a7e..e057ce18 100644
--- a/subprojects/frontend/src/editor/EditorTheme.ts
+++ b/subprojects/frontend/src/editor/EditorTheme.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import errorSVG from '@material-icons/svg/svg/error/baseline.svg?raw'; 7import errorSVG from '@material-icons/svg/svg/error/baseline.svg?raw';
2import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw'; 8import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw';
3import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw'; 9import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw';
@@ -8,32 +14,6 @@ function svgURL(svg: string): string {
8 return `url('data:image/svg+xml;utf8,${svg}')`; 14 return `url('data:image/svg+xml;utf8,${svg}')`;
9} 15}
10 16
11function radialShadowTheme(
12 origin: string,
13 scaleX: boolean,
14 scaleY: boolean,
15): CSSObject {
16 function radialGradient(opacity: number, scale: string): string {
17 return `radial-gradient(
18 farthest-side at ${origin},
19 rgba(0, 0, 0, ${opacity}),
20 rgba(0, 0, 0, 0)
21 )
22 ${origin} /
23 ${scaleX ? scale : '100%'}
24 ${scaleY ? scale : '100%'}
25 no-repeat`;
26 }
27
28 return {
29 background: `
30 ${radialGradient(0.2, '40%')},
31 ${radialGradient(0.14, '50%')},
32 ${radialGradient(0.12, '100%')}
33 `,
34 };
35}
36
37export default styled('div', { 17export default styled('div', {
38 name: 'EditorTheme', 18 name: 'EditorTheme',
39 shouldForwardProp: (propName) => 19 shouldForwardProp: (propName) =>
@@ -52,98 +32,13 @@ export default styled('div', {
52 }, 32 },
53 }; 33 };
54 34
55 const scrollerThumbOpacity = theme.palette.mode === 'dark' ? 0.16 : 0.28;
56
57 const generalStyle: CSSObject = { 35 const generalStyle: CSSObject = {
58 background: theme.palette.background.default, 36 background: theme.palette.background.default,
59 '&, .cm-editor': { 37 '&, .cm-editor': {
60 height: '100%', 38 height: '100%',
61 }, 39 },
62 '.cm-scroller-holder': {
63 display: 'flex',
64 position: 'relative',
65 flexDirection: 'column',
66 overflow: 'hidden',
67 flex: '1 1',
68 },
69 '.cm-scroller-spacer': {
70 position: 'sticky',
71 flexShrink: 0,
72 zIndex: 300,
73 width: 1,
74 marginRight: -1,
75 pointerEvents: 'none',
76 },
77 '.cm-scroller': { 40 '.cm-scroller': {
78 color: theme.palette.text.secondary, 41 color: theme.palette.text.secondary,
79 scrollbarWidth: 'none',
80 MsOverflowStyle: 'none',
81 '&::-webkit-scrollbar': {
82 width: 0,
83 height: 0,
84 background: 'transparent',
85 },
86 },
87 '.cm-scroller-track': {
88 position: 'absolute',
89 zIndex: 300,
90 touchAction: 'none',
91 },
92 '.cm-scroller-thumb': {
93 position: 'absolute',
94 background: theme.palette.text.secondary,
95 opacity: scrollerThumbOpacity,
96 transition: theme.transitions.create('opacity', {
97 duration: theme.transitions.duration.shortest,
98 }),
99 touchAction: 'none',
100 WebkitTapHighlightColor: 'transparent',
101 '&:hover': {
102 opacity: 0.75,
103 '@media (hover: none)': {
104 opacity: scrollerThumbOpacity,
105 },
106 },
107 '&.active': {
108 opacity: 1,
109 pointerEvents: 'none',
110 userSelect: 'none',
111 },
112 },
113 '.cm-scroller-track-y, .cm-scroller-thumb-y': {
114 top: 0,
115 right: 0,
116 width: 12,
117 },
118 '.cm-scroller-track-x, .cm-scroller-thumb-x': {
119 left: 0,
120 bottom: 0,
121 height: 12,
122 },
123 '.cm-scroller-track-x': {
124 right: 12,
125 },
126 '.cm-scroller-gutter-decoration': {
127 position: 'absolute',
128 top: 0,
129 bottom: 0,
130 left: 0,
131 width: 0,
132 transition: theme.transitions.create('width', {
133 duration: theme.transitions.duration.shortest,
134 }),
135 ...radialShadowTheme('0 50%', true, false),
136 },
137 '.cm-scroller-top-decoration': {
138 position: 'absolute',
139 top: 0,
140 left: 0,
141 right: 0,
142 height: 0,
143 transition: theme.transitions.create('height', {
144 duration: theme.transitions.duration.shortest,
145 }),
146 ...radialShadowTheme('50% 0', false, true),
147 }, 42 },
148 '.cm-gutters': { 43 '.cm-gutters': {
149 background: theme.palette.background.default, 44 background: theme.palette.background.default,
@@ -162,7 +57,6 @@ export default styled('div', {
162 background: 'transparent', 57 background: 'transparent',
163 }, 58 },
164 '.cm-cursor, .cm-cursor-primary': { 59 '.cm-cursor, .cm-cursor-primary': {
165 marginLeft: -1,
166 borderLeft: `2px solid ${theme.palette.info.main}`, 60 borderLeft: `2px solid ${theme.palette.info.main}`,
167 }, 61 },
168 '.cm-selectionBackground': { 62 '.cm-selectionBackground': {
@@ -175,7 +69,6 @@ export default styled('div', {
175 }, 69 },
176 }, 70 },
177 '.cm-line': { 71 '.cm-line': {
178 position: 'relative', // For indentation highlights
179 padding: '0 12px 0 0px', 72 padding: '0 12px 0 0px',
180 }, 73 },
181 }; 74 };
@@ -265,13 +158,6 @@ export default styled('div', {
265 '.cm-searchMatch-selected': { 158 '.cm-searchMatch-selected': {
266 background: theme.palette.highlight.search.selected, 159 background: theme.palette.highlight.search.selected,
267 }, 160 },
268 '.cm-indentation-marker': {
269 display: 'inline-block',
270 boxShadow: `1px 0 0 ${theme.palette.text.disabled} inset`,
271 '&.active': {
272 boxShadow: `1px 0 0 ${theme.palette.text.primary} inset`,
273 },
274 },
275 '.cm-scroller-selection': { 161 '.cm-scroller-selection': {
276 position: 'absolute', 162 position: 'absolute',
277 right: 0, 163 right: 0,
@@ -452,11 +338,11 @@ export default styled('div', {
452 338
453 const foldStyle = { 339 const foldStyle = {
454 '.cm-foldGutter': { 340 '.cm-foldGutter': {
455 width: 17, 341 width: 16,
456 }, 342 },
457 '.problem-editor-foldMarker': { 343 '.problem-editor-foldMarker': {
458 display: 'block', 344 display: 'block',
459 margin: '4px 1px 4px 0', 345 margin: '4px 0 4px 0',
460 padding: 0, 346 padding: 0,
461 maskImage: svgURL(expandMoreSVG), 347 maskImage: svgURL(expandMoreSVG),
462 maskSize: '16px 16px', 348 maskSize: '16px 16px',
@@ -467,7 +353,7 @@ export default styled('div', {
467 cursor: 'pointer', 353 cursor: 'pointer',
468 WebkitTapHighlightColor: 'transparent', 354 WebkitTapHighlightColor: 'transparent',
469 [theme.breakpoints.down('sm')]: { 355 [theme.breakpoints.down('sm')]: {
470 margin: '2px 1px 2px 0', 356 margin: '2px 0 2px 0',
471 }, 357 },
472 }, 358 },
473 '.problem-editor-foldMarker-open': { 359 '.problem-editor-foldMarker-open': {
diff --git a/subprojects/frontend/src/editor/GenerateButton.tsx b/subprojects/frontend/src/editor/GenerateButton.tsx
index 2036fc28..3837ef8e 100644
--- a/subprojects/frontend/src/editor/GenerateButton.tsx
+++ b/subprojects/frontend/src/editor/GenerateButton.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import DangerousOutlinedIcon from '@mui/icons-material/DangerousOutlined'; 7import DangerousOutlinedIcon from '@mui/icons-material/DangerousOutlined';
2import PlayArrowIcon from '@mui/icons-material/PlayArrow'; 8import PlayArrowIcon from '@mui/icons-material/PlayArrow';
3import Button from '@mui/material/Button'; 9import Button from '@mui/material/Button';
diff --git a/subprojects/frontend/src/editor/LintPanelStore.ts b/subprojects/frontend/src/editor/LintPanelStore.ts
index 502f9c59..f81587fa 100644
--- a/subprojects/frontend/src/editor/LintPanelStore.ts
+++ b/subprojects/frontend/src/editor/LintPanelStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { closeLintPanel, openLintPanel } from '@codemirror/lint'; 7import { closeLintPanel, openLintPanel } from '@codemirror/lint';
2 8
3import type EditorStore from './EditorStore'; 9import type EditorStore from './EditorStore';
diff --git a/subprojects/frontend/src/editor/PanelStore.ts b/subprojects/frontend/src/editor/PanelStore.ts
index 4f827280..25ef8b6c 100644
--- a/subprojects/frontend/src/editor/PanelStore.ts
+++ b/subprojects/frontend/src/editor/PanelStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { Command } from '@codemirror/view'; 7import type { Command } from '@codemirror/view';
2import { action, makeObservable, observable } from 'mobx'; 8import { action, makeObservable, observable } from 'mobx';
3 9
diff --git a/subprojects/frontend/src/editor/SearchPanel.ts b/subprojects/frontend/src/editor/SearchPanel.ts
index c9df41b7..b63d5eed 100644
--- a/subprojects/frontend/src/editor/SearchPanel.ts
+++ b/subprojects/frontend/src/editor/SearchPanel.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 type EditorView, 8 type EditorView,
3 type Panel, 9 type Panel,
diff --git a/subprojects/frontend/src/editor/SearchPanelPortal.tsx b/subprojects/frontend/src/editor/SearchPanelPortal.tsx
index 5cf1c90e..b4b07c74 100644
--- a/subprojects/frontend/src/editor/SearchPanelPortal.tsx
+++ b/subprojects/frontend/src/editor/SearchPanelPortal.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import Portal from '@mui/material/Portal'; 7import Portal from '@mui/material/Portal';
2import { observer } from 'mobx-react-lite'; 8import { observer } from 'mobx-react-lite';
3 9
diff --git a/subprojects/frontend/src/editor/SearchPanelStore.ts b/subprojects/frontend/src/editor/SearchPanelStore.ts
index 65d595a8..6a97baf1 100644
--- a/subprojects/frontend/src/editor/SearchPanelStore.ts
+++ b/subprojects/frontend/src/editor/SearchPanelStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 closeSearchPanel, 8 closeSearchPanel,
3 findNext, 9 findNext,
diff --git a/subprojects/frontend/src/editor/SearchToolbar.tsx b/subprojects/frontend/src/editor/SearchToolbar.tsx
index 54f3dba7..4ae7e893 100644
--- a/subprojects/frontend/src/editor/SearchToolbar.tsx
+++ b/subprojects/frontend/src/editor/SearchToolbar.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import CloseIcon from '@mui/icons-material/Close'; 7import CloseIcon from '@mui/icons-material/Close';
2import FindReplaceIcon from '@mui/icons-material/FindReplace'; 8import FindReplaceIcon from '@mui/icons-material/FindReplace';
3import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; 9import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
diff --git a/subprojects/frontend/src/editor/createEditorState.ts b/subprojects/frontend/src/editor/createEditorState.ts
index ce1efa4f..67b8fb9e 100644
--- a/subprojects/frontend/src/editor/createEditorState.ts
+++ b/subprojects/frontend/src/editor/createEditorState.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 closeBrackets, 8 closeBrackets,
3 closeBracketsKeymap, 9 closeBracketsKeymap,
@@ -38,8 +44,6 @@ import type EditorStore from './EditorStore';
38import SearchPanel from './SearchPanel'; 44import SearchPanel from './SearchPanel';
39import exposeDiagnostics from './exposeDiagnostics'; 45import exposeDiagnostics from './exposeDiagnostics';
40import findOccurrences from './findOccurrences'; 46import findOccurrences from './findOccurrences';
41import indentationMarkerViewPlugin from './indentationMarkerViewPlugin';
42import scrollbarViewPlugin from './scrollbarViewPlugin';
43import semanticHighlighting from './semanticHighlighting'; 47import semanticHighlighting from './semanticHighlighting';
44 48
45export default function createEditorState( 49export default function createEditorState(
@@ -64,7 +68,6 @@ export default function createEditorState(
64 highlightSpecialChars(), 68 highlightSpecialChars(),
65 history(), 69 history(),
66 indentOnInput(), 70 indentOnInput(),
67 indentationMarkerViewPlugin(),
68 rectangularSelection(), 71 rectangularSelection(),
69 search({ 72 search({
70 createPanel(view) { 73 createPanel(view) {
@@ -123,7 +126,6 @@ export default function createEditorState(
123 ...defaultKeymap, 126 ...defaultKeymap,
124 ]), 127 ]),
125 problemLanguageSupport(), 128 problemLanguageSupport(),
126 scrollbarViewPlugin(store),
127 ], 129 ],
128 }); 130 });
129} 131}
diff --git a/subprojects/frontend/src/editor/defineDecorationSetExtension.ts b/subprojects/frontend/src/editor/defineDecorationSetExtension.ts
index d9c7bc7d..0887c92e 100644
--- a/subprojects/frontend/src/editor/defineDecorationSetExtension.ts
+++ b/subprojects/frontend/src/editor/defineDecorationSetExtension.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { StateEffect, StateField, TransactionSpec } from '@codemirror/state'; 7import { StateEffect, StateField, TransactionSpec } from '@codemirror/state';
2import { EditorView, Decoration, DecorationSet } from '@codemirror/view'; 8import { EditorView, Decoration, DecorationSet } from '@codemirror/view';
3 9
diff --git a/subprojects/frontend/src/editor/exposeDiagnostics.ts b/subprojects/frontend/src/editor/exposeDiagnostics.ts
index 82f24c93..c4dcbb87 100644
--- a/subprojects/frontend/src/editor/exposeDiagnostics.ts
+++ b/subprojects/frontend/src/editor/exposeDiagnostics.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { setDiagnosticsEffect } from '@codemirror/lint'; 7import { setDiagnosticsEffect } from '@codemirror/lint';
2import { 8import {
3 StateField, 9 StateField,
diff --git a/subprojects/frontend/src/editor/findOccurrences.ts b/subprojects/frontend/src/editor/findOccurrences.ts
index 08c078c2..00dffc96 100644
--- a/subprojects/frontend/src/editor/findOccurrences.ts
+++ b/subprojects/frontend/src/editor/findOccurrences.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 type Range, 8 type Range,
3 RangeSet, 9 RangeSet,
diff --git a/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts b/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts
deleted file mode 100644
index 730fa6e3..00000000
--- a/subprojects/frontend/src/editor/indentationMarkerViewPlugin.ts
+++ /dev/null
@@ -1,341 +0,0 @@
1/**
2 * @file CodeMirror plugin to highlight indentation
3 *
4 * This file is based on the
5 * [@replit/codemirror-indentation-markers](https://github.com/replit/codemirror-indentation-markers)
6 * package, which is available under the
7 * [MIT License](https://github.com/replit/codemirror-indentation-markers/blob/543cc508ca5cef5d8350af23973eb1425e31525c/LICENSE).
8 *
9 * The highlighting heuristics were adjusted to make them more suitable
10 * for logic programming.
11 *
12 * @see https://github.com/replit/codemirror-indentation-markers/blob/543cc508ca5cef5d8350af23973eb1425e31525c/src/index.ts
13 */
14
15import { getIndentUnit } from '@codemirror/language';
16import { Text, RangeSet, EditorState } from '@codemirror/state';
17import {
18 ViewPlugin,
19 Decoration,
20 EditorView,
21 WidgetType,
22 PluginValue,
23} from '@codemirror/view';
24
25export const INDENTATION_MARKER_CLASS = 'cm-indentation-marker';
26
27export const INDENTATION_MARKER_ACTIVE_CLASS = 'active';
28
29const indentationMark = Decoration.mark({
30 class: INDENTATION_MARKER_CLASS,
31 tagName: 'span',
32});
33
34const activeIndentationMark = Decoration.mark({
35 class: `${INDENTATION_MARKER_CLASS} ${INDENTATION_MARKER_ACTIVE_CLASS}`,
36 tagName: 'span',
37});
38
39/**
40 * Widget used to simulate N indentation markers on empty lines.
41 */
42class IndentationWidget extends WidgetType {
43 constructor(
44 readonly numIndent: number,
45 readonly indentSize: number,
46 readonly activeIndent?: number,
47 ) {
48 super();
49 }
50
51 override eq(other: IndentationWidget) {
52 return (
53 this.numIndent === other.numIndent &&
54 this.indentSize === other.indentSize &&
55 this.activeIndent === other.activeIndent
56 );
57 }
58
59 override toDOM(view: EditorView) {
60 const indentSize = getIndentUnit(view.state);
61
62 const wrapper = document.createElement('span');
63 wrapper.style.top = '0';
64 wrapper.style.left = '0';
65 wrapper.style.position = 'absolute';
66 wrapper.style.pointerEvents = 'none';
67
68 for (let indent = 0; indent < this.numIndent; indent += 1) {
69 const element = document.createElement('span');
70 element.className = INDENTATION_MARKER_CLASS;
71 element.classList.toggle(
72 INDENTATION_MARKER_ACTIVE_CLASS,
73 indent === this.activeIndent,
74 );
75 element.innerHTML = ' '.repeat(indentSize);
76 wrapper.appendChild(element);
77 }
78
79 return wrapper;
80 }
81}
82
83/**
84 * Returns the number of indentation markers a non-empty line should have
85 * based on the text in the line and the size of the indent.
86 */
87function getNumIndentMarkersForNonEmptyLine(
88 text: string,
89 indentSize: number,
90 onIndentMarker?: (pos: number) => void,
91) {
92 let numIndents = 0;
93 let numConsecutiveSpaces = 0;
94 let prevChar: string | undefined;
95
96 for (let char = 0; char < text.length; char += 1) {
97 // Bail if we encounter a non-whitespace character
98 if (text[char] !== ' ' && text[char] !== '\t') {
99 // We still increment the indentation level if we would
100 // have added a marker here had this been a space or tab.
101 if (numConsecutiveSpaces % indentSize === 0 && char !== 0) {
102 numIndents += 1;
103 }
104
105 return numIndents;
106 }
107
108 // Every tab and N space has an indentation marker
109 const shouldAddIndent =
110 prevChar === '\t' || numConsecutiveSpaces % indentSize === 0;
111
112 if (shouldAddIndent) {
113 numIndents += 1;
114
115 if (onIndentMarker) {
116 onIndentMarker(char);
117 }
118 }
119
120 if (text[char] === ' ') {
121 numConsecutiveSpaces += 1;
122 } else {
123 numConsecutiveSpaces = 0;
124 }
125
126 prevChar = text[char];
127 }
128
129 return numIndents;
130}
131
132/**
133 * Returns the number of indent markers an empty line should have
134 * based on the number of indent markers of the previous
135 * and next non-empty lines.
136 */
137function getNumIndentMarkersForEmptyLine(prev: number, next: number) {
138 const min = Math.min(prev, next);
139 const max = Math.max(prev, next);
140
141 // If only one side is non-zero, we omit markers,
142 // because in logic programming, a block often ends with an empty line.
143 if (min === 0 && max > 0) {
144 return 0;
145 }
146
147 // Else, default to the minimum of the two
148 return min;
149}
150
151/**
152 * Returns the next non-empty line and its indent level.
153 */
154function findNextNonEmptyLineAndIndentLevel(
155 doc: Text,
156 startLine: number,
157 indentSize: number,
158): [number, number] {
159 const numLines = doc.lines;
160 let lineNo = startLine;
161
162 while (lineNo <= numLines) {
163 const { text } = doc.line(lineNo);
164
165 if (text.trim().length === 0) {
166 lineNo += 1;
167 } else {
168 const indent = getNumIndentMarkersForNonEmptyLine(text, indentSize);
169 return [lineNo, indent];
170 }
171 }
172
173 // Reached the end of the doc
174 return [numLines + 1, 0];
175}
176
177interface IndentationMarkerDesc {
178 lineNumber: number;
179 from: number;
180 to: number;
181 create(activeIndentIndex?: number): Decoration;
182}
183
184/**
185 * Returns a range of lines with an active indent marker.
186 */
187function getLinesWithActiveIndentMarker(
188 state: EditorState,
189 indentMap: Map<number, number>,
190): { start: number; end: number; activeIndent: number } {
191 const currentLine = state.doc.lineAt(state.selection.main.head);
192 const currentIndent = indentMap.get(currentLine.number);
193 const currentLineNo = currentLine.number;
194
195 if (!currentIndent) {
196 return { start: -1, end: -1, activeIndent: NaN };
197 }
198
199 let start: number;
200 let end: number;
201
202 for (start = currentLineNo; start >= 0; start -= 1) {
203 const indent = indentMap.get(start - 1);
204 if (!indent || indent < currentIndent) {
205 break;
206 }
207 }
208
209 for (end = currentLineNo; ; end += 1) {
210 const indent = indentMap.get(end + 1);
211 if (!indent || indent < currentIndent) {
212 break;
213 }
214 }
215
216 return { start, end, activeIndent: currentIndent };
217}
218/**
219 * Adds indentation markers to all lines within view.
220 */
221function addIndentationMarkers(view: EditorView) {
222 const indentSize = getIndentUnit(view.state);
223 const indentSizeMap = new Map</* lineNumber */ number, number>();
224 const decorations: Array<IndentationMarkerDesc> = [];
225
226 view.visibleRanges.forEach(({ from, to }) => {
227 let pos = from;
228
229 let prevIndentMarkers = 0;
230 let nextIndentMarkers = 0;
231 let nextNonEmptyLine = 0;
232
233 while (pos <= to) {
234 const line = view.state.doc.lineAt(pos);
235 const { text } = line;
236
237 // If a line is empty, we match the indentation according
238 // to a heuristic based on the indentations of the
239 // previous and next non-empty lines.
240 if (text.trim().length === 0) {
241 // To retrieve the next non-empty indentation level,
242 // we perform a lookahead and cache the result.
243 if (nextNonEmptyLine < line.number) {
244 const [nextLine, nextIndent] = findNextNonEmptyLineAndIndentLevel(
245 view.state.doc,
246 line.number + 1,
247 indentSize,
248 );
249
250 nextNonEmptyLine = nextLine;
251 nextIndentMarkers = nextIndent;
252 }
253
254 const numIndentMarkers = getNumIndentMarkersForEmptyLine(
255 prevIndentMarkers,
256 nextIndentMarkers,
257 );
258
259 // Add the indent widget and move on to next line
260 indentSizeMap.set(line.number, numIndentMarkers);
261 decorations.push({
262 from: pos,
263 to: pos,
264 lineNumber: line.number,
265 create: (activeIndentIndex) =>
266 Decoration.widget({
267 widget: new IndentationWidget(
268 numIndentMarkers,
269 indentSize,
270 activeIndentIndex,
271 ),
272 }),
273 });
274 } else {
275 const indices: Array<number> = [];
276
277 prevIndentMarkers = getNumIndentMarkersForNonEmptyLine(
278 text,
279 indentSize,
280 (char) => indices.push(char),
281 );
282
283 indentSizeMap.set(line.number, indices.length);
284 decorations.push(
285 ...indices.map(
286 (char, i): IndentationMarkerDesc => ({
287 from: line.from + char,
288 to: line.from + char + 1,
289 lineNumber: line.number,
290 create: (activeIndentIndex) =>
291 activeIndentIndex === i
292 ? activeIndentationMark
293 : indentationMark,
294 }),
295 ),
296 );
297 }
298
299 // Move on to the next line
300 pos = line.to + 1;
301 }
302 });
303
304 const activeBlockRange = getLinesWithActiveIndentMarker(
305 view.state,
306 indentSizeMap,
307 );
308
309 return RangeSet.of<Decoration>(
310 Array.from(decorations).map(({ lineNumber, from, to, create }) => {
311 const activeIndent =
312 lineNumber >= activeBlockRange.start &&
313 lineNumber <= activeBlockRange.end
314 ? activeBlockRange.activeIndent - 1
315 : undefined;
316
317 return { from, to, value: create(activeIndent) };
318 }),
319 true,
320 );
321}
322
323export default function indentationMarkerViewPlugin() {
324 return ViewPlugin.define<PluginValue & { decorations: RangeSet<Decoration> }>(
325 (view) => ({
326 decorations: addIndentationMarkers(view),
327 update(update) {
328 if (
329 update.docChanged ||
330 update.viewportChanged ||
331 update.selectionSet
332 ) {
333 this.decorations = addIndentationMarkers(update.view);
334 }
335 },
336 }),
337 {
338 decorations: (v) => v.decorations,
339 },
340 );
341}
diff --git a/subprojects/frontend/src/editor/scrollbarViewPlugin.ts b/subprojects/frontend/src/editor/scrollbarViewPlugin.ts
deleted file mode 100644
index f44034fd..00000000
--- a/subprojects/frontend/src/editor/scrollbarViewPlugin.ts
+++ /dev/null
@@ -1,357 +0,0 @@
1import { EditorSelection } from '@codemirror/state';
2import {
3 type EditorView,
4 type PluginValue,
5 ViewPlugin,
6} from '@codemirror/view';
7import { reaction } from 'mobx';
8
9import type EditorStore from './EditorStore';
10import { getDiagnostics } from './exposeDiagnostics';
11import findOccurrences from './findOccurrences';
12
13export const HOLDER_CLASS = 'cm-scroller-holder';
14export const SPACER_CLASS = 'cm-scroller-spacer';
15export const TRACK_CLASS = 'cm-scroller-track';
16export const THUMB_CLASS = 'cm-scroller-thumb';
17export const THUMB_ACTIVE_CLASS = 'active';
18export const GUTTER_DECORATION_CLASS = 'cm-scroller-gutter-decoration';
19export const TOP_DECORATION_CLASS = 'cm-scroller-top-decoration';
20export const ANNOTATION_SELECTION_CLASS = 'cm-scroller-selection';
21export const ANNOTATION_DIAGNOSTIC_CLASS = 'cm-scroller-diagnostic';
22export const ANNOTATION_OCCURRENCE_CLASS = 'cm-scroller-occurrence';
23export const SHADOW_WIDTH = 10;
24export const SCROLLBAR_WIDTH = 12;
25export const ANNOTATION_WIDTH = SCROLLBAR_WIDTH / 2;
26export const MIN_ANNOTATION_HEIGHT = 1;
27
28function createScrollbar(
29 holder: HTMLElement,
30 direction: 'x' | 'y',
31 touchCallback: (offsetX: number, offsetY: number) => void,
32 moveCallback: (movementX: number, movementY: number) => void,
33): { track: HTMLElement; thumb: HTMLElement } {
34 const track = holder.ownerDocument.createElement('div');
35 track.className = `${TRACK_CLASS} ${TRACK_CLASS}-${direction}`;
36 holder.appendChild(track);
37
38 const thumb = holder.ownerDocument.createElement('div');
39 thumb.className = `${THUMB_CLASS} ${THUMB_CLASS}-${direction}`;
40 track.appendChild(thumb);
41
42 let pointerId: number | undefined;
43 track.addEventListener('pointerdown', (event) => {
44 if (pointerId !== undefined) {
45 event.preventDefault();
46 return;
47 }
48 ({ pointerId } = event);
49 thumb.classList.add(THUMB_ACTIVE_CLASS);
50 if (event.target === thumb) {
51 // Prevent implicit pointer capture on mobile.
52 thumb.releasePointerCapture(pointerId);
53 } else {
54 touchCallback(event.offsetX, event.offsetY);
55 }
56 track.setPointerCapture(pointerId);
57 });
58
59 track.addEventListener('pointermove', (event) => {
60 if (event.pointerId !== pointerId) {
61 return;
62 }
63 moveCallback(event.movementX, event.movementY);
64 event.preventDefault();
65 });
66
67 function scrollEnd(event: PointerEvent) {
68 if (event.pointerId !== pointerId) {
69 return;
70 }
71 pointerId = undefined;
72 thumb.classList.remove(THUMB_ACTIVE_CLASS);
73 }
74
75 track.addEventListener('pointerup', scrollEnd, { passive: true });
76 track.addEventListener('pointercancel', scrollEnd, { passive: true });
77
78 return { track, thumb };
79}
80
81function rebuildAnnotations(
82 view: EditorView,
83 scrollHeight: number,
84 trackYHeight: number,
85 holder: HTMLElement,
86 annotations: HTMLDivElement[],
87) {
88 const { state } = view;
89 const overlayAnnotationsHeight =
90 (view.contentHeight / scrollHeight) * trackYHeight;
91 const lineHeight = overlayAnnotationsHeight / state.doc.lines;
92
93 let i = 0;
94
95 function getOrCreateAnnotation(from: number, to?: number): HTMLDivElement {
96 const startLine = state.doc.lineAt(from).number;
97 const endLine = to === undefined ? startLine : state.doc.lineAt(to).number;
98 const top = (startLine - 1) * lineHeight;
99 const height = Math.max(
100 MIN_ANNOTATION_HEIGHT,
101 Math.max(1, endLine - startLine) * lineHeight,
102 );
103
104 let annotation: HTMLDivElement | undefined;
105 if (i < annotations.length) {
106 annotation = annotations[i];
107 }
108 if (annotation === undefined) {
109 annotation = holder.ownerDocument.createElement('div');
110 annotations.push(annotation);
111 holder.appendChild(annotation);
112 }
113 i += 1;
114
115 annotation.style.top = `${top}px`;
116 annotation.style.height = `${height}px`;
117
118 return annotation;
119 }
120
121 state.selection.ranges.forEach(({ head }) => {
122 const selectionAnnotation = getOrCreateAnnotation(head);
123 selectionAnnotation.className = ANNOTATION_SELECTION_CLASS;
124 selectionAnnotation.style.width = `${SCROLLBAR_WIDTH}px`;
125 });
126
127 const diagnosticsIter = getDiagnostics(state).iter();
128 while (diagnosticsIter.value !== null) {
129 const diagnosticAnnotation = getOrCreateAnnotation(
130 diagnosticsIter.from,
131 diagnosticsIter.to,
132 );
133 diagnosticAnnotation.className = `${ANNOTATION_DIAGNOSTIC_CLASS} ${ANNOTATION_DIAGNOSTIC_CLASS}-${diagnosticsIter.value.severity}`;
134 diagnosticAnnotation.style.width = `${ANNOTATION_WIDTH}px`;
135 diagnosticsIter.next();
136 }
137
138 const occurrences = view.state.field(findOccurrences);
139 const occurrencesIter = occurrences.iter();
140 while (occurrencesIter.value !== null) {
141 const occurrenceAnnotation = getOrCreateAnnotation(
142 occurrencesIter.from,
143 occurrencesIter.to,
144 );
145 occurrenceAnnotation.className = ANNOTATION_OCCURRENCE_CLASS;
146 occurrenceAnnotation.style.width = `${ANNOTATION_WIDTH}px`;
147 occurrenceAnnotation.style.right = `${ANNOTATION_WIDTH}px`;
148 occurrencesIter.next();
149 }
150
151 annotations
152 .splice(i)
153 .forEach((staleAnnotation) => holder.removeChild(staleAnnotation));
154}
155
156export default function scrollbarViewPlugin(
157 editorStore: EditorStore,
158): ViewPlugin<PluginValue> {
159 return ViewPlugin.define((view) => {
160 const { scrollDOM } = view;
161 const { ownerDocument, parentElement: parentDOM } = scrollDOM;
162 if (parentDOM === null) {
163 return {};
164 }
165
166 const holder = ownerDocument.createElement('div');
167 holder.className = HOLDER_CLASS;
168 parentDOM.replaceChild(holder, scrollDOM);
169 holder.appendChild(scrollDOM);
170
171 const spacer = ownerDocument.createElement('div');
172 spacer.className = SPACER_CLASS;
173 scrollDOM.insertBefore(spacer, scrollDOM.firstChild);
174
175 let gutterWidth = 0;
176
177 scrollDOM.addEventListener('click', (event) => {
178 const scrollX = scrollDOM.scrollLeft + event.offsetX;
179 const scrollY = scrollDOM.scrollTop + event.offsetY;
180 if (scrollX > gutterWidth && scrollY > view.contentHeight) {
181 event.preventDefault();
182 view.focus();
183 editorStore.dispatch({
184 scrollIntoView: true,
185 selection: EditorSelection.create([
186 EditorSelection.cursor(view.state.doc.length),
187 ]),
188 });
189 }
190 });
191
192 let factorY = 1;
193 let factorX = 1;
194
195 const { track: trackY, thumb: thumbY } = createScrollbar(
196 holder,
197 'y',
198 (_offsetX, offsetY) => {
199 const scaledOffset = offsetY / factorY;
200 const { height: scrollerHeight } = scrollDOM.getBoundingClientRect();
201 const target = Math.max(0, scaledOffset - scrollerHeight / 2);
202 scrollDOM.scrollTo({ top: target });
203 },
204 (_movementX, movementY) => {
205 scrollDOM.scrollBy({ top: movementY / factorY });
206 },
207 );
208
209 const { track: trackX, thumb: thumbX } = createScrollbar(
210 holder,
211 'x',
212 (offsetX) => {
213 const scaledOffset = offsetX / factorX;
214 const { width: scrollerWidth } = scrollDOM.getBoundingClientRect();
215 const target = Math.max(0, scaledOffset - scrollerWidth / 2);
216 scrollDOM.scrollTo({ left: target });
217 },
218 (movementX) => {
219 scrollDOM.scrollBy({ left: movementX / factorX });
220 },
221 );
222
223 const gutterDecoration = ownerDocument.createElement('div');
224 gutterDecoration.className = GUTTER_DECORATION_CLASS;
225 holder.appendChild(gutterDecoration);
226
227 const topDecoration = ownerDocument.createElement('div');
228 topDecoration.className = TOP_DECORATION_CLASS;
229 holder.appendChild(topDecoration);
230
231 const disposePanelReaction = reaction(
232 () => editorStore.searchPanel.state,
233 (panelOpen) => {
234 topDecoration.style.display = panelOpen ? 'none' : 'block';
235 },
236 { fireImmediately: true },
237 );
238
239 let gutters: Element | undefined;
240
241 let firstRun = true;
242 let firstRunTimeout: number | undefined;
243 let requested = false;
244 let rebuildRequested = false;
245
246 const annotations: HTMLDivElement[] = [];
247
248 let observer: ResizeObserver | undefined;
249
250 function update() {
251 requested = false;
252
253 if (gutters === undefined) {
254 gutters = scrollDOM.querySelector('.cm-gutters') ?? undefined;
255 if (gutters !== undefined && observer !== undefined) {
256 observer.observe(gutters);
257 }
258 }
259
260 const { height: scrollerHeight, width: scrollerWidth } =
261 scrollDOM.getBoundingClientRect();
262 const { scrollTop, scrollLeft, scrollWidth } = scrollDOM;
263 const scrollHeight =
264 view.contentHeight + scrollerHeight - view.defaultLineHeight;
265 if (firstRun) {
266 if (firstRunTimeout !== undefined) {
267 clearTimeout(firstRunTimeout);
268 }
269 firstRunTimeout = setTimeout(() => {
270 spacer.style.minHeight = `${scrollHeight}px`;
271 firstRun = false;
272 }, 0);
273 } else {
274 spacer.style.minHeight = `${scrollHeight}px`;
275 }
276 gutterWidth = gutters?.clientWidth ?? 0;
277 let trackYHeight = scrollerHeight;
278
279 // Prevent spurious horizontal scrollbar by rounding up to the nearest pixel.
280 if (scrollWidth > Math.ceil(scrollerWidth)) {
281 // Leave space for horizontal scrollbar.
282 trackYHeight -= SCROLLBAR_WIDTH;
283 // Alwalys leave space for annotation in the vertical scrollbar.
284 const trackXWidth = scrollerWidth - gutterWidth - SCROLLBAR_WIDTH;
285 const thumbWidth = trackXWidth * (scrollerWidth / scrollWidth);
286 factorX = (trackXWidth - thumbWidth) / (scrollWidth - scrollerWidth);
287 trackY.style.bottom = `${SCROLLBAR_WIDTH}px`;
288 trackX.style.display = 'block';
289 trackX.style.left = `${gutterWidth}px`;
290 thumbX.style.width = `${thumbWidth}px`;
291 thumbX.style.left = `${scrollLeft * factorX}px`;
292 scrollDOM.style.overflowX = 'scroll';
293 } else {
294 trackY.style.bottom = '0px';
295 trackX.style.display = 'none';
296 scrollDOM.style.overflowX = 'hidden';
297 }
298
299 const thumbHeight = trackYHeight * (scrollerHeight / scrollHeight);
300 factorY = (trackYHeight - thumbHeight) / (scrollHeight - scrollerHeight);
301 thumbY.style.display = 'block';
302 thumbY.style.height = `${thumbHeight}px`;
303 thumbY.style.top = `${scrollTop * factorY}px`;
304
305 gutterDecoration.style.left = `${gutterWidth}px`;
306 gutterDecoration.style.width = `${Math.max(
307 0,
308 Math.min(scrollLeft, SHADOW_WIDTH),
309 )}px`;
310
311 topDecoration.style.height = `${Math.max(
312 0,
313 Math.min(scrollTop, SHADOW_WIDTH),
314 )}px`;
315
316 if (rebuildRequested) {
317 rebuildAnnotations(
318 view,
319 scrollHeight,
320 trackYHeight,
321 holder,
322 annotations,
323 );
324 rebuildRequested = false;
325 }
326 }
327
328 function requestUpdate() {
329 if (!requested) {
330 requested = true;
331 view.requestMeasure({ read: update });
332 }
333 }
334
335 function requestRebuild() {
336 requestUpdate();
337 rebuildRequested = true;
338 }
339
340 observer = new ResizeObserver(requestRebuild);
341 observer.observe(holder);
342
343 scrollDOM.addEventListener('scroll', requestUpdate);
344
345 requestRebuild();
346
347 return {
348 update: requestRebuild,
349 destroy() {
350 disposePanelReaction();
351 observer?.disconnect();
352 scrollDOM.removeEventListener('scroll', requestUpdate);
353 parentDOM.replaceChild(holder, holder);
354 },
355 };
356 });
357}
diff --git a/subprojects/frontend/src/editor/semanticHighlighting.ts b/subprojects/frontend/src/editor/semanticHighlighting.ts
index 2c1bd67d..1f2e564c 100644
--- a/subprojects/frontend/src/editor/semanticHighlighting.ts
+++ b/subprojects/frontend/src/editor/semanticHighlighting.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { RangeSet, type TransactionSpec } from '@codemirror/state'; 7import { RangeSet, type TransactionSpec } from '@codemirror/state';
2import { Decoration } from '@codemirror/view'; 8import { Decoration } from '@codemirror/view';
3 9
diff --git a/subprojects/frontend/src/index.tsx b/subprojects/frontend/src/index.tsx
index 29b2b196..cb11e6c3 100644
--- a/subprojects/frontend/src/index.tsx
+++ b/subprojects/frontend/src/index.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { configure } from 'mobx'; 7import { configure } from 'mobx';
2import { type Root, createRoot } from 'react-dom/client'; 8import { type Root, createRoot } from 'react-dom/client';
3 9
diff --git a/subprojects/frontend/src/language/folding.ts b/subprojects/frontend/src/language/folding.ts
index 4dabfa27..b4d4ca22 100644
--- a/subprojects/frontend/src/language/folding.ts
+++ b/subprojects/frontend/src/language/folding.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { EditorState } from '@codemirror/state'; 7import type { EditorState } from '@codemirror/state';
2import type { SyntaxNode } from '@lezer/common'; 8import type { SyntaxNode } from '@lezer/common';
3 9
diff --git a/subprojects/frontend/src/language/indentation.ts b/subprojects/frontend/src/language/indentation.ts
index a0f7032d..8446d7fa 100644
--- a/subprojects/frontend/src/language/indentation.ts
+++ b/subprojects/frontend/src/language/indentation.ts
@@ -1,3 +1,10 @@
1/*
2 * Copyright (C) 2018-2021 by Marijn Haverbeke <marijnh@gmail.com> and others
3 * Copyright (C) 2021-2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: MIT OR EPL-2.0
6 */
7
1import type { TreeIndentContext } from '@codemirror/language'; 8import type { TreeIndentContext } from '@codemirror/language';
2 9
3/** 10/**
diff --git a/subprojects/frontend/src/language/problem.grammar b/subprojects/frontend/src/language/problem.grammar
index 704badab..a7b1fb0a 100644
--- a/subprojects/frontend/src/language/problem.grammar
+++ b/subprojects/frontend/src/language/problem.grammar
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1@detectDelim 7@detectDelim
2 8
3@external prop implicitCompletion from './props' 9@external prop implicitCompletion from './props'
diff --git a/subprojects/frontend/src/language/problemLanguageSupport.ts b/subprojects/frontend/src/language/problemLanguageSupport.ts
index c3ae7ed9..2121e05f 100644
--- a/subprojects/frontend/src/language/problemLanguageSupport.ts
+++ b/subprojects/frontend/src/language/problemLanguageSupport.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 foldInside, 8 foldInside,
3 foldNodeProp, 9 foldNodeProp,
diff --git a/subprojects/frontend/src/language/props.ts b/subprojects/frontend/src/language/props.ts
index 65392e75..aa67145a 100644
--- a/subprojects/frontend/src/language/props.ts
+++ b/subprojects/frontend/src/language/props.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1/* eslint-disable import/prefer-default-export -- Lezer needs non-default exports */ 7/* eslint-disable import/prefer-default-export -- Lezer needs non-default exports */
2 8
3import { NodeProp } from '@lezer/common'; 9import { NodeProp } from '@lezer/common';
diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx
index ff97d524..78146f25 100644
--- a/subprojects/frontend/src/theme/ThemeProvider.tsx
+++ b/subprojects/frontend/src/theme/ThemeProvider.tsx
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 alpha, 8 alpha,
3 createTheme, 9 createTheme,
@@ -69,7 +75,7 @@ function createResponsiveTheme(
69 ...options, 75 ...options,
70 typography: { 76 typography: {
71 fontFamily: 77 fontFamily:
72 '"InterVariable", "Inter", "Roboto", "Helvetica", "Arial", sans-serif', 78 '"Inter Variable", "Inter", "Roboto", "Helvetica", "Arial", sans-serif',
73 fontWeightMedium: 600, 79 fontWeightMedium: 600,
74 fontWeightEditorNormal: 400, 80 fontWeightEditorNormal: 400,
75 fontWeightEditorBold: 700, 81 fontWeightEditorBold: 700,
@@ -79,7 +85,7 @@ function createResponsiveTheme(
79 }, 85 },
80 editor: { 86 editor: {
81 fontFamily: 87 fontFamily:
82 '"JetBrains MonoVariable", "JetBrains Mono", "Cascadia Code", "Fira Code", monospace', 88 '"JetBrains Mono Variable", "JetBrains Mono", "Cascadia Code", "Fira Code", monospace',
83 fontFeatureSettings: '"liga", "calt"', 89 fontFeatureSettings: '"liga", "calt"',
84 // `rem` for JetBrains MonoVariable make the text too large in Safari. 90 // `rem` for JetBrains MonoVariable make the text too large in Safari.
85 fontSize: '16px', 91 fontSize: '16px',
diff --git a/subprojects/frontend/src/theme/ThemeStore.ts b/subprojects/frontend/src/theme/ThemeStore.ts
index e09d8d99..7c657449 100644
--- a/subprojects/frontend/src/theme/ThemeStore.ts
+++ b/subprojects/frontend/src/theme/ThemeStore.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { makeAutoObservable } from 'mobx'; 7import { makeAutoObservable } from 'mobx';
2 8
3export enum ThemePreference { 9export enum ThemePreference {
diff --git a/subprojects/frontend/src/utils/CancelledError.ts b/subprojects/frontend/src/utils/CancelledError.ts
index ee23676f..96b67af7 100644
--- a/subprojects/frontend/src/utils/CancelledError.ts
+++ b/subprojects/frontend/src/utils/CancelledError.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1export default class CancelledError extends Error { 7export default class CancelledError extends Error {
2 constructor(message = 'Operation cancelled') { 8 constructor(message = 'Operation cancelled') {
3 super(message); 9 super(message);
diff --git a/subprojects/frontend/src/utils/PendingTask.ts b/subprojects/frontend/src/utils/PendingTask.ts
index d0b24c1f..80d1a346 100644
--- a/subprojects/frontend/src/utils/PendingTask.ts
+++ b/subprojects/frontend/src/utils/PendingTask.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import TimeoutError from './TimeoutError'; 7import TimeoutError from './TimeoutError';
2import getLogger from './getLogger'; 8import getLogger from './getLogger';
3 9
diff --git a/subprojects/frontend/src/utils/PriorityMutex.ts b/subprojects/frontend/src/utils/PriorityMutex.ts
index 78736141..c1215c76 100644
--- a/subprojects/frontend/src/utils/PriorityMutex.ts
+++ b/subprojects/frontend/src/utils/PriorityMutex.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import CancelledError from './CancelledError'; 7import CancelledError from './CancelledError';
2import PendingTask from './PendingTask'; 8import PendingTask from './PendingTask';
3import getLogger from './getLogger'; 9import getLogger from './getLogger';
diff --git a/subprojects/frontend/src/utils/TimeoutError.ts b/subprojects/frontend/src/utils/TimeoutError.ts
index eb800f40..21365502 100644
--- a/subprojects/frontend/src/utils/TimeoutError.ts
+++ b/subprojects/frontend/src/utils/TimeoutError.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1export default class TimeoutError extends Error { 7export default class TimeoutError extends Error {
2 constructor() { 8 constructor() {
3 super('Operation timed out'); 9 super('Operation timed out');
diff --git a/subprojects/frontend/src/utils/getLogger.ts b/subprojects/frontend/src/utils/getLogger.ts
index 301fd76d..09b0b17f 100644
--- a/subprojects/frontend/src/utils/getLogger.ts
+++ b/subprojects/frontend/src/utils/getLogger.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import styles, { type CSPair } from 'ansi-styles'; 7import styles, { type CSPair } from 'ansi-styles';
2import log from 'loglevel'; 8import log from 'loglevel';
3import prefix from 'loglevel-plugin-prefix'; 9import prefix from 'loglevel-plugin-prefix';
diff --git a/subprojects/frontend/src/utils/useDelayedSnackbar.ts b/subprojects/frontend/src/utils/useDelayedSnackbar.ts
index 03ad6caa..3d6df3e3 100644
--- a/subprojects/frontend/src/utils/useDelayedSnackbar.ts
+++ b/subprojects/frontend/src/utils/useDelayedSnackbar.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 useSnackbar, 8 useSnackbar,
3 type SnackbarKey, 9 type SnackbarKey,
diff --git a/subprojects/frontend/src/xtext/BackendConfig.ts b/subprojects/frontend/src/xtext/BackendConfig.ts
index 41737c0b..4c7eac5f 100644
--- a/subprojects/frontend/src/xtext/BackendConfig.ts
+++ b/subprojects/frontend/src/xtext/BackendConfig.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ 7/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */
2 8
3import { z } from 'zod'; 9import { z } from 'zod';
diff --git a/subprojects/frontend/src/xtext/ContentAssistService.ts b/subprojects/frontend/src/xtext/ContentAssistService.ts
index 78f61c06..fd30c4f9 100644
--- a/subprojects/frontend/src/xtext/ContentAssistService.ts
+++ b/subprojects/frontend/src/xtext/ContentAssistService.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { 7import type {
2 Completion, 8 Completion,
3 CompletionContext, 9 CompletionContext,
diff --git a/subprojects/frontend/src/xtext/HighlightingService.ts b/subprojects/frontend/src/xtext/HighlightingService.ts
index a126ee40..447f1401 100644
--- a/subprojects/frontend/src/xtext/HighlightingService.ts
+++ b/subprojects/frontend/src/xtext/HighlightingService.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type EditorStore from '../editor/EditorStore'; 7import type EditorStore from '../editor/EditorStore';
2import type { IHighlightRange } from '../editor/semanticHighlighting'; 8import type { IHighlightRange } from '../editor/semanticHighlighting';
3 9
diff --git a/subprojects/frontend/src/xtext/OccurrencesService.ts b/subprojects/frontend/src/xtext/OccurrencesService.ts
index fc72ead2..c9c6c699 100644
--- a/subprojects/frontend/src/xtext/OccurrencesService.ts
+++ b/subprojects/frontend/src/xtext/OccurrencesService.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { Transaction } from '@codemirror/state'; 7import type { Transaction } from '@codemirror/state';
2import { debounce } from 'lodash-es'; 8import { debounce } from 'lodash-es';
3import ms from 'ms'; 9import ms from 'ms';
diff --git a/subprojects/frontend/src/xtext/UpdateService.ts b/subprojects/frontend/src/xtext/UpdateService.ts
index 63e28652..ee5ebde2 100644
--- a/subprojects/frontend/src/xtext/UpdateService.ts
+++ b/subprojects/frontend/src/xtext/UpdateService.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { ChangeDesc, Transaction } from '@codemirror/state'; 7import type { ChangeDesc, Transaction } from '@codemirror/state';
2import { debounce } from 'lodash-es'; 8import { debounce } from 'lodash-es';
3import { nanoid } from 'nanoid'; 9import { nanoid } from 'nanoid';
diff --git a/subprojects/frontend/src/xtext/UpdateStateTracker.ts b/subprojects/frontend/src/xtext/UpdateStateTracker.ts
index 5d4ce49e..4ce93ed6 100644
--- a/subprojects/frontend/src/xtext/UpdateStateTracker.ts
+++ b/subprojects/frontend/src/xtext/UpdateStateTracker.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { 7import {
2 type ChangeDesc, 8 type ChangeDesc,
3 ChangeSet, 9 ChangeSet,
diff --git a/subprojects/frontend/src/xtext/ValidationService.ts b/subprojects/frontend/src/xtext/ValidationService.ts
index 72414590..64fb63eb 100644
--- a/subprojects/frontend/src/xtext/ValidationService.ts
+++ b/subprojects/frontend/src/xtext/ValidationService.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { Diagnostic } from '@codemirror/lint'; 7import type { Diagnostic } from '@codemirror/lint';
2 8
3import type EditorStore from '../editor/EditorStore'; 9import type EditorStore from '../editor/EditorStore';
diff --git a/subprojects/frontend/src/xtext/XtextClient.ts b/subprojects/frontend/src/xtext/XtextClient.ts
index 14fb2430..e8181af0 100644
--- a/subprojects/frontend/src/xtext/XtextClient.ts
+++ b/subprojects/frontend/src/xtext/XtextClient.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import type { 7import type {
2 CompletionContext, 8 CompletionContext,
3 CompletionResult, 9 CompletionResult,
diff --git a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
index 6b734546..6bb7eec8 100644
--- a/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
+++ b/subprojects/frontend/src/xtext/XtextWebSocketClient.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import { createAtom, makeAutoObservable, observable } from 'mobx'; 7import { createAtom, makeAutoObservable, observable } from 'mobx';
2import ms from 'ms'; 8import ms from 'ms';
3import { nanoid } from 'nanoid'; 9import { nanoid } from 'nanoid';
diff --git a/subprojects/frontend/src/xtext/fetchBackendConfig.ts b/subprojects/frontend/src/xtext/fetchBackendConfig.ts
index 15e976d8..71ff2e63 100644
--- a/subprojects/frontend/src/xtext/fetchBackendConfig.ts
+++ b/subprojects/frontend/src/xtext/fetchBackendConfig.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import BackendConfig, { ENDPOINT } from './BackendConfig'; 7import BackendConfig, { ENDPOINT } from './BackendConfig';
2 8
3export default async function fetchBackendConfig(): Promise<BackendConfig> { 9export default async function fetchBackendConfig(): Promise<BackendConfig> {
diff --git a/subprojects/frontend/src/xtext/webSocketMachine.ts b/subprojects/frontend/src/xtext/webSocketMachine.ts
index fc53fef3..2fb1f52f 100644
--- a/subprojects/frontend/src/xtext/webSocketMachine.ts
+++ b/subprojects/frontend/src/xtext/webSocketMachine.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import ms from 'ms'; 7import ms from 'ms';
2import { actions, assign, createMachine } from 'xstate'; 8import { actions, assign, createMachine } from 'xstate';
3 9
diff --git a/subprojects/frontend/src/xtext/xtextMessages.ts b/subprojects/frontend/src/xtext/xtextMessages.ts
index ec7a2a31..bbbff064 100644
--- a/subprojects/frontend/src/xtext/xtextMessages.ts
+++ b/subprojects/frontend/src/xtext/xtextMessages.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ 7/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */
2 8
3import { z } from 'zod'; 9import { z } from 'zod';
diff --git a/subprojects/frontend/src/xtext/xtextServiceResults.ts b/subprojects/frontend/src/xtext/xtextServiceResults.ts
index e93c6714..d3b467ad 100644
--- a/subprojects/frontend/src/xtext/xtextServiceResults.ts
+++ b/subprojects/frontend/src/xtext/xtextServiceResults.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */ 7/* eslint-disable @typescript-eslint/no-redeclare -- Declare types with their companion objects */
2 8
3import { z } from 'zod'; 9import { z } from 'zod';
diff --git a/subprojects/frontend/tsconfig.base.json b/subprojects/frontend/tsconfig.base.json
index b960e93c..5ef50b5e 100644
--- a/subprojects/frontend/tsconfig.base.json
+++ b/subprojects/frontend/tsconfig.base.json
@@ -1,10 +1,41 @@
1/*
2 * Copyright (c) Microsoft Corporation.
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: MIT OR EPL-2.0
6 *
7 * This file is based on
8 * https://github.com/tsconfig/bases/blob/7db25a41bc5a9c0f66d91f6f3aa28438afcb2f18/bases/strictest.json
9 * but we moved it inside the project for better tooling support.
10 */
1{ 11{
2 "extends": "@tsconfig/strictest",
3 "compilerOptions": { 12 "compilerOptions": {
4 "useDefineForClassFields": true, 13 "strict": true,
5 "verbatimModuleSyntax": false, 14 "allowUnusedLabels": false,
15 "allowUnreachableCode": false,
16 "exactOptionalPropertyTypes": true,
17 "noFallthroughCasesInSwitch": true,
18 "noImplicitOverride": true,
19 "noImplicitReturns": true,
20 "noPropertyAccessFromIndexSignature": true,
21 "noUncheckedIndexedAccess": true,
22 "noUnusedLocals": true,
23 "noUnusedParameters": true,
24 // "verbatimModuleSyntax" is incompatible with `import` syntax in modules
25 // with CommonJS import resolution, so we use "isolatedModules" only.
26 // "verbatimModuleSyntax": false,
6 "isolatedModules": true, 27 "isolatedModules": true,
28 "checkJs": true,
29 "esModuleInterop": true,
30 "skipLibCheck": true,
31 "forceConsistentCasingInFileNames": true,
32 "useDefineForClassFields": true,
33 // Project-specific configuration below.
7 "module": "es2022", 34 "module": "es2022",
8 "moduleResolution": "node" 35 "moduleResolution": "node",
36 "incremental": true,
37 "declaration": true,
38 "emitDeclarationOnly": true,
39 "outDir": "build/typescript"
9 } 40 }
10} 41}
diff --git a/subprojects/frontend/tsconfig.json b/subprojects/frontend/tsconfig.json
index 35abd789..06f6d8fe 100644
--- a/subprojects/frontend/tsconfig.json
+++ b/subprojects/frontend/tsconfig.json
@@ -1,8 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1{ 6{
2 "extends": "./tsconfig.base.json", 7 "extends": "./tsconfig.base.json",
3 "compilerOptions": { 8 "compilerOptions": {
4 "jsx": "react-jsx", 9 "jsx": "react-jsx",
5 "noEmit": true,
6 "lib": ["DOM", "DOM.Iterable", "ES2022"], 10 "lib": ["DOM", "DOM.Iterable", "ES2022"],
7 "types": ["vite/client", "vite-plugin-pwa/client"] 11 "types": ["vite/client", "vite-plugin-pwa/client"]
8 }, 12 },
diff --git a/subprojects/frontend/tsconfig.node.json b/subprojects/frontend/tsconfig.node.json
index f4908bcb..47feaf97 100644
--- a/subprojects/frontend/tsconfig.node.json
+++ b/subprojects/frontend/tsconfig.node.json
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1{ 6{
2 "extends": "./tsconfig.base.json", 7 "extends": "./tsconfig.base.json",
3 "compilerOptions": { 8 "compilerOptions": {
@@ -10,6 +15,7 @@
10 "include": [ 15 "include": [
11 ".eslintrc.cjs", 16 ".eslintrc.cjs",
12 "config/*.ts", 17 "config/*.ts",
18 "config/*.cjs",
13 "prettier.config.cjs", 19 "prettier.config.cjs",
14 "types/node", 20 "types/node",
15 "vite.config.ts" 21 "vite.config.ts"
diff --git a/subprojects/frontend/tsconfig.shared.json b/subprojects/frontend/tsconfig.shared.json
index b7e1de55..154fe122 100644
--- a/subprojects/frontend/tsconfig.shared.json
+++ b/subprojects/frontend/tsconfig.shared.json
@@ -1,13 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1{ 6{
2 "extends": "./tsconfig.base.json", 7 "extends": "./tsconfig.base.json",
3 "compilerOptions": { 8 "compilerOptions": {
4 "composite": true, 9 "composite": true,
5 "lib": ["ES2022"], 10 "lib": ["ES2022"],
6 "types": [], 11 "types": [],
7 "emitDeclarationOnly": true,
8 "outDir": "build/typescript"
9 }, 12 },
10 "include": [ 13 "include": [
11 "src/xtext/BackendConfig.ts", 14 "src/xtext/BackendConfig.ts"
12 ] 15 ]
13} 16}
diff --git a/subprojects/frontend/types/ImportMeta.d.ts b/subprojects/frontend/types/ImportMeta.d.ts
index c32b48f5..f5a32ef1 100644
--- a/subprojects/frontend/types/ImportMeta.d.ts
+++ b/subprojects/frontend/types/ImportMeta.d.ts
@@ -1,3 +1,10 @@
1/*
2 * Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors
3 * Copyright (c) 2021-2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: MIT OR EPL-2.0
6 */
7
1interface ImportMeta { 8interface ImportMeta {
2 env: { 9 env: {
3 BASE_URL: string; 10 BASE_URL: string;
diff --git a/subprojects/frontend/types/grammar.d.ts b/subprojects/frontend/types/grammar.d.ts
index 1480085b..e7a7eebf 100644
--- a/subprojects/frontend/types/grammar.d.ts
+++ b/subprojects/frontend/types/grammar.d.ts
@@ -1,3 +1,10 @@
1/*
2 * Copyright (C) 2018 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
3 * Copyright (C) 2021-2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: MIT OR EPL-2.0
6 */
7
1declare module '*.grammar' { 8declare module '*.grammar' {
2 import type { LRParser } from '@lezer/lr'; 9 import type { LRParser } from '@lezer/lr';
3 10
diff --git a/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts b/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts
index 9c1ff03e..4ef9f4e3 100644
--- a/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts
+++ b/subprojects/frontend/types/node/@lezer-generator-rollup.d.ts
@@ -1,3 +1,10 @@
1/*
2 * Copyright (C) 2018 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
3 * Copyright (C) 2021-2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: MIT OR EPL-2.0
6 */
7
1// We have to explicitly redeclare the type of the `./rollup` ESM export of `@lezer/generator`, 8// We have to explicitly redeclare the type of the `./rollup` ESM export of `@lezer/generator`,
2// because TypeScript can't find it on its own even with `"moduleResolution": "Node16"`. 9// because TypeScript can't find it on its own even with `"moduleResolution": "Node16"`.
3declare module '@lezer/generator/rollup' { 10declare module '@lezer/generator/rollup' {
diff --git a/subprojects/frontend/types/windowControlsOverlay.d.ts b/subprojects/frontend/types/windowControlsOverlay.d.ts
index d8f3182f..2513d620 100644
--- a/subprojects/frontend/types/windowControlsOverlay.d.ts
+++ b/subprojects/frontend/types/windowControlsOverlay.d.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1interface WindowControlsOverlayGeometryChangeEvent extends Event { 7interface WindowControlsOverlayGeometryChangeEvent extends Event {
2 titlebarAreaRect: DOMRect; 8 titlebarAreaRect: DOMRect;
3 9
diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts
index cd9993cc..9e08ccc4 100644
--- a/subprojects/frontend/vite.config.ts
+++ b/subprojects/frontend/vite.config.ts
@@ -1,3 +1,9 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
1import path from 'node:path'; 7import path from 'node:path';
2import { fileURLToPath } from 'node:url'; 8import { fileURLToPath } from 'node:url';
3 9
diff --git a/subprojects/language-ide/build.gradle b/subprojects/language-ide/build.gradle
deleted file mode 100644
index 3786762b..00000000
--- a/subprojects/language-ide/build.gradle
+++ /dev/null
@@ -1,18 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3 id 'refinery-xtext-conventions'
4}
5
6dependencies {
7 api project(':refinery-language')
8 api libs.xtext.ide
9 api libs.xtext.xbase.ide
10}
11
12def generateXtextLanguage = project(':refinery-language').tasks.named('generateXtextLanguage')
13
14for (taskName in ['compileJava', 'processResources']) {
15 tasks.named(taskName) {
16 dependsOn generateXtextLanguage
17 }
18}
diff --git a/subprojects/language-ide/build.gradle.kts b/subprojects/language-ide/build.gradle.kts
new file mode 100644
index 00000000..1259cd67
--- /dev/null
+++ b/subprojects/language-ide/build.gradle.kts
@@ -0,0 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9 id("tools.refinery.gradle.xtext-generated")
10}
11
12dependencies {
13 api(project(":refinery-language"))
14 api(libs.xtext.ide)
15 api(libs.xtext.xbase.ide)
16 xtextGenerated(project(":refinery-language", "generatedIdeSources"))
17}
18
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java
index fb620065..122fe874 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeModule.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.ide; 10package tools.refinery.language.ide;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java
index 5b88d41f..9d77e022 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/ProblemIdeSetup.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.ide; 10package tools.refinery.language.ide;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java
index fe722ca1..4511223b 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/FuzzyMatcher.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.ide.contentassist; 6package tools.refinery.language.ide.contentassist;
2 7
3import org.eclipse.xtext.ide.editor.contentassist.IPrefixMatcher; 8import org.eclipse.xtext.ide.editor.contentassist.IPrefixMatcher;
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 8f04ed00..e194ee31 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
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.ide.contentassist; 6package tools.refinery.language.ide.contentassist;
2 7
3import java.util.Objects; 8import java.util.Objects;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java
index 3ece6f67..146bd8da 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingPartialProblemContentAssistParser.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.ide.contentassist; 6package tools.refinery.language.ide.contentassist;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java
index 80dfee5c..f906d881 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/TokenSourceInjectingProblemParser.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.ide.contentassist; 6package tools.refinery.language.ide.contentassist;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java
index c6c7f41f..fdc17c4f 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/contentassist/antlr/ProblemTokenSource.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.29.0.M2 8 * generated by Xtext 2.29.0.M2
3 */ 9 */
4package tools.refinery.language.ide.contentassist.antlr; 10package tools.refinery.language.ide.contentassist.antlr;
diff --git a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java
index 7703e4e3..e8f97d51 100644
--- a/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java
+++ b/subprojects/language-ide/src/main/java/tools/refinery/language/ide/syntaxcoloring/ProblemSemanticHighlightingCalculator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.ide.syntaxcoloring; 6package tools.refinery.language.ide.syntaxcoloring;
2 7
3import com.google.common.collect.ImmutableList; 8import com.google.common.collect.ImmutableList;
diff --git a/subprojects/language-model/META-INF/MANIFEST.MF.license b/subprojects/language-model/META-INF/MANIFEST.MF.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/language-model/META-INF/MANIFEST.MF.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/language-model/build.gradle b/subprojects/language-model/build.gradle
deleted file mode 100644
index 275db188..00000000
--- a/subprojects/language-model/build.gradle
+++ /dev/null
@@ -1,55 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3 id 'refinery-mwe2'
4 id 'refinery-sonarqube'
5}
6
7dependencies {
8 api libs.ecore
9 api libs.ecore.xmi
10 mwe2 libs.ecore.codegen
11 mwe2 libs.mwe.utils
12 mwe2 libs.mwe2.lib
13 mwe2 libs.xtext.core
14 mwe2 libs.xtext.xbase
15}
16
17sourceSets {
18 main {
19 java.srcDirs += ['src/main/emf-gen']
20 }
21}
22
23def generateEPackage = tasks.register('generateEPackage', JavaExec) {
24 mainClass = 'org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher'
25 classpath = configurations.mwe2
26 inputs.file 'src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2'
27 inputs.file 'src/main/resources/model/problem.ecore'
28 inputs.file 'src/main/resources/model/problem.genmodel'
29 outputs.dir 'src/main/emf-gen'
30 args += 'src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2'
31 args += '-p'
32 args += "rootPath=/${projectDir}"
33}
34
35for (taskName in ['compileJava', 'processResources', 'generateEclipseSourceFolders']) {
36 tasks.named(taskName) {
37 dependsOn generateEPackage
38 }
39}
40
41tasks.named('clean') {
42 delete 'src/main/emf-gen'
43}
44
45sonarqube.properties {
46 properties['sonar.exclusions'] += [
47 'src/main/emf-gen/**',
48 ]
49}
50
51eclipse.project.natures += [
52 'org.eclipse.sirius.nature.modelingproject',
53 'org.eclipse.pde.PluginNature',
54 'org.eclipse.xtext.ui.shared.xtextNature'
55]
diff --git a/subprojects/language-model/build.gradle.kts b/subprojects/language-model/build.gradle.kts
new file mode 100644
index 00000000..59ff9046
--- /dev/null
+++ b/subprojects/language-model/build.gradle.kts
@@ -0,0 +1,65 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import tools.refinery.gradle.utils.SonarPropertiesUtils
8
9plugins {
10 id("tools.refinery.gradle.java-library")
11 id("tools.refinery.gradle.mwe2")
12 id("tools.refinery.gradle.sonarqube")
13}
14
15dependencies {
16 api(libs.ecore)
17 api(libs.ecore.xmi)
18 mwe2(libs.ecore.codegen)
19 mwe2(libs.mwe.utils)
20 mwe2(libs.mwe2.lib)
21 mwe2(libs.xtext.core)
22 mwe2(libs.xtext.xbase)
23}
24
25sourceSets {
26 main {
27 java.srcDir("src/main/emf-gen")
28 }
29}
30
31tasks {
32 val generateEPackage by registering(JavaExec::class) {
33 mainClass.set("org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher")
34 classpath(configurations.mwe2)
35 inputs.file("src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2")
36 inputs.file("src/main/resources/model/problem.ecore")
37 inputs.file("src/main/resources/model/problem.genmodel")
38 outputs.file("build.properties")
39 outputs.file("META-INF/MANIFEST.MF")
40 outputs.file("plugin.xml")
41 outputs.file("plugin.properties")
42 outputs.dir("src/main/emf-gen")
43 args("src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2", "-p", "rootPath=/$projectDir")
44 }
45
46 for (taskName in listOf("compileJava", "processResources", "generateEclipseSourceFolders")) {
47 named(taskName) {
48 dependsOn(generateEPackage)
49 }
50 }
51
52 clean {
53 delete("src/main/emf-gen")
54 }
55}
56
57sonarqube.properties {
58 SonarPropertiesUtils.addToList(properties, "sonar.exclusions", "src/main/emf-gen/**")
59}
60
61eclipse.project.natures.plusAssign(listOf(
62 "org.eclipse.sirius.nature.modelingproject",
63 "org.eclipse.pde.PluginNature",
64 "org.eclipse.xtext.ui.shared.xtextNature",
65))
diff --git a/subprojects/language-model/build.properties b/subprojects/language-model/build.properties
index 65dfc7c4..9b9859ff 100644
--- a/subprojects/language-model/build.properties
+++ b/subprojects/language-model/build.properties
@@ -1,4 +1,6 @@
1# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
1# 2#
3# SPDX-License-Identifier: EPL-2.0
2 4
3bin.includes = .,\ 5bin.includes = .,\
4 src/main/resources/model/,\ 6 src/main/resources/model/,\
diff --git a/subprojects/language-model/plugin.properties b/subprojects/language-model/plugin.properties
index c4fb7e23..c410feb7 100644
--- a/subprojects/language-model/plugin.properties
+++ b/subprojects/language-model/plugin.properties
@@ -1,4 +1,6 @@
1# SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
1# 2#
3# SPDX-License-Identifier: EPL-2.0
2 4
3pluginName = tools.refinery.language.model 5pluginName = tools.refinery.language.model
4providerName = refinery.tools 6providerName = refinery.tools
diff --git a/subprojects/language-model/plugin.xml b/subprojects/language-model/plugin.xml
index 4ca005a8..ef1e21f4 100644
--- a/subprojects/language-model/plugin.xml
+++ b/subprojects/language-model/plugin.xml
@@ -2,6 +2,9 @@
2<?eclipse version="3.0"?> 2<?eclipse version="3.0"?>
3 3
4<!-- 4<!--
5 SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
6
7 SPDX-License-Identifier: EPL-2.0
5--> 8-->
6 9
7<plugin> 10<plugin>
diff --git a/subprojects/language-model/problem.aird.license b/subprojects/language-model/problem.aird.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/language-model/problem.aird.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2 b/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
index 15198d69..074b6b71 100644
--- a/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
+++ b/subprojects/language-model/src/main/java/tools/refinery/language/model/GenerateProblemModel.mwe2
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1module tools.refinery.language.model.GenerateProblemModel 6module tools.refinery.language.model.GenerateProblemModel
2 7
3Workflow { 8Workflow {
diff --git a/subprojects/language-model/src/main/resources/model/problem.ecore.license b/subprojects/language-model/src/main/resources/model/problem.ecore.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/language-model/src/main/resources/model/problem.ecore.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/language-model/src/main/resources/model/problem.genmodel.license b/subprojects/language-model/src/main/resources/model/problem.genmodel.license
new file mode 100644
index 00000000..e5db6ccd
--- /dev/null
+++ b/subprojects/language-model/src/main/resources/model/problem.genmodel.license
@@ -0,0 +1,3 @@
1SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2
3SPDX-License-Identifier: EPL-2.0
diff --git a/subprojects/language-semantics/build.gradle b/subprojects/language-semantics/build.gradle
deleted file mode 100644
index 4f43ad24..00000000
--- a/subprojects/language-semantics/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3}
4
5dependencies {
6 implementation libs.eclipseCollections
7 implementation libs.eclipseCollections.api
8 api project(':refinery-language')
9 api project(':refinery-store')
10 testImplementation testFixtures(project(':refinery-language'))
11}
diff --git a/subprojects/language-semantics/build.gradle.kts b/subprojects/language-semantics/build.gradle.kts
new file mode 100644
index 00000000..38cd9e0d
--- /dev/null
+++ b/subprojects/language-semantics/build.gradle.kts
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 implementation(libs.eclipseCollections)
13 implementation(libs.eclipseCollections.api)
14 api(project(":refinery-language"))
15 api(project(":refinery-store"))
16 testImplementation(testFixtures(project(":refinery-language")))
17}
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
index a6712a89..06b8ad77 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/ModelInitializer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model; 6package tools.refinery.language.semantics.model;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
@@ -39,8 +44,8 @@ public class ModelInitializer {
39 var isEqualsRelation = relation == builtinSymbols.equals(); 44 var isEqualsRelation = relation == builtinSymbols.equals();
40 var decisionTree = mergeAssertions(relationInfo, isEqualsRelation); 45 var decisionTree = mergeAssertions(relationInfo, isEqualsRelation);
41 var defaultValue = isEqualsRelation ? TruthValue.FALSE : TruthValue.UNKNOWN; 46 var defaultValue = isEqualsRelation ? TruthValue.FALSE : TruthValue.UNKNOWN;
42 relationTrace.put(relation, new Symbol<>(relationInfo.name(), relationInfo.arity(), TruthValue.class, defaultValue 47 relationTrace.put(relation, Symbol.of(
43 )); 48 relationInfo.name(), relationInfo.arity(), TruthValue.class, defaultValue));
44 } 49 }
45 } 50 }
46 51
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
index 55edee6d..c1afecf9 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTree.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import org.eclipse.collections.api.factory.primitive.IntObjectMaps; 8import org.eclipse.collections.api.factory.primitive.IntObjectMaps;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
index fdf8e452..9a1e15a3 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeCursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
index b81ea3fe..3c54e3c5 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeNode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import org.eclipse.collections.api.LazyIntIterable; 8import org.eclipse.collections.api.LazyIntIterable;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
index 495a53dd..915ae2bf 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/DecisionTreeValue.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import tools.refinery.store.representation.TruthValue; 8import tools.refinery.store.representation.TruthValue;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
index c4200509..e6f01d48 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/IntermediateNode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import org.eclipse.collections.api.LazyIntIterable; 8import org.eclipse.collections.api.LazyIntIterable;
diff --git a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
index 4af836ff..ce49aa62 100644
--- a/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
+++ b/subprojects/language-semantics/src/main/java/tools/refinery/language/semantics/model/internal/TerminalNode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.internal; 6package tools.refinery.language.semantics.model.internal;
2 7
3import org.eclipse.collections.api.LazyIntIterable; 8import org.eclipse.collections.api.LazyIntIterable;
diff --git a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
index 4630bf53..b3fcbabb 100644
--- a/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
+++ b/subprojects/language-semantics/src/test/java/tools/refinery/language/semantics/model/tests/DecisionTreeTests.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.semantics.model.tests; 6package tools.refinery.language.semantics.model.tests;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/language-web/build.gradle b/subprojects/language-web/build.gradle
deleted file mode 100644
index 8d277a5b..00000000
--- a/subprojects/language-web/build.gradle
+++ /dev/null
@@ -1,87 +0,0 @@
1plugins {
2 id 'refinery-java-application'
3 id 'refinery-xtext-conventions'
4}
5
6configurations {
7 webapp {
8 canBeConsumed = false
9 canBeResolved = true
10 }
11
12 all {
13 // Use log4j-over-slf4j instead of log4j 1.x
14 exclude group: 'log4j', module: 'log4j'
15 }
16}
17
18dependencies {
19 implementation project(':refinery-language')
20 implementation project(':refinery-language-ide')
21 implementation libs.jetty.server
22 implementation libs.jetty.servlet
23 implementation libs.jetty.websocket.server
24 implementation libs.slf4j.api
25 implementation libs.slf4j.simple
26 implementation libs.slf4j.log4j
27 implementation libs.xtext.web
28 webapp project(path: ':refinery-frontend', configuration: 'productionAssets')
29 testImplementation testFixtures(project(':refinery-language'))
30 testImplementation libs.jetty.websocket.client
31}
32
33def generateXtextLanguage = project(':refinery-language').tasks.named('generateXtextLanguage')
34
35for (taskName in ['compileJava', 'processResources']) {
36 tasks.named(taskName) {
37 dependsOn generateXtextLanguage
38 }
39}
40
41mainClassName = 'tools.refinery.language.web.ServerLauncher'
42
43// Enable JDK 19 preview features for virtual thread support.
44application {
45 applicationDefaultJvmArgs += '--enable-preview'
46}
47tasks.withType(JavaCompile) {
48 options.release = 19
49 options.compilerArgs += '--enable-preview'
50}
51tasks.withType(Test) {
52 jvmArgs += '--enable-preview'
53}
54
55tasks.named('jar') {
56 dependsOn project.configurations.webapp
57 from(project.configurations.webapp) {
58 into 'webapp'
59 }
60}
61
62tasks.named('shadowJar') {
63 dependsOn project.configurations.webapp
64 from(project.sourceSets.main.output)
65 configurations = [project.configurations.runtimeClasspath]
66 exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA','schema/*',
67 '.options', '.api_description', '*.profile', 'about.*', 'about_*.html', 'about_files/*',
68 'plugin.xml', 'systembundle.properties', 'profile.list', 'META-INF/resources/xtext/**')
69 append('plugin.properties')
70 from(project.configurations.webapp) {
71 into 'webapp'
72 }
73}
74
75tasks.register('serveBackend', JavaExec) {
76 dependsOn project.configurations.webapp
77 dependsOn sourceSets.main.runtimeClasspath
78 classpath = sourceSets.main.runtimeClasspath
79 mainClass = mainClassName
80 // Enable JDK 19 preview features for virtual thread support.
81 jvmArgs += '--enable-preview'
82 standardInput = System.in
83 def baseResource = project.configurations.webapp.incoming.artifacts.artifactFiles.first()
84 environment BASE_RESOURCE: baseResource
85 group = 'run'
86 description = 'Start a Jetty web server serving the Xtex API and assets.'
87}
diff --git a/subprojects/language-web/build.gradle.kts b/subprojects/language-web/build.gradle.kts
new file mode 100644
index 00000000..562a1bd9
--- /dev/null
+++ b/subprojects/language-web/build.gradle.kts
@@ -0,0 +1,68 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-application")
9 id("tools.refinery.gradle.xtext-generated")
10}
11
12val webapp: Configuration by configurations.creating {
13 isCanBeConsumed = false
14 isCanBeResolved = true
15}
16
17dependencies {
18 implementation(project(":refinery-language"))
19 implementation(project(":refinery-language-ide"))
20 implementation(libs.jetty.server)
21 implementation(libs.jetty.servlet)
22 implementation(libs.jetty.websocket.api)
23 implementation(libs.jetty.websocket.server)
24 implementation(libs.slf4j.api)
25 implementation(libs.xtext.web)
26 xtextGenerated(project(":refinery-language", "generatedWebSources"))
27 webapp(project(":refinery-frontend", "productionAssets"))
28 testImplementation(testFixtures(project(":refinery-language")))
29 testImplementation(libs.jetty.websocket.client)
30}
31
32application {
33 mainClass.set("tools.refinery.language.web.ServerLauncher")
34}
35
36tasks {
37 jar {
38 dependsOn(webapp)
39 from(webapp) {
40 into("webapp")
41 }
42 }
43
44 shadowJar {
45 dependsOn(webapp)
46 from(project.sourceSets.main.map { it.output })
47 exclude("META-INF/INDEX.LIST", "META-INF/*.SF", "META-INF/*.DSA", "META-INF/*.RSA", "schema/*",
48 ".options", ".api_description", "*.profile", "about.*", "about_*.html", "about_files/*",
49 "plugin.xml", "systembundle.properties", "profile.list", "META-INF/resources/xtext/**")
50 append("plugin.properties")
51 from(webapp) {
52 into("webapp")
53 }
54 }
55
56 register<JavaExec>("serveBackend") {
57 dependsOn(webapp)
58 val mainRuntimeClasspath = sourceSets.main.map { it.runtimeClasspath }
59 dependsOn(mainRuntimeClasspath)
60 classpath(mainRuntimeClasspath)
61 mainClass.set(application.mainClass)
62 standardInput = System.`in`
63 val baseResource = webapp.incoming.artifacts.artifactFiles.first()
64 environment("BASE_RESOURCE", baseResource)
65 group = "run"
66 description = "Start a Jetty web server serving the Xtex API and assets."
67 }
68}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
index fd2af1b2..53f78c3c 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/CacheControlFilter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web; 6package tools.refinery.language.web;
2 7
3import jakarta.servlet.*; 8import jakarta.servlet.*;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java
index 706413a9..b0197c01 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebModule.java
@@ -1,15 +1,19 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.web; 10package tools.refinery.language.web;
5 11
6import org.eclipse.xtext.ide.ExecutorServiceProvider;
7import org.eclipse.xtext.web.server.XtextServiceDispatcher; 12import org.eclipse.xtext.web.server.XtextServiceDispatcher;
8import org.eclipse.xtext.web.server.model.IWebDocumentProvider; 13import org.eclipse.xtext.web.server.model.IWebDocumentProvider;
9import org.eclipse.xtext.web.server.model.XtextWebDocumentAccess; 14import org.eclipse.xtext.web.server.model.XtextWebDocumentAccess;
10import org.eclipse.xtext.web.server.occurrences.OccurrencesService; 15import org.eclipse.xtext.web.server.occurrences.OccurrencesService;
11import tools.refinery.language.web.occurrences.ProblemOccurrencesService; 16import tools.refinery.language.web.occurrences.ProblemOccurrencesService;
12import tools.refinery.language.web.xtext.VirtualThreadExecutorServiceProvider;
13import tools.refinery.language.web.xtext.server.push.PushServiceDispatcher; 17import tools.refinery.language.web.xtext.server.push.PushServiceDispatcher;
14import tools.refinery.language.web.xtext.server.push.PushWebDocumentAccess; 18import tools.refinery.language.web.xtext.server.push.PushWebDocumentAccess;
15import tools.refinery.language.web.xtext.server.push.PushWebDocumentProvider; 19import tools.refinery.language.web.xtext.server.push.PushWebDocumentProvider;
@@ -33,8 +37,4 @@ public class ProblemWebModule extends AbstractProblemWebModule {
33 public Class<? extends OccurrencesService> bindOccurrencesService() { 37 public Class<? extends OccurrencesService> bindOccurrencesService() {
34 return ProblemOccurrencesService.class; 38 return ProblemOccurrencesService.class;
35 } 39 }
36
37 public Class<? extends ExecutorServiceProvider> bindExecutorServiceProvider() {
38 return VirtualThreadExecutorServiceProvider.class;
39 }
40} 40}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java
index 4738bc80..53a394d8 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSetup.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.web; 10package tools.refinery.language.web;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java
index df67b521..7b48cde8 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ProblemWebSocketServlet.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web; 6package tools.refinery.language.web;
2 7
3import org.eclipse.xtext.util.DisposableRegistry; 8import org.eclipse.xtext.util.DisposableRegistry;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java
index c41db799..7b094fde 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/SecurityHeadersFilter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web; 6package tools.refinery.language.web;
2 7
3import jakarta.servlet.*; 8import jakarta.servlet.*;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java
index f49f46ee..ad19e77d 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/ServerLauncher.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.web; 10package tools.refinery.language.web;
@@ -13,6 +19,7 @@ import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletConta
13import org.eclipse.jetty.server.Server; 19import org.eclipse.jetty.server.Server;
14import org.eclipse.jetty.util.resource.Resource; 20import org.eclipse.jetty.util.resource.Resource;
15import org.eclipse.jetty.util.resource.ResourceFactory; 21import org.eclipse.jetty.util.resource.ResourceFactory;
22import org.eclipse.jetty.util.thread.QueuedThreadPool;
16import org.slf4j.Logger; 23import org.slf4j.Logger;
17import org.slf4j.LoggerFactory; 24import org.slf4j.LoggerFactory;
18import tools.refinery.language.web.config.BackendConfigServlet; 25import tools.refinery.language.web.config.BackendConfigServlet;
@@ -43,7 +50,8 @@ public class ServerLauncher {
43 private final Server server; 50 private final Server server;
44 51
45 public ServerLauncher(InetSocketAddress bindAddress, String[] allowedOrigins, String webSocketUrl) { 52 public ServerLauncher(InetSocketAddress bindAddress, String[] allowedOrigins, String webSocketUrl) {
46 server = VirtualThreadUtils.newServerWithVirtualThreadsThreadPool("jetty", bindAddress); 53 server = new Server(bindAddress);
54 ((QueuedThreadPool) server.getThreadPool()).setName("jetty");
47 var handler = new ServletContextHandler(); 55 var handler = new ServletContextHandler();
48 addSessionHandler(handler); 56 addSessionHandler(handler);
49 addProblemServlet(handler, allowedOrigins); 57 addProblemServlet(handler, allowedOrigins);
@@ -105,7 +113,7 @@ public class ServerLauncher {
105 var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html"); 113 var indexUrlInJar = ServerLauncher.class.getResource("/webapp/index.html");
106 if (indexUrlInJar != null) { 114 if (indexUrlInJar != null) {
107 // If the app is packaged in the jar, serve it. 115 // If the app is packaged in the jar, serve it.
108 URI webRootUri = null; 116 URI webRootUri;
109 try { 117 try {
110 webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/")); 118 webRootUri = URI.create(indexUrlInJar.toURI().toASCIIString().replaceFirst("/index.html$", "/"));
111 } catch (URISyntaxException e) { 119 } catch (URISyntaxException e) {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java
deleted file mode 100644
index a055e755..00000000
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/VirtualThreadUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
1package tools.refinery.language.web;
2
3import org.eclipse.jetty.server.Server;
4import org.eclipse.jetty.server.ServerConnector;
5import org.eclipse.jetty.util.thread.QueuedThreadPool;
6import org.eclipse.jetty.util.thread.ThreadPool;
7
8import java.net.InetSocketAddress;
9import java.time.Duration;
10import java.util.concurrent.ExecutorService;
11import java.util.concurrent.Executors;
12
13public final class VirtualThreadUtils {
14 private VirtualThreadUtils() {
15 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
16 }
17
18 public static ExecutorService newNamedVirtualThreadsExecutor(String name) {
19 // Based on
20 // https://github.com/eclipse/jetty.project/blob/83154b4ffe4767ef44981598d6c26e6a5d32e57c/jetty-server/src/main/config/etc/jetty-threadpool-virtual-preview.xml
21 return Executors.newThreadPerTaskExecutor(Thread.ofVirtual()
22 .allowSetThreadLocals(true)
23 .inheritInheritableThreadLocals(false)
24 .name(name + "-virtual-", 0)
25 .factory());
26 }
27
28 public static ThreadPool newThreadPoolWithVirtualThreadsExecutor(String name) {
29 // Based on
30 // https://github.com/eclipse/jetty.project/blob/83154b4ffe4767ef44981598d6c26e6a5d32e57c/jetty-server/src/main/config/etc/jetty-threadpool-virtual-preview.xml
31 int timeout = (int) Duration.ofMinutes(1).toMillis();
32 var threadPool = new QueuedThreadPool(200, 10, timeout, -1, null, null);
33 threadPool.setName(name);
34 threadPool.setDetailedDump(false);
35 threadPool.setVirtualThreadsExecutor(newNamedVirtualThreadsExecutor(name));
36 return threadPool;
37 }
38
39 public static Server newServerWithVirtualThreadsThreadPool(String name, InetSocketAddress listenAddress) {
40 var server = new Server(newThreadPoolWithVirtualThreadsExecutor(name));
41 var connector = new ServerConnector(server);
42 try {
43 connector.setHost(listenAddress.getHostName());
44 connector.setPort(listenAddress.getPort());
45 server.addConnector(connector);
46 } catch (Exception e) {
47 connector.close();
48 throw e;
49 }
50 return server;
51 }
52}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java
index 2e864998..807b789c 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfig.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.config; 6package tools.refinery.language.web.config;
2 7
3import com.google.gson.annotations.SerializedName; 8import com.google.gson.annotations.SerializedName;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java
index f314a9fa..a2f04e34 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/config/BackendConfigServlet.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.config; 6package tools.refinery.language.web.config;
2 7
3import com.google.gson.Gson; 8import com.google.gson.Gson;
@@ -29,7 +34,7 @@ public class BackendConfigServlet extends HttpServlet {
29 } 34 }
30 35
31 @Override 36 @Override
32 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 37 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
33 resp.setStatus(HttpStatus.OK_200); 38 resp.setStatus(HttpStatus.OK_200);
34 resp.setContentType("application/json"); 39 resp.setContentType("application/json");
35 var writer = resp.getWriter(); 40 var writer = resp.getWriter();
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java
index d32bbb54..34117384 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/occurrences/ProblemOccurrencesService.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.occurrences; 6package tools.refinery.language.web.occurrences;
2 7
3import org.eclipse.emf.ecore.EObject; 8import org.eclipse.emf.ecore.EObject;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java
deleted file mode 100644
index abbcbd53..00000000
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/VirtualThreadExecutorServiceProvider.java
+++ /dev/null
@@ -1,16 +0,0 @@
1package tools.refinery.language.web.xtext;
2
3import org.eclipse.xtext.ide.ExecutorServiceProvider;
4import tools.refinery.language.web.VirtualThreadUtils;
5
6import java.util.concurrent.ExecutorService;
7
8public class VirtualThreadExecutorServiceProvider extends ExecutorServiceProvider {
9 private static final String THREAD_POOL_NAME = "xtextWeb";
10
11 @Override
12 protected ExecutorService createInstance(String key) {
13 var name = key == null ? THREAD_POOL_NAME : THREAD_POOL_NAME + "-" + key;
14 return VirtualThreadUtils.newNamedVirtualThreadsExecutor(name);
15 }
16}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java
index fe510f51..27b2e04e 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/PongResult.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server; 6package tools.refinery.language.web.xtext.server;
2 7
3import java.util.Objects; 8import java.util.Objects;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java
index 2a85afe3..3069c2dd 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandler.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server; 6package tools.refinery.language.web.xtext.server;
2 7
3import tools.refinery.language.web.xtext.server.message.XtextWebResponse; 8import tools.refinery.language.web.xtext.server.message.XtextWebResponse;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
index b686d33a..366ef0a7 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/ResponseHandlerException.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server; 6package tools.refinery.language.web.xtext.server;
2 7
3import java.io.Serial; 8import java.io.Serial;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java
index 78e00a9e..04212b84 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/SubscribingServiceContext.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server; 6package tools.refinery.language.web.xtext.server;
2 7
3import java.util.Set; 8import java.util.Set;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
index 7bb11d2e..0135d8f5 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/TransactionExecutor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server; 6package tools.refinery.language.web.xtext.server;
2 7
3import com.google.common.base.Strings; 8import com.google.common.base.Strings;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java
index f74bae74..6f4f265c 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorKind.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3import com.google.gson.annotations.SerializedName; 8import com.google.gson.annotations.SerializedName;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java
index 01d78c31..af38ad70 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebErrorResponse.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3import java.util.Objects; 8import java.util.Objects;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java
index 8af27247..73527ee5 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebOkResponse.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3import java.util.Objects; 8import java.util.Objects;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java
index c9432e1c..e9ff87c4 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebPushMessage.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3import java.util.Objects; 8import java.util.Objects;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java
index 959749f8..ff788e94 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebRequest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3import java.util.Map; 8import java.util.Map;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java
index 3bd13047..61444c99 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/message/XtextWebResponse.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.message; 6package tools.refinery.language.web.xtext.server.message;
2 7
3public sealed interface XtextWebResponse permits XtextWebOkResponse,XtextWebErrorResponse,XtextWebPushMessage { 8public sealed interface XtextWebResponse permits XtextWebOkResponse,XtextWebErrorResponse,XtextWebPushMessage {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java
index 79a284db..110c8f52 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PrecomputationListener.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.push; 6package tools.refinery.language.web.xtext.server.push;
2 7
3import org.eclipse.xtext.web.server.IServiceResult; 8import org.eclipse.xtext.web.server.IServiceResult;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java
index c7b8108d..4c9135c8 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushServiceDispatcher.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.push; 6package tools.refinery.language.web.xtext.server.push;
2 7
3import org.eclipse.xtext.web.server.IServiceContext; 8import org.eclipse.xtext.web.server.IServiceContext;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java
index 906b9e30..56fd12c9 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocument.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.push; 6package tools.refinery.language.web.xtext.server.push;
2 7
3import java.util.ArrayList; 8import java.util.ArrayList;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java
index b3666a86..d9e548cd 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentAccess.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.push; 6package tools.refinery.language.web.xtext.server.push;
2 7
3import org.eclipse.xtext.service.OperationCanceledManager; 8import org.eclipse.xtext.service.OperationCanceledManager;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java
index b6f04748..b6f4fb43 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/server/push/PushWebDocumentProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.server.push; 6package tools.refinery.language.web.xtext.server.push;
2 7
3import org.eclipse.xtext.web.server.IServiceContext; 8import org.eclipse.xtext.web.server.IServiceContext;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java
index 43e37160..fee1141d 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleServiceContext.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3import java.util.Map; 8import java.util.Map;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java
index 09c055a2..bc60c282 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/SimpleSession.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3import java.util.HashMap; 8import java.util.HashMap;
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java
index 0cd229e8..caa98e84 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextStatusCode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3public final class XtextStatusCode { 8public final class XtextStatusCode {
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
index 1d9e0463..043d318c 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocket.java
@@ -1,12 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3import com.google.gson.Gson; 8import com.google.gson.Gson;
4import com.google.gson.JsonIOException; 9import com.google.gson.JsonIOException;
5import com.google.gson.JsonParseException; 10import com.google.gson.JsonParseException;
6import org.eclipse.jetty.ee10.websocket.api.Session; 11import org.eclipse.jetty.websocket.api.Callback;
7import org.eclipse.jetty.ee10.websocket.api.StatusCode; 12import org.eclipse.jetty.websocket.api.Session;
8import org.eclipse.jetty.ee10.websocket.api.WriteCallback; 13import org.eclipse.jetty.websocket.api.StatusCode;
9import org.eclipse.jetty.ee10.websocket.api.annotations.*; 14import org.eclipse.jetty.websocket.api.annotations.*;
10import org.eclipse.xtext.resource.IResourceServiceProvider; 15import org.eclipse.xtext.resource.IResourceServiceProvider;
11import org.eclipse.xtext.web.server.ISession; 16import org.eclipse.xtext.web.server.ISession;
12import org.slf4j.Logger; 17import org.slf4j.Logger;
@@ -20,7 +25,7 @@ import tools.refinery.language.web.xtext.server.message.XtextWebResponse;
20import java.io.Reader; 25import java.io.Reader;
21 26
22@WebSocket 27@WebSocket
23public class XtextWebSocket implements WriteCallback, ResponseHandler { 28public class XtextWebSocket implements ResponseHandler {
24 private static final Logger LOG = LoggerFactory.getLogger(XtextWebSocket.class); 29 private static final Logger LOG = LoggerFactory.getLogger(XtextWebSocket.class);
25 30
26 private final Gson gson = new Gson(); 31 private final Gson gson = new Gson();
@@ -38,13 +43,13 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
38 this(new TransactionExecutor(session, resourceServiceProviderRegistry)); 43 this(new TransactionExecutor(session, resourceServiceProviderRegistry));
39 } 44 }
40 45
41 @OnWebSocketConnect 46 @OnWebSocketOpen
42 public void onConnect(Session webSocketSession) { 47 public void onOpen(Session webSocketSession) {
43 if (this.webSocketSession != null) { 48 if (this.webSocketSession != null) {
44 LOG.error("Websocket session onConnect when already connected"); 49 LOG.error("Websocket session onConnect when already connected");
45 return; 50 return;
46 } 51 }
47 LOG.debug("New websocket connection from {}", webSocketSession.getRemoteAddress()); 52 LOG.debug("New websocket connection from {}", webSocketSession.getRemoteSocketAddress());
48 this.webSocketSession = webSocketSession; 53 this.webSocketSession = webSocketSession;
49 } 54 }
50 55
@@ -55,10 +60,10 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
55 return; 60 return;
56 } 61 }
57 if (statusCode == StatusCode.NORMAL || statusCode == StatusCode.SHUTDOWN) { 62 if (statusCode == StatusCode.NORMAL || statusCode == StatusCode.SHUTDOWN) {
58 LOG.debug("{} closed connection normally: {}", webSocketSession.getRemoteAddress(), reason); 63 LOG.debug("{} closed connection normally: {}", webSocketSession.getRemoteSocketAddress(), reason);
59 } else { 64 } else {
60 LOG.warn("{} closed connection with status code {}: {}", webSocketSession.getRemoteAddress(), statusCode, 65 LOG.warn("{} closed connection with status code {}: {}", webSocketSession.getRemoteSocketAddress(),
61 reason); 66 statusCode, reason);
62 } 67 }
63 webSocketSession = null; 68 webSocketSession = null;
64 } 69 }
@@ -68,7 +73,7 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
68 if (webSocketSession == null) { 73 if (webSocketSession == null) {
69 return; 74 return;
70 } 75 }
71 LOG.error("Internal websocket error in connection from" + webSocketSession.getRemoteAddress(), error); 76 LOG.error("Internal websocket error in connection from" + webSocketSession.getRemoteSocketAddress(), error);
72 } 77 }
73 78
74 @OnWebSocketMessage 79 @OnWebSocketMessage
@@ -81,14 +86,14 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
81 try { 86 try {
82 request = gson.fromJson(reader, XtextWebRequest.class); 87 request = gson.fromJson(reader, XtextWebRequest.class);
83 } catch (JsonIOException e) { 88 } catch (JsonIOException e) {
84 LOG.error("Cannot read from websocket from" + webSocketSession.getRemoteAddress(), e); 89 LOG.error("Cannot read from websocket from" + webSocketSession.getRemoteSocketAddress(), e);
85 if (webSocketSession.isOpen()) { 90 if (webSocketSession.isOpen()) {
86 webSocketSession.close(StatusCode.SERVER_ERROR, "Cannot read payload"); 91 webSocketSession.close(StatusCode.SERVER_ERROR, "Cannot read payload", Callback.NOOP);
87 } 92 }
88 return; 93 return;
89 } catch (JsonParseException e) { 94 } catch (JsonParseException e) {
90 LOG.warn("Malformed websocket request from" + webSocketSession.getRemoteAddress(), e); 95 LOG.warn("Malformed websocket request from" + webSocketSession.getRemoteSocketAddress(), e);
91 webSocketSession.close(XtextStatusCode.INVALID_JSON, "Invalid JSON payload"); 96 webSocketSession.close(XtextStatusCode.INVALID_JSON, "Invalid JSON payload", Callback.NOOP);
92 return; 97 return;
93 } 98 }
94 try { 99 try {
@@ -96,7 +101,7 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
96 } catch (ResponseHandlerException e) { 101 } catch (ResponseHandlerException e) {
97 LOG.warn("Cannot write websocket response", e); 102 LOG.warn("Cannot write websocket response", e);
98 if (webSocketSession.isOpen()) { 103 if (webSocketSession.isOpen()) {
99 webSocketSession.close(StatusCode.SERVER_ERROR, "Cannot write response"); 104 webSocketSession.close(StatusCode.SERVER_ERROR, "Cannot write response", Callback.NOOP);
100 } 105 }
101 } 106 }
102 } 107 }
@@ -107,15 +112,14 @@ public class XtextWebSocket implements WriteCallback, ResponseHandler {
107 throw new ResponseHandlerException("Trying to send message when websocket is disconnected"); 112 throw new ResponseHandlerException("Trying to send message when websocket is disconnected");
108 } 113 }
109 var responseString = gson.toJson(response); 114 var responseString = gson.toJson(response);
110 webSocketSession.getRemote().sendPartialString(responseString, true, this); 115 webSocketSession.sendText(responseString, Callback.from(() -> {}, this::writeFailed));
111 } 116 }
112 117
113 @Override
114 public void writeFailed(Throwable x) { 118 public void writeFailed(Throwable x) {
115 if (webSocketSession == null) { 119 if (webSocketSession == null) {
116 LOG.error("Cannot complete async write to disconnected websocket", x); 120 LOG.error("Cannot complete async write to disconnected websocket", x);
117 return; 121 return;
118 } 122 }
119 LOG.warn("Cannot complete async write to websocket " + webSocketSession.getRemoteAddress(), x); 123 LOG.warn("Cannot complete async write to websocket " + webSocketSession.getRemoteSocketAddress(), x);
120 } 124 }
121} 125}
diff --git a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java
index 9a32b937..5e4fb0ce 100644
--- a/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java
+++ b/subprojects/language-web/src/main/java/tools/refinery/language/web/xtext/servlet/XtextWebSocketServlet.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3import jakarta.servlet.ServletConfig; 8import jakarta.servlet.ServletConfig;
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java
index ecbefc4f..927eeab1 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/ProblemWebSocketServletIntegrationTest.java
@@ -1,20 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web; 6package tools.refinery.language.web;
2 7
3import org.eclipse.jetty.ee10.servlet.ServletContextHandler; 8import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
4import org.eclipse.jetty.ee10.servlet.ServletHolder; 9import org.eclipse.jetty.ee10.servlet.ServletHolder;
5import org.eclipse.jetty.ee10.websocket.api.Session;
6import org.eclipse.jetty.ee10.websocket.api.StatusCode;
7import org.eclipse.jetty.ee10.websocket.api.annotations.WebSocket;
8import org.eclipse.jetty.ee10.websocket.api.exceptions.UpgradeException;
9import org.eclipse.jetty.ee10.websocket.client.ClientUpgradeRequest;
10import org.eclipse.jetty.ee10.websocket.client.WebSocketClient;
11import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer; 10import org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer;
12import org.eclipse.jetty.http.HttpHeader; 11import org.eclipse.jetty.http.HttpHeader;
13import org.eclipse.jetty.http.HttpStatus; 12import org.eclipse.jetty.http.HttpStatus;
14import org.eclipse.jetty.server.Server; 13import org.eclipse.jetty.server.Server;
14import org.eclipse.jetty.util.thread.QueuedThreadPool;
15import org.eclipse.jetty.websocket.api.Callback;
16import org.eclipse.jetty.websocket.api.Session;
17import org.eclipse.jetty.websocket.api.StatusCode;
18import org.eclipse.jetty.websocket.api.annotations.WebSocket;
19import org.eclipse.jetty.websocket.api.exceptions.UpgradeException;
20import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
21import org.eclipse.jetty.websocket.client.WebSocketClient;
15import org.eclipse.xtext.testing.GlobalRegistries; 22import org.eclipse.xtext.testing.GlobalRegistries;
16import org.eclipse.xtext.testing.GlobalRegistries.GlobalStateMemento; 23import org.eclipse.xtext.testing.GlobalRegistries.GlobalStateMemento;
17import org.junit.jupiter.api.*; 24import org.junit.jupiter.api.AfterEach;
25import org.junit.jupiter.api.BeforeEach;
26import org.junit.jupiter.api.Test;
27import org.junit.jupiter.api.TestInfo;
18import org.junit.jupiter.params.ParameterizedTest; 28import org.junit.jupiter.params.ParameterizedTest;
19import org.junit.jupiter.params.provider.ValueSource; 29import org.junit.jupiter.params.provider.ValueSource;
20import tools.refinery.language.web.tests.WebSocketIntegrationTestClient; 30import tools.refinery.language.web.tests.WebSocketIntegrationTestClient;
@@ -86,23 +96,34 @@ class ProblemWebSocketServletIntegrationTest {
86 assertThat(responses, hasSize(5)); 96 assertThat(responses, hasSize(5));
87 assertThat(responses.get(0), equalTo("{\"id\":\"foo\",\"response\":{\"stateId\":\"-80000000\"}}")); 97 assertThat(responses.get(0), equalTo("{\"id\":\"foo\",\"response\":{\"stateId\":\"-80000000\"}}"));
88 assertThat(responses.get(1), startsWith( 98 assertThat(responses.get(1), startsWith(
89 "{\"resource\":\"test.problem\",\"stateId\":\"-80000000\",\"service\":\"highlight\",\"push\":{\"regions\":[")); 99 "{\"resource\":\"test.problem\",\"stateId\":\"-80000000\",\"service\":\"highlight\"," +
100 "\"push\":{\"regions\":["));
90 assertThat(responses.get(2), equalTo( 101 assertThat(responses.get(2), equalTo(
91 "{\"resource\":\"test.problem\",\"stateId\":\"-80000000\",\"service\":\"validate\",\"push\":{\"issues\":[]}}")); 102 "{\"resource\":\"test.problem\",\"stateId\":\"-80000000\",\"service\":\"validate\"," +
103 "\"push\":{\"issues\":[]}}"));
92 assertThat(responses.get(3), equalTo("{\"id\":\"bar\",\"response\":{\"stateId\":\"-7fffffff\"}}")); 104 assertThat(responses.get(3), equalTo("{\"id\":\"bar\",\"response\":{\"stateId\":\"-7fffffff\"}}"));
93 assertThat(responses.get(4), startsWith( 105 assertThat(responses.get(4), startsWith(
94 "{\"resource\":\"test.problem\",\"stateId\":\"-7fffffff\",\"service\":\"highlight\",\"push\":{\"regions\":[")); 106 "{\"resource\":\"test.problem\",\"stateId\":\"-7fffffff\",\"service\":\"highlight\"," +
107 "\"push\":{\"regions\":["));
95 } 108 }
96 109
97 @WebSocket 110 @WebSocket
98 public static class UpdateTestClient extends WebSocketIntegrationTestClient { 111 public static class UpdateTestClient extends WebSocketIntegrationTestClient {
99 @Override 112 @Override
100 protected void arrange(Session session, int responsesReceived) throws IOException { 113 protected void arrange(Session session, int responsesReceived) {
101 switch (responsesReceived) { 114 switch (responsesReceived) {
102 case 0 -> session.getRemote().sendString( 115 case 0 -> session.sendText(
103 "{\"id\":\"foo\",\"request\":{\"resource\":\"test.problem\",\"serviceType\":\"update\",\"fullText\":\"class Person.\n\"}}"); 116 "{\"id\":\"foo\",\"request\":{\"resource\":\"test.problem\",\"serviceType\":\"update\"," +
104 case 3 -> session.getRemote().sendString( 117 "\"fullText\":\"class Person.\n\"}}",
105 "{\"id\":\"bar\",\"request\":{\"resource\":\"test.problem\",\"serviceType\":\"update\",\"requiredStateId\":\"-80000000\",\"deltaText\":\"indiv q.\nnode(q).\n\",\"deltaOffset\":\"0\",\"deltaReplaceLength\":\"0\"}}"); 118 Callback.NOOP
119 );
120 case 3 -> //noinspection TextBlockMigration
121 session.sendText(
122 "{\"id\":\"bar\",\"request\":{\"resource\":\"test.problem\",\"serviceType\":\"update\"," +
123 "\"requiredStateId\":\"-80000000\",\"deltaText\":\"indiv q.\nnode(q).\n\"," +
124 "\"deltaOffset\":\"0\",\"deltaReplaceLength\":\"0\"}}",
125 Callback.NOOP
126 );
106 case 5 -> session.close(); 127 case 5 -> session.close();
107 } 128 }
108 } 129 }
@@ -152,13 +173,13 @@ class ProblemWebSocketServletIntegrationTest {
152 @WebSocket 173 @WebSocket
153 public static class InvalidJsonTestClient extends WebSocketIntegrationTestClient { 174 public static class InvalidJsonTestClient extends WebSocketIntegrationTestClient {
154 @Override 175 @Override
155 protected void arrange(Session session, int responsesReceived) throws IOException { 176 protected void arrange(Session session, int responsesReceived) {
156 session.getRemote().sendString("<invalid json>"); 177 session.sendText("<invalid json>", Callback.NOOP);
157 } 178 }
158 } 179 }
159 180
160 @ParameterizedTest(name = "validOriginTest(\"{0}\")") 181 @ParameterizedTest(name = "validOriginTest(\"{0}\")")
161 @ValueSource(strings = { "https://refinery.example", "https://refinery.example:443", "HTTPS://REFINERY.EXAMPLE" }) 182 @ValueSource(strings = {"https://refinery.example", "https://refinery.example:443", "HTTPS://REFINERY.EXAMPLE"})
162 void validOriginTest(String origin) { 183 void validOriginTest(String origin) {
163 startServer("https://refinery.example,https://refinery.example:443"); 184 startServer("https://refinery.example,https://refinery.example:443");
164 var clientSocket = new CloseImmediatelyTestClient(); 185 var clientSocket = new CloseImmediatelyTestClient();
@@ -188,7 +209,8 @@ class ProblemWebSocketServletIntegrationTest {
188 private void startServer(String allowedOrigins) { 209 private void startServer(String allowedOrigins) {
189 var testName = getClass().getSimpleName() + "-" + testInfo.getDisplayName(); 210 var testName = getClass().getSimpleName() + "-" + testInfo.getDisplayName();
190 var listenAddress = new InetSocketAddress(HOSTNAME, serverPort); 211 var listenAddress = new InetSocketAddress(HOSTNAME, serverPort);
191 server = VirtualThreadUtils.newServerWithVirtualThreadsThreadPool(testName, listenAddress); 212 server = new Server(listenAddress);
213 ((QueuedThreadPool) server.getThreadPool()).setName(testName);
192 var handler = new ServletContextHandler(); 214 var handler = new ServletContextHandler();
193 var holder = new ServletHolder(ProblemWebSocketServlet.class); 215 var holder = new ServletHolder(ProblemWebSocketServlet.class);
194 if (allowedOrigins != null) { 216 if (allowedOrigins != null) {
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
index c634e8fc..52acee6d 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/AwaitTerminationExecutorServiceProvider.java
@@ -1,14 +1,19 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.tests; 6package tools.refinery.language.web.tests;
2 7
3import com.google.inject.Singleton; 8import com.google.inject.Singleton;
4import tools.refinery.language.web.xtext.VirtualThreadExecutorServiceProvider; 9import org.eclipse.xtext.ide.ExecutorServiceProvider;
5 10
6import java.util.ArrayList; 11import java.util.ArrayList;
7import java.util.List; 12import java.util.List;
8import java.util.concurrent.ExecutorService; 13import java.util.concurrent.ExecutorService;
9 14
10@Singleton 15@Singleton
11public class AwaitTerminationExecutorServiceProvider extends VirtualThreadExecutorServiceProvider { 16public class AwaitTerminationExecutorServiceProvider extends ExecutorServiceProvider {
12 private final List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>(); 17 private final List<RestartableCachedThreadPool> servicesToShutDown = new ArrayList<>();
13 18
14 @Override 19 @Override
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java
index 43c12faa..4a5eed95 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/ProblemWebInjectorProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.tests; 6package tools.refinery.language.web.tests;
2 7
3import org.eclipse.xtext.ide.ExecutorServiceProvider; 8import org.eclipse.xtext.ide.ExecutorServiceProvider;
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
index cf805eda..09079aa8 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/RestartableCachedThreadPool.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.tests; 6package tools.refinery.language.web.tests;
2 7
3import com.google.inject.Provider; 8import com.google.inject.Provider;
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
index f19c10ca..6ccf1760 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/tests/WebSocketIntegrationTestClient.java
@@ -1,12 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.tests; 6package tools.refinery.language.web.tests;
2 7
3import org.eclipse.jetty.ee10.websocket.api.Session; 8import org.eclipse.jetty.websocket.api.Session;
4import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketClose; 9import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
5import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketConnect; 10import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
6import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketError; 11import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
7import org.eclipse.jetty.ee10.websocket.api.annotations.OnWebSocketMessage; 12import org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen;
8 13
9import java.io.IOException;
10import java.time.Duration; 14import java.time.Duration;
11import java.util.ArrayList; 15import java.util.ArrayList;
12import java.util.List; 16import java.util.List;
@@ -14,7 +18,7 @@ import java.util.List;
14import static org.junit.jupiter.api.Assertions.fail; 18import static org.junit.jupiter.api.Assertions.fail;
15 19
16public abstract class WebSocketIntegrationTestClient { 20public abstract class WebSocketIntegrationTestClient {
17 private static final long TIMEOUT_MILLIS = Duration.ofSeconds(1).toMillis(); 21 private static final long TIMEOUT_MILLIS = Duration.ofSeconds(10).toMillis();
18 22
19 private boolean finished = false; 23 private boolean finished = false;
20 24
@@ -34,8 +38,8 @@ public abstract class WebSocketIntegrationTestClient {
34 return responses; 38 return responses;
35 } 39 }
36 40
37 @OnWebSocketConnect 41 @OnWebSocketOpen
38 public void onConnect(Session session) { 42 public void onOpen(Session session) {
39 arrangeAndCatchErrors(session); 43 arrangeAndCatchErrors(session);
40 } 44 }
41 45
@@ -47,7 +51,7 @@ public abstract class WebSocketIntegrationTestClient {
47 } 51 }
48 } 52 }
49 53
50 protected abstract void arrange(Session session, int responsesReceived) throws IOException; 54 protected abstract void arrange(Session session, int responsesReceived);
51 55
52 @OnWebSocketClose 56 @OnWebSocketClose
53 public void onClose(int statusCode, String reason) { 57 public void onClose(int statusCode, String reason) {
diff --git a/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java b/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
index 17f1ff5c..841bacd3 100644
--- a/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
+++ b/subprojects/language-web/src/test/java/tools/refinery/language/web/xtext/servlet/TransactionExecutorTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.web.xtext.servlet; 6package tools.refinery.language.web.xtext.servlet;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/build.gradle b/subprojects/language/build.gradle
deleted file mode 100644
index 654558e3..00000000
--- a/subprojects/language/build.gradle
+++ /dev/null
@@ -1,73 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3 id 'refinery-java-test-fixtures'
4 id 'refinery-mwe2'
5 id 'refinery-sonarqube'
6 id 'refinery-xtext-conventions'
7}
8
9dependencies {
10 api platform(libs.xtext.bom)
11 api libs.ecore
12 api libs.xtext.core
13 api libs.xtext.xbase
14 api project(':refinery-language-model')
15 testFixturesApi libs.xtext.testing
16 mwe2 libs.xtext.generator
17 mwe2 libs.xtext.generator.antlr
18}
19
20sourceSets {
21 testFixtures {
22 java.srcDirs += ['src/testFixtures/xtext-gen']
23 resources.srcDirs += ['src/testFixtures/xtext-gen']
24 }
25}
26
27tasks.named('jar') {
28 from(sourceSets.main.allSource) {
29 include '**/*.xtext'
30 }
31}
32
33def generateXtextLanguage = tasks.register('generateXtextLanguage', JavaExec) {
34 mainClass = 'org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher'
35 classpath = configurations.mwe2
36 inputs.file 'src/main/java/tools/refinery/language/GenerateProblem.mwe2'
37 inputs.file 'src/main/java/tools/refinery/language/Problem.xtext'
38 outputs.dir 'src/main/xtext-gen'
39 outputs.dir 'src/testFixtures/xtext-gen'
40 outputs.dir '../language-ide/src/main/xtext-gen'
41 outputs.dir '../language-web/src/main/xtext-gen'
42 args += 'src/main/java/tools/refinery/language/GenerateProblem.mwe2'
43 args += '-p'
44 args += "rootPath=/${projectDir}/.."
45}
46
47for (taskName in [
48 'compileJava',
49 'processResources',
50 'processTestFixturesResources',
51 'generateEclipseSourceFolders'
52 ]) {
53 tasks.named(taskName) {
54 dependsOn generateXtextLanguage
55 }
56}
57
58tasks.named('clean') {
59 delete 'src/main/xtext-gen'
60 delete 'src/testFixtures/xtext-gen'
61 delete '../language-ide/src/main/xtext-gen'
62 delete '../language-web/src/main/xtext-gen'
63}
64
65sonarqube.properties {
66 properties['sonar.exclusions'] += [
67 'src/testFixtures/xtext-gen/**',
68 ]
69}
70
71eclipse.project.natures += [
72 'org.eclipse.xtext.ui.shared.xtextNature'
73]
diff --git a/subprojects/language/build.gradle.kts b/subprojects/language/build.gradle.kts
new file mode 100644
index 00000000..bac1e586
--- /dev/null
+++ b/subprojects/language/build.gradle.kts
@@ -0,0 +1,101 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7import tools.refinery.gradle.utils.SonarPropertiesUtils
8
9plugins {
10 id("tools.refinery.gradle.java-library")
11 id("tools.refinery.gradle.java-test-fixtures")
12 id("tools.refinery.gradle.mwe2")
13 id("tools.refinery.gradle.sonarqube")
14 id("tools.refinery.gradle.xtext-generated")
15}
16
17val generatedIdeSources: Configuration by configurations.creating {
18 isCanBeConsumed = true
19 isCanBeResolved = false
20}
21
22val generatedWebSources: Configuration by configurations.creating {
23 isCanBeConsumed = true
24 isCanBeResolved = false
25}
26
27dependencies {
28 api(platform(libs.xtext.bom))
29 api(libs.ecore)
30 api(libs.xtext.core)
31 api(libs.xtext.xbase)
32 api(project(":refinery-language-model"))
33 testFixturesApi(libs.xtext.testing)
34 mwe2(libs.xtext.generator)
35 mwe2(libs.xtext.generator.antlr)
36}
37
38sourceSets {
39 testFixtures {
40 java.srcDir("src/testFixtures/xtext-gen")
41 resources.srcDir("src/testFixtures/xtext-gen")
42 }
43}
44
45val generateXtextLanguage by tasks.registering(JavaExec::class) {
46 mainClass.set("org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher")
47 classpath(configurations.mwe2)
48 inputs.file("src/main/java/tools/refinery/language/GenerateProblem.mwe2")
49 inputs.file("src/main/java/tools/refinery/language/Problem.xtext")
50 inputs.file("../language-model/src/main/resources/model/problem.ecore")
51 inputs.file("../language-model/src/main/resources/model/problem.genmodel")
52 outputs.dir("src/main/xtext-gen")
53 outputs.dir("src/testFixtures/xtext-gen")
54 outputs.dir("$buildDir/generated/sources/xtext/ide")
55 outputs.dir("$buildDir/generated/sources/xtext/web")
56 args("src/main/java/tools/refinery/language/GenerateProblem.mwe2", "-p", "rootPath=/$projectDir/..")
57}
58
59tasks {
60 jar {
61 from(sourceSets.main.map { it.allSource }) {
62 include("**/*.xtext")
63 }
64 }
65
66 syncXtextGeneratedSources {
67 // We generate Xtext runtime sources directly to {@code src/main/xtext-gen}, so there is no need to copy them
68 // from an artifact. We expose the {@code generatedIdeSources} and {@code generatedWebSources} artifacts to
69 // sibling IDE and web projects which can use this task to consume them and copy the appropriate sources to
70 // their own {@code src/main/xtext-gen} directory.
71 enabled = false
72 }
73
74 for (taskName in listOf("compileJava", "processResources", "compileTestFixturesJava",
75 "processTestFixturesResources", "generateEclipseSourceFolders")) {
76 named(taskName) {
77 dependsOn(generateXtextLanguage)
78 }
79 }
80
81 clean {
82 delete("src/main/xtext-gen")
83 delete("src/testFixtures/xtext-gen")
84 }
85}
86
87artifacts {
88 add(generatedIdeSources.name, file("$buildDir/generated/sources/xtext/ide")) {
89 builtBy(generateXtextLanguage)
90 }
91
92 add(generatedWebSources.name, file("$buildDir/generated/sources/xtext/web")) {
93 builtBy(generateXtextLanguage)
94 }
95}
96
97sonarqube.properties {
98 SonarPropertiesUtils.addToList(properties, "sonar.exclusions", "src/textFixtures/xtext-gen/**")
99}
100
101eclipse.project.natures.plusAssign("org.eclipse.xtext.ui.shared.xtextNature")
diff --git a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2 b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
index 21ff456e..59eba8f7 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
+++ b/subprojects/language/src/main/java/tools/refinery/language/GenerateProblem.mwe2
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1module tools.refinery.language.GenerateProblem 6module tools.refinery.language.GenerateProblem
2 7
3import org.eclipse.xtext.xtext.generator.* 8import org.eclipse.xtext.xtext.generator.*
@@ -11,16 +16,28 @@ Workflow {
11 project = StandardProjectConfig { 16 project = StandardProjectConfig {
12 baseName = 'language' 17 baseName = 'language'
13 rootPath = rootPath 18 rootPath = rootPath
19 runtime = {
20 // Do not generate new files into src/main/java
21 src = null
22 }
14 runtimeTest = { 23 runtimeTest = {
15 enabled = true 24 enabled = true
16 srcGen = 'src/testFixtures/xtext-gen' 25 // Only generate the xtext-gen files and leave the rest of the project alone
26 root = null
27 srcGen = '${rootPath}/language/src/testFixtures/xtext-gen'
17 } 28 }
18 genericIde = { 29 genericIde = {
19 name = 'language-ide' 30 name = 'language-ide'
31 // Only generate the xtext-gen files and leave the rest of the project alone
32 root = null
33 srcGen = "${rootPath}/language/build/generated/sources/xtext/ide"
20 } 34 }
21 web = { 35 web = {
22 enabled = true 36 enabled = true
23 name = 'language-web' 37 name = 'language-web'
38 // Only generate the xtext-gen files and leave the rest of the project alone
39 root = null
40 srcGen = "${rootPath}/language/build/generated/sources/xtext/web"
24 } 41 }
25 mavenLayout = true 42 mavenLayout = true
26 } 43 }
@@ -55,7 +72,7 @@ Workflow {
55 } 72 }
56 webSupport = { 73 webSupport = {
57 // We only generate the {@code AbstractProblemWebModule}, 74 // We only generate the {@code AbstractProblemWebModule},
58 // because we write our own integration code for CodeMirror 6. 75 // because we write our own integration code for CodeMirror 6.
59 framework = 'codemirror' 76 framework = 'codemirror'
60 generateHtmlExample = false 77 generateHtmlExample = false
61 generateJettyLauncher = false 78 generateJettyLauncher = false
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 187ebf1f..9e330347 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
+++ b/subprojects/language/src/main/java/tools/refinery/language/Problem.xtext
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1grammar tools.refinery.language.Problem with org.eclipse.xtext.common.Terminals 6grammar tools.refinery.language.Problem with org.eclipse.xtext.common.Terminals
2 7
3import "http://www.eclipse.org/emf/2002/Ecore" as ecore 8import "http://www.eclipse.org/emf/2002/Ecore" as ecore
diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
index 5efcdc81..2636a8ee 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemRuntimeModule.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language; 10package tools.refinery.language;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java b/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java
index 41c96114..639d6778 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/ProblemStandaloneSetup.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language; 10package tools.refinery.language;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java b/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java
index 508688ed..afbc367e 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/conversion/ProblemValueConverterService.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.conversion; 6package tools.refinery.language.conversion;
2 7
3import org.eclipse.xtext.common.services.DefaultTerminalConverters; 8import org.eclipse.xtext.common.services.DefaultTerminalConverters;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java b/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java
index be0d15ad..4886757d 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/conversion/UpperBoundValueConverter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.conversion; 6package tools.refinery.language.conversion;
2 7
3import org.eclipse.xtext.conversion.ValueConverterException; 8import org.eclipse.xtext.conversion.ValueConverterException;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java
index 797535ea..55a5ac20 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/formatting2/ProblemFormatter.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.26.0.M2 8 * generated by Xtext 2.26.0.M2
3 */ 9 */
4package tools.refinery.language.formatting2; 10package tools.refinery.language.formatting2;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java b/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java
index e959be74..1647d4e7 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/naming/NamingUtil.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.naming; 6package tools.refinery.language.naming;
2 7
3import java.util.regex.Pattern; 8import java.util.regex.Pattern;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java b/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java
index 5453906f..74b4e208 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/naming/ProblemQualifiedNameConverter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.naming; 6package tools.refinery.language.naming;
2 7
3import org.eclipse.xtext.naming.IQualifiedNameConverter; 8import org.eclipse.xtext.naming.IQualifiedNameConverter;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java
index ab133a90..306a86fc 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/IdentifierTokenProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.parser.antlr; 6package tools.refinery.language.parser.antlr;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java
index 0b4e7185..5b91a6cc 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/ProblemTokenSource.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.29.0.M2 8 * generated by Xtext 2.29.0.M2
3 */ 9 */
4package tools.refinery.language.parser.antlr; 10package tools.refinery.language.parser.antlr;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java
index 0cdd38d8..fe4c0bc7 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/parser/antlr/TokenSourceInjectingProblemParser.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.parser.antlr; 6package tools.refinery.language.parser.antlr;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java
index 6176b0c4..07c5da41 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/DerivedVariableComputer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java
index b0ac2ab6..e97c8287 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ImplicitVariableScope.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import org.eclipse.emf.ecore.EObject; 8import org.eclipse.emf.ecore.EObject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
index 419be0d3..e5deca4d 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/NodeNameCollector.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import com.google.common.collect.ImmutableSet; 8import com.google.common.collect.ImmutableSet;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
index 8d3a552a..b145ef27 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemDerivedStateComputer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java
index df822987..1fe2df89 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemLocationInFileProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import org.eclipse.emf.ecore.EObject; 8import org.eclipse.emf.ecore.EObject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java
index 1a0b73a8..630be379 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ProblemResourceDescriptionStrategy.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import org.eclipse.emf.ecore.EObject; 8import org.eclipse.emf.ecore.EObject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java b/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java
index ca20325e..f1be55ee 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/resource/ReferenceCounter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.resource; 6package tools.refinery.language.resource;
2 7
3import java.util.HashMap; 8import java.util.HashMap;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java
index b749154c..4d2dd772 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemGlobalScopeProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.scoping; 6package tools.refinery.language.scoping;
2 7
3import java.util.LinkedHashSet; 8import java.util.LinkedHashSet;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java
index 61883f0e..229960a0 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/scoping/ProblemLocalScopeProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.scoping; 6package tools.refinery.language.scoping;
2 7
3import java.util.List; 8import java.util.List;
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 3ab07496..cf099aba 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,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.scoping; 10package tools.refinery.language.scoping;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java
index 27ce1521..b9cafbc2 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/serializer/PreferShortAssertionsProblemSemanticSequencer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.serializer; 6package tools.refinery.language.serializer;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
index d3777cd3..c8c7fd4a 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/BuiltinSymbols.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import tools.refinery.language.model.problem.*; 8import tools.refinery.language.model.problem.*;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java b/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java
index b5682f32..e4e4d07a 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/CollectedSymbols.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import java.util.Map; 8import java.util.Map;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java
index 708e10a9..a43c7dfe 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ContainmentRole.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import tools.refinery.language.model.problem.PredicateKind; 8import tools.refinery.language.model.problem.PredicateKind;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
index c8f47653..0fa7a454 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/NodeInfo.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3public record NodeInfo(String name, boolean individual) { 8public record NodeInfo(String name, boolean individual) {
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
index b8200919..738a0896 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemDesugarer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
index 1e5164d3..9486dc2a 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/ProblemUtil.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import org.eclipse.emf.common.util.URI; 8import org.eclipse.emf.common.util.URI;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java b/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java
index 2253d257..1c46fe72 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/RelationInfo.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import tools.refinery.language.model.problem.*; 8import tools.refinery.language.model.problem.*;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
index 65167ed6..a4ea1113 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/utils/SymbolCollector.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.utils; 6package tools.refinery.language.utils;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
index 659d882c..88d50c5b 100644
--- a/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
+++ b/subprojects/language/src/main/java/tools/refinery/language/validation/ProblemValidator.java
@@ -1,4 +1,10 @@
1/* 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7/*
2 * generated by Xtext 2.25.0 8 * generated by Xtext 2.25.0
3 */ 9 */
4package tools.refinery.language.validation; 10package tools.refinery.language.validation;
diff --git a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
index 06b6da1d..9c1d7669 100644
--- a/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
+++ b/subprojects/language/src/main/resources/tools/refinery/language/builtin.problem
@@ -1,3 +1,6 @@
1% SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
2%
3% SPDX-License-Identifier: EPL-2.0
1problem builtin. 4problem builtin.
2 5
3abstract class node { 6abstract class node {
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
index 58daa365..c7952369 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/ProblemParsingTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests; 6package tools.refinery.language.tests;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
index 6e0802ca..f688d970 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/formatting2/ProblemFormatterTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.formatting2; 6package tools.refinery.language.tests.formatting2;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
index abff8d9c..37d38dd9 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/IdentifierTokenProviderTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.parser.antlr; 6package tools.refinery.language.tests.parser.antlr;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
index cb42d5d0..644744a0 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/ProblemTokenSourceTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.parser.antlr; 6package tools.refinery.language.tests.parser.antlr;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
index 65ceb45f..1180d131 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/parser/antlr/TransitiveClosureParserTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.parser.antlr; 6package tools.refinery.language.tests.parser.antlr;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
index 72e5e18a..68514bfa 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/rules/RuleParsingTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.rules; 6package tools.refinery.language.tests.rules;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
index fa462691..734bfcd1 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/scoping/NodeScopingTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.scoping; 6package tools.refinery.language.tests.scoping;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
index 4a18704a..3f3a081f 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/serializer/ProblemSerializerTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.serializer; 6package tools.refinery.language.tests.serializer;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
index af6de37f..d200eeff 100644
--- a/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
+++ b/subprojects/language/src/test/java/tools/refinery/language/tests/utils/SymbolCollectorTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.tests.utils; 6package tools.refinery.language.tests.utils;
2 7
3import com.google.inject.Inject; 8import com.google.inject.Inject;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java
index 5761935b..d92011a9 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemNavigationUtil.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import java.util.List; 8import java.util.List;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java
index 5e044a94..6f6a87f7 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/ProblemParseHelper.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import org.eclipse.xtext.testing.util.ParseHelper; 8import org.eclipse.xtext.testing.util.ParseHelper;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java
index d176727b..3a49a0b9 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Action; 8import tools.refinery.language.model.problem.Action;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java
index 9e4c59f5..ed749fed 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedArgument.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.*; 8import tools.refinery.language.model.problem.*;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java
index 2c38639d..b2ef6e48 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertion.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Assertion; 8import tools.refinery.language.model.problem.Assertion;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
index 840c1f74..b36f2506 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAssertionArgument.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.AssertionArgument; 8import tools.refinery.language.model.problem.AssertionArgument;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java
index 498991f8..c02f447b 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedAtom.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Atom; 8import tools.refinery.language.model.problem.Atom;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
index 41b2ea62..a228137c 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedClassDeclaration.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.ClassDeclaration; 8import tools.refinery.language.model.problem.ClassDeclaration;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java
index 88ff71ab..b126b1ce 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConjunction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Conjunction; 8import tools.refinery.language.model.problem.Conjunction;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java
index 46faa7da..8d6a92f8 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedConsequent.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Consequent; 8import tools.refinery.language.model.problem.Consequent;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java
index 74dcf01b..229a8c0a 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedEnumDeclaration.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.EnumDeclaration; 8import tools.refinery.language.model.problem.EnumDeclaration;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java
index 4aa71b99..160e5dd8 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedLiteral.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Atom; 8import tools.refinery.language.model.problem.Atom;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java
index c2f18a60..d44b79ed 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedParametricDefinition.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.Parameter; 8import tools.refinery.language.model.problem.Parameter;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java
index 7b95ecc1..2cf5fd89 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedPredicateDefinition.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.PredicateDefinition; 8import tools.refinery.language.model.problem.PredicateDefinition;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
index 78ca95c7..e5aa0043 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedProblem.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import org.eclipse.emf.ecore.resource.Resource.Diagnostic; 8import org.eclipse.emf.ecore.resource.Resource.Diagnostic;
diff --git a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java
index a4cf2eaf..326d8ec3 100644
--- a/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java
+++ b/subprojects/language/src/testFixtures/java/tools/refinery/language/model/tests/utils/WrappedRuleDefinition.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.language.model.tests.utils; 6package tools.refinery.language.model.tests.utils;
2 7
3import tools.refinery.language.model.problem.RuleDefinition; 8import tools.refinery.language.model.problem.RuleDefinition;
diff --git a/subprojects/store-query-viatra/NOTICE.md b/subprojects/store-query-viatra/NOTICE.md
new file mode 100644
index 00000000..7c21726a
--- /dev/null
+++ b/subprojects/store-query-viatra/NOTICE.md
@@ -0,0 +1,87 @@
1<!--
2 Copyright (c) 2018-2019, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
4
5 SPDX-License-Identifier: EPL-2.0
6-->
7
8This module contains source code from the [Eclipse VIATRA project](https://projects.eclipse.org/projects/modeling.viatra), which is available under the terms of the [Eclipse Public License v 2.0](http://www.eclipse.org/legal/epl-v20.html).
9
10We reproduce the [accompanying notices](https://github.com/viatra/org.eclipse.viatra/blob/d422bcc626a99c4640c0d13931f393ccea0d2326/NOTICE.md) in full below:
11
12# Notices for Eclipse VIATRA
13
14This content is produced and maintained by the Eclipse VIATRA project.
15
16* Project home: https://projects.eclipse.org/projects/modeling.viatra
17
18## Trademarks
19
20Eclipse VIATRA, and VIATRA are trademarks of the Eclipse Foundation.
21
22## Copyright
23
24All content is the property of the respective authors or their employers. For
25more information regarding authorship of content, please consult the listed
26source code repository logs.
27
28## Declared Project Licenses
29
30This program and the accompanying materials are made available under the terms
31of the Eclipse Public License v. 2.0 which is available at
32http://www.eclipse.org/legal/epl-v20.html.
33
34SPDX-License-Identifier: EPL-2.0
35
36## Source Code
37
38The project maintains the following source code repositories:
39
40* http://git.eclipse.org/c/viatra/org.eclipse.viatra.git
41* http://git.eclipse.org/c/viatra/org.eclipse.viatra.modelobfuscator.git
42* http://git.eclipse.org/c/viatra/org.eclipse.viatra.examples.git
43* http://git.eclipse.org/c/viatra/org.eclipse.viatra2.vpm.git
44
45## Third-party Content
46
47This project leverages the following third party content.
48
49ANTLR Runtime only: (3.2)
50
51* License: New BSD license
52
53Apache Commons Language Library (2.1)
54
55* License: Apache License, 2.0
56
57Google Guice / Inject Core API (3.0.0)
58
59* License: Apache License, 2.0
60
61Google Guice / Inject Core API (3.0.0)
62
63* License: Apache License 2.0
64
65Guava (10.0.1)
66
67* License: Apache License, 2.0
68
69Guice (2.0)
70
71* License: Apache License, 2.0
72
73guice-multibindings (3.0.0)
74
75* License: Apache License, 2.0
76
77log4j (1.2.15)
78
79* License: Apache License 2.0
80
81LPG Java Runtime (lpgjavaruntime.jar) (1.1)
82
83* License: Eclipse Public License
84
85mockito (1.9.5)
86
87* License: Apache License, 2.0, New BSD license, MIT license
diff --git a/subprojects/store-query-viatra/build.gradle b/subprojects/store-query-viatra/build.gradle
deleted file mode 100644
index 13a7544f..00000000
--- a/subprojects/store-query-viatra/build.gradle
+++ /dev/null
@@ -1,16 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3}
4
5configurations.testRuntimeClasspath {
6 // VIATRA requires log4j 1.x, but we use log4j-over-slf4j instead
7 exclude group: 'log4j', module: 'log4j'
8}
9
10dependencies {
11 implementation libs.ecore
12 api libs.viatra
13 api project(':refinery-store-query')
14 testImplementation libs.slf4j.simple
15 testImplementation libs.slf4j.log4j
16}
diff --git a/subprojects/store-query-viatra/build.gradle.kts b/subprojects/store-query-viatra/build.gradle.kts
new file mode 100644
index 00000000..e3a22145
--- /dev/null
+++ b/subprojects/store-query-viatra/build.gradle.kts
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 implementation(libs.ecore)
13 api(libs.viatra)
14 api(project(":refinery-store-query"))
15}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
deleted file mode 100644
index 677e3c7d..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQuery.java
+++ /dev/null
@@ -1,21 +0,0 @@
1package tools.refinery.store.query.viatra;
2
3import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
4import tools.refinery.store.model.ModelStoreBuilder;
5import tools.refinery.store.query.ModelQuery;
6import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl;
7
8public final class ViatraModelQuery extends ModelAdapterBuilderFactory<ViatraModelQueryAdapter,
9 ViatraModelQueryStoreAdapter, ViatraModelQueryBuilder> {
10 public static final ViatraModelQuery ADAPTER = new ViatraModelQuery();
11
12 private ViatraModelQuery() {
13 super(ViatraModelQueryAdapter.class, ViatraModelQueryStoreAdapter.class, ViatraModelQueryBuilder.class);
14 extendsAdapter(ModelQuery.ADAPTER);
15 }
16
17 @Override
18 public ViatraModelQueryBuilder createBuilder(ModelStoreBuilder storeBuilder) {
19 return new ViatraModelQueryBuilderImpl(storeBuilder);
20 }
21}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java
index 7e21476b..12c93f62 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryAdapter.java
@@ -1,8 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import tools.refinery.store.query.ModelQueryAdapter; 8import tools.refinery.store.query.ModelQueryAdapter;
9import tools.refinery.store.query.viatra.internal.ViatraModelQueryBuilderImpl;
4 10
5public interface ViatraModelQueryAdapter extends ModelQueryAdapter { 11public interface ViatraModelQueryAdapter extends ModelQueryAdapter {
6 @Override 12 @Override
7 ViatraModelQueryStoreAdapter getStoreAdapter(); 13 ViatraModelQueryStoreAdapter getStoreAdapter();
14
15 static ViatraModelQueryBuilder builder() {
16 return new ViatraModelQueryBuilderImpl();
17 }
8} 18}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
index 7ae86f9f..931a07aa 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryBuilder.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; 8import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
@@ -45,5 +50,5 @@ public interface ViatraModelQueryBuilder extends ModelQueryBuilder {
45 ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint); 50 ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint);
46 51
47 @Override 52 @Override
48 ViatraModelQueryStoreAdapter createStoreAdapter(ModelStore store); 53 ViatraModelQueryStoreAdapter build(ModelStore store);
49} 54}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
index 1ee02f12..da6d7bd5 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/ViatraModelQueryStoreAdapter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions; 8import org.eclipse.viatra.query.runtime.api.ViatraQueryEngineOptions;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
index 8328e759..d1a65a89 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/RelationalScope.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal; 6package tools.refinery.store.query.viatra.internal;
2 7
3import org.apache.log4j.Logger; 8import org.apache.log4j.Logger;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
index 8be30fee..7103a561 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryAdapterImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal; 6package tools.refinery.store.query.viatra.internal;
2 7
3import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine; 8import org.eclipse.viatra.query.runtime.api.AdvancedViatraQueryEngine;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
index bfabf26e..ce2467b4 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryBuilderImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal; 6package tools.refinery.store.query.viatra.internal;
2 7
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification; 8import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
@@ -20,7 +25,8 @@ import tools.refinery.store.query.viatra.internal.pquery.Dnf2PQuery;
20import java.util.*; 25import java.util.*;
21import java.util.function.Function; 26import java.util.function.Function;
22 27
23public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder implements ViatraModelQueryBuilder { 28public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder<ViatraModelQueryStoreAdapterImpl>
29 implements ViatraModelQueryBuilder {
24 private ViatraQueryEngineOptions.Builder engineOptionsBuilder; 30 private ViatraQueryEngineOptions.Builder engineOptionsBuilder;
25 private QueryEvaluationHint defaultHint = new QueryEvaluationHint(Map.of( 31 private QueryEvaluationHint defaultHint = new QueryEvaluationHint(Map.of(
26 // Use a cost function that ignores the initial (empty) model but allows higher arity input keys. 32 // Use a cost function that ignores the initial (empty) model but allows higher arity input keys.
@@ -30,8 +36,7 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp
30 private final Set<AnyQuery> vacuousQueries = new LinkedHashSet<>(); 36 private final Set<AnyQuery> vacuousQueries = new LinkedHashSet<>();
31 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>(); 37 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications = new LinkedHashMap<>();
32 38
33 public ViatraModelQueryBuilderImpl(ModelStoreBuilder storeBuilder) { 39 public ViatraModelQueryBuilderImpl() {
34 super(storeBuilder);
35 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder() 40 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder()
36 .withDefaultBackend(ReteBackendFactory.INSTANCE) 41 .withDefaultBackend(ReteBackendFactory.INSTANCE)
37 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE) 42 .withDefaultCachingBackend(ReteBackendFactory.INSTANCE)
@@ -40,36 +45,42 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp
40 45
41 @Override 46 @Override
42 public ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions) { 47 public ViatraModelQueryBuilder engineOptions(ViatraQueryEngineOptions engineOptions) {
48 checkNotConfigured();
43 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder(engineOptions); 49 engineOptionsBuilder = new ViatraQueryEngineOptions.Builder(engineOptions);
44 return this; 50 return this;
45 } 51 }
46 52
47 @Override 53 @Override
48 public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) { 54 public ViatraModelQueryBuilder defaultHint(QueryEvaluationHint queryEvaluationHint) {
55 checkNotConfigured();
49 defaultHint = defaultHint.overrideBy(queryEvaluationHint); 56 defaultHint = defaultHint.overrideBy(queryEvaluationHint);
50 return this; 57 return this;
51 } 58 }
52 59
53 @Override 60 @Override
54 public ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory) { 61 public ViatraModelQueryBuilder backend(IQueryBackendFactory queryBackendFactory) {
62 checkNotConfigured();
55 engineOptionsBuilder.withDefaultBackend(queryBackendFactory); 63 engineOptionsBuilder.withDefaultBackend(queryBackendFactory);
56 return this; 64 return this;
57 } 65 }
58 66
59 @Override 67 @Override
60 public ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory) { 68 public ViatraModelQueryBuilder cachingBackend(IQueryBackendFactory queryBackendFactory) {
69 checkNotConfigured();
61 engineOptionsBuilder.withDefaultCachingBackend(queryBackendFactory); 70 engineOptionsBuilder.withDefaultCachingBackend(queryBackendFactory);
62 return this; 71 return this;
63 } 72 }
64 73
65 @Override 74 @Override
66 public ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory) { 75 public ViatraModelQueryBuilder searchBackend(IQueryBackendFactory queryBackendFactory) {
76 checkNotConfigured();
67 engineOptionsBuilder.withDefaultSearchBackend(queryBackendFactory); 77 engineOptionsBuilder.withDefaultSearchBackend(queryBackendFactory);
68 return this; 78 return this;
69 } 79 }
70 80
71 @Override 81 @Override
72 public ViatraModelQueryBuilder query(AnyQuery query) { 82 public ViatraModelQueryBuilder query(AnyQuery query) {
83 checkNotConfigured();
73 if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) { 84 if (querySpecifications.containsKey(query) || vacuousQueries.contains(query)) {
74 // Ignore duplicate queries. 85 // Ignore duplicate queries.
75 return this; 86 return this;
@@ -98,21 +109,27 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp
98 109
99 @Override 110 @Override
100 public ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint) { 111 public ViatraModelQueryBuilder computeHint(Function<Dnf, QueryEvaluationHint> computeHint) {
112 checkNotConfigured();
101 dnf2PQuery.setComputeHint(computeHint); 113 dnf2PQuery.setComputeHint(computeHint);
102 return this; 114 return this;
103 } 115 }
104 116
105 @Override 117 @Override
106 public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) { 118 public ViatraModelQueryBuilder hint(Dnf dnf, QueryEvaluationHint queryEvaluationHint) {
119 checkNotConfigured();
107 dnf2PQuery.hint(dnf, queryEvaluationHint); 120 dnf2PQuery.hint(dnf, queryEvaluationHint);
108 return this; 121 return this;
109 } 122 }
110 123
111 @Override 124 @Override
112 public ViatraModelQueryStoreAdapterImpl createStoreAdapter(ModelStore store) { 125 public void doConfigure(ModelStoreBuilder storeBuilder) {
113 validateSymbols(store);
114 dnf2PQuery.assertNoUnusedHints(); 126 dnf2PQuery.assertNoUnusedHints();
115 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getRelationViews(), 127 }
128
129 @Override
130 public ViatraModelQueryStoreAdapterImpl doBuild(ModelStore store) {
131 validateSymbols(store);
132 return new ViatraModelQueryStoreAdapterImpl(store, buildEngineOptions(), dnf2PQuery.getSymbolViews(),
116 Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries)); 133 Collections.unmodifiableMap(querySpecifications), Collections.unmodifiableSet(vacuousQueries));
117 } 134 }
118 135
@@ -135,11 +152,11 @@ public class ViatraModelQueryBuilderImpl extends AbstractModelAdapterBuilder imp
135 152
136 private void validateSymbols(ModelStore store) { 153 private void validateSymbols(ModelStore store) {
137 var symbols = store.getSymbols(); 154 var symbols = store.getSymbols();
138 for (var relationView : dnf2PQuery.getRelationViews().keySet()) { 155 for (var symbolView : dnf2PQuery.getSymbolViews().keySet()) {
139 var symbol = relationView.getSymbol(); 156 var symbol = symbolView.getSymbol();
140 if (!symbols.contains(symbol)) { 157 if (!symbols.contains(symbol)) {
141 throw new IllegalArgumentException("Cannot query relation view %s: symbol %s is not in the model" 158 throw new IllegalArgumentException("Cannot query view %s: symbol %s is not in the model"
142 .formatted(relationView, symbol)); 159 .formatted(symbolView, symbol));
143 } 160 }
144 } 161 }
145 } 162 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
index 04c48c43..11a3c7fd 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/ViatraModelQueryStoreAdapterImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal; 6package tools.refinery.store.query.viatra.internal;
2 7
3import org.eclipse.viatra.query.runtime.api.IQuerySpecification; 8import org.eclipse.viatra.query.runtime.api.IQuerySpecification;
@@ -8,20 +13,20 @@ import tools.refinery.store.model.ModelStore;
8import tools.refinery.store.query.dnf.AnyQuery; 13import tools.refinery.store.query.dnf.AnyQuery;
9import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter; 14import tools.refinery.store.query.viatra.ViatraModelQueryStoreAdapter;
10import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher; 15import tools.refinery.store.query.viatra.internal.matcher.RawPatternMatcher;
11import tools.refinery.store.query.view.AnyRelationView; 16import tools.refinery.store.query.view.AnySymbolView;
12 17
13import java.util.*; 18import java.util.*;
14 19
15public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter { 20public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAdapter {
16 private final ModelStore store; 21 private final ModelStore store;
17 private final ViatraQueryEngineOptions engineOptions; 22 private final ViatraQueryEngineOptions engineOptions;
18 private final Map<AnyRelationView, IInputKey> inputKeys; 23 private final Map<AnySymbolView, IInputKey> inputKeys;
19 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications; 24 private final Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications;
20 private final Set<AnyQuery> vacuousQueries; 25 private final Set<AnyQuery> vacuousQueries;
21 private final Set<AnyQuery> allQueries; 26 private final Set<AnyQuery> allQueries;
22 27
23 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions, 28 ViatraModelQueryStoreAdapterImpl(ModelStore store, ViatraQueryEngineOptions engineOptions,
24 Map<AnyRelationView, IInputKey> inputKeys, 29 Map<AnySymbolView, IInputKey> inputKeys,
25 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications, 30 Map<AnyQuery, IQuerySpecification<RawPatternMatcher>> querySpecifications,
26 Set<AnyQuery> vacuousQueries) { 31 Set<AnyQuery> vacuousQueries) {
27 this.store = store; 32 this.store = store;
@@ -40,11 +45,11 @@ public class ViatraModelQueryStoreAdapterImpl implements ViatraModelQueryStoreAd
40 return store; 45 return store;
41 } 46 }
42 47
43 public Collection<AnyRelationView> getRelationViews() { 48 public Collection<AnySymbolView> getSymbolViews() {
44 return inputKeys.keySet(); 49 return inputKeys.keySet();
45 } 50 }
46 51
47 public Map<AnyRelationView, IInputKey> getInputKeys() { 52 public Map<AnySymbolView, IInputKey> getInputKeys() {
48 return inputKeys; 53 return inputKeys;
49 } 54 }
50 55
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
deleted file mode 100644
index e0bca9e0..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperator.java
+++ /dev/null
@@ -1,97 +0,0 @@
1package tools.refinery.store.query.viatra.internal.cardinality;
2
3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.BoundAggregator;
4import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
5import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
6import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
7import tools.refinery.store.representation.cardinality.UpperCardinalities;
8import tools.refinery.store.representation.cardinality.UpperCardinality;
9
10import java.util.stream.Stream;
11
12public class UpperCardinalitySumAggregationOperator implements IMultisetAggregationOperator<UpperCardinality,
13 UpperCardinalitySumAggregationOperator.Accumulator, UpperCardinality> {
14 public static final UpperCardinalitySumAggregationOperator INSTANCE = new UpperCardinalitySumAggregationOperator();
15
16 public static final BoundAggregator BOUND_AGGREGATOR = new BoundAggregator(INSTANCE, UpperCardinality.class,
17 UpperCardinality.class);
18
19 private UpperCardinalitySumAggregationOperator() {
20 // Singleton constructor.
21 }
22
23 @Override
24 public String getName() {
25 return "sum<UpperCardinality>";
26 }
27
28 @Override
29 public String getShortDescription() {
30 return "%s computes the sum of finite or unbounded upper cardinalities".formatted(getName());
31 }
32
33 @Override
34 public Accumulator createNeutral() {
35 return new Accumulator();
36 }
37
38 @Override
39 public boolean isNeutral(Accumulator result) {
40 return result.sumFiniteUpperBounds == 0 && result.countUnbounded == 0;
41 }
42
43 @Override
44 public Accumulator update(Accumulator oldResult, UpperCardinality updateValue, boolean isInsertion) {
45 if (updateValue instanceof FiniteUpperCardinality finiteUpperCardinality) {
46 int finiteUpperBound = finiteUpperCardinality.finiteUpperBound();
47 if (isInsertion) {
48 oldResult.sumFiniteUpperBounds += finiteUpperBound;
49 } else {
50 oldResult.sumFiniteUpperBounds -= finiteUpperBound;
51 }
52 } else if (updateValue instanceof UnboundedUpperCardinality) {
53 if (isInsertion) {
54 oldResult.countUnbounded += 1;
55 } else {
56 oldResult.countUnbounded -= 1;
57 }
58 } else {
59 throw new IllegalArgumentException("Unknown UpperCardinality: " + updateValue);
60 }
61 return oldResult;
62 }
63
64 @Override
65 public UpperCardinality getAggregate(Accumulator result) {
66 return result.countUnbounded > 0 ? UpperCardinalities.UNBOUNDED :
67 UpperCardinalities.valueOf(result.sumFiniteUpperBounds);
68 }
69
70 @Override
71 public UpperCardinality aggregateStream(Stream<UpperCardinality> stream) {
72 var result = stream.collect(this::createNeutral, (accumulator, value) -> update(accumulator, value, true),
73 (left, right) -> new Accumulator(left.sumFiniteUpperBounds + right.sumFiniteUpperBounds,
74 left.countUnbounded + right.countUnbounded));
75 return getAggregate(result);
76 }
77
78 @Override
79 public Accumulator clone(Accumulator original) {
80 return new Accumulator(original.sumFiniteUpperBounds, original.countUnbounded);
81 }
82
83 public static class Accumulator {
84 private int sumFiniteUpperBounds;
85
86 private int countUnbounded;
87
88 private Accumulator(int sumFiniteUpperBounds, int countUnbounded) {
89 this.sumFiniteUpperBounds = sumFiniteUpperBounds;
90 this.countUnbounded = countUnbounded;
91 }
92
93 private Accumulator() {
94 this(0, 0);
95 }
96 }
97}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java
index 2a24b67c..8cb199d2 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/DummyBaseIndexer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.context; 6package tools.refinery.store.query.viatra.internal.context;
2 7
3import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; 8import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
index 28bc69d0..7220f8ca 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalEngineContext.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.context; 6package tools.refinery.store.query.viatra.internal.context;
2 7
3import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex; 8import org.eclipse.viatra.query.runtime.api.scope.IBaseIndex;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
index d2c6beb4..211eacb4 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalQueryMetaContext.java
@@ -1,12 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.context; 6package tools.refinery.store.query.viatra.internal.context;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext; 8import org.eclipse.viatra.query.runtime.matchers.context.AbstractQueryMetaContext;
4import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; 9import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
5import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication; 10import org.eclipse.viatra.query.runtime.matchers.context.InputKeyImplication;
6import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey; 11import org.eclipse.viatra.query.runtime.matchers.context.common.JavaTransitiveInstancesKey;
7import tools.refinery.store.query.term.DataSort; 12import tools.refinery.store.query.viatra.internal.pquery.SymbolViewWrapper;
8import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; 13import tools.refinery.store.query.view.AnySymbolView;
9import tools.refinery.store.query.view.AnyRelationView;
10 14
11import java.util.*; 15import java.util.*;
12 16
@@ -14,9 +18,9 @@ import java.util.*;
14 * The meta context information for String scopes. 18 * The meta context information for String scopes.
15 */ 19 */
16public class RelationalQueryMetaContext extends AbstractQueryMetaContext { 20public class RelationalQueryMetaContext extends AbstractQueryMetaContext {
17 private final Map<AnyRelationView, IInputKey> inputKeys; 21 private final Map<AnySymbolView, IInputKey> inputKeys;
18 22
19 RelationalQueryMetaContext(Map<AnyRelationView, IInputKey> inputKeys) { 23 RelationalQueryMetaContext(Map<AnySymbolView, IInputKey> inputKeys) {
20 this.inputKeys = inputKeys; 24 this.inputKeys = inputKeys;
21 } 25 }
22 26
@@ -42,29 +46,29 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext {
42 if (implyingKey instanceof JavaTransitiveInstancesKey) { 46 if (implyingKey instanceof JavaTransitiveInstancesKey) {
43 return List.of(); 47 return List.of();
44 } 48 }
45 var relationView = checkKey(implyingKey); 49 var symbolView = checkKey(implyingKey);
46 var relationViewImplications = relationView.getImpliedRelationViews(); 50 var relationViewImplications = symbolView.getImpliedRelationViews();
47 var inputKeyImplications = new HashSet<InputKeyImplication>(relationViewImplications.size()); 51 var inputKeyImplications = new HashSet<InputKeyImplication>(relationViewImplications.size());
48 for (var relationViewImplication : relationViewImplications) { 52 for (var relationViewImplication : relationViewImplications) {
49 if (!relationView.equals(relationViewImplication.implyingRelationView())) { 53 if (!symbolView.equals(relationViewImplication.implyingView())) {
50 throw new IllegalArgumentException("Relation view %s returned unrelated implication %s".formatted( 54 throw new IllegalArgumentException("Relation view %s returned unrelated implication %s".formatted(
51 relationView, relationViewImplication)); 55 symbolView, relationViewImplication));
52 } 56 }
53 var impliedInputKey = inputKeys.get(relationViewImplication.impliedRelationView()); 57 var impliedInputKey = inputKeys.get(relationViewImplication.impliedView());
54 // Ignore implications not relevant for any queries included in the model. 58 // Ignore implications not relevant for any queries included in the model.
55 if (impliedInputKey != null) { 59 if (impliedInputKey != null) {
56 inputKeyImplications.add(new InputKeyImplication(implyingKey, impliedInputKey, 60 inputKeyImplications.add(new InputKeyImplication(implyingKey, impliedInputKey,
57 relationViewImplication.impliedIndices())); 61 relationViewImplication.impliedIndices()));
58 } 62 }
59 } 63 }
60 var sorts = relationView.getSorts(); 64 var parameters = symbolView.getParameters();
61 int arity = relationView.arity(); 65 int arity = symbolView.arity();
62 for (int i = 0; i < arity; i++) { 66 for (int i = 0; i < arity; i++) {
63 var sort = sorts.get(i); 67 var parameter = parameters.get(i);
64 if (sort instanceof DataSort<?> dataSort) { 68 var parameterType = parameter.tryGetType();
65 var javaTransitiveInstancesKey = new JavaTransitiveInstancesKey(dataSort.type()); 69 if (parameterType.isPresent()) {
66 var javaImplication = new InputKeyImplication(implyingKey, javaTransitiveInstancesKey, 70 var javaTransitiveInstancesKey = new JavaTransitiveInstancesKey(parameterType.get());
67 List.of(i)); 71 var javaImplication = new InputKeyImplication(implyingKey, javaTransitiveInstancesKey, List.of(i));
68 inputKeyImplications.add(javaImplication); 72 inputKeyImplications.add(javaImplication);
69 } 73 }
70 } 74 }
@@ -94,20 +98,20 @@ public class RelationalQueryMetaContext extends AbstractQueryMetaContext {
94 return flattened; 98 return flattened;
95 } 99 }
96 100
97 private static void checkValidIndices(AnyRelationView relationView, Collection<Integer> indices) { 101 private static void checkValidIndices(AnySymbolView relationView, Collection<Integer> indices) {
98 indices.stream().filter(relationView::invalidIndex).findAny().ifPresent(i -> { 102 indices.stream().filter(relationView::invalidIndex).findAny().ifPresent(i -> {
99 throw new IllegalArgumentException("Index %d is invalid for %s".formatted(i, relationView)); 103 throw new IllegalArgumentException("Index %d is invalid for %s".formatted(i, relationView));
100 }); 104 });
101 } 105 }
102 106
103 public AnyRelationView checkKey(IInputKey key) { 107 public AnySymbolView checkKey(IInputKey key) {
104 if (!(key instanceof RelationViewWrapper wrapper)) { 108 if (!(key instanceof SymbolViewWrapper wrapper)) {
105 throw new IllegalArgumentException("The input key %s is not a valid input key".formatted(key)); 109 throw new IllegalArgumentException("The input key %s is not a valid input key".formatted(key));
106 } 110 }
107 var relationView = wrapper.getWrappedKey(); 111 var symbolView = wrapper.getWrappedKey();
108 if (!inputKeys.containsKey(relationView)) { 112 if (!inputKeys.containsKey(symbolView)) {
109 throw new IllegalArgumentException("The input key %s is not present in the model".formatted(key)); 113 throw new IllegalArgumentException("The input key %s is not present in the model".formatted(key));
110 } 114 }
111 return relationView; 115 return symbolView;
112 } 116 }
113} 117}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
index 854817b1..0f2daca8 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/context/RelationalRuntimeContext.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.context; 6package tools.refinery.store.query.viatra.internal.context;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.*; 8import org.eclipse.viatra.query.runtime.matchers.context.*;
@@ -8,9 +13,9 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
8import org.eclipse.viatra.query.runtime.matchers.util.Accuracy; 13import org.eclipse.viatra.query.runtime.matchers.util.Accuracy;
9import tools.refinery.store.model.Model; 14import tools.refinery.store.model.Model;
10import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 15import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
11import tools.refinery.store.query.viatra.internal.pquery.RelationViewWrapper; 16import tools.refinery.store.query.viatra.internal.pquery.SymbolViewWrapper;
12import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener; 17import tools.refinery.store.query.viatra.internal.update.ModelUpdateListener;
13import tools.refinery.store.query.view.AnyRelationView; 18import tools.refinery.store.query.view.AnySymbolView;
14 19
15import java.lang.reflect.InvocationTargetException; 20import java.lang.reflect.InvocationTargetException;
16import java.util.Iterator; 21import java.util.Iterator;
@@ -54,9 +59,9 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
54 59
55 @Override 60 @Override
56 public boolean isIndexed(IInputKey key, IndexingService service) { 61 public boolean isIndexed(IInputKey key, IndexingService service) {
57 if (key instanceof RelationViewWrapper wrapper) { 62 if (key instanceof SymbolViewWrapper wrapper) {
58 var relationalKey = wrapper.getWrappedKey(); 63 var symbolViewKey = wrapper.getWrappedKey();
59 return this.modelUpdateListener.containsRelationView(relationalKey); 64 return this.modelUpdateListener.containsSymbolView(symbolViewKey);
60 } else { 65 } else {
61 return false; 66 return false;
62 } 67 }
@@ -69,13 +74,13 @@ public class RelationalRuntimeContext implements IQueryRuntimeContext {
69 } 74 }
70 } 75 }
71 76
72 AnyRelationView checkKey(IInputKey key) { 77 AnySymbolView checkKey(IInputKey key) {
73 if (key instanceof RelationViewWrapper wrappedKey) { 78 if (key instanceof SymbolViewWrapper wrappedKey) {
74 var relationViewKey = wrappedKey.getWrappedKey(); 79 var symbolViewKey = wrappedKey.getWrappedKey();
75 if (modelUpdateListener.containsRelationView(relationViewKey)) { 80 if (modelUpdateListener.containsSymbolView(symbolViewKey)) {
76 return relationViewKey; 81 return symbolViewKey;
77 } else { 82 } else {
78 throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(relationViewKey)); 83 throw new IllegalStateException("Query is asking for non-indexed key %s".formatted(symbolViewKey));
79 } 84 }
80 } else { 85 } else {
81 throw new IllegalStateException("Query is asking for non-relational key"); 86 throw new IllegalStateException("Query is asking for non-relational key");
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java
index 2d3dd5a7..37177cbf 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendOperationExecutor.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro 2 * Copyright (c) 2010-2013, Zoltan Ujhelyi, Akos Horvath, Istvan Rath and Daniel Varro
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 5 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java
index aaaece80..9d48c785 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/ExtendPositivePatternCall.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs 2 * Copyright (c) 2010-2016, Grill Balázs, IncQueryLabs
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 5 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java
index 84cab142..cc906f22 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/FlatCostFunction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.localsearch; 6package tools.refinery.store.query.viatra.internal.localsearch;
2 7
3import org.eclipse.viatra.query.runtime.localsearch.planner.cost.IConstraintEvaluationContext; 8import org.eclipse.viatra.query.runtime.localsearch.planner.cost.IConstraintEvaluationContext;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java
index 64653658..96ac4a72 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/GenericTypeExtend.java
@@ -1,5 +1,6 @@
1/******************************************************************************* 1/*******************************************************************************
2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd. 2 * Copyright (c) 2010-2017, Zoltan Ujhelyi, IncQuery Labs Ltd.
3 * Copyright (c) 2023 The Refinery Authors <https://refinery.tools/>
3 * This program and the accompanying materials are made available under the 4 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v. 2.0 which is available at 5 * terms of the Eclipse Public License v. 2.0 which is available at
5 * http://www.eclipse.org/legal/epl-v20.html. 6 * http://www.eclipse.org/legal/epl-v20.html.
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java
index 156eb313..0c77f587 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchBackendFactory.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.localsearch; 6package tools.refinery.store.query.viatra.internal.localsearch;
2 7
3import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; 8import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java
index be2a38ca..da37be14 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalLocalSearchResultProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.localsearch; 6package tools.refinery.store.query.viatra.internal.localsearch;
2 7
3import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider; 8import org.eclipse.viatra.query.runtime.localsearch.matcher.integration.AbstractLocalSearchResultProvider;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java
index b6832b39..f76ef486 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/localsearch/RelationalOperationCompiler.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.localsearch; 6package tools.refinery.store.query.viatra.internal.localsearch;
2 7
3import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtendSingleValue; 8import org.eclipse.viatra.query.runtime.localsearch.operations.generic.GenericTypeExtendSingleValue;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
index 4daa14a1..47efb2aa 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalCursor.java
@@ -1,17 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
4import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer; 8import org.eclipse.viatra.query.runtime.rete.index.IterableIndexer;
5import tools.refinery.store.map.Cursor; 9import tools.refinery.store.map.Cursor;
6import tools.refinery.store.tuple.TupleLike; 10import tools.refinery.store.tuple.Tuple;
7 11
8import java.util.Iterator; 12import java.util.Iterator;
9 13
10class FunctionalCursor<T> implements Cursor<TupleLike, T> { 14class FunctionalCursor<T> implements Cursor<Tuple, T> {
11 private final IterableIndexer indexer; 15 private final IterableIndexer indexer;
12 private final Iterator<Tuple> iterator; 16 private final Iterator<org.eclipse.viatra.query.runtime.matchers.tuple.Tuple> iterator;
13 private boolean terminated; 17 private boolean terminated;
14 private TupleLike key; 18 private Tuple key;
15 private T value; 19 private T value;
16 20
17 public FunctionalCursor(IterableIndexer indexer) { 21 public FunctionalCursor(IterableIndexer indexer) {
@@ -20,7 +24,7 @@ class FunctionalCursor<T> implements Cursor<TupleLike, T> {
20 } 24 }
21 25
22 @Override 26 @Override
23 public TupleLike getKey() { 27 public Tuple getKey() {
24 return key; 28 return key;
25 } 29 }
26 30
@@ -38,7 +42,7 @@ class FunctionalCursor<T> implements Cursor<TupleLike, T> {
38 public boolean move() { 42 public boolean move() {
39 if (!terminated && iterator.hasNext()) { 43 if (!terminated && iterator.hasNext()) {
40 var match = iterator.next(); 44 var match = iterator.next();
41 key = new ViatraTupleLike(match); 45 key = MatcherUtils.toRefineryTuple(match);
42 value = MatcherUtils.getSingleValue(indexer.get(match)); 46 value = MatcherUtils.getSingleValue(indexer.get(match));
43 return true; 47 return true;
44 } 48 }
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
index 6aa45af2..f018288b 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/FunctionalViatraMatcher.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; 8import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider;
@@ -11,7 +16,7 @@ import tools.refinery.store.query.ResultSet;
11import tools.refinery.store.query.dnf.FunctionalQuery; 16import tools.refinery.store.query.dnf.FunctionalQuery;
12import tools.refinery.store.query.dnf.Query; 17import tools.refinery.store.query.dnf.Query;
13import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 18import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
14import tools.refinery.store.tuple.TupleLike; 19import tools.refinery.store.tuple.Tuple;
15 20
16/** 21/**
17 * Directly access the tuples inside a VIATRA pattern matcher.<p> 22 * Directly access the tuples inside a VIATRA pattern matcher.<p>
@@ -63,7 +68,7 @@ public class FunctionalViatraMatcher<T> implements ResultSet<T> {
63 } 68 }
64 69
65 @Override 70 @Override
66 public T get(TupleLike parameters) { 71 public T get(Tuple parameters) {
67 var tuple = MatcherUtils.toViatraTuple(parameters); 72 var tuple = MatcherUtils.toViatraTuple(parameters);
68 if (omitOutputIndexer == null) { 73 if (omitOutputIndexer == null) {
69 return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator()); 74 return MatcherUtils.getSingleValue(backend.getAllMatches(omitOutputMask, tuple).iterator());
@@ -73,7 +78,7 @@ public class FunctionalViatraMatcher<T> implements ResultSet<T> {
73 } 78 }
74 79
75 @Override 80 @Override
76 public Cursor<TupleLike, T> getAll() { 81 public Cursor<Tuple, T> getAll() {
77 if (omitOutputIndexer == null) { 82 if (omitOutputIndexer == null) {
78 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); 83 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf());
79 return new UnsafeFunctionalCursor<>(allMatches.iterator()); 84 return new UnsafeFunctionalCursor<>(allMatches.iterator());
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java
index 55eb8c44..15f00b2d 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/IndexerUtils.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask; 8import org.eclipse.viatra.query.runtime.matchers.tuple.TupleMask;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
index 5d4be95d..1c784492 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtils.java
@@ -1,10 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 8import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; 9import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
5import org.jetbrains.annotations.Nullable; 10import org.jetbrains.annotations.Nullable;
6import tools.refinery.store.tuple.Tuple; 11import tools.refinery.store.tuple.*;
7import tools.refinery.store.tuple.TupleLike;
8 12
9import java.util.Iterator; 13import java.util.Iterator;
10 14
@@ -13,25 +17,80 @@ final class MatcherUtils {
13 throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); 17 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
14 } 18 }
15 19
16 public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(TupleLike tuple) { 20 public static org.eclipse.viatra.query.runtime.matchers.tuple.Tuple toViatraTuple(Tuple refineryTuple) {
17 if (tuple instanceof ViatraTupleLike viatraTupleLike) { 21 if (refineryTuple instanceof Tuple0) {
18 return viatraTupleLike.wrappedTuple().toImmutable(); 22 return Tuples.staticArityFlatTupleOf();
23 } else if (refineryTuple instanceof Tuple1) {
24 return Tuples.staticArityFlatTupleOf(refineryTuple);
25 } else if (refineryTuple instanceof Tuple2 tuple2) {
26 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple2.value0()), Tuple.of(tuple2.value1()));
27 } else if (refineryTuple instanceof Tuple3 tuple3) {
28 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple3.value0()), Tuple.of(tuple3.value1()),
29 Tuple.of(tuple3.value2()));
30 } else if (refineryTuple instanceof Tuple4 tuple4) {
31 return Tuples.staticArityFlatTupleOf(Tuple.of(tuple4.value0()), Tuple.of(tuple4.value1()),
32 Tuple.of(tuple4.value2()), Tuple.of(tuple4.value3()));
33 } else {
34 int arity = refineryTuple.getSize();
35 var values = new Object[arity];
36 for (int i = 0; i < arity; i++) {
37 values[i] = Tuple.of(refineryTuple.get(i));
38 }
39 return Tuples.flatTupleOf(values);
19 } 40 }
20 int size = tuple.getSize(); 41 }
21 var array = new Object[size]; 42
22 for (int i = 0; i < size; i++) { 43 public static Tuple toRefineryTuple(ITuple viatraTuple) {
23 var value = tuple.get(i); 44 int arity = viatraTuple.getSize();
24 array[i] = Tuple.of(value); 45 if (arity == 1) {
46 return getWrapper(viatraTuple, 0);
25 } 47 }
26 return Tuples.flatTupleOf(array); 48 return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize());
49 }
50
51 public static Tuple keyToRefineryTuple(ITuple viatraTuple) {
52 return prefixToRefineryTuple(viatraTuple, viatraTuple.getSize() - 1);
27 } 53 }
28 54
55 private static Tuple prefixToRefineryTuple(ITuple viatraTuple, int targetArity) {
56 if (targetArity < 0) {
57 throw new IllegalArgumentException("Requested negative prefix %d of %s"
58 .formatted(targetArity, viatraTuple));
59 }
60 return switch (targetArity) {
61 case 0 -> Tuple.of();
62 case 1 -> Tuple.of(unwrap(viatraTuple, 0));
63 case 2 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1));
64 case 3 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2));
65 case 4 -> Tuple.of(unwrap(viatraTuple, 0), unwrap(viatraTuple, 1), unwrap(viatraTuple, 2),
66 unwrap(viatraTuple, 3));
67 default -> {
68 var entries = new int[targetArity];
69 for (int i = 0; i < targetArity; i++) {
70 entries[i] = unwrap(viatraTuple, i);
71 }
72 yield Tuple.of(entries);
73 }
74 };
75 }
76
77 private static Tuple1 getWrapper(ITuple viatraTuple, int index) {
78 if (!((viatraTuple.get(index)) instanceof Tuple1 wrappedObjectId)) {
79 throw new IllegalArgumentException("Element %d of tuple %s is not an object id"
80 .formatted(index, viatraTuple));
81 }
82 return wrappedObjectId;
83 }
84
85 private static int unwrap(ITuple viatraTuple, int index) {
86 return getWrapper(viatraTuple, index).value0();
87 }
29 88
30 public static <T> T getSingleValue(@Nullable Iterable<? extends ITuple> tuples) { 89 public static <T> T getSingleValue(@Nullable Iterable<? extends ITuple> viatraTuples) {
31 if (tuples == null) { 90 if (viatraTuples == null) {
32 return null; 91 return null;
33 } 92 }
34 return getSingleValue(tuples.iterator()); 93 return getSingleValue(viatraTuples.iterator());
35 } 94 }
36 95
37 public static <T> T getSingleValue(Iterator<? extends ITuple> iterator) { 96 public static <T> T getSingleValue(Iterator<? extends ITuple> iterator) {
@@ -42,7 +101,7 @@ final class MatcherUtils {
42 @SuppressWarnings("unchecked") 101 @SuppressWarnings("unchecked")
43 var result = (T) match.get(match.getSize() - 1); 102 var result = (T) match.get(match.getSize() - 1);
44 if (iterator.hasNext()) { 103 if (iterator.hasNext()) {
45 var input = new OmitOutputViatraTupleLike(match); 104 var input = keyToRefineryTuple(match);
46 throw new IllegalStateException("Query is not functional for input tuple: " + input); 105 throw new IllegalStateException("Query is not functional for input tuple: " + input);
47 } 106 }
48 return result; 107 return result;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java
deleted file mode 100644
index bd9301ba..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/OmitOutputViatraTupleLike.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.query.viatra.internal.matcher;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.tuple.Tuple1;
5import tools.refinery.store.tuple.TupleLike;
6
7record OmitOutputViatraTupleLike(ITuple wrappedTuple) implements TupleLike {
8 @Override
9 public int getSize() {
10 return wrappedTuple.getSize() - 1;
11 }
12
13 @Override
14 public int get(int element) {
15 var wrappedValue = (Tuple1) wrappedTuple.get(element);
16 return wrappedValue.value0();
17 }
18
19 @Override
20 public String toString() {
21 return TupleLike.toString(this);
22 }
23}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java
index b3d05967..5b82c4b7 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RawPatternMatcher.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher; 8import org.eclipse.viatra.query.runtime.api.GenericPatternMatcher;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
index c2dcc565..1dc8f5db 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalCursor.java
@@ -1,22 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 8import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.map.Cursor; 9import tools.refinery.store.map.Cursor;
5import tools.refinery.store.tuple.TupleLike; 10import tools.refinery.store.tuple.Tuple;
6 11
7import java.util.Iterator; 12import java.util.Iterator;
8 13
9class RelationalCursor implements Cursor<TupleLike, Boolean> { 14class RelationalCursor implements Cursor<Tuple, Boolean> {
10 private final Iterator<? extends ITuple> tuplesIterator; 15 private final Iterator<? extends ITuple> tuplesIterator;
11 private boolean terminated; 16 private boolean terminated;
12 private TupleLike key; 17 private Tuple key;
13 18
14 public RelationalCursor(Iterator<? extends ITuple> tuplesIterator) { 19 public RelationalCursor(Iterator<? extends ITuple> tuplesIterator) {
15 this.tuplesIterator = tuplesIterator; 20 this.tuplesIterator = tuplesIterator;
16 } 21 }
17 22
18 @Override 23 @Override
19 public TupleLike getKey() { 24 public Tuple getKey() {
20 return key; 25 return key;
21 } 26 }
22 27
@@ -33,7 +38,7 @@ class RelationalCursor implements Cursor<TupleLike, Boolean> {
33 @Override 38 @Override
34 public boolean move() { 39 public boolean move() {
35 if (!terminated && tuplesIterator.hasNext()) { 40 if (!terminated && tuplesIterator.hasNext()) {
36 key = new ViatraTupleLike(tuplesIterator.next()); 41 key = MatcherUtils.toRefineryTuple(tuplesIterator.next());
37 return true; 42 return true;
38 } 43 }
39 terminated = true; 44 terminated = true;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
index b9bc3f1e..d1476920 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/RelationalViatraMatcher.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider; 8import org.eclipse.viatra.query.runtime.matchers.backend.IQueryResultProvider;
@@ -12,7 +17,7 @@ import tools.refinery.store.query.ResultSet;
12import tools.refinery.store.query.dnf.Query; 17import tools.refinery.store.query.dnf.Query;
13import tools.refinery.store.query.dnf.RelationalQuery; 18import tools.refinery.store.query.dnf.RelationalQuery;
14import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 19import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
15import tools.refinery.store.tuple.TupleLike; 20import tools.refinery.store.tuple.Tuple;
16 21
17/** 22/**
18 * Directly access the tuples inside a VIATRA pattern matcher.<p> 23 * Directly access the tuples inside a VIATRA pattern matcher.<p>
@@ -58,7 +63,7 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
58 } 63 }
59 64
60 @Override 65 @Override
61 public Boolean get(TupleLike parameters) { 66 public Boolean get(Tuple parameters) {
62 var tuple = MatcherUtils.toViatraTuple(parameters); 67 var tuple = MatcherUtils.toViatraTuple(parameters);
63 if (emptyMaskIndexer == null) { 68 if (emptyMaskIndexer == null) {
64 return backend.hasMatch(identityMask, tuple); 69 return backend.hasMatch(identityMask, tuple);
@@ -68,7 +73,7 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
68 } 73 }
69 74
70 @Override 75 @Override
71 public Cursor<TupleLike, Boolean> getAll() { 76 public Cursor<Tuple, Boolean> getAll() {
72 if (emptyMaskIndexer == null) { 77 if (emptyMaskIndexer == null) {
73 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf()); 78 var allMatches = backend.getAllMatches(emptyMask, Tuples.staticArityFlatTupleOf());
74 return new RelationalCursor(allMatches.iterator()); 79 return new RelationalCursor(allMatches.iterator());
@@ -85,5 +90,4 @@ public class RelationalViatraMatcher implements ResultSet<Boolean> {
85 var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf()); 90 var matches = emptyMaskIndexer.get(Tuples.staticArityFlatTupleOf());
86 return matches == null ? 0 : matches.size(); 91 return matches == null ? 0 : matches.size();
87 } 92 }
88
89} 93}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
index 6c53fff1..4a41d724 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/UnsafeFunctionalCursor.java
@@ -1,8 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.matcher; 6package tools.refinery.store.query.viatra.internal.matcher;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 8import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.map.Cursor; 9import tools.refinery.store.map.Cursor;
5import tools.refinery.store.tuple.TupleLike; 10import tools.refinery.store.tuple.Tuple;
6 11
7import java.util.Iterator; 12import java.util.Iterator;
8 13
@@ -11,10 +16,10 @@ import java.util.Iterator;
11 * functional dependency of the output on the inputs is obeyed. 16 * functional dependency of the output on the inputs is obeyed.
12 * @param <T> The output type. 17 * @param <T> The output type.
13 */ 18 */
14class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> { 19class UnsafeFunctionalCursor<T> implements Cursor<Tuple, T> {
15 private final Iterator<? extends ITuple> tuplesIterator; 20 private final Iterator<? extends ITuple> tuplesIterator;
16 private boolean terminated; 21 private boolean terminated;
17 private TupleLike key; 22 private Tuple key;
18 private T value; 23 private T value;
19 24
20 public UnsafeFunctionalCursor(Iterator<? extends ITuple> tuplesIterator) { 25 public UnsafeFunctionalCursor(Iterator<? extends ITuple> tuplesIterator) {
@@ -22,7 +27,7 @@ class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> {
22 } 27 }
23 28
24 @Override 29 @Override
25 public TupleLike getKey() { 30 public Tuple getKey() {
26 return key; 31 return key;
27 } 32 }
28 33
@@ -40,7 +45,7 @@ class UnsafeFunctionalCursor<T> implements Cursor<TupleLike, T> {
40 public boolean move() { 45 public boolean move() {
41 if (!terminated && tuplesIterator.hasNext()) { 46 if (!terminated && tuplesIterator.hasNext()) {
42 var match = tuplesIterator.next(); 47 var match = tuplesIterator.next();
43 key = new OmitOutputViatraTupleLike(match); 48 key = MatcherUtils.keyToRefineryTuple(match);
44 @SuppressWarnings("unchecked") 49 @SuppressWarnings("unchecked")
45 var typedValue = (T) match.get(match.getSize() - 1); 50 var typedValue = (T) match.get(match.getSize() - 1);
46 value = typedValue; 51 value = typedValue;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java
deleted file mode 100644
index 76a3e40b..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/matcher/ViatraTupleLike.java
+++ /dev/null
@@ -1,23 +0,0 @@
1package tools.refinery.store.query.viatra.internal.matcher;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
4import tools.refinery.store.tuple.Tuple1;
5import tools.refinery.store.tuple.TupleLike;
6
7record ViatraTupleLike(ITuple wrappedTuple) implements TupleLike {
8 @Override
9 public int getSize() {
10 return wrappedTuple.getSize();
11 }
12
13 @Override
14 public int get(int element) {
15 var wrappedValue = (Tuple1) wrappedTuple.get(element);
16 return wrappedValue.value0();
17 }
18
19 @Override
20 public String toString() {
21 return TupleLike.toString(this);
22 }
23}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java
index a80b0f90..cf127291 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/AssumptionEvaluator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; 8import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java
index 7afeb977..5b0ea61d 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/Dnf2PQuery.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory; 8import org.eclipse.viatra.query.runtime.matchers.backend.IQueryBackendFactory;
@@ -14,17 +19,19 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.Consta
14import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall; 19import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.PositivePatternCall;
15import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint; 20import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeConstraint;
16import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; 21import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter;
22import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameterDirection;
17import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; 23import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery;
18import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple; 24import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
19import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; 25import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
20import tools.refinery.store.query.dnf.Dnf; 26import tools.refinery.store.query.dnf.Dnf;
21import tools.refinery.store.query.dnf.DnfClause; 27import tools.refinery.store.query.dnf.DnfClause;
28import tools.refinery.store.query.dnf.SymbolicParameter;
22import tools.refinery.store.query.literal.*; 29import tools.refinery.store.query.literal.*;
23import tools.refinery.store.query.term.ConstantTerm; 30import tools.refinery.store.query.term.ConstantTerm;
24import tools.refinery.store.query.term.StatefulAggregator; 31import tools.refinery.store.query.term.StatefulAggregator;
25import tools.refinery.store.query.term.StatelessAggregator; 32import tools.refinery.store.query.term.StatelessAggregator;
26import tools.refinery.store.query.term.Variable; 33import tools.refinery.store.query.term.Variable;
27import tools.refinery.store.query.view.AnyRelationView; 34import tools.refinery.store.query.view.AnySymbolView;
28import tools.refinery.store.util.CycleDetectingMapper; 35import tools.refinery.store.util.CycleDetectingMapper;
29 36
30import java.util.*; 37import java.util.*;
@@ -48,8 +55,8 @@ public class Dnf2PQuery {
48 return mapper.map(dnfQuery); 55 return mapper.map(dnfQuery);
49 } 56 }
50 57
51 public Map<AnyRelationView, IInputKey> getRelationViews() { 58 public Map<AnySymbolView, IInputKey> getSymbolViews() {
52 return wrapperFactory.getRelationViews(); 59 return wrapperFactory.getSymbolViews();
53 } 60 }
54 61
55 public void hint(Dnf dnf, QueryEvaluationHint hint) { 62 public void hint(Dnf dnf, QueryEvaluationHint hint) {
@@ -77,15 +84,19 @@ public class Dnf2PQuery {
77 var pQuery = new RawPQuery(dnfQuery.getUniqueName()); 84 var pQuery = new RawPQuery(dnfQuery.getUniqueName());
78 pQuery.setEvaluationHints(consumeHint(dnfQuery)); 85 pQuery.setEvaluationHints(consumeHint(dnfQuery));
79 86
80 Map<Variable, PParameter> parameters = new HashMap<>(); 87 Map<SymbolicParameter, PParameter> parameters = new HashMap<>();
81 for (Variable variable : dnfQuery.getParameters()) {
82 parameters.put(variable, new PParameter(variable.getUniqueName()));
83 }
84
85 List<PParameter> parameterList = new ArrayList<>(); 88 List<PParameter> parameterList = new ArrayList<>();
86 for (var param : dnfQuery.getParameters()) { 89 for (var parameter : dnfQuery.getSymbolicParameters()) {
87 parameterList.add(parameters.get(param)); 90 var direction = switch (parameter.getDirection()) {
91 case OUT -> parameter.isUnifiable() ? PParameterDirection.INOUT : PParameterDirection.OUT;
92 case IN -> throw new IllegalArgumentException("Query %s with input parameter %s is not supported"
93 .formatted(dnfQuery, parameter.getVariable()));
94 };
95 var pParameter = new PParameter(parameter.getVariable().getUniqueName(), null, null, direction);
96 parameters.put(parameter, pParameter);
97 parameterList.add(pParameter);
88 } 98 }
99
89 pQuery.setParameters(parameterList); 100 pQuery.setParameters(parameterList);
90 101
91 for (var functionalDependency : dnfQuery.getFunctionalDependencies()) { 102 for (var functionalDependency : dnfQuery.getFunctionalDependencies()) {
@@ -105,15 +116,15 @@ public class Dnf2PQuery {
105 synchronized (P_CONSTRAINT_LOCK) { 116 synchronized (P_CONSTRAINT_LOCK) {
106 for (DnfClause clause : dnfQuery.getClauses()) { 117 for (DnfClause clause : dnfQuery.getClauses()) {
107 PBody body = new PBody(pQuery); 118 PBody body = new PBody(pQuery);
108 List<ExportedParameter> symbolicParameters = new ArrayList<>(); 119 List<ExportedParameter> parameterExports = new ArrayList<>();
109 for (var param : dnfQuery.getParameters()) { 120 for (var parameter : dnfQuery.getSymbolicParameters()) {
110 PVariable pVar = body.getOrCreateVariableByName(param.getUniqueName()); 121 PVariable pVar = body.getOrCreateVariableByName(parameter.getVariable().getUniqueName());
111 symbolicParameters.add(new ExportedParameter(body, pVar, parameters.get(param))); 122 parameterExports.add(new ExportedParameter(body, pVar, parameters.get(parameter)));
112 } 123 }
113 body.setSymbolicParameters(symbolicParameters); 124 body.setSymbolicParameters(parameterExports);
114 pQuery.addBody(body); 125 pQuery.addBody(body);
115 for (Literal literal : clause.literals()) { 126 for (Literal literal : clause.literals()) {
116 translateLiteral(literal, clause, body); 127 translateLiteral(literal, body);
117 } 128 }
118 } 129 }
119 } 130 }
@@ -121,11 +132,11 @@ public class Dnf2PQuery {
121 return pQuery; 132 return pQuery;
122 } 133 }
123 134
124 private void translateLiteral(Literal literal, DnfClause clause, PBody body) { 135 private void translateLiteral(Literal literal, PBody body) {
125 if (literal instanceof EquivalenceLiteral equivalenceLiteral) { 136 if (literal instanceof EquivalenceLiteral equivalenceLiteral) {
126 translateEquivalenceLiteral(equivalenceLiteral, body); 137 translateEquivalenceLiteral(equivalenceLiteral, body);
127 } else if (literal instanceof CallLiteral callLiteral) { 138 } else if (literal instanceof CallLiteral callLiteral) {
128 translateCallLiteral(callLiteral, clause, body); 139 translateCallLiteral(callLiteral, body);
129 } else if (literal instanceof ConstantLiteral constantLiteral) { 140 } else if (literal instanceof ConstantLiteral constantLiteral) {
130 translateConstantLiteral(constantLiteral, body); 141 translateConstantLiteral(constantLiteral, body);
131 } else if (literal instanceof AssignLiteral<?> assignLiteral) { 142 } else if (literal instanceof AssignLiteral<?> assignLiteral) {
@@ -133,9 +144,9 @@ public class Dnf2PQuery {
133 } else if (literal instanceof AssumeLiteral assumeLiteral) { 144 } else if (literal instanceof AssumeLiteral assumeLiteral) {
134 translateAssumeLiteral(assumeLiteral, body); 145 translateAssumeLiteral(assumeLiteral, body);
135 } else if (literal instanceof CountLiteral countLiteral) { 146 } else if (literal instanceof CountLiteral countLiteral) {
136 translateCountLiteral(countLiteral, clause, body); 147 translateCountLiteral(countLiteral, body);
137 } else if (literal instanceof AggregationLiteral<?, ?> aggregationLiteral) { 148 } else if (literal instanceof AggregationLiteral<?, ?> aggregationLiteral) {
138 translateAggregationLiteral(aggregationLiteral, clause, body); 149 translateAggregationLiteral(aggregationLiteral, body);
139 } else { 150 } else {
140 throw new IllegalArgumentException("Unknown literal: " + literal.toString()); 151 throw new IllegalArgumentException("Unknown literal: " + literal.toString());
141 } 152 }
@@ -151,7 +162,7 @@ public class Dnf2PQuery {
151 } 162 }
152 } 163 }
153 164
154 private void translateCallLiteral(CallLiteral callLiteral, DnfClause clause, PBody body) { 165 private void translateCallLiteral(CallLiteral callLiteral, PBody body) {
155 var polarity = callLiteral.getPolarity(); 166 var polarity = callLiteral.getPolarity();
156 switch (polarity) { 167 switch (polarity) {
157 case POSITIVE -> { 168 case POSITIVE -> {
@@ -160,8 +171,8 @@ public class Dnf2PQuery {
160 if (constraint instanceof Dnf dnf) { 171 if (constraint instanceof Dnf dnf) {
161 var pattern = translate(dnf); 172 var pattern = translate(dnf);
162 new PositivePatternCall(body, substitution, pattern); 173 new PositivePatternCall(body, substitution, pattern);
163 } else if (constraint instanceof AnyRelationView relationView) { 174 } else if (constraint instanceof AnySymbolView symbolView) {
164 var inputKey = wrapperFactory.getInputKey(relationView); 175 var inputKey = wrapperFactory.getInputKey(symbolView);
165 new TypeConstraint(body, substitution, inputKey); 176 new TypeConstraint(body, substitution, inputKey);
166 } else { 177 } else {
167 throw new IllegalArgumentException("Unknown Constraint: " + constraint); 178 throw new IllegalArgumentException("Unknown Constraint: " + constraint);
@@ -173,15 +184,15 @@ public class Dnf2PQuery {
173 PQuery pattern; 184 PQuery pattern;
174 if (constraint instanceof Dnf dnf) { 185 if (constraint instanceof Dnf dnf) {
175 pattern = translate(dnf); 186 pattern = translate(dnf);
176 } else if (constraint instanceof AnyRelationView relationView) { 187 } else if (constraint instanceof AnySymbolView symbolView) {
177 pattern = wrapperFactory.wrapRelationViewIdentityArguments(relationView); 188 pattern = wrapperFactory.wrapSymbolViewIdentityArguments(symbolView);
178 } else { 189 } else {
179 throw new IllegalArgumentException("Unknown Constraint: " + constraint); 190 throw new IllegalArgumentException("Unknown Constraint: " + constraint);
180 } 191 }
181 new BinaryTransitiveClosure(body, substitution, pattern); 192 new BinaryTransitiveClosure(body, substitution, pattern);
182 } 193 }
183 case NEGATIVE -> { 194 case NEGATIVE -> {
184 var wrappedCall = wrapperFactory.maybeWrapConstraint(callLiteral, clause); 195 var wrappedCall = wrapperFactory.maybeWrapConstraint(callLiteral);
185 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); 196 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body);
186 var pattern = wrappedCall.pattern(); 197 var pattern = wrappedCall.pattern();
187 new NegativePatternCall(body, substitution, pattern); 198 new NegativePatternCall(body, substitution, pattern);
@@ -221,15 +232,14 @@ public class Dnf2PQuery {
221 new ExpressionEvaluation(body, evaluator, null); 232 new ExpressionEvaluation(body, evaluator, null);
222 } 233 }
223 234
224 private void translateCountLiteral(CountLiteral countLiteral, DnfClause clause, PBody body) { 235 private void translateCountLiteral(CountLiteral countLiteral, PBody body) {
225 var wrappedCall = wrapperFactory.maybeWrapConstraint(countLiteral, clause); 236 var wrappedCall = wrapperFactory.maybeWrapConstraint(countLiteral);
226 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); 237 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body);
227 var resultVariable = body.getOrCreateVariableByName(countLiteral.getResultVariable().getUniqueName()); 238 var resultVariable = body.getOrCreateVariableByName(countLiteral.getResultVariable().getUniqueName());
228 new PatternMatchCounter(body, substitution, wrappedCall.pattern(), resultVariable); 239 new PatternMatchCounter(body, substitution, wrappedCall.pattern(), resultVariable);
229 } 240 }
230 241
231 private <R, T> void translateAggregationLiteral(AggregationLiteral<R, T> aggregationLiteral, DnfClause clause, 242 private <R, T> void translateAggregationLiteral(AggregationLiteral<R, T> aggregationLiteral, PBody body) {
232 PBody body) {
233 var aggregator = aggregationLiteral.getAggregator(); 243 var aggregator = aggregationLiteral.getAggregator();
234 IMultisetAggregationOperator<T, ?, R> aggregationOperator; 244 IMultisetAggregationOperator<T, ?, R> aggregationOperator;
235 if (aggregator instanceof StatelessAggregator<R, T> statelessAggregator) { 245 if (aggregator instanceof StatelessAggregator<R, T> statelessAggregator) {
@@ -239,7 +249,7 @@ public class Dnf2PQuery {
239 } else { 249 } else {
240 throw new IllegalArgumentException("Unknown aggregator: " + aggregator); 250 throw new IllegalArgumentException("Unknown aggregator: " + aggregator);
241 } 251 }
242 var wrappedCall = wrapperFactory.maybeWrapConstraint(aggregationLiteral, clause); 252 var wrappedCall = wrapperFactory.maybeWrapConstraint(aggregationLiteral);
243 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body); 253 var substitution = translateSubstitution(wrappedCall.remappedArguments(), body);
244 var inputVariable = body.getOrCreateVariableByName(aggregationLiteral.getInputVariable().getUniqueName()); 254 var inputVariable = body.getOrCreateVariableByName(aggregationLiteral.getInputVariable().getUniqueName());
245 var aggregatedColumn = substitution.invertIndex().get(inputVariable); 255 var aggregatedColumn = substitution.invertIndex().get(inputVariable);
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java
index 24ae5196..2b7280f2 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/QueryWrapperFactory.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; 8import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
@@ -9,15 +14,16 @@ import org.eclipse.viatra.query.runtime.matchers.psystem.basicenumerables.TypeCo
9import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter; 14import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PParameter;
10import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery; 15import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PQuery;
11import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility; 16import org.eclipse.viatra.query.runtime.matchers.psystem.queries.PVisibility;
17import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
12import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; 18import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
13import tools.refinery.store.query.Constraint; 19import tools.refinery.store.query.Constraint;
14import tools.refinery.store.query.dnf.Dnf; 20import tools.refinery.store.query.dnf.Dnf;
15import tools.refinery.store.query.dnf.DnfClause;
16import tools.refinery.store.query.dnf.DnfUtils; 21import tools.refinery.store.query.dnf.DnfUtils;
17import tools.refinery.store.query.literal.AbstractCallLiteral; 22import tools.refinery.store.query.literal.AbstractCallLiteral;
23import tools.refinery.store.query.term.ParameterDirection;
18import tools.refinery.store.query.term.Variable; 24import tools.refinery.store.query.term.Variable;
19import tools.refinery.store.query.view.AnyRelationView; 25import tools.refinery.store.query.view.AnySymbolView;
20import tools.refinery.store.query.view.RelationView; 26import tools.refinery.store.query.view.SymbolView;
21import tools.refinery.store.util.CycleDetectingMapper; 27import tools.refinery.store.util.CycleDetectingMapper;
22 28
23import java.util.*; 29import java.util.*;
@@ -25,7 +31,7 @@ import java.util.function.ToIntFunction;
25 31
26class QueryWrapperFactory { 32class QueryWrapperFactory {
27 private final Dnf2PQuery dnf2PQuery; 33 private final Dnf2PQuery dnf2PQuery;
28 private final Map<AnyRelationView, RelationViewWrapper> view2WrapperMap = new LinkedHashMap<>(); 34 private final Map<AnySymbolView, SymbolViewWrapper> view2WrapperMap = new LinkedHashMap<>();
29 private final CycleDetectingMapper<RemappedConstraint, RawPQuery> wrapConstraint = new CycleDetectingMapper<>( 35 private final CycleDetectingMapper<RemappedConstraint, RawPQuery> wrapConstraint = new CycleDetectingMapper<>(
30 RemappedConstraint::toString, this::doWrapConstraint); 36 RemappedConstraint::toString, this::doWrapConstraint);
31 37
@@ -33,28 +39,24 @@ class QueryWrapperFactory {
33 this.dnf2PQuery = dnf2PQuery; 39 this.dnf2PQuery = dnf2PQuery;
34 } 40 }
35 41
36 public PQuery wrapRelationViewIdentityArguments(AnyRelationView relationView) { 42 public PQuery wrapSymbolViewIdentityArguments(AnySymbolView symbolView) {
37 var identity = new int[relationView.arity()]; 43 var identity = new int[symbolView.arity()];
38 for (int i = 0; i < identity.length; i++) { 44 for (int i = 0; i < identity.length; i++) {
39 identity[i] = i; 45 identity[i] = i;
40 } 46 }
41 return maybeWrapConstraint(relationView, identity); 47 return maybeWrapConstraint(symbolView, identity);
42 } 48 }
43 public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral, DnfClause clause) { 49
50 public WrappedCall maybeWrapConstraint(AbstractCallLiteral callLiteral) {
44 var arguments = callLiteral.getArguments(); 51 var arguments = callLiteral.getArguments();
45 int arity = arguments.size(); 52 int arity = arguments.size();
46 var remappedParameters = new int[arity]; 53 var remappedParameters = new int[arity];
47 var boundVariables = clause.boundVariables();
48 var unboundVariableIndices = new HashMap<Variable, Integer>(); 54 var unboundVariableIndices = new HashMap<Variable, Integer>();
49 var appendVariable = new VariableAppender(); 55 var appendVariable = new VariableAppender();
50 for (int i = 0; i < arity; i++) { 56 for (int i = 0; i < arity; i++) {
51 var variable = arguments.get(i); 57 var variable = arguments.get(i);
52 if (boundVariables.contains(variable)) { 58 // Unify all variables to avoid VIATRA bugs, even if they're bound in the containing clause.
53 // Do not join bound variable to make sure that the embedded pattern stays as general as possible. 59 remappedParameters[i] = unboundVariableIndices.computeIfAbsent(variable, appendVariable::applyAsInt);
54 remappedParameters[i] = appendVariable.applyAsInt(variable);
55 } else {
56 remappedParameters[i] = unboundVariableIndices.computeIfAbsent(variable, appendVariable::applyAsInt);
57 }
58 } 60 }
59 var pattern = maybeWrapConstraint(callLiteral.getTarget(), remappedParameters); 61 var pattern = maybeWrapConstraint(callLiteral.getTarget(), remappedParameters);
60 return new WrappedCall(pattern, appendVariable.getRemappedArguments()); 62 return new WrappedCall(pattern, appendVariable.getRemappedArguments());
@@ -84,6 +86,8 @@ class QueryWrapperFactory {
84 var constraint = remappedConstraint.constraint(); 86 var constraint = remappedConstraint.constraint();
85 var remappedParameters = remappedConstraint.remappedParameters(); 87 var remappedParameters = remappedConstraint.remappedParameters();
86 88
89 checkNoInputParameters(constraint);
90
87 var embeddedPQuery = new RawPQuery(DnfUtils.generateUniqueName(constraint.name()), PVisibility.EMBEDDED); 91 var embeddedPQuery = new RawPQuery(DnfUtils.generateUniqueName(constraint.name()), PVisibility.EMBEDDED);
88 var body = new PBody(embeddedPQuery); 92 var body = new PBody(embeddedPQuery);
89 int arity = Arrays.stream(remappedParameters).max().orElse(-1) + 1; 93 int arity = Arrays.stream(remappedParameters).max().orElse(-1) + 1;
@@ -107,24 +111,36 @@ class QueryWrapperFactory {
107 } 111 }
108 var argumentTuple = Tuples.flatTupleOf(arguments); 112 var argumentTuple = Tuples.flatTupleOf(arguments);
109 113
110 if (constraint instanceof RelationView<?> relationView) { 114 addPositiveConstraint(constraint, body, argumentTuple);
111 new TypeConstraint(body, argumentTuple, getInputKey(relationView)); 115 embeddedPQuery.addBody(body);
116 return embeddedPQuery;
117 }
118
119 private static void checkNoInputParameters(Constraint constraint) {
120 for (var constraintParameter : constraint.getParameters()) {
121 if (constraintParameter.getDirection() == ParameterDirection.IN) {
122 throw new IllegalArgumentException("Input parameter %s of %s is not supported"
123 .formatted(constraintParameter, constraint));
124 }
125 }
126 }
127
128 private void addPositiveConstraint(Constraint constraint, PBody body, Tuple argumentTuple) {
129 if (constraint instanceof SymbolView<?> view) {
130 new TypeConstraint(body, argumentTuple, getInputKey(view));
112 } else if (constraint instanceof Dnf dnf) { 131 } else if (constraint instanceof Dnf dnf) {
113 var calledPQuery = dnf2PQuery.translate(dnf); 132 var calledPQuery = dnf2PQuery.translate(dnf);
114 new PositivePatternCall(body, argumentTuple, calledPQuery); 133 new PositivePatternCall(body, argumentTuple, calledPQuery);
115 } else { 134 } else {
116 throw new IllegalArgumentException("Unknown Constraint: " + constraint); 135 throw new IllegalArgumentException("Unknown Constraint: " + constraint);
117 } 136 }
118
119 embeddedPQuery.addBody(body);
120 return embeddedPQuery;
121 } 137 }
122 138
123 public IInputKey getInputKey(AnyRelationView relationView) { 139 public IInputKey getInputKey(AnySymbolView symbolView) {
124 return view2WrapperMap.computeIfAbsent(relationView, RelationViewWrapper::new); 140 return view2WrapperMap.computeIfAbsent(symbolView, SymbolViewWrapper::new);
125 } 141 }
126 142
127 public Map<AnyRelationView, IInputKey> getRelationViews() { 143 public Map<AnySymbolView, IInputKey> getSymbolViews() {
128 return Collections.unmodifiableMap(view2WrapperMap); 144 return Collections.unmodifiableMap(view2WrapperMap);
129 } 145 }
130 146
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
index aad4ba3c..255738c5 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RawPQuery.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification; 8import org.eclipse.viatra.query.runtime.api.GenericQuerySpecification;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java
index 2798a252..461416f7 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatefulMultisetAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; 8import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java
index 7cc71ee9..49175d75 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/StatelessMultisetAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator; 8import org.eclipse.viatra.query.runtime.matchers.psystem.aggregations.IMultisetAggregationOperator;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java
index 48bf558d..a777613e 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/RelationViewWrapper.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/SymbolViewWrapper.java
@@ -1,10 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper; 8import org.eclipse.viatra.query.runtime.matchers.context.common.BaseInputKeyWrapper;
4import tools.refinery.store.query.view.AnyRelationView; 9import tools.refinery.store.query.view.AnySymbolView;
5 10
6public class RelationViewWrapper extends BaseInputKeyWrapper<AnyRelationView> { 11public class SymbolViewWrapper extends BaseInputKeyWrapper<AnySymbolView> {
7 public RelationViewWrapper(AnyRelationView wrappedKey) { 12 public SymbolViewWrapper(AnySymbolView wrappedKey) {
8 super(wrappedKey); 13 super(wrappedKey);
9 } 14 }
10 15
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
index ab123c50..1187f57a 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/TermEvaluator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.psystem.IExpressionEvaluator; 8import org.eclipse.viatra.query.runtime.matchers.psystem.IExpressionEvaluator;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java
index 30c2fce7..62cb8b3a 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/pquery/ValueProviderBasedValuation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.pquery; 6package tools.refinery.store.query.viatra.internal.pquery;
2 7
3import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider; 8import org.eclipse.viatra.query.runtime.matchers.psystem.IValueProvider;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
index fc935aa6..986bb0b1 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/ModelUpdateListener.java
@@ -1,46 +1,51 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.update; 6package tools.refinery.store.query.viatra.internal.update;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; 8import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
4import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener; 9import org.eclipse.viatra.query.runtime.matchers.context.IQueryRuntimeContextListener;
5import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple; 10import org.eclipse.viatra.query.runtime.matchers.tuple.ITuple;
6import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 11import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
7import tools.refinery.store.query.view.AnyRelationView; 12import tools.refinery.store.query.view.AnySymbolView;
8import tools.refinery.store.query.view.RelationView; 13import tools.refinery.store.query.view.SymbolView;
9 14
10import java.util.HashMap; 15import java.util.HashMap;
11import java.util.Map; 16import java.util.Map;
12 17
13public class ModelUpdateListener { 18public class ModelUpdateListener {
14 private final Map<AnyRelationView, RelationViewUpdateListener<?>> relationViewUpdateListeners; 19 private final Map<AnySymbolView, SymbolViewUpdateListener<?>> symbolViewUpdateListeners;
15 20
16 public ModelUpdateListener(ViatraModelQueryAdapterImpl adapter) { 21 public ModelUpdateListener(ViatraModelQueryAdapterImpl adapter) {
17 var relationViews = adapter.getStoreAdapter().getInputKeys().keySet(); 22 var symbolViews = adapter.getStoreAdapter().getInputKeys().keySet();
18 relationViewUpdateListeners = new HashMap<>(relationViews.size()); 23 symbolViewUpdateListeners = new HashMap<>(symbolViews.size());
19 for (var relationView : relationViews) { 24 for (var symbolView : symbolViews) {
20 registerView(adapter, (RelationView<?>) relationView); 25 registerView(adapter, (SymbolView<?>) symbolView);
21 } 26 }
22 } 27 }
23 28
24 private <T> void registerView(ViatraModelQueryAdapterImpl adapter, RelationView<T> relationView) { 29 private <T> void registerView(ViatraModelQueryAdapterImpl adapter, SymbolView<T> view) {
25 var model = adapter.getModel(); 30 var model = adapter.getModel();
26 var interpretation = model.getInterpretation(relationView.getSymbol()); 31 var interpretation = model.getInterpretation(view.getSymbol());
27 var listener = RelationViewUpdateListener.of(adapter, relationView, interpretation); 32 var listener = SymbolViewUpdateListener.of(adapter, view, interpretation);
28 relationViewUpdateListeners.put(relationView, listener); 33 symbolViewUpdateListeners.put(view, listener);
29 } 34 }
30 35
31 public boolean containsRelationView(AnyRelationView relationView) { 36 public boolean containsSymbolView(AnySymbolView relationView) {
32 return relationViewUpdateListeners.containsKey(relationView); 37 return symbolViewUpdateListeners.containsKey(relationView);
33 } 38 }
34 39
35 public void addListener(IInputKey key, AnyRelationView relationView, ITuple seed, 40 public void addListener(IInputKey key, AnySymbolView symbolView, ITuple seed,
36 IQueryRuntimeContextListener listener) { 41 IQueryRuntimeContextListener listener) {
37 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView); 42 var symbolViewUpdateListener = symbolViewUpdateListeners.get(symbolView);
38 relationViewUpdateListener.addFilter(key, seed, listener); 43 symbolViewUpdateListener.addFilter(key, seed, listener);
39 } 44 }
40 45
41 public void removeListener(IInputKey key, AnyRelationView relationView, ITuple seed, 46 public void removeListener(IInputKey key, AnySymbolView symbolView, ITuple seed,
42 IQueryRuntimeContextListener listener) { 47 IQueryRuntimeContextListener listener) {
43 var relationViewUpdateListener = relationViewUpdateListeners.get(relationView); 48 var symbolViewUpdateListener = symbolViewUpdateListeners.get(symbolView);
44 relationViewUpdateListener.removeFilter(key, seed, listener); 49 symbolViewUpdateListener.removeFilter(key, seed, listener);
45 } 50 }
46} 51}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
index 221f1b4a..efdbfcbe 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewFilter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.update; 6package tools.refinery.store.query.viatra.internal.update;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; 8import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java
index 5e5f60e3..f1a2ac7c 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/RelationViewUpdateListener.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/SymbolViewUpdateListener.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.update; 6package tools.refinery.store.query.viatra.internal.update;
2 7
3import org.eclipse.viatra.query.runtime.matchers.context.IInputKey; 8import org.eclipse.viatra.query.runtime.matchers.context.IInputKey;
@@ -7,18 +12,18 @@ import org.eclipse.viatra.query.runtime.matchers.tuple.Tuple;
7import tools.refinery.store.model.Interpretation; 12import tools.refinery.store.model.Interpretation;
8import tools.refinery.store.model.InterpretationListener; 13import tools.refinery.store.model.InterpretationListener;
9import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 14import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
10import tools.refinery.store.query.view.RelationView; 15import tools.refinery.store.query.view.SymbolView;
11import tools.refinery.store.query.view.TuplePreservingRelationView; 16import tools.refinery.store.query.view.TuplePreservingView;
12 17
13import java.util.ArrayList; 18import java.util.ArrayList;
14import java.util.List; 19import java.util.List;
15 20
16public abstract class RelationViewUpdateListener<T> implements InterpretationListener<T> { 21public abstract class SymbolViewUpdateListener<T> implements InterpretationListener<T> {
17 private final ViatraModelQueryAdapterImpl adapter; 22 private final ViatraModelQueryAdapterImpl adapter;
18 private final Interpretation<T> interpretation; 23 private final Interpretation<T> interpretation;
19 private final List<RelationViewFilter> filters = new ArrayList<>(); 24 private final List<RelationViewFilter> filters = new ArrayList<>();
20 25
21 protected RelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, Interpretation<T> interpretation) { 26 protected SymbolViewUpdateListener(ViatraModelQueryAdapterImpl adapter, Interpretation<T> interpretation) {
22 this.adapter = adapter; 27 this.adapter = adapter;
23 this.interpretation = interpretation; 28 this.interpretation = interpretation;
24 } 29 }
@@ -48,13 +53,13 @@ public abstract class RelationViewUpdateListener<T> implements InterpretationLis
48 } 53 }
49 } 54 }
50 55
51 public static <T> RelationViewUpdateListener<T> of(ViatraModelQueryAdapterImpl adapter, 56 public static <T> SymbolViewUpdateListener<T> of(ViatraModelQueryAdapterImpl adapter,
52 RelationView<T> relationView, 57 SymbolView<T> view,
53 Interpretation<T> interpretation) { 58 Interpretation<T> interpretation) {
54 if (relationView instanceof TuplePreservingRelationView<T> tuplePreservingRelationView) { 59 if (view instanceof TuplePreservingView<T> tuplePreservingRelationView) {
55 return new TuplePreservingRelationViewUpdateListener<>(adapter, tuplePreservingRelationView, 60 return new TuplePreservingViewUpdateListener<>(adapter, tuplePreservingRelationView,
56 interpretation); 61 interpretation);
57 } 62 }
58 return new TupleChangingRelationViewUpdateListener<>(adapter, relationView, interpretation); 63 return new TupleChangingViewUpdateListener<>(adapter, view, interpretation);
59 } 64 }
60} 65}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
deleted file mode 100644
index 0f6ed3b3..00000000
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingRelationViewUpdateListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
1package tools.refinery.store.query.viatra.internal.update;
2
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.model.Interpretation;
5import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
6import tools.refinery.store.query.view.RelationView;
7import tools.refinery.store.tuple.Tuple;
8
9import java.util.Arrays;
10
11public class TupleChangingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> {
12 private final RelationView<T> relationView;
13
14 TupleChangingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, RelationView<T> relationView,
15 Interpretation<T> interpretation) {
16 super(adapter, interpretation);
17 this.relationView = relationView;
18 }
19
20 @Override
21 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
22 boolean fromPresent = relationView.filter(key, fromValue);
23 boolean toPresent = relationView.filter(key, toValue);
24 if (fromPresent) {
25 if (toPresent) { // value change
26 var fromArray = relationView.forwardMap(key, fromValue);
27 var toArray = relationView.forwardMap(key, toValue);
28 if (!Arrays.equals(fromArray, toArray)) {
29 processUpdate(Tuples.flatTupleOf(fromArray), false);
30 processUpdate(Tuples.flatTupleOf(toArray), true);
31 }
32 } else { // fromValue disappears
33 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, fromValue)), false);
34 }
35 } else if (toPresent) { // toValue appears
36 processUpdate(Tuples.flatTupleOf(relationView.forwardMap(key, toValue)), true);
37 }
38 }
39}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java
new file mode 100644
index 00000000..45d35571
--- /dev/null
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TupleChangingViewUpdateListener.java
@@ -0,0 +1,44 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.viatra.internal.update;
7
8import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
9import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
11import tools.refinery.store.query.view.SymbolView;
12import tools.refinery.store.tuple.Tuple;
13
14import java.util.Arrays;
15
16public class TupleChangingViewUpdateListener<T> extends SymbolViewUpdateListener<T> {
17 private final SymbolView<T> view;
18
19 TupleChangingViewUpdateListener(ViatraModelQueryAdapterImpl adapter, SymbolView<T> view,
20 Interpretation<T> interpretation) {
21 super(adapter, interpretation);
22 this.view = view;
23 }
24
25 @Override
26 public void put(Tuple key, T fromValue, T toValue, boolean restoring) {
27 boolean fromPresent = view.filter(key, fromValue);
28 boolean toPresent = view.filter(key, toValue);
29 if (fromPresent) {
30 if (toPresent) { // value change
31 var fromArray = view.forwardMap(key, fromValue);
32 var toArray = view.forwardMap(key, toValue);
33 if (!Arrays.equals(fromArray, toArray)) {
34 processUpdate(Tuples.flatTupleOf(fromArray), false);
35 processUpdate(Tuples.flatTupleOf(toArray), true);
36 }
37 } else { // fromValue disappears
38 processUpdate(Tuples.flatTupleOf(view.forwardMap(key, fromValue)), false);
39 }
40 } else if (toPresent) { // toValue appears
41 processUpdate(Tuples.flatTupleOf(view.forwardMap(key, toValue)), true);
42 }
43 }
44}
diff --git a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java
index 91e9371b..c18dbafb 100644
--- a/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingRelationViewUpdateListener.java
+++ b/subprojects/store-query-viatra/src/main/java/tools/refinery/store/query/viatra/internal/update/TuplePreservingViewUpdateListener.java
@@ -1,16 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.internal.update; 6package tools.refinery.store.query.viatra.internal.update;
2 7
3import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples; 8import org.eclipse.viatra.query.runtime.matchers.tuple.Tuples;
4import tools.refinery.store.model.Interpretation; 9import tools.refinery.store.model.Interpretation;
5import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl; 10import tools.refinery.store.query.viatra.internal.ViatraModelQueryAdapterImpl;
6import tools.refinery.store.query.view.TuplePreservingRelationView; 11import tools.refinery.store.query.view.TuplePreservingView;
7import tools.refinery.store.tuple.Tuple; 12import tools.refinery.store.tuple.Tuple;
8 13
9public class TuplePreservingRelationViewUpdateListener<T> extends RelationViewUpdateListener<T> { 14public class TuplePreservingViewUpdateListener<T> extends SymbolViewUpdateListener<T> {
10 private final TuplePreservingRelationView<T> view; 15 private final TuplePreservingView<T> view;
11 16
12 TuplePreservingRelationViewUpdateListener(ViatraModelQueryAdapterImpl adapter, 17 TuplePreservingViewUpdateListener(ViatraModelQueryAdapterImpl adapter, TuplePreservingView<T> view,
13 TuplePreservingRelationView<T> view, Interpretation<T> interpretation) { 18 Interpretation<T> interpretation) {
14 super(adapter, interpretation); 19 super(adapter, interpretation);
15 this.view = view; 20 this.view = view;
16 } 21 }
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
index 90229b73..6aae2ebe 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/DiagonalQueryTest.java
@@ -1,17 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.query.ModelQuery; 10import tools.refinery.store.query.ModelQueryAdapter;
6import tools.refinery.store.query.dnf.Dnf; 11import tools.refinery.store.query.dnf.Dnf;
7import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
8import tools.refinery.store.query.term.Variable;
9import tools.refinery.store.query.viatra.tests.QueryEngineTest; 13import tools.refinery.store.query.viatra.tests.QueryEngineTest;
10import tools.refinery.store.query.view.FunctionalRelationView; 14import tools.refinery.store.query.view.AnySymbolView;
11import tools.refinery.store.query.view.KeyOnlyRelationView; 15import tools.refinery.store.query.view.FunctionView;
16import tools.refinery.store.query.view.KeyOnlyView;
12import tools.refinery.store.representation.Symbol; 17import tools.refinery.store.representation.Symbol;
13import tools.refinery.store.tuple.Tuple; 18import tools.refinery.store.tuple.Tuple;
14 19
20import java.util.List;
15import java.util.Map; 21import java.util.Map;
16import java.util.Optional; 22import java.util.Optional;
17 23
@@ -21,34 +27,33 @@ import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNull
21import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; 27import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
22 28
23class DiagonalQueryTest { 29class DiagonalQueryTest {
30 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
31 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
32 private static final Symbol<Boolean> symbol = Symbol.of("symbol", 4);
33 private static final Symbol<Integer> intSymbol = Symbol.of("intSymbol", 4, Integer.class);
34 private static final AnySymbolView personView = new KeyOnlyView<>(person);
35 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
36 private static final AnySymbolView symbolView = new KeyOnlyView<>(symbol);
37 private static final FunctionView<Integer> intSymbolView = new FunctionView<>(intSymbol);
38
24 @QueryEngineTest 39 @QueryEngineTest
25 void inputKeyNegationTest(QueryEvaluationHint hint) { 40 void inputKeyNegationTest(QueryEvaluationHint hint) {
26 var person = new Symbol<>("Person", 1, Boolean.class, false); 41 var query = Query.of("Diagonal", (builder, p1) -> builder.clause(p2 -> List.of(
27 var symbol = new Symbol<>("symbol", 4, Boolean.class, false); 42 personView.call(p1),
28 var personView = new KeyOnlyRelationView<>(person); 43 not(symbolView.call(p1, p1, p2, p2))
29 var symbolView = new KeyOnlyRelationView<>(symbol); 44 )));
30
31 var p1 = Variable.of("p1");
32 var p2 = Variable.of("p2");
33 var query = Query.builder("Diagonal")
34 .parameter(p1)
35 .clause(
36 personView.call(p1),
37 not(symbolView.call(p1, p1, p2, p2))
38 )
39 .build();
40 45
41 var store = ModelStore.builder() 46 var store = ModelStore.builder()
42 .symbols(person, symbol) 47 .symbols(person, symbol)
43 .with(ViatraModelQuery.ADAPTER) 48 .with(ViatraModelQueryAdapter.builder()
44 .defaultHint(hint) 49 .defaultHint(hint)
45 .queries(query) 50 .queries(query))
46 .build(); 51 .build();
47 52
48 var model = store.createEmptyModel(); 53 var model = store.createEmptyModel();
49 var personInterpretation = model.getInterpretation(person); 54 var personInterpretation = model.getInterpretation(person);
50 var symbolInterpretation = model.getInterpretation(symbol); 55 var symbolInterpretation = model.getInterpretation(symbol);
51 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 56 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
52 var queryResultSet = queryEngine.getResultSet(query); 57 var queryResultSet = queryEngine.getResultSet(query);
53 58
54 personInterpretation.put(Tuple.of(0), true); 59 personInterpretation.put(Tuple.of(0), true);
@@ -71,17 +76,7 @@ class DiagonalQueryTest {
71 76
72 @QueryEngineTest 77 @QueryEngineTest
73 void subQueryNegationTest(QueryEvaluationHint hint) { 78 void subQueryNegationTest(QueryEvaluationHint hint) {
74 var person = new Symbol<>("Person", 1, Boolean.class, false); 79 var subQuery = Query.of("SubQuery", (builder, p1, p2, p3, p4) -> builder
75 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
76 var personView = new KeyOnlyRelationView<>(person);
77 var symbolView = new KeyOnlyRelationView<>(symbol);
78
79 var p1 = Variable.of("p1");
80 var p2 = Variable.of("p2");
81 var p3 = Variable.of("p3");
82 var p4 = Variable.of("p4");
83 var subQuery = Dnf.builder("SubQuery")
84 .parameters(p1, p2, p3, p4)
85 .clause( 80 .clause(
86 personView.call(p1), 81 personView.call(p1),
87 symbolView.call(p1, p2, p3, p4) 82 symbolView.call(p1, p2, p3, p4)
@@ -89,27 +84,23 @@ class DiagonalQueryTest {
89 .clause( 84 .clause(
90 personView.call(p2), 85 personView.call(p2),
91 symbolView.call(p1, p2, p3, p4) 86 symbolView.call(p1, p2, p3, p4)
92 ) 87 ));
93 .build(); 88 var query = Query.of("Diagonal", (builder, p1) -> builder.clause(p2 -> List.of(
94 var query = Query.builder("Diagonal") 89 personView.call(p1),
95 .parameter(p1) 90 not(subQuery.call(p1, p1, p2, p2))
96 .clause( 91 )));
97 personView.call(p1),
98 not(subQuery.call(p1, p1, p2, p2))
99 )
100 .build();
101 92
102 var store = ModelStore.builder() 93 var store = ModelStore.builder()
103 .symbols(person, symbol) 94 .symbols(person, symbol)
104 .with(ViatraModelQuery.ADAPTER) 95 .with(ViatraModelQueryAdapter.builder()
105 .defaultHint(hint) 96 .defaultHint(hint)
106 .queries(query) 97 .queries(query))
107 .build(); 98 .build();
108 99
109 var model = store.createEmptyModel(); 100 var model = store.createEmptyModel();
110 var personInterpretation = model.getInterpretation(person); 101 var personInterpretation = model.getInterpretation(person);
111 var symbolInterpretation = model.getInterpretation(symbol); 102 var symbolInterpretation = model.getInterpretation(symbol);
112 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 103 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
113 var queryResultSet = queryEngine.getResultSet(query); 104 var queryResultSet = queryEngine.getResultSet(query);
114 105
115 personInterpretation.put(Tuple.of(0), true); 106 personInterpretation.put(Tuple.of(0), true);
@@ -132,34 +123,22 @@ class DiagonalQueryTest {
132 123
133 @QueryEngineTest 124 @QueryEngineTest
134 void inputKeyCountTest(QueryEvaluationHint hint) { 125 void inputKeyCountTest(QueryEvaluationHint hint) {
135 var person = new Symbol<>("Person", 1, Boolean.class, false); 126 var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause(p2 -> List.of(
136 var symbol = new Symbol<>("symbol", 4, Boolean.class, false); 127 personView.call(p1),
137 var personView = new KeyOnlyRelationView<>(person); 128 output.assign(symbolView.count(p1, p1, p2, p2))
138 var symbolView = new KeyOnlyRelationView<>(symbol); 129 )));
139
140 var p1 = Variable.of("p1");
141 var p2 = Variable.of("p2");
142 var x = Variable.of("x", Integer.class);
143 var query = Query.builder("Diagonal")
144 .parameter(p1)
145 .output(x)
146 .clause(
147 personView.call(p1),
148 x.assign(symbolView.count(p1, p1, p2, p2))
149 )
150 .build();
151 130
152 var store = ModelStore.builder() 131 var store = ModelStore.builder()
153 .symbols(person, symbol) 132 .symbols(person, symbol)
154 .with(ViatraModelQuery.ADAPTER) 133 .with(ViatraModelQueryAdapter.builder()
155 .defaultHint(hint) 134 .defaultHint(hint)
156 .queries(query) 135 .queries(query))
157 .build(); 136 .build();
158 137
159 var model = store.createEmptyModel(); 138 var model = store.createEmptyModel();
160 var personInterpretation = model.getInterpretation(person); 139 var personInterpretation = model.getInterpretation(person);
161 var symbolInterpretation = model.getInterpretation(symbol); 140 var symbolInterpretation = model.getInterpretation(symbol);
162 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 141 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
163 var queryResultSet = queryEngine.getResultSet(query); 142 var queryResultSet = queryEngine.getResultSet(query);
164 143
165 personInterpretation.put(Tuple.of(0), true); 144 personInterpretation.put(Tuple.of(0), true);
@@ -183,47 +162,30 @@ class DiagonalQueryTest {
183 162
184 @QueryEngineTest 163 @QueryEngineTest
185 void subQueryCountTest(QueryEvaluationHint hint) { 164 void subQueryCountTest(QueryEvaluationHint hint) {
186 var person = new Symbol<>("Person", 1, Boolean.class, false); 165 var subQuery = Query.of("SubQuery", (builder, p1, p2, p3, p4) -> builder.clause(
187 var symbol = new Symbol<>("symbol", 4, Boolean.class, false);
188 var personView = new KeyOnlyRelationView<>(person);
189 var symbolView = new KeyOnlyRelationView<>(symbol);
190
191 var p1 = Variable.of("p1");
192 var p2 = Variable.of("p2");
193 var p3 = Variable.of("p3");
194 var p4 = Variable.of("p4");
195 var x = Variable.of("x", Integer.class);
196 var subQuery = Dnf.builder("SubQuery")
197 .parameters(p1, p2, p3, p4)
198 .clause(
199 personView.call(p1), 166 personView.call(p1),
200 symbolView.call(p1, p2, p3, p4) 167 symbolView.call(p1, p2, p3, p4)
201 ) 168 )
202 .clause( 169 .clause(
203 personView.call(p2), 170 personView.call(p2),
204 symbolView.call(p1, p2, p3, p4) 171 symbolView.call(p1, p2, p3, p4)
205 ) 172 ));
206 .build(); 173 var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder.clause(p2 -> List.of(
207 var query = Query.builder("Diagonal") 174 personView.call(p1),
208 .parameter(p1) 175 output.assign(subQuery.count(p1, p1, p2, p2))
209 .output(x) 176 )));
210 .clause(
211 personView.call(p1),
212 x.assign(subQuery.count(p1, p1, p2, p2))
213 )
214 .build();
215 177
216 var store = ModelStore.builder() 178 var store = ModelStore.builder()
217 .symbols(person, symbol) 179 .symbols(person, symbol)
218 .with(ViatraModelQuery.ADAPTER) 180 .with(ViatraModelQueryAdapter.builder()
219 .defaultHint(hint) 181 .defaultHint(hint)
220 .queries(query) 182 .queries(query))
221 .build(); 183 .build();
222 184
223 var model = store.createEmptyModel(); 185 var model = store.createEmptyModel();
224 var personInterpretation = model.getInterpretation(person); 186 var personInterpretation = model.getInterpretation(person);
225 var symbolInterpretation = model.getInterpretation(symbol); 187 var symbolInterpretation = model.getInterpretation(symbol);
226 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 188 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
227 var queryResultSet = queryEngine.getResultSet(query); 189 var queryResultSet = queryEngine.getResultSet(query);
228 190
229 personInterpretation.put(Tuple.of(0), true); 191 personInterpretation.put(Tuple.of(0), true);
@@ -247,46 +209,34 @@ class DiagonalQueryTest {
247 209
248 @QueryEngineTest 210 @QueryEngineTest
249 void inputKeyAggregationTest(QueryEvaluationHint hint) { 211 void inputKeyAggregationTest(QueryEvaluationHint hint) {
250 var person = new Symbol<>("Person", 1, Boolean.class, false); 212 var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder
251 var symbol = new Symbol<>("symbol", 4, Integer.class, null); 213 .clause((p2) -> List.of(
252 var personView = new KeyOnlyRelationView<>(person);
253 var symbolView = new FunctionalRelationView<>(symbol);
254
255 var p1 = Variable.of("p1");
256 var p2 = Variable.of("p2");
257 var x = Variable.of("x", Integer.class);
258 var y = Variable.of("y", Integer.class);
259 var query = Query.builder("Diagonal")
260 .parameter(p1)
261 .output(x)
262 .clause(
263 personView.call(p1), 214 personView.call(p1),
264 x.assign(symbolView.aggregate(y, INT_SUM, p1, p1, p2, p2, y)) 215 output.assign(intSymbolView.aggregate(INT_SUM, p1, p1, p2, p2))
265 ) 216 )));
266 .build();
267 217
268 var store = ModelStore.builder() 218 var store = ModelStore.builder()
269 .symbols(person, symbol) 219 .symbols(person, intSymbol)
270 .with(ViatraModelQuery.ADAPTER) 220 .with(ViatraModelQueryAdapter.builder()
271 .defaultHint(hint) 221 .defaultHint(hint)
272 .queries(query) 222 .queries(query))
273 .build(); 223 .build();
274 224
275 var model = store.createEmptyModel(); 225 var model = store.createEmptyModel();
276 var personInterpretation = model.getInterpretation(person); 226 var personInterpretation = model.getInterpretation(person);
277 var symbolInterpretation = model.getInterpretation(symbol); 227 var intSymbolInterpretation = model.getInterpretation(intSymbol);
278 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 228 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
279 var queryResultSet = queryEngine.getResultSet(query); 229 var queryResultSet = queryEngine.getResultSet(query);
280 230
281 personInterpretation.put(Tuple.of(0), true); 231 personInterpretation.put(Tuple.of(0), true);
282 personInterpretation.put(Tuple.of(1), true); 232 personInterpretation.put(Tuple.of(1), true);
283 personInterpretation.put(Tuple.of(2), true); 233 personInterpretation.put(Tuple.of(2), true);
284 234
285 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); 235 intSymbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1);
286 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); 236 intSymbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2);
287 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); 237 intSymbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10);
288 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); 238 intSymbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11);
289 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); 239 intSymbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12);
290 240
291 queryEngine.flushChanges(); 241 queryEngine.flushChanges();
292 assertNullableResults(Map.of( 242 assertNullableResults(Map.of(
@@ -299,62 +249,52 @@ class DiagonalQueryTest {
299 249
300 @QueryEngineTest 250 @QueryEngineTest
301 void subQueryAggregationTest(QueryEvaluationHint hint) { 251 void subQueryAggregationTest(QueryEvaluationHint hint) {
302 var person = new Symbol<>("Person", 1, Boolean.class, false); 252 var subQuery = Dnf.of("SubQuery", builder -> {
303 var symbol = new Symbol<>("symbol", 4, Integer.class, null); 253 var p1 = builder.parameter("p1");
304 var personView = new KeyOnlyRelationView<>(person); 254 var p2 = builder.parameter("p2");
305 var symbolView = new FunctionalRelationView<>(symbol); 255 var p3 = builder.parameter("p3");
306 256 var p4 = builder.parameter("p4");
307 var p1 = Variable.of("p1"); 257 var x = builder.parameter("x", Integer.class);
308 var p2 = Variable.of("p2"); 258 var y = builder.parameter("y", Integer.class);
309 var p3 = Variable.of("p3"); 259 builder.clause(
310 var p4 = Variable.of("p4"); 260 personView.call(p1),
311 var x = Variable.of("x", Integer.class); 261 intSymbolView.call(p1, p2, p3, p4, x),
312 var y = Variable.of("y", Integer.class); 262 y.assign(x)
313 var z = Variable.of("z", Integer.class); 263 );
314 var subQuery = Dnf.builder("SubQuery") 264 builder.clause(
315 .parameters(p1, p2, p3, p4, x, y) 265 personView.call(p2),
316 .clause( 266 intSymbolView.call(p1, p2, p3, p4, x),
267 y.assign(x)
268 );
269 });
270 var query = Query.of("Diagonal", Integer.class, (builder, p1, output) -> builder
271 .clause(Integer.class, Integer.class, (p2, y, z) -> List.of(
317 personView.call(p1), 272 personView.call(p1),
318 symbolView.call(p1, p2, p3, p4, x), 273 output.assign(subQuery.aggregateBy(y, INT_SUM, p1, p1, p2, p2, y, z))
319 y.assign(x) 274 )));
320 )
321 .clause(
322 personView.call(p2),
323 symbolView.call(p1, p2, p3, p4, x),
324 y.assign(x)
325 )
326 .build();
327 var query = Query.builder("Diagonal")
328 .parameter(p1)
329 .output(x)
330 .clause(
331 personView.call(p1),
332 x.assign(subQuery.aggregate(z, INT_SUM, p1, p1, p2, p2, z, z))
333 )
334 .build();
335 275
336 var store = ModelStore.builder() 276 var store = ModelStore.builder()
337 .symbols(person, symbol) 277 .symbols(person, intSymbol)
338 .with(ViatraModelQuery.ADAPTER) 278 .with(ViatraModelQueryAdapter.builder()
339 .defaultHint(hint) 279 .defaultHint(hint)
340 .queries(query) 280 .queries(query))
341 .build(); 281 .build();
342 282
343 var model = store.createEmptyModel(); 283 var model = store.createEmptyModel();
344 var personInterpretation = model.getInterpretation(person); 284 var personInterpretation = model.getInterpretation(person);
345 var symbolInterpretation = model.getInterpretation(symbol); 285 var intSymbolInterpretation = model.getInterpretation(intSymbol);
346 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 286 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
347 var queryResultSet = queryEngine.getResultSet(query); 287 var queryResultSet = queryEngine.getResultSet(query);
348 288
349 personInterpretation.put(Tuple.of(0), true); 289 personInterpretation.put(Tuple.of(0), true);
350 personInterpretation.put(Tuple.of(1), true); 290 personInterpretation.put(Tuple.of(1), true);
351 personInterpretation.put(Tuple.of(2), true); 291 personInterpretation.put(Tuple.of(2), true);
352 292
353 symbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1); 293 intSymbolInterpretation.put(Tuple.of(0, 0, 1, 1), 1);
354 symbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2); 294 intSymbolInterpretation.put(Tuple.of(0, 0, 2, 2), 2);
355 symbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10); 295 intSymbolInterpretation.put(Tuple.of(0, 0, 1, 2), 10);
356 symbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11); 296 intSymbolInterpretation.put(Tuple.of(1, 1, 0, 1), 11);
357 symbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12); 297 intSymbolInterpretation.put(Tuple.of(1, 2, 1, 1), 12);
358 298
359 queryEngine.flushChanges(); 299 queryEngine.flushChanges();
360 assertNullableResults(Map.of( 300 assertNullableResults(Map.of(
@@ -367,40 +307,31 @@ class DiagonalQueryTest {
367 307
368 @QueryEngineTest 308 @QueryEngineTest
369 void inputKeyTransitiveTest(QueryEvaluationHint hint) { 309 void inputKeyTransitiveTest(QueryEvaluationHint hint) {
370 var person = new Symbol<>("Person", 1, Boolean.class, false); 310 var query = Query.of("Diagonal", (builder, p1) -> builder.clause(
371 var symbol = new Symbol<>("symbol", 2, Boolean.class, false); 311 personView.call(p1),
372 var personView = new KeyOnlyRelationView<>(person); 312 friendView.callTransitive(p1, p1)
373 var symbolView = new KeyOnlyRelationView<>(symbol); 313 ));
374
375 var p1 = Variable.of("p1");
376 var query = Query.builder("Diagonal")
377 .parameter(p1)
378 .clause(
379 personView.call(p1),
380 symbolView.callTransitive(p1, p1)
381 )
382 .build();
383 314
384 var store = ModelStore.builder() 315 var store = ModelStore.builder()
385 .symbols(person, symbol) 316 .symbols(person, friend)
386 .with(ViatraModelQuery.ADAPTER) 317 .with(ViatraModelQueryAdapter.builder()
387 .defaultHint(hint) 318 .defaultHint(hint)
388 .queries(query) 319 .queries(query))
389 .build(); 320 .build();
390 321
391 var model = store.createEmptyModel(); 322 var model = store.createEmptyModel();
392 var personInterpretation = model.getInterpretation(person); 323 var personInterpretation = model.getInterpretation(person);
393 var symbolInterpretation = model.getInterpretation(symbol); 324 var friendInterpretation = model.getInterpretation(friend);
394 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 325 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
395 var queryResultSet = queryEngine.getResultSet(query); 326 var queryResultSet = queryEngine.getResultSet(query);
396 327
397 personInterpretation.put(Tuple.of(0), true); 328 personInterpretation.put(Tuple.of(0), true);
398 personInterpretation.put(Tuple.of(1), true); 329 personInterpretation.put(Tuple.of(1), true);
399 personInterpretation.put(Tuple.of(2), true); 330 personInterpretation.put(Tuple.of(2), true);
400 331
401 symbolInterpretation.put(Tuple.of(0, 0), true); 332 friendInterpretation.put(Tuple.of(0, 0), true);
402 symbolInterpretation.put(Tuple.of(0, 1), true); 333 friendInterpretation.put(Tuple.of(0, 1), true);
403 symbolInterpretation.put(Tuple.of(1, 2), true); 334 friendInterpretation.put(Tuple.of(1, 2), true);
404 335
405 queryEngine.flushChanges(); 336 queryEngine.flushChanges();
406 assertResults(Map.of( 337 assertResults(Map.of(
@@ -413,52 +344,40 @@ class DiagonalQueryTest {
413 344
414 @QueryEngineTest 345 @QueryEngineTest
415 void subQueryTransitiveTest(QueryEvaluationHint hint) { 346 void subQueryTransitiveTest(QueryEvaluationHint hint) {
416 var person = new Symbol<>("Person", 1, Boolean.class, false); 347 var subQuery = Query.of("SubQuery", (builder, p1, p2) -> builder
417 var symbol = new Symbol<>("symbol", 2, Boolean.class, false);
418 var personView = new KeyOnlyRelationView<>(person);
419 var symbolView = new KeyOnlyRelationView<>(symbol);
420
421 var p1 = Variable.of("p1");
422 var p2 = Variable.of("p2");
423 var subQuery = Dnf.builder("SubQuery")
424 .parameters(p1, p2)
425 .clause( 348 .clause(
426 personView.call(p1), 349 personView.call(p1),
427 symbolView.call(p1, p2) 350 friendView.call(p1, p2)
428 ) 351 )
429 .clause( 352 .clause(
430 personView.call(p2), 353 personView.call(p2),
431 symbolView.call(p1, p2) 354 friendView.call(p1, p2)
432 ) 355 ));
433 .build(); 356 var query = Query.of("Diagonal", (builder, p1) -> builder.clause(
434 var query = Query.builder("Diagonal") 357 personView.call(p1),
435 .parameter(p1) 358 subQuery.callTransitive(p1, p1)
436 .clause( 359 ));
437 personView.call(p1),
438 subQuery.callTransitive(p1, p1)
439 )
440 .build();
441 360
442 var store = ModelStore.builder() 361 var store = ModelStore.builder()
443 .symbols(person, symbol) 362 .symbols(person, friend)
444 .with(ViatraModelQuery.ADAPTER) 363 .with(ViatraModelQueryAdapter.builder()
445 .defaultHint(hint) 364 .defaultHint(hint)
446 .queries(query) 365 .queries(query))
447 .build(); 366 .build();
448 367
449 var model = store.createEmptyModel(); 368 var model = store.createEmptyModel();
450 var personInterpretation = model.getInterpretation(person); 369 var personInterpretation = model.getInterpretation(person);
451 var symbolInterpretation = model.getInterpretation(symbol); 370 var friendInterpretation = model.getInterpretation(friend);
452 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 371 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
453 var queryResultSet = queryEngine.getResultSet(query); 372 var queryResultSet = queryEngine.getResultSet(query);
454 373
455 personInterpretation.put(Tuple.of(0), true); 374 personInterpretation.put(Tuple.of(0), true);
456 personInterpretation.put(Tuple.of(1), true); 375 personInterpretation.put(Tuple.of(1), true);
457 personInterpretation.put(Tuple.of(2), true); 376 personInterpretation.put(Tuple.of(2), true);
458 377
459 symbolInterpretation.put(Tuple.of(0, 0), true); 378 friendInterpretation.put(Tuple.of(0, 0), true);
460 symbolInterpretation.put(Tuple.of(0, 1), true); 379 friendInterpretation.put(Tuple.of(0, 1), true);
461 symbolInterpretation.put(Tuple.of(1, 2), true); 380 friendInterpretation.put(Tuple.of(1, 2), true);
462 381
463 queryEngine.flushChanges(); 382 queryEngine.flushChanges();
464 assertResults(Map.of( 383 assertResults(Map.of(
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java
index fa2a008f..258127e7 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/FunctionalQueryTest.java
@@ -1,20 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import tools.refinery.store.map.Cursor; 9import tools.refinery.store.map.Cursor;
5import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.ModelQuery; 11import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.dnf.Dnf;
8import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable; 13import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.viatra.tests.QueryEngineTest; 14import tools.refinery.store.query.viatra.tests.QueryEngineTest;
11import tools.refinery.store.query.view.FilteredRelationView; 15import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.query.view.FunctionalRelationView; 16import tools.refinery.store.query.view.FilteredView;
13import tools.refinery.store.query.view.KeyOnlyRelationView; 17import tools.refinery.store.query.view.FunctionView;
18import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol; 19import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.representation.TruthValue; 20import tools.refinery.store.representation.TruthValue;
16import tools.refinery.store.tuple.Tuple; 21import tools.refinery.store.tuple.Tuple;
17 22
23import java.util.List;
18import java.util.Map; 24import java.util.Map;
19import java.util.Optional; 25import java.util.Optional;
20 26
@@ -29,35 +35,31 @@ import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNull
29import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; 35import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
30 36
31class FunctionalQueryTest { 37class FunctionalQueryTest {
38 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
39 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
40 private static final Symbol<TruthValue> friend = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE);
41 private static final AnySymbolView personView = new KeyOnlyView<>(person);
42 private static final FunctionView<Integer> ageView = new FunctionView<>(age);
43 private static final AnySymbolView friendMustView = new FilteredView<>(friend, "must", TruthValue::must);
44
32 @QueryEngineTest 45 @QueryEngineTest
33 void inputKeyTest(QueryEvaluationHint hint) { 46 void inputKeyTest(QueryEvaluationHint hint) {
34 var person = new Symbol<>("Person", 1, Boolean.class, false); 47 var query = Query.of("InputKey", Integer.class, (builder, p1, output) -> builder.clause(
35 var age = new Symbol<>("age", 1, Integer.class, null); 48 personView.call(p1),
36 var personView = new KeyOnlyRelationView<>(person); 49 ageView.call(p1, output)
37 var ageView = new FunctionalRelationView<>(age); 50 ));
38
39 var p1 = Variable.of("p1");
40 var x = Variable.of("x", Integer.class);
41 var query = Query.builder("InputKey")
42 .parameter(p1)
43 .output(x)
44 .clause(
45 personView.call(p1),
46 ageView.call(p1, x)
47 )
48 .build();
49 51
50 var store = ModelStore.builder() 52 var store = ModelStore.builder()
51 .symbols(person, age) 53 .symbols(person, age)
52 .with(ViatraModelQuery.ADAPTER) 54 .with(ViatraModelQueryAdapter.builder()
53 .defaultHint(hint) 55 .defaultHint(hint)
54 .queries(query) 56 .queries(query))
55 .build(); 57 .build();
56 58
57 var model = store.createEmptyModel(); 59 var model = store.createEmptyModel();
58 var personInterpretation = model.getInterpretation(person); 60 var personInterpretation = model.getInterpretation(person);
59 var ageInterpretation = model.getInterpretation(age); 61 var ageInterpretation = model.getInterpretation(age);
60 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 62 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
61 var queryResultSet = queryEngine.getResultSet(query); 63 var queryResultSet = queryEngine.getResultSet(query);
62 64
63 personInterpretation.put(Tuple.of(0), true); 65 personInterpretation.put(Tuple.of(0), true);
@@ -77,40 +79,26 @@ class FunctionalQueryTest {
77 79
78 @QueryEngineTest 80 @QueryEngineTest
79 void predicateTest(QueryEvaluationHint hint) { 81 void predicateTest(QueryEvaluationHint hint) {
80 var person = new Symbol<>("Person", 1, Boolean.class, false); 82 var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause(
81 var age = new Symbol<>("age", 1, Integer.class, null); 83 personView.call(p1),
82 var personView = new KeyOnlyRelationView<>(person); 84 ageView.call(p1, x)
83 var ageView = new FunctionalRelationView<>(age); 85 ));
84 86 var query = Query.of("Predicate", Integer.class, (builder, p1, output) -> builder.clause(
85 var p1 = Variable.of("p1"); 87 personView.call(p1),
86 var x = Variable.of("x", Integer.class); 88 output.assign(subQuery.call(p1))
87 var subQuery = Dnf.builder("SubQuery") 89 ));
88 .parameters(p1, x)
89 .clause(
90 personView.call(p1),
91 ageView.call(p1, x)
92 )
93 .build();
94 var query = Query.builder("Predicate")
95 .parameter(p1)
96 .output(x)
97 .clause(
98 personView.call(p1),
99 subQuery.call(p1, x)
100 )
101 .build();
102 90
103 var store = ModelStore.builder() 91 var store = ModelStore.builder()
104 .symbols(person, age) 92 .symbols(person, age)
105 .with(ViatraModelQuery.ADAPTER) 93 .with(ViatraModelQueryAdapter.builder()
106 .defaultHint(hint) 94 .defaultHint(hint)
107 .queries(query) 95 .queries(query))
108 .build(); 96 .build();
109 97
110 var model = store.createEmptyModel(); 98 var model = store.createEmptyModel();
111 var personInterpretation = model.getInterpretation(person); 99 var personInterpretation = model.getInterpretation(person);
112 var ageInterpretation = model.getInterpretation(age); 100 var ageInterpretation = model.getInterpretation(age);
113 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 101 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
114 var queryResultSet = queryEngine.getResultSet(query); 102 var queryResultSet = queryEngine.getResultSet(query);
115 103
116 personInterpretation.put(Tuple.of(0), true); 104 personInterpretation.put(Tuple.of(0), true);
@@ -130,35 +118,26 @@ class FunctionalQueryTest {
130 118
131 @QueryEngineTest 119 @QueryEngineTest
132 void computationTest(QueryEvaluationHint hint) { 120 void computationTest(QueryEvaluationHint hint) {
133 var person = new Symbol<>("Person", 1, Boolean.class, false); 121 var query = Query.of("Computation", Integer.class, (builder, p1, output) -> builder.clause(() -> {
134 var age = new Symbol<>("age", 1, Integer.class, null); 122 var x = Variable.of("x", Integer.class);
135 var personView = new KeyOnlyRelationView<>(person); 123 return List.of(
136 var ageView = new FunctionalRelationView<>(age); 124 personView.call(p1),
137 125 ageView.call(p1, x),
138 var p1 = Variable.of("p1"); 126 output.assign(mul(x, constant(7)))
139 var x = Variable.of("x", Integer.class); 127 );
140 var y = Variable.of("y", Integer.class); 128 }));
141 var query = Query.builder("Computation")
142 .parameter(p1)
143 .output(y)
144 .clause(
145 personView.call(p1),
146 ageView.call(p1, x),
147 y.assign(mul(x, constant(7)))
148 )
149 .build();
150 129
151 var store = ModelStore.builder() 130 var store = ModelStore.builder()
152 .symbols(person, age) 131 .symbols(person, age)
153 .with(ViatraModelQuery.ADAPTER) 132 .with(ViatraModelQueryAdapter.builder()
154 .defaultHint(hint) 133 .defaultHint(hint)
155 .queries(query) 134 .queries(query))
156 .build(); 135 .build();
157 136
158 var model = store.createEmptyModel(); 137 var model = store.createEmptyModel();
159 var personInterpretation = model.getInterpretation(person); 138 var personInterpretation = model.getInterpretation(person);
160 var ageInterpretation = model.getInterpretation(age); 139 var ageInterpretation = model.getInterpretation(age);
161 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 140 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
162 var queryResultSet = queryEngine.getResultSet(query); 141 var queryResultSet = queryEngine.getResultSet(query);
163 142
164 personInterpretation.put(Tuple.of(0), true); 143 personInterpretation.put(Tuple.of(0), true);
@@ -177,34 +156,22 @@ class FunctionalQueryTest {
177 156
178 @QueryEngineTest 157 @QueryEngineTest
179 void inputKeyCountTest(QueryEvaluationHint hint) { 158 void inputKeyCountTest(QueryEvaluationHint hint) {
180 var person = new Symbol<>("Person", 1, Boolean.class, false); 159 var query = Query.of("Count", Integer.class, (builder, p1, output) -> builder.clause(
181 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 160 personView.call(p1),
182 var personView = new KeyOnlyRelationView<>(person); 161 output.assign(friendMustView.count(p1, Variable.of()))
183 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 162 ));
184
185 var p1 = Variable.of("p1");
186 var p2 = Variable.of("p2");
187 var x = Variable.of("x", Integer.class);
188 var query = Query.builder("Count")
189 .parameter(p1)
190 .output(x)
191 .clause(
192 personView.call(p1),
193 x.assign(friendMustView.count(p1, p2))
194 )
195 .build();
196 163
197 var store = ModelStore.builder() 164 var store = ModelStore.builder()
198 .symbols(person, friend) 165 .symbols(person, friend)
199 .with(ViatraModelQuery.ADAPTER) 166 .with(ViatraModelQueryAdapter.builder()
200 .defaultHint(hint) 167 .defaultHint(hint)
201 .queries(query) 168 .queries(query))
202 .build(); 169 .build();
203 170
204 var model = store.createEmptyModel(); 171 var model = store.createEmptyModel();
205 var personInterpretation = model.getInterpretation(person); 172 var personInterpretation = model.getInterpretation(person);
206 var friendInterpretation = model.getInterpretation(friend); 173 var friendInterpretation = model.getInterpretation(friend);
207 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 174 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
208 var queryResultSet = queryEngine.getResultSet(query); 175 var queryResultSet = queryEngine.getResultSet(query);
209 176
210 personInterpretation.put(Tuple.of(0), true); 177 personInterpretation.put(Tuple.of(0), true);
@@ -226,42 +193,27 @@ class FunctionalQueryTest {
226 193
227 @QueryEngineTest 194 @QueryEngineTest
228 void predicateCountTest(QueryEvaluationHint hint) { 195 void predicateCountTest(QueryEvaluationHint hint) {
229 var person = new Symbol<>("Person", 1, Boolean.class, false); 196 var subQuery = Query.of("SubQuery", (builder, p1, p2) -> builder.clause(
230 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 197 personView.call(p1),
231 var personView = new KeyOnlyRelationView<>(person); 198 personView.call(p2),
232 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 199 friendMustView.call(p1, p2)
233 200 ));
234 var p1 = Variable.of("p1"); 201 var query = Query.of("Count", Integer.class, (builder, p1, output) -> builder.clause(
235 var p2 = Variable.of("p2"); 202 personView.call(p1),
236 var x = Variable.of("x", Integer.class); 203 output.assign(subQuery.count(p1, Variable.of()))
237 var subQuery = Dnf.builder("SubQuery") 204 ));
238 .parameters(p1, p2)
239 .clause(
240 personView.call(p1),
241 personView.call(p2),
242 friendMustView.call(p1, p2)
243 )
244 .build();
245 var query = Query.builder("Count")
246 .parameter(p1)
247 .output(x)
248 .clause(
249 personView.call(p1),
250 x.assign(subQuery.count(p1, p2))
251 )
252 .build();
253 205
254 var store = ModelStore.builder() 206 var store = ModelStore.builder()
255 .symbols(person, friend) 207 .symbols(person, friend)
256 .with(ViatraModelQuery.ADAPTER) 208 .with(ViatraModelQueryAdapter.builder()
257 .defaultHint(hint) 209 .defaultHint(hint)
258 .queries(query) 210 .queries(query))
259 .build(); 211 .build();
260 212
261 var model = store.createEmptyModel(); 213 var model = store.createEmptyModel();
262 var personInterpretation = model.getInterpretation(person); 214 var personInterpretation = model.getInterpretation(person);
263 var friendInterpretation = model.getInterpretation(friend); 215 var friendInterpretation = model.getInterpretation(friend);
264 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 216 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
265 var queryResultSet = queryEngine.getResultSet(query); 217 var queryResultSet = queryEngine.getResultSet(query);
266 218
267 personInterpretation.put(Tuple.of(0), true); 219 personInterpretation.put(Tuple.of(0), true);
@@ -283,29 +235,20 @@ class FunctionalQueryTest {
283 235
284 @QueryEngineTest 236 @QueryEngineTest
285 void inputKeyAggregationTest(QueryEvaluationHint hint) { 237 void inputKeyAggregationTest(QueryEvaluationHint hint) {
286 var age = new Symbol<>("age", 1, Integer.class, null); 238 var query = Query.of("Aggregate", Integer.class, (builder, output) -> builder.clause(
287 var ageView = new FunctionalRelationView<>(age); 239 output.assign(ageView.aggregate(INT_SUM, Variable.of()))
288 240 ));
289 var p1 = Variable.of("p1");
290 var x = Variable.of("x", Integer.class);
291 var y = Variable.of("y", Integer.class);
292 var query = Query.builder("Aggregate")
293 .output(x)
294 .clause(
295 x.assign(ageView.aggregate(y, INT_SUM, p1, y))
296 )
297 .build();
298 241
299 var store = ModelStore.builder() 242 var store = ModelStore.builder()
300 .symbols(age) 243 .symbols(age)
301 .with(ViatraModelQuery.ADAPTER) 244 .with(ViatraModelQueryAdapter.builder()
302 .defaultHint(hint) 245 .defaultHint(hint)
303 .queries(query) 246 .queries(query))
304 .build(); 247 .build();
305 248
306 var model = store.createEmptyModel(); 249 var model = store.createEmptyModel();
307 var ageInterpretation = model.getInterpretation(age); 250 var ageInterpretation = model.getInterpretation(age);
308 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 251 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
309 var queryResultSet = queryEngine.getResultSet(query); 252 var queryResultSet = queryEngine.getResultSet(query);
310 253
311 ageInterpretation.put(Tuple.of(0), 12); 254 ageInterpretation.put(Tuple.of(0), 12);
@@ -317,39 +260,25 @@ class FunctionalQueryTest {
317 260
318 @QueryEngineTest 261 @QueryEngineTest
319 void predicateAggregationTest(QueryEvaluationHint hint) { 262 void predicateAggregationTest(QueryEvaluationHint hint) {
320 var person = new Symbol<>("Person", 1, Boolean.class, false); 263 var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause(
321 var age = new Symbol<>("age", 1, Integer.class, null); 264 personView.call(p1),
322 var personView = new KeyOnlyRelationView<>(person); 265 ageView.call(p1, x)
323 var ageView = new FunctionalRelationView<>(age); 266 ));
324 267 var query = Query.of("Aggregate", Integer.class, (builder, output) -> builder.clause(
325 var p1 = Variable.of("p1"); 268 output.assign(subQuery.aggregate(INT_SUM, Variable.of()))
326 var x = Variable.of("x", Integer.class); 269 ));
327 var y = Variable.of("y", Integer.class);
328 var subQuery = Dnf.builder("SubQuery")
329 .parameters(p1, x)
330 .clause(
331 personView.call(p1),
332 ageView.call(p1, x)
333 )
334 .build();
335 var query = Query.builder("Aggregate")
336 .output(x)
337 .clause(
338 x.assign(subQuery.aggregate(y, INT_SUM, p1, y))
339 )
340 .build();
341 270
342 var store = ModelStore.builder() 271 var store = ModelStore.builder()
343 .symbols(person, age) 272 .symbols(person, age)
344 .with(ViatraModelQuery.ADAPTER) 273 .with(ViatraModelQueryAdapter.builder()
345 .defaultHint(hint) 274 .defaultHint(hint)
346 .queries(query) 275 .queries(query))
347 .build(); 276 .build();
348 277
349 var model = store.createEmptyModel(); 278 var model = store.createEmptyModel();
350 var personInterpretation = model.getInterpretation(person); 279 var personInterpretation = model.getInterpretation(person);
351 var ageInterpretation = model.getInterpretation(age); 280 var ageInterpretation = model.getInterpretation(age);
352 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 281 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
353 var queryResultSet = queryEngine.getResultSet(query); 282 var queryResultSet = queryEngine.getResultSet(query);
354 283
355 personInterpretation.put(Tuple.of(0), true); 284 personInterpretation.put(Tuple.of(0), true);
@@ -364,46 +293,28 @@ class FunctionalQueryTest {
364 293
365 @QueryEngineTest 294 @QueryEngineTest
366 void extremeValueTest(QueryEvaluationHint hint) { 295 void extremeValueTest(QueryEvaluationHint hint) {
367 var person = new Symbol<>("Person", 1, Boolean.class, false); 296 var subQuery = Query.of("SubQuery", Integer.class, (builder, p1, x) -> builder.clause(
368 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 297 personView.call(p1),
369 var personView = new KeyOnlyRelationView<>(person); 298 x.assign(friendMustView.count(p1, Variable.of()))
370 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 299 ));
371 300 var minQuery = Query.of("Min", Integer.class, (builder, output) -> builder.clause(
372 var p1 = Variable.of("p1"); 301 output.assign(subQuery.aggregate(INT_MIN, Variable.of()))
373 var p2 = Variable.of("p2"); 302 ));
374 var x = Variable.of("x", Integer.class); 303 var maxQuery = Query.of("Max", Integer.class, (builder, output) -> builder.clause(
375 var y = Variable.of("y", Integer.class); 304 output.assign(subQuery.aggregate(INT_MAX, Variable.of()))
376 var subQuery = Dnf.builder("SubQuery") 305 ));
377 .parameters(p1, x)
378 .clause(
379 personView.call(p1),
380 x.assign(friendMustView.count(p1, p2))
381 )
382 .build();
383 var minQuery = Query.builder("Min")
384 .output(x)
385 .clause(
386 x.assign(subQuery.aggregate(y, INT_MIN, p1, y))
387 )
388 .build();
389 var maxQuery = Query.builder("Max")
390 .output(x)
391 .clause(
392 x.assign(subQuery.aggregate(y, INT_MAX, p1, y))
393 )
394 .build();
395 306
396 var store = ModelStore.builder() 307 var store = ModelStore.builder()
397 .symbols(person, friend) 308 .symbols(person, friend)
398 .with(ViatraModelQuery.ADAPTER) 309 .with(ViatraModelQueryAdapter.builder()
399 .defaultHint(hint) 310 .defaultHint(hint)
400 .queries(minQuery, maxQuery) 311 .queries(minQuery, maxQuery))
401 .build(); 312 .build();
402 313
403 var model = store.createEmptyModel(); 314 var model = store.createEmptyModel();
404 var personInterpretation = model.getInterpretation(person); 315 var personInterpretation = model.getInterpretation(person);
405 var friendInterpretation = model.getInterpretation(friend); 316 var friendInterpretation = model.getInterpretation(friend);
406 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 317 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
407 var minResultSet = queryEngine.getResultSet(minQuery); 318 var minResultSet = queryEngine.getResultSet(minQuery);
408 var maxResultSet = queryEngine.getResultSet(maxQuery); 319 var maxResultSet = queryEngine.getResultSet(maxQuery);
409 320
@@ -440,35 +351,24 @@ class FunctionalQueryTest {
440 351
441 @QueryEngineTest 352 @QueryEngineTest
442 void invalidComputationTest(QueryEvaluationHint hint) { 353 void invalidComputationTest(QueryEvaluationHint hint) {
443 var person = new Symbol<>("Person", 1, Boolean.class, false); 354 var query = Query.of("InvalidComputation", Integer.class,
444 var age = new Symbol<>("age", 1, Integer.class, null); 355 (builder, p1, output) -> builder.clause(Integer.class, (x) -> List.of(
445 var personView = new KeyOnlyRelationView<>(person);
446 var ageView = new FunctionalRelationView<>(age);
447
448 var p1 = Variable.of("p1");
449 var x = Variable.of("x", Integer.class);
450 var y = Variable.of("y", Integer.class);
451 var query = Query.builder("InvalidComputation")
452 .parameter(p1)
453 .output(y)
454 .clause(
455 personView.call(p1), 356 personView.call(p1),
456 ageView.call(p1, x), 357 ageView.call(p1, x),
457 y.assign(div(constant(120), x)) 358 output.assign(div(constant(120), x))
458 ) 359 )));
459 .build();
460 360
461 var store = ModelStore.builder() 361 var store = ModelStore.builder()
462 .symbols(person, age) 362 .symbols(person, age)
463 .with(ViatraModelQuery.ADAPTER) 363 .with(ViatraModelQueryAdapter.builder()
464 .defaultHint(hint) 364 .defaultHint(hint)
465 .queries(query) 365 .queries(query))
466 .build(); 366 .build();
467 367
468 var model = store.createEmptyModel(); 368 var model = store.createEmptyModel();
469 var personInterpretation = model.getInterpretation(person); 369 var personInterpretation = model.getInterpretation(person);
470 var ageInterpretation = model.getInterpretation(age); 370 var ageInterpretation = model.getInterpretation(age);
471 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 371 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
472 var queryResultSet = queryEngine.getResultSet(query); 372 var queryResultSet = queryEngine.getResultSet(query);
473 373
474 personInterpretation.put(Tuple.of(0), true); 374 personInterpretation.put(Tuple.of(0), true);
@@ -487,33 +387,23 @@ class FunctionalQueryTest {
487 387
488 @QueryEngineTest 388 @QueryEngineTest
489 void invalidAssumeTest(QueryEvaluationHint hint) { 389 void invalidAssumeTest(QueryEvaluationHint hint) {
490 var person = new Symbol<>("Person", 1, Boolean.class, false); 390 var query = Query.of("InvalidAssume", (builder, p1) -> builder.clause(Integer.class, (x) -> List.of(
491 var age = new Symbol<>("age", 1, Integer.class, null); 391 personView.call(p1),
492 var personView = new KeyOnlyRelationView<>(person); 392 ageView.call(p1, x),
493 var ageView = new FunctionalRelationView<>(age); 393 assume(lessEq(div(constant(120), x), constant(5)))
494 394 )));
495 var p1 = Variable.of("p1");
496 var x = Variable.of("x", Integer.class);
497 var query = Query.builder("InvalidComputation")
498 .parameter(p1)
499 .clause(
500 personView.call(p1),
501 ageView.call(p1, x),
502 assume(lessEq(div(constant(120), x), constant(5)))
503 )
504 .build();
505 395
506 var store = ModelStore.builder() 396 var store = ModelStore.builder()
507 .symbols(person, age) 397 .symbols(person, age)
508 .with(ViatraModelQuery.ADAPTER) 398 .with(ViatraModelQueryAdapter.builder()
509 .defaultHint(hint) 399 .defaultHint(hint)
510 .queries(query) 400 .queries(query))
511 .build(); 401 .build();
512 402
513 var model = store.createEmptyModel(); 403 var model = store.createEmptyModel();
514 var personInterpretation = model.getInterpretation(person); 404 var personInterpretation = model.getInterpretation(person);
515 var ageInterpretation = model.getInterpretation(age); 405 var ageInterpretation = model.getInterpretation(age);
516 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 406 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
517 var queryResultSet = queryEngine.getResultSet(query); 407 var queryResultSet = queryEngine.getResultSet(query);
518 408
519 personInterpretation.put(Tuple.of(0), true); 409 personInterpretation.put(Tuple.of(0), true);
@@ -535,38 +425,24 @@ class FunctionalQueryTest {
535 425
536 @QueryEngineTest 426 @QueryEngineTest
537 void notFunctionalTest(QueryEvaluationHint hint) { 427 void notFunctionalTest(QueryEvaluationHint hint) {
538 var person = new Symbol<>("Person", 1, Boolean.class, false); 428 var query = Query.of("NotFunctional", Integer.class, (builder, p1, output) -> builder.clause((p2) -> List.of(
539 var age = new Symbol<>("age", 1, Integer.class, null); 429 personView.call(p1),
540 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 430 friendMustView.call(p1, p2),
541 var personView = new KeyOnlyRelationView<>(person); 431 ageView.call(p2, output)
542 var ageView = new FunctionalRelationView<>(age); 432 )));
543 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must);
544
545 var p1 = Variable.of("p1");
546 var p2 = Variable.of("p2");
547 var x = Variable.of("x", Integer.class);
548 var query = Query.builder("NotFunctional")
549 .parameter(p1)
550 .output(x)
551 .clause(
552 personView.call(p1),
553 friendMustView.call(p1, p2),
554 ageView.call(p2, x)
555 )
556 .build();
557 433
558 var store = ModelStore.builder() 434 var store = ModelStore.builder()
559 .symbols(person, age, friend) 435 .symbols(person, age, friend)
560 .with(ViatraModelQuery.ADAPTER) 436 .with(ViatraModelQueryAdapter.builder()
561 .defaultHint(hint) 437 .defaultHint(hint)
562 .query(query) 438 .queries(query))
563 .build(); 439 .build();
564 440
565 var model = store.createEmptyModel(); 441 var model = store.createEmptyModel();
566 var personInterpretation = model.getInterpretation(person); 442 var personInterpretation = model.getInterpretation(person);
567 var ageInterpretation = model.getInterpretation(age); 443 var ageInterpretation = model.getInterpretation(age);
568 var friendInterpretation = model.getInterpretation(friend); 444 var friendInterpretation = model.getInterpretation(friend);
569 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 445 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
570 var queryResultSet = queryEngine.getResultSet(query); 446 var queryResultSet = queryEngine.getResultSet(query);
571 447
572 personInterpretation.put(Tuple.of(0), true); 448 personInterpretation.put(Tuple.of(0), true);
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
index 8a3f9d88..297cdf04 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTest.java
@@ -1,23 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import org.junit.jupiter.api.Test; 9import org.junit.jupiter.api.Test;
5import tools.refinery.store.model.ModelStore; 10import tools.refinery.store.model.ModelStore;
6import tools.refinery.store.query.ModelQuery; 11import tools.refinery.store.query.ModelQueryAdapter;
7import tools.refinery.store.query.dnf.Dnf;
8import tools.refinery.store.query.dnf.Query; 12import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable; 13import tools.refinery.store.query.term.Variable;
10import tools.refinery.store.query.viatra.tests.QueryEngineTest; 14import tools.refinery.store.query.viatra.tests.QueryEngineTest;
11import tools.refinery.store.query.view.FilteredRelationView; 15import tools.refinery.store.query.view.AnySymbolView;
12import tools.refinery.store.query.view.FunctionalRelationView; 16import tools.refinery.store.query.view.FilteredView;
13import tools.refinery.store.query.view.KeyOnlyRelationView; 17import tools.refinery.store.query.view.FunctionView;
18import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol; 19import tools.refinery.store.representation.Symbol;
15import tools.refinery.store.representation.TruthValue; 20import tools.refinery.store.representation.TruthValue;
16import tools.refinery.store.tuple.Tuple; 21import tools.refinery.store.tuple.Tuple;
17 22
23import java.util.List;
18import java.util.Map; 24import java.util.Map;
19 25
20import static org.junit.jupiter.api.Assertions.assertThrows;
21import static tools.refinery.store.query.literal.Literals.assume; 26import static tools.refinery.store.query.literal.Literals.assume;
22import static tools.refinery.store.query.literal.Literals.not; 27import static tools.refinery.store.query.literal.Literals.not;
23import static tools.refinery.store.query.term.int_.IntTerms.constant; 28import static tools.refinery.store.query.term.int_.IntTerms.constant;
@@ -25,29 +30,28 @@ import static tools.refinery.store.query.term.int_.IntTerms.greaterEq;
25import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; 30import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
26 31
27class QueryTest { 32class QueryTest {
33 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
34 private static final Symbol<TruthValue> friend = Symbol.of("friend", 2, TruthValue.class, TruthValue.FALSE);
35 private static final AnySymbolView personView = new KeyOnlyView<>(person);
36 private static final AnySymbolView friendMustView = new FilteredView<>(friend, "must", TruthValue::must);
37
28 @QueryEngineTest 38 @QueryEngineTest
29 void typeConstraintTest(QueryEvaluationHint hint) { 39 void typeConstraintTest(QueryEvaluationHint hint) {
30 var person = new Symbol<>("Person", 1, Boolean.class, false); 40 var asset = Symbol.of("Asset", 1);
31 var asset = new Symbol<>("Asset", 1, Boolean.class, false); 41
32 var personView = new KeyOnlyRelationView<>(person); 42 var predicate = Query.of("TypeConstraint", (builder, p1) -> builder.clause(personView.call(p1)));
33
34 var p1 = Variable.of("p1");
35 var predicate = Query.builder("TypeConstraint")
36 .parameters(p1)
37 .clause(personView.call(p1))
38 .build();
39 43
40 var store = ModelStore.builder() 44 var store = ModelStore.builder()
41 .symbols(person, asset) 45 .symbols(person, asset)
42 .with(ViatraModelQuery.ADAPTER) 46 .with(ViatraModelQueryAdapter.builder()
43 .defaultHint(hint) 47 .defaultHint(hint)
44 .query(predicate) 48 .queries(predicate))
45 .build(); 49 .build();
46 50
47 var model = store.createEmptyModel(); 51 var model = store.createEmptyModel();
48 var personInterpretation = model.getInterpretation(person); 52 var personInterpretation = model.getInterpretation(person);
49 var assetInterpretation = model.getInterpretation(asset); 53 var assetInterpretation = model.getInterpretation(asset);
50 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 54 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
51 var predicateResultSet = queryEngine.getResultSet(predicate); 55 var predicateResultSet = queryEngine.getResultSet(predicate);
52 56
53 personInterpretation.put(Tuple.of(0), true); 57 personInterpretation.put(Tuple.of(0), true);
@@ -66,33 +70,23 @@ class QueryTest {
66 70
67 @QueryEngineTest 71 @QueryEngineTest
68 void relationConstraintTest(QueryEvaluationHint hint) { 72 void relationConstraintTest(QueryEvaluationHint hint) {
69 var person = new Symbol<>("Person", 1, Boolean.class, false); 73 var predicate = Query.of("RelationConstraint", (builder, p1, p2) -> builder.clause(
70 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 74 personView.call(p1),
71 var personView = new KeyOnlyRelationView<>(person); 75 personView.call(p2),
72 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 76 friendMustView.call(p1, p2)
73 77 ));
74 var p1 = Variable.of("p1");
75 var p2 = Variable.of("p2");
76 var predicate = Query.builder("RelationConstraint")
77 .parameters(p1, p2)
78 .clause(
79 personView.call(p1),
80 personView.call(p2),
81 friendMustView.call(p1, p2)
82 )
83 .build();
84 78
85 var store = ModelStore.builder() 79 var store = ModelStore.builder()
86 .symbols(person, friend) 80 .symbols(person, friend)
87 .with(ViatraModelQuery.ADAPTER) 81 .with(ViatraModelQueryAdapter.builder()
88 .defaultHint(hint) 82 .defaultHint(hint)
89 .queries(predicate) 83 .queries(predicate))
90 .build(); 84 .build();
91 85
92 var model = store.createEmptyModel(); 86 var model = store.createEmptyModel();
93 var personInterpretation = model.getInterpretation(person); 87 var personInterpretation = model.getInterpretation(person);
94 var friendInterpretation = model.getInterpretation(friend); 88 var friendInterpretation = model.getInterpretation(friend);
95 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 89 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
96 var predicateResultSet = queryEngine.getResultSet(predicate); 90 var predicateResultSet = queryEngine.getResultSet(predicate);
97 91
98 personInterpretation.put(Tuple.of(0), true); 92 personInterpretation.put(Tuple.of(0), true);
@@ -115,33 +109,23 @@ class QueryTest {
115 109
116 @QueryEngineTest 110 @QueryEngineTest
117 void existTest(QueryEvaluationHint hint) { 111 void existTest(QueryEvaluationHint hint) {
118 var person = new Symbol<>("Person", 1, Boolean.class, false); 112 var predicate = Query.of("Exists", (builder, p1) -> builder.clause((p2) -> List.of(
119 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 113 personView.call(p1),
120 var personView = new KeyOnlyRelationView<>(person); 114 personView.call(p2),
121 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 115 friendMustView.call(p1, p2)
122 116 )));
123 var p1 = Variable.of("p1");
124 var p2 = Variable.of("p2");
125 var predicate = Query.builder("RelationConstraint")
126 .parameters(p1)
127 .clause(
128 personView.call(p1),
129 personView.call(p2),
130 friendMustView.call(p1, p2)
131 )
132 .build();
133 117
134 var store = ModelStore.builder() 118 var store = ModelStore.builder()
135 .symbols(person, friend) 119 .symbols(person, friend)
136 .with(ViatraModelQuery.ADAPTER) 120 .with(ViatraModelQueryAdapter.builder()
137 .defaultHint(hint) 121 .defaultHint(hint)
138 .queries(predicate) 122 .queries(predicate))
139 .build(); 123 .build();
140 124
141 var model = store.createEmptyModel(); 125 var model = store.createEmptyModel();
142 var personInterpretation = model.getInterpretation(person); 126 var personInterpretation = model.getInterpretation(person);
143 var friendInterpretation = model.getInterpretation(friend); 127 var friendInterpretation = model.getInterpretation(friend);
144 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 128 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
145 var predicateResultSet = queryEngine.getResultSet(predicate); 129 var predicateResultSet = queryEngine.getResultSet(predicate);
146 130
147 personInterpretation.put(Tuple.of(0), true); 131 personInterpretation.put(Tuple.of(0), true);
@@ -164,41 +148,31 @@ class QueryTest {
164 148
165 @QueryEngineTest 149 @QueryEngineTest
166 void orTest(QueryEvaluationHint hint) { 150 void orTest(QueryEvaluationHint hint) {
167 var person = new Symbol<>("Person", 1, Boolean.class, false); 151 var animal = Symbol.of("Animal", 1);
168 var animal = new Symbol<>("Animal", 1, Boolean.class, false); 152 var animalView = new KeyOnlyView<>(animal);
169 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 153
170 var personView = new KeyOnlyRelationView<>(person); 154 var predicate = Query.of("Or", (builder, p1, p2) -> builder.clause(
171 var animalView = new KeyOnlyRelationView<>(animal); 155 personView.call(p1),
172 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 156 personView.call(p2),
173 157 friendMustView.call(p1, p2)
174 var p1 = Variable.of("p1"); 158 ).clause(
175 var p2 = Variable.of("p2"); 159 animalView.call(p1),
176 var predicate = Query.builder("Or") 160 animalView.call(p2),
177 .parameters(p1, p2) 161 friendMustView.call(p1, p2)
178 .clause( 162 ));
179 personView.call(p1),
180 personView.call(p2),
181 friendMustView.call(p1, p2)
182 )
183 .clause(
184 animalView.call(p1),
185 animalView.call(p2),
186 friendMustView.call(p1, p2)
187 )
188 .build();
189 163
190 var store = ModelStore.builder() 164 var store = ModelStore.builder()
191 .symbols(person, animal, friend) 165 .symbols(person, animal, friend)
192 .with(ViatraModelQuery.ADAPTER) 166 .with(ViatraModelQueryAdapter.builder()
193 .defaultHint(hint) 167 .defaultHint(hint)
194 .queries(predicate) 168 .queries(predicate))
195 .build(); 169 .build();
196 170
197 var model = store.createEmptyModel(); 171 var model = store.createEmptyModel();
198 var personInterpretation = model.getInterpretation(person); 172 var personInterpretation = model.getInterpretation(person);
199 var animalInterpretation = model.getInterpretation(animal); 173 var animalInterpretation = model.getInterpretation(animal);
200 var friendInterpretation = model.getInterpretation(friend); 174 var friendInterpretation = model.getInterpretation(friend);
201 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 175 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
202 var predicateResultSet = queryEngine.getResultSet(predicate); 176 var predicateResultSet = queryEngine.getResultSet(predicate);
203 177
204 personInterpretation.put(Tuple.of(0), true); 178 personInterpretation.put(Tuple.of(0), true);
@@ -224,30 +198,22 @@ class QueryTest {
224 198
225 @QueryEngineTest 199 @QueryEngineTest
226 void equalityTest(QueryEvaluationHint hint) { 200 void equalityTest(QueryEvaluationHint hint) {
227 var person = new Symbol<>("Person", 1, Boolean.class, false); 201 var predicate = Query.of("Equality", (builder, p1, p2) -> builder.clause(
228 var personView = new KeyOnlyRelationView<>(person); 202 personView.call(p1),
229 203 personView.call(p2),
230 var p1 = Variable.of("p1"); 204 p1.isEquivalent(p2)
231 var p2 = Variable.of("p2"); 205 ));
232 var predicate = Query.builder("Equality")
233 .parameters(p1, p2)
234 .clause(
235 personView.call(p1),
236 personView.call(p2),
237 p1.isEquivalent(p2)
238 )
239 .build();
240 206
241 var store = ModelStore.builder() 207 var store = ModelStore.builder()
242 .symbols(person) 208 .symbols(person)
243 .with(ViatraModelQuery.ADAPTER) 209 .with(ViatraModelQueryAdapter.builder()
244 .defaultHint(hint) 210 .defaultHint(hint)
245 .queries(predicate) 211 .queries(predicate))
246 .build(); 212 .build();
247 213
248 var model = store.createEmptyModel(); 214 var model = store.createEmptyModel();
249 var personInterpretation = model.getInterpretation(person); 215 var personInterpretation = model.getInterpretation(person);
250 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 216 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
251 var predicateResultSet = queryEngine.getResultSet(predicate); 217 var predicateResultSet = queryEngine.getResultSet(predicate);
252 218
253 personInterpretation.put(Tuple.of(0), true); 219 personInterpretation.put(Tuple.of(0), true);
@@ -266,36 +232,25 @@ class QueryTest {
266 232
267 @QueryEngineTest 233 @QueryEngineTest
268 void inequalityTest(QueryEvaluationHint hint) { 234 void inequalityTest(QueryEvaluationHint hint) {
269 var person = new Symbol<>("Person", 1, Boolean.class, false); 235 var predicate = Query.of("Inequality", (builder, p1, p2, p3) -> builder.clause(
270 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 236 personView.call(p1),
271 var personView = new KeyOnlyRelationView<>(person); 237 personView.call(p2),
272 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 238 friendMustView.call(p1, p3),
273 239 friendMustView.call(p2, p3),
274 var p1 = Variable.of("p1"); 240 p1.notEquivalent(p2)
275 var p2 = Variable.of("p2"); 241 ));
276 var p3 = Variable.of("p3");
277 var predicate = Query.builder("Inequality")
278 .parameters(p1, p2, p3)
279 .clause(
280 personView.call(p1),
281 personView.call(p2),
282 friendMustView.call(p1, p3),
283 friendMustView.call(p2, p3),
284 p1.notEquivalent(p2)
285 )
286 .build();
287 242
288 var store = ModelStore.builder() 243 var store = ModelStore.builder()
289 .symbols(person, friend) 244 .symbols(person, friend)
290 .with(ViatraModelQuery.ADAPTER) 245 .with(ViatraModelQueryAdapter.builder()
291 .defaultHint(hint) 246 .defaultHint(hint)
292 .queries(predicate) 247 .queries(predicate))
293 .build(); 248 .build();
294 249
295 var model = store.createEmptyModel(); 250 var model = store.createEmptyModel();
296 var personInterpretation = model.getInterpretation(person); 251 var personInterpretation = model.getInterpretation(person);
297 var friendInterpretation = model.getInterpretation(friend); 252 var friendInterpretation = model.getInterpretation(friend);
298 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 253 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
299 var predicateResultSet = queryEngine.getResultSet(predicate); 254 var predicateResultSet = queryEngine.getResultSet(predicate);
300 255
301 personInterpretation.put(Tuple.of(0), true); 256 personInterpretation.put(Tuple.of(0), true);
@@ -315,44 +270,28 @@ class QueryTest {
315 270
316 @QueryEngineTest 271 @QueryEngineTest
317 void patternCallTest(QueryEvaluationHint hint) { 272 void patternCallTest(QueryEvaluationHint hint) {
318 var person = new Symbol<>("Person", 1, Boolean.class, false); 273 var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause(
319 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 274 personView.call(p1),
320 var personView = new KeyOnlyRelationView<>(person); 275 personView.call(p2),
321 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 276 friendMustView.call(p1, p2)
322 277 ));
323 var p1 = Variable.of("p1"); 278 var predicate = Query.of("PositivePatternCall", (builder, p3, p4) -> builder.clause(
324 var p2 = Variable.of("p2"); 279 personView.call(p3),
325 var friendPredicate = Dnf.builder("RelationConstraint") 280 personView.call(p4),
326 .parameters(p1, p2) 281 friendPredicate.call(p3, p4)
327 .clause( 282 ));
328 personView.call(p1),
329 personView.call(p2),
330 friendMustView.call(p1, p2)
331 )
332 .build();
333
334 var p3 = Variable.of("p3");
335 var p4 = Variable.of("p4");
336 var predicate = Query.builder("PositivePatternCall")
337 .parameters(p3, p4)
338 .clause(
339 personView.call(p3),
340 personView.call(p4),
341 friendPredicate.call(p3, p4)
342 )
343 .build();
344 283
345 var store = ModelStore.builder() 284 var store = ModelStore.builder()
346 .symbols(person, friend) 285 .symbols(person, friend)
347 .with(ViatraModelQuery.ADAPTER) 286 .with(ViatraModelQueryAdapter.builder()
348 .defaultHint(hint) 287 .defaultHint(hint)
349 .queries(predicate) 288 .queries(predicate))
350 .build(); 289 .build();
351 290
352 var model = store.createEmptyModel(); 291 var model = store.createEmptyModel();
353 var personInterpretation = model.getInterpretation(person); 292 var personInterpretation = model.getInterpretation(person);
354 var friendInterpretation = model.getInterpretation(friend); 293 var friendInterpretation = model.getInterpretation(friend);
355 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 294 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
356 var predicateResultSet = queryEngine.getResultSet(predicate); 295 var predicateResultSet = queryEngine.getResultSet(predicate);
357 296
358 personInterpretation.put(Tuple.of(0), true); 297 personInterpretation.put(Tuple.of(0), true);
@@ -374,33 +313,23 @@ class QueryTest {
374 313
375 @QueryEngineTest 314 @QueryEngineTest
376 void negativeRelationViewTest(QueryEvaluationHint hint) { 315 void negativeRelationViewTest(QueryEvaluationHint hint) {
377 var person = new Symbol<>("Person", 1, Boolean.class, false); 316 var predicate = Query.of("NegativePatternCall", (builder, p1, p2) -> builder.clause(
378 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 317 personView.call(p1),
379 var personView = new KeyOnlyRelationView<>(person); 318 personView.call(p2),
380 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 319 not(friendMustView.call(p1, p2))
381 320 ));
382 var p1 = Variable.of("p1");
383 var p2 = Variable.of("p2");
384 var predicate = Query.builder("NegativePatternCall")
385 .parameters(p1, p2)
386 .clause(
387 personView.call(p1),
388 personView.call(p2),
389 not(friendMustView.call(p1, p2))
390 )
391 .build();
392 321
393 var store = ModelStore.builder() 322 var store = ModelStore.builder()
394 .symbols(person, friend) 323 .symbols(person, friend)
395 .with(ViatraModelQuery.ADAPTER) 324 .with(ViatraModelQueryAdapter.builder()
396 .defaultHint(hint) 325 .defaultHint(hint)
397 .queries(predicate) 326 .queries(predicate))
398 .build(); 327 .build();
399 328
400 var model = store.createEmptyModel(); 329 var model = store.createEmptyModel();
401 var personInterpretation = model.getInterpretation(person); 330 var personInterpretation = model.getInterpretation(person);
402 var friendInterpretation = model.getInterpretation(friend); 331 var friendInterpretation = model.getInterpretation(friend);
403 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 332 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
404 var predicateResultSet = queryEngine.getResultSet(predicate); 333 var predicateResultSet = queryEngine.getResultSet(predicate);
405 334
406 personInterpretation.put(Tuple.of(0), true); 335 personInterpretation.put(Tuple.of(0), true);
@@ -428,44 +357,28 @@ class QueryTest {
428 357
429 @QueryEngineTest 358 @QueryEngineTest
430 void negativePatternCallTest(QueryEvaluationHint hint) { 359 void negativePatternCallTest(QueryEvaluationHint hint) {
431 var person = new Symbol<>("Person", 1, Boolean.class, false); 360 var friendPredicate = Query.of("Friend", (builder, p1, p2) -> builder.clause(
432 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 361 personView.call(p1),
433 var personView = new KeyOnlyRelationView<>(person); 362 personView.call(p2),
434 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 363 friendMustView.call(p1, p2)
435 364 ));
436 var p1 = Variable.of("p1"); 365 var predicate = Query.of("NegativePatternCall", (builder, p3, p4) -> builder.clause(
437 var p2 = Variable.of("p2"); 366 personView.call(p3),
438 var friendPredicate = Dnf.builder("RelationConstraint") 367 personView.call(p4),
439 .parameters(p1, p2) 368 not(friendPredicate.call(p3, p4))
440 .clause( 369 ));
441 personView.call(p1),
442 personView.call(p2),
443 friendMustView.call(p1, p2)
444 )
445 .build();
446
447 var p3 = Variable.of("p3");
448 var p4 = Variable.of("p4");
449 var predicate = Query.builder("NegativePatternCall")
450 .parameters(p3, p4)
451 .clause(
452 personView.call(p3),
453 personView.call(p4),
454 not(friendPredicate.call(p3, p4))
455 )
456 .build();
457 370
458 var store = ModelStore.builder() 371 var store = ModelStore.builder()
459 .symbols(person, friend) 372 .symbols(person, friend)
460 .with(ViatraModelQuery.ADAPTER) 373 .with(ViatraModelQueryAdapter.builder()
461 .defaultHint(hint) 374 .defaultHint(hint)
462 .queries(predicate) 375 .queries(predicate))
463 .build(); 376 .build();
464 377
465 var model = store.createEmptyModel(); 378 var model = store.createEmptyModel();
466 var personInterpretation = model.getInterpretation(person); 379 var personInterpretation = model.getInterpretation(person);
467 var friendInterpretation = model.getInterpretation(friend); 380 var friendInterpretation = model.getInterpretation(friend);
468 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 381 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
469 var predicateResultSet = queryEngine.getResultSet(predicate); 382 var predicateResultSet = queryEngine.getResultSet(predicate);
470 383
471 personInterpretation.put(Tuple.of(0), true); 384 personInterpretation.put(Tuple.of(0), true);
@@ -493,33 +406,22 @@ class QueryTest {
493 406
494 @QueryEngineTest 407 @QueryEngineTest
495 void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) { 408 void negativeRelationViewWithQuantificationTest(QueryEvaluationHint hint) {
496 var person = new Symbol<>("Person", 1, Boolean.class, false); 409 var predicate = Query.of("Negative", (builder, p1) -> builder.clause(
497 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 410 personView.call(p1),
498 var personView = new KeyOnlyRelationView<>(person); 411 not(friendMustView.call(p1, Variable.of()))
499 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 412 ));
500
501 var p1 = Variable.of("p1");
502 var p2 = Variable.of("p2");
503
504 var predicate = Query.builder("Count")
505 .parameters(p1)
506 .clause(
507 personView.call(p1),
508 not(friendMustView.call(p1, p2))
509 )
510 .build();
511 413
512 var store = ModelStore.builder() 414 var store = ModelStore.builder()
513 .symbols(person, friend) 415 .symbols(person, friend)
514 .with(ViatraModelQuery.ADAPTER) 416 .with(ViatraModelQueryAdapter.builder()
515 .defaultHint(hint) 417 .defaultHint(hint)
516 .queries(predicate) 418 .queries(predicate))
517 .build(); 419 .build();
518 420
519 var model = store.createEmptyModel(); 421 var model = store.createEmptyModel();
520 var personInterpretation = model.getInterpretation(person); 422 var personInterpretation = model.getInterpretation(person);
521 var friendInterpretation = model.getInterpretation(friend); 423 var friendInterpretation = model.getInterpretation(friend);
522 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 424 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
523 var predicateResultSet = queryEngine.getResultSet(predicate); 425 var predicateResultSet = queryEngine.getResultSet(predicate);
524 426
525 personInterpretation.put(Tuple.of(0), true); 427 personInterpretation.put(Tuple.of(0), true);
@@ -540,42 +442,27 @@ class QueryTest {
540 442
541 @QueryEngineTest 443 @QueryEngineTest
542 void negativeWithQuantificationTest(QueryEvaluationHint hint) { 444 void negativeWithQuantificationTest(QueryEvaluationHint hint) {
543 var person = new Symbol<>("Person", 1, Boolean.class, false); 445 var called = Query.of("Called", (builder, p1, p2) -> builder.clause(
544 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 446 personView.call(p1),
545 var personView = new KeyOnlyRelationView<>(person); 447 personView.call(p2),
546 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 448 friendMustView.call(p1, p2)
547 449 ));
548 var p1 = Variable.of("p1"); 450 var predicate = Query.of("Negative", (builder, p1) -> builder.clause(
549 var p2 = Variable.of("p2"); 451 personView.call(p1),
550 452 not(called.call(p1, Variable.of()))
551 var called = Dnf.builder("Called") 453 ));
552 .parameters(p1, p2)
553 .clause(
554 personView.call(p1),
555 personView.call(p2),
556 friendMustView.call(p1, p2)
557 )
558 .build();
559
560 var predicate = Query.builder("Count")
561 .parameters(p1)
562 .clause(
563 personView.call(p1),
564 not(called.call(p1, p2))
565 )
566 .build();
567 454
568 var store = ModelStore.builder() 455 var store = ModelStore.builder()
569 .symbols(person, friend) 456 .symbols(person, friend)
570 .with(ViatraModelQuery.ADAPTER) 457 .with(ViatraModelQueryAdapter.builder()
571 .defaultHint(hint) 458 .defaultHint(hint)
572 .queries(predicate) 459 .queries(predicate))
573 .build(); 460 .build();
574 461
575 var model = store.createEmptyModel(); 462 var model = store.createEmptyModel();
576 var personInterpretation = model.getInterpretation(person); 463 var personInterpretation = model.getInterpretation(person);
577 var friendInterpretation = model.getInterpretation(friend); 464 var friendInterpretation = model.getInterpretation(friend);
578 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 465 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
579 var predicateResultSet = queryEngine.getResultSet(predicate); 466 var predicateResultSet = queryEngine.getResultSet(predicate);
580 467
581 personInterpretation.put(Tuple.of(0), true); 468 personInterpretation.put(Tuple.of(0), true);
@@ -596,33 +483,23 @@ class QueryTest {
596 483
597 @QueryEngineTest 484 @QueryEngineTest
598 void transitiveRelationViewTest(QueryEvaluationHint hint) { 485 void transitiveRelationViewTest(QueryEvaluationHint hint) {
599 var person = new Symbol<>("Person", 1, Boolean.class, false); 486 var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause(
600 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 487 personView.call(p1),
601 var personView = new KeyOnlyRelationView<>(person); 488 personView.call(p2),
602 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 489 friendMustView.callTransitive(p1, p2)
603 490 ));
604 var p1 = Variable.of("p1");
605 var p2 = Variable.of("p2");
606 var predicate = Query.builder("TransitivePatternCall")
607 .parameters(p1, p2)
608 .clause(
609 personView.call(p1),
610 personView.call(p2),
611 friendMustView.callTransitive(p1, p2)
612 )
613 .build();
614 491
615 var store = ModelStore.builder() 492 var store = ModelStore.builder()
616 .symbols(person, friend) 493 .symbols(person, friend)
617 .with(ViatraModelQuery.ADAPTER) 494 .with(ViatraModelQueryAdapter.builder()
618 .defaultHint(hint) 495 .defaultHint(hint)
619 .queries(predicate) 496 .queries(predicate))
620 .build(); 497 .build();
621 498
622 var model = store.createEmptyModel(); 499 var model = store.createEmptyModel();
623 var personInterpretation = model.getInterpretation(person); 500 var personInterpretation = model.getInterpretation(person);
624 var friendInterpretation = model.getInterpretation(friend); 501 var friendInterpretation = model.getInterpretation(friend);
625 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 502 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
626 var predicateResultSet = queryEngine.getResultSet(predicate); 503 var predicateResultSet = queryEngine.getResultSet(predicate);
627 504
628 personInterpretation.put(Tuple.of(0), true); 505 personInterpretation.put(Tuple.of(0), true);
@@ -649,44 +526,28 @@ class QueryTest {
649 526
650 @QueryEngineTest 527 @QueryEngineTest
651 void transitivePatternCallTest(QueryEvaluationHint hint) { 528 void transitivePatternCallTest(QueryEvaluationHint hint) {
652 var person = new Symbol<>("Person", 1, Boolean.class, false); 529 var called = Query.of("Called", (builder, p1, p2) -> builder.clause(
653 var friend = new Symbol<>("friend", 2, TruthValue.class, TruthValue.FALSE); 530 personView.call(p1),
654 var personView = new KeyOnlyRelationView<>(person); 531 personView.call(p2),
655 var friendMustView = new FilteredRelationView<>(friend, "must", TruthValue::must); 532 friendMustView.call(p1, p2)
656 533 ));
657 var p1 = Variable.of("p1"); 534 var predicate = Query.of("Transitive", (builder, p1, p2) -> builder.clause(
658 var p2 = Variable.of("p2"); 535 personView.call(p1),
659 var friendPredicate = Dnf.builder("RelationConstraint") 536 personView.call(p2),
660 .parameters(p1, p2) 537 called.callTransitive(p1, p2)
661 .clause( 538 ));
662 personView.call(p1),
663 personView.call(p2),
664 friendMustView.call(p1, p2)
665 )
666 .build();
667
668 var p3 = Variable.of("p3");
669 var p4 = Variable.of("p4");
670 var predicate = Query.builder("TransitivePatternCall")
671 .parameters(p3, p4)
672 .clause(
673 personView.call(p3),
674 personView.call(p4),
675 friendPredicate.callTransitive(p3, p4)
676 )
677 .build();
678 539
679 var store = ModelStore.builder() 540 var store = ModelStore.builder()
680 .symbols(person, friend) 541 .symbols(person, friend)
681 .with(ViatraModelQuery.ADAPTER) 542 .with(ViatraModelQueryAdapter.builder()
682 .defaultHint(hint) 543 .defaultHint(hint)
683 .queries(predicate) 544 .queries(predicate))
684 .build(); 545 .build();
685 546
686 var model = store.createEmptyModel(); 547 var model = store.createEmptyModel();
687 var personInterpretation = model.getInterpretation(person); 548 var personInterpretation = model.getInterpretation(person);
688 var friendInterpretation = model.getInterpretation(friend); 549 var friendInterpretation = model.getInterpretation(friend);
689 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 550 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
690 var predicateResultSet = queryEngine.getResultSet(predicate); 551 var predicateResultSet = queryEngine.getResultSet(predicate);
691 552
692 personInterpretation.put(Tuple.of(0), true); 553 personInterpretation.put(Tuple.of(0), true);
@@ -713,33 +574,26 @@ class QueryTest {
713 574
714 @QueryEngineTest 575 @QueryEngineTest
715 void assumeTest(QueryEvaluationHint hint) { 576 void assumeTest(QueryEvaluationHint hint) {
716 var person = new Symbol<>("Person", 1, Boolean.class, false); 577 var age = Symbol.of("age", 1, Integer.class);
717 var age = new Symbol<>("age", 1, Integer.class, null); 578 var ageView = new FunctionView<>(age);
718 var personView = new KeyOnlyRelationView<>(person); 579
719 var ageView = new FunctionalRelationView<>(age); 580 var query = Query.of("Constraint", (builder, p1) -> builder.clause(Integer.class, (x) -> List.of(
720 581 personView.call(p1),
721 var p1 = Variable.of("p1"); 582 ageView.call(p1, x),
722 var x = Variable.of("x", Integer.class); 583 assume(greaterEq(x, constant(18)))
723 var query = Query.builder("Constraint") 584 )));
724 .parameter(p1)
725 .clause(
726 personView.call(p1),
727 ageView.call(p1, x),
728 assume(greaterEq(x, constant(18)))
729 )
730 .build();
731 585
732 var store = ModelStore.builder() 586 var store = ModelStore.builder()
733 .symbols(person, age) 587 .symbols(person, age)
734 .with(ViatraModelQuery.ADAPTER) 588 .with(ViatraModelQueryAdapter.builder()
735 .defaultHint(hint) 589 .defaultHint(hint)
736 .queries(query) 590 .queries(query))
737 .build(); 591 .build();
738 592
739 var model = store.createEmptyModel(); 593 var model = store.createEmptyModel();
740 var personInterpretation = model.getInterpretation(person); 594 var personInterpretation = model.getInterpretation(person);
741 var ageInterpretation = model.getInterpretation(age); 595 var ageInterpretation = model.getInterpretation(age);
742 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 596 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
743 var queryResultSet = queryEngine.getResultSet(query); 597 var queryResultSet = queryEngine.getResultSet(query);
744 598
745 personInterpretation.put(Tuple.of(0), true); 599 personInterpretation.put(Tuple.of(0), true);
@@ -758,20 +612,17 @@ class QueryTest {
758 612
759 @Test 613 @Test
760 void alwaysFalseTest() { 614 void alwaysFalseTest() {
761 var person = new Symbol<>("Person", 1, Boolean.class, false); 615 var predicate = Query.of("AlwaysFalse", builder -> builder.parameter("p1"));
762
763 var p1 = Variable.of("p1");
764 var predicate = Query.builder("AlwaysFalse").parameters(p1).build();
765 616
766 var store = ModelStore.builder() 617 var store = ModelStore.builder()
767 .symbols(person) 618 .symbols(person)
768 .with(ViatraModelQuery.ADAPTER) 619 .with(ViatraModelQueryAdapter.builder()
769 .queries(predicate) 620 .queries(predicate))
770 .build(); 621 .build();
771 622
772 var model = store.createEmptyModel(); 623 var model = store.createEmptyModel();
773 var personInterpretation = model.getInterpretation(person); 624 var personInterpretation = model.getInterpretation(person);
774 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 625 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
775 var predicateResultSet = queryEngine.getResultSet(predicate); 626 var predicateResultSet = queryEngine.getResultSet(predicate);
776 627
777 personInterpretation.put(Tuple.of(0), true); 628 personInterpretation.put(Tuple.of(0), true);
@@ -781,17 +632,4 @@ class QueryTest {
781 queryEngine.flushChanges(); 632 queryEngine.flushChanges();
782 assertResults(Map.of(), predicateResultSet); 633 assertResults(Map.of(), predicateResultSet);
783 } 634 }
784
785 @Test
786 void alwaysTrueTest() {
787 var person = new Symbol<>("Person", 1, Boolean.class, false);
788
789 var p1 = Variable.of("p1");
790 var predicate = Query.builder("AlwaysTrue").parameters(p1).clause().build();
791
792 var storeBuilder = ModelStore.builder().symbols(person);
793 var queryBuilder = storeBuilder.with(ViatraModelQuery.ADAPTER);
794
795 assertThrows(IllegalArgumentException.class, () -> queryBuilder.queries(predicate));
796 }
797} 635}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
index abd49341..66f043c6 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/QueryTransactionTest.java
@@ -1,15 +1,21 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra; 6package tools.refinery.store.query.viatra;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
4import org.junit.jupiter.api.Disabled; 9import org.junit.jupiter.api.Disabled;
5import org.junit.jupiter.api.Test; 10import org.junit.jupiter.api.Test;
6import tools.refinery.store.model.ModelStore; 11import tools.refinery.store.model.ModelStore;
7import tools.refinery.store.query.ModelQuery; 12import tools.refinery.store.query.ModelQueryAdapter;
8import tools.refinery.store.query.dnf.Query; 13import tools.refinery.store.query.dnf.Query;
9import tools.refinery.store.query.term.Variable; 14import tools.refinery.store.query.dnf.RelationalQuery;
10import tools.refinery.store.query.view.FilteredRelationView; 15import tools.refinery.store.query.view.AnySymbolView;
11import tools.refinery.store.query.view.FunctionalRelationView; 16import tools.refinery.store.query.view.FilteredView;
12import tools.refinery.store.query.view.KeyOnlyRelationView; 17import tools.refinery.store.query.view.FunctionView;
18import tools.refinery.store.query.view.KeyOnlyView;
13import tools.refinery.store.representation.Symbol; 19import tools.refinery.store.representation.Symbol;
14import tools.refinery.store.tuple.Tuple; 20import tools.refinery.store.tuple.Tuple;
15 21
@@ -22,26 +28,24 @@ import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertNull
22import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults; 28import static tools.refinery.store.query.viatra.tests.QueryAssertions.assertResults;
23 29
24class QueryTransactionTest { 30class QueryTransactionTest {
31 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
32 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
33 private static final AnySymbolView personView = new KeyOnlyView<>(person);
34 private static final AnySymbolView ageView = new FunctionView<>(age);
35 private static final RelationalQuery predicate = Query.of("TypeConstraint", (builder, p1) ->
36 builder.clause(personView.call(p1)));
37
25 @Test 38 @Test
26 void flushTest() { 39 void flushTest() {
27 var person = new Symbol<>("Person", 1, Boolean.class, false);
28 var personView = new KeyOnlyRelationView<>(person);
29
30 var p1 = Variable.of("p1");
31 var predicate = Query.builder("TypeConstraint")
32 .parameters(p1)
33 .clause(personView.call(p1))
34 .build();
35
36 var store = ModelStore.builder() 40 var store = ModelStore.builder()
37 .symbols(person) 41 .symbols(person)
38 .with(ViatraModelQuery.ADAPTER) 42 .with(ViatraModelQueryAdapter.builder()
39 .queries(predicate) 43 .queries(predicate))
40 .build(); 44 .build();
41 45
42 var model = store.createEmptyModel(); 46 var model = store.createEmptyModel();
43 var personInterpretation = model.getInterpretation(person); 47 var personInterpretation = model.getInterpretation(person);
44 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 48 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
45 var predicateResultSet = queryEngine.getResultSet(predicate); 49 var predicateResultSet = queryEngine.getResultSet(predicate);
46 50
47 assertResults(Map.of( 51 assertResults(Map.of(
@@ -95,25 +99,16 @@ class QueryTransactionTest {
95 99
96 @Test 100 @Test
97 void localSearchTest() { 101 void localSearchTest() {
98 var person = new Symbol<>("Person", 1, Boolean.class, false);
99 var personView = new KeyOnlyRelationView<>(person);
100
101 var p1 = Variable.of("p1");
102 var predicate = Query.builder("TypeConstraint")
103 .parameters(p1)
104 .clause(personView.call(p1))
105 .build();
106
107 var store = ModelStore.builder() 102 var store = ModelStore.builder()
108 .symbols(person) 103 .symbols(person)
109 .with(ViatraModelQuery.ADAPTER) 104 .with(ViatraModelQueryAdapter.builder()
110 .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH)) 105 .defaultHint(new QueryEvaluationHint(null, QueryEvaluationHint.BackendRequirement.DEFAULT_SEARCH))
111 .queries(predicate) 106 .queries(predicate))
112 .build(); 107 .build();
113 108
114 var model = store.createEmptyModel(); 109 var model = store.createEmptyModel();
115 var personInterpretation = model.getInterpretation(person); 110 var personInterpretation = model.getInterpretation(person);
116 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 111 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
117 var predicateResultSet = queryEngine.getResultSet(predicate); 112 var predicateResultSet = queryEngine.getResultSet(predicate);
118 113
119 assertResults(Map.of( 114 assertResults(Map.of(
@@ -149,26 +144,18 @@ class QueryTransactionTest {
149 144
150 @Test 145 @Test
151 void unrelatedChangesTest() { 146 void unrelatedChangesTest() {
152 var person = new Symbol<>("Person", 1, Boolean.class, false); 147 var asset = Symbol.of("Asset", 1);
153 var asset = new Symbol<>("Asset", 1, Boolean.class, false);
154 var personView = new KeyOnlyRelationView<>(person);
155
156 var p1 = Variable.of("p1");
157 var predicate = Query.builder("TypeConstraint")
158 .parameters(p1)
159 .clause(personView.call(p1))
160 .build();
161 148
162 var store = ModelStore.builder() 149 var store = ModelStore.builder()
163 .symbols(person, asset) 150 .symbols(person, asset)
164 .with(ViatraModelQuery.ADAPTER) 151 .with(ViatraModelQueryAdapter.builder()
165 .queries(predicate) 152 .queries(predicate))
166 .build(); 153 .build();
167 154
168 var model = store.createEmptyModel(); 155 var model = store.createEmptyModel();
169 var personInterpretation = model.getInterpretation(person); 156 var personInterpretation = model.getInterpretation(person);
170 var assetInterpretation = model.getInterpretation(asset); 157 var assetInterpretation = model.getInterpretation(asset);
171 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 158 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
172 var predicateResultSet = queryEngine.getResultSet(predicate); 159 var predicateResultSet = queryEngine.getResultSet(predicate);
173 160
174 assertFalse(queryEngine.hasPendingChanges()); 161 assertFalse(queryEngine.hasPendingChanges());
@@ -222,32 +209,21 @@ class QueryTransactionTest {
222 209
223 @Test 210 @Test
224 void tupleChangingChangeTest() { 211 void tupleChangingChangeTest() {
225 var person = new Symbol<>("Person", 1, Boolean.class, false); 212 var query = Query.of("TypeConstraint", Integer.class, (builder, p1, output) -> builder.clause(
226 var age = new Symbol<>("age", 1, Integer.class, null); 213 personView.call(p1),
227 var personView = new KeyOnlyRelationView<>(person); 214 ageView.call(p1, output)
228 var ageView = new FunctionalRelationView<>(age); 215 ));
229
230 var p1 = Variable.of("p1");
231 var x = Variable.of("x", Integer.class);
232 var query = Query.builder()
233 .parameter(p1)
234 .output(x)
235 .clause(
236 personView.call(p1),
237 ageView.call(p1, x)
238 )
239 .build();
240 216
241 var store = ModelStore.builder() 217 var store = ModelStore.builder()
242 .symbols(person, age) 218 .symbols(person, age)
243 .with(ViatraModelQuery.ADAPTER) 219 .with(ViatraModelQueryAdapter.builder()
244 .query(query) 220 .queries(query))
245 .build(); 221 .build();
246 222
247 var model = store.createEmptyModel(); 223 var model = store.createEmptyModel();
248 var personInterpretation = model.getInterpretation(person); 224 var personInterpretation = model.getInterpretation(person);
249 var ageInterpretation = model.getInterpretation(age); 225 var ageInterpretation = model.getInterpretation(age);
250 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 226 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
251 var queryResultSet = queryEngine.getResultSet(query); 227 var queryResultSet = queryEngine.getResultSet(query);
252 228
253 personInterpretation.put(Tuple.of(0), true); 229 personInterpretation.put(Tuple.of(0), true);
@@ -270,31 +246,23 @@ class QueryTransactionTest {
270 246
271 @Test 247 @Test
272 void tuplePreservingUnchangedTest() { 248 void tuplePreservingUnchangedTest() {
273 var person = new Symbol<>("Person", 1, Boolean.class, false); 249 var adultView = new FilteredView<>(age, "adult", n -> n != null && n >= 18);
274 var age = new Symbol<>("age", 1, Integer.class, null); 250
275 var personView = new KeyOnlyRelationView<>(person); 251 var query = Query.of("TypeConstraint", (builder, p1) -> builder.clause(
276 var adultView = new FilteredRelationView<>(age, "adult", n -> n != null && n >= 18); 252 personView.call(p1),
277 253 adultView.call(p1)
278 var p1 = Variable.of("p1"); 254 ));
279 var x = Variable.of("x", Integer.class);
280 var query = Query.builder()
281 .parameter(p1)
282 .clause(
283 personView.call(p1),
284 adultView.call(p1)
285 )
286 .build();
287 255
288 var store = ModelStore.builder() 256 var store = ModelStore.builder()
289 .symbols(person, age) 257 .symbols(person, age)
290 .with(ViatraModelQuery.ADAPTER) 258 .with(ViatraModelQueryAdapter.builder()
291 .query(query) 259 .queries(query))
292 .build(); 260 .build();
293 261
294 var model = store.createEmptyModel(); 262 var model = store.createEmptyModel();
295 var personInterpretation = model.getInterpretation(person); 263 var personInterpretation = model.getInterpretation(person);
296 var ageInterpretation = model.getInterpretation(age); 264 var ageInterpretation = model.getInterpretation(age);
297 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 265 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
298 var queryResultSet = queryEngine.getResultSet(query); 266 var queryResultSet = queryEngine.getResultSet(query);
299 267
300 personInterpretation.put(Tuple.of(0), true); 268 personInterpretation.put(Tuple.of(0), true);
@@ -318,24 +286,15 @@ class QueryTransactionTest {
318 @Disabled("TODO Fix DiffCursor") 286 @Disabled("TODO Fix DiffCursor")
319 @Test 287 @Test
320 void commitAfterFlushTest() { 288 void commitAfterFlushTest() {
321 var person = new Symbol<>("Person", 1, Boolean.class, false);
322 var personView = new KeyOnlyRelationView<>(person);
323
324 var p1 = Variable.of("p1");
325 var predicate = Query.builder("TypeConstraint")
326 .parameters(p1)
327 .clause(personView.call(p1))
328 .build();
329
330 var store = ModelStore.builder() 289 var store = ModelStore.builder()
331 .symbols(person) 290 .symbols(person)
332 .with(ViatraModelQuery.ADAPTER) 291 .with(ViatraModelQueryAdapter.builder()
333 .queries(predicate) 292 .queries(predicate))
334 .build(); 293 .build();
335 294
336 var model = store.createEmptyModel(); 295 var model = store.createEmptyModel();
337 var personInterpretation = model.getInterpretation(person); 296 var personInterpretation = model.getInterpretation(person);
338 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 297 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
339 var predicateResultSet = queryEngine.getResultSet(predicate); 298 var predicateResultSet = queryEngine.getResultSet(predicate);
340 299
341 personInterpretation.put(Tuple.of(0), true); 300 personInterpretation.put(Tuple.of(0), true);
@@ -376,24 +335,15 @@ class QueryTransactionTest {
376 @Disabled("TODO Fix DiffCursor") 335 @Disabled("TODO Fix DiffCursor")
377 @Test 336 @Test
378 void commitWithoutFlushTest() { 337 void commitWithoutFlushTest() {
379 var person = new Symbol<>("Person", 1, Boolean.class, false);
380 var personView = new KeyOnlyRelationView<>(person);
381
382 var p1 = Variable.of("p1");
383 var predicate = Query.builder("TypeConstraint")
384 .parameters(p1)
385 .clause(personView.call(p1))
386 .build();
387
388 var store = ModelStore.builder() 338 var store = ModelStore.builder()
389 .symbols(person) 339 .symbols(person)
390 .with(ViatraModelQuery.ADAPTER) 340 .with(ViatraModelQueryAdapter.builder()
391 .queries(predicate) 341 .queries(predicate))
392 .build(); 342 .build();
393 343
394 var model = store.createEmptyModel(); 344 var model = store.createEmptyModel();
395 var personInterpretation = model.getInterpretation(person); 345 var personInterpretation = model.getInterpretation(person);
396 var queryEngine = model.getAdapter(ModelQuery.ADAPTER); 346 var queryEngine = model.getAdapter(ModelQueryAdapter.class);
397 var predicateResultSet = queryEngine.getResultSet(predicate); 347 var predicateResultSet = queryEngine.getResultSet(predicate);
398 348
399 personInterpretation.put(Tuple.of(0), true); 349 personInterpretation.put(Tuple.of(0), true);
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
deleted file mode 100644
index 20dad543..00000000
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
1package tools.refinery.store.query.viatra.internal.cardinality;
2
3import org.junit.jupiter.api.BeforeEach;
4import org.junit.jupiter.api.Test;
5import tools.refinery.store.representation.cardinality.UpperCardinalities;
6import tools.refinery.store.representation.cardinality.UpperCardinality;
7
8import static org.hamcrest.MatcherAssert.assertThat;
9import static org.hamcrest.Matchers.equalTo;
10
11class UpperCardinalitySumAggregationOperatorTest {
12 private UpperCardinalitySumAggregationOperator.Accumulator accumulator;
13
14 @BeforeEach
15 void beforeEach() {
16 accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.createNeutral();
17 }
18
19 @Test
20 void emptyAggregationTest() {
21 assertResult(UpperCardinality.of(0));
22 }
23
24 @Test
25 void singleBoundedTest() {
26 insert(UpperCardinality.of(3));
27 assertResult(UpperCardinality.of(3));
28 }
29
30 @Test
31 void multipleBoundedTest() {
32 insert(UpperCardinality.of(2));
33 insert(UpperCardinality.of(3));
34 assertResult(UpperCardinality.of(5));
35 }
36
37 @Test
38 void singleUnboundedTest() {
39 insert(UpperCardinalities.UNBOUNDED);
40 assertResult(UpperCardinalities.UNBOUNDED);
41 }
42
43 @Test
44 void multipleUnboundedTest() {
45 insert(UpperCardinalities.UNBOUNDED);
46 insert(UpperCardinalities.UNBOUNDED);
47 assertResult(UpperCardinalities.UNBOUNDED);
48 }
49
50 @Test
51 void removeBoundedTest() {
52 insert(UpperCardinality.of(2));
53 insert(UpperCardinality.of(3));
54 remove(UpperCardinality.of(2));
55 assertResult(UpperCardinality.of(3));
56 }
57
58 @Test
59 void removeAllUnboundedTest() {
60 insert(UpperCardinalities.UNBOUNDED);
61 insert(UpperCardinality.of(3));
62 remove(UpperCardinalities.UNBOUNDED);
63 assertResult(UpperCardinality.of(3));
64 }
65
66 @Test
67 void removeSomeUnboundedTest() {
68 insert(UpperCardinalities.UNBOUNDED);
69 insert(UpperCardinalities.UNBOUNDED);
70 insert(UpperCardinality.of(3));
71 remove(UpperCardinalities.UNBOUNDED);
72 assertResult(UpperCardinalities.UNBOUNDED);
73 }
74
75 private void insert(UpperCardinality value) {
76 accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, true);
77 }
78
79 private void remove(UpperCardinality value) {
80 accumulator = UpperCardinalitySumAggregationOperator.INSTANCE.update(accumulator, value, false);
81 }
82
83 private void assertResult(UpperCardinality expected) {
84 var result = UpperCardinalitySumAggregationOperator.INSTANCE.getAggregate(accumulator);
85 assertThat(result, equalTo(expected));
86 }
87}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java
new file mode 100644
index 00000000..968c6c5e
--- /dev/null
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/matcher/MatcherUtilsTest.java
@@ -0,0 +1,239 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.viatra.internal.matcher;
7
8import org.eclipse.viatra.query.runtime.matchers.tuple.*;
9import org.junit.jupiter.api.Test;
10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.store.tuple.*;
12
13import java.util.List;
14
15import static org.hamcrest.MatcherAssert.assertThat;
16import static org.hamcrest.Matchers.*;
17import static org.junit.jupiter.api.Assertions.assertThrows;
18
19class MatcherUtilsTest {
20 @Test
21 void toViatra0Test() {
22 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of());
23 assertThat(viatraTuple.getSize(), is(0));
24 assertThat(viatraTuple, instanceOf(FlatTuple0.class));
25 }
26
27 @Test
28 void toViatra1Test() {
29 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2));
30 assertThat(viatraTuple.getSize(), is(1));
31 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
32 assertThat(viatraTuple, instanceOf(FlatTuple1.class));
33 }
34
35 @Test
36 void toViatra2Test() {
37 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3));
38 assertThat(viatraTuple.getSize(), is(2));
39 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
40 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
41 assertThat(viatraTuple, instanceOf(FlatTuple2.class));
42 }
43
44 @Test
45 void toViatra3Test() {
46 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5));
47 assertThat(viatraTuple.getSize(), is(3));
48 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
49 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
50 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
51 assertThat(viatraTuple, instanceOf(FlatTuple3.class));
52 }
53
54 @Test
55 void toViatra4Test() {
56 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8));
57 assertThat(viatraTuple.getSize(), is(4));
58 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
59 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
60 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
61 assertThat(viatraTuple.get(3), is(Tuple.of(8)));
62 assertThat(viatraTuple, instanceOf(FlatTuple4.class));
63 }
64
65 @Test
66 void toViatra5Test() {
67 var viatraTuple = MatcherUtils.toViatraTuple(Tuple.of(2, 3, 5, 8, 13));
68 assertThat(viatraTuple.getSize(), is(5));
69 assertThat(viatraTuple.get(0), is(Tuple.of(2)));
70 assertThat(viatraTuple.get(1), is(Tuple.of(3)));
71 assertThat(viatraTuple.get(2), is(Tuple.of(5)));
72 assertThat(viatraTuple.get(3), is(Tuple.of(8)));
73 assertThat(viatraTuple.get(4), is(Tuple.of(13)));
74 assertThat(viatraTuple, instanceOf(FlatTuple.class));
75 }
76
77 @Test
78 void toRefinery0Test() {
79 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf());
80 assertThat(refineryTuple.getSize(), is(0));
81 assertThat(refineryTuple, instanceOf(Tuple0.class));
82 }
83
84 @Test
85 void toRefinery1Test() {
86 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2)));
87 assertThat(refineryTuple.getSize(), is(1));
88 assertThat(refineryTuple.get(0), is(2));
89 assertThat(refineryTuple, instanceOf(Tuple1.class));
90 }
91
92 @Test
93 void toRefinery2Test() {
94 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3)));
95 assertThat(refineryTuple.getSize(), is(2));
96 assertThat(refineryTuple.get(0), is(2));
97 assertThat(refineryTuple.get(1), is(3));
98 assertThat(refineryTuple, instanceOf(Tuple2.class));
99 }
100
101 @Test
102 void toRefinery3Test() {
103 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5)));
104 assertThat(refineryTuple.getSize(), is(3));
105 assertThat(refineryTuple.get(0), is(2));
106 assertThat(refineryTuple.get(1), is(3));
107 assertThat(refineryTuple.get(2), is(5));
108 assertThat(refineryTuple, instanceOf(Tuple3.class));
109 }
110
111 @Test
112 void toRefinery4Test() {
113 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
114 Tuple.of(8)));
115 assertThat(refineryTuple.getSize(), is(4));
116 assertThat(refineryTuple.get(0), is(2));
117 assertThat(refineryTuple.get(1), is(3));
118 assertThat(refineryTuple.get(2), is(5));
119 assertThat(refineryTuple.get(3), is(8));
120 assertThat(refineryTuple, instanceOf(Tuple4.class));
121 }
122
123 @Test
124 void toRefinery5Test() {
125 var refineryTuple = MatcherUtils.toRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
126 Tuple.of(8), Tuple.of(13)));
127 assertThat(refineryTuple.getSize(), is(5));
128 assertThat(refineryTuple.get(0), is(2));
129 assertThat(refineryTuple.get(1), is(3));
130 assertThat(refineryTuple.get(2), is(5));
131 assertThat(refineryTuple.get(3), is(8));
132 assertThat(refineryTuple.get(4), is(13));
133 assertThat(refineryTuple, instanceOf(TupleN.class));
134 }
135
136 @Test
137 void toRefineryInvalidValueTest() {
138 var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98);
139 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.toRefineryTuple(viatraTuple));
140 }
141
142 @Test
143 void keyToRefinery0Test() {
144 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(-99));
145 assertThat(refineryTuple.getSize(), is(0));
146 assertThat(refineryTuple, instanceOf(Tuple0.class));
147 }
148
149 @Test
150 void keyToRefinery1Test() {
151 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), -99));
152 assertThat(refineryTuple.getSize(), is(1));
153 assertThat(refineryTuple.get(0), is(2));
154 assertThat(refineryTuple, instanceOf(Tuple1.class));
155 }
156
157 @Test
158 void keyToRefinery2Test() {
159 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), -99));
160 assertThat(refineryTuple.getSize(), is(2));
161 assertThat(refineryTuple.get(0), is(2));
162 assertThat(refineryTuple.get(1), is(3));
163 assertThat(refineryTuple, instanceOf(Tuple2.class));
164 }
165
166 @Test
167 void keyToRefinery3Test() {
168 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
169 -99));
170 assertThat(refineryTuple.getSize(), is(3));
171 assertThat(refineryTuple.get(0), is(2));
172 assertThat(refineryTuple.get(1), is(3));
173 assertThat(refineryTuple.get(2), is(5));
174 assertThat(refineryTuple, instanceOf(Tuple3.class));
175 }
176
177 @Test
178 void keyToRefinery4Test() {
179 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
180 Tuple.of(8), -99));
181 assertThat(refineryTuple.getSize(), is(4));
182 assertThat(refineryTuple.get(0), is(2));
183 assertThat(refineryTuple.get(1), is(3));
184 assertThat(refineryTuple.get(2), is(5));
185 assertThat(refineryTuple.get(3), is(8));
186 assertThat(refineryTuple, instanceOf(Tuple4.class));
187 }
188
189 @Test
190 void keyToRefinery5Test() {
191 var refineryTuple = MatcherUtils.keyToRefineryTuple(Tuples.flatTupleOf(Tuple.of(2), Tuple.of(3), Tuple.of(5),
192 Tuple.of(8), Tuple.of(13), -99));
193 assertThat(refineryTuple.getSize(), is(5));
194 assertThat(refineryTuple.get(0), is(2));
195 assertThat(refineryTuple.get(1), is(3));
196 assertThat(refineryTuple.get(2), is(5));
197 assertThat(refineryTuple.get(3), is(8));
198 assertThat(refineryTuple.get(4), is(13));
199 assertThat(refineryTuple, instanceOf(TupleN.class));
200 }
201
202 @Test
203 void keyToRefineryTooShortTest() {
204 var viatraTuple = Tuples.flatTupleOf();
205 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple));
206 }
207
208 @Test
209 void keyToRefineryInvalidValueTest() {
210 var viatraTuple = Tuples.flatTupleOf(Tuple.of(2), -98, -99);
211 assertThrows(IllegalArgumentException.class, () -> MatcherUtils.keyToRefineryTuple(viatraTuple));
212 }
213
214 @Test
215 void getSingleValueTest() {
216 var value = MatcherUtils.getSingleValue(List.of(Tuples.flatTupleOf(Tuple.of(2), -99)));
217 assertThat(value, is(-99));
218 }
219
220 // Static analysis accurately determines that the result is always {@code null}, but we check anyways.
221 @SuppressWarnings("ConstantValue")
222 @Test
223 void getSingleValueNullTest() {
224 var value = MatcherUtils.getSingleValue((Iterable<? extends ITuple>) null);
225 assertThat(value, nullValue());
226 }
227
228 @Test
229 void getSingleValueEmptyTest() {
230 var value = MatcherUtils.getSingleValue(List.of());
231 assertThat(value, nullValue());
232 }
233
234 @Test
235 void getSingleValueMultipleTest() {
236 var viatraTuples = List.of(Tuples.flatTupleOf(Tuple.of(2), -98), Tuples.flatTupleOf(Tuple.of(2), -99));
237 assertThrows(IllegalStateException.class, () -> MatcherUtils.getSingleValue(viatraTuples));
238 }
239}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
index 6f50ec73..7a25cfdc 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryAssertions.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.tests; 6package tools.refinery.store.query.viatra.tests;
2 7
3import org.junit.jupiter.api.function.Executable; 8import org.junit.jupiter.api.function.Executable;
@@ -42,7 +47,7 @@ public final class QueryAssertions {
42 var cursor = resultSet.getAll(); 47 var cursor = resultSet.getAll();
43 while (cursor.move()) { 48 while (cursor.move()) {
44 var key = cursor.getKey(); 49 var key = cursor.getKey();
45 var previous = actual.put(key.toTuple(), cursor.getValue()); 50 var previous = actual.put(key, cursor.getValue());
46 assertThat("duplicate value for key " + key, previous, nullValue()); 51 assertThat("duplicate value for key " + key, previous, nullValue());
47 } 52 }
48 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected))); 53 executables.add(() -> assertThat("results cursor", actual, is(filteredExpected)));
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java
index b1818a17..dc0e92c8 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryBackendHint.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.tests; 6package tools.refinery.store.query.viatra.tests;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java
index f129520c..d4f16da7 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEngineTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.tests; 6package tools.refinery.store.query.viatra.tests;
2 7
3import org.junit.jupiter.params.ParameterizedTest; 8import org.junit.jupiter.params.ParameterizedTest;
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java
index a55762e2..9e75d5f3 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java
+++ b/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/tests/QueryEvaluationHintSource.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.viatra.tests; 6package tools.refinery.store.query.viatra.tests;
2 7
3import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint; 8import org.eclipse.viatra.query.runtime.matchers.backend.QueryEvaluationHint;
diff --git a/subprojects/store-query/build.gradle b/subprojects/store-query/build.gradle
deleted file mode 100644
index 97761936..00000000
--- a/subprojects/store-query/build.gradle
+++ /dev/null
@@ -1,9 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3 id 'refinery-java-test-fixtures'
4}
5
6dependencies {
7 api project(':refinery-store')
8 testFixturesApi libs.hamcrest
9}
diff --git a/subprojects/store-query/build.gradle.kts b/subprojects/store-query/build.gradle.kts
new file mode 100644
index 00000000..4d8e2605
--- /dev/null
+++ b/subprojects/store-query/build.gradle.kts
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9 id("tools.refinery.gradle.java-test-fixtures")
10}
11
12dependencies {
13 api(project(":refinery-store"))
14 testFixturesApi(libs.hamcrest)
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java
index 6d411212..f29bb278 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/AnyResultSet.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.query.dnf.AnyQuery; 8import tools.refinery.store.query.dnf.AnyQuery;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java
index cec4c19f..916fb35c 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Constraint.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -9,25 +14,27 @@ import java.util.List;
9public interface Constraint { 14public interface Constraint {
10 String name(); 15 String name();
11 16
12 List<Sort> getSorts(); 17 List<Parameter> getParameters();
13 18
14 default int arity() { 19 default int arity() {
15 return getSorts().size(); 20 return getParameters().size();
16 } 21 }
17 22
18 default boolean invalidIndex(int i) { 23 default boolean invalidIndex(int i) {
19 return i < 0 || i >= arity(); 24 return i < 0 || i >= arity();
20 } 25 }
21 26
22 default LiteralReduction getReduction() { 27 default Reduction getReduction() {
23 return LiteralReduction.NOT_REDUCIBLE; 28 return Reduction.NOT_REDUCIBLE;
24 } 29 }
25 30
26 default boolean equals(LiteralEqualityHelper helper, Constraint other) { 31 default boolean equals(LiteralEqualityHelper helper, Constraint other) {
27 return equals(other); 32 return equals(other);
28 } 33 }
29 34
30 String toReferenceString(); 35 default String toReferenceString() {
36 return name();
37 }
31 38
32 default CallLiteral call(CallPolarity polarity, List<Variable> arguments) { 39 default CallLiteral call(CallPolarity polarity, List<Variable> arguments) {
33 return new CallLiteral(polarity, this, arguments); 40 return new CallLiteral(polarity, this, arguments);
@@ -53,13 +60,13 @@ public interface Constraint {
53 return count(List.of(arguments)); 60 return count(List.of(arguments));
54 } 61 }
55 62
56 default <R, T> AssignedValue<R> aggregate(DataVariable<T> inputVariable, Aggregator<R, T> aggregator, 63 default <R, T> AssignedValue<R> aggregateBy(DataVariable<T> inputVariable, Aggregator<R, T> aggregator,
57 List<Variable> arguments) { 64 List<Variable> arguments) {
58 return targetVariable -> new AggregationLiteral<>(targetVariable, aggregator, inputVariable, this, arguments); 65 return targetVariable -> new AggregationLiteral<>(targetVariable, aggregator, inputVariable, this, arguments);
59 } 66 }
60 67
61 default <R, T> AssignedValue<R> aggregate(DataVariable<T> inputVariable, Aggregator<R, T> aggregator, 68 default <R, T> AssignedValue<R> aggregateBy(DataVariable<T> inputVariable, Aggregator<R, T> aggregator,
62 Variable... arguments) { 69 Variable... arguments) {
63 return aggregate(inputVariable, aggregator, List.of(arguments)); 70 return aggregateBy(inputVariable, aggregator, List.of(arguments));
64 } 71 }
65} 72}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
index 9af73bdd..5361f645 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/EmptyResultSet.java
@@ -1,9 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
4import tools.refinery.store.map.Cursors; 9import tools.refinery.store.map.Cursors;
5import tools.refinery.store.query.dnf.Query; 10import tools.refinery.store.query.dnf.Query;
6import tools.refinery.store.tuple.TupleLike; 11import tools.refinery.store.tuple.Tuple;
7 12
8public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> { 13public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) implements ResultSet<T> {
9 @Override 14 @Override
@@ -17,13 +22,12 @@ public record EmptyResultSet<T>(ModelQueryAdapter adapter, Query<T> query) imple
17 } 22 }
18 23
19 @Override 24 @Override
20 public T get(TupleLike parameters) { 25 public T get(Tuple parameters) {
21 return query.defaultValue(); 26 return query.defaultValue();
22 } 27 }
23 28
24
25 @Override 29 @Override
26 public Cursor<TupleLike, T> getAll() { 30 public Cursor<Tuple, T> getAll() {
27 return Cursors.empty(); 31 return Cursors.empty();
28 } 32 }
29 33
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java
deleted file mode 100644
index 6a1aeabb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQuery.java
+++ /dev/null
@@ -1,11 +0,0 @@
1package tools.refinery.store.query;
2
3import tools.refinery.store.adapter.ModelAdapterType;
4
5public final class ModelQuery extends ModelAdapterType<ModelQueryAdapter, ModelQueryStoreAdapter, ModelQueryBuilder> {
6 public static final ModelQuery ADAPTER = new ModelQuery();
7
8 private ModelQuery() {
9 super(ModelQueryAdapter.class, ModelQueryStoreAdapter.class, ModelQueryBuilder.class);
10 }
11}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
index 2e30fec4..ae3bbcbb 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryAdapter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
index 4fdc9210..c62a95b5 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryBuilder.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
@@ -21,5 +26,5 @@ public interface ModelQueryBuilder extends ModelAdapterBuilder {
21 ModelQueryBuilder query(AnyQuery query); 26 ModelQueryBuilder query(AnyQuery query);
22 27
23 @Override 28 @Override
24 ModelQueryStoreAdapter createStoreAdapter(ModelStore store); 29 ModelQueryStoreAdapter build(ModelStore store);
25} 30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
index 514e582b..f0a950a6 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ModelQueryStoreAdapter.java
@@ -1,14 +1,19 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
4import tools.refinery.store.model.Model; 9import tools.refinery.store.model.Model;
5import tools.refinery.store.query.dnf.AnyQuery; 10import tools.refinery.store.query.dnf.AnyQuery;
6import tools.refinery.store.query.view.AnyRelationView; 11import tools.refinery.store.query.view.AnySymbolView;
7 12
8import java.util.Collection; 13import java.util.Collection;
9 14
10public interface ModelQueryStoreAdapter extends ModelStoreAdapter { 15public interface ModelQueryStoreAdapter extends ModelStoreAdapter {
11 Collection<AnyRelationView> getRelationViews(); 16 Collection<AnySymbolView> getSymbolViews();
12 17
13 Collection<AnyQuery> getQueries(); 18 Collection<AnyQuery> getQueries();
14 19
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java
index 146089f6..82c52b04 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/LiteralReduction.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/Reduction.java
@@ -1,6 +1,11 @@
1package tools.refinery.store.query.literal; 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query;
2 7
3public enum LiteralReduction { 8public enum Reduction {
4 /** 9 /**
5 * Signifies that a literal should be preserved in the clause. 10 * Signifies that a literal should be preserved in the clause.
6 */ 11 */
@@ -16,7 +21,7 @@ public enum LiteralReduction {
16 */ 21 */
17 ALWAYS_FALSE; 22 ALWAYS_FALSE;
18 23
19 public LiteralReduction negate() { 24 public Reduction negate() {
20 return switch (this) { 25 return switch (this) {
21 case NOT_REDUCIBLE -> NOT_REDUCIBLE; 26 case NOT_REDUCIBLE -> NOT_REDUCIBLE;
22 case ALWAYS_TRUE -> ALWAYS_FALSE; 27 case ALWAYS_TRUE -> ALWAYS_FALSE;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
index 3f6bc06f..9ab83172 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/ResultSet.java
@@ -1,13 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query; 6package tools.refinery.store.query;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
4import tools.refinery.store.query.dnf.Query; 9import tools.refinery.store.query.dnf.Query;
5import tools.refinery.store.tuple.TupleLike; 10import tools.refinery.store.tuple.Tuple;
6 11
7public non-sealed interface ResultSet<T> extends AnyResultSet { 12public non-sealed interface ResultSet<T> extends AnyResultSet {
8 Query<T> getQuery(); 13 Query<T> getQuery();
9 14
10 T get(TupleLike parameters); 15 T get(Tuple parameters);
11 16
12 Cursor<TupleLike, T> getAll(); 17 Cursor<Tuple, T> getAll();
13} 18}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java
new file mode 100644
index 00000000..2a3e3ce0
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AbstractQueryBuilder.java
@@ -0,0 +1,175 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.dnf.callback.*;
9import tools.refinery.store.query.literal.Literal;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.ParameterDirection;
12import tools.refinery.store.query.term.Variable;
13
14import java.util.Collection;
15import java.util.List;
16import java.util.Set;
17
18public abstract class AbstractQueryBuilder<T extends AbstractQueryBuilder<T>> {
19 protected final DnfBuilder dnfBuilder;
20
21 protected AbstractQueryBuilder(DnfBuilder dnfBuilder) {
22 this.dnfBuilder = dnfBuilder;
23 }
24
25 protected abstract T self();
26
27 public NodeVariable parameter() {
28 return dnfBuilder.parameter();
29 }
30
31 public NodeVariable parameter(String name) {
32 return dnfBuilder.parameter(name);
33 }
34
35 public NodeVariable parameter(ParameterDirection direction) {
36 return dnfBuilder.parameter(direction);
37 }
38
39 public NodeVariable parameter(String name, ParameterDirection direction) {
40 return dnfBuilder.parameter(name, direction);
41 }
42
43 public T parameter(NodeVariable variable) {
44 dnfBuilder.parameter(variable);
45 return self();
46 }
47
48 public T parameter(NodeVariable variable, ParameterDirection direction) {
49 dnfBuilder.parameter(variable, direction);
50 return self();
51 }
52
53 public T parameters(NodeVariable... variables) {
54 dnfBuilder.parameters(variables);
55 return self();
56 }
57
58 public T parameters(List<NodeVariable> variables) {
59 dnfBuilder.parameters(variables);
60 return self();
61 }
62
63 public T parameters(List<NodeVariable> variables, ParameterDirection direction) {
64 dnfBuilder.parameters(variables, direction);
65 return self();
66 }
67
68 public T symbolicParameters(List<SymbolicParameter> parameters) {
69 dnfBuilder.symbolicParameters(parameters);
70 return self();
71 }
72
73 public T functionalDependencies(Collection<FunctionalDependency<Variable>> functionalDependencies) {
74 dnfBuilder.functionalDependencies(functionalDependencies);
75 return self();
76 }
77
78 public T functionalDependency(FunctionalDependency<Variable> functionalDependency) {
79 dnfBuilder.functionalDependency(functionalDependency);
80 return self();
81 }
82
83 public T functionalDependency(Set<? extends Variable> forEach, Set<? extends Variable> unique) {
84 dnfBuilder.functionalDependency(forEach, unique);
85 return self();
86 }
87
88 public T clause(ClauseCallback0 callback) {
89 dnfBuilder.clause(callback);
90 return self();
91 }
92
93 public T clause(ClauseCallback1Data0 callback) {
94 dnfBuilder.clause(callback);
95 return self();
96 }
97
98 public <U1> T clause(Class<U1> type1, ClauseCallback1Data1<U1> callback) {
99 dnfBuilder.clause(type1, callback);
100 return self();
101 }
102
103 public T clause(ClauseCallback2Data0 callback) {
104 dnfBuilder.clause(callback);
105 return self();
106 }
107
108 public <U1> T clause(Class<U1> type1, ClauseCallback2Data1<U1> callback) {
109 dnfBuilder.clause(type1, callback);
110 return self();
111 }
112
113 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback2Data2<U1, U2> callback) {
114 dnfBuilder.clause(type1, type2, callback);
115 return self();
116 }
117
118 public T clause(ClauseCallback3Data0 callback) {
119 dnfBuilder.clause(callback);
120 return self();
121 }
122
123 public <U1> T clause(Class<U1> type1, ClauseCallback3Data1<U1> callback) {
124 dnfBuilder.clause(type1, callback);
125 return self();
126 }
127
128 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback3Data2<U1, U2> callback) {
129 dnfBuilder.clause(type1, type2, callback);
130 return self();
131 }
132
133 public <U1, U2, U3> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3,
134 ClauseCallback3Data3<U1, U2, U3> callback) {
135 dnfBuilder.clause(type1, type2, type3, callback);
136 return self();
137 }
138
139 public T clause(ClauseCallback4Data0 callback) {
140 dnfBuilder.clause(callback);
141 return self();
142 }
143
144 public <U1> T clause(Class<U1> type1, ClauseCallback4Data1<U1> callback) {
145 dnfBuilder.clause(type1, callback);
146 return self();
147 }
148
149 public <U1, U2> T clause(Class<U1> type1, Class<U2> type2, ClauseCallback4Data2<U1, U2> callback) {
150 dnfBuilder.clause(type1, type2, callback);
151 return self();
152 }
153
154 public <U1, U2, U3> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3,
155 ClauseCallback4Data3<U1, U2, U3> callback) {
156 dnfBuilder.clause(type1, type2, type3, callback);
157 return self();
158 }
159
160 public <U1, U2, U3, U4> T clause(Class<U1> type1, Class<U2> type2, Class<U3> type3, Class<U4> type4,
161 ClauseCallback4Data4<U1, U2, U3, U4> callback) {
162 dnfBuilder.clause(type1, type2, type3, type4, callback);
163 return self();
164 }
165
166 public T clause(Literal... literals) {
167 dnfBuilder.clause(literals);
168 return self();
169 }
170
171 public T clause(Collection<? extends Literal> literals) {
172 dnfBuilder.clause(literals);
173 return self();
174 }
175}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java
index d0a2367f..5e28af68 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/AnyQuery.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3public sealed interface AnyQuery permits Query { 8public sealed interface AnyQuery permits Query {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
new file mode 100644
index 00000000..b5e7092b
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/ClausePostProcessor.java
@@ -0,0 +1,324 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.jetbrains.annotations.NotNull;
9import tools.refinery.store.query.literal.BooleanLiteral;
10import tools.refinery.store.query.literal.EquivalenceLiteral;
11import tools.refinery.store.query.literal.Literal;
12import tools.refinery.store.query.substitution.MapBasedSubstitution;
13import tools.refinery.store.query.substitution.StatelessSubstitution;
14import tools.refinery.store.query.substitution.Substitution;
15import tools.refinery.store.query.term.NodeVariable;
16import tools.refinery.store.query.term.ParameterDirection;
17import tools.refinery.store.query.term.Variable;
18
19import java.util.*;
20import java.util.function.Function;
21
22class ClausePostProcessor {
23 private final Map<Variable, ParameterInfo> parameters;
24 private final List<Literal> literals;
25 private final Map<NodeVariable, NodeVariable> representatives = new LinkedHashMap<>();
26 private final Map<NodeVariable, Set<NodeVariable>> equivalencePartition = new HashMap<>();
27 private List<Literal> substitutedLiterals;
28 private final Set<Variable> existentiallyQuantifiedVariables = new LinkedHashSet<>();
29 private Set<Variable> positiveVariables;
30 private Map<Variable, Set<SortableLiteral>> variableToLiteralInputMap;
31 private PriorityQueue<SortableLiteral> literalsWithAllInputsBound;
32 private LinkedHashSet<Literal> topologicallySortedLiterals;
33
34 public ClausePostProcessor(Map<Variable, ParameterInfo> parameters, List<Literal> literals) {
35 this.parameters = parameters;
36 this.literals = literals;
37 }
38
39 public Result postProcessClause() {
40 mergeEquivalentNodeVariables();
41 substitutedLiterals = new ArrayList<>(literals.size());
42 keepParameterEquivalences();
43 substituteLiterals();
44 computeExistentiallyQuantifiedVariables();
45 computePositiveVariables();
46 validatePositiveRepresentatives();
47 validatePrivateVariables();
48 topologicallySortLiterals();
49 var filteredLiterals = new ArrayList<Literal>(topologicallySortedLiterals.size());
50 for (var literal : topologicallySortedLiterals) {
51 var reducedLiteral = literal.reduce();
52 if (BooleanLiteral.FALSE.equals(reducedLiteral)) {
53 return ConstantResult.ALWAYS_FALSE;
54 } else if (!BooleanLiteral.TRUE.equals(reducedLiteral)) {
55 filteredLiterals.add(reducedLiteral);
56 }
57 }
58 if (filteredLiterals.isEmpty()) {
59 return ConstantResult.ALWAYS_TRUE;
60 }
61 var clause = new DnfClause(Collections.unmodifiableSet(positiveVariables),
62 Collections.unmodifiableList(filteredLiterals));
63 return new ClauseResult(clause);
64 }
65
66 private void mergeEquivalentNodeVariables() {
67 for (var literal : literals) {
68 if (isPositiveEquivalence(literal)) {
69 var equivalenceLiteral = (EquivalenceLiteral) literal;
70 mergeVariables(equivalenceLiteral.left(), equivalenceLiteral.right());
71 }
72 }
73 }
74
75 private static boolean isPositiveEquivalence(Literal literal) {
76 return literal instanceof EquivalenceLiteral equivalenceLiteral && equivalenceLiteral.positive();
77 }
78
79 private void mergeVariables(NodeVariable left, NodeVariable right) {
80 var leftRepresentative = getRepresentative(left);
81 var rightRepresentative = getRepresentative(right);
82 var leftInfo = parameters.get(leftRepresentative);
83 var rightInfo = parameters.get(rightRepresentative);
84 if (leftInfo != null && (rightInfo == null || leftInfo.index() <= rightInfo.index())) {
85 // Prefer the variable occurring earlier in the parameter list as a representative.
86 doMergeVariables(leftRepresentative, rightRepresentative);
87 } else {
88 doMergeVariables(rightRepresentative, leftRepresentative);
89 }
90 }
91
92 private void doMergeVariables(NodeVariable parentRepresentative, NodeVariable newChildRepresentative) {
93 var parentSet = getEquivalentVariables(parentRepresentative);
94 var childSet = getEquivalentVariables(newChildRepresentative);
95 parentSet.addAll(childSet);
96 equivalencePartition.remove(newChildRepresentative);
97 for (var childEquivalentNodeVariable : childSet) {
98 representatives.put(childEquivalentNodeVariable, parentRepresentative);
99 }
100 }
101
102 private NodeVariable getRepresentative(NodeVariable variable) {
103 return representatives.computeIfAbsent(variable, Function.identity());
104 }
105
106 private Set<NodeVariable> getEquivalentVariables(NodeVariable variable) {
107 var representative = getRepresentative(variable);
108 if (!representative.equals(variable)) {
109 throw new AssertionError("NodeVariable %s already has a representative %s"
110 .formatted(variable, representative));
111 }
112 return equivalencePartition.computeIfAbsent(variable, key -> {
113 var set = new HashSet<NodeVariable>(1);
114 set.add(key);
115 return set;
116 });
117 }
118
119 private void keepParameterEquivalences() {
120 for (var pair : representatives.entrySet()) {
121 var left = pair.getKey();
122 var right = pair.getValue();
123 if (!left.equals(right) && parameters.containsKey(left) && parameters.containsKey(right)) {
124 substitutedLiterals.add(left.isEquivalent(right));
125 }
126 }
127 }
128
129 private void substituteLiterals() {
130 Substitution substitution;
131 if (representatives.isEmpty()) {
132 substitution = null;
133 } else {
134 substitution = new MapBasedSubstitution(Collections.unmodifiableMap(representatives),
135 StatelessSubstitution.IDENTITY);
136 }
137 for (var literal : literals) {
138 if (isPositiveEquivalence(literal)) {
139 // We already retained all equivalences that cannot be replaced with substitutions in
140 // {@link#keepParameterEquivalences()}.
141 continue;
142 }
143 var substitutedLiteral = substitution == null ? literal : literal.substitute(substitution);
144 substitutedLiterals.add(substitutedLiteral);
145 }
146 }
147
148 private void computeExistentiallyQuantifiedVariables() {
149 for (var literal : substitutedLiterals) {
150 for (var variable : literal.getOutputVariables()) {
151 boolean added = existentiallyQuantifiedVariables.add(variable);
152 if (!variable.isUnifiable()) {
153 var parameterInfo = parameters.get(variable);
154 if (parameterInfo != null && parameterInfo.direction() == ParameterDirection.IN) {
155 throw new IllegalArgumentException("Trying to bind %s parameter %s"
156 .formatted(ParameterDirection.IN, variable));
157 }
158 if (!added) {
159 throw new IllegalArgumentException("Variable %s has multiple assigned values"
160 .formatted(variable));
161 }
162 }
163 }
164 }
165 }
166
167 private void computePositiveVariables() {
168 positiveVariables = new LinkedHashSet<>();
169 for (var pair : parameters.entrySet()) {
170 var variable = pair.getKey();
171 if (pair.getValue().direction() == ParameterDirection.IN) {
172 // Inputs count as positive, because they are already bound when we evaluate literals.
173 positiveVariables.add(variable);
174 } else if (!existentiallyQuantifiedVariables.contains(variable)) {
175 throw new IllegalArgumentException("Unbound %s parameter %s"
176 .formatted(ParameterDirection.OUT, variable));
177 }
178 }
179 positiveVariables.addAll(existentiallyQuantifiedVariables);
180 }
181
182 private void validatePositiveRepresentatives() {
183 for (var pair : equivalencePartition.entrySet()) {
184 var representative = pair.getKey();
185 if (!positiveVariables.contains(representative)) {
186 var variableSet = pair.getValue();
187 throw new IllegalArgumentException("Variables %s were merged by equivalence but are not bound"
188 .formatted(variableSet));
189 }
190 }
191 }
192
193 private void validatePrivateVariables() {
194 var negativeVariablesMap = new HashMap<Variable, Literal>();
195 for (var literal : substitutedLiterals) {
196 for (var variable : literal.getPrivateVariables(positiveVariables)) {
197 var oldLiteral = negativeVariablesMap.put(variable, literal);
198 if (oldLiteral != null) {
199 throw new IllegalArgumentException("Unbound variable %s appears in multiple literals %s and %s"
200 .formatted(variable, oldLiteral, literal));
201 }
202 }
203 }
204 }
205
206 private void topologicallySortLiterals() {
207 topologicallySortedLiterals = new LinkedHashSet<>(substitutedLiterals.size());
208 variableToLiteralInputMap = new HashMap<>();
209 literalsWithAllInputsBound = new PriorityQueue<>();
210 int size = substitutedLiterals.size();
211 for (int i = 0; i < size; i++) {
212 var literal = substitutedLiterals.get(i);
213 var sortableLiteral = new SortableLiteral(i, literal);
214 sortableLiteral.enqueue();
215 }
216 while (!literalsWithAllInputsBound.isEmpty()) {
217 var variable = literalsWithAllInputsBound.remove();
218 variable.addToSortedLiterals();
219 }
220 if (!variableToLiteralInputMap.isEmpty()) {
221 throw new IllegalArgumentException("Unbound input variables %s"
222 .formatted(variableToLiteralInputMap.keySet()));
223 }
224 }
225
226 private class SortableLiteral implements Comparable<SortableLiteral> {
227 private final int index;
228 private final Literal literal;
229 private final Set<Variable> remainingInputs;
230
231 private SortableLiteral(int index, Literal literal) {
232 this.index = index;
233 this.literal = literal;
234 remainingInputs = new HashSet<>(literal.getInputVariables(positiveVariables));
235 for (var pair : parameters.entrySet()) {
236 if (pair.getValue().direction() == ParameterDirection.IN) {
237 remainingInputs.remove(pair.getKey());
238 }
239 }
240 }
241
242 public void enqueue() {
243 if (allInputsBound()) {
244 addToAllInputsBoundQueue();
245 } else {
246 addToVariableToLiteralInputMap();
247 }
248 }
249
250 private void bindVariable(Variable input) {
251 if (!remainingInputs.remove(input)) {
252 throw new AssertionError("Already processed input %s of literal %s".formatted(input, literal));
253 }
254 if (allInputsBound()) {
255 addToAllInputsBoundQueue();
256 }
257 }
258
259 private boolean allInputsBound() {
260 return remainingInputs.isEmpty();
261 }
262
263 private void addToVariableToLiteralInputMap() {
264 for (var inputVariable : remainingInputs) {
265 var literalSetForInput = variableToLiteralInputMap.computeIfAbsent(
266 inputVariable, key -> new HashSet<>());
267 literalSetForInput.add(this);
268 }
269 }
270
271 private void addToAllInputsBoundQueue() {
272 literalsWithAllInputsBound.add(this);
273 }
274
275 public void addToSortedLiterals() {
276 if (!allInputsBound()) {
277 throw new AssertionError("Inputs %s of %s are not yet bound".formatted(remainingInputs, literal));
278 }
279 // Add literal if we haven't yet added a duplicate of this literal.
280 topologicallySortedLiterals.add(literal);
281 for (var variable : literal.getOutputVariables()) {
282 var literalSetForInput = variableToLiteralInputMap.remove(variable);
283 if (literalSetForInput == null) {
284 continue;
285 }
286 for (var targetSortableLiteral : literalSetForInput) {
287 targetSortableLiteral.bindVariable(variable);
288 }
289 }
290 }
291
292 @Override
293 public int compareTo(@NotNull ClausePostProcessor.SortableLiteral other) {
294 return Integer.compare(index, other.index);
295 }
296
297 @Override
298 public boolean equals(Object o) {
299 if (this == o) return true;
300 if (o == null || getClass() != o.getClass()) return false;
301 SortableLiteral that = (SortableLiteral) o;
302 return index == that.index && Objects.equals(literal, that.literal);
303 }
304
305 @Override
306 public int hashCode() {
307 return Objects.hash(index, literal);
308 }
309 }
310
311 public sealed interface Result permits ClauseResult, ConstantResult {
312 }
313
314 public record ClauseResult(DnfClause clause) implements Result {
315 }
316
317 public enum ConstantResult implements Result {
318 ALWAYS_TRUE,
319 ALWAYS_FALSE
320 }
321
322 public record ParameterInfo(ParameterDirection direction, int index) {
323 }
324}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java
index 1b7759c7..c5b51b81 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Dnf.java
@@ -1,57 +1,61 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
8import tools.refinery.store.query.Constraint;
9import tools.refinery.store.query.Reduction;
3import tools.refinery.store.query.equality.DnfEqualityChecker; 10import tools.refinery.store.query.equality.DnfEqualityChecker;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 11import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.Constraint; 12import tools.refinery.store.query.term.Parameter;
6import tools.refinery.store.query.literal.LiteralReduction;
7import tools.refinery.store.query.term.Sort;
8import tools.refinery.store.query.term.Variable; 13import tools.refinery.store.query.term.Variable;
9 14
10import java.util.Collection; 15import java.util.Collection;
11import java.util.HashSet; 16import java.util.Collections;
12import java.util.List; 17import java.util.List;
13import java.util.Set; 18import java.util.Set;
19import java.util.function.Consumer;
20import java.util.stream.Collectors;
14 21
15public final class Dnf implements Constraint { 22public final class Dnf implements Constraint {
16 private static final String INDENTATION = " "; 23 private static final String INDENTATION = " ";
17 24
18 private final String name; 25 private final String name;
19
20 private final String uniqueName; 26 private final String uniqueName;
21 27 private final List<SymbolicParameter> symbolicParameters;
22 private final List<Variable> parameters;
23
24 private final List<FunctionalDependency<Variable>> functionalDependencies; 28 private final List<FunctionalDependency<Variable>> functionalDependencies;
25
26 private final List<DnfClause> clauses; 29 private final List<DnfClause> clauses;
27 30
28 Dnf(String name, List<Variable> parameters, List<FunctionalDependency<Variable>> functionalDependencies, 31 Dnf(String name, List<SymbolicParameter> symbolicParameters,
29 List<DnfClause> clauses) { 32 List<FunctionalDependency<Variable>> functionalDependencies, List<DnfClause> clauses) {
30 validateFunctionalDependencies(parameters, functionalDependencies); 33 validateFunctionalDependencies(symbolicParameters, functionalDependencies);
31 this.name = name; 34 this.name = name;
32 this.uniqueName = DnfUtils.generateUniqueName(name); 35 this.uniqueName = DnfUtils.generateUniqueName(name);
33 this.parameters = parameters; 36 this.symbolicParameters = symbolicParameters;
34 this.functionalDependencies = functionalDependencies; 37 this.functionalDependencies = functionalDependencies;
35 this.clauses = clauses; 38 this.clauses = clauses;
36 } 39 }
37 40
38 private static void validateFunctionalDependencies( 41 private static void validateFunctionalDependencies(
39 Collection<Variable> parameters, Collection<FunctionalDependency<Variable>> functionalDependencies) { 42 Collection<SymbolicParameter> symbolicParameters,
40 var parameterSet = new HashSet<>(parameters); 43 Collection<FunctionalDependency<Variable>> functionalDependencies) {
44 var parameterSet = symbolicParameters.stream().map(SymbolicParameter::getVariable).collect(Collectors.toSet());
41 for (var functionalDependency : functionalDependencies) { 45 for (var functionalDependency : functionalDependencies) {
42 validateParameters(parameters, parameterSet, functionalDependency.forEach(), functionalDependency); 46 validateParameters(symbolicParameters, parameterSet, functionalDependency.forEach(), functionalDependency);
43 validateParameters(parameters, parameterSet, functionalDependency.unique(), functionalDependency); 47 validateParameters(symbolicParameters, parameterSet, functionalDependency.unique(), functionalDependency);
44 } 48 }
45 } 49 }
46 50
47 private static void validateParameters(Collection<Variable> parameters, Set<Variable> parameterSet, 51 private static void validateParameters(Collection<SymbolicParameter> symbolicParameters,
48 Collection<Variable> toValidate, 52 Set<Variable> parameterSet, Collection<Variable> toValidate,
49 FunctionalDependency<Variable> functionalDependency) { 53 FunctionalDependency<Variable> functionalDependency) {
50 for (var variable : toValidate) { 54 for (var variable : toValidate) {
51 if (!parameterSet.contains(variable)) { 55 if (!parameterSet.contains(variable)) {
52 throw new IllegalArgumentException( 56 throw new IllegalArgumentException(
53 "Variable %s of functional dependency %s does not appear in the parameter list %s" 57 "Variable %s of functional dependency %s does not appear in the parameter list %s"
54 .formatted(variable, functionalDependency, parameters)); 58 .formatted(variable, functionalDependency, symbolicParameters));
55 } 59 }
56 } 60 }
57 } 61 }
@@ -69,13 +73,12 @@ public final class Dnf implements Constraint {
69 return uniqueName; 73 return uniqueName;
70 } 74 }
71 75
72 public List<Variable> getParameters() { 76 public List<SymbolicParameter> getSymbolicParameters() {
73 return parameters; 77 return symbolicParameters;
74 } 78 }
75 79
76 @Override 80 public List<Parameter> getParameters() {
77 public List<Sort> getSorts() { 81 return Collections.unmodifiableList(symbolicParameters);
78 return parameters.stream().map(Variable::getSort).toList();
79 } 82 }
80 83
81 public List<FunctionalDependency<Variable>> getFunctionalDependencies() { 84 public List<FunctionalDependency<Variable>> getFunctionalDependencies() {
@@ -84,7 +87,7 @@ public final class Dnf implements Constraint {
84 87
85 @Override 88 @Override
86 public int arity() { 89 public int arity() {
87 return parameters.size(); 90 return symbolicParameters.size();
88 } 91 }
89 92
90 public List<DnfClause> getClauses() { 93 public List<DnfClause> getClauses() {
@@ -100,28 +103,34 @@ public final class Dnf implements Constraint {
100 } 103 }
101 104
102 @Override 105 @Override
103 public LiteralReduction getReduction() { 106 public Reduction getReduction() {
104 if (clauses.isEmpty()) { 107 if (clauses.isEmpty()) {
105 return LiteralReduction.ALWAYS_FALSE; 108 return Reduction.ALWAYS_FALSE;
106 } 109 }
107 for (var clause : clauses) { 110 for (var clause : clauses) {
108 if (clause.literals().isEmpty()) { 111 if (clause.literals().isEmpty()) {
109 return LiteralReduction.ALWAYS_TRUE; 112 return Reduction.ALWAYS_TRUE;
110 } 113 }
111 } 114 }
112 return LiteralReduction.NOT_REDUCIBLE; 115 return Reduction.NOT_REDUCIBLE;
113 } 116 }
114 117
115 public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) { 118 public boolean equalsWithSubstitution(DnfEqualityChecker callEqualityChecker, Dnf other) {
116 if (arity() != other.arity()) { 119 if (arity() != other.arity()) {
117 return false; 120 return false;
118 } 121 }
122 for (int i = 0; i < arity(); i++) {
123 if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) {
124 return false;
125 }
126 }
119 int numClauses = clauses.size(); 127 int numClauses = clauses.size();
120 if (numClauses != other.clauses.size()) { 128 if (numClauses != other.clauses.size()) {
121 return false; 129 return false;
122 } 130 }
123 for (int i = 0; i < numClauses; i++) { 131 for (int i = 0; i < numClauses; i++) {
124 var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, parameters, other.parameters); 132 var literalEqualityHelper = new LiteralEqualityHelper(callEqualityChecker, symbolicParameters,
133 other.symbolicParameters);
125 if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) { 134 if (!clauses.get(i).equalsWithSubstitution(literalEqualityHelper, other.clauses.get(i))) {
126 return false; 135 return false;
127 } 136 }
@@ -139,18 +148,18 @@ public final class Dnf implements Constraint {
139 148
140 @Override 149 @Override
141 public String toString() { 150 public String toString() {
142 return "%s/%d".formatted(name, arity()); 151 return "%s/%d".formatted(name(), arity());
143 } 152 }
144 153
145 @Override 154 @Override
146 public String toReferenceString() { 155 public String toReferenceString() {
147 return "@Dnf " + name; 156 return "@Dnf " + name();
148 } 157 }
149 158
150 public String toDefinitionString() { 159 public String toDefinitionString() {
151 var builder = new StringBuilder(); 160 var builder = new StringBuilder();
152 builder.append("pred ").append(name()).append("("); 161 builder.append("pred ").append(name()).append("(");
153 var parameterIterator = parameters.iterator(); 162 var parameterIterator = symbolicParameters.iterator();
154 if (parameterIterator.hasNext()) { 163 if (parameterIterator.hasNext()) {
155 builder.append(parameterIterator.next()); 164 builder.append(parameterIterator.next());
156 while (parameterIterator.hasNext()) { 165 while (parameterIterator.hasNext()) {
@@ -191,4 +200,14 @@ public final class Dnf implements Constraint {
191 public static DnfBuilder builder(String name) { 200 public static DnfBuilder builder(String name) {
192 return new DnfBuilder(name); 201 return new DnfBuilder(name);
193 } 202 }
203
204 public static Dnf of(Consumer<DnfBuilder> callback) {
205 return of(null, callback);
206 }
207
208 public static Dnf of(String name, Consumer<DnfBuilder> callback) {
209 var builder = builder(name);
210 callback.accept(builder);
211 return builder.build();
212 }
194} 213}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java
index aad5a85f..8e38ca6b 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfBuilder.java
@@ -1,7 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
8import tools.refinery.store.query.dnf.callback.*;
3import tools.refinery.store.query.literal.Literal; 9import tools.refinery.store.query.literal.Literal;
4import tools.refinery.store.query.term.DataVariable; 10import tools.refinery.store.query.term.DataVariable;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.ParameterDirection;
5import tools.refinery.store.query.term.Variable; 13import tools.refinery.store.query.term.Variable;
6 14
7import java.util.*; 15import java.util.*;
@@ -9,23 +17,57 @@ import java.util.*;
9@SuppressWarnings("UnusedReturnValue") 17@SuppressWarnings("UnusedReturnValue")
10public final class DnfBuilder { 18public final class DnfBuilder {
11 private final String name; 19 private final String name;
12 20 private final Set<Variable> parameterVariables = new LinkedHashSet<>();
13 private final List<Variable> parameters = new ArrayList<>(); 21 private final List<SymbolicParameter> parameters = new ArrayList<>();
14
15 private final List<FunctionalDependency<Variable>> functionalDependencies = new ArrayList<>(); 22 private final List<FunctionalDependency<Variable>> functionalDependencies = new ArrayList<>();
16
17 private final List<List<Literal>> clauses = new ArrayList<>(); 23 private final List<List<Literal>> clauses = new ArrayList<>();
18 24
19 DnfBuilder(String name) { 25 DnfBuilder(String name) {
20 this.name = name; 26 this.name = name;
21 } 27 }
22 28
29 public NodeVariable parameter() {
30 return parameter((String) null);
31 }
32
33 public NodeVariable parameter(String name) {
34 return parameter(name, ParameterDirection.OUT);
35 }
36
37 public NodeVariable parameter(ParameterDirection direction) {
38 return parameter((String) null, direction);
39 }
40
41 public NodeVariable parameter(String name, ParameterDirection direction) {
42 var variable = Variable.of(name);
43 parameter(variable, direction);
44 return variable;
45 }
46
47 public <T> DataVariable<T> parameter(Class<T> type) {
48 return parameter(null, type);
49 }
50
51 public <T> DataVariable<T> parameter(String name, Class<T> type) {
52 return parameter(name, type, ParameterDirection.OUT);
53 }
54
55 public <T> DataVariable<T> parameter(Class<T> type, ParameterDirection direction) {
56 return parameter(null, type, direction);
57 }
58
59 public <T> DataVariable<T> parameter(String name, Class<T> type, ParameterDirection direction) {
60 var variable = Variable.of(name, type);
61 parameter(variable, direction);
62 return variable;
63 }
64
23 public DnfBuilder parameter(Variable variable) { 65 public DnfBuilder parameter(Variable variable) {
24 if (parameters.contains(variable)) { 66 return parameter(variable, ParameterDirection.OUT);
25 throw new IllegalArgumentException("Duplicate parameter: " + variable); 67 }
26 } 68
27 parameters.add(variable); 69 public DnfBuilder parameter(Variable variable, ParameterDirection direction) {
28 return this; 70 return symbolicParameter(new SymbolicParameter(variable, direction));
29 } 71 }
30 72
31 public DnfBuilder parameters(Variable... variables) { 73 public DnfBuilder parameters(Variable... variables) {
@@ -33,7 +75,34 @@ public final class DnfBuilder {
33 } 75 }
34 76
35 public DnfBuilder parameters(Collection<? extends Variable> variables) { 77 public DnfBuilder parameters(Collection<? extends Variable> variables) {
36 parameters.addAll(variables); 78 return parameters(variables, ParameterDirection.OUT);
79 }
80
81 public DnfBuilder parameters(Collection<? extends Variable> variables, ParameterDirection direction) {
82 for (var variable : variables) {
83 parameter(variable, direction);
84 }
85 return this;
86 }
87
88 public DnfBuilder symbolicParameter(SymbolicParameter symbolicParameter) {
89 var variable = symbolicParameter.getVariable();
90 if (!parameterVariables.add(variable)) {
91 throw new IllegalArgumentException("Variable %s is already on the parameter list %s"
92 .formatted(variable, parameters));
93 }
94 parameters.add(symbolicParameter);
95 return this;
96 }
97
98 public DnfBuilder symbolicParameters(SymbolicParameter... symbolicParameters) {
99 return symbolicParameters(List.of(symbolicParameters));
100 }
101
102 public DnfBuilder symbolicParameters(Collection<SymbolicParameter> symbolicParameters) {
103 for (var symbolicParameter : symbolicParameters) {
104 symbolicParameter(symbolicParameter);
105 }
37 return this; 106 return this;
38 } 107 }
39 108
@@ -51,33 +120,91 @@ public final class DnfBuilder {
51 return functionalDependency(new FunctionalDependency<>(Set.copyOf(forEach), Set.copyOf(unique))); 120 return functionalDependency(new FunctionalDependency<>(Set.copyOf(forEach), Set.copyOf(unique)));
52 } 121 }
53 122
123 public DnfBuilder clause(ClauseCallback0 callback) {
124 return clause(callback.toLiterals());
125 }
126
127 public DnfBuilder clause(ClauseCallback1Data0 callback) {
128 return clause(callback.toLiterals(Variable.of("v1")));
129 }
130
131 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback1Data1<T> callback) {
132 return clause(callback.toLiterals(Variable.of("v1", type1)));
133 }
134
135 public DnfBuilder clause(ClauseCallback2Data0 callback) {
136 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2")));
137 }
138
139 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback2Data1<T> callback) {
140 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1)));
141 }
142
143 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback2Data2<T1, T2> callback) {
144 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2)));
145 }
146
147 public DnfBuilder clause(ClauseCallback3Data0 callback) {
148 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3")));
149 }
150
151 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback3Data1<T> callback) {
152 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("d1", type1)));
153 }
154
155 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback3Data2<T1, T2> callback) {
156 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1), Variable.of("d2", type2)));
157 }
158
159 public <T1, T2, T3> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3,
160 ClauseCallback3Data3<T1, T2, T3> callback) {
161 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2),
162 Variable.of("d3", type3)));
163 }
164
165 public DnfBuilder clause(ClauseCallback4Data0 callback) {
166 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3"), Variable.of("v4")));
167 }
168
169 public <T> DnfBuilder clause(Class<T> type1, ClauseCallback4Data1<T> callback) {
170 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("v3"), Variable.of("d1",
171 type1)));
172 }
173
174 public <T1, T2> DnfBuilder clause(Class<T1> type1, Class<T2> type2, ClauseCallback4Data2<T1, T2> callback) {
175 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("v2"), Variable.of("d1", type1),
176 Variable.of("d2", type2)));
177 }
178
179 public <T1, T2, T3> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3,
180 ClauseCallback4Data3<T1, T2, T3> callback) {
181 return clause(callback.toLiterals(Variable.of("v1"), Variable.of("d1", type1), Variable.of("d2", type2),
182 Variable.of("d3", type3)));
183 }
184
185 public <T1, T2, T3, T4> DnfBuilder clause(Class<T1> type1, Class<T2> type2, Class<T3> type3, Class<T4> type4,
186 ClauseCallback4Data4<T1, T2, T3, T4> callback) {
187 return clause(callback.toLiterals(Variable.of("d1", type1), Variable.of("d2", type2),
188 Variable.of("d3", type3), Variable.of("d4", type4)));
189 }
190
54 public DnfBuilder clause(Literal... literals) { 191 public DnfBuilder clause(Literal... literals) {
55 clause(List.of(literals)); 192 clause(List.of(literals));
56 return this; 193 return this;
57 } 194 }
58 195
59 public DnfBuilder clause(Collection<? extends Literal> literals) { 196 public DnfBuilder clause(Collection<? extends Literal> literals) {
60 // Remove duplicates by using a hashed data structure. 197 clauses.add(List.copyOf(literals));
61 var filteredLiterals = new LinkedHashSet<Literal>(literals.size());
62 for (var literal : literals) {
63 var reduction = literal.getReduction();
64 switch (reduction) {
65 case NOT_REDUCIBLE -> filteredLiterals.add(literal);
66 case ALWAYS_TRUE -> {
67 // Literals reducible to {@code true} can be omitted, because the model is always assumed to have at
68 // least on object.
69 }
70 case ALWAYS_FALSE -> {
71 // Clauses with {@code false} literals can be omitted entirely.
72 return this;
73 }
74 default -> throw new IllegalArgumentException("Invalid reduction: " + reduction);
75 }
76 }
77 clauses.add(List.copyOf(filteredLiterals));
78 return this; 198 return this;
79 } 199 }
80 200
201 <T> void output(DataVariable<T> outputVariable) {
202 // Copy parameter variables to exclude the newly added {@code outputVariable}.
203 var fromParameters = Set.copyOf(parameterVariables);
204 parameter(outputVariable, ParameterDirection.OUT);
205 functionalDependency(fromParameters, Set.of(outputVariable));
206 }
207
81 public Dnf build() { 208 public Dnf build() {
82 var postProcessedClauses = postProcessClauses(); 209 var postProcessedClauses = postProcessClauses();
83 return new Dnf(name, Collections.unmodifiableList(parameters), 210 return new Dnf(name, Collections.unmodifiableList(parameters),
@@ -85,26 +212,51 @@ public final class DnfBuilder {
85 Collections.unmodifiableList(postProcessedClauses)); 212 Collections.unmodifiableList(postProcessedClauses));
86 } 213 }
87 214
88 <T> void output(DataVariable<T> outputVariable) {
89 functionalDependency(Set.copyOf(parameters), Set.of(outputVariable));
90 parameter(outputVariable);
91 }
92
93 private List<DnfClause> postProcessClauses() { 215 private List<DnfClause> postProcessClauses() {
216 var parameterInfoMap = getParameterInfoMap();
94 var postProcessedClauses = new ArrayList<DnfClause>(clauses.size()); 217 var postProcessedClauses = new ArrayList<DnfClause>(clauses.size());
95 for (var literals : clauses) { 218 for (var literals : clauses) {
96 if (literals.isEmpty()) { 219 var postProcessor = new ClausePostProcessor(parameterInfoMap, literals);
97 // Predicate will always match, the other clauses are irrelevant. 220 var result = postProcessor.postProcessClause();
98 return List.of(new DnfClause(Set.of(), List.of())); 221 if (result instanceof ClausePostProcessor.ClauseResult clauseResult) {
99 } 222 postProcessedClauses.add(clauseResult.clause());
100 var variables = new HashSet<Variable>(); 223 } else if (result instanceof ClausePostProcessor.ConstantResult constantResult) {
101 for (var literal : literals) { 224 switch (constantResult) {
102 variables.addAll(literal.getBoundVariables()); 225 case ALWAYS_TRUE -> {
226 var inputVariables = getInputVariables();
227 return List.of(new DnfClause(inputVariables, List.of()));
228 }
229 case ALWAYS_FALSE -> {
230 // Skip this clause because it can never match.
231 }
232 default -> throw new IllegalStateException("Unexpected ClausePostProcessor.ConstantResult: " +
233 constantResult);
234 }
235 } else {
236 throw new IllegalStateException("Unexpected ClausePostProcessor.Result: " + result);
103 } 237 }
104 parameters.forEach(variables::remove);
105 postProcessedClauses.add(new DnfClause(Collections.unmodifiableSet(variables),
106 Collections.unmodifiableList(literals)));
107 } 238 }
108 return postProcessedClauses; 239 return postProcessedClauses;
109 } 240 }
241
242 private Map<Variable, ClausePostProcessor.ParameterInfo> getParameterInfoMap() {
243 var mutableParameterInfoMap = new LinkedHashMap<Variable, ClausePostProcessor.ParameterInfo>();
244 int arity = parameters.size();
245 for (int i = 0; i < arity; i++) {
246 var parameter = parameters.get(i);
247 mutableParameterInfoMap.put(parameter.getVariable(),
248 new ClausePostProcessor.ParameterInfo(parameter.getDirection(), i));
249 }
250 return Collections.unmodifiableMap(mutableParameterInfoMap);
251 }
252
253 private Set<Variable> getInputVariables() {
254 var inputParameters = new LinkedHashSet<Variable>();
255 for (var parameter : parameters) {
256 if (parameter.getDirection() == ParameterDirection.IN) {
257 inputParameters.add(parameter.getVariable());
258 }
259 }
260 return Collections.unmodifiableSet(inputParameters);
261 }
110} 262}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java
index 01830af1..fdd0d47c 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfClause.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -7,7 +12,7 @@ import tools.refinery.store.query.term.Variable;
7import java.util.List; 12import java.util.List;
8import java.util.Set; 13import java.util.Set;
9 14
10public record DnfClause(Set<Variable> boundVariables, List<Literal> literals) { 15public record DnfClause(Set<Variable> positiveVariables, List<Literal> literals) {
11 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) { 16 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, DnfClause other) {
12 int size = literals.size(); 17 int size = literals.size();
13 if (size != other.literals.size()) { 18 if (size != other.literals.size()) {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java
index 9bcf944c..65ab3634 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/DnfUtils.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import java.util.UUID; 8import java.util.UUID;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java
index f4cd109f..b00b2cb7 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalDependency.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import java.util.HashSet; 8import java.util.HashSet;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java
index 5bf6f8c5..5a32b1ba 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQuery.java
@@ -1,44 +1,47 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import tools.refinery.store.query.literal.CallPolarity; 8import tools.refinery.store.query.literal.CallPolarity;
4import tools.refinery.store.query.term.*; 9import tools.refinery.store.query.term.Aggregator;
10import tools.refinery.store.query.term.AssignedValue;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.Variable;
5 13
6import java.util.ArrayList; 14import java.util.ArrayList;
7import java.util.List; 15import java.util.List;
8import java.util.Objects; 16import java.util.Objects;
9 17
10public final class FunctionalQuery<T> implements Query<T> { 18public final class FunctionalQuery<T> extends Query<T> {
11 private final Dnf dnf;
12 private final Class<T> type; 19 private final Class<T> type;
13 20
14 FunctionalQuery(Dnf dnf, Class<T> type) { 21 FunctionalQuery(Dnf dnf, Class<T> type) {
15 var parameters = dnf.getParameters(); 22 super(dnf);
23 var parameters = dnf.getSymbolicParameters();
16 int outputIndex = dnf.arity() - 1; 24 int outputIndex = dnf.arity() - 1;
17 for (int i = 0; i < outputIndex; i++) { 25 for (int i = 0; i < outputIndex; i++) {
18 var parameter = parameters.get(i); 26 var parameter = parameters.get(i);
19 if (!(parameter instanceof NodeVariable)) { 27 var parameterType = parameter.tryGetType();
20 throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" 28 if (parameterType.isPresent()) {
21 .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); 29 throw new IllegalArgumentException("Expected parameter %s of %s to be a node variable, got %s instead"
30 .formatted(parameter, dnf, parameterType.get().getName()));
22 } 31 }
23 } 32 }
24 var outputParameter = parameters.get(outputIndex); 33 var outputParameter = parameters.get(outputIndex);
25 if (!(outputParameter instanceof DataVariable<?> dataOutputParameter) || 34 var outputParameterType = outputParameter.tryGetType();
26 !dataOutputParameter.getType().equals(type)) { 35 if (outputParameterType.isEmpty() || !outputParameterType.get().equals(type)) {
27 throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" 36 throw new IllegalArgumentException("Expected parameter %s of %s to be %s, but got %s instead".formatted(
28 .formatted(outputParameter, dnf, type, outputParameter.getSort())); 37 outputParameter, dnf, type, outputParameterType.map(Class::getName).orElse("node")));
29 } 38 }
30 this.dnf = dnf;
31 this.type = type; 39 this.type = type;
32 } 40 }
33 41
34 @Override 42 @Override
35 public String name() {
36 return dnf.name();
37 }
38
39 @Override
40 public int arity() { 43 public int arity() {
41 return dnf.arity() - 1; 44 return getDnf().arity() - 1;
42 } 45 }
43 46
44 @Override 47 @Override
@@ -51,17 +54,12 @@ public final class FunctionalQuery<T> implements Query<T> {
51 return null; 54 return null;
52 } 55 }
53 56
54 @Override
55 public Dnf getDnf() {
56 return dnf;
57 }
58
59 public AssignedValue<T> call(List<NodeVariable> arguments) { 57 public AssignedValue<T> call(List<NodeVariable> arguments) {
60 return targetVariable -> { 58 return targetVariable -> {
61 var argumentsWithTarget = new ArrayList<Variable>(arguments.size() + 1); 59 var argumentsWithTarget = new ArrayList<Variable>(arguments.size() + 1);
62 argumentsWithTarget.addAll(arguments); 60 argumentsWithTarget.addAll(arguments);
63 argumentsWithTarget.add(targetVariable); 61 argumentsWithTarget.add(targetVariable);
64 return dnf.call(CallPolarity.POSITIVE, argumentsWithTarget); 62 return getDnf().call(CallPolarity.POSITIVE, argumentsWithTarget);
65 }; 63 };
66 } 64 }
67 65
@@ -75,7 +73,9 @@ public final class FunctionalQuery<T> implements Query<T> {
75 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1); 73 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
76 argumentsWithPlaceholder.addAll(arguments); 74 argumentsWithPlaceholder.addAll(arguments);
77 argumentsWithPlaceholder.add(placeholderVariable); 75 argumentsWithPlaceholder.add(placeholderVariable);
78 return dnf.aggregate(placeholderVariable, aggregator, argumentsWithPlaceholder).toLiteral(targetVariable); 76 return getDnf()
77 .aggregateBy(placeholderVariable, aggregator, argumentsWithPlaceholder)
78 .toLiteral(targetVariable);
79 }; 79 };
80 } 80 }
81 81
@@ -87,17 +87,13 @@ public final class FunctionalQuery<T> implements Query<T> {
87 public boolean equals(Object o) { 87 public boolean equals(Object o) {
88 if (this == o) return true; 88 if (this == o) return true;
89 if (o == null || getClass() != o.getClass()) return false; 89 if (o == null || getClass() != o.getClass()) return false;
90 if (!super.equals(o)) return false;
90 FunctionalQuery<?> that = (FunctionalQuery<?>) o; 91 FunctionalQuery<?> that = (FunctionalQuery<?>) o;
91 return dnf.equals(that.dnf) && type.equals(that.type); 92 return Objects.equals(type, that.type);
92 } 93 }
93 94
94 @Override 95 @Override
95 public int hashCode() { 96 public int hashCode() {
96 return Objects.hash(dnf, type); 97 return Objects.hash(super.hashCode(), type);
97 }
98
99 @Override
100 public String toString() {
101 return dnf.toString();
102 } 98 }
103} 99}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java
index ca2bc006..d1cd7ba8 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/FunctionalQueryBuilder.java
@@ -1,46 +1,29 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import tools.refinery.store.query.literal.Literal; 8import tools.refinery.store.query.term.DataVariable;
4import tools.refinery.store.query.term.Variable;
5 9
6import java.util.Collection; 10public final class FunctionalQueryBuilder<T> extends AbstractQueryBuilder<FunctionalQueryBuilder<T>> {
7import java.util.Set; 11 private final DataVariable<T> outputVariable;
8
9public final class FunctionalQueryBuilder<T> {
10 private final DnfBuilder dnfBuilder;
11 private final Class<T> type; 12 private final Class<T> type;
12 13
13 FunctionalQueryBuilder(DnfBuilder dnfBuilder, Class<T> type) { 14 FunctionalQueryBuilder(DataVariable<T> outputVariable, DnfBuilder dnfBuilder, Class<T> type) {
14 this.dnfBuilder = dnfBuilder; 15 super(dnfBuilder);
16 this.outputVariable = outputVariable;
15 this.type = type; 17 this.type = type;
16 } 18 }
17 19
18 public FunctionalQueryBuilder<T> functionalDependencies(Collection<FunctionalDependency<Variable>> functionalDependencies) { 20 @Override
19 dnfBuilder.functionalDependencies(functionalDependencies); 21 protected FunctionalQueryBuilder<T> self() {
20 return this;
21 }
22
23 public FunctionalQueryBuilder<T> functionalDependency(FunctionalDependency<Variable> functionalDependency) {
24 dnfBuilder.functionalDependency(functionalDependency);
25 return this;
26 }
27
28 public FunctionalQueryBuilder<T> functionalDependency(Set<? extends Variable> forEach, Set<? extends Variable> unique) {
29 dnfBuilder.functionalDependency(forEach, unique);
30 return this;
31 }
32
33 public FunctionalQueryBuilder<T> clause(Literal... literals) {
34 dnfBuilder.clause(literals);
35 return this;
36 }
37
38 public FunctionalQueryBuilder<T> clause(Collection<? extends Literal> literals) {
39 dnfBuilder.clause(literals);
40 return this; 22 return this;
41 } 23 }
42 24
43 public FunctionalQuery<T> build() { 25 public FunctionalQuery<T> build() {
26 dnfBuilder.output(outputVariable);
44 return dnfBuilder.build().asFunction(type); 27 return dnfBuilder.build().asFunction(type);
45 } 28 }
46} 29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
index 32e33052..aaa52ce6 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/Query.java
@@ -1,16 +1,179 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3public sealed interface Query<T> extends AnyQuery permits RelationalQuery, FunctionalQuery { 8import tools.refinery.store.query.dnf.callback.*;
9import tools.refinery.store.query.term.ParameterDirection;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.Objects;
13
14public abstract sealed class Query<T> implements AnyQuery permits FunctionalQuery, RelationalQuery {
15 private static final String OUTPUT_VARIABLE_NAME = "output";
16
17 private final Dnf dnf;
18
19 protected Query(Dnf dnf) {
20 for (var parameter : dnf.getSymbolicParameters()) {
21 if (parameter.getDirection() != ParameterDirection.OUT) {
22 throw new IllegalArgumentException("Query parameter %s with direction %s is not allowed"
23 .formatted(parameter.getVariable(), parameter.getDirection()));
24 }
25 }
26 this.dnf = dnf;
27 }
28
29 @Override
30 public String name() {
31 return dnf.name();
32 }
33
34 @Override
35 public Dnf getDnf() {
36 return dnf;
37 }
38
39 // Allow redeclaration of the method with refined return type.
40 @SuppressWarnings("squid:S3038")
4 @Override 41 @Override
5 Class<T> valueType(); 42 public abstract Class<T> valueType();
6 43
7 T defaultValue(); 44 public abstract T defaultValue();
8 45
9 static QueryBuilder builder() { 46 @Override
10 return new QueryBuilder(); 47 public boolean equals(Object o) {
48 if (this == o) return true;
49 if (o == null || getClass() != o.getClass()) return false;
50 Query<?> that = (Query<?>) o;
51 return Objects.equals(dnf, that.dnf);
52 }
53
54 @Override
55 public int hashCode() {
56 return Objects.hash(dnf);
11 } 57 }
12 58
13 static QueryBuilder builder(String name) { 59 @Override
60 public String toString() {
61 return dnf.toString();
62 }
63
64 public static QueryBuilder builder() {
65 return builder(null);
66 }
67
68 public static QueryBuilder builder(String name) {
14 return new QueryBuilder(name); 69 return new QueryBuilder(name);
15 } 70 }
71
72 public static RelationalQuery of(QueryCallback0 callback) {
73 return of(null, callback);
74 }
75
76 public static RelationalQuery of(String name, QueryCallback0 callback) {
77 var builder = builder(name);
78 callback.accept(builder);
79 return builder.build();
80 }
81
82 public static RelationalQuery of(QueryCallback1 callback) {
83 return of(null, callback);
84 }
85
86 public static RelationalQuery of(String name, QueryCallback1 callback) {
87 var builder = builder(name);
88 callback.accept(builder, builder.parameter("p1"));
89 return builder.build();
90 }
91
92 public static RelationalQuery of(QueryCallback2 callback) {
93 return of(null, callback);
94 }
95
96 public static RelationalQuery of(String name, QueryCallback2 callback) {
97 var builder = builder(name);
98 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"));
99 return builder.build();
100 }
101
102 public static RelationalQuery of(QueryCallback3 callback) {
103 return of(null, callback);
104 }
105
106 public static RelationalQuery of(String name, QueryCallback3 callback) {
107 var builder = builder(name);
108 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"));
109 return builder.build();
110 }
111
112 public static RelationalQuery of(QueryCallback4 callback) {
113 return of(null, callback);
114 }
115
116 public static RelationalQuery of(String name, QueryCallback4 callback) {
117 var builder = builder(name);
118 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
119 builder.parameter("p4"));
120 return builder.build();
121 }
122
123 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback0<T> callback) {
124 return of(null, type, callback);
125 }
126
127 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback0<T> callback) {
128 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
129 var builder = builder(name).output(outputVariable);
130 callback.accept(builder, outputVariable);
131 return builder.build();
132 }
133
134 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback1<T> callback) {
135 return of(null, type, callback);
136 }
137
138 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback1<T> callback) {
139 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
140 var builder = builder(name).output(outputVariable);
141 callback.accept(builder, builder.parameter("p1"), outputVariable);
142 return builder.build();
143 }
144
145 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback2<T> callback) {
146 return of(null, type, callback);
147 }
148
149 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback2<T> callback) {
150 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
151 var builder = builder(name).output(outputVariable);
152 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), outputVariable);
153 return builder.build();
154 }
155
156 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback3<T> callback) {
157 return of(null, type, callback);
158 }
159
160 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback3<T> callback) {
161 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
162 var builder = builder(name).output(outputVariable);
163 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
164 outputVariable);
165 return builder.build();
166 }
167
168 public static <T> FunctionalQuery<T> of(Class<T> type, FunctionalQueryCallback4<T> callback) {
169 return of(null, type, callback);
170 }
171
172 public static <T> FunctionalQuery<T> of(String name, Class<T> type, FunctionalQueryCallback4<T> callback) {
173 var outputVariable = Variable.of(OUTPUT_VARIABLE_NAME, type);
174 var builder = builder(name).output(outputVariable);
175 callback.accept(builder, builder.parameter("p1"), builder.parameter("p2"), builder.parameter("p3"),
176 builder.parameter("p4"), outputVariable);
177 return builder.build();
178 }
16} 179}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java
index ed253cc9..138911bc 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/QueryBuilder.java
@@ -1,68 +1,24 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import tools.refinery.store.query.literal.Literal;
4import tools.refinery.store.query.term.DataVariable; 8import tools.refinery.store.query.term.DataVariable;
5import tools.refinery.store.query.term.NodeVariable;
6import tools.refinery.store.query.term.Variable;
7
8import java.util.Collection;
9import java.util.List;
10import java.util.Set;
11
12public final class QueryBuilder {
13 private final DnfBuilder dnfBuilder;
14 9
10public final class QueryBuilder extends AbstractQueryBuilder<QueryBuilder> {
15 QueryBuilder(String name) { 11 QueryBuilder(String name) {
16 dnfBuilder = Dnf.builder(name); 12 super(Dnf.builder(name));
17 }
18
19 QueryBuilder() {
20 dnfBuilder = Dnf.builder();
21 }
22
23 public QueryBuilder parameter(NodeVariable variable) {
24 dnfBuilder.parameter(variable);
25 return this;
26 } 13 }
27 14
28 public QueryBuilder parameters(NodeVariable... variables) { 15 @Override
29 dnfBuilder.parameters(variables); 16 protected QueryBuilder self() {
30 return this;
31 }
32
33 public QueryBuilder parameters(List<NodeVariable> variables) {
34 dnfBuilder.parameters(variables);
35 return this; 17 return this;
36 } 18 }
37 19
38 public <T> FunctionalQueryBuilder<T> output(DataVariable<T> outputVariable) { 20 public <T> FunctionalQueryBuilder<T> output(DataVariable<T> outputVariable) {
39 dnfBuilder.output(outputVariable); 21 return new FunctionalQueryBuilder<>(outputVariable, dnfBuilder, outputVariable.getType());
40 return new FunctionalQueryBuilder<>(dnfBuilder, outputVariable.getType());
41 }
42
43 public QueryBuilder functionalDependencies(Collection<FunctionalDependency<Variable>> functionalDependencies) {
44 dnfBuilder.functionalDependencies(functionalDependencies);
45 return this;
46 }
47
48 public QueryBuilder functionalDependency(FunctionalDependency<Variable> functionalDependency) {
49 dnfBuilder.functionalDependency(functionalDependency);
50 return this;
51 }
52
53 public QueryBuilder functionalDependency(Set<? extends Variable> forEach, Set<? extends Variable> unique) {
54 dnfBuilder.functionalDependency(forEach, unique);
55 return this;
56 }
57
58 public QueryBuilder clause(Literal... literals) {
59 dnfBuilder.clause(literals);
60 return this;
61 }
62
63 public QueryBuilder clause(Collection<? extends Literal> literals) {
64 dnfBuilder.clause(literals);
65 return this;
66 } 22 }
67 23
68 public RelationalQuery build() { 24 public RelationalQuery build() {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java
index 5307e509..d34a7ace 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/RelationalQuery.java
@@ -1,36 +1,33 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.dnf; 6package tools.refinery.store.query.dnf;
2 7
3import tools.refinery.store.query.literal.CallLiteral; 8import tools.refinery.store.query.literal.CallLiteral;
4import tools.refinery.store.query.literal.CallPolarity; 9import tools.refinery.store.query.literal.CallPolarity;
5import tools.refinery.store.query.term.AssignedValue; 10import tools.refinery.store.query.term.AssignedValue;
6import tools.refinery.store.query.term.NodeSort;
7import tools.refinery.store.query.term.NodeVariable; 11import tools.refinery.store.query.term.NodeVariable;
8 12
9import java.util.Collections; 13import java.util.Collections;
10import java.util.List; 14import java.util.List;
11import java.util.Objects;
12
13public final class RelationalQuery implements Query<Boolean> {
14 private final Dnf dnf;
15 15
16public final class RelationalQuery extends Query<Boolean> {
16 RelationalQuery(Dnf dnf) { 17 RelationalQuery(Dnf dnf) {
17 for (var parameter : dnf.getParameters()) { 18 super(dnf);
18 if (!(parameter instanceof NodeVariable)) { 19 for (var parameter : dnf.getSymbolicParameters()) {
19 throw new IllegalArgumentException("Expected parameter %s of %s to be of sort %s, but got %s instead" 20 var parameterType = parameter.tryGetType();
20 .formatted(parameter, dnf, NodeSort.INSTANCE, parameter.getSort())); 21 if (parameterType.isPresent()) {
22 throw new IllegalArgumentException("Expected parameter %s of %s to be a node variable, got %s instead"
23 .formatted(parameter, dnf, parameterType.get().getName()));
21 } 24 }
22 } 25 }
23 this.dnf = dnf;
24 }
25
26 @Override
27 public String name() {
28 return dnf.name();
29 } 26 }
30 27
31 @Override 28 @Override
32 public int arity() { 29 public int arity() {
33 return dnf.arity(); 30 return getDnf().arity();
34 } 31 }
35 32
36 @Override 33 @Override
@@ -43,51 +40,27 @@ public final class RelationalQuery implements Query<Boolean> {
43 return false; 40 return false;
44 } 41 }
45 42
46 @Override
47 public Dnf getDnf() {
48 return dnf;
49 }
50
51 public CallLiteral call(CallPolarity polarity, List<NodeVariable> arguments) { 43 public CallLiteral call(CallPolarity polarity, List<NodeVariable> arguments) {
52 return dnf.call(polarity, Collections.unmodifiableList(arguments)); 44 return getDnf().call(polarity, Collections.unmodifiableList(arguments));
53 } 45 }
54 46
55 public CallLiteral call(CallPolarity polarity, NodeVariable... arguments) { 47 public CallLiteral call(CallPolarity polarity, NodeVariable... arguments) {
56 return dnf.call(polarity, arguments); 48 return getDnf().call(polarity, arguments);
57 } 49 }
58 50
59 public CallLiteral call(NodeVariable... arguments) { 51 public CallLiteral call(NodeVariable... arguments) {
60 return dnf.call(arguments); 52 return getDnf().call(arguments);
61 } 53 }
62 54
63 public CallLiteral callTransitive(NodeVariable left, NodeVariable right) { 55 public CallLiteral callTransitive(NodeVariable left, NodeVariable right) {
64 return dnf.callTransitive(left, right); 56 return getDnf().callTransitive(left, right);
65 } 57 }
66 58
67 public AssignedValue<Integer> count(List<NodeVariable> arguments) { 59 public AssignedValue<Integer> count(List<NodeVariable> arguments) {
68 return dnf.count(Collections.unmodifiableList(arguments)); 60 return getDnf().count(Collections.unmodifiableList(arguments));
69 } 61 }
70 62
71 public AssignedValue<Integer> count(NodeVariable... arguments) { 63 public AssignedValue<Integer> count(NodeVariable... arguments) {
72 return dnf.count(arguments); 64 return getDnf().count(arguments);
73 }
74
75
76 @Override
77 public boolean equals(Object o) {
78 if (this == o) return true;
79 if (o == null || getClass() != o.getClass()) return false;
80 RelationalQuery that = (RelationalQuery) o;
81 return dnf.equals(that.dnf);
82 }
83
84 @Override
85 public int hashCode() {
86 return Objects.hash(dnf);
87 }
88
89 @Override
90 public String toString() {
91 return dnf.toString();
92 } 65 }
93} 66}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
new file mode 100644
index 00000000..e0d3ba1f
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/SymbolicParameter.java
@@ -0,0 +1,52 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import tools.refinery.store.query.term.Parameter;
9import tools.refinery.store.query.term.ParameterDirection;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.Objects;
13
14public final class SymbolicParameter extends Parameter {
15 private final Variable variable;
16
17 public SymbolicParameter(Variable variable, ParameterDirection direction) {
18 super(variable.tryGetType().orElse(null), direction);
19 this.variable = variable;
20 }
21
22 public Variable getVariable() {
23 return variable;
24 }
25
26 public boolean isUnifiable() {
27 return variable.isUnifiable();
28 }
29
30 @Override
31 public String toString() {
32 var direction = getDirection();
33 if (direction == ParameterDirection.OUT) {
34 return variable.toString();
35 }
36 return "%s %s".formatted(getDirection(), variable);
37 }
38
39 @Override
40 public boolean equals(Object o) {
41 if (this == o) return true;
42 if (o == null || getClass() != o.getClass()) return false;
43 if (!super.equals(o)) return false;
44 SymbolicParameter that = (SymbolicParameter) o;
45 return Objects.equals(variable, that.variable);
46 }
47
48 @Override
49 public int hashCode() {
50 return Objects.hash(super.hashCode(), variable);
51 }
52}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java
new file mode 100644
index 00000000..d98dda2e
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback0.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9
10import java.util.Collection;
11
12@FunctionalInterface
13public interface ClauseCallback0 {
14 Collection<Literal> toLiterals();
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java
new file mode 100644
index 00000000..4c01a527
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data0.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback1Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java
new file mode 100644
index 00000000..2c0cb6eb
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback1Data1.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback1Data1<T> {
15 Collection<Literal> toLiterals(DataVariable<T> d1);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java
new file mode 100644
index 00000000..d764bdba
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data0.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback2Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java
new file mode 100644
index 00000000..140af03a
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data1.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback2Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T> x1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java
new file mode 100644
index 00000000..bfc8637c
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback2Data2.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback2Data2<T1, T2> {
15 Collection<Literal> toLiterals(DataVariable<T1> x1, DataVariable<T2> x2);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java
new file mode 100644
index 00000000..074df65b
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data0.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback3Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java
new file mode 100644
index 00000000..24ba5187
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data1.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback3Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, DataVariable<T> d1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java
new file mode 100644
index 00000000..2a2e837a
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data2.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback3Data2<T1, T2> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T1> d1, DataVariable<T2> d2);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java
new file mode 100644
index 00000000..8f4bdd01
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback3Data3.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback3Data3<T1, T2, T3> {
15 Collection<Literal> toLiterals(DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java
new file mode 100644
index 00000000..ed0f87b2
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data0.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.NodeVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback4Data0 {
15 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3, NodeVariable v4);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java
new file mode 100644
index 00000000..9b27e2e1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data1.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data1<T> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, NodeVariable v3, DataVariable<T> d1);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java
new file mode 100644
index 00000000..cbc4808e
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data2.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data2<T1, T2> {
16 Collection<Literal> toLiterals(NodeVariable v1, NodeVariable v2, DataVariable<T1> d1, DataVariable<T2> d2);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java
new file mode 100644
index 00000000..a6258f36
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data3.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12import java.util.Collection;
13
14@FunctionalInterface
15public interface ClauseCallback4Data3<T1, T2, T3> {
16 Collection<Literal> toLiterals(NodeVariable v1, DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3);
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java
new file mode 100644
index 00000000..b52a911a
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/ClauseCallback4Data4.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.literal.Literal;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collection;
12
13@FunctionalInterface
14public interface ClauseCallback4Data4<T1, T2, T3, T4> {
15 Collection<Literal> toLiterals(DataVariable<T1> d1, DataVariable<T2> d2, DataVariable<T3> d3, DataVariable<T4> d4);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java
new file mode 100644
index 00000000..63b3eee6
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback0.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10
11@FunctionalInterface
12public interface FunctionalQueryCallback0<T> {
13 void accept(FunctionalQueryBuilder<T> builder, DataVariable<T> output);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java
new file mode 100644
index 00000000..1295a118
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback1.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback1<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, DataVariable<T> output);
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java
new file mode 100644
index 00000000..d5b7f9ff
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback2.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback2<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, DataVariable<T> output);
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java
new file mode 100644
index 00000000..dc8404a0
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback3.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback3<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, NodeVariable p3,
15 DataVariable<T> output);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java
new file mode 100644
index 00000000..b6d3ddb0
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/FunctionalQueryCallback4.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.FunctionalQueryBuilder;
9import tools.refinery.store.query.term.DataVariable;
10import tools.refinery.store.query.term.NodeVariable;
11
12@FunctionalInterface
13public interface FunctionalQueryCallback4<T> {
14 void accept(FunctionalQueryBuilder<T> builder, NodeVariable p1, NodeVariable p2, NodeVariable p3, NodeVariable p4,
15 DataVariable<T> output);
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java
new file mode 100644
index 00000000..3cf1de48
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback0.java
@@ -0,0 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9
10@FunctionalInterface
11public interface QueryCallback0 {
12 void accept(QueryBuilder builder);
13}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java
new file mode 100644
index 00000000..0a150955
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback1.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback1 {
13 void accept(QueryBuilder builder, NodeVariable p1);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java
new file mode 100644
index 00000000..9493a7b4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback2.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback2 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java
new file mode 100644
index 00000000..358c7da7
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback3.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback3 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java
new file mode 100644
index 00000000..890dda16
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/dnf/callback/QueryCallback4.java
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf.callback;
7
8import tools.refinery.store.query.dnf.QueryBuilder;
9import tools.refinery.store.query.term.NodeVariable;
10
11@FunctionalInterface
12public interface QueryCallback4 {
13 void accept(QueryBuilder builder, NodeVariable p1, NodeVariable p2, NodeVariable p3, NodeVariable p4);
14}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java
index c3bc3ea3..1eeb5723 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DeepDnfEqualityChecker.java
@@ -1,6 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.equality; 6package tools.refinery.store.query.equality;
2 7
3import tools.refinery.store.query.dnf.Dnf; 8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.DnfClause;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.literal.Literal;
4import tools.refinery.store.util.CycleDetectingMapper; 12import tools.refinery.store.util.CycleDetectingMapper;
5 13
6import java.util.List; 14import java.util.List;
@@ -14,6 +22,45 @@ public class DeepDnfEqualityChecker implements DnfEqualityChecker {
14 return mapper.map(new Pair(left, right)); 22 return mapper.map(new Pair(left, right));
15 } 23 }
16 24
25 public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters,
26 List<? extends List<? extends Literal>> clauses, Dnf other) {
27 int arity = symbolicParameters.size();
28 if (arity != other.arity()) {
29 return false;
30 }
31 for (int i = 0; i < arity; i++) {
32 if (!symbolicParameters.get(i).getDirection().equals(other.getSymbolicParameters().get(i).getDirection())) {
33 return false;
34 }
35 }
36 int numClauses = clauses.size();
37 if (numClauses != other.getClauses().size()) {
38 return false;
39 }
40 for (int i = 0; i < numClauses; i++) {
41 var literalEqualityHelper = new LiteralEqualityHelper(this, symbolicParameters,
42 other.getSymbolicParameters());
43 if (!equalsWithSubstitutionRaw(literalEqualityHelper, clauses.get(i), other.getClauses().get(i))) {
44 return false;
45 }
46 }
47 return true;
48 }
49
50 private boolean equalsWithSubstitutionRaw(LiteralEqualityHelper helper, List<? extends Literal> literals,
51 DnfClause other) {
52 int size = literals.size();
53 if (size != other.literals().size()) {
54 return false;
55 }
56 for (int i = 0; i < size; i++) {
57 if (!literals.get(i).equalsWithSubstitution(helper, other.literals().get(i))) {
58 return false;
59 }
60 }
61 return true;
62 }
63
17 protected boolean doCheckEqual(Pair pair) { 64 protected boolean doCheckEqual(Pair pair) {
18 return pair.left.equalsWithSubstitution(this, pair.right); 65 return pair.left.equalsWithSubstitution(this, pair.right);
19 } 66 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java
index 6b1f2076..4a8bee3b 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/DnfEqualityChecker.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.equality; 6package tools.refinery.store.query.equality;
2 7
3import tools.refinery.store.query.dnf.Dnf; 8import tools.refinery.store.query.dnf.Dnf;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java
index 07d261ea..9315fb30 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/equality/LiteralEqualityHelper.java
@@ -1,6 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.equality; 6package tools.refinery.store.query.equality;
2 7
3import tools.refinery.store.query.dnf.Dnf; 8import tools.refinery.store.query.dnf.Dnf;
9import tools.refinery.store.query.dnf.SymbolicParameter;
4import tools.refinery.store.query.term.Variable; 10import tools.refinery.store.query.term.Variable;
5 11
6import java.util.HashMap; 12import java.util.HashMap;
@@ -12,8 +18,8 @@ public class LiteralEqualityHelper {
12 private final Map<Variable, Variable> leftToRight; 18 private final Map<Variable, Variable> leftToRight;
13 private final Map<Variable, Variable> rightToLeft; 19 private final Map<Variable, Variable> rightToLeft;
14 20
15 public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List<Variable> leftParameters, 21 public LiteralEqualityHelper(DnfEqualityChecker dnfEqualityChecker, List<SymbolicParameter> leftParameters,
16 List<Variable> rightParameters) { 22 List<SymbolicParameter> rightParameters) {
17 this.dnfEqualityChecker = dnfEqualityChecker; 23 this.dnfEqualityChecker = dnfEqualityChecker;
18 var arity = leftParameters.size(); 24 var arity = leftParameters.size();
19 if (arity != rightParameters.size()) { 25 if (arity != rightParameters.size()) {
@@ -22,7 +28,7 @@ public class LiteralEqualityHelper {
22 leftToRight = new HashMap<>(arity); 28 leftToRight = new HashMap<>(arity);
23 rightToLeft = new HashMap<>(arity); 29 rightToLeft = new HashMap<>(arity);
24 for (int i = 0; i < arity; i++) { 30 for (int i = 0; i < arity; i++) {
25 if (!variableEqual(leftParameters.get(i), rightParameters.get(i))) { 31 if (!variableEqual(leftParameters.get(i).getVariable(), rightParameters.get(i).getVariable())) {
26 throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i); 32 throw new IllegalArgumentException("Parameter lists cannot be unified: duplicate parameter " + i);
27 } 33 }
28 } 34 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
index 657ca26b..8ef8e8b4 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AbstractCallLiteral.java
@@ -1,17 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 10import tools.refinery.store.query.substitution.Substitution;
11import tools.refinery.store.query.term.ParameterDirection;
6import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
7 13
8import java.util.List; 14import java.util.*;
9import java.util.Objects;
10 15
11public abstract class AbstractCallLiteral implements Literal { 16public abstract class AbstractCallLiteral implements Literal {
12 private final Constraint target; 17 private final Constraint target;
13 private final List<Variable> arguments; 18 private final List<Variable> arguments;
19 private final Set<Variable> inArguments;
20 private final Set<Variable> outArguments;
14 21
22 // Use exhaustive switch over enums.
23 @SuppressWarnings("squid:S1301")
15 protected AbstractCallLiteral(Constraint target, List<Variable> arguments) { 24 protected AbstractCallLiteral(Constraint target, List<Variable> arguments) {
16 int arity = target.arity(); 25 int arity = target.arity();
17 if (arguments.size() != arity) { 26 if (arguments.size() != arity) {
@@ -20,14 +29,46 @@ public abstract class AbstractCallLiteral implements Literal {
20 } 29 }
21 this.target = target; 30 this.target = target;
22 this.arguments = arguments; 31 this.arguments = arguments;
23 var sorts = target.getSorts(); 32 var mutableInArguments = new LinkedHashSet<Variable>();
33 var mutableOutArguments = new LinkedHashSet<Variable>();
34 var parameters = target.getParameters();
24 for (int i = 0; i < arity; i++) { 35 for (int i = 0; i < arity; i++) {
25 var argument = arguments.get(i); 36 var argument = arguments.get(i);
26 var sort = sorts.get(i); 37 var parameter = parameters.get(i);
27 if (!sort.isInstance(argument)) { 38 if (!parameter.isAssignable(argument)) {
28 throw new IllegalArgumentException("Required argument %d of %s to be of sort %s, but got %s instead" 39 throw new IllegalArgumentException("Argument %d of %s is not assignable to parameter %s"
29 .formatted(i, target, sort, argument.getSort())); 40 .formatted(i, target, parameter));
30 } 41 }
42 switch (parameter.getDirection()) {
43 case IN -> {
44 if (mutableOutArguments.remove(argument)) {
45 checkInOutUnifiable(argument);
46 }
47 mutableInArguments.add(argument);
48 }
49 case OUT -> {
50 if (mutableInArguments.contains(argument)) {
51 checkInOutUnifiable(argument);
52 } else if (!mutableOutArguments.add(argument)) {
53 checkDuplicateOutUnifiable(argument);
54 }
55 }
56 }
57 }
58 inArguments = Collections.unmodifiableSet(mutableInArguments);
59 outArguments = Collections.unmodifiableSet(mutableOutArguments);
60 }
61
62 private static void checkInOutUnifiable(Variable argument) {
63 if (!argument.isUnifiable()) {
64 throw new IllegalArgumentException("Argument %s cannot appear with both %s and %s direction"
65 .formatted(argument, ParameterDirection.IN, ParameterDirection.OUT));
66 }
67 }
68
69 private static void checkDuplicateOutUnifiable(Variable argument) {
70 if (!argument.isUnifiable()) {
71 throw new IllegalArgumentException("Argument %s cannot be bound multiple times".formatted(argument));
31 } 72 }
32 } 73 }
33 74
@@ -39,6 +80,28 @@ public abstract class AbstractCallLiteral implements Literal {
39 return arguments; 80 return arguments;
40 } 81 }
41 82
83 protected Set<Variable> getArgumentsOfDirection(ParameterDirection direction) {
84 return switch (direction) {
85 case IN -> inArguments;
86 case OUT -> outArguments;
87 };
88 }
89
90 @Override
91 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
92 var inputVariables = new LinkedHashSet<>(getArgumentsOfDirection(ParameterDirection.OUT));
93 inputVariables.retainAll(positiveVariablesInClause);
94 inputVariables.addAll(getArgumentsOfDirection(ParameterDirection.IN));
95 return Collections.unmodifiableSet(inputVariables);
96 }
97
98 @Override
99 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
100 var privateVariables = new LinkedHashSet<>(getArgumentsOfDirection(ParameterDirection.OUT));
101 privateVariables.removeAll(positiveVariablesInClause);
102 return Collections.unmodifiableSet(privateVariables);
103 }
104
42 @Override 105 @Override
43 public Literal substitute(Substitution substitution) { 106 public Literal substitute(Substitution substitution) {
44 var substitutedArguments = arguments.stream().map(substitution::getSubstitute).toList(); 107 var substitutedArguments = arguments.stream().map(substitution::getSubstitute).toList();
@@ -75,6 +138,6 @@ public abstract class AbstractCallLiteral implements Literal {
75 138
76 @Override 139 @Override
77 public int hashCode() { 140 public int hashCode() {
78 return Objects.hash(target, arguments); 141 return Objects.hash(getClass(), target, arguments);
79 } 142 }
80} 143}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java
index df64839c..3a5eb5c7 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AggregationLiteral.java
@@ -1,11 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 10import tools.refinery.store.query.substitution.Substitution;
6import tools.refinery.store.query.term.Aggregator; 11import tools.refinery.store.query.term.*;
7import tools.refinery.store.query.term.DataVariable;
8import tools.refinery.store.query.term.Variable;
9 12
10import java.util.List; 13import java.util.List;
11import java.util.Objects; 14import java.util.Objects;
@@ -23,14 +26,14 @@ public class AggregationLiteral<R, T> extends AbstractCallLiteral {
23 throw new IllegalArgumentException("Input variable %s must of type %s, got %s instead".formatted( 26 throw new IllegalArgumentException("Input variable %s must of type %s, got %s instead".formatted(
24 inputVariable, aggregator.getInputType().getName(), inputVariable.getType().getName())); 27 inputVariable, aggregator.getInputType().getName(), inputVariable.getType().getName()));
25 } 28 }
29 if (!getArgumentsOfDirection(ParameterDirection.OUT).contains(inputVariable)) {
30 throw new IllegalArgumentException("Input variable %s must be bound with direction %s in the argument list"
31 .formatted(inputVariable, ParameterDirection.OUT));
32 }
26 if (!resultVariable.getType().equals(aggregator.getResultType())) { 33 if (!resultVariable.getType().equals(aggregator.getResultType())) {
27 throw new IllegalArgumentException("Result variable %s must of type %s, got %s instead".formatted( 34 throw new IllegalArgumentException("Result variable %s must of type %s, got %s instead".formatted(
28 resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName())); 35 resultVariable, aggregator.getResultType().getName(), resultVariable.getType().getName()));
29 } 36 }
30 if (!arguments.contains(inputVariable)) {
31 throw new IllegalArgumentException("Input variable %s must appear in the argument list".formatted(
32 inputVariable));
33 }
34 if (arguments.contains(resultVariable)) { 37 if (arguments.contains(resultVariable)) {
35 throw new IllegalArgumentException("Result variable %s must not appear in the argument list".formatted( 38 throw new IllegalArgumentException("Result variable %s must not appear in the argument list".formatted(
36 resultVariable)); 39 resultVariable));
@@ -53,11 +56,33 @@ public class AggregationLiteral<R, T> extends AbstractCallLiteral {
53 } 56 }
54 57
55 @Override 58 @Override
56 public Set<Variable> getBoundVariables() { 59 public Set<Variable> getOutputVariables() {
57 return Set.of(resultVariable); 60 return Set.of(resultVariable);
58 } 61 }
59 62
60 @Override 63 @Override
64 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
65 if (positiveVariablesInClause.contains(inputVariable)) {
66 throw new IllegalArgumentException("Aggregation variable %s must not be bound".formatted(inputVariable));
67 }
68 return super.getInputVariables(positiveVariablesInClause);
69 }
70
71 @Override
72 public Literal reduce() {
73 var reduction = getTarget().getReduction();
74 return switch (reduction) {
75 case ALWAYS_FALSE -> {
76 var emptyValue = aggregator.getEmptyResult();
77 yield emptyValue == null ? BooleanLiteral.FALSE :
78 resultVariable.assign(new ConstantTerm<>(resultVariable.getType(), emptyValue));
79 }
80 case ALWAYS_TRUE -> throw new IllegalArgumentException("Trying to aggregate over an infinite set");
81 case NOT_REDUCIBLE -> this;
82 };
83 }
84
85 @Override
61 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) { 86 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
62 return new AggregationLiteral<>(substitution.getTypeSafeSubstitute(resultVariable), aggregator, 87 return new AggregationLiteral<>(substitution.getTypeSafeSubstitute(resultVariable), aggregator,
63 substitution.getTypeSafeSubstitute(inputVariable), getTarget(), substitutedArguments); 88 substitution.getTypeSafeSubstitute(inputVariable), getTarget(), substitutedArguments);
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java
index 52ac42d7..dbf999a2 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssignLiteral.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -6,6 +11,8 @@ import tools.refinery.store.query.term.DataVariable;
6import tools.refinery.store.query.term.Term; 11import tools.refinery.store.query.term.Term;
7import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
8 13
14import java.util.Collections;
15import java.util.Objects;
9import java.util.Set; 16import java.util.Set;
10 17
11public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implements Literal { 18public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implements Literal {
@@ -14,14 +21,29 @@ public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implement
14 throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted( 21 throw new IllegalArgumentException("Term %s must be of type %s, got %s instead".formatted(
15 term, variable.getType().getName(), term.getType().getName())); 22 term, variable.getType().getName(), term.getType().getName()));
16 } 23 }
24 var inputVariables = term.getInputVariables();
25 if (inputVariables.contains(variable)) {
26 throw new IllegalArgumentException("Result variable %s must not appear in the term %s".formatted(
27 variable, term));
28 }
17 } 29 }
18 30
19 @Override 31 @Override
20 public Set<Variable> getBoundVariables() { 32 public Set<Variable> getOutputVariables() {
21 return Set.of(variable); 33 return Set.of(variable);
22 } 34 }
23 35
24 @Override 36 @Override
37 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
38 return Collections.unmodifiableSet(term.getInputVariables());
39 }
40
41 @Override
42 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
43 return Set.of();
44 }
45
46 @Override
25 public Literal substitute(Substitution substitution) { 47 public Literal substitute(Substitution substitution) {
26 return new AssignLiteral<>(substitution.getTypeSafeSubstitute(variable), term.substitute(substitution)); 48 return new AssignLiteral<>(substitution.getTypeSafeSubstitute(variable), term.substitute(substitution));
27 } 49 }
@@ -36,9 +58,22 @@ public record AssignLiteral<T>(DataVariable<T> variable, Term<T> term) implement
36 otherLetLiteral.term); 58 otherLetLiteral.term);
37 } 59 }
38 60
39
40 @Override 61 @Override
41 public String toString() { 62 public String toString() {
42 return "%s is (%s)".formatted(variable, term); 63 return "%s is (%s)".formatted(variable, term);
43 } 64 }
65
66 @Override
67 public boolean equals(Object obj) {
68 if (obj == this) return true;
69 if (obj == null || obj.getClass() != this.getClass()) return false;
70 var that = (AssignLiteral<?>) obj;
71 return Objects.equals(this.variable, that.variable) &&
72 Objects.equals(this.term, that.term);
73 }
74
75 @Override
76 public int hashCode() {
77 return Objects.hash(getClass(), variable, term);
78 }
44} 79}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java
index 0b4267b4..1ca04c77 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/AssumeLiteral.java
@@ -1,11 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
4import tools.refinery.store.query.substitution.Substitution; 9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.ConstantTerm;
5import tools.refinery.store.query.term.Term; 11import tools.refinery.store.query.term.Term;
6import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
7import tools.refinery.store.query.term.bool.BoolConstantTerm;
8 13
14import java.util.Collections;
15import java.util.Objects;
9import java.util.Set; 16import java.util.Set;
10 17
11public record AssumeLiteral(Term<Boolean> term) implements Literal { 18public record AssumeLiteral(Term<Boolean> term) implements Literal {
@@ -17,11 +24,22 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal {
17 } 24 }
18 25
19 @Override 26 @Override
20 public Set<Variable> getBoundVariables() { 27 public Set<Variable> getOutputVariables() {
21 return Set.of(); 28 return Set.of();
22 } 29 }
23 30
24 @Override 31 @Override
32 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
33 return Collections.unmodifiableSet(term.getInputVariables());
34 }
35
36 @Override
37 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
38 return Set.of();
39 }
40
41
42 @Override
25 public Literal substitute(Substitution substitution) { 43 public Literal substitute(Substitution substitution) {
26 return new AssumeLiteral(term.substitute(substitution)); 44 return new AssumeLiteral(term.substitute(substitution));
27 } 45 }
@@ -36,18 +54,30 @@ public record AssumeLiteral(Term<Boolean> term) implements Literal {
36 } 54 }
37 55
38 @Override 56 @Override
39 public LiteralReduction getReduction() { 57 public Literal reduce() {
40 if (BoolConstantTerm.TRUE.equals(term)) { 58 if (term instanceof ConstantTerm<Boolean> constantTerm) {
41 return LiteralReduction.ALWAYS_TRUE; 59 // Return {@link BooleanLiteral#FALSE} for {@code false} or {@code null} literals.
42 } else if (BoolConstantTerm.FALSE.equals(term)) { 60 return Boolean.TRUE.equals(constantTerm.getValue()) ? BooleanLiteral.TRUE :
43 return LiteralReduction.ALWAYS_FALSE; 61 BooleanLiteral.FALSE;
44 } else {
45 return LiteralReduction.NOT_REDUCIBLE;
46 } 62 }
63 return this;
47 } 64 }
48 65
49 @Override 66 @Override
50 public String toString() { 67 public String toString() {
51 return "(%s)".formatted(term); 68 return "(%s)".formatted(term);
52 } 69 }
70
71 @Override
72 public boolean equals(Object obj) {
73 if (obj == this) return true;
74 if (obj == null || obj.getClass() != this.getClass()) return false;
75 var that = (AssumeLiteral) obj;
76 return Objects.equals(this.term, that.term);
77 }
78
79 @Override
80 public int hashCode() {
81 return Objects.hash(getClass(), term);
82 }
53} 83}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java
index 38be61a4..f312d202 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/BooleanLiteral.java
@@ -1,8 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.term.Variable;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.Variable;
6 11
7import java.util.Set; 12import java.util.Set;
8 13
@@ -17,19 +22,24 @@ public enum BooleanLiteral implements CanNegate<BooleanLiteral> {
17 } 22 }
18 23
19 @Override 24 @Override
20 public Set<Variable> getBoundVariables() { 25 public Set<Variable> getOutputVariables() {
21 return Set.of(); 26 return Set.of();
22 } 27 }
23 28
24 @Override 29 @Override
25 public Literal substitute(Substitution substitution) { 30 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
26 // No variables to substitute. 31 return Set.of();
27 return this;
28 } 32 }
29 33
30 @Override 34 @Override
31 public LiteralReduction getReduction() { 35 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
32 return value ? LiteralReduction.ALWAYS_TRUE : LiteralReduction.ALWAYS_FALSE; 36 return Set.of();
37 }
38
39 @Override
40 public Literal substitute(Substitution substitution) {
41 // No variables to substitute.
42 return this;
33 } 43 }
34 44
35 @Override 45 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java
index 78fae7f5..29772aee 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallLiteral.java
@@ -1,26 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 10import tools.refinery.store.query.substitution.Substitution;
6import tools.refinery.store.query.term.NodeSort; 11import tools.refinery.store.query.term.ParameterDirection;
7import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
8 13
9import java.util.List; 14import java.util.*;
10import java.util.Objects;
11import java.util.Set;
12 15
13public final class CallLiteral extends AbstractCallLiteral implements CanNegate<CallLiteral> { 16public final class CallLiteral extends AbstractCallLiteral implements CanNegate<CallLiteral> {
14 private final CallPolarity polarity; 17 private final CallPolarity polarity;
15 18
16 public CallLiteral(CallPolarity polarity, Constraint target, List<Variable> arguments) { 19 public CallLiteral(CallPolarity polarity, Constraint target, List<Variable> arguments) {
17 super(target, arguments); 20 super(target, arguments);
21 var parameters = target.getParameters();
22 int arity = target.arity();
18 if (polarity.isTransitive()) { 23 if (polarity.isTransitive()) {
19 if (target.arity() != 2) { 24 if (arity != 2) {
20 throw new IllegalArgumentException("Transitive closures can only take binary relations"); 25 throw new IllegalArgumentException("Transitive closures can only take binary relations");
21 } 26 }
22 var sorts = target.getSorts(); 27 if (parameters.get(0).isDataVariable() || parameters.get(1).isDataVariable()) {
23 if (!sorts.get(0).equals(NodeSort.INSTANCE) || !sorts.get(1).equals(NodeSort.INSTANCE)) {
24 throw new IllegalArgumentException("Transitive closures can only be computed over nodes"); 28 throw new IllegalArgumentException("Transitive closures can only be computed over nodes");
25 } 29 }
26 } 30 }
@@ -32,19 +36,43 @@ public final class CallLiteral extends AbstractCallLiteral implements CanNegate<
32 } 36 }
33 37
34 @Override 38 @Override
35 public Set<Variable> getBoundVariables() { 39 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
36 return polarity.isPositive() ? Set.copyOf(getArguments()) : Set.of(); 40 return new CallLiteral(polarity, getTarget(), substitutedArguments);
37 } 41 }
38 42
39 @Override 43 @Override
40 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) { 44 public Set<Variable> getOutputVariables() {
41 return new CallLiteral(polarity, getTarget(), substitutedArguments); 45 if (polarity.isPositive()) {
46 return getArgumentsOfDirection(ParameterDirection.OUT);
47 }
48 return Set.of();
49 }
50
51 @Override
52 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
53 if (polarity.isPositive()) {
54 return getArgumentsOfDirection(ParameterDirection.IN);
55 }
56 return super.getInputVariables(positiveVariablesInClause);
57 }
58
59 @Override
60 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
61 if (polarity.isPositive()) {
62 return Set.of();
63 }
64 return super.getPrivateVariables(positiveVariablesInClause);
42 } 65 }
43 66
44 @Override 67 @Override
45 public LiteralReduction getReduction() { 68 public Literal reduce() {
46 var reduction = getTarget().getReduction(); 69 var reduction = getTarget().getReduction();
47 return polarity.isPositive() ? reduction : reduction.negate(); 70 var negatedReduction = polarity.isPositive() ? reduction : reduction.negate();
71 return switch (negatedReduction) {
72 case ALWAYS_TRUE -> BooleanLiteral.TRUE;
73 case ALWAYS_FALSE -> BooleanLiteral.FALSE;
74 default -> this;
75 };
48 } 76 }
49 77
50 @Override 78 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java
index 84b4b771..ca70b0fd 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CallPolarity.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3public enum CallPolarity { 8public enum CallPolarity {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java
index 3e159c43..35dcb3fb 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CanNegate.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3public interface CanNegate<T extends CanNegate<T>> extends Literal { 8public interface CanNegate<T extends CanNegate<T>> extends Literal {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java
index 93fa3df0..73545620 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/ConstantLiteral.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -5,15 +10,26 @@ import tools.refinery.store.query.substitution.Substitution;
5import tools.refinery.store.query.term.NodeVariable; 10import tools.refinery.store.query.term.NodeVariable;
6import tools.refinery.store.query.term.Variable; 11import tools.refinery.store.query.term.Variable;
7 12
13import java.util.Objects;
8import java.util.Set; 14import java.util.Set;
9 15
10public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal { 16public record ConstantLiteral(NodeVariable variable, int nodeId) implements Literal {
11 @Override 17 @Override
12 public Set<Variable> getBoundVariables() { 18 public Set<Variable> getOutputVariables() {
13 return Set.of(variable); 19 return Set.of(variable);
14 } 20 }
15 21
16 @Override 22 @Override
23 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
24 return Set.of();
25 }
26
27 @Override
28 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
29 return Set.of();
30 }
31
32 @Override
17 public ConstantLiteral substitute(Substitution substitution) { 33 public ConstantLiteral substitute(Substitution substitution) {
18 return new ConstantLiteral(substitution.getTypeSafeSubstitute(variable), nodeId); 34 return new ConstantLiteral(substitution.getTypeSafeSubstitute(variable), nodeId);
19 } 35 }
@@ -27,8 +43,23 @@ public record ConstantLiteral(NodeVariable variable, int nodeId) implements Lite
27 return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId; 43 return helper.variableEqual(variable, otherConstantLiteral.variable) && nodeId == otherConstantLiteral.nodeId;
28 } 44 }
29 45
46
30 @Override 47 @Override
31 public String toString() { 48 public String toString() {
32 return "%s === @Constant %d".formatted(variable, nodeId); 49 return "%s === @Constant %d".formatted(variable, nodeId);
33 } 50 }
51
52 @Override
53 public boolean equals(Object obj) {
54 if (obj == this) return true;
55 if (obj == null || obj.getClass() != this.getClass()) return false;
56 var that = (ConstantLiteral) obj;
57 return Objects.equals(this.variable, that.variable) &&
58 this.nodeId == that.nodeId;
59 }
60
61 @Override
62 public int hashCode() {
63 return Objects.hash(getClass(), variable, nodeId);
64 }
34} 65}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java
index 32e7ba3a..4d4749c8 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/CountLiteral.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
@@ -5,6 +10,7 @@ import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 10import tools.refinery.store.query.substitution.Substitution;
6import tools.refinery.store.query.term.DataVariable; 11import tools.refinery.store.query.term.DataVariable;
7import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
13import tools.refinery.store.query.term.int_.IntTerms;
8 14
9import java.util.List; 15import java.util.List;
10import java.util.Objects; 16import java.util.Objects;
@@ -31,11 +37,23 @@ public class CountLiteral extends AbstractCallLiteral {
31 } 37 }
32 38
33 @Override 39 @Override
34 public Set<Variable> getBoundVariables() { 40 public Set<Variable> getOutputVariables() {
35 return Set.of(resultVariable); 41 return Set.of(resultVariable);
36 } 42 }
37 43
38 @Override 44 @Override
45 public Literal reduce() {
46 var reduction = getTarget().getReduction();
47 return switch (reduction) {
48 case ALWAYS_FALSE -> getResultVariable().assign(IntTerms.constant(0));
49 // The only way a constant {@code true} predicate can be called in a negative position is to have all of
50 // its arguments bound as input variables. Thus, there will only be a single match.
51 case ALWAYS_TRUE -> getResultVariable().assign(IntTerms.constant(1));
52 case NOT_REDUCIBLE -> this;
53 };
54 }
55
56 @Override
39 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) { 57 protected Literal doSubstitute(Substitution substitution, List<Variable> substitutedArguments) {
40 return new CountLiteral(substitution.getTypeSafeSubstitute(resultVariable), getTarget(), substitutedArguments); 58 return new CountLiteral(substitution.getTypeSafeSubstitute(resultVariable), getTarget(), substitutedArguments);
41 } 59 }
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
index 4dc86b98..28ba7625 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/EquivalenceLiteral.java
@@ -1,18 +1,32 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.term.NodeVariable;
4import tools.refinery.store.query.term.Variable;
5import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
6import tools.refinery.store.query.substitution.Substitution; 9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.Variable;
7 12
13import java.util.Objects;
8import java.util.Set; 14import java.util.Set;
9 15
10public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right) 16public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariable right)
11 implements CanNegate<EquivalenceLiteral> { 17 implements CanNegate<EquivalenceLiteral> {
12 @Override 18 @Override
13 public Set<Variable> getBoundVariables() { 19 public Set<Variable> getOutputVariables() {
14 // If one side of a {@code positive} equivalence is bound, it may bind its other side, but we under-approximate 20 return Set.of(left);
15 // this behavior by not binding any of the sides by default. 21 }
22
23 @Override
24 public Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause) {
25 return Set.of(right);
26 }
27
28 @Override
29 public Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause) {
16 return Set.of(); 30 return Set.of();
17 } 31 }
18 32
@@ -28,11 +42,11 @@ public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariab
28 } 42 }
29 43
30 @Override 44 @Override
31 public LiteralReduction getReduction() { 45 public Literal reduce() {
32 if (left.equals(right)) { 46 if (left.equals(right)) {
33 return positive ? LiteralReduction.ALWAYS_TRUE : LiteralReduction.ALWAYS_FALSE; 47 return positive ? BooleanLiteral.TRUE : BooleanLiteral.FALSE;
34 } 48 }
35 return LiteralReduction.NOT_REDUCIBLE; 49 return this;
36 } 50 }
37 51
38 @Override 52 @Override
@@ -49,4 +63,19 @@ public record EquivalenceLiteral(boolean positive, NodeVariable left, NodeVariab
49 public String toString() { 63 public String toString() {
50 return "%s %s %s".formatted(left, positive ? "===" : "!==", right); 64 return "%s %s %s".formatted(left, positive ? "===" : "!==", right);
51 } 65 }
66
67 @Override
68 public boolean equals(Object obj) {
69 if (obj == this) return true;
70 if (obj == null || obj.getClass() != this.getClass()) return false;
71 var that = (EquivalenceLiteral) obj;
72 return this.positive == that.positive &&
73 Objects.equals(this.left, that.left) &&
74 Objects.equals(this.right, that.right);
75 }
76
77 @Override
78 public int hashCode() {
79 return Objects.hash(getClass(), positive, left, right);
80 }
52} 81}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java
index 6347410e..ce6c11fe 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literal.java
@@ -1,18 +1,27 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.term.Variable;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.substitution.Substitution; 9import tools.refinery.store.query.substitution.Substitution;
10import tools.refinery.store.query.term.Variable;
6 11
7import java.util.Set; 12import java.util.Set;
8 13
9public interface Literal { 14public interface Literal {
10 Set<Variable> getBoundVariables(); 15 Set<Variable> getOutputVariables();
16
17 Set<Variable> getInputVariables(Set<? extends Variable> positiveVariablesInClause);
18
19 Set<Variable> getPrivateVariables(Set<? extends Variable> positiveVariablesInClause);
11 20
12 Literal substitute(Substitution substitution); 21 Literal substitute(Substitution substitution);
13 22
14 default LiteralReduction getReduction() { 23 default Literal reduce() {
15 return LiteralReduction.NOT_REDUCIBLE; 24 return this;
16 } 25 }
17 26
18 @SuppressWarnings("BooleanMethodIsAlwaysInverted") 27 @SuppressWarnings("BooleanMethodIsAlwaysInverted")
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java
index 89039352..b3a87811 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/literal/Literals.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.literal; 6package tools.refinery.store.query.literal;
2 7
3import tools.refinery.store.query.term.Term; 8import tools.refinery.store.query.term.Term;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java
deleted file mode 100644
index f8064ca2..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/CompositeSubstitution.java
+++ /dev/null
@@ -1,10 +0,0 @@
1package tools.refinery.store.query.substitution;
2
3import tools.refinery.store.query.term.Variable;
4
5public record CompositeSubstitution(Substitution first, Substitution second) implements Substitution {
6 @Override
7 public Variable getSubstitute(Variable variable) {
8 return second.getSubstitute(first.getSubstitute(variable));
9 }
10}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java
index c7754619..a8201eef 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/MapBasedSubstitution.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.substitution; 6package tools.refinery.store.query.substitution;
2 7
3import tools.refinery.store.query.term.Variable; 8import tools.refinery.store.query.term.Variable;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java
index 7847e582..9b737ceb 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/RenewingSubstitution.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.substitution; 6package tools.refinery.store.query.substitution;
2 7
3import tools.refinery.store.query.term.Variable; 8import tools.refinery.store.query.term.Variable;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java
index eed414d9..bb3803d3 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/StatelessSubstitution.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.substitution; 6package tools.refinery.store.query.substitution;
2 7
3import tools.refinery.store.query.term.Variable; 8import tools.refinery.store.query.term.Variable;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java
index 99f84b9e..834fce12 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitution.java
@@ -1,6 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.substitution; 6package tools.refinery.store.query.substitution;
2 7
3import tools.refinery.store.query.term.AnyDataVariable;
4import tools.refinery.store.query.term.DataVariable; 8import tools.refinery.store.query.term.DataVariable;
5import tools.refinery.store.query.term.NodeVariable; 9import tools.refinery.store.query.term.NodeVariable;
6import tools.refinery.store.query.term.Variable; 10import tools.refinery.store.query.term.Variable;
@@ -14,16 +18,12 @@ public interface Substitution {
14 return substitute.asNodeVariable(); 18 return substitute.asNodeVariable();
15 } 19 }
16 20
17 default AnyDataVariable getTypeSafeSubstitute(AnyDataVariable variable) {
18 return getTypeSafeSubstitute((DataVariable<?>) variable);
19 }
20
21 default <T> DataVariable<T> getTypeSafeSubstitute(DataVariable<T> variable) { 21 default <T> DataVariable<T> getTypeSafeSubstitute(DataVariable<T> variable) {
22 var substitute = getSubstitute(variable); 22 var substitute = getSubstitute(variable);
23 return substitute.asDataVariable(variable.getType()); 23 return substitute.asDataVariable(variable.getType());
24 } 24 }
25 25
26 default Substitution andThen(Substitution second) { 26 static SubstitutionBuilder builder() {
27 return new CompositeSubstitution(this, second); 27 return new SubstitutionBuilder();
28 } 28 }
29} 29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java
new file mode 100644
index 00000000..37fb6908
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/SubstitutionBuilder.java
@@ -0,0 +1,79 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.substitution;
7
8import tools.refinery.store.query.term.DataVariable;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.Variable;
11
12import java.util.Collections;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16
17@SuppressWarnings("UnusedReturnValue")
18public class SubstitutionBuilder {
19 private final Map<Variable, Variable> map = new HashMap<>();
20 private Substitution fallback;
21
22 SubstitutionBuilder() {
23 total();
24 }
25
26 public SubstitutionBuilder put(NodeVariable original, NodeVariable substitute) {
27 return putChecked(original, substitute);
28 }
29
30 public <T> SubstitutionBuilder put(DataVariable<T> original, DataVariable<T> substitute) {
31 return putChecked(original, substitute);
32 }
33
34 public SubstitutionBuilder putChecked(Variable original, Variable substitute) {
35 if (!original.tryGetType().equals(substitute.tryGetType())) {
36 throw new IllegalArgumentException("Cannot substitute variable %s of sort %s with variable %s of sort %s"
37 .formatted(original, original.tryGetType().map(Class::getName).orElse("node"), substitute,
38 substitute.tryGetType().map(Class::getName).orElse("node")));
39 }
40 if (map.containsKey(original)) {
41 throw new IllegalArgumentException("Already has substitution for variable %s".formatted(original));
42 }
43 map.put(original, substitute);
44 return this;
45 }
46
47 public SubstitutionBuilder putManyChecked(List<Variable> originals, List<Variable> substitutes) {
48 int size = originals.size();
49 if (size != substitutes.size()) {
50 throw new IllegalArgumentException("Cannot substitute %d variables %s with %d variables %s"
51 .formatted(size, originals, substitutes.size(), substitutes));
52 }
53 for (int i = 0; i < size; i++) {
54 putChecked(originals.get(i), substitutes.get(i));
55 }
56 return this;
57 }
58
59 public SubstitutionBuilder fallback(Substitution newFallback) {
60 fallback = newFallback;
61 return this;
62 }
63
64 public SubstitutionBuilder total() {
65 return fallback(StatelessSubstitution.FAILING);
66 }
67
68 public SubstitutionBuilder partial() {
69 return fallback(StatelessSubstitution.IDENTITY);
70 }
71
72 public SubstitutionBuilder renewing() {
73 return fallback(new RenewingSubstitution());
74 }
75
76 public Substitution build() {
77 return map.isEmpty() ? fallback : new MapBasedSubstitution(Collections.unmodifiableMap(map), fallback);
78 }
79}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java
deleted file mode 100644
index 5d4654da..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/substitution/Substitutions.java
+++ /dev/null
@@ -1,33 +0,0 @@
1package tools.refinery.store.query.substitution;
2
3import org.jetbrains.annotations.NotNull;
4import org.jetbrains.annotations.Nullable;
5import tools.refinery.store.query.term.Variable;
6
7import java.util.Map;
8
9public final class Substitutions {
10 private Substitutions() {
11 throw new IllegalStateException("This is a static utility class and should not be instantiate directly");
12 }
13
14 public static Substitution total(Map<Variable, Variable> map) {
15 return new MapBasedSubstitution(map, StatelessSubstitution.FAILING);
16 }
17
18 public static Substitution partial(Map<Variable, Variable> map) {
19 return new MapBasedSubstitution(map, StatelessSubstitution.IDENTITY);
20 }
21
22 public static Substitution renewing(Map<Variable, Variable> map) {
23 return new MapBasedSubstitution(map, renewing());
24 }
25
26 public static Substitution renewing() {
27 return new RenewingSubstitution();
28 }
29
30 public static Substitution compose(@Nullable Substitution first, @NotNull Substitution second) {
31 return first == null ? second : first.andThen(second);
32 }
33}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java
new file mode 100644
index 00000000..d0ae3c12
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AbstractTerm.java
@@ -0,0 +1,41 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import tools.refinery.store.query.equality.LiteralEqualityHelper;
9
10import java.util.Objects;
11
12public abstract class AbstractTerm<T> implements Term<T> {
13 private final Class<T> type;
14
15 protected AbstractTerm(Class<T> type) {
16 this.type = type;
17 }
18
19 @Override
20 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
21 return getClass().equals(other.getClass()) && type.equals(other.getType());
22 }
23
24 @Override
25 public Class<T> getType() {
26 return type;
27 }
28
29 @Override
30 public boolean equals(Object o) {
31 if (this == o) return true;
32 if (o == null || getClass() != o.getClass()) return false;
33 AbstractTerm<?> that = (AbstractTerm<?>) o;
34 return type.equals(that.type);
35 }
36
37 @Override
38 public int hashCode() {
39 return Objects.hash(getClass(), type);
40 }
41}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java
index 47421a94..0684a9d9 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Aggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import java.util.stream.Stream; 8import java.util.stream.Stream;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
index ecfefcf9..192c39c5 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyDataVariable.java
@@ -1,8 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
5 10
11import java.util.Optional;
6import java.util.Set; 12import java.util.Set;
7 13
8public abstract sealed class AnyDataVariable extends Variable implements AnyTerm permits DataVariable { 14public abstract sealed class AnyDataVariable extends Variable implements AnyTerm permits DataVariable {
@@ -11,6 +17,11 @@ public abstract sealed class AnyDataVariable extends Variable implements AnyTerm
11 } 17 }
12 18
13 @Override 19 @Override
20 public Optional<Class<?>> tryGetType() {
21 return Optional.of(getType());
22 }
23
24 @Override
14 public NodeVariable asNodeVariable() { 25 public NodeVariable asNodeVariable() {
15 throw new IllegalStateException("%s is a data variable".formatted(this)); 26 throw new IllegalStateException("%s is a data variable".formatted(this));
16 } 27 }
@@ -26,6 +37,11 @@ public abstract sealed class AnyDataVariable extends Variable implements AnyTerm
26 } 37 }
27 38
28 @Override 39 @Override
40 public boolean isUnifiable() {
41 return false;
42 }
43
44 @Override
29 public abstract AnyDataVariable renew(@Nullable String name); 45 public abstract AnyDataVariable renew(@Nullable String name);
30 46
31 @Override 47 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java
index 8f998d45..c12c0166 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AnyTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java
deleted file mode 100644
index 8706a046..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryOperator.java
+++ /dev/null
@@ -1,26 +0,0 @@
1package tools.refinery.store.query.term;
2
3public enum ArithmeticBinaryOperator {
4 ADD("+", true),
5 SUB("-", true),
6 MUL("*", true),
7 DIV("/", true),
8 POW("**", true),
9 MIN("min", false),
10 MAX("max", false);
11
12 private final String text;
13 private final boolean infix;
14
15 ArithmeticBinaryOperator(String text, boolean infix) {
16 this.text = text;
17 this.infix = infix;
18 }
19
20 public String formatString(String left, String right) {
21 if (infix) {
22 return "(%s) %s (%s)".formatted(left, text, right);
23 }
24 return "%s(%s, %s)".formatted(text, left, right);
25 }
26}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java
deleted file mode 100644
index 887a1e6e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticBinaryTerm.java
+++ /dev/null
@@ -1,56 +0,0 @@
1package tools.refinery.store.query.term;
2
3import tools.refinery.store.query.equality.LiteralEqualityHelper;
4
5import java.util.Objects;
6
7public abstract class ArithmeticBinaryTerm<T> extends BinaryTerm<T, T, T> {
8 private final ArithmeticBinaryOperator operator;
9
10 protected ArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<T> left, Term<T> right) {
11 super(left, right);
12 this.operator = operator;
13 }
14
15 @Override
16 public Class<T> getLeftType() {
17 return getType();
18 }
19
20 @Override
21 public Class<T> getRightType() {
22 return getType();
23 }
24
25 public ArithmeticBinaryOperator getOperator() {
26 return operator;
27 }
28
29 @Override
30 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
31 if (!super.equalsWithSubstitution(helper, other)) {
32 return false;
33 }
34 var otherArithmeticBinaryTerm = (ArithmeticBinaryTerm<?>) other;
35 return operator == otherArithmeticBinaryTerm.operator;
36 }
37
38 @Override
39 public String toString() {
40 return operator.formatString(getLeft().toString(), getRight().toString());
41 }
42
43 @Override
44 public boolean equals(Object o) {
45 if (this == o) return true;
46 if (o == null || getClass() != o.getClass()) return false;
47 if (!super.equals(o)) return false;
48 ArithmeticBinaryTerm<?> that = (ArithmeticBinaryTerm<?>) o;
49 return operator == that.operator;
50 }
51
52 @Override
53 public int hashCode() {
54 return Objects.hash(super.hashCode(), operator);
55 }
56}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java
deleted file mode 100644
index 6a7c25db..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryOperator.java
+++ /dev/null
@@ -1,16 +0,0 @@
1package tools.refinery.store.query.term;
2
3public enum ArithmeticUnaryOperator {
4 PLUS("+"),
5 MINUS("-");
6
7 private final String prefix;
8
9 ArithmeticUnaryOperator(String prefix) {
10 this.prefix = prefix;
11 }
12
13 public String formatString(String body) {
14 return "%s(%s)".formatted(prefix, body);
15 }
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java
deleted file mode 100644
index b78239c7..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ArithmeticUnaryTerm.java
+++ /dev/null
@@ -1,51 +0,0 @@
1package tools.refinery.store.query.term;
2
3import tools.refinery.store.query.equality.LiteralEqualityHelper;
4
5import java.util.Objects;
6
7public abstract class ArithmeticUnaryTerm<T> extends UnaryTerm<T, T> {
8 private final ArithmeticUnaryOperator operator;
9
10 protected ArithmeticUnaryTerm(ArithmeticUnaryOperator operator, Term<T> body) {
11 super(body);
12 this.operator = operator;
13 }
14
15 @Override
16 public Class<T> getBodyType() {
17 return getType();
18 }
19
20 public ArithmeticUnaryOperator getOperator() {
21 return operator;
22 }
23
24 @Override
25 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
26 if (!super.equalsWithSubstitution(helper, other)) {
27 return false;
28 }
29 var otherArithmeticUnaryTerm = (ArithmeticUnaryTerm<?>) other;
30 return operator == otherArithmeticUnaryTerm.operator;
31 }
32
33 @Override
34 public String toString() {
35 return operator.formatString(getBody().toString());
36 }
37
38 @Override
39 public boolean equals(Object o) {
40 if (this == o) return true;
41 if (o == null || getClass() != o.getClass()) return false;
42 if (!super.equals(o)) return false;
43 ArithmeticUnaryTerm<?> that = (ArithmeticUnaryTerm<?>) o;
44 return operator == that.operator;
45 }
46
47 @Override
48 public int hashCode() {
49 return Objects.hash(super.hashCode(), operator);
50 }
51}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java
index 465e690f..0cf30aa6 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/AssignedValue.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.literal.Literal; 8import tools.refinery.store.query.literal.Literal;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java
index 34f48ccc..8ad17839 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/BinaryTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -9,26 +14,35 @@ import java.util.HashSet;
9import java.util.Objects; 14import java.util.Objects;
10import java.util.Set; 15import java.util.Set;
11 16
12public abstract class BinaryTerm<R, T1, T2> implements Term<R> { 17public abstract class BinaryTerm<R, T1, T2> extends AbstractTerm<R> {
18 private final Class<T1> leftType;
19 private final Class<T2> rightType;
13 private final Term<T1> left; 20 private final Term<T1> left;
14 private final Term<T2> right; 21 private final Term<T2> right;
15 22
16 protected BinaryTerm(Term<T1> left, Term<T2> right) { 23 protected BinaryTerm(Class<R> type, Class<T1> leftType, Class<T2> rightType, Term<T1> left, Term<T2> right) {
17 if (!left.getType().equals(getLeftType())) { 24 super(type);
18 throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted(left, 25 if (!left.getType().equals(leftType)) {
19 getLeftType().getName(), left.getType().getName())); 26 throw new IllegalArgumentException("Expected left %s to be of type %s, got %s instead".formatted(
27 left, leftType.getName(), left.getType().getName()));
20 } 28 }
21 if (!right.getType().equals(getRightType())) { 29 if (!right.getType().equals(rightType)) {
22 throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted(right, 30 throw new IllegalArgumentException("Expected right %s to be of type %s, got %s instead".formatted(
23 getRightType().getName(), right.getType().getName())); 31 right, rightType.getName(), right.getType().getName()));
24 } 32 }
33 this.leftType = leftType;
34 this.rightType = rightType;
25 this.left = left; 35 this.left = left;
26 this.right = right; 36 this.right = right;
27 } 37 }
28 38
29 public abstract Class<T1> getLeftType(); 39 public Class<T1> getLeftType() {
40 return leftType;
41 }
30 42
31 public abstract Class<T2> getRightType(); 43 public Class<T2> getRightType() {
44 return rightType;
45 }
32 46
33 public Term<T1> getLeft() { 47 public Term<T1> getLeft() {
34 return left; 48 return left;
@@ -55,12 +69,14 @@ public abstract class BinaryTerm<R, T1, T2> implements Term<R> {
55 69
56 @Override 70 @Override
57 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { 71 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
58 if (getClass() != other.getClass()) { 72 if (!super.equalsWithSubstitution(helper, other)) {
59 return false; 73 return false;
60 } 74 }
61 var otherBinaryTerm = (BinaryTerm<?, ?, ?>) other; 75 var otherBinaryTerm = (BinaryTerm<?, ?, ?>) other;
62 return left.equalsWithSubstitution(helper, otherBinaryTerm.left) && right.equalsWithSubstitution(helper, 76 return leftType.equals(otherBinaryTerm.leftType) &&
63 otherBinaryTerm.right); 77 rightType.equals(otherBinaryTerm.rightType) &&
78 left.equalsWithSubstitution(helper, otherBinaryTerm.left) &&
79 right.equalsWithSubstitution(helper, otherBinaryTerm.right);
64 } 80 }
65 81
66 @Override 82 @Override
@@ -82,12 +98,16 @@ public abstract class BinaryTerm<R, T1, T2> implements Term<R> {
82 public boolean equals(Object o) { 98 public boolean equals(Object o) {
83 if (this == o) return true; 99 if (this == o) return true;
84 if (o == null || getClass() != o.getClass()) return false; 100 if (o == null || getClass() != o.getClass()) return false;
101 if (!super.equals(o)) return false;
85 BinaryTerm<?, ?, ?> that = (BinaryTerm<?, ?, ?>) o; 102 BinaryTerm<?, ?, ?> that = (BinaryTerm<?, ?, ?>) o;
86 return left.equals(that.left) && right.equals(that.right); 103 return Objects.equals(leftType, that.leftType) &&
104 Objects.equals(rightType, that.rightType) &&
105 Objects.equals(left, that.left) &&
106 Objects.equals(right, that.right);
87 } 107 }
88 108
89 @Override 109 @Override
90 public int hashCode() { 110 public int hashCode() {
91 return Objects.hash(getClass(), left, right); 111 return Objects.hash(super.hashCode(), leftType, rightType, left, right);
92 } 112 }
93} 113}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java
deleted file mode 100644
index 44dcce10..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonOperator.java
+++ /dev/null
@@ -1,20 +0,0 @@
1package tools.refinery.store.query.term;
2
3public enum ComparisonOperator {
4 EQ("=="),
5 NOT_EQ("!="),
6 LESS("<"),
7 LESS_EQ("<="),
8 GREATER(">"),
9 GREATER_EQ(">=");
10
11 private final String text;
12
13 ComparisonOperator(String text) {
14 this.text = text;
15 }
16
17 public String formatString(String left, String right) {
18 return "(%s) %s (%s)".formatted(left, text, right);
19 }
20}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java
deleted file mode 100644
index 320d42df..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ComparisonTerm.java
+++ /dev/null
@@ -1,63 +0,0 @@
1package tools.refinery.store.query.term;
2
3import tools.refinery.store.query.equality.LiteralEqualityHelper;
4
5import java.util.Objects;
6
7public abstract class ComparisonTerm<T> extends BinaryTerm<Boolean, T, T> {
8 private final ComparisonOperator operator;
9
10 protected ComparisonTerm(ComparisonOperator operator, Term<T> left, Term<T> right) {
11 super(left, right);
12 this.operator = operator;
13 }
14
15 @Override
16 public Class<Boolean> getType() {
17 return Boolean.class;
18 }
19
20 public abstract Class<T> getOperandType();
21
22 @Override
23 public Class<T> getLeftType() {
24 return getOperandType();
25 }
26
27 @Override
28 public Class<T> getRightType() {
29 return getOperandType();
30 }
31
32 public ComparisonOperator getOperator() {
33 return operator;
34 }
35
36 @Override
37 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
38 if (!super.equalsWithSubstitution(helper, other)) {
39 return false;
40 }
41 var otherComparisonTerm = (ComparisonTerm<?>) other;
42 return operator == otherComparisonTerm.operator;
43 }
44
45 @Override
46 public String toString() {
47 return operator.formatString(getLeft().toString(), getRight().toString());
48 }
49
50 @Override
51 public boolean equals(Object o) {
52 if (this == o) return true;
53 if (o == null || getClass() != o.getClass()) return false;
54 if (!super.equals(o)) return false;
55 ComparisonTerm<?> that = (ComparisonTerm<?>) o;
56 return operator == that.operator;
57 }
58
59 @Override
60 public int hashCode() {
61 return Objects.hash(super.hashCode(), operator);
62 }
63}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java
index 2185fe37..2f6c56d1 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ConstantTerm.java
@@ -1,24 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
4import tools.refinery.store.query.substitution.Substitution; 9import tools.refinery.store.query.substitution.Substitution;
5import tools.refinery.store.query.valuation.Valuation; 10import tools.refinery.store.query.valuation.Valuation;
6 11
12import java.util.Objects;
7import java.util.Set; 13import java.util.Set;
8 14
9public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> { 15public final class ConstantTerm<T> extends AbstractTerm<T> {
10 public ConstantTerm { 16 private final T value;
11 if (value == null) {
12 throw new IllegalArgumentException("value should not be null");
13 }
14 if (!type.isInstance(value)) {
15 throw new IllegalArgumentException("value %s is not an instance of %s".formatted(value, type.getName()));
16 }
17 }
18 17
19 @Override 18 public ConstantTerm(Class<T> type, T value) {
20 public Class<T> getType() { 19 super(type);
21 return type; 20 if (value != null && !type.isInstance(value)) {
21 throw new IllegalArgumentException("Value %s is not an instance of %s".formatted(value, type.getName()));
22 }
23 this.value = value;
22 } 24 }
23 25
24 public T getValue() { 26 public T getValue() {
@@ -37,7 +39,11 @@ public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> {
37 39
38 @Override 40 @Override
39 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { 41 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
40 return equals(other); 42 if (!super.equalsWithSubstitution(helper, other)) {
43 return false;
44 }
45 var otherConstantTerm = (ConstantTerm<?>) other;
46 return Objects.equals(value, otherConstantTerm.value);
41 } 47 }
42 48
43 @Override 49 @Override
@@ -47,6 +53,19 @@ public record ConstantTerm<T>(Class<T> type, T value) implements Term<T> {
47 53
48 @Override 54 @Override
49 public String toString() { 55 public String toString() {
50 return getValue().toString(); 56 return value.toString();
57 }
58
59 @Override
60 public boolean equals(Object o) {
61 if (this == o) return true;
62 if (o == null || getClass() != o.getClass()) return false;
63 ConstantTerm<?> that = (ConstantTerm<?>) o;
64 return Objects.equals(value, that.value);
65 }
66
67 @Override
68 public int hashCode() {
69 return Objects.hash(value);
51 } 70 }
52} 71}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java
deleted file mode 100644
index 4fb44492..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataSort.java
+++ /dev/null
@@ -1,29 +0,0 @@
1package tools.refinery.store.query.term;
2
3import org.jetbrains.annotations.Nullable;
4
5public record DataSort<T>(Class<T> type) implements Sort {
6 public static final DataSort<Integer> INT = new DataSort<>(Integer.class);
7
8 public static final DataSort<Boolean> BOOL = new DataSort<>(Boolean.class);
9
10 @Override
11 public boolean isInstance(Variable variable) {
12 return variable instanceof DataVariable<?> dataVariable && type.equals(dataVariable.getType());
13 }
14
15 @Override
16 public DataVariable<T> newInstance(@Nullable String name) {
17 return Variable.of(name, type);
18 }
19
20 @Override
21 public DataVariable<T> newInstance() {
22 return newInstance(null);
23 }
24
25 @Override
26 public String toString() {
27 return type.getName();
28 }
29}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
index af070ca7..00950360 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/DataVariable.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
@@ -17,11 +22,6 @@ public final class DataVariable<T> extends AnyDataVariable implements Term<T> {
17 } 22 }
18 23
19 @Override 24 @Override
20 public DataSort<T> getSort() {
21 return new DataSort<>(getType());
22 }
23
24 @Override
25 public Class<T> getType() { 25 public Class<T> getType() {
26 return type; 26 return type;
27 } 27 }
@@ -37,11 +37,6 @@ public final class DataVariable<T> extends AnyDataVariable implements Term<T> {
37 } 37 }
38 38
39 @Override 39 @Override
40 public NodeVariable asNodeVariable() {
41 throw new IllegalStateException("%s is a data variable".formatted(this));
42 }
43
44 @Override
45 public <U> DataVariable<U> asDataVariable(Class<U> newType) { 40 public <U> DataVariable<U> asDataVariable(Class<U> newType) {
46 if (!getType().equals(newType)) { 41 if (!getType().equals(newType)) {
47 throw new IllegalStateException("%s is not of type %s but of type %s".formatted(this, newType.getName(), 42 throw new IllegalStateException("%s is not of type %s but of type %s".formatted(this, newType.getName(),
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java
index 57ff597c..657cb631 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ExtremeValueAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import java.util.Comparator; 8import java.util.Comparator;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java
deleted file mode 100644
index 1a4b2d4b..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeSort.java
+++ /dev/null
@@ -1,30 +0,0 @@
1package tools.refinery.store.query.term;
2
3import org.jetbrains.annotations.Nullable;
4
5public final class NodeSort implements Sort {
6 public static final NodeSort INSTANCE = new NodeSort();
7
8 private NodeSort() {
9 }
10
11 @Override
12 public boolean isInstance(Variable variable) {
13 return variable instanceof NodeVariable;
14 }
15
16 @Override
17 public NodeVariable newInstance(@Nullable String name) {
18 return new NodeVariable(name);
19 }
20
21 @Override
22 public NodeVariable newInstance() {
23 return newInstance(null);
24 }
25
26 @Override
27 public String toString() {
28 return "<node>";
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
index 7419aaad..a2f3261f 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/NodeVariable.java
@@ -1,17 +1,29 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
4import tools.refinery.store.query.literal.ConstantLiteral; 9import tools.refinery.store.query.literal.ConstantLiteral;
5import tools.refinery.store.query.literal.EquivalenceLiteral; 10import tools.refinery.store.query.literal.EquivalenceLiteral;
6 11
12import java.util.Optional;
13
7public final class NodeVariable extends Variable { 14public final class NodeVariable extends Variable {
8 NodeVariable(@Nullable String name) { 15 NodeVariable(@Nullable String name) {
9 super(name); 16 super(name);
10 } 17 }
11 18
12 @Override 19 @Override
13 public NodeSort getSort() { 20 public Optional<Class<?>> tryGetType() {
14 return NodeSort.INSTANCE; 21 return Optional.empty();
22 }
23
24 @Override
25 public boolean isUnifiable() {
26 return true;
15 } 27 }
16 28
17 @Override 29 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java
deleted file mode 100644
index 8faa9c75..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/OpaqueTerm.java
+++ /dev/null
@@ -1,80 +0,0 @@
1package tools.refinery.store.query.term;
2
3import tools.refinery.store.query.equality.LiteralEqualityHelper;
4import tools.refinery.store.query.substitution.Substitution;
5import tools.refinery.store.query.substitution.Substitutions;
6import tools.refinery.store.query.valuation.Valuation;
7
8import java.util.Objects;
9import java.util.Set;
10import java.util.function.Function;
11import java.util.stream.Collectors;
12
13public final class OpaqueTerm<T> implements Term<T> {
14 private final Class<T> type;
15 private final Function<? super Valuation, ? extends T> evaluator;
16 private final Set<AnyDataVariable> variables;
17 private final Substitution substitution;
18
19 public OpaqueTerm(Class<T> type, Function<? super Valuation, ? extends T> evaluator,
20 Set<? extends AnyDataVariable> variables) {
21 this(type, evaluator, variables, null);
22 }
23
24 private OpaqueTerm(Class<T> type, Function<? super Valuation, ? extends T> evaluator,
25 Set<? extends AnyDataVariable> variables, Substitution substitution) {
26 this.type = type;
27 this.evaluator = evaluator;
28 this.variables = Set.copyOf(variables);
29 this.substitution = substitution;
30 }
31
32 @Override
33 public Class<T> getType() {
34 return type;
35 }
36
37 @Override
38 public Set<AnyDataVariable> getInputVariables() {
39 return variables;
40 }
41
42 @Override
43 public T evaluate(Valuation valuation) {
44 return evaluator.apply(valuation.substitute(substitution));
45 }
46
47 @Override
48 public Term<T> substitute(Substitution newSubstitution) {
49 var substitutedVariables = variables.stream()
50 .map(newSubstitution::getTypeSafeSubstitute)
51 .collect(Collectors.toUnmodifiableSet());
52 return new OpaqueTerm<>(type, evaluator, substitutedVariables,
53 Substitutions.compose(substitution, newSubstitution));
54 }
55
56 @Override
57 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
58 // Cannot inspect the opaque evaluator for deep equality.
59 return equals(other);
60 }
61
62 @Override
63 public String toString() {
64 return "<opaque>";
65 }
66
67 @Override
68 public boolean equals(Object o) {
69 if (this == o) return true;
70 if (o == null || getClass() != o.getClass()) return false;
71 OpaqueTerm<?> that = (OpaqueTerm<?>) o;
72 return type.equals(that.type) && evaluator.equals(that.evaluator) && Objects.equals(substitution,
73 that.substitution);
74 }
75
76 @Override
77 public int hashCode() {
78 return Objects.hash(type, evaluator, substitution);
79 }
80}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java
new file mode 100644
index 00000000..e5a0cdf1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Parameter.java
@@ -0,0 +1,60 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import java.util.Objects;
9import java.util.Optional;
10
11public class Parameter {
12 public static final Parameter NODE_OUT = new Parameter(null, ParameterDirection.OUT);
13
14 private final Class<?> dataType;
15 private final ParameterDirection direction;
16
17 public Parameter(Class<?> dataType, ParameterDirection direction) {
18 this.dataType = dataType;
19 this.direction = direction;
20 }
21
22 public boolean isNodeVariable() {
23 return dataType == null;
24 }
25
26 public boolean isDataVariable() {
27 return !isNodeVariable();
28 }
29
30 public Optional<Class<?>> tryGetType() {
31 return Optional.ofNullable(dataType);
32 }
33
34 public ParameterDirection getDirection() {
35 return direction;
36 }
37
38 public boolean isAssignable(Variable variable) {
39 if (variable instanceof AnyDataVariable dataVariable) {
40 return dataVariable.getType().equals(dataType);
41 } else if (variable instanceof NodeVariable) {
42 return !isDataVariable();
43 } else {
44 throw new IllegalArgumentException("Unknown variable " + variable);
45 }
46 }
47
48 @Override
49 public boolean equals(Object o) {
50 if (this == o) return true;
51 if (o == null || getClass() != o.getClass()) return false;
52 Parameter parameter = (Parameter) o;
53 return Objects.equals(dataType, parameter.dataType) && direction == parameter.direction;
54 }
55
56 @Override
57 public int hashCode() {
58 return Objects.hash(dataType, direction);
59 }
60}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java
new file mode 100644
index 00000000..cd0739be
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/ParameterDirection.java
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8public enum ParameterDirection {
9 OUT("@Out"),
10 IN("@In");
11
12 private final String name;
13
14 ParameterDirection(String name) {
15 this.name = name;
16 }
17
18 @Override
19 public String toString() {
20 return name;
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java
deleted file mode 100644
index 622bcfce..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Sort.java
+++ /dev/null
@@ -1,11 +0,0 @@
1package tools.refinery.store.query.term;
2
3import org.jetbrains.annotations.Nullable;
4
5public sealed interface Sort permits DataSort, NodeSort {
6 boolean isInstance(Variable variable);
7
8 Variable newInstance(@Nullable String name);
9
10 Variable newInstance();
11}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java
index 7ce91305..ab310556 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregate.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3public interface StatefulAggregate<R, T> { 8public interface StatefulAggregate<R, T> {
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java
index c215a511..df746a90 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatefulAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import java.util.stream.Stream; 8import java.util.stream.Stream;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java
index 74dbd335..a094919e 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/StatelessAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import java.util.stream.Stream; 8import java.util.stream.Stream;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java
index 95434db2..e6818b88 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Term.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.literal.AssignLiteral; 8import tools.refinery.store.query.literal.AssignLiteral;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java
index 4083111a..a46ebe31 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/UnaryTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import tools.refinery.store.query.equality.LiteralEqualityHelper; 8import tools.refinery.store.query.equality.LiteralEqualityHelper;
@@ -7,18 +12,23 @@ import tools.refinery.store.query.valuation.Valuation;
7import java.util.Objects; 12import java.util.Objects;
8import java.util.Set; 13import java.util.Set;
9 14
10public abstract class UnaryTerm<R, T> implements Term<R> { 15public abstract class UnaryTerm<R, T> extends AbstractTerm<R> {
16 private final Class<T> bodyType;
11 private final Term<T> body; 17 private final Term<T> body;
12 18
13 protected UnaryTerm(Term<T> body) { 19 protected UnaryTerm(Class<R> type, Class<T> bodyType, Term<T> body) {
14 if (!body.getType().equals(getBodyType())) { 20 super(type);
21 if (!body.getType().equals(bodyType)) {
15 throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body, 22 throw new IllegalArgumentException("Expected body %s to be of type %s, got %s instead".formatted(body,
16 getBodyType().getName(), body.getType().getName())); 23 bodyType.getName(), body.getType().getName()));
17 } 24 }
25 this.bodyType = bodyType;
18 this.body = body; 26 this.body = body;
19 } 27 }
20 28
21 public abstract Class<T> getBodyType(); 29 public Class<T> getBodyType() {
30 return bodyType;
31 }
22 32
23 public Term<T> getBody() { 33 public Term<T> getBody() {
24 return body; 34 return body;
@@ -34,11 +44,11 @@ public abstract class UnaryTerm<R, T> implements Term<R> {
34 44
35 @Override 45 @Override
36 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) { 46 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
37 if (getClass() != other.getClass()) { 47 if (!super.equalsWithSubstitution(helper, other)) {
38 return false; 48 return false;
39 } 49 }
40 var otherUnaryTerm = (UnaryTerm<?, ?>) other; 50 var otherUnaryTerm = (UnaryTerm<?, ?>) other;
41 return body.equalsWithSubstitution(helper, otherUnaryTerm.body); 51 return bodyType.equals(otherUnaryTerm.bodyType) && body.equalsWithSubstitution(helper, otherUnaryTerm.body);
42 } 52 }
43 53
44 @Override 54 @Override
@@ -57,12 +67,13 @@ public abstract class UnaryTerm<R, T> implements Term<R> {
57 public boolean equals(Object o) { 67 public boolean equals(Object o) {
58 if (this == o) return true; 68 if (this == o) return true;
59 if (o == null || getClass() != o.getClass()) return false; 69 if (o == null || getClass() != o.getClass()) return false;
70 if (!super.equals(o)) return false;
60 UnaryTerm<?, ?> unaryTerm = (UnaryTerm<?, ?>) o; 71 UnaryTerm<?, ?> unaryTerm = (UnaryTerm<?, ?>) o;
61 return body.equals(unaryTerm.body); 72 return Objects.equals(bodyType, unaryTerm.bodyType) && Objects.equals(body, unaryTerm.body);
62 } 73 }
63 74
64 @Override 75 @Override
65 public int hashCode() { 76 public int hashCode() {
66 return Objects.hash(getClass(), body); 77 return Objects.hash(super.hashCode(), bodyType, body);
67 } 78 }
68} 79}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
index 957e10f8..a0268c8e 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/Variable.java
@@ -1,9 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term; 6package tools.refinery.store.query.term;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
4import tools.refinery.store.query.dnf.DnfUtils; 9import tools.refinery.store.query.dnf.DnfUtils;
5 10
6import java.util.Objects; 11import java.util.Objects;
12import java.util.Optional;
7 13
8public abstract sealed class Variable permits AnyDataVariable, NodeVariable { 14public abstract sealed class Variable permits AnyDataVariable, NodeVariable {
9 private final String explicitName; 15 private final String explicitName;
@@ -14,7 +20,7 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable {
14 uniqueName = DnfUtils.generateUniqueName(name); 20 uniqueName = DnfUtils.generateUniqueName(name);
15 } 21 }
16 22
17 public abstract Sort getSort(); 23 public abstract Optional<Class<?>> tryGetType();
18 24
19 public String getName() { 25 public String getName() {
20 return explicitName == null ? uniqueName : explicitName; 26 return explicitName == null ? uniqueName : explicitName;
@@ -32,6 +38,8 @@ public abstract sealed class Variable permits AnyDataVariable, NodeVariable {
32 return uniqueName; 38 return uniqueName;
33 } 39 }
34 40
41 public abstract boolean isUnifiable();
42
35 public abstract Variable renew(@Nullable String name); 43 public abstract Variable renew(@Nullable String name);
36 44
37 public abstract Variable renew(); 45 public abstract Variable renew();
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java
new file mode 100644
index 00000000..f9e1c06f
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolAndTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolAndTerm extends BoolBinaryTerm {
12 public BoolAndTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolAndTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue && rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s && %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java
new file mode 100644
index 00000000..a85aa63a
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolBinaryTerm.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class BoolBinaryTerm extends BinaryTerm<Boolean, Boolean, Boolean> {
12 protected BoolBinaryTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(Boolean.class, Boolean.class, Boolean.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java
deleted file mode 100644
index 5079f1ce..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolConstantTerm.java
+++ /dev/null
@@ -1,16 +0,0 @@
1package tools.refinery.store.query.term.bool;
2
3import tools.refinery.store.query.term.ConstantTerm;
4
5public final class BoolConstantTerm {
6 public static final ConstantTerm<Boolean> TRUE = new ConstantTerm<>(Boolean.class, true);
7 public static final ConstantTerm<Boolean> FALSE = new ConstantTerm<>(Boolean.class, false);
8
9 private BoolConstantTerm() {
10 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
11 }
12
13 public static ConstantTerm<Boolean> valueOf(boolean boolValue) {
14 return boolValue ? TRUE : FALSE;
15 }
16}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java
deleted file mode 100644
index d85f864d..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolLogicBinaryTerm.java
+++ /dev/null
@@ -1,78 +0,0 @@
1package tools.refinery.store.query.term.bool;
2
3import tools.refinery.store.query.equality.LiteralEqualityHelper;
4import tools.refinery.store.query.substitution.Substitution;
5import tools.refinery.store.query.term.*;
6
7import java.util.Objects;
8
9public class BoolLogicBinaryTerm extends BinaryTerm<Boolean, Boolean, Boolean> {
10 private final LogicBinaryOperator operator;
11
12 protected BoolLogicBinaryTerm(LogicBinaryOperator operator, Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 this.operator = operator;
15 }
16
17 @Override
18 public Class<Boolean> getType() {
19 return Boolean.class;
20 }
21
22 @Override
23 public Class<Boolean> getLeftType() {
24 return getType();
25 }
26
27 @Override
28 public Class<Boolean> getRightType() {
29 return getType();
30 }
31
32 public LogicBinaryOperator getOperator() {
33 return operator;
34 }
35
36 @Override
37 public boolean equalsWithSubstitution(LiteralEqualityHelper helper, AnyTerm other) {
38 if (!super.equalsWithSubstitution(helper, other)) {
39 return false;
40 }
41 var otherBoolLogicBinaryTerm = (BoolLogicBinaryTerm) other;
42 return operator == otherBoolLogicBinaryTerm.operator;
43 }
44
45 @Override
46 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
47 Term<Boolean> substitutedRight) {
48 return new BoolLogicBinaryTerm(getOperator(), substitutedLeft, substitutedRight);
49 }
50
51 @Override
52 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
53 return switch (getOperator()) {
54 case AND -> leftValue && rightValue;
55 case OR -> leftValue || rightValue;
56 case XOR -> leftValue ^ rightValue;
57 };
58 }
59
60 @Override
61 public String toString() {
62 return operator.formatString(getLeft().toString(), getRight().toString());
63 }
64
65 @Override
66 public boolean equals(Object o) {
67 if (this == o) return true;
68 if (o == null || getClass() != o.getClass()) return false;
69 if (!super.equals(o)) return false;
70 BoolLogicBinaryTerm that = (BoolLogicBinaryTerm) o;
71 return operator == that.operator;
72 }
73
74 @Override
75 public int hashCode() {
76 return Objects.hash(super.hashCode(), operator);
77 }
78}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java
index 855139b5..8d3382b3 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolNotTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.bool; 6package tools.refinery.store.query.term.bool;
2 7
3import tools.refinery.store.query.substitution.Substitution; 8import tools.refinery.store.query.substitution.Substitution;
@@ -6,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm;
6 11
7public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> { 12public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> {
8 protected BoolNotTerm(Term<Boolean> body) { 13 protected BoolNotTerm(Term<Boolean> body) {
9 super(body); 14 super(Boolean.class, Boolean.class, body);
10 }
11
12 @Override
13 public Class<Boolean> getType() {
14 return Boolean.class;
15 }
16
17 @Override
18 public Class<Boolean> getBodyType() {
19 return getType();
20 } 15 }
21 16
22 @Override 17 @Override
@@ -31,6 +26,6 @@ public class BoolNotTerm extends UnaryTerm<Boolean, Boolean> {
31 26
32 @Override 27 @Override
33 public String toString() { 28 public String toString() {
34 return "!(%s)".formatted(getBody()); 29 return "(!%s)".formatted(getBody());
35 } 30 }
36} 31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java
new file mode 100644
index 00000000..b5195d52
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolOrTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolOrTerm extends BoolBinaryTerm {
12 public BoolOrTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolOrTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue || rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s || %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java
index 3d6c8d9d..fa54f686 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolTerms.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.bool; 6package tools.refinery.store.query.term.bool;
2 7
3import tools.refinery.store.query.term.ConstantTerm; 8import tools.refinery.store.query.term.ConstantTerm;
@@ -8,23 +13,23 @@ public final class BoolTerms {
8 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); 13 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
9 } 14 }
10 15
11 public static ConstantTerm<Boolean> constant(boolean value) { 16 public static Term<Boolean> constant(Boolean value) {
12 return BoolConstantTerm.valueOf(value); 17 return new ConstantTerm<>(Boolean.class, value);
13 } 18 }
14 19
15 public static BoolNotTerm not(Term<Boolean> body) { 20 public static Term<Boolean> not(Term<Boolean> body) {
16 return new BoolNotTerm(body); 21 return new BoolNotTerm(body);
17 } 22 }
18 23
19 public static BoolLogicBinaryTerm and(Term<Boolean> left, Term<Boolean> right) { 24 public static Term<Boolean> and(Term<Boolean> left, Term<Boolean> right) {
20 return new BoolLogicBinaryTerm(LogicBinaryOperator.AND, left, right); 25 return new BoolAndTerm(left, right);
21 } 26 }
22 27
23 public static BoolLogicBinaryTerm or(Term<Boolean> left, Term<Boolean> right) { 28 public static Term<Boolean> or(Term<Boolean> left, Term<Boolean> right) {
24 return new BoolLogicBinaryTerm(LogicBinaryOperator.OR, left, right); 29 return new BoolOrTerm(left, right);
25 } 30 }
26 31
27 public static BoolLogicBinaryTerm xor(Term<Boolean> left, Term<Boolean> right) { 32 public static Term<Boolean> xor(Term<Boolean> left, Term<Boolean> right) {
28 return new BoolLogicBinaryTerm(LogicBinaryOperator.XOR, left, right); 33 return new BoolXorTerm(left, right);
29 } 34 }
30} 35}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java
new file mode 100644
index 00000000..7478b8a5
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/BoolXorTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class BoolXorTerm extends BoolBinaryTerm {
12 public BoolXorTerm(Term<Boolean> left, Term<Boolean> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Boolean> doSubstitute(Substitution substitution, Term<Boolean> substitutedLeft,
18 Term<Boolean> substitutedRight) {
19 return new BoolXorTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Boolean doEvaluate(Boolean leftValue, Boolean rightValue) {
24 return leftValue ^ rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s ^^ %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java
deleted file mode 100644
index ca9ac66e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/bool/LogicBinaryOperator.java
+++ /dev/null
@@ -1,17 +0,0 @@
1package tools.refinery.store.query.term.bool;
2
3public enum LogicBinaryOperator {
4 AND("&&"),
5 OR("||"),
6 XOR("^^");
7
8 private final String text;
9
10 LogicBinaryOperator(String text) {
11 this.text = text;
12 }
13
14 public String formatString(String left, String right) {
15 return "(%s) %s (%s)".formatted(left, text, right);
16 }
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java
new file mode 100644
index 00000000..5ca5a0a1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/ComparisonTerm.java
@@ -0,0 +1,19 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class ComparisonTerm<T> extends BinaryTerm<Boolean, T, T> {
12 protected ComparisonTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(Boolean.class, argumentType, argumentType, left, right);
14 }
15
16 public Class<T> getArgumentType() {
17 return getLeftType();
18 }
19}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java
new file mode 100644
index 00000000..b8cf36f8
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/EqTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class EqTerm<T> extends ComparisonTerm<T> {
12 public EqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.equals(rightValue);
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new EqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s == %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java
new file mode 100644
index 00000000..b109eb1a
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterEqTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class GreaterEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public GreaterEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) >= 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new GreaterEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s >= %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java
new file mode 100644
index 00000000..1b67f8b5
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/GreaterTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class GreaterTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public GreaterTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) > 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new GreaterTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s > %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java
new file mode 100644
index 00000000..1b34535f
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessEqTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class LessEqTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public LessEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) <= 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new LessEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s <= %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java
new file mode 100644
index 00000000..44e70902
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/LessTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class LessTerm<T extends Comparable<T>> extends ComparisonTerm<T> {
12 public LessTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return leftValue.compareTo(rightValue) < 0;
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new LessTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s < %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java
new file mode 100644
index 00000000..1f9734c4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/comparable/NotEqTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.comparable;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class NotEqTerm<T> extends ComparisonTerm<T> {
12 public NotEqTerm(Class<T> argumentType, Term<T> left, Term<T> right) {
13 super(argumentType, left, right);
14 }
15
16 @Override
17 protected Boolean doEvaluate(T leftValue, T rightValue) {
18 return !leftValue.equals(rightValue);
19 }
20
21 @Override
22 public Term<Boolean> doSubstitute(Substitution substitution, Term<T> substitutedLeft, Term<T> substitutedRight) {
23 return new NotEqTerm<>(getArgumentType(), substitutedLeft, substitutedRight);
24 }
25
26 @Override
27 public String toString() {
28 return "(%s != %s)".formatted(getLeft(), getRight());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java
new file mode 100644
index 00000000..dbea3efc
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntAddTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntAddTerm extends IntBinaryTerm {
12 public IntAddTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntAddTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue + rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java
deleted file mode 100644
index 32e41718..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticBinaryTerm.java
+++ /dev/null
@@ -1,48 +0,0 @@
1package tools.refinery.store.query.term.int_;
2
3import tools.refinery.store.query.substitution.Substitution;
4import tools.refinery.store.query.term.ArithmeticBinaryOperator;
5import tools.refinery.store.query.term.ArithmeticBinaryTerm;
6import tools.refinery.store.query.term.Term;
7
8public class IntArithmeticBinaryTerm extends ArithmeticBinaryTerm<Integer> {
9 public IntArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<Integer> left, Term<Integer> right) {
10 super(operator, left, right);
11 }
12
13 @Override
14 public Class<Integer> getType() {
15 return Integer.class;
16 }
17
18 @Override
19 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
20 Term<Integer> substitutedRight) {
21 return new IntArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight);
22 }
23
24 @Override
25 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
26 return switch (getOperator()) {
27 case ADD -> leftValue + rightValue;
28 case SUB -> leftValue - rightValue;
29 case MUL -> leftValue * rightValue;
30 case DIV -> rightValue == 0 ? null : leftValue / rightValue;
31 case POW -> rightValue < 0 ? null : power(leftValue, rightValue);
32 case MIN -> Math.min(leftValue, rightValue);
33 case MAX -> Math.max(leftValue, rightValue);
34 };
35 }
36
37 private static int power(int base, int exponent) {
38 int accum = 1;
39 while (exponent > 0) {
40 if (exponent % 2 == 1) {
41 accum = accum * base;
42 }
43 base = base * base;
44 exponent = exponent / 2;
45 }
46 return accum;
47 }
48}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java
deleted file mode 100644
index 1e769259..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntArithmeticUnaryTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1package tools.refinery.store.query.term.int_;
2
3import tools.refinery.store.query.substitution.Substitution;
4import tools.refinery.store.query.term.Term;
5import tools.refinery.store.query.term.ArithmeticUnaryOperator;
6import tools.refinery.store.query.term.ArithmeticUnaryTerm;
7
8public class IntArithmeticUnaryTerm extends ArithmeticUnaryTerm<Integer> {
9 public IntArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term<Integer> body) {
10 super(operation, body);
11 }
12
13 @Override
14 public Class<Integer> getType() {
15 return Integer.class;
16 }
17
18 @Override
19 protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
20 return new IntArithmeticUnaryTerm(getOperator(), substitutedBody);
21 }
22
23 @Override
24 protected Integer doEvaluate(Integer bodyValue) {
25 return switch(getOperator()) {
26 case PLUS -> bodyValue;
27 case MINUS -> -bodyValue;
28 };
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java
new file mode 100644
index 00000000..27ced4e4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntBinaryTerm.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class IntBinaryTerm extends BinaryTerm<Integer, Integer, Integer> {
12 protected IntBinaryTerm(Term<Integer> left, Term<Integer> right) {
13 super(Integer.class, Integer.class, Integer.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java
deleted file mode 100644
index 322d2b80..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntComparisonTerm.java
+++ /dev/null
@@ -1,34 +0,0 @@
1package tools.refinery.store.query.term.int_;
2import tools.refinery.store.query.substitution.Substitution;
3import tools.refinery.store.query.term.ComparisonOperator;
4import tools.refinery.store.query.term.ComparisonTerm;
5import tools.refinery.store.query.term.Term;
6
7public class IntComparisonTerm extends ComparisonTerm<Integer> {
8 public IntComparisonTerm(ComparisonOperator operator, Term<Integer> left, Term<Integer> right) {
9 super(operator, left, right);
10 }
11
12 @Override
13 public Class<Integer> getOperandType() {
14 return Integer.class;
15 }
16
17 @Override
18 public Term<Boolean> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
19 Term<Integer> substitutedRight) {
20 return new IntComparisonTerm(getOperator(), substitutedLeft, substitutedRight);
21 }
22
23 @Override
24 protected Boolean doEvaluate(Integer leftValue, Integer rightValue) {
25 return switch (getOperator()) {
26 case EQ -> leftValue.equals(rightValue);
27 case NOT_EQ -> !leftValue.equals(rightValue);
28 case LESS -> leftValue < rightValue;
29 case LESS_EQ -> leftValue <= rightValue;
30 case GREATER -> leftValue > rightValue;
31 case GREATER_EQ -> leftValue >= rightValue;
32 };
33 }
34}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java
new file mode 100644
index 00000000..2a35058c
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntDivTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntDivTerm extends IntBinaryTerm {
12 public IntDivTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntDivTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return rightValue == 0 ? null : leftValue / rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s / %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java
deleted file mode 100644
index d5a6add0..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntExtremeValueAggregator.java
+++ /dev/null
@@ -1,17 +0,0 @@
1package tools.refinery.store.query.term.int_;
2
3import tools.refinery.store.query.term.ExtremeValueAggregator;
4
5import java.util.Comparator;
6
7public final class IntExtremeValueAggregator {
8 public static final ExtremeValueAggregator<Integer> MINIMUM = new ExtremeValueAggregator<>(Integer.class,
9 Integer.MAX_VALUE);
10
11 public static final ExtremeValueAggregator<Integer> MAXIMUM = new ExtremeValueAggregator<>(Integer.class,
12 Integer.MIN_VALUE, Comparator.reverseOrder());
13
14 private IntExtremeValueAggregator() {
15 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
16 }
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java
new file mode 100644
index 00000000..f81fc509
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMaxTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMaxTerm extends IntBinaryTerm {
12 public IntMaxTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMaxTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return Math.max(rightValue, leftValue);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java
new file mode 100644
index 00000000..89182e26
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMinTerm extends IntBinaryTerm {
12 public IntMinTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMinTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return Math.min(rightValue, leftValue);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java
new file mode 100644
index 00000000..709aa5ba
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMinusTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMinusTerm extends IntUnaryTerm {
12 public IntMinusTerm(Term<Integer> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
18 return new IntMinusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Integer doEvaluate(Integer bodyValue) {
23 return -bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(-%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java
new file mode 100644
index 00000000..89d4c5f4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntMulTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntMulTerm extends IntBinaryTerm {
12 public IntMulTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntMulTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue * rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java
new file mode 100644
index 00000000..aef83bb4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPlusTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntPlusTerm extends IntUnaryTerm {
12 public IntPlusTerm(Term<Integer> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedBody) {
18 return new IntPlusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Integer doEvaluate(Integer bodyValue) {
23 return bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(+%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java
new file mode 100644
index 00000000..d5af97a1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntPowTerm.java
@@ -0,0 +1,43 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntPowTerm extends IntBinaryTerm {
12 public IntPowTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntPowTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return rightValue < 0 ? null : power(leftValue, rightValue);
25 }
26
27 private static int power(int base, int exponent) {
28 int accum = 1;
29 while (exponent > 0) {
30 if (exponent % 2 == 1) {
31 accum = accum * base;
32 }
33 base = base * base;
34 exponent = exponent / 2;
35 }
36 return accum;
37 }
38
39 @Override
40 public String toString() {
41 return "(%s ** %s)".formatted(getLeft(), getRight());
42 }
43}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java
new file mode 100644
index 00000000..2c27afb1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSubTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class IntSubTerm extends IntBinaryTerm {
12 public IntSubTerm(Term<Integer> left, Term<Integer> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Integer> doSubstitute(Substitution substitution, Term<Integer> substitutedLeft,
18 Term<Integer> substitutedRight) {
19 return new IntSubTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Integer doEvaluate(Integer leftValue, Integer rightValue) {
24 return leftValue - rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s - %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java
index 65024f52..cd718c53 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntSumAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.int_; 6package tools.refinery.store.query.term.int_;
2 7
3import tools.refinery.store.query.term.StatelessAggregator; 8import tools.refinery.store.query.term.StatelessAggregator;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java
index 86594deb..acb98b94 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntTerms.java
@@ -1,81 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.int_; 6package tools.refinery.store.query.term.int_;
2 7
3import tools.refinery.store.query.term.*; 8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13
14import java.util.Comparator;
4 15
5public final class IntTerms { 16public final class IntTerms {
6 public static final Aggregator<Integer, Integer> INT_SUM = IntSumAggregator.INSTANCE; 17 public static final Aggregator<Integer, Integer> INT_SUM = IntSumAggregator.INSTANCE;
7 public static final Aggregator<Integer, Integer> INT_MIN = IntExtremeValueAggregator.MINIMUM; 18 public static final Aggregator<Integer, Integer> INT_MIN = new ExtremeValueAggregator<>(Integer.class,
8 public static final Aggregator<Integer, Integer> INT_MAX = IntExtremeValueAggregator.MAXIMUM; 19 Integer.MAX_VALUE);
20 public static final Aggregator<Integer, Integer> INT_MAX = new ExtremeValueAggregator<>(Integer.class,
21 Integer.MIN_VALUE, Comparator.reverseOrder());
9 22
10 private IntTerms() { 23 private IntTerms() {
11 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); 24 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
12 } 25 }
13 26
14 public static ConstantTerm<Integer> constant(int value) { 27 public static Term<Integer> constant(Integer value) {
15 return new ConstantTerm<>(Integer.class, value); 28 return new ConstantTerm<>(Integer.class, value);
16 } 29 }
17 30
18 public static IntArithmeticUnaryTerm plus(Term<Integer> body) { 31 public static Term<Integer> plus(Term<Integer> body) {
19 return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); 32 return new IntPlusTerm(body);
20 } 33 }
21 34
22 public static IntArithmeticUnaryTerm minus(Term<Integer> body) { 35 public static Term<Integer> minus(Term<Integer> body) {
23 return new IntArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); 36 return new IntMinusTerm(body);
24 } 37 }
25 38
26 public static IntArithmeticBinaryTerm add(Term<Integer> left, Term<Integer> right) { 39 public static Term<Integer> add(Term<Integer> left, Term<Integer> right) {
27 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); 40 return new IntAddTerm(left, right);
28 } 41 }
29 42
30 public static IntArithmeticBinaryTerm sub(Term<Integer> left, Term<Integer> right) { 43 public static Term<Integer> sub(Term<Integer> left, Term<Integer> right) {
31 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); 44 return new IntSubTerm(left, right);
32 } 45 }
33 46
34 public static IntArithmeticBinaryTerm mul(Term<Integer> left, Term<Integer> right) { 47 public static Term<Integer> mul(Term<Integer> left, Term<Integer> right) {
35 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); 48 return new IntMulTerm(left, right);
36 } 49 }
37 50
38 public static IntArithmeticBinaryTerm div(Term<Integer> left, Term<Integer> right) { 51 public static Term<Integer> div(Term<Integer> left, Term<Integer> right) {
39 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); 52 return new IntDivTerm(left, right);
40 } 53 }
41 54
42 public static IntArithmeticBinaryTerm pow(Term<Integer> left, Term<Integer> right) { 55 public static Term<Integer> pow(Term<Integer> left, Term<Integer> right) {
43 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); 56 return new IntPowTerm(left, right);
44 } 57 }
45 58
46 public static IntArithmeticBinaryTerm min(Term<Integer> left, Term<Integer> right) { 59 public static Term<Integer> min(Term<Integer> left, Term<Integer> right) {
47 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); 60 return new IntMinTerm(left, right);
48 } 61 }
49 62
50 public static IntArithmeticBinaryTerm max(Term<Integer> left, Term<Integer> right) { 63 public static Term<Integer> max(Term<Integer> left, Term<Integer> right) {
51 return new IntArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); 64 return new IntMaxTerm(left, right);
52 } 65 }
53 66
54 public static IntComparisonTerm eq(Term<Integer> left, Term<Integer> right) { 67 public static Term<Boolean> eq(Term<Integer> left, Term<Integer> right) {
55 return new IntComparisonTerm(ComparisonOperator.EQ, left, right); 68 return new EqTerm<>(Integer.class, left, right);
56 } 69 }
57 70
58 public static IntComparisonTerm notEq(Term<Integer> left, Term<Integer> right) { 71 public static Term<Boolean> notEq(Term<Integer> left, Term<Integer> right) {
59 return new IntComparisonTerm(ComparisonOperator.NOT_EQ, left, right); 72 return new NotEqTerm<>(Integer.class, left, right);
60 } 73 }
61 74
62 public static IntComparisonTerm less(Term<Integer> left, Term<Integer> right) { 75 public static Term<Boolean> less(Term<Integer> left, Term<Integer> right) {
63 return new IntComparisonTerm(ComparisonOperator.LESS, left, right); 76 return new LessTerm<>(Integer.class, left, right);
64 } 77 }
65 78
66 public static IntComparisonTerm lessEq(Term<Integer> left, Term<Integer> right) { 79 public static Term<Boolean> lessEq(Term<Integer> left, Term<Integer> right) {
67 return new IntComparisonTerm(ComparisonOperator.LESS_EQ, left, right); 80 return new LessEqTerm<>(Integer.class, left, right);
68 } 81 }
69 82
70 public static IntComparisonTerm greater(Term<Integer> left, Term<Integer> right) { 83 public static Term<Boolean> greater(Term<Integer> left, Term<Integer> right) {
71 return new IntComparisonTerm(ComparisonOperator.GREATER, left, right); 84 return new GreaterTerm<>(Integer.class, left, right);
72 } 85 }
73 86
74 public static IntComparisonTerm greaterEq(Term<Integer> left, Term<Integer> right) { 87 public static Term<Boolean> greaterEq(Term<Integer> left, Term<Integer> right) {
75 return new IntComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); 88 return new GreaterEqTerm<>(Integer.class, left, right);
76 } 89 }
77 90
78 public static RealToIntTerm asInt(Term<Double> body) { 91 public static Term<Integer> asInt(Term<Double> body) {
79 return new RealToIntTerm(body); 92 return new RealToIntTerm(body);
80 } 93 }
81} 94}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java
new file mode 100644
index 00000000..49b4c647
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/IntUnaryTerm.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import tools.refinery.store.query.term.Term;
9import tools.refinery.store.query.term.UnaryTerm;
10
11public abstract class IntUnaryTerm extends UnaryTerm<Integer, Integer> {
12 protected IntUnaryTerm(Term<Integer> body) {
13 super(Integer.class, Integer.class, body);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java
index 53875ddc..7d383562 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/int_/RealToIntTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.int_; 6package tools.refinery.store.query.term.int_;
2 7
3import tools.refinery.store.query.substitution.Substitution; 8import tools.refinery.store.query.substitution.Substitution;
@@ -6,22 +11,12 @@ import tools.refinery.store.query.term.UnaryTerm;
6 11
7public class RealToIntTerm extends UnaryTerm<Integer, Double> { 12public class RealToIntTerm extends UnaryTerm<Integer, Double> {
8 protected RealToIntTerm(Term<Double> body) { 13 protected RealToIntTerm(Term<Double> body) {
9 super(body); 14 super(Integer.class, Double.class, body);
10 }
11
12 @Override
13 public Class<Integer> getType() {
14 return Integer.class;
15 }
16
17 @Override
18 public Class<Double> getBodyType() {
19 return Double.class;
20 } 15 }
21 16
22 @Override 17 @Override
23 protected Integer doEvaluate(Double bodyValue) { 18 protected Integer doEvaluate(Double bodyValue) {
24 return bodyValue.intValue(); 19 return bodyValue.isNaN() ? null : bodyValue.intValue();
25 } 20 }
26 21
27 @Override 22 @Override
@@ -31,6 +26,6 @@ public class RealToIntTerm extends UnaryTerm<Integer, Double> {
31 26
32 @Override 27 @Override
33 public String toString() { 28 public String toString() {
34 return "(%s) as int".formatted(getBody()); 29 return "(%s as int)".formatted(getBody());
35 } 30 }
36} 31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java
index 55590824..2f53117a 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/IntToRealTerm.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.real; 6package tools.refinery.store.query.term.real;
2 7
3import tools.refinery.store.query.substitution.Substitution; 8import tools.refinery.store.query.substitution.Substitution;
@@ -6,17 +11,7 @@ import tools.refinery.store.query.term.UnaryTerm;
6 11
7public class IntToRealTerm extends UnaryTerm<Double, Integer> { 12public class IntToRealTerm extends UnaryTerm<Double, Integer> {
8 protected IntToRealTerm(Term<Integer> body) { 13 protected IntToRealTerm(Term<Integer> body) {
9 super(body); 14 super(Double.class, Integer.class, body);
10 }
11
12 @Override
13 public Class<Double> getType() {
14 return Double.class;
15 }
16
17 @Override
18 public Class<Integer> getBodyType() {
19 return Integer.class;
20 } 15 }
21 16
22 @Override 17 @Override
@@ -31,6 +26,6 @@ public class IntToRealTerm extends UnaryTerm<Double, Integer> {
31 26
32 @Override 27 @Override
33 public String toString() { 28 public String toString() {
34 return "(%s) as real".formatted(getBody()); 29 return "(%s as real)".formatted(getBody());
35 } 30 }
36} 31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java
new file mode 100644
index 00000000..33fc9e41
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealAddTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealAddTerm extends RealBinaryTerm {
12 public RealAddTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealAddTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue + rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java
deleted file mode 100644
index 57bcbe5e..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticBinaryTerm.java
+++ /dev/null
@@ -1,36 +0,0 @@
1package tools.refinery.store.query.term.real;
2
3import tools.refinery.store.query.substitution.Substitution;
4import tools.refinery.store.query.term.ArithmeticBinaryOperator;
5import tools.refinery.store.query.term.ArithmeticBinaryTerm;
6import tools.refinery.store.query.term.Term;
7
8public class RealArithmeticBinaryTerm extends ArithmeticBinaryTerm<Double> {
9 public RealArithmeticBinaryTerm(ArithmeticBinaryOperator operator, Term<Double> left, Term<Double> right) {
10 super(operator, left, right);
11 }
12
13 @Override
14 public Class<Double> getType() {
15 return Double.class;
16 }
17
18 @Override
19 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
20 Term<Double> substitutedRight) {
21 return new RealArithmeticBinaryTerm(getOperator(), substitutedLeft, substitutedRight);
22 }
23
24 @Override
25 protected Double doEvaluate(Double leftValue, Double rightValue) {
26 return switch (getOperator()) {
27 case ADD -> leftValue + rightValue;
28 case SUB -> leftValue - rightValue;
29 case MUL -> leftValue * rightValue;
30 case DIV -> leftValue / rightValue;
31 case POW -> Math.pow(leftValue, rightValue);
32 case MIN -> Math.min(leftValue, rightValue);
33 case MAX -> Math.max(leftValue, rightValue);
34 };
35 }
36}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java
deleted file mode 100644
index 632e68bf..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealArithmeticUnaryTerm.java
+++ /dev/null
@@ -1,30 +0,0 @@
1package tools.refinery.store.query.term.real;
2
3import tools.refinery.store.query.substitution.Substitution;
4import tools.refinery.store.query.term.ArithmeticUnaryOperator;
5import tools.refinery.store.query.term.ArithmeticUnaryTerm;
6import tools.refinery.store.query.term.Term;
7
8public class RealArithmeticUnaryTerm extends ArithmeticUnaryTerm<Double> {
9 public RealArithmeticUnaryTerm(ArithmeticUnaryOperator operation, Term<Double> body) {
10 super(operation, body);
11 }
12
13 @Override
14 public Class<Double> getType() {
15 return Double.class;
16 }
17
18 @Override
19 protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
20 return new RealArithmeticUnaryTerm(getOperator(), substitutedBody);
21 }
22
23 @Override
24 protected Double doEvaluate(Double bodyValue) {
25 return switch(getOperator()) {
26 case PLUS -> bodyValue;
27 case MINUS -> -bodyValue;
28 };
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java
new file mode 100644
index 00000000..000f3623
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealBinaryTerm.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10
11public abstract class RealBinaryTerm extends BinaryTerm<Double, Double, Double> {
12 protected RealBinaryTerm(Term<Double> left, Term<Double> right) {
13 super(Double.class, Double.class, Double.class, left, right);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java
deleted file mode 100644
index 75d97adb..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealComparisonTerm.java
+++ /dev/null
@@ -1,35 +0,0 @@
1package tools.refinery.store.query.term.real;
2
3import tools.refinery.store.query.substitution.Substitution;
4import tools.refinery.store.query.term.ComparisonOperator;
5import tools.refinery.store.query.term.ComparisonTerm;
6import tools.refinery.store.query.term.Term;
7
8public class RealComparisonTerm extends ComparisonTerm<Double> {
9 public RealComparisonTerm(ComparisonOperator operator, Term<Double> left, Term<Double> right) {
10 super(operator, left, right);
11 }
12
13 @Override
14 public Class<Double> getOperandType() {
15 return Double.class;
16 }
17
18 @Override
19 public Term<Boolean> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
20 Term<Double> substitutedRight) {
21 return new RealComparisonTerm(getOperator(), substitutedLeft, substitutedRight);
22 }
23
24 @Override
25 protected Boolean doEvaluate(Double leftValue, Double rightValue) {
26 return switch (getOperator()) {
27 case EQ -> leftValue.equals(rightValue);
28 case NOT_EQ -> !leftValue.equals(rightValue);
29 case LESS -> leftValue < rightValue;
30 case LESS_EQ -> leftValue <= rightValue;
31 case GREATER -> leftValue > rightValue;
32 case GREATER_EQ -> leftValue >= rightValue;
33 };
34 }
35}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java
new file mode 100644
index 00000000..1e55bf42
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealDivTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealDivTerm extends RealBinaryTerm {
12 public RealDivTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealDivTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue / rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s / %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java
deleted file mode 100644
index 23384530..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealExtremeValueAggregator.java
+++ /dev/null
@@ -1,17 +0,0 @@
1package tools.refinery.store.query.term.real;
2
3import tools.refinery.store.query.term.ExtremeValueAggregator;
4
5import java.util.Comparator;
6
7public final class RealExtremeValueAggregator {
8 public static final ExtremeValueAggregator<Double> MINIMUM = new ExtremeValueAggregator<>(Double.class,
9 Double.POSITIVE_INFINITY);
10
11 public static final ExtremeValueAggregator<Double> MAXIMUM = new ExtremeValueAggregator<>(Double.class,
12 Double.NEGATIVE_INFINITY, Comparator.reverseOrder());
13
14 private RealExtremeValueAggregator() {
15 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
16 }
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java
new file mode 100644
index 00000000..2a249496
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMaxTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMaxTerm extends RealBinaryTerm {
12 public RealMaxTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMaxTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.max(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java
new file mode 100644
index 00000000..2eb4cc1e
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMinTerm extends RealBinaryTerm {
12 public RealMinTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMinTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.min(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java
new file mode 100644
index 00000000..4afec7a1
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMinusTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMinusTerm extends RealUnaryTerm {
12 public RealMinusTerm(Term<Double> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
18 return new RealMinusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Double doEvaluate(Double bodyValue) {
23 return -bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(-%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java
new file mode 100644
index 00000000..ec95ac6f
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealMulTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealMulTerm extends RealBinaryTerm {
12 public RealMulTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealMulTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue * rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java
new file mode 100644
index 00000000..64dd2e70
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPlusTerm.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealPlusTerm extends RealUnaryTerm {
12 public RealPlusTerm(Term<Double> body) {
13 super(body);
14 }
15
16 @Override
17 protected Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedBody) {
18 return new RealPlusTerm(substitutedBody);
19 }
20
21 @Override
22 protected Double doEvaluate(Double bodyValue) {
23 return bodyValue;
24 }
25
26 @Override
27 public String toString() {
28 return "(+%s)".formatted(getBody());
29 }
30}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java
new file mode 100644
index 00000000..11c952ea
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealPowTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealPowTerm extends RealBinaryTerm {
12 public RealPowTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealPowTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return Math.pow(leftValue, rightValue);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s ** %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java
new file mode 100644
index 00000000..8cc701ed
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSubTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10
11public class RealSubTerm extends RealBinaryTerm {
12 public RealSubTerm(Term<Double> left, Term<Double> right) {
13 super(left, right);
14 }
15
16 @Override
17 public Term<Double> doSubstitute(Substitution substitution, Term<Double> substitutedLeft,
18 Term<Double> substitutedRight) {
19 return new RealSubTerm(substitutedLeft, substitutedRight);
20 }
21
22 @Override
23 protected Double doEvaluate(Double leftValue, Double rightValue) {
24 return leftValue - rightValue;
25 }
26
27 @Override
28 public String toString() {
29 return "(%s - %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java
index d5888664..d21048e9 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealSumAggregator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.real; 6package tools.refinery.store.query.term.real;
2 7
3import tools.refinery.store.query.term.StatefulAggregate; 8import tools.refinery.store.query.term.StatefulAggregate;
@@ -14,12 +19,12 @@ public final class RealSumAggregator implements StatefulAggregator<Double, Doubl
14 19
15 @Override 20 @Override
16 public Class<Double> getResultType() { 21 public Class<Double> getResultType() {
17 return null; 22 return Double.class;
18 } 23 }
19 24
20 @Override 25 @Override
21 public Class<Double> getInputType() { 26 public Class<Double> getInputType() {
22 return null; 27 return Double.class;
23 } 28 }
24 29
25 @Override 30 @Override
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java
index a8117842..79220358 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealTerms.java
@@ -1,81 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.term.real; 6package tools.refinery.store.query.term.real;
2 7
3import tools.refinery.store.query.term.*; 8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13
14import java.util.Comparator;
4 15
5public final class RealTerms { 16public final class RealTerms {
6 public static final Aggregator<Double, Double> REAL_SUM = RealSumAggregator.INSTANCE; 17 public static final Aggregator<Double, Double> REAL_SUM = RealSumAggregator.INSTANCE;
7 public static final Aggregator<Double, Double> REAL_MIN = RealExtremeValueAggregator.MINIMUM; 18 public static final Aggregator<Double, Double> REAL_MIN = new ExtremeValueAggregator<>(Double.class,
8 public static final Aggregator<Double, Double> REAL_MAX = RealExtremeValueAggregator.MAXIMUM; 19 Double.POSITIVE_INFINITY);
20 public static final Aggregator<Double, Double> REAL_MAX = new ExtremeValueAggregator<>(Double.class,
21 Double.NEGATIVE_INFINITY, Comparator.reverseOrder());
9 22
10 private RealTerms() { 23 private RealTerms() {
11 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly"); 24 throw new IllegalArgumentException("This is a static utility class and should not be instantiated directly");
12 } 25 }
13 26
14 public static ConstantTerm<Double> constant(double value) { 27 public static Term<Double> constant(Double value) {
15 return new ConstantTerm<>(Double.class, value); 28 return new ConstantTerm<>(Double.class, value);
16 } 29 }
17 30
18 public static RealArithmeticUnaryTerm plus(Term<Double> body) { 31 public static Term<Double> plus(Term<Double> body) {
19 return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.PLUS, body); 32 return new RealPlusTerm(body);
20 } 33 }
21 34
22 public static RealArithmeticUnaryTerm minus(Term<Double> body) { 35 public static Term<Double> minus(Term<Double> body) {
23 return new RealArithmeticUnaryTerm(ArithmeticUnaryOperator.MINUS, body); 36 return new RealMinusTerm(body);
24 } 37 }
25 38
26 public static RealArithmeticBinaryTerm add(Term<Double> left, Term<Double> right) { 39 public static Term<Double> add(Term<Double> left, Term<Double> right) {
27 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.ADD, left, right); 40 return new RealAddTerm(left, right);
28 } 41 }
29 42
30 public static RealArithmeticBinaryTerm sub(Term<Double> left, Term<Double> right) { 43 public static Term<Double> sub(Term<Double> left, Term<Double> right) {
31 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.SUB, left, right); 44 return new RealSubTerm(left, right);
32 } 45 }
33 46
34 public static RealArithmeticBinaryTerm mul(Term<Double> left, Term<Double> right) { 47 public static Term<Double> mul(Term<Double> left, Term<Double> right) {
35 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MUL, left, right); 48 return new RealMulTerm(left, right);
36 } 49 }
37 50
38 public static RealArithmeticBinaryTerm div(Term<Double> left, Term<Double> right) { 51 public static Term<Double> div(Term<Double> left, Term<Double> right) {
39 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.DIV, left, right); 52 return new RealDivTerm(left, right);
40 } 53 }
41 54
42 public static RealArithmeticBinaryTerm pow(Term<Double> left, Term<Double> right) { 55 public static Term<Double> pow(Term<Double> left, Term<Double> right) {
43 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.POW, left, right); 56 return new RealPowTerm(left, right);
44 } 57 }
45 58
46 public static RealArithmeticBinaryTerm min(Term<Double> left, Term<Double> right) { 59 public static Term<Double> min(Term<Double> left, Term<Double> right) {
47 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MIN, left, right); 60 return new RealMinTerm(left, right);
48 } 61 }
49 62
50 public static RealArithmeticBinaryTerm max(Term<Double> left, Term<Double> right) { 63 public static Term<Double> max(Term<Double> left, Term<Double> right) {
51 return new RealArithmeticBinaryTerm(ArithmeticBinaryOperator.MAX, left, right); 64 return new RealMaxTerm(left, right);
52 } 65 }
53 66
54 public static RealComparisonTerm eq(Term<Double> left, Term<Double> right) { 67 public static Term<Boolean> eq(Term<Double> left, Term<Double> right) {
55 return new RealComparisonTerm(ComparisonOperator.EQ, left, right); 68 return new EqTerm<>(Double.class, left, right);
56 } 69 }
57 70
58 public static RealComparisonTerm notEq(Term<Double> left, Term<Double> right) { 71 public static Term<Boolean> notEq(Term<Double> left, Term<Double> right) {
59 return new RealComparisonTerm(ComparisonOperator.NOT_EQ, left, right); 72 return new NotEqTerm<>(Double.class, left, right);
60 } 73 }
61 74
62 public static RealComparisonTerm less(Term<Double> left, Term<Double> right) { 75 public static Term<Boolean> less(Term<Double> left, Term<Double> right) {
63 return new RealComparisonTerm(ComparisonOperator.LESS, left, right); 76 return new LessTerm<>(Double.class, left, right);
64 } 77 }
65 78
66 public static RealComparisonTerm lessEq(Term<Double> left, Term<Double> right) { 79 public static Term<Boolean> lessEq(Term<Double> left, Term<Double> right) {
67 return new RealComparisonTerm(ComparisonOperator.LESS_EQ, left, right); 80 return new LessEqTerm<>(Double.class, left, right);
68 } 81 }
69 82
70 public static RealComparisonTerm greater(Term<Double> left, Term<Double> right) { 83 public static Term<Boolean> greater(Term<Double> left, Term<Double> right) {
71 return new RealComparisonTerm(ComparisonOperator.GREATER, left, right); 84 return new GreaterTerm<>(Double.class, left, right);
72 } 85 }
73 86
74 public static RealComparisonTerm greaterEq(Term<Double> left, Term<Double> right) { 87 public static Term<Boolean> greaterEq(Term<Double> left, Term<Double> right) {
75 return new RealComparisonTerm(ComparisonOperator.GREATER_EQ, left, right); 88 return new GreaterEqTerm<>(Double.class, left, right);
76 } 89 }
77 90
78 public static IntToRealTerm asReal(Term<Integer> body) { 91 public static Term<Double> asReal(Term<Integer> body) {
79 return new IntToRealTerm(body); 92 return new IntToRealTerm(body);
80 } 93 }
81} 94}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java
new file mode 100644
index 00000000..d41c4ed9
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/real/RealUnaryTerm.java
@@ -0,0 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import tools.refinery.store.query.term.Term;
9import tools.refinery.store.query.term.UnaryTerm;
10
11public abstract class RealUnaryTerm extends UnaryTerm<Double, Double> {
12 protected RealUnaryTerm(Term<Double> body) {
13 super(Double.class, Double.class, body);
14 }
15}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java
new file mode 100644
index 00000000..68905f51
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityAddTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityAddTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityAddTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.add(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityAddTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s + %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java
new file mode 100644
index 00000000..0cf8fe44
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityBinaryTerm.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.BinaryTerm;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public abstract class UpperCardinalityBinaryTerm extends BinaryTerm<UpperCardinality, UpperCardinality,
13 UpperCardinality> {
14 protected UpperCardinalityBinaryTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
15 super(UpperCardinality.class, UpperCardinality.class, UpperCardinality.class, left, right);
16 }
17}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java
new file mode 100644
index 00000000..ff75f64e
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMaxTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMaxTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMaxTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.max(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMaxTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "max(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java
new file mode 100644
index 00000000..1e89e9f4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMinTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMinTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMinTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.min(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMinTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "min(%s, %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java
new file mode 100644
index 00000000..3b4970f4
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityMulTerm.java
@@ -0,0 +1,31 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.substitution.Substitution;
9import tools.refinery.store.query.term.Term;
10import tools.refinery.store.representation.cardinality.UpperCardinality;
11
12public class UpperCardinalityMulTerm extends UpperCardinalityBinaryTerm {
13 protected UpperCardinalityMulTerm(Term<UpperCardinality> left, Term<UpperCardinality> right) {
14 super(left, right);
15 }
16
17 @Override
18 protected UpperCardinality doEvaluate(UpperCardinality leftValue, UpperCardinality rightValue) {
19 return leftValue.multiply(rightValue);
20 }
21
22 @Override
23 public Term<UpperCardinality> doSubstitute(Substitution substitution, Term<UpperCardinality> substitutedLeft, Term<UpperCardinality> substitutedRight) {
24 return new UpperCardinalityMulTerm(substitutedLeft, substitutedRight);
25 }
26
27 @Override
28 public String toString() {
29 return "(%s * %s)".formatted(getLeft(), getRight());
30 }
31}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java
new file mode 100644
index 00000000..5bbd3081
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregator.java
@@ -0,0 +1,86 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.StatefulAggregate;
9import tools.refinery.store.query.term.StatefulAggregator;
10import tools.refinery.store.representation.cardinality.FiniteUpperCardinality;
11import tools.refinery.store.representation.cardinality.UnboundedUpperCardinality;
12import tools.refinery.store.representation.cardinality.UpperCardinalities;
13import tools.refinery.store.representation.cardinality.UpperCardinality;
14
15public class UpperCardinalitySumAggregator implements StatefulAggregator<UpperCardinality, UpperCardinality> {
16 public static final UpperCardinalitySumAggregator INSTANCE = new UpperCardinalitySumAggregator();
17
18 private UpperCardinalitySumAggregator() {
19 }
20
21 @Override
22 public Class<UpperCardinality> getResultType() {
23 return UpperCardinality.class;
24 }
25
26 @Override
27 public Class<UpperCardinality> getInputType() {
28 return UpperCardinality.class;
29 }
30
31 @Override
32 public StatefulAggregate<UpperCardinality, UpperCardinality> createEmptyAggregate() {
33 return new Aggregate();
34 }
35
36 private static class Aggregate implements StatefulAggregate<UpperCardinality, UpperCardinality> {
37 private int sumFiniteUpperBounds;
38 private int countUnbounded;
39
40 public Aggregate() {
41 this(0, 0);
42 }
43
44 private Aggregate(int sumFiniteUpperBounds, int countUnbounded) {
45 this.sumFiniteUpperBounds = sumFiniteUpperBounds;
46 this.countUnbounded = countUnbounded;
47 }
48
49 @Override
50 public void add(UpperCardinality value) {
51 if (value instanceof FiniteUpperCardinality finiteUpperCardinality) {
52 sumFiniteUpperBounds += finiteUpperCardinality.finiteUpperBound();
53 } else if (value instanceof UnboundedUpperCardinality) {
54 countUnbounded += 1;
55 } else {
56 throw new IllegalArgumentException("Unknown UpperCardinality: " + value);
57 }
58 }
59
60 @Override
61 public void remove(UpperCardinality value) {
62 if (value instanceof FiniteUpperCardinality finiteUpperCardinality) {
63 sumFiniteUpperBounds -= finiteUpperCardinality.finiteUpperBound();
64 } else if (value instanceof UnboundedUpperCardinality) {
65 countUnbounded -= 1;
66 } else {
67 throw new IllegalArgumentException("Unknown UpperCardinality: " + value);
68 }
69 }
70
71 @Override
72 public UpperCardinality getResult() {
73 return countUnbounded > 0 ? UpperCardinalities.UNBOUNDED : UpperCardinalities.valueOf(sumFiniteUpperBounds);
74 }
75
76 @Override
77 public boolean isEmpty() {
78 return sumFiniteUpperBounds == 0 && countUnbounded == 0;
79 }
80
81 @Override
82 public StatefulAggregate<UpperCardinality, UpperCardinality> deepCopy() {
83 return new Aggregate(sumFiniteUpperBounds, countUnbounded);
84 }
85 }
86}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java
new file mode 100644
index 00000000..13914f2d
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTerms.java
@@ -0,0 +1,73 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import tools.refinery.store.query.term.Aggregator;
9import tools.refinery.store.query.term.ConstantTerm;
10import tools.refinery.store.query.term.ExtremeValueAggregator;
11import tools.refinery.store.query.term.Term;
12import tools.refinery.store.query.term.comparable.*;
13import tools.refinery.store.representation.cardinality.UpperCardinalities;
14import tools.refinery.store.representation.cardinality.UpperCardinality;
15
16import java.util.Comparator;
17
18public final class UpperCardinalityTerms {
19 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_SUM =
20 UpperCardinalitySumAggregator.INSTANCE;
21 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MIN =
22 new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.UNBOUNDED);
23 public static final Aggregator<UpperCardinality, UpperCardinality> UPPER_CARDINALITY_MAX =
24 new ExtremeValueAggregator<>(UpperCardinality.class, UpperCardinalities.ZERO, Comparator.reverseOrder());
25
26 private UpperCardinalityTerms() {
27 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
28 }
29
30 public static Term<UpperCardinality> constant(UpperCardinality value) {
31 return new ConstantTerm<>(UpperCardinality.class, value);
32 }
33
34 public static Term<UpperCardinality> add(Term<UpperCardinality> left, Term<UpperCardinality> right) {
35 return new UpperCardinalityAddTerm(left, right);
36 }
37
38 public static Term<UpperCardinality> mul(Term<UpperCardinality> left, Term<UpperCardinality> right) {
39 return new UpperCardinalityMulTerm(left, right);
40 }
41
42 public static Term<UpperCardinality> min(Term<UpperCardinality> left, Term<UpperCardinality> right) {
43 return new UpperCardinalityMinTerm(left, right);
44 }
45
46 public static Term<UpperCardinality> max(Term<UpperCardinality> left, Term<UpperCardinality> right) {
47 return new UpperCardinalityMaxTerm(left, right);
48 }
49
50 public static Term<Boolean> eq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
51 return new EqTerm<>(UpperCardinality.class, left, right);
52 }
53
54 public static Term<Boolean> notEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
55 return new NotEqTerm<>(UpperCardinality.class, left, right);
56 }
57
58 public static Term<Boolean> less(Term<UpperCardinality> left, Term<UpperCardinality> right) {
59 return new LessTerm<>(UpperCardinality.class, left, right);
60 }
61
62 public static Term<Boolean> lessEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
63 return new LessEqTerm<>(UpperCardinality.class, left, right);
64 }
65
66 public static Term<Boolean> greater(Term<UpperCardinality> left, Term<UpperCardinality> right) {
67 return new GreaterTerm<>(UpperCardinality.class, left, right);
68 }
69
70 public static Term<Boolean> greaterEq(Term<UpperCardinality> left, Term<UpperCardinality> right) {
71 return new GreaterEqTerm<>(UpperCardinality.class, left, right);
72 }
73}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java
new file mode 100644
index 00000000..261ceaa5
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/MapBasedValuation.java
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.term.AnyDataVariable;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Map;
12
13record MapBasedValuation(Map<AnyDataVariable, Object> values) implements Valuation {
14 @Override
15 public <T> T getValue(DataVariable<T> variable) {
16 if (!values.containsKey(variable)) {
17 throw new IllegalArgumentException("No value for variable %s".formatted(variable));
18 }
19 var value = values.get(variable);
20 return variable.getType().cast(value);
21 }
22}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java
index fb512d88..fc8406aa 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/RestrictedValuation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.valuation; 6package tools.refinery.store.query.valuation;
2 7
3import tools.refinery.store.query.term.AnyDataVariable; 8import tools.refinery.store.query.term.AnyDataVariable;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java
index 8e79663c..1c14112c 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/SubstitutedValuation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.valuation; 6package tools.refinery.store.query.valuation;
2 7
3import tools.refinery.store.query.substitution.Substitution; 8import tools.refinery.store.query.substitution.Substitution;
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java
index 3ba9a6b8..1588e957 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/Valuation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.valuation; 6package tools.refinery.store.query.valuation;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
@@ -5,6 +10,7 @@ import tools.refinery.store.query.substitution.Substitution;
5import tools.refinery.store.query.term.AnyDataVariable; 10import tools.refinery.store.query.term.AnyDataVariable;
6import tools.refinery.store.query.term.DataVariable; 11import tools.refinery.store.query.term.DataVariable;
7 12
13import java.util.Map;
8import java.util.Set; 14import java.util.Set;
9 15
10public interface Valuation { 16public interface Valuation {
@@ -20,4 +26,12 @@ public interface Valuation {
20 default Valuation restrict(Set<? extends AnyDataVariable> allowedVariables) { 26 default Valuation restrict(Set<? extends AnyDataVariable> allowedVariables) {
21 return new RestrictedValuation(this, Set.copyOf(allowedVariables)); 27 return new RestrictedValuation(this, Set.copyOf(allowedVariables));
22 } 28 }
29
30 static ValuationBuilder builder() {
31 return new ValuationBuilder();
32 }
33
34 static Valuation empty() {
35 return new MapBasedValuation(Map.of());
36 }
23} 37}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java
new file mode 100644
index 00000000..7337dbc3
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/valuation/ValuationBuilder.java
@@ -0,0 +1,40 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.valuation;
7
8import tools.refinery.store.query.term.AnyDataVariable;
9import tools.refinery.store.query.term.DataVariable;
10
11import java.util.Collections;
12import java.util.HashMap;
13import java.util.Map;
14
15public class ValuationBuilder {
16 private final Map<AnyDataVariable, Object> values = new HashMap<>();
17
18 ValuationBuilder() {
19 }
20
21 public <T> ValuationBuilder put(DataVariable<T> variable, T value) {
22 return putChecked(variable, value);
23 }
24
25 public ValuationBuilder putChecked(AnyDataVariable variable, Object value) {
26 if (value != null && !variable.getType().isInstance(value)) {
27 throw new IllegalArgumentException("Value %s is not an instance of %s"
28 .formatted(value, variable.getType().getName()));
29 }
30 if (values.containsKey(variable)) {
31 throw new IllegalArgumentException("Already has value for variable %s".formatted(variable));
32 }
33 values.put(variable, value);
34 return this;
35 }
36
37 public Valuation build() {
38 return new MapBasedValuation(Collections.unmodifiableMap(values));
39 }
40}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java
new file mode 100644
index 00000000..c1f9d688
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AbstractFunctionView.java
@@ -0,0 +1,112 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.view;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.query.dnf.FunctionalDependency;
10import tools.refinery.store.query.term.Parameter;
11import tools.refinery.store.representation.Symbol;
12import tools.refinery.store.tuple.Tuple;
13import tools.refinery.store.tuple.Tuple1;
14
15import java.util.Arrays;
16import java.util.List;
17import java.util.Objects;
18import java.util.Set;
19import java.util.stream.Collectors;
20import java.util.stream.IntStream;
21
22public abstract class AbstractFunctionView<T> extends SymbolView<T> {
23 private final T defaultValue;
24 private final List<Parameter> parameters;
25
26 protected AbstractFunctionView(Symbol<T> symbol, String name, Parameter outParameter) {
27 super(symbol, name);
28 defaultValue = symbol.defaultValue();
29 parameters = createParameters(symbol.arity(), outParameter);
30 }
31
32 @Override
33 public Set<FunctionalDependency<Integer>> getFunctionalDependencies() {
34 var arity = getSymbol().arity();
35 var forEach = IntStream.range(0, arity).boxed().collect(Collectors.toUnmodifiableSet());
36 var unique = Set.of(arity);
37 return Set.of(new FunctionalDependency<>(forEach, unique));
38 }
39
40 @Override
41 public Set<ViewImplication> getImpliedRelationViews() {
42 var symbol = getSymbol();
43 var impliedIndices = IntStream.range(0, symbol.arity()).boxed().toList();
44 var keysView = new KeyOnlyView<>(symbol);
45 return Set.of(new ViewImplication(this, keysView, impliedIndices));
46 }
47
48 @Override
49 public final boolean filter(Tuple key, T value) {
50 return !Objects.equals(defaultValue, value);
51 }
52
53 protected Object forwardMapValue(Tuple key, T value) {
54 return value;
55 }
56
57 protected boolean valueEquals(Tuple key, T value, Object otherForwardMappedValue) {
58 return Objects.equals(otherForwardMappedValue, forwardMapValue(key, value));
59 }
60
61 @Override
62 public Object[] forwardMap(Tuple key, T value) {
63 int size = key.getSize();
64 Object[] result = new Object[size + 1];
65 for (int i = 0; i < size; i++) {
66 result[i] = Tuple.of(key.get(i));
67 }
68 result[key.getSize()] = forwardMapValue(key, value);
69 return result;
70 }
71
72 @Override
73 public boolean get(Model model, Object[] tuple) {
74 int[] content = new int[tuple.length - 1];
75 for (int i = 0; i < tuple.length - 1; i++) {
76 if (!(tuple[i] instanceof Tuple1 wrapper)) {
77 return false;
78 }
79 content[i] = wrapper.value0();
80 }
81 Tuple key = Tuple.of(content);
82 var valueInTuple = tuple[tuple.length - 1];
83 T valueInMap = model.getInterpretation(getSymbol()).get(key);
84 return valueEquals(key, valueInMap, valueInTuple);
85 }
86
87 @Override
88 public List<Parameter> getParameters() {
89 return parameters;
90 }
91
92 @Override
93 public boolean equals(Object o) {
94 if (this == o) return true;
95 if (o == null || getClass() != o.getClass()) return false;
96 if (!super.equals(o)) return false;
97 AbstractFunctionView<?> that = (AbstractFunctionView<?>) o;
98 return Objects.equals(defaultValue, that.defaultValue) && Objects.equals(parameters, that.parameters);
99 }
100
101 @Override
102 public int hashCode() {
103 return Objects.hash(super.hashCode(), defaultValue, parameters);
104 }
105
106 private static List<Parameter> createParameters(int symbolArity, Parameter outParameter) {
107 var parameters = new Parameter[symbolArity + 1];
108 Arrays.fill(parameters, Parameter.NODE_OUT);
109 parameters[symbolArity] = outParameter;
110 return List.of(parameters);
111 }
112}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java
index 6ae410f2..90b27ebb 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnyRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/AnySymbolView.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
@@ -7,7 +12,7 @@ import tools.refinery.store.query.Constraint;
7 12
8import java.util.Set; 13import java.util.Set;
9 14
10public sealed interface AnyRelationView extends Constraint permits RelationView { 15public sealed interface AnySymbolView extends Constraint permits SymbolView {
11 AnySymbol getSymbol(); 16 AnySymbol getSymbol();
12 17
13 String getViewName(); 18 String getViewName();
@@ -16,7 +21,7 @@ public sealed interface AnyRelationView extends Constraint permits RelationView
16 return Set.of(); 21 return Set.of();
17 } 22 }
18 23
19 default Set<RelationViewImplication> getImpliedRelationViews() { 24 default Set<ViewImplication> getImpliedRelationViews() {
20 return Set.of(); 25 return Set.of();
21 } 26 }
22 27
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java
index 64c601bb..922c7355 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FilteredView.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.tuple.Tuple; 8import tools.refinery.store.tuple.Tuple;
@@ -7,24 +12,24 @@ import java.util.Objects;
7import java.util.function.BiPredicate; 12import java.util.function.BiPredicate;
8import java.util.function.Predicate; 13import java.util.function.Predicate;
9 14
10public class FilteredRelationView<T> extends TuplePreservingRelationView<T> { 15public class FilteredView<T> extends TuplePreservingView<T> {
11 private final BiPredicate<Tuple, T> predicate; 16 private final BiPredicate<Tuple, T> predicate;
12 17
13 public FilteredRelationView(Symbol<T> symbol, String name, BiPredicate<Tuple, T> predicate) { 18 public FilteredView(Symbol<T> symbol, String name, BiPredicate<Tuple, T> predicate) {
14 super(symbol, name); 19 super(symbol, name);
15 this.predicate = predicate; 20 this.predicate = predicate;
16 } 21 }
17 22
18 public FilteredRelationView(Symbol<T> symbol, BiPredicate<Tuple, T> predicate) { 23 public FilteredView(Symbol<T> symbol, BiPredicate<Tuple, T> predicate) {
19 super(symbol); 24 super(symbol);
20 this.predicate = predicate; 25 this.predicate = predicate;
21 } 26 }
22 27
23 public FilteredRelationView(Symbol<T> symbol, String name, Predicate<T> predicate) { 28 public FilteredView(Symbol<T> symbol, String name, Predicate<T> predicate) {
24 this(symbol, name, (k, v) -> predicate.test(v)); 29 this(symbol, name, (k, v) -> predicate.test(v));
25 } 30 }
26 31
27 public FilteredRelationView(Symbol<T> symbol, Predicate<T> predicate) { 32 public FilteredView(Symbol<T> symbol, Predicate<T> predicate) {
28 this(symbol, (k, v) -> predicate.test(v)); 33 this(symbol, (k, v) -> predicate.test(v));
29 } 34 }
30 35
@@ -38,7 +43,7 @@ public class FilteredRelationView<T> extends TuplePreservingRelationView<T> {
38 if (this == o) return true; 43 if (this == o) return true;
39 if (o == null || getClass() != o.getClass()) return false; 44 if (o == null || getClass() != o.getClass()) return false;
40 if (!super.equals(o)) return false; 45 if (!super.equals(o)) return false;
41 FilteredRelationView<?> that = (FilteredRelationView<?>) o; 46 FilteredView<?> that = (FilteredView<?>) o;
42 return Objects.equals(predicate, that.predicate); 47 return Objects.equals(predicate, that.predicate);
43 } 48 }
44 49
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java
index 050b9496..26b717ee 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ForbiddenView.java
@@ -1,11 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
4import tools.refinery.store.representation.TruthValue; 9import tools.refinery.store.representation.TruthValue;
5import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
6 11
7public class ForbiddenRelationView extends TuplePreservingRelationView<TruthValue> { 12public class ForbiddenView extends TuplePreservingView<TruthValue> {
8 public ForbiddenRelationView(Symbol<TruthValue> symbol) { 13 public ForbiddenView(Symbol<TruthValue> symbol) {
9 super(symbol, "forbidden"); 14 super(symbol, "forbidden");
10 } 15 }
11 16
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java
new file mode 100644
index 00000000..74a5be07
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionView.java
@@ -0,0 +1,36 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.view;
7
8import tools.refinery.store.query.term.*;
9import tools.refinery.store.representation.Symbol;
10
11import java.util.ArrayList;
12import java.util.List;
13
14public final class FunctionView<T> extends AbstractFunctionView<T> {
15 public FunctionView(Symbol<T> symbol, String name) {
16 super(symbol, name, new Parameter(symbol.valueType(), ParameterDirection.OUT));
17 }
18
19 public FunctionView(Symbol<T> symbol) {
20 this(symbol, "function");
21 }
22
23 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, List<NodeVariable> arguments) {
24 return targetVariable -> {
25 var placeholderVariable = Variable.of(getSymbol().valueType());
26 var argumentsWithPlaceholder = new ArrayList<Variable>(arguments.size() + 1);
27 argumentsWithPlaceholder.addAll(arguments);
28 argumentsWithPlaceholder.add(placeholderVariable);
29 return aggregateBy(placeholderVariable, aggregator, argumentsWithPlaceholder).toLiteral(targetVariable);
30 };
31 }
32
33 public <R> AssignedValue<R> aggregate(Aggregator<R, T> aggregator, NodeVariable... arguments) {
34 return aggregate(aggregator, List.of(arguments));
35 }
36}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
deleted file mode 100644
index 7ec9e7ac..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/FunctionalRelationView.java
+++ /dev/null
@@ -1,105 +0,0 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.query.dnf.FunctionalDependency;
5import tools.refinery.store.query.term.DataSort;
6import tools.refinery.store.query.term.NodeSort;
7import tools.refinery.store.query.term.Sort;
8import tools.refinery.store.representation.Symbol;
9import tools.refinery.store.tuple.Tuple;
10import tools.refinery.store.tuple.Tuple1;
11
12import java.util.List;
13import java.util.Objects;
14import java.util.Set;
15import java.util.stream.Collectors;
16import java.util.stream.IntStream;
17
18public final class FunctionalRelationView<T> extends RelationView<T> {
19 private final T defaultValue;
20
21 public FunctionalRelationView(Symbol<T> symbol, String name) {
22 super(symbol, name);
23 defaultValue = symbol.defaultValue();
24 }
25
26 public FunctionalRelationView(Symbol<T> symbol) {
27 super(symbol);
28 defaultValue = symbol.defaultValue();
29 }
30
31 @Override
32 public Set<FunctionalDependency<Integer>> getFunctionalDependencies() {
33 var arity = getSymbol().arity();
34 var forEach = IntStream.range(0, arity).boxed().collect(Collectors.toUnmodifiableSet());
35 var unique = Set.of(arity);
36 return Set.of(new FunctionalDependency<>(forEach, unique));
37 }
38
39 @Override
40 public Set<RelationViewImplication> getImpliedRelationViews() {
41 var symbol = getSymbol();
42 var impliedIndices = IntStream.range(0, symbol.arity()).boxed().toList();
43 var keyOnlyRelationView = new KeyOnlyRelationView<>(symbol);
44 return Set.of(new RelationViewImplication(this, keyOnlyRelationView, impliedIndices));
45 }
46
47 @Override
48 public boolean filter(Tuple key, T value) {
49 return !Objects.equals(defaultValue, value);
50 }
51
52 @Override
53 public Object[] forwardMap(Tuple key, T value) {
54 int size = key.getSize();
55 Object[] result = new Object[size + 1];
56 for (int i = 0; i < size; i++) {
57 result[i] = Tuple.of(key.get(i));
58 }
59 result[key.getSize()] = value;
60 return result;
61 }
62
63 @Override
64 public boolean get(Model model, Object[] tuple) {
65 int[] content = new int[tuple.length - 1];
66 for (int i = 0; i < tuple.length - 1; i++) {
67 content[i] = ((Tuple1) tuple[i]).value0();
68 }
69 Tuple key = Tuple.of(content);
70 @SuppressWarnings("unchecked")
71 T valueInTuple = (T) tuple[tuple.length - 1];
72 T valueInMap = model.getInterpretation(getSymbol()).get(key);
73 return valueInTuple.equals(valueInMap);
74 }
75
76 @Override
77 public int arity() {
78 return getSymbol().arity() + 1;
79 }
80
81 @Override
82 public List<Sort> getSorts() {
83 var sorts = new Sort[arity()];
84 int valueIndex = sorts.length - 1;
85 for (int i = 0; i < valueIndex; i++) {
86 sorts[i] = NodeSort.INSTANCE;
87 }
88 sorts[valueIndex] = new DataSort<>(getSymbol().valueType());
89 return List.of(sorts);
90 }
91
92 @Override
93 public boolean equals(Object o) {
94 if (this == o) return true;
95 if (o == null || getClass() != o.getClass()) return false;
96 if (!super.equals(o)) return false;
97 FunctionalRelationView<?> that = (FunctionalRelationView<?>) o;
98 return Objects.equals(defaultValue, that.defaultValue);
99 }
100
101 @Override
102 public int hashCode() {
103 return Objects.hash(super.hashCode(), defaultValue);
104 }
105}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java
index e1b2e45b..7e86f6e4 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/KeyOnlyView.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
@@ -5,12 +10,12 @@ import tools.refinery.store.tuple.Tuple;
5 10
6import java.util.Objects; 11import java.util.Objects;
7 12
8public final class KeyOnlyRelationView<T> extends TuplePreservingRelationView<T> { 13public final class KeyOnlyView<T> extends TuplePreservingView<T> {
9 public static final String VIEW_NAME = "key"; 14 public static final String VIEW_NAME = "key";
10 15
11 private final T defaultValue; 16 private final T defaultValue;
12 17
13 public KeyOnlyRelationView(Symbol<T> symbol) { 18 public KeyOnlyView(Symbol<T> symbol) {
14 super(symbol, VIEW_NAME); 19 super(symbol, VIEW_NAME);
15 defaultValue = symbol.defaultValue(); 20 defaultValue = symbol.defaultValue();
16 } 21 }
@@ -25,7 +30,7 @@ public final class KeyOnlyRelationView<T> extends TuplePreservingRelationView<T>
25 if (this == o) return true; 30 if (this == o) return true;
26 if (o == null || getClass() != o.getClass()) return false; 31 if (o == null || getClass() != o.getClass()) return false;
27 if (!super.equals(o)) return false; 32 if (!super.equals(o)) return false;
28 KeyOnlyRelationView<?> that = (KeyOnlyRelationView<?>) o; 33 KeyOnlyView<?> that = (KeyOnlyView<?>) o;
29 return Objects.equals(defaultValue, that.defaultValue); 34 return Objects.equals(defaultValue, that.defaultValue);
30 } 35 }
31 36
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java
index a2a84b3c..e75a8171 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MayView.java
@@ -1,11 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
4import tools.refinery.store.representation.TruthValue; 9import tools.refinery.store.representation.TruthValue;
5import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
6 11
7public class MayRelationView extends TuplePreservingRelationView<TruthValue> { 12public class MayView extends TuplePreservingView<TruthValue> {
8 public MayRelationView(Symbol<TruthValue> symbol) { 13 public MayView(Symbol<TruthValue> symbol) {
9 super(symbol, "may"); 14 super(symbol, "may");
10 } 15 }
11 16
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java
index 72ac0ca3..a48f8045 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustRelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/MustView.java
@@ -1,11 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
4import tools.refinery.store.representation.TruthValue; 9import tools.refinery.store.representation.TruthValue;
5import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
6 11
7public class MustRelationView extends TuplePreservingRelationView<TruthValue> { 12public class MustView extends TuplePreservingView<TruthValue> {
8 public MustRelationView(Symbol<TruthValue> symbol) { 13 public MustView(Symbol<TruthValue> symbol) {
9 super(symbol, "must"); 14 super(symbol, "must");
10 } 15 }
11 16
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java
new file mode 100644
index 00000000..fcf11506
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/NodeFunctionView.java
@@ -0,0 +1,20 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.view;
7
8import tools.refinery.store.query.term.Parameter;
9import tools.refinery.store.representation.Symbol;
10import tools.refinery.store.tuple.Tuple1;
11
12public final class NodeFunctionView extends AbstractFunctionView<Tuple1> {
13 public NodeFunctionView(Symbol<Tuple1> symbol, String name) {
14 super(symbol, name, Parameter.NODE_OUT);
15 }
16
17 public NodeFunctionView(Symbol<Tuple1> symbol) {
18 this(symbol, "function");
19 }
20}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java
deleted file mode 100644
index 2ba1fcc4..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationViewImplication.java
+++ /dev/null
@@ -1,19 +0,0 @@
1package tools.refinery.store.query.view;
2
3import java.util.List;
4
5public record RelationViewImplication(AnyRelationView implyingRelationView, AnyRelationView impliedRelationView,
6 List<Integer> impliedIndices) {
7 public RelationViewImplication {
8 if (impliedIndices.size() != impliedRelationView.arity()) {
9 throw new IllegalArgumentException("Expected %d implied indices for %s, but %d are provided"
10 .formatted(impliedRelationView.arity(), impliedRelationView, impliedIndices.size()));
11 }
12 for (var index : impliedIndices) {
13 if (impliedRelationView.invalidIndex(index)) {
14 throw new IllegalArgumentException("%d is not a valid index for %s".formatted(index,
15 implyingRelationView));
16 }
17 }
18 }
19}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java
index d7164b3b..267a99d3 100644
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/RelationView.java
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/SymbolView.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.view; 6package tools.refinery.store.query.view;
2 7
3import tools.refinery.store.map.CursorAsIterator; 8import tools.refinery.store.map.CursorAsIterator;
@@ -14,17 +19,17 @@ import java.util.UUID;
14 * @param <T> 19 * @param <T>
15 * @author Oszkar Semerath 20 * @author Oszkar Semerath
16 */ 21 */
17public abstract non-sealed class RelationView<T> implements AnyRelationView { 22public abstract non-sealed class SymbolView<T> implements AnySymbolView {
18 private final Symbol<T> symbol; 23 private final Symbol<T> symbol;
19 24
20 private final String viewName; 25 private final String viewName;
21 26
22 protected RelationView(Symbol<T> symbol, String viewName) { 27 protected SymbolView(Symbol<T> symbol, String viewName) {
23 this.symbol = symbol; 28 this.symbol = symbol;
24 this.viewName = viewName; 29 this.viewName = viewName;
25 } 30 }
26 31
27 protected RelationView(Symbol<T> representation) { 32 protected SymbolView(Symbol<T> representation) {
28 this(representation, UUID.randomUUID().toString()); 33 this(representation, UUID.randomUUID().toString());
29 } 34 }
30 35
@@ -66,7 +71,7 @@ public abstract non-sealed class RelationView<T> implements AnyRelationView {
66 public boolean equals(Object o) { 71 public boolean equals(Object o) {
67 if (this == o) return true; 72 if (this == o) return true;
68 if (o == null || getClass() != o.getClass()) return false; 73 if (o == null || getClass() != o.getClass()) return false;
69 RelationView<?> that = (RelationView<?>) o; 74 SymbolView<?> that = (SymbolView<?>) o;
70 return Objects.equals(symbol, that.symbol) && Objects.equals(viewName, that.viewName); 75 return Objects.equals(symbol, that.symbol) && Objects.equals(viewName, that.viewName);
71 } 76 }
72 77
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
deleted file mode 100644
index 234b3a9a..00000000
--- a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingRelationView.java
+++ /dev/null
@@ -1,57 +0,0 @@
1package tools.refinery.store.query.view;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.query.term.NodeSort;
5import tools.refinery.store.query.term.Sort;
6import tools.refinery.store.tuple.Tuple;
7import tools.refinery.store.tuple.Tuple1;
8import tools.refinery.store.representation.Symbol;
9
10import java.util.Arrays;
11import java.util.List;
12
13public abstract class TuplePreservingRelationView<T> extends RelationView<T> {
14 protected TuplePreservingRelationView(Symbol<T> symbol, String name) {
15 super(symbol, name);
16 }
17
18 protected TuplePreservingRelationView(Symbol<T> symbol) {
19 super(symbol);
20 }
21
22 public Object[] forwardMap(Tuple key) {
23 Object[] result = new Object[key.getSize()];
24 for (int i = 0; i < key.getSize(); i++) {
25 result[i] = Tuple.of(key.get(i));
26 }
27 return result;
28 }
29
30 @Override
31 public Object[] forwardMap(Tuple key, T value) {
32 return forwardMap(key);
33 }
34
35 @Override
36 public boolean get(Model model, Object[] tuple) {
37 int[] content = new int[tuple.length];
38 for (int i = 0; i < tuple.length; i++) {
39 content[i] = ((Tuple1) tuple[i]).value0();
40 }
41 Tuple key = Tuple.of(content);
42 T value = model.getInterpretation(getSymbol()).get(key);
43 return filter(key, value);
44 }
45
46 @Override
47 public int arity() {
48 return this.getSymbol().arity();
49 }
50
51 @Override
52 public List<Sort> getSorts() {
53 var sorts = new Sort[arity()];
54 Arrays.fill(sorts, NodeSort.INSTANCE);
55 return List.of(sorts);
56 }
57}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java
new file mode 100644
index 00000000..6bc5a708
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/TuplePreservingView.java
@@ -0,0 +1,82 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.view;
7
8import tools.refinery.store.model.Model;
9import tools.refinery.store.query.term.Parameter;
10import tools.refinery.store.representation.Symbol;
11import tools.refinery.store.tuple.Tuple;
12import tools.refinery.store.tuple.Tuple1;
13
14import java.util.Arrays;
15import java.util.List;
16import java.util.Objects;
17
18public abstract class TuplePreservingView<T> extends SymbolView<T> {
19 private final List<Parameter> parameters;
20
21 protected TuplePreservingView(Symbol<T> symbol, String name) {
22 super(symbol, name);
23 this.parameters = createParameters(symbol.arity());
24 }
25
26 protected TuplePreservingView(Symbol<T> symbol) {
27 super(symbol);
28 this.parameters = createParameters(symbol.arity());
29 }
30
31 public Object[] forwardMap(Tuple key) {
32 Object[] result = new Object[key.getSize()];
33 for (int i = 0; i < key.getSize(); i++) {
34 result[i] = Tuple.of(key.get(i));
35 }
36 return result;
37 }
38
39 @Override
40 public Object[] forwardMap(Tuple key, T value) {
41 return forwardMap(key);
42 }
43
44 @Override
45 public boolean get(Model model, Object[] tuple) {
46 int[] content = new int[tuple.length];
47 for (int i = 0; i < tuple.length; i++) {
48 if (!(tuple[i] instanceof Tuple1 wrapper)) {
49 return false;
50 }
51 content[i] = wrapper.value0();
52 }
53 Tuple key = Tuple.of(content);
54 T value = model.getInterpretation(getSymbol()).get(key);
55 return filter(key, value);
56 }
57
58 @Override
59 public List<Parameter> getParameters() {
60 return parameters;
61 }
62
63 @Override
64 public boolean equals(Object o) {
65 if (this == o) return true;
66 if (o == null || getClass() != o.getClass()) return false;
67 if (!super.equals(o)) return false;
68 TuplePreservingView<?> that = (TuplePreservingView<?>) o;
69 return Objects.equals(parameters, that.parameters);
70 }
71
72 @Override
73 public int hashCode() {
74 return Objects.hash(super.hashCode(), parameters);
75 }
76
77 private static List<Parameter> createParameters(int arity) {
78 var parameters = new Parameter[arity];
79 Arrays.fill(parameters, Parameter.NODE_OUT);
80 return List.of(parameters);
81 }
82}
diff --git a/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java
new file mode 100644
index 00000000..fc2db9f2
--- /dev/null
+++ b/subprojects/store-query/src/main/java/tools/refinery/store/query/view/ViewImplication.java
@@ -0,0 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.view;
7
8import java.util.List;
9
10public record ViewImplication(AnySymbolView implyingView, AnySymbolView impliedView, List<Integer> impliedIndices) {
11 public ViewImplication {
12 if (impliedIndices.size() != impliedView.arity()) {
13 throw new IllegalArgumentException("Expected %d implied indices for %s, but %d are provided"
14 .formatted(impliedView.arity(), impliedView, impliedIndices.size()));
15 }
16 for (var index : impliedIndices) {
17 if (impliedView.invalidIndex(index)) {
18 throw new IllegalArgumentException("%d is not a valid index for %s".formatted(index,
19 implyingView));
20 }
21 }
22 }
23}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java
index ceb46d6f..e17496e3 100644
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfBuilderTest.java
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderLiteralEliminationTest.java
@@ -1,24 +1,39 @@
1package tools.refinery.store.query; 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
4import tools.refinery.store.query.dnf.Dnf; 9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
5import tools.refinery.store.query.literal.BooleanLiteral; 11import tools.refinery.store.query.literal.BooleanLiteral;
12import tools.refinery.store.query.term.NodeVariable;
13import tools.refinery.store.query.term.ParameterDirection;
6import tools.refinery.store.query.term.Variable; 14import tools.refinery.store.query.term.Variable;
7import tools.refinery.store.query.view.KeyOnlyRelationView; 15import tools.refinery.store.query.term.bool.BoolTerms;
16import tools.refinery.store.query.view.KeyOnlyView;
17import tools.refinery.store.query.view.SymbolView;
8import tools.refinery.store.representation.Symbol; 18import tools.refinery.store.representation.Symbol;
9 19
20import java.util.List;
21
10import static org.hamcrest.MatcherAssert.assertThat; 22import static org.hamcrest.MatcherAssert.assertThat;
23import static tools.refinery.store.query.literal.Literals.assume;
11import static tools.refinery.store.query.literal.Literals.not; 24import static tools.refinery.store.query.literal.Literals.not;
12import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; 25import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
13 26
14class DnfBuilderTest { 27class DnfBuilderLiteralEliminationTest {
28 private final Symbol<Boolean> friend = Symbol.of("friend", 2);
29 private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend);
30 private final NodeVariable p = Variable.of("p");
31 private final NodeVariable q = Variable.of("q");
32 private final Dnf trueDnf = Dnf.builder().parameter(p, ParameterDirection.IN).clause().build();
33 private final Dnf falseDnf = Dnf.builder().parameter(p).build();
34
15 @Test 35 @Test
16 void eliminateTrueTest() { 36 void eliminateTrueTest() {
17 var p = Variable.of("p");
18 var q = Variable.of("q");
19 var friend = new Symbol<>("friend", 2, Boolean.class, false);
20 var friendView = new KeyOnlyRelationView<>(friend);
21
22 var actual = Dnf.builder() 37 var actual = Dnf.builder()
23 .parameters(p, q) 38 .parameters(p, q)
24 .clause(BooleanLiteral.TRUE, friendView.call(p, q)) 39 .clause(BooleanLiteral.TRUE, friendView.call(p, q))
@@ -29,12 +44,18 @@ class DnfBuilderTest {
29 } 44 }
30 45
31 @Test 46 @Test
32 void eliminateFalseTest() { 47 void eliminateTrueAssumptionTest() {
33 var p = Variable.of("p"); 48 var actual = Dnf.builder()
34 var q = Variable.of("q"); 49 .parameters(p, q)
35 var friend = new Symbol<>("friend", 2, Boolean.class, false); 50 .clause(assume(BoolTerms.constant(true)), friendView.call(p, q))
36 var friendView = new KeyOnlyRelationView<>(friend); 51 .build();
52 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
53
54 assertThat(actual, structurallyEqualTo(expected));
55 }
37 56
57 @Test
58 void eliminateFalseTest() {
38 var actual = Dnf.builder() 59 var actual = Dnf.builder()
39 .parameters(p, q) 60 .parameters(p, q)
40 .clause(friendView.call(p, q)) 61 .clause(friendView.call(p, q))
@@ -45,30 +66,36 @@ class DnfBuilderTest {
45 assertThat(actual, structurallyEqualTo(expected)); 66 assertThat(actual, structurallyEqualTo(expected));
46 } 67 }
47 68
69 @ParameterizedTest
70 @CsvSource(value = {
71 "false",
72 "null"
73 }, nullValues = "null")
74 void eliminateFalseAssumptionTest(Boolean value) {
75 var actual = Dnf.builder()
76 .parameters(p, q)
77 .clause(friendView.call(p, q))
78 .clause(friendView.call(q, p), assume(BoolTerms.constant(value)))
79 .build();
80 var expected = Dnf.builder().parameters(p, q).clause(friendView.call(p, q)).build();
81
82 assertThat(actual, structurallyEqualTo(expected));
83 }
84
48 @Test 85 @Test
49 void alwaysTrueTest() { 86 void alwaysTrueTest() {
50 var p = Variable.of("p");
51 var q = Variable.of("q");
52 var friend = new Symbol<>("friend", 2, Boolean.class, false);
53 var friendView = new KeyOnlyRelationView<>(friend);
54
55 var actual = Dnf.builder() 87 var actual = Dnf.builder()
56 .parameters(p, q) 88 .parameters(List.of(p, q), ParameterDirection.IN)
57 .clause(friendView.call(p, q)) 89 .clause(friendView.call(p, q))
58 .clause(BooleanLiteral.TRUE) 90 .clause(BooleanLiteral.TRUE)
59 .build(); 91 .build();
60 var expected = Dnf.builder().parameters(p, q).clause().build(); 92 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
61 93
62 assertThat(actual, structurallyEqualTo(expected)); 94 assertThat(actual, structurallyEqualTo(expected));
63 } 95 }
64 96
65 @Test 97 @Test
66 void alwaysFalseTest() { 98 void alwaysFalseTest() {
67 var p = Variable.of("p");
68 var q = Variable.of("q");
69 var friend = new Symbol<>("friend", 2, Boolean.class, false);
70 var friendView = new KeyOnlyRelationView<>(friend);
71
72 var actual = Dnf.builder() 99 var actual = Dnf.builder()
73 .parameters(p, q) 100 .parameters(p, q)
74 .clause(friendView.call(p, q), BooleanLiteral.FALSE) 101 .clause(friendView.call(p, q), BooleanLiteral.FALSE)
@@ -80,12 +107,6 @@ class DnfBuilderTest {
80 107
81 @Test 108 @Test
82 void eliminateTrueDnfTest() { 109 void eliminateTrueDnfTest() {
83 var p = Variable.of("p");
84 var q = Variable.of("q");
85 var friend = new Symbol<>("friend", 2, Boolean.class, false);
86 var friendView = new KeyOnlyRelationView<>(friend);
87 var trueDnf = Dnf.builder().parameter(p).clause().build();
88
89 var actual = Dnf.builder() 110 var actual = Dnf.builder()
90 .parameters(p, q) 111 .parameters(p, q)
91 .clause(trueDnf.call(q), friendView.call(p, q)) 112 .clause(trueDnf.call(q), friendView.call(p, q))
@@ -97,12 +118,6 @@ class DnfBuilderTest {
97 118
98 @Test 119 @Test
99 void eliminateFalseDnfTest() { 120 void eliminateFalseDnfTest() {
100 var p = Variable.of("p");
101 var q = Variable.of("q");
102 var friend = new Symbol<>("friend", 2, Boolean.class, false);
103 var friendView = new KeyOnlyRelationView<>(friend);
104 var falseDnf = Dnf.builder().parameter(p).build();
105
106 var actual = Dnf.builder() 121 var actual = Dnf.builder()
107 .parameters(p, q) 122 .parameters(p, q)
108 .clause(friendView.call(p, q)) 123 .clause(friendView.call(p, q))
@@ -115,30 +130,18 @@ class DnfBuilderTest {
115 130
116 @Test 131 @Test
117 void alwaysTrueDnfTest() { 132 void alwaysTrueDnfTest() {
118 var p = Variable.of("p");
119 var q = Variable.of("q");
120 var friend = new Symbol<>("friend", 2, Boolean.class, false);
121 var friendView = new KeyOnlyRelationView<>(friend);
122 var trueDnf = Dnf.builder().parameter(p).clause().build();
123
124 var actual = Dnf.builder() 133 var actual = Dnf.builder()
125 .parameters(p, q) 134 .parameters(List.of(p, q), ParameterDirection.IN)
126 .clause(friendView.call(p, q)) 135 .clause(friendView.call(p, q))
127 .clause(trueDnf.call(q)) 136 .clause(trueDnf.call(q))
128 .build(); 137 .build();
129 var expected = Dnf.builder().parameters(p, q).clause().build(); 138 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
130 139
131 assertThat(actual, structurallyEqualTo(expected)); 140 assertThat(actual, structurallyEqualTo(expected));
132 } 141 }
133 142
134 @Test 143 @Test
135 void alwaysFalseDnfTest() { 144 void alwaysFalseDnfTest() {
136 var p = Variable.of("p");
137 var q = Variable.of("q");
138 var friend = new Symbol<>("friend", 2, Boolean.class, false);
139 var friendView = new KeyOnlyRelationView<>(friend);
140 var falseDnf = Dnf.builder().parameter(p).build();
141
142 var actual = Dnf.builder() 145 var actual = Dnf.builder()
143 .parameters(p, q) 146 .parameters(p, q)
144 .clause(friendView.call(p, q), falseDnf.call(q)) 147 .clause(friendView.call(p, q), falseDnf.call(q))
@@ -150,12 +153,6 @@ class DnfBuilderTest {
150 153
151 @Test 154 @Test
152 void eliminateNotFalseDnfTest() { 155 void eliminateNotFalseDnfTest() {
153 var p = Variable.of("p");
154 var q = Variable.of("q");
155 var friend = new Symbol<>("friend", 2, Boolean.class, false);
156 var friendView = new KeyOnlyRelationView<>(friend);
157 var falseDnf = Dnf.builder().parameter(p).build();
158
159 var actual = Dnf.builder() 156 var actual = Dnf.builder()
160 .parameters(p, q) 157 .parameters(p, q)
161 .clause(not(falseDnf.call(q)), friendView.call(p, q)) 158 .clause(not(falseDnf.call(q)), friendView.call(p, q))
@@ -167,12 +164,6 @@ class DnfBuilderTest {
167 164
168 @Test 165 @Test
169 void eliminateNotTrueDnfTest() { 166 void eliminateNotTrueDnfTest() {
170 var p = Variable.of("p");
171 var q = Variable.of("q");
172 var friend = new Symbol<>("friend", 2, Boolean.class, false);
173 var friendView = new KeyOnlyRelationView<>(friend);
174 var trueDnf = Dnf.builder().parameter(p).clause().build();
175
176 var actual = Dnf.builder() 167 var actual = Dnf.builder()
177 .parameters(p, q) 168 .parameters(p, q)
178 .clause(friendView.call(p, q)) 169 .clause(friendView.call(p, q))
@@ -185,30 +176,18 @@ class DnfBuilderTest {
185 176
186 @Test 177 @Test
187 void alwaysNotFalseDnfTest() { 178 void alwaysNotFalseDnfTest() {
188 var p = Variable.of("p");
189 var q = Variable.of("q");
190 var friend = new Symbol<>("friend", 2, Boolean.class, false);
191 var friendView = new KeyOnlyRelationView<>(friend);
192 var falseDnf = Dnf.builder().parameter(p).build();
193
194 var actual = Dnf.builder() 179 var actual = Dnf.builder()
195 .parameters(p, q) 180 .parameters(List.of(p, q), ParameterDirection.IN)
196 .clause(friendView.call(p, q)) 181 .clause(friendView.call(p, q))
197 .clause(not(falseDnf.call(q))) 182 .clause(not(falseDnf.call(q)))
198 .build(); 183 .build();
199 var expected = Dnf.builder().parameters(p, q).clause().build(); 184 var expected = Dnf.builder().parameters(List.of(p, q), ParameterDirection.IN).clause().build();
200 185
201 assertThat(actual, structurallyEqualTo(expected)); 186 assertThat(actual, structurallyEqualTo(expected));
202 } 187 }
203 188
204 @Test 189 @Test
205 void alwaysNotTrueDnfTest() { 190 void alwaysNotTrueDnfTest() {
206 var p = Variable.of("p");
207 var q = Variable.of("q");
208 var friend = new Symbol<>("friend", 2, Boolean.class, false);
209 var friendView = new KeyOnlyRelationView<>(friend);
210 var trueDnf = Dnf.builder().parameter(p).clause().build();
211
212 var actual = Dnf.builder() 191 var actual = Dnf.builder()
213 .parameters(p, q) 192 .parameters(p, q)
214 .clause(friendView.call(p, q), not(trueDnf.call(q))) 193 .clause(friendView.call(p, q), not(trueDnf.call(q)))
@@ -217,4 +196,15 @@ class DnfBuilderTest {
217 196
218 assertThat(actual, structurallyEqualTo(expected)); 197 assertThat(actual, structurallyEqualTo(expected));
219 } 198 }
199
200 @Test
201 void removeDuplicateTest() {
202 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
203 friendView.call(p, q),
204 friendView.call(p, q)
205 )));
206 var expected = Dnf.of(builder -> builder.clause((p, q) -> List.of(friendView.call(p, q))));
207
208 assertThat(actual, structurallyEqualTo(expected));
209 }
220} 210}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java
new file mode 100644
index 00000000..fc40c7b3
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfBuilderVariableUnificationTest.java
@@ -0,0 +1,325 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.term.ParameterDirection;
10import tools.refinery.store.query.term.Variable;
11import tools.refinery.store.query.view.KeyOnlyView;
12import tools.refinery.store.query.view.SymbolView;
13import tools.refinery.store.representation.Symbol;
14
15import java.util.List;
16
17import static org.hamcrest.MatcherAssert.assertThat;
18import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
19
20class DnfBuilderVariableUnificationTest {
21 private final Symbol<Boolean> friend = Symbol.of("friend", 2);
22 private final Symbol<Boolean> children = Symbol.of("children", 2);
23 private final SymbolView<Boolean> friendView = new KeyOnlyView<>(friend);
24 private final SymbolView<Boolean> childrenView = new KeyOnlyView<>(children);
25
26 @Test
27 void equalToParameterTest() {
28 var actual = Dnf.of(builder -> {
29 var p = builder.parameter("p");
30 builder.clause(q -> List.of(
31 friendView.call(p, q),
32 p.isEquivalent(q)
33 ));
34 });
35
36 var expectedP = Variable.of("p");
37 assertThat(actual, structurallyEqualTo(
38 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
39 List.of(
40 List.of(friendView.call(expectedP, expectedP))
41 )
42 ));
43 }
44
45 @Test
46 void equalToParameterReverseTest() {
47 var actual = Dnf.of(builder -> {
48 var p = builder.parameter("p");
49 builder.clause(q -> List.of(
50 friendView.call(p, q),
51 q.isEquivalent(p)
52 ));
53 });
54
55 var expectedP = Variable.of("p");
56 assertThat(actual, structurallyEqualTo(
57 List.of(new SymbolicParameter(expectedP, ParameterDirection.OUT)),
58 List.of(
59 List.of(friendView.call(expectedP, expectedP))
60 )
61 ));
62 }
63
64 @Test
65 void equalQuantifiedTest() {
66 var actual = Dnf.of(builder -> builder.clause((p, q) -> List.of(
67 friendView.call(p, q),
68 p.isEquivalent(q)
69 )));
70
71 var expectedP = Variable.of("p");
72 assertThat(actual, structurallyEqualTo(
73 List.of(),
74 List.of(
75 List.of(friendView.call(expectedP, expectedP))
76 )
77 ));
78 }
79
80 @Test
81 void equalQuantifiedTransitiveTest() {
82 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
83 friendView.call(p, q),
84 p.isEquivalent(q),
85 childrenView.call(p, r),
86 q.isEquivalent(r)
87 )));
88
89 var expectedP = Variable.of("p");
90 assertThat(actual, structurallyEqualTo(
91 List.of(),
92 List.of(
93 List.of(friendView.call(expectedP, expectedP), childrenView.call(expectedP, expectedP))
94 )
95 ));
96 }
97
98 @Test
99 void equalQuantifiedTransitiveRemoveDuplicateTest() {
100 var actual = Dnf.of(builder -> builder.clause((p, q, r) -> List.of(
101 friendView.call(p, q),
102 p.isEquivalent(q),
103 friendView.call(p, r),
104 q.isEquivalent(r)
105 )));
106
107 var expectedP = Variable.of("p");
108 assertThat(actual, structurallyEqualTo(
109 List.of(),
110 List.of(
111 List.of(friendView.call(expectedP, expectedP))
112 )
113 ));
114 }
115
116 @Test
117 void parametersEqualTest() {
118 var actual = Dnf.of(builder -> {
119 var p = builder.parameter("p");
120 var q = builder.parameter("q");
121 builder.clause(
122 friendView.call(p, q),
123 p.isEquivalent(q)
124 );
125 });
126
127 var expectedP = Variable.of("p");
128 var expectedQ = Variable.of("q");
129 assertThat(actual, structurallyEqualTo(
130 List.of(
131 new SymbolicParameter(expectedP, ParameterDirection.OUT),
132 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
133 ),
134 List.of(
135 List.of(friendView.call(expectedP, expectedP), expectedQ.isEquivalent(expectedP))
136 )
137 ));
138 }
139
140 @Test
141 void parametersEqualTransitiveTest() {
142 var actual = Dnf.of(builder -> {
143 var p = builder.parameter("p");
144 var q = builder.parameter("q");
145 var r = builder.parameter("r");
146 builder.clause(
147 friendView.call(p, q),
148 childrenView.call(p, r),
149 p.isEquivalent(q),
150 r.isEquivalent(q)
151 );
152 });
153
154 var expectedP = Variable.of("p");
155 var expectedQ = Variable.of("q");
156 var expectedR = Variable.of("r");
157 assertThat(actual, structurallyEqualTo(
158 List.of(
159 new SymbolicParameter(expectedP, ParameterDirection.OUT),
160 new SymbolicParameter(expectedQ, ParameterDirection.OUT),
161 new SymbolicParameter(expectedR, ParameterDirection.OUT)
162 ),
163 List.of(
164 List.of(
165 friendView.call(expectedP, expectedP),
166 expectedQ.isEquivalent(expectedP),
167 expectedR.isEquivalent(expectedP),
168 childrenView.call(expectedP, expectedP)
169 )
170 )
171 ));
172 }
173
174 @Test
175 void parameterAndQuantifiedEqualsTest() {
176 var actual = Dnf.of(builder -> {
177 var p = builder.parameter("p");
178 var q = builder.parameter("q");
179 builder.clause((r) -> List.of(
180 friendView.call(p, r),
181 p.isEquivalent(r),
182 childrenView.call(q, r),
183 q.isEquivalent(r)
184 ));
185 });
186
187
188 var expectedP = Variable.of("p");
189 var expectedQ = Variable.of("q");
190 assertThat(actual, structurallyEqualTo(
191 List.of(
192 new SymbolicParameter(expectedP, ParameterDirection.OUT),
193 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
194 ),
195 List.of(
196 List.of(
197 friendView.call(expectedP, expectedP),
198 expectedQ.isEquivalent(expectedP),
199 childrenView.call(expectedP, expectedP)
200 )
201 )
202 ));
203 }
204
205 @Test
206 void parameterAndQuantifiedEqualsReverseFirstTest() {
207 var actual = Dnf.of(builder -> {
208 var p = builder.parameter("p");
209 var q = builder.parameter("q");
210 builder.clause((r) -> List.of(
211 friendView.call(p, r),
212 r.isEquivalent(p),
213 childrenView.call(q, r),
214 q.isEquivalent(r)
215 ));
216 });
217
218 var expectedP = Variable.of("p");
219 var expectedQ = Variable.of("q");
220 assertThat(actual, structurallyEqualTo(
221 List.of(
222 new SymbolicParameter(expectedP, ParameterDirection.OUT),
223 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
224 ),
225 List.of(
226 List.of(
227 friendView.call(expectedP, expectedP),
228 expectedQ.isEquivalent(expectedP),
229 childrenView.call(expectedP, expectedP)
230 )
231 )
232 ));
233 }
234
235 @Test
236 void parameterAndQuantifiedEqualsReverseSecondTest() {
237 var actual = Dnf.of(builder -> {
238 var p = builder.parameter("p");
239 var q = builder.parameter("q");
240 builder.clause((r) -> List.of(
241 friendView.call(p, r),
242 p.isEquivalent(r),
243 childrenView.call(q, r),
244 r.isEquivalent(q)
245 ));
246 });
247
248 var expectedP = Variable.of("p");
249 var expectedQ = Variable.of("q");
250 assertThat(actual, structurallyEqualTo(
251 List.of(
252 new SymbolicParameter(expectedP, ParameterDirection.OUT),
253 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
254 ),
255 List.of(
256 List.of(
257 friendView.call(expectedP, expectedP),
258 expectedQ.isEquivalent(expectedP),
259 childrenView.call(expectedP, expectedP)
260 )
261 )
262 ));
263 }
264
265 @Test
266 void parameterAndQuantifiedEqualsReverseBoth() {
267 var actual = Dnf.of(builder -> {
268 var p = builder.parameter("p");
269 var q = builder.parameter("q");
270 builder.clause((r) -> List.of(
271 friendView.call(p, r),
272 p.isEquivalent(r),
273 childrenView.call(q, r),
274 r.isEquivalent(q)
275 ));
276 });
277
278 var expectedP = Variable.of("p");
279 var expectedQ = Variable.of("q");
280 assertThat(actual, structurallyEqualTo(
281 List.of(
282 new SymbolicParameter(expectedP, ParameterDirection.OUT),
283 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
284 ),
285 List.of(
286 List.of(
287 friendView.call(expectedP, expectedP),
288 expectedQ.isEquivalent(expectedP),
289 childrenView.call(expectedP, expectedP)
290 )
291 )
292 ));
293 }
294
295 @Test
296 void parameterAndTwoQuantifiedEqualsTest() {
297 var actual = Dnf.of(builder -> {
298 var p = builder.parameter("p");
299 var q = builder.parameter("q");
300 builder.clause((r, s) -> List.of(
301 r.isEquivalent(s),
302 friendView.call(p, r),
303 p.isEquivalent(r),
304 childrenView.call(q, s),
305 q.isEquivalent(s)
306 ));
307 });
308
309 var expectedP = Variable.of("p");
310 var expectedQ = Variable.of("q");
311 assertThat(actual, structurallyEqualTo(
312 List.of(
313 new SymbolicParameter(expectedP, ParameterDirection.OUT),
314 new SymbolicParameter(expectedQ, ParameterDirection.OUT)
315 ),
316 List.of(
317 List.of(
318 friendView.call(expectedP, expectedP),
319 expectedQ.isEquivalent(expectedP),
320 childrenView.call(expectedP, expectedP)
321 )
322 )
323 ));
324 }
325}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java
index 9b469bb0..d75d7f17 100644
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/DnfToDefinitionStringTest.java
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/DnfToDefinitionStringTest.java
@@ -1,9 +1,16 @@
1package tools.refinery.store.query; 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
4import tools.refinery.store.query.dnf.Dnf; 9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.ParameterDirection;
5import tools.refinery.store.query.term.Variable; 11import tools.refinery.store.query.term.Variable;
6import tools.refinery.store.query.view.KeyOnlyRelationView; 12import tools.refinery.store.query.view.AnySymbolView;
13import tools.refinery.store.query.view.KeyOnlyView;
7import tools.refinery.store.representation.Symbol; 14import tools.refinery.store.representation.Symbol;
8 15
9import static org.hamcrest.MatcherAssert.assertThat; 16import static org.hamcrest.MatcherAssert.assertThat;
@@ -11,9 +18,15 @@ import static org.hamcrest.Matchers.is;
11import static tools.refinery.store.query.literal.Literals.not; 18import static tools.refinery.store.query.literal.Literals.not;
12 19
13class DnfToDefinitionStringTest { 20class DnfToDefinitionStringTest {
21 private static final Symbol<Boolean> person = Symbol.of("person", 1);
22 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
23 private static final AnySymbolView personView = new KeyOnlyView<>(person);
24 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
25 private static final NodeVariable p = Variable.of("p");
26 private static final NodeVariable q = Variable.of("q");
27
14 @Test 28 @Test
15 void noClausesTest() { 29 void noClausesTest() {
16 var p = Variable.of("p");
17 var dnf = Dnf.builder("Example").parameter(p).build(); 30 var dnf = Dnf.builder("Example").parameter(p).build();
18 31
19 assertThat(dnf.toDefinitionString(), is(""" 32 assertThat(dnf.toDefinitionString(), is("""
@@ -34,21 +47,16 @@ class DnfToDefinitionStringTest {
34 47
35 @Test 48 @Test
36 void emptyClauseTest() { 49 void emptyClauseTest() {
37 var p = Variable.of("p"); 50 var dnf = Dnf.builder("Example").parameter(p, ParameterDirection.IN).clause().build();
38 var dnf = Dnf.builder("Example").parameter(p).clause().build();
39 51
40 assertThat(dnf.toDefinitionString(), is(""" 52 assertThat(dnf.toDefinitionString(), is("""
41 pred Example(p) <-> 53 pred Example(@In p) <->
42 <empty>. 54 <empty>.
43 """)); 55 """));
44 } 56 }
45 57
46 @Test 58 @Test
47 void relationViewPositiveTest() { 59 void relationViewPositiveTest() {
48 var p = Variable.of("p");
49 var q = Variable.of("q");
50 var friend = new Symbol<>("friend", 2, Boolean.class, false);
51 var friendView = new KeyOnlyRelationView<>(friend);
52 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build(); 60 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.call(p, q)).build();
53 61
54 assertThat(dnf.toDefinitionString(), is(""" 62 assertThat(dnf.toDefinitionString(), is("""
@@ -59,24 +67,19 @@ class DnfToDefinitionStringTest {
59 67
60 @Test 68 @Test
61 void relationViewNegativeTest() { 69 void relationViewNegativeTest() {
62 var p = Variable.of("p"); 70 var dnf = Dnf.builder("Example")
63 var q = Variable.of("q"); 71 .parameter(p, ParameterDirection.IN)
64 var friend = new Symbol<>("friend", 2, Boolean.class, false); 72 .clause(not(friendView.call(p, q)))
65 var friendView = new KeyOnlyRelationView<>(friend); 73 .build();
66 var dnf = Dnf.builder("Example").parameter(p).clause(not(friendView.call(p, q))).build();
67 74
68 assertThat(dnf.toDefinitionString(), is(""" 75 assertThat(dnf.toDefinitionString(), is("""
69 pred Example(p) <-> 76 pred Example(@In p) <->
70 !(@RelationView("key") friend(p, q)). 77 !(@RelationView("key") friend(p, q)).
71 """)); 78 """));
72 } 79 }
73 80
74 @Test 81 @Test
75 void relationViewTransitiveTest() { 82 void relationViewTransitiveTest() {
76 var p = Variable.of("p");
77 var q = Variable.of("q");
78 var friend = new Symbol<>("friend", 2, Boolean.class, false);
79 var friendView = new KeyOnlyRelationView<>(friend);
80 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build(); 83 var dnf = Dnf.builder("Example").parameter(p).clause(friendView.callTransitive(p, q)).build();
81 84
82 assertThat(dnf.toDefinitionString(), is(""" 85 assertThat(dnf.toDefinitionString(), is("""
@@ -87,10 +90,6 @@ class DnfToDefinitionStringTest {
87 90
88 @Test 91 @Test
89 void multipleParametersTest() { 92 void multipleParametersTest() {
90 var p = Variable.of("p");
91 var q = Variable.of("q");
92 var friend = new Symbol<>("friend", 2, Boolean.class, false);
93 var friendView = new KeyOnlyRelationView<>(friend);
94 var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build(); 93 var dnf = Dnf.builder("Example").parameters(p, q).clause(friendView.call(p, q)).build();
95 94
96 assertThat(dnf.toDefinitionString(), is(""" 95 assertThat(dnf.toDefinitionString(), is("""
@@ -101,12 +100,6 @@ class DnfToDefinitionStringTest {
101 100
102 @Test 101 @Test
103 void multipleLiteralsTest() { 102 void multipleLiteralsTest() {
104 var p = Variable.of("p");
105 var q = Variable.of("q");
106 var person = new Symbol<>("person", 1, Boolean.class, false);
107 var personView = new KeyOnlyRelationView<>(person);
108 var friend = new Symbol<>("friend", 2, Boolean.class, false);
109 var friendView = new KeyOnlyRelationView<>(friend);
110 var dnf = Dnf.builder("Example") 103 var dnf = Dnf.builder("Example")
111 .parameter(p) 104 .parameter(p)
112 .clause( 105 .clause(
@@ -126,10 +119,6 @@ class DnfToDefinitionStringTest {
126 119
127 @Test 120 @Test
128 void multipleClausesTest() { 121 void multipleClausesTest() {
129 var p = Variable.of("p");
130 var q = Variable.of("q");
131 var friend = new Symbol<>("friend", 2, Boolean.class, false);
132 var friendView = new KeyOnlyRelationView<>(friend);
133 var dnf = Dnf.builder("Example") 122 var dnf = Dnf.builder("Example")
134 .parameter(p) 123 .parameter(p)
135 .clause(friendView.call(p, q)) 124 .clause(friendView.call(p, q))
@@ -146,14 +135,8 @@ class DnfToDefinitionStringTest {
146 135
147 @Test 136 @Test
148 void dnfTest() { 137 void dnfTest() {
149 var p = Variable.of("p");
150 var q = Variable.of("q");
151 var r = Variable.of("r"); 138 var r = Variable.of("r");
152 var s = Variable.of("s"); 139 var s = Variable.of("s");
153 var person = new Symbol<>("person", 1, Boolean.class, false);
154 var personView = new KeyOnlyRelationView<>(person);
155 var friend = new Symbol<>("friend", 2, Boolean.class, false);
156 var friendView = new KeyOnlyRelationView<>(friend);
157 var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build(); 140 var called = Dnf.builder("Called").parameters(r, s).clause(friendView.call(r, s)).build();
158 var dnf = Dnf.builder("Example") 141 var dnf = Dnf.builder("Example")
159 .parameter(p) 142 .parameter(p)
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java
new file mode 100644
index 00000000..e22dbb21
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/TopologicalSortTest.java
@@ -0,0 +1,112 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.term.NodeVariable;
10import tools.refinery.store.query.term.ParameterDirection;
11import tools.refinery.store.query.term.Variable;
12import tools.refinery.store.query.view.AnySymbolView;
13import tools.refinery.store.query.view.KeyOnlyView;
14import tools.refinery.store.representation.Symbol;
15
16import java.util.List;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.junit.jupiter.api.Assertions.assertThrows;
20import static tools.refinery.store.query.literal.Literals.not;
21import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
22
23class TopologicalSortTest {
24 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
25 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
26 private static final Dnf example = Dnf.of("example", builder -> {
27 var a = builder.parameter("a", ParameterDirection.IN);
28 var b = builder.parameter("b", ParameterDirection.IN);
29 var c = builder.parameter("c", ParameterDirection.OUT);
30 var d = builder.parameter("d", ParameterDirection.OUT);
31 builder.clause(
32 friendView.call(a, b),
33 friendView.call(b, c),
34 friendView.call(c, d)
35 );
36 });
37 private static final NodeVariable p = Variable.of("p");
38 private static final NodeVariable q = Variable.of("q");
39 private static final NodeVariable r = Variable.of("r");
40 private static final NodeVariable s = Variable.of("s");
41 private static final NodeVariable t = Variable.of("t");
42
43 @Test
44 void topologicalSortTest() {
45 var actual = Dnf.builder("Actual")
46 .parameter(p, ParameterDirection.IN)
47 .parameter(q, ParameterDirection.OUT)
48 .clause(
49 not(friendView.call(p, q)),
50 example.call(p, q, r, s),
51 example.call(r, t, q, s),
52 friendView.call(r, t)
53 )
54 .build();
55
56 assertThat(actual, structurallyEqualTo(
57 List.of(
58 new SymbolicParameter(p, ParameterDirection.IN),
59 new SymbolicParameter(q, ParameterDirection.OUT)
60 ),
61 List.of(
62 List.of(
63 friendView.call(r, t),
64 example.call(r, t, q, s),
65 not(friendView.call(p, q)),
66 example.call(p, q, r, s)
67 )
68 )
69 ));
70 }
71
72 @Test
73 void missingInputTest() {
74 var builder = Dnf.builder("Actual")
75 .parameter(p, ParameterDirection.OUT)
76 .parameter(q, ParameterDirection.OUT)
77 .clause(
78 not(friendView.call(p, q)),
79 example.call(p, q, r, s),
80 example.call(r, t, q, s),
81 friendView.call(r, t)
82 );
83 assertThrows(IllegalArgumentException.class, builder::build);
84 }
85
86 @Test
87 void missingVariableTest() {
88 var builder = Dnf.builder("Actual")
89 .parameter(p, ParameterDirection.IN)
90 .parameter(q, ParameterDirection.OUT)
91 .clause(
92 not(friendView.call(p, q)),
93 example.call(p, q, r, s),
94 example.call(r, t, q, s)
95 );
96 assertThrows(IllegalArgumentException.class, builder::build);
97 }
98
99 @Test
100 void circularDependencyTest() {
101 var builder = Dnf.builder("Actual")
102 .parameter(p, ParameterDirection.IN)
103 .parameter(q, ParameterDirection.OUT)
104 .clause(
105 not(friendView.call(p, q)),
106 example.call(p, q, r, s),
107 example.call(r, t, q, s),
108 example.call(p, q, r, t)
109 );
110 assertThrows(IllegalArgumentException.class, builder::build);
111 }
112}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java
new file mode 100644
index 00000000..c52d26b2
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/dnf/VariableDirectionTest.java
@@ -0,0 +1,428 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.dnf;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.query.literal.BooleanLiteral;
12import tools.refinery.store.query.literal.Literal;
13import tools.refinery.store.query.term.DataVariable;
14import tools.refinery.store.query.term.NodeVariable;
15import tools.refinery.store.query.term.ParameterDirection;
16import tools.refinery.store.query.term.Variable;
17import tools.refinery.store.query.view.AnySymbolView;
18import tools.refinery.store.query.view.FunctionView;
19import tools.refinery.store.query.view.KeyOnlyView;
20import tools.refinery.store.representation.Symbol;
21
22import java.util.ArrayList;
23import java.util.List;
24import java.util.stream.Stream;
25
26import static org.hamcrest.MatcherAssert.assertThat;
27import static org.hamcrest.Matchers.hasItem;
28import static org.hamcrest.Matchers.not;
29import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
30import static org.junit.jupiter.api.Assertions.assertThrows;
31import static tools.refinery.store.query.literal.Literals.assume;
32import static tools.refinery.store.query.literal.Literals.not;
33import static tools.refinery.store.query.term.int_.IntTerms.*;
34
35class VariableDirectionTest {
36 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
37 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
38 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
39 private static final AnySymbolView personView = new KeyOnlyView<>(person);
40 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
41 private static final FunctionView<Integer> ageView = new FunctionView<>(age);
42 private static final NodeVariable p = Variable.of("p");
43 private static final NodeVariable q = Variable.of("q");
44 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
45 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
46 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
47
48 @ParameterizedTest
49 @MethodSource("clausesWithVariableInput")
50 void unboundOutVariableTest(List<? extends Literal> clause) {
51 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(clause);
52 assertThrows(IllegalArgumentException.class, builder::build);
53 }
54
55 @ParameterizedTest
56 @MethodSource("clausesWithVariableInput")
57 void unboundInVariableTest(List<? extends Literal> clause) {
58 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(clause);
59 var dnf = assertDoesNotThrow(builder::build);
60 var clauses = dnf.getClauses();
61 if (clauses.size() > 0) {
62 assertThat(clauses.get(0).positiveVariables(), hasItem(p));
63 }
64 }
65
66 @ParameterizedTest
67 @MethodSource("clausesWithVariableInput")
68 void boundPrivateVariableTest(List<? extends Literal> clause) {
69 var clauseWithBinding = new ArrayList<Literal>(clause);
70 clauseWithBinding.add(personView.call(p));
71 var builder = Dnf.builder().clause(clauseWithBinding);
72 var dnf = assertDoesNotThrow(builder::build);
73 var clauses = dnf.getClauses();
74 if (clauses.size() > 0) {
75 assertThat(clauses.get(0).positiveVariables(), hasItem(p));
76 }
77 }
78
79 static Stream<Arguments> clausesWithVariableInput() {
80 return Stream.concat(
81 clausesNotBindingVariable(),
82 literalToClauseArgumentStream(literalsWithRequiredVariableInput())
83 );
84 }
85
86 @ParameterizedTest
87 @MethodSource("clausesNotBindingVariable")
88 void unboundPrivateVariableTest(List<? extends Literal> clause) {
89 var builder = Dnf.builder().clause(clause);
90 var dnf = assertDoesNotThrow(builder::build);
91 var clauses = dnf.getClauses();
92 if (clauses.size() > 0) {
93 assertThat(clauses.get(0).positiveVariables(), not(hasItem(p)));
94 }
95 }
96
97 @ParameterizedTest
98 @MethodSource("clausesNotBindingVariable")
99 void unboundByEquivalencePrivateVariableTest(List<? extends Literal> clause) {
100 var r = Variable.of("r");
101 var clauseWithEquivalence = new ArrayList<Literal>(clause);
102 clauseWithEquivalence.add(r.isEquivalent(p));
103 var builder = Dnf.builder().clause(clauseWithEquivalence);
104 assertThrows(IllegalArgumentException.class, builder::build);
105 }
106
107 static Stream<Arguments> clausesNotBindingVariable() {
108 return Stream.concat(
109 Stream.of(
110 Arguments.of(List.of()),
111 Arguments.of(List.of(BooleanLiteral.TRUE)),
112 Arguments.of(List.of(BooleanLiteral.FALSE))
113 ),
114 literalToClauseArgumentStream(literalsWithPrivateVariable())
115 );
116 }
117
118 @ParameterizedTest
119 @MethodSource("literalsWithPrivateVariable")
120 void unboundTwicePrivateVariableTest(Literal literal) {
121 var builder = Dnf.builder().clause(not(personView.call(p)), literal);
122 assertThrows(IllegalArgumentException.class, builder::build);
123 }
124
125 @ParameterizedTest
126 @MethodSource("literalsWithPrivateVariable")
127 void unboundTwiceByEquivalencePrivateVariableTest(Literal literal) {
128 var r = Variable.of("r");
129 var builder = Dnf.builder().clause(not(personView.call(r)), r.isEquivalent(p), literal);
130 assertThrows(IllegalArgumentException.class, builder::build);
131 }
132
133 static Stream<Arguments> literalsWithPrivateVariable() {
134 var dnfWithOutput = Dnf.builder("WithOutput")
135 .parameter(p, ParameterDirection.OUT)
136 .parameter(q, ParameterDirection.OUT)
137 .clause(friendView.call(p, q))
138 .build();
139 var dnfWithOutputToAggregate = Dnf.builder("WithOutputToAggregate")
140 .parameter(p, ParameterDirection.OUT)
141 .parameter(q, ParameterDirection.OUT)
142 .parameter(x, ParameterDirection.OUT)
143 .clause(
144 friendView.call(p, q),
145 ageView.call(q, x)
146 )
147 .build();
148
149 return Stream.of(
150 Arguments.of(not(friendView.call(p, q))),
151 Arguments.of(y.assign(friendView.count(p, q))),
152 Arguments.of(y.assign(ageView.aggregate(INT_SUM, p))),
153 Arguments.of(not(dnfWithOutput.call(p, q))),
154 Arguments.of(y.assign(dnfWithOutput.count(p, q))),
155 Arguments.of(y.assign(dnfWithOutputToAggregate.aggregateBy(z, INT_SUM, p, q, z)))
156 );
157 }
158
159 @ParameterizedTest
160 @MethodSource("literalsWithRequiredVariableInput")
161 void unboundPrivateVariableTest(Literal literal) {
162 var builder = Dnf.builder().clause(literal);
163 assertThrows(IllegalArgumentException.class, builder::build);
164 }
165
166 @ParameterizedTest
167 @MethodSource("literalsWithRequiredVariableInput")
168 void boundPrivateVariableInputTest(Literal literal) {
169 var builder = Dnf.builder().clause(personView.call(p), literal);
170 var dnf = assertDoesNotThrow(builder::build);
171 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
172 }
173
174 static Stream<Arguments> literalsWithRequiredVariableInput() {
175 var dnfWithInput = Dnf.builder("WithInput")
176 .parameter(p, ParameterDirection.IN)
177 .parameter(q, ParameterDirection.OUT)
178 .clause(friendView.call(p, q)).build();
179 var dnfWithInputToAggregate = Dnf.builder("WithInputToAggregate")
180 .parameter(p, ParameterDirection.IN)
181 .parameter(q, ParameterDirection.OUT)
182 .parameter(x, ParameterDirection.OUT)
183 .clause(
184 friendView.call(p, q),
185 ageView.call(q, x)
186 ).build();
187
188 return Stream.of(
189 Arguments.of(dnfWithInput.call(p, q)),
190 Arguments.of(dnfWithInput.call(p, p)),
191 Arguments.of(not(dnfWithInput.call(p, q))),
192 Arguments.of(not(dnfWithInput.call(p, p))),
193 Arguments.of(y.assign(dnfWithInput.count(p, q))),
194 Arguments.of(y.assign(dnfWithInput.count(p, p))),
195 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, q, z))),
196 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, p, p, z)))
197 );
198 }
199
200 @ParameterizedTest
201 @MethodSource("literalsWithVariableOutput")
202 void boundParameterTest(Literal literal) {
203 var builder = Dnf.builder().parameter(p, ParameterDirection.OUT).clause(literal);
204 var dnf = assertDoesNotThrow(builder::build);
205 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
206 }
207
208 @ParameterizedTest
209 @MethodSource("literalsWithVariableOutput")
210 void boundTwiceParameterTest(Literal literal) {
211 var builder = Dnf.builder().parameter(p, ParameterDirection.IN).clause(literal);
212 var dnf = assertDoesNotThrow(builder::build);
213 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
214 }
215
216 @ParameterizedTest
217 @MethodSource("literalsWithVariableOutput")
218 void boundPrivateVariableOutputTest(Literal literal) {
219 var dnfWithInput = Dnf.builder("WithInput")
220 .parameter(p, ParameterDirection.IN)
221 .clause(personView.call(p))
222 .build();
223 var builder = Dnf.builder().clause(dnfWithInput.call(p), literal);
224 var dnf = assertDoesNotThrow(builder::build);
225 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
226 }
227
228 @ParameterizedTest
229 @MethodSource("literalsWithVariableOutput")
230 void boundTwicePrivateVariableOutputTest(Literal literal) {
231 var builder = Dnf.builder().clause(personView.call(p), literal);
232 var dnf = assertDoesNotThrow(builder::build);
233 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(p));
234 }
235
236 static Stream<Arguments> literalsWithVariableOutput() {
237 var dnfWithOutput = Dnf.builder("WithOutput")
238 .parameter(p, ParameterDirection.OUT)
239 .parameter(q, ParameterDirection.OUT)
240 .clause(friendView.call(p, q))
241 .build();
242
243 return Stream.of(
244 Arguments.of(friendView.call(p, q)),
245 Arguments.of(dnfWithOutput.call(p, q))
246 );
247 }
248
249 @ParameterizedTest
250 @MethodSource("clausesWithDataVariableInput")
251 void unboundOutDataVariableTest(List<? extends Literal> clause) {
252 var builder = Dnf.builder().parameter(x, ParameterDirection.OUT).clause(clause);
253 assertThrows(IllegalArgumentException.class, builder::build);
254 }
255
256 @ParameterizedTest
257 @MethodSource("clausesWithDataVariableInput")
258 void unboundInDataVariableTest(List<? extends Literal> clause) {
259 var builder = Dnf.builder().parameter(x, ParameterDirection.IN).clause(clause);
260 var dnf = assertDoesNotThrow(builder::build);
261 var clauses = dnf.getClauses();
262 if (clauses.size() > 0) {
263 assertThat(clauses.get(0).positiveVariables(), hasItem(x));
264 }
265 }
266
267 @ParameterizedTest
268 @MethodSource("clausesWithDataVariableInput")
269 void boundPrivateDataVariableTest(List<? extends Literal> clause) {
270 var clauseWithBinding = new ArrayList<Literal>(clause);
271 clauseWithBinding.add(x.assign(constant(27)));
272 var builder = Dnf.builder().clause(clauseWithBinding);
273 var dnf = assertDoesNotThrow(builder::build);
274 var clauses = dnf.getClauses();
275 if (clauses.size() > 0) {
276 assertThat(clauses.get(0).positiveVariables(), hasItem(x));
277 }
278 }
279
280 static Stream<Arguments> clausesWithDataVariableInput() {
281 return Stream.concat(
282 clausesNotBindingDataVariable(),
283 literalToClauseArgumentStream(literalsWithRequiredDataVariableInput())
284 );
285 }
286
287 @ParameterizedTest
288 @MethodSource("clausesNotBindingDataVariable")
289 void unboundPrivateDataVariableTest(List<? extends Literal> clause) {
290 var builder = Dnf.builder().clause(clause);
291 var dnf = assertDoesNotThrow(builder::build);
292 var clauses = dnf.getClauses();
293 if (clauses.size() > 0) {
294 assertThat(clauses.get(0).positiveVariables(), not(hasItem(x)));
295 }
296 }
297
298 static Stream<Arguments> clausesNotBindingDataVariable() {
299 return Stream.concat(
300 Stream.of(
301 Arguments.of(List.of()),
302 Arguments.of(List.of(BooleanLiteral.TRUE)),
303 Arguments.of(List.of(BooleanLiteral.FALSE))
304 ),
305 literalToClauseArgumentStream(literalsWithPrivateDataVariable())
306 );
307 }
308
309 @ParameterizedTest
310 @MethodSource("literalsWithPrivateDataVariable")
311 void unboundTwicePrivateDataVariableTest(Literal literal) {
312 var builder = Dnf.builder().clause(not(ageView.call(p, x)), literal);
313 assertThrows(IllegalArgumentException.class, builder::build);
314 }
315
316 static Stream<Arguments> literalsWithPrivateDataVariable() {
317 var dnfWithOutput = Dnf.builder("WithDataOutput")
318 .parameter(y, ParameterDirection.OUT)
319 .parameter(q, ParameterDirection.OUT)
320 .clause(ageView.call(q, y))
321 .build();
322
323 return Stream.of(
324 Arguments.of(not(ageView.call(q, x))),
325 Arguments.of(y.assign(ageView.count(q, x))),
326 Arguments.of(not(dnfWithOutput.call(x, q)))
327 );
328 }
329
330 @ParameterizedTest
331 @MethodSource("literalsWithRequiredDataVariableInput")
332 void unboundPrivateDataVariableTest(Literal literal) {
333 var builder = Dnf.builder().clause(literal);
334 assertThrows(IllegalArgumentException.class, builder::build);
335 }
336
337 static Stream<Arguments> literalsWithRequiredDataVariableInput() {
338 var dnfWithInput = Dnf.builder("WithDataInput")
339 .parameter(y, ParameterDirection.IN)
340 .parameter(q, ParameterDirection.OUT)
341 .clause(ageView.call(q, x))
342 .build();
343 // We are passing {@code y} to the parameter named {@code right} of {@code greaterEq}.
344 @SuppressWarnings("SuspiciousNameCombination")
345 var dnfWithInputToAggregate = Dnf.builder("WithDataInputToAggregate")
346 .parameter(y, ParameterDirection.IN)
347 .parameter(q, ParameterDirection.OUT)
348 .parameter(x, ParameterDirection.OUT)
349 .clause(
350 friendView.call(p, q),
351 ageView.call(q, x),
352 assume(greaterEq(x, y))
353 )
354 .build();
355
356 return Stream.of(
357 Arguments.of(dnfWithInput.call(x, q)),
358 Arguments.of(not(dnfWithInput.call(x, q))),
359 Arguments.of(y.assign(dnfWithInput.count(x, q))),
360 Arguments.of(y.assign(dnfWithInputToAggregate.aggregateBy(z, INT_SUM, x, q, z)))
361 );
362 }
363
364 @ParameterizedTest
365 @MethodSource("literalsWithDataVariableOutput")
366 void boundDataParameterTest(Literal literal) {
367 var builder = Dnf.builder().parameter(x, ParameterDirection.OUT).clause(literal);
368 var dnf = assertDoesNotThrow(builder::build);
369 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(x));
370 }
371
372 @ParameterizedTest
373 @MethodSource("literalsWithDataVariableOutput")
374 void boundTwiceDataParameterTest(Literal literal) {
375 var builder = Dnf.builder().parameter(x, ParameterDirection.IN).clause(literal);
376 assertThrows(IllegalArgumentException.class, builder::build);
377 }
378
379 @ParameterizedTest
380 @MethodSource("literalsWithDataVariableOutput")
381 void boundPrivateDataVariableOutputTest(Literal literal) {
382 var dnfWithInput = Dnf.builder("WithInput")
383 .parameter(x, ParameterDirection.IN)
384 .clause(assume(greaterEq(x, constant(24))))
385 .build();
386 var builder = Dnf.builder().clause(dnfWithInput.call(x), literal);
387 var dnf = assertDoesNotThrow(builder::build);
388 assertThat(dnf.getClauses().get(0).positiveVariables(), hasItem(x));
389 }
390
391 @ParameterizedTest
392 @MethodSource("literalsWithDataVariableOutput")
393 void boundTwicePrivateDataVariableOutputTest(Literal literal) {
394 var builder = Dnf.builder().clause(x.assign(constant(27)), literal);
395 assertThrows(IllegalArgumentException.class, builder::build);
396 }
397
398 static Stream<Arguments> literalsWithDataVariableOutput() {
399 var dnfWithOutput = Dnf.builder("WithOutput")
400 .parameter(q, ParameterDirection.OUT)
401 .clause(personView.call(q))
402 .build();
403 var dnfWithDataOutput = Dnf.builder("WithDataOutput")
404 .parameter(y, ParameterDirection.OUT)
405 .parameter(q, ParameterDirection.OUT)
406 .clause(ageView.call(q, y))
407 .build();
408 var dnfWithOutputToAggregate = Dnf.builder("WithDataOutputToAggregate")
409 .parameter(q, ParameterDirection.OUT)
410 .parameter(y, ParameterDirection.OUT)
411 .clause(ageView.call(q, y))
412 .build();
413
414 return Stream.of(
415 Arguments.of(x.assign(constant(24))),
416 Arguments.of(ageView.call(q, x)),
417 Arguments.of(x.assign(personView.count(q))),
418 Arguments.of(x.assign(ageView.aggregate(INT_SUM, q))),
419 Arguments.of(dnfWithDataOutput.call(x, q)),
420 Arguments.of(x.assign(dnfWithOutput.count(q))),
421 Arguments.of(x.assign(dnfWithOutputToAggregate.aggregateBy(z, INT_SUM, q, z)))
422 );
423 }
424
425 private static Stream<Arguments> literalToClauseArgumentStream(Stream<Arguments> literalArgumentsStream) {
426 return literalArgumentsStream.map(arguments -> Arguments.of(List.of(arguments.get()[0])));
427 }
428}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java
new file mode 100644
index 00000000..35910e08
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/AggregationLiteralTest.java
@@ -0,0 +1,88 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.term.*;
12
13import java.util.List;
14import java.util.Set;
15
16import static org.hamcrest.MatcherAssert.assertThat;
17import static org.hamcrest.Matchers.containsInAnyOrder;
18import static org.hamcrest.Matchers.empty;
19import static org.junit.jupiter.api.Assertions.assertAll;
20import static org.junit.jupiter.api.Assertions.assertThrows;
21import static tools.refinery.store.query.literal.Literals.not;
22import static tools.refinery.store.query.term.int_.IntTerms.INT_SUM;
23import static tools.refinery.store.query.term.int_.IntTerms.constant;
24
25class AggregationLiteralTest {
26 private static final NodeVariable p = Variable.of("p");
27 private static final DataVariable<Integer> x = Variable.of("x", Integer.class);
28 private static final DataVariable<Integer> y = Variable.of("y", Integer.class);
29 private static final DataVariable<Integer> z = Variable.of("z", Integer.class);
30 private static final Constraint fakeConstraint = new Constraint() {
31 @Override
32 public String name() {
33 return getClass().getName();
34 }
35
36 @Override
37 public List<Parameter> getParameters() {
38 return List.of(
39 new Parameter(null, ParameterDirection.OUT),
40 new Parameter(Integer.class, ParameterDirection.OUT)
41 );
42 }
43 };
44
45 @Test
46 void parameterDirectionTest() {
47 var literal = x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y));
48 assertAll(
49 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(x)),
50 () -> assertThat(literal.getInputVariables(Set.of()), empty()),
51 () -> assertThat(literal.getInputVariables(Set.of(p)), containsInAnyOrder(p)),
52 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(p, y)),
53 () -> assertThat(literal.getPrivateVariables(Set.of(p)), containsInAnyOrder(y))
54 );
55 }
56
57 @Test
58 void missingAggregationVariableTest() {
59 var aggregation = fakeConstraint.aggregateBy(y, INT_SUM, p, z);
60 assertThrows(IllegalArgumentException.class, () -> x.assign(aggregation));
61 }
62
63 @Test
64 void circularAggregationVariableTest() {
65 var aggregation = fakeConstraint.aggregateBy(x, INT_SUM, p, x);
66 assertThrows(IllegalArgumentException.class, () -> x.assign(aggregation));
67 }
68
69 @Test
70 void unboundTwiceVariableTest() {
71 var builder = Dnf.builder()
72 .clause(
73 not(fakeConstraint.call(p, y)),
74 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
75 );
76 assertThrows(IllegalArgumentException.class, builder::build);
77 }
78
79 @Test
80 void unboundBoundVariableTest() {
81 var builder = Dnf.builder()
82 .clause(
83 y.assign(constant(27)),
84 x.assign(fakeConstraint.aggregateBy(y, INT_SUM, p, y))
85 );
86 assertThrows(IllegalArgumentException.class, builder::build);
87 }
88}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java
new file mode 100644
index 00000000..a01c6586
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/literal/CallLiteralTest.java
@@ -0,0 +1,94 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.literal;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.Constraint;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.Parameter;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14
15import java.util.List;
16import java.util.Set;
17
18import static org.hamcrest.MatcherAssert.assertThat;
19import static org.hamcrest.Matchers.containsInAnyOrder;
20import static org.hamcrest.Matchers.empty;
21import static org.junit.jupiter.api.Assertions.assertAll;
22import static tools.refinery.store.query.literal.Literals.not;
23
24class CallLiteralTest {
25 private static final NodeVariable p = Variable.of("p");
26 private static final NodeVariable q = Variable.of("q");
27 private static final NodeVariable r = Variable.of("r");
28 private static final NodeVariable s = Variable.of("s");
29
30 private static final Constraint fakeConstraint = new Constraint() {
31 @Override
32 public String name() {
33 return getClass().getName();
34 }
35
36 @Override
37 public List<Parameter> getParameters() {
38 return List.of(
39 new Parameter(null, ParameterDirection.IN),
40 new Parameter(null, ParameterDirection.IN),
41 new Parameter(null, ParameterDirection.OUT),
42 new Parameter(null, ParameterDirection.OUT)
43 );
44 }
45 };
46
47 @Test
48 void notRepeatedPositiveDirectionTest() {
49 var literal = fakeConstraint.call(p, q, r, s);
50 assertAll(
51 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(r, s)),
52 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
53 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q)),
54 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
55 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), empty())
56 );
57 }
58
59 @Test
60 void notRepeatedNegativeDirectionTest() {
61 var literal = not(fakeConstraint.call(p, q, r, s));
62 assertAll(
63 () -> assertThat(literal.getOutputVariables(), empty()),
64 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p, q)),
65 () -> assertThat(literal.getInputVariables(Set.of(p, q, r)), containsInAnyOrder(p, q, r)),
66 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(r, s)),
67 () -> assertThat(literal.getPrivateVariables(Set.of(p, q, r)), containsInAnyOrder(s))
68 );
69 }
70
71 @Test
72 void repeatedPositiveDirectionTest() {
73 var literal = fakeConstraint.call(p, p, q, q);
74 assertAll(
75 () -> assertThat(literal.getOutputVariables(), containsInAnyOrder(q)),
76 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
77 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p)),
78 () -> assertThat(literal.getPrivateVariables(Set.of()), empty()),
79 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
80 );
81 }
82
83 @Test
84 void repeatedNegativeDirectionTest() {
85 var literal = not(fakeConstraint.call(p, p, q, q));
86 assertAll(
87 () -> assertThat(literal.getOutputVariables(), empty()),
88 () -> assertThat(literal.getInputVariables(Set.of()), containsInAnyOrder(p)),
89 () -> assertThat(literal.getInputVariables(Set.of(p, q)), containsInAnyOrder(p, q)),
90 () -> assertThat(literal.getPrivateVariables(Set.of()), containsInAnyOrder(q)),
91 () -> assertThat(literal.getPrivateVariables(Set.of(p, q)), empty())
92 );
93 }
94}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java
new file mode 100644
index 00000000..1cbc101a
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/TermSubstitutionTest.java
@@ -0,0 +1,97 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term;
7
8import org.junit.jupiter.api.Assertions;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.Arguments;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.store.query.dnf.Dnf;
13import tools.refinery.store.query.equality.LiteralEqualityHelper;
14import tools.refinery.store.query.substitution.Substitution;
15import tools.refinery.store.query.term.bool.BoolTerms;
16import tools.refinery.store.query.term.int_.IntTerms;
17import tools.refinery.store.query.term.real.RealTerms;
18import tools.refinery.store.query.term.uppercardinality.UpperCardinalityTerms;
19import tools.refinery.store.representation.cardinality.UpperCardinality;
20
21import java.util.List;
22import java.util.stream.Stream;
23
24class TermSubstitutionTest {
25 private final static DataVariable<Integer> intA = Variable.of("intA", Integer.class);
26 private final static DataVariable<Integer> intB = Variable.of("intB", Integer.class);
27 private final static DataVariable<Double> realA = Variable.of("realA", Double.class);
28 private final static DataVariable<Double> realB = Variable.of("realB", Double.class);
29 private final static DataVariable<Boolean> boolA = Variable.of("boolA", Boolean.class);
30 private final static DataVariable<Boolean> boolB = Variable.of("boolB", Boolean.class);
31 private final static DataVariable<UpperCardinality> upperCardinalityA = Variable.of("upperCardinalityA",
32 UpperCardinality.class);
33 private final static DataVariable<UpperCardinality> upperCardinalityB = Variable.of("upperCardinalityB",
34 UpperCardinality.class);
35 private final static Substitution substitution = Substitution.builder()
36 .put(intA, intB)
37 .put(intB, intA)
38 .put(realA, realB)
39 .put(realB, realA)
40 .put(boolA, boolB)
41 .put(boolB, boolA)
42 .put(upperCardinalityA, upperCardinalityB)
43 .put(upperCardinalityB, upperCardinalityA)
44 .build();
45
46 @ParameterizedTest
47 @MethodSource
48 void substitutionTest(AnyTerm term) {
49 var substitutedTerm1 = term.substitute(substitution);
50 Assertions.assertNotEquals(term, substitutedTerm1, "Original term is not equal to substituted term");
51 var helper = new LiteralEqualityHelper(Dnf::equals, List.of(), List.of());
52 Assertions.assertTrue(term.equalsWithSubstitution(helper, substitutedTerm1), "Terms are equal by helper");
53 // The {@link #substitution} is its own inverse.
54 var substitutedTerm2 = substitutedTerm1.substitute(substitution);
55 Assertions.assertEquals(term, substitutedTerm2, "Original term is not equal to back-substituted term");
56 }
57
58 static Stream<Arguments> substitutionTest() {
59 return Stream.of(
60 Arguments.of(IntTerms.plus(intA)),
61 Arguments.of(IntTerms.minus(intA)),
62 Arguments.of(IntTerms.add(intA, intB)),
63 Arguments.of(IntTerms.sub(intA, intB)),
64 Arguments.of(IntTerms.mul(intA, intB)),
65 Arguments.of(IntTerms.div(intA, intB)),
66 Arguments.of(IntTerms.pow(intA, intB)),
67 Arguments.of(IntTerms.min(intA, intB)),
68 Arguments.of(IntTerms.max(intA, intB)),
69 Arguments.of(IntTerms.eq(intA, intB)),
70 Arguments.of(IntTerms.notEq(intA, intB)),
71 Arguments.of(IntTerms.less(intA, intB)),
72 Arguments.of(IntTerms.lessEq(intA, intB)),
73 Arguments.of(IntTerms.greater(intA, intB)),
74 Arguments.of(IntTerms.greaterEq(intA, intB)),
75 Arguments.of(IntTerms.asInt(realA)),
76 Arguments.of(RealTerms.plus(realA)),
77 Arguments.of(RealTerms.minus(realA)),
78 Arguments.of(RealTerms.add(realA, realB)),
79 Arguments.of(RealTerms.sub(realA, realB)),
80 Arguments.of(RealTerms.mul(realA, realB)),
81 Arguments.of(RealTerms.div(realA, realB)),
82 Arguments.of(RealTerms.pow(realA, realB)),
83 Arguments.of(RealTerms.min(realA, realB)),
84 Arguments.of(RealTerms.max(realA, realB)),
85 Arguments.of(RealTerms.asReal(intA)),
86 Arguments.of(BoolTerms.not(boolA)),
87 Arguments.of(BoolTerms.and(boolA, boolB)),
88 Arguments.of(BoolTerms.or(boolA, boolB)),
89 Arguments.of(BoolTerms.xor(boolA, boolB)),
90 Arguments.of(RealTerms.eq(realA, realB)),
91 Arguments.of(UpperCardinalityTerms.add(upperCardinalityA, upperCardinalityB)),
92 Arguments.of(UpperCardinalityTerms.mul(upperCardinalityA, upperCardinalityB)),
93 Arguments.of(UpperCardinalityTerms.min(upperCardinalityA, upperCardinalityB)),
94 Arguments.of(UpperCardinalityTerms.max(upperCardinalityA, upperCardinalityB))
95 );
96 }
97}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java
new file mode 100644
index 00000000..beff705e
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/bool/BoolTermsEvaluateTest.java
@@ -0,0 +1,75 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.bool;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.CsvSource;
10import tools.refinery.store.query.valuation.Valuation;
11
12import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.is;
14
15class BoolTermsEvaluateTest {
16 @ParameterizedTest(name = "!{0} == {1}")
17 @CsvSource(value = {
18 "false, true",
19 "true, false",
20 "null, null"
21 }, nullValues = "null")
22 void notTest(Boolean a, Boolean result) {
23 var term = BoolTerms.not(BoolTerms.constant(a));
24 assertThat(term.getType(), is(Boolean.class));
25 assertThat(term.evaluate(Valuation.empty()), is(result));
26 }
27
28 @ParameterizedTest(name = "{0} && {1} == {2}")
29 @CsvSource(value = {
30 "false, false, false",
31 "false, true, false",
32 "true, false, false",
33 "true, true, true",
34 "false, null, null",
35 "null, false, null",
36 "null, null, null"
37 }, nullValues = "null")
38 void andTest(Boolean a, Boolean b, Boolean result) {
39 var term = BoolTerms.and(BoolTerms.constant(a), BoolTerms.constant(b));
40 assertThat(term.getType(), is(Boolean.class));
41 assertThat(term.evaluate(Valuation.empty()), is(result));
42 }
43
44 @ParameterizedTest(name = "{0} || {1} == {2}")
45 @CsvSource(value = {
46 "false, false, false",
47 "false, true, true",
48 "true, false, true",
49 "true, true, true",
50 "true, null, null",
51 "null, true, null",
52 "null, null, null"
53 }, nullValues = "null")
54 void orTest(Boolean a, Boolean b, Boolean result) {
55 var term = BoolTerms.or(BoolTerms.constant(a), BoolTerms.constant(b));
56 assertThat(term.getType(), is(Boolean.class));
57 assertThat(term.evaluate(Valuation.empty()), is(result));
58 }
59
60 @ParameterizedTest(name = "{0} ^^ {1} == {2}")
61 @CsvSource(value = {
62 "false, false, false",
63 "false, true, true",
64 "true, false, true",
65 "true, true, false",
66 "false, null, null",
67 "null, false, null",
68 "null, null, null"
69 }, nullValues = "null")
70 void xorTest(Boolean a, Boolean b, Boolean result) {
71 var term = BoolTerms.xor(BoolTerms.constant(a), BoolTerms.constant(b));
72 assertThat(term.getType(), is(Boolean.class));
73 assertThat(term.evaluate(Valuation.empty()), is(result));
74 }
75}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java
new file mode 100644
index 00000000..abe50d75
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/int_/IntTermsEvaluateTest.java
@@ -0,0 +1,259 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.int_;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.CsvSource;
11import org.junit.jupiter.params.provider.MethodSource;
12import tools.refinery.store.query.term.real.RealTerms;
13import tools.refinery.store.query.valuation.Valuation;
14
15import java.util.stream.Stream;
16
17import static org.hamcrest.Matchers.is;
18import static org.hamcrest.MatcherAssert.assertThat;
19
20class IntTermsEvaluateTest {
21 @ParameterizedTest(name = "+{0} == {1}")
22 @CsvSource(value = {
23 "2, 2",
24 "null, null"
25 }, nullValues = "null")
26 void plusTest(Integer a, Integer result) {
27 var term = IntTerms.plus(IntTerms.constant(a));
28 assertThat(term.getType(), is(Integer.class));
29 assertThat(term.evaluate(Valuation.empty()), is(result));
30 }
31
32 @ParameterizedTest(name = "-{0} == {1}")
33 @CsvSource(value = {
34 "2, -2",
35 "null, null"
36 }, nullValues = "null")
37 void minusTest(Integer a, Integer result) {
38 var term = IntTerms.minus(IntTerms.constant(a));
39 assertThat(term.getType(), is(Integer.class));
40 assertThat(term.evaluate(Valuation.empty()), is(result));
41 }
42
43 @ParameterizedTest(name = "{0} + {1} == {2}")
44 @CsvSource(value = {
45 "1, 2, 3",
46 "null, 2, null",
47 "1, null, null",
48 "null, null, null"
49 }, nullValues = "null")
50 void addTest(Integer a, Integer b, Integer result) {
51 var term = IntTerms.add(IntTerms.constant(a), IntTerms.constant(b));
52 assertThat(term.getType(), is(Integer.class));
53 assertThat(term.evaluate(Valuation.empty()), is(result));
54 }
55
56 @ParameterizedTest(name = "{0} - {1} == {2}")
57 @CsvSource(value = {
58 "1, 3, -2",
59 "null, 3, null",
60 "1, null, null",
61 "null, null, null"
62 }, nullValues = "null")
63 void subTest(Integer a, Integer b, Integer result) {
64 var term = IntTerms.sub(IntTerms.constant(a), IntTerms.constant(b));
65 assertThat(term.getType(), is(Integer.class));
66 assertThat(term.evaluate(Valuation.empty()), is(result));
67 }
68
69 @ParameterizedTest(name = "{0} * {1} == {2}")
70 @CsvSource(value = {
71 "2, 3, 6",
72 "null, 3, null",
73 "2, null, null",
74 "null, null, null"
75 }, nullValues = "null")
76 void mulTest(Integer a, Integer b, Integer result) {
77 var term = IntTerms.mul(IntTerms.constant(a), IntTerms.constant(b));
78 assertThat(term.getType(), is(Integer.class));
79 assertThat(term.evaluate(Valuation.empty()), is(result));
80 }
81
82 @ParameterizedTest(name = "{0} * {1} == {2}")
83 @CsvSource(value = {
84 "6, 3, 2",
85 "7, 3, 2",
86 "6, 0, null",
87 "null, 3, null",
88 "6, null, null",
89 "null, null, null"
90 }, nullValues = "null")
91 void divTest(Integer a, Integer b, Integer result) {
92 var term = IntTerms.div(IntTerms.constant(a), IntTerms.constant(b));
93 assertThat(term.getType(), is(Integer.class));
94 assertThat(term.evaluate(Valuation.empty()), is(result));
95 }
96
97 @ParameterizedTest(name = "{0} ** {1} == {2}")
98 @CsvSource(value = {
99 "1, 0, 1",
100 "1, 3, 1",
101 "1, -3, null",
102 "2, 0, 1",
103 "2, 2, 4",
104 "2, 3, 8",
105 "2, 4, 16",
106 "2, 5, 32",
107 "2, 6, 64",
108 "2, -3, null",
109 "null, 3, null",
110 "2, null, null",
111 "null, null, null"
112 }, nullValues = "null")
113 void powTest(Integer a, Integer b, Integer result) {
114 var term = IntTerms.pow(IntTerms.constant(a), IntTerms.constant(b));
115 assertThat(term.getType(), is(Integer.class));
116 assertThat(term.evaluate(Valuation.empty()), is(result));
117 }
118
119 @ParameterizedTest(name = "min({0}, {1}) == {2}")
120 @CsvSource(value = {
121 "1, 2, 1",
122 "2, 1, 1",
123 "null, 2, null",
124 "1, null, null",
125 "null, null, null"
126 }, nullValues = "null")
127 void minTest(Integer a, Integer b, Integer result) {
128 var term = IntTerms.min(IntTerms.constant(a), IntTerms.constant(b));
129 assertThat(term.getType(), is(Integer.class));
130 assertThat(term.evaluate(Valuation.empty()), is(result));
131 }
132
133 @ParameterizedTest(name = "max({0}, {1}) == {2}")
134 @CsvSource(value = {
135 "1, 2, 2",
136 "2, 1, 2",
137 "null, 2, null",
138 "1, null, null",
139 "null, null, null"
140 }, nullValues = "null")
141 void maxTest(Integer a, Integer b, Integer result) {
142 var term = IntTerms.max(IntTerms.constant(a), IntTerms.constant(b));
143 assertThat(term.getType(), is(Integer.class));
144 assertThat(term.evaluate(Valuation.empty()), is(result));
145 }
146
147 @ParameterizedTest(name = "({0} == {1}) == {2}")
148 @CsvSource(value = {
149 "1, 1, true",
150 "1, 2, false",
151 "null, 1, null",
152 "1, null, null",
153 "null, null, null"
154 }, nullValues = "null")
155 void eqTest(Integer a, Integer b, Boolean result) {
156 var term = IntTerms.eq(IntTerms.constant(a), IntTerms.constant(b));
157 assertThat(term.getType(), is(Boolean.class));
158 assertThat(term.evaluate(Valuation.empty()), is(result));
159 }
160
161 @ParameterizedTest(name = "({0} != {1}) == {2}")
162 @CsvSource(value = {
163 "1, 1, false",
164 "1, 2, true",
165 "null, 1, null",
166 "1, null, null",
167 "null, null, null"
168 }, nullValues = "null")
169 void notEqTest(Integer a, Integer b, Boolean result) {
170 var term = IntTerms.notEq(IntTerms.constant(a), IntTerms.constant(b));
171 assertThat(term.getType(), is(Boolean.class));
172 assertThat(term.evaluate(Valuation.empty()), is(result));
173 }
174
175 @ParameterizedTest(name = "({0} < {1}) == {2}")
176 @CsvSource(value = {
177 "1, -2, false",
178 "1, 1, false",
179 "1, 2, true",
180 "null, 1, null",
181 "1, null, null",
182 "null, null, null"
183 }, nullValues = "null")
184 void lessTest(Integer a, Integer b, Boolean result) {
185 var term = IntTerms.less(IntTerms.constant(a), IntTerms.constant(b));
186 assertThat(term.getType(), is(Boolean.class));
187 assertThat(term.evaluate(Valuation.empty()), is(result));
188 }
189
190 @ParameterizedTest(name = "({0} <= {1}) == {2}")
191 @CsvSource(value = {
192 "1, -2, false",
193 "1, 1, true",
194 "1, 2, true",
195 "null, 1, null",
196 "1, null, null",
197 "null, null, null"
198 }, nullValues = "null")
199 void lessEqTest(Integer a, Integer b, Boolean result) {
200 var term = IntTerms.lessEq(IntTerms.constant(a), IntTerms.constant(b));
201 assertThat(term.getType(), is(Boolean.class));
202 assertThat(term.evaluate(Valuation.empty()), is(result));
203 }
204
205 @ParameterizedTest(name = "({0} > {1}) == {2}")
206 @CsvSource(value = {
207 "1, -2, true",
208 "1, 1, false",
209 "1, 2, false",
210 "null, 1, null",
211 "1, null, null",
212 "null, null, null"
213 }, nullValues = "null")
214 void greaterTest(Integer a, Integer b, Boolean result) {
215 var term = IntTerms.greater(IntTerms.constant(a), IntTerms.constant(b));
216 assertThat(term.getType(), is(Boolean.class));
217 assertThat(term.evaluate(Valuation.empty()), is(result));
218 }
219
220 @ParameterizedTest(name = "({0} >= {1}) == {2}")
221 @CsvSource(value = {
222 "1, -2, true",
223 "1, 1, true",
224 "1, 2, false",
225 "null, 1, null",
226 "1, null, null",
227 "null, null, null"
228 }, nullValues = "null")
229 void greaterEqTest(Integer a, Integer b, Boolean result) {
230 var term = IntTerms.greaterEq(IntTerms.constant(a), IntTerms.constant(b));
231 assertThat(term.getType(), is(Boolean.class));
232 assertThat(term.evaluate(Valuation.empty()), is(result));
233 }
234
235 @ParameterizedTest(name = "{0} as int == {1}")
236 @MethodSource
237 void asIntTest(Double a, Integer result) {
238 var term = IntTerms.asInt(RealTerms.constant(a));
239 assertThat(term.getType(), is(Integer.class));
240 assertThat(term.evaluate(Valuation.empty()), is(result));
241 }
242
243 static Stream<Arguments> asIntTest() {
244 return Stream.of(
245 Arguments.of(2.0, 2),
246 Arguments.of(2.1, 2),
247 Arguments.of(2.9, 2),
248 Arguments.of(-2.0, -2),
249 Arguments.of(-2.1, -2),
250 Arguments.of(-2.9, -2),
251 Arguments.of(0.0, 0),
252 Arguments.of(-0.0, 0),
253 Arguments.of(Double.POSITIVE_INFINITY, Integer.MAX_VALUE),
254 Arguments.of(Double.NEGATIVE_INFINITY, Integer.MIN_VALUE),
255 Arguments.of(Double.NaN, null),
256 Arguments.of(null, null)
257 );
258 }
259}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java
new file mode 100644
index 00000000..6a8eebf1
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/real/RealTermEvaluateTest.java
@@ -0,0 +1,238 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.real;
7
8import org.hamcrest.Matcher;
9import org.junit.jupiter.params.ParameterizedTest;
10import org.junit.jupiter.params.provider.CsvSource;
11import tools.refinery.store.query.term.int_.IntTerms;
12import tools.refinery.store.query.valuation.Valuation;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.*;
16
17class RealTermEvaluateTest {
18 public static final double TOLERANCE = 1e-6;
19
20 private static Matcher<Double> closeToOrNull(Double expected) {
21 return expected == null ? nullValue(Double.class) : closeTo(expected, TOLERANCE);
22 }
23
24 @ParameterizedTest(name = "+{0} == {1}")
25 @CsvSource(value = {
26 "2.5, 2.5",
27 "null, null"
28 }, nullValues = "null")
29 void plusTest(Double a, Double result) {
30 var term = RealTerms.plus(RealTerms.constant(a));
31 assertThat(term.getType(), is(Double.class));
32 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
33 }
34
35 @ParameterizedTest(name = "-{0} == {1}")
36 @CsvSource(value = {
37 "2.5, -2.5",
38 "null, null"
39 }, nullValues = "null")
40 void minusTest(Double a, Double result) {
41 var term = RealTerms.minus(RealTerms.constant(a));
42 assertThat(term.getType(), is(Double.class));
43 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
44 }
45
46 @ParameterizedTest(name = "{0} + {1} == {2}")
47 @CsvSource(value = {
48 "1.2, 2.3, 3.5",
49 "null, 2.3, null",
50 "1.2, null, null",
51 "null, null, null"
52 }, nullValues = "null")
53 void addTest(Double a, Double b, Double result) {
54 var term = RealTerms.add(RealTerms.constant(a), RealTerms.constant(b));
55 assertThat(term.getType(), is(Double.class));
56 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
57 }
58
59 @ParameterizedTest(name = "{0} - {1} == {2}")
60 @CsvSource(value = {
61 "1.2, 3.4, -2.2",
62 "null, 3.4, null",
63 "1.2, null, null",
64 "null, null, null"
65 }, nullValues = "null")
66 void subTest(Double a, Double b, Double result) {
67 var term = RealTerms.sub(RealTerms.constant(a), RealTerms.constant(b));
68 assertThat(term.getType(), is(Double.class));
69 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
70 }
71
72 @ParameterizedTest(name = "{0} * {1} == {2}")
73 @CsvSource(value = {
74 "2.3, 3.4, 7.82",
75 "null, 3.4, null",
76 "2.3, null, null",
77 "null, null, null"
78 }, nullValues = "null")
79 void mulTest(Double a, Double b, Double result) {
80 var term = RealTerms.mul(RealTerms.constant(a), RealTerms.constant(b));
81 assertThat(term.getType(), is(Double.class));
82 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
83 }
84
85 @ParameterizedTest(name = "{0} * {1} == {2}")
86 @CsvSource(value = {
87 "7.82, 3.4, 2.3",
88 "null, 3.4, null",
89 "7.82, null, null",
90 "null, null, null"
91 }, nullValues = "null")
92 void divTest(Double a, Double b, Double result) {
93 var term = RealTerms.div(RealTerms.constant(a), RealTerms.constant(b));
94 assertThat(term.getType(), is(Double.class));
95 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
96 }
97
98 @ParameterizedTest(name = "{0} ** {1} == {2}")
99 @CsvSource(value = {
100 "2.0, 6.0, 64.0",
101 "null, 6.0, null",
102 "2.0, null, null",
103 "null, null, null"
104 }, nullValues = "null")
105 void powTest(Double a, Double b, Double result) {
106 var term = RealTerms.pow(RealTerms.constant(a), RealTerms.constant(b));
107 assertThat(term.getType(), is(Double.class));
108 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
109 }
110
111 @ParameterizedTest(name = "min({0}, {1}) == {2}")
112 @CsvSource(value = {
113 "1.5, 2.7, 1.5",
114 "2.7, 1.5, 1.5",
115 "null, 2.7, null",
116 "1.5, null, null",
117 "null, null, null"
118 }, nullValues = "null")
119 void minTest(Double a, Double b, Double result) {
120 var term = RealTerms.min(RealTerms.constant(a), RealTerms.constant(b));
121 assertThat(term.getType(), is(Double.class));
122 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
123 }
124
125 @ParameterizedTest(name = "max({0}, {1}) == {2}")
126 @CsvSource(value = {
127 "1.5, 2.7, 2.7",
128 "2.7, 1.7, 2.7",
129 "null, 2.7, null",
130 "1.5, null, null",
131 "null, null, null"
132 }, nullValues = "null")
133 void maxTest(Double a, Double b, Double result) {
134 var term = RealTerms.max(RealTerms.constant(a), RealTerms.constant(b));
135 assertThat(term.getType(), is(Double.class));
136 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
137 }
138
139 @ParameterizedTest(name = "({0} == {1}) == {2}")
140 @CsvSource(value = {
141 "1.5, 1.5, true",
142 "1.5, 2.7, false",
143 "null, 1.5, null",
144 "1.5, null, null",
145 "null, null, null"
146 }, nullValues = "null")
147 void eqTest(Double a, Double b, Boolean result) {
148 var term = RealTerms.eq(RealTerms.constant(a), RealTerms.constant(b));
149 assertThat(term.getType(), is(Boolean.class));
150 assertThat(term.evaluate(Valuation.empty()), is(result));
151 }
152
153 @ParameterizedTest(name = "({0} != {1}) == {2}")
154 @CsvSource(value = {
155 "1.5, 1.5, false",
156 "1.5, 2.7, true",
157 "null, 1.5, null",
158 "1.5, null, null",
159 "null, null, null"
160 }, nullValues = "null")
161 void notEqTest(Double a, Double b, Boolean result) {
162 var term = RealTerms.notEq(RealTerms.constant(a), RealTerms.constant(b));
163 assertThat(term.getType(), is(Boolean.class));
164 assertThat(term.evaluate(Valuation.empty()), is(result));
165 }
166
167 @ParameterizedTest(name = "({0} < {1}) == {2}")
168 @CsvSource(value = {
169 "1.5, -2.7, false",
170 "1.5, 1.5, false",
171 "1.5, 2.7, true",
172 "null, 1.5, null",
173 "1.5, null, null",
174 "null, null, null"
175 }, nullValues = "null")
176 void lessTest(Double a, Double b, Boolean result) {
177 var term = RealTerms.less(RealTerms.constant(a), RealTerms.constant(b));
178 assertThat(term.getType(), is(Boolean.class));
179 assertThat(term.evaluate(Valuation.empty()), is(result));
180 }
181
182 @ParameterizedTest(name = "({0} <= {1}) == {2}")
183 @CsvSource(value = {
184 "1.5, -2.7, false",
185 "1.5, 1.5, true",
186 "1.5, 2.7, true",
187 "null, 1.5, null",
188 "1.5, null, null",
189 "null, null, null"
190 }, nullValues = "null")
191 void lessEqTest(Double a, Double b, Boolean result) {
192 var term = RealTerms.lessEq(RealTerms.constant(a), RealTerms.constant(b));
193 assertThat(term.getType(), is(Boolean.class));
194 assertThat(term.evaluate(Valuation.empty()), is(result));
195 }
196
197 @ParameterizedTest(name = "({0} > {1}) == {2}")
198 @CsvSource(value = {
199 "1.5, -2.7, true",
200 "1.5, 1.5, false",
201 "1.5, 2.7, false",
202 "null, 1.5, null",
203 "1.5, null, null",
204 "null, null, null"
205 }, nullValues = "null")
206 void greaterTest(Double a, Double b, Boolean result) {
207 var term = RealTerms.greater(RealTerms.constant(a), RealTerms.constant(b));
208 assertThat(term.getType(), is(Boolean.class));
209 assertThat(term.evaluate(Valuation.empty()), is(result));
210 }
211
212 @ParameterizedTest(name = "({0} >= {1}) == {2}")
213 @CsvSource(value = {
214 "1.5, -2.7, true",
215 "1.5, 1.5, true",
216 "1.5, 2.7, false",
217 "null, 1.5, null",
218 "1.5, null, null",
219 "null, null, null"
220 }, nullValues = "null")
221 void greaterEqTest(Double a, Double b, Boolean result) {
222 var term = RealTerms.greaterEq(RealTerms.constant(a), RealTerms.constant(b));
223 assertThat(term.getType(), is(Boolean.class));
224 assertThat(term.evaluate(Valuation.empty()), is(result));
225 }
226
227 @ParameterizedTest(name = "{0} as real == {1}")
228 @CsvSource(value = {
229 "0, 0.0",
230 "5, 5.0",
231 "null, null"
232 }, nullValues = "null")
233 void asRealTest(Integer a, Double result) {
234 var term = RealTerms.asReal(IntTerms.constant(a));
235 assertThat(term.getType(), is(Double.class));
236 assertThat(term.evaluate(Valuation.empty()), closeToOrNull(result));
237 }
238}
diff --git a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
index c529117e..31baf36e 100644
--- a/subprojects/store-query-viatra/src/test/java/tools/refinery/store/query/viatra/internal/cardinality/UpperCardinalitySumAggregationOperatorStreamTest.java
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorStreamTest.java
@@ -1,4 +1,9 @@
1package tools.refinery.store.query.viatra.internal.cardinality; 1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
2 7
3import org.junit.jupiter.params.ParameterizedTest; 8import org.junit.jupiter.params.ParameterizedTest;
4import org.junit.jupiter.params.provider.Arguments; 9import org.junit.jupiter.params.provider.Arguments;
@@ -10,14 +15,14 @@ import java.util.List;
10import java.util.stream.Stream; 15import java.util.stream.Stream;
11 16
12import static org.hamcrest.MatcherAssert.assertThat; 17import static org.hamcrest.MatcherAssert.assertThat;
13import static org.hamcrest.Matchers.equalTo; 18import static org.hamcrest.Matchers.is;
14 19
15class UpperCardinalitySumAggregationOperatorStreamTest { 20class UpperCardinalitySumAggregatorStreamTest {
16 @ParameterizedTest 21 @ParameterizedTest
17 @MethodSource 22 @MethodSource
18 void testStream(List<UpperCardinality> list, UpperCardinality expected) { 23 void testStream(List<UpperCardinality> list, UpperCardinality expected) {
19 var result = UpperCardinalitySumAggregationOperator.INSTANCE.aggregateStream(list.stream()); 24 var result = UpperCardinalitySumAggregator.INSTANCE.aggregateStream(list.stream());
20 assertThat(result, equalTo(expected)); 25 assertThat(result, is(expected));
21 } 26 }
22 27
23 static Stream<Arguments> testStream() { 28 static Stream<Arguments> testStream() {
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
new file mode 100644
index 00000000..780cd0ab
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalitySumAggregatorTest.java
@@ -0,0 +1,80 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import org.junit.jupiter.api.BeforeEach;
9import org.junit.jupiter.api.Test;
10import tools.refinery.store.query.term.StatefulAggregate;
11import tools.refinery.store.representation.cardinality.UpperCardinalities;
12import tools.refinery.store.representation.cardinality.UpperCardinality;
13
14import static org.hamcrest.MatcherAssert.assertThat;
15import static org.hamcrest.Matchers.is;
16
17class UpperCardinalitySumAggregatorTest {
18 private StatefulAggregate<UpperCardinality, UpperCardinality> accumulator;
19
20 @BeforeEach
21 void beforeEach() {
22 accumulator = UpperCardinalitySumAggregator.INSTANCE.createEmptyAggregate();
23 }
24
25 @Test
26 void emptyAggregationTest() {
27 assertThat(accumulator.getResult(), is(UpperCardinality.of(0)));
28 }
29
30 @Test
31 void singleBoundedTest() {
32 accumulator.add(UpperCardinality.of(3));
33 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
34 }
35
36 @Test
37 void multipleBoundedTest() {
38 accumulator.add(UpperCardinality.of(2));
39 accumulator.add(UpperCardinality.of(3));
40 assertThat(accumulator.getResult(), is(UpperCardinality.of(5)));
41 }
42
43 @Test
44 void singleUnboundedTest() {
45 accumulator.add(UpperCardinalities.UNBOUNDED);
46 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
47 }
48
49 @Test
50 void multipleUnboundedTest() {
51 accumulator.add(UpperCardinalities.UNBOUNDED);
52 accumulator.add(UpperCardinalities.UNBOUNDED);
53 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
54 }
55
56 @Test
57 void removeBoundedTest() {
58 accumulator.add(UpperCardinality.of(2));
59 accumulator.add(UpperCardinality.of(3));
60 accumulator.remove(UpperCardinality.of(2));
61 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
62 }
63
64 @Test
65 void removeAllUnboundedTest() {
66 accumulator.add(UpperCardinalities.UNBOUNDED);
67 accumulator.add(UpperCardinality.of(3));
68 accumulator.remove(UpperCardinalities.UNBOUNDED);
69 assertThat(accumulator.getResult(), is(UpperCardinality.of(3)));
70 }
71
72 @Test
73 void removeSomeUnboundedTest() {
74 accumulator.add(UpperCardinalities.UNBOUNDED);
75 accumulator.add(UpperCardinalities.UNBOUNDED);
76 accumulator.add(UpperCardinality.of(3));
77 accumulator.remove(UpperCardinalities.UNBOUNDED);
78 assertThat(accumulator.getResult(), is(UpperCardinalities.UNBOUNDED));
79 }
80}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
new file mode 100644
index 00000000..9d0f3bde
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/term/uppercardinality/UpperCardinalityTermsEvaluateTest.java
@@ -0,0 +1,104 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.term.uppercardinality;
7
8import org.junit.jupiter.params.ParameterizedTest;
9import org.junit.jupiter.params.provider.Arguments;
10import org.junit.jupiter.params.provider.MethodSource;
11import tools.refinery.store.query.valuation.Valuation;
12import tools.refinery.store.representation.cardinality.UpperCardinalities;
13import tools.refinery.store.representation.cardinality.UpperCardinality;
14
15import java.util.stream.Stream;
16
17import static org.hamcrest.MatcherAssert.assertThat;
18import static org.hamcrest.Matchers.is;
19
20class UpperCardinalityTermsEvaluateTest {
21 @ParameterizedTest(name = "min({0}, {1}) == {2}")
22 @MethodSource
23 void minTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
24 var term = UpperCardinalityTerms.min(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
25 assertThat(term.getType(), is(UpperCardinality.class));
26 assertThat(term.evaluate(Valuation.empty()), is(expected));
27 }
28
29 static Stream<Arguments> minTest() {
30 return Stream.of(
31 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
32 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(0)),
33 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(0)),
34 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinality.of(0)),
35 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinality.of(0)),
36 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
37 Arguments.of(UpperCardinality.of(1), null, null),
38 Arguments.of(null, UpperCardinality.of(1), null),
39 Arguments.of(null, null, null)
40 );
41 }
42
43 @ParameterizedTest(name = "max({0}, {1}) == {2}")
44 @MethodSource
45 void maxTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
46 var term = UpperCardinalityTerms.max(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
47 assertThat(term.getType(), is(UpperCardinality.class));
48 assertThat(term.evaluate(Valuation.empty()), is(expected));
49 }
50
51 static Stream<Arguments> maxTest() {
52 return Stream.of(
53 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(0), UpperCardinality.of(0)),
54 Arguments.of(UpperCardinality.of(0), UpperCardinality.of(1), UpperCardinality.of(1)),
55 Arguments.of(UpperCardinality.of(1), UpperCardinality.of(0), UpperCardinality.of(1)),
56 Arguments.of(UpperCardinality.of(0), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
57 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(0), UpperCardinalities.UNBOUNDED),
58 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
59 Arguments.of(UpperCardinality.of(1), null, null),
60 Arguments.of(null, UpperCardinality.of(1), null),
61 Arguments.of(null, null, null)
62 );
63 }
64
65 @ParameterizedTest(name = "{0} + {1} == {2}")
66 @MethodSource
67 void addTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
68 var term = UpperCardinalityTerms.add(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
69 assertThat(term.getType(), is(UpperCardinality.class));
70 assertThat(term.evaluate(Valuation.empty()), is(expected));
71 }
72
73 static Stream<Arguments> addTest() {
74 return Stream.of(
75 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(5)),
76 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
77 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
78 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
79 Arguments.of(UpperCardinality.of(1), null, null),
80 Arguments.of(null, UpperCardinality.of(1), null),
81 Arguments.of(null, null, null)
82 );
83 }
84
85 @ParameterizedTest(name = "{0} * {1} == {2}")
86 @MethodSource
87 void mulTest(UpperCardinality a, UpperCardinality b, UpperCardinality expected) {
88 var term = UpperCardinalityTerms.mul(UpperCardinalityTerms.constant(a), UpperCardinalityTerms.constant(b));
89 assertThat(term.getType(), is(UpperCardinality.class));
90 assertThat(term.evaluate(Valuation.empty()), is(expected));
91 }
92
93 static Stream<Arguments> mulTest() {
94 return Stream.of(
95 Arguments.of(UpperCardinality.of(2), UpperCardinality.of(3), UpperCardinality.of(6)),
96 Arguments.of(UpperCardinality.of(2), UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
97 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinality.of(2), UpperCardinalities.UNBOUNDED),
98 Arguments.of(UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED, UpperCardinalities.UNBOUNDED),
99 Arguments.of(UpperCardinality.of(1), null, null),
100 Arguments.of(null, UpperCardinality.of(1), null),
101 Arguments.of(null, null, null)
102 );
103 }
104}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java
new file mode 100644
index 00000000..d447e99c
--- /dev/null
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToRawTest.java
@@ -0,0 +1,159 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.junit.jupiter.api.Test;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.term.NodeVariable;
12import tools.refinery.store.query.term.ParameterDirection;
13import tools.refinery.store.query.term.Variable;
14import tools.refinery.store.query.view.AnySymbolView;
15import tools.refinery.store.query.view.KeyOnlyView;
16import tools.refinery.store.representation.Symbol;
17
18import java.util.List;
19
20import static org.hamcrest.CoreMatchers.containsString;
21import static org.hamcrest.MatcherAssert.assertThat;
22import static org.hamcrest.Matchers.allOf;
23import static org.junit.jupiter.api.Assertions.assertThrows;
24import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
25
26class StructurallyEqualToRawTest {
27 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
28 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
29 private static final AnySymbolView personView = new KeyOnlyView<>(person);
30 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
31 private static final NodeVariable p = Variable.of("p");
32 private static final NodeVariable q = Variable.of("q");
33
34 @Test
35 void flatEqualsTest() {
36 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
37
38 assertThat(actual, structurallyEqualTo(
39 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
40 List.of(List.of(personView.call(q)))
41 ));
42 }
43
44 @Test
45 void flatNotEqualsTest() {
46 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
47
48 var assertion = structurallyEqualTo(
49 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
50 List.of(List.of(friendView.call(q, q)))
51 );
52 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
53 }
54
55 @Test
56 void deepEqualsTest() {
57 var actual = Dnf.builder("Actual").parameters(q).clause(
58 Dnf.builder("Actual2").parameters(p).clause(personView.call(p)).build().call(q)
59 ).build();
60
61 assertThat(actual, structurallyEqualTo(
62 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
63 List.of(
64 List.of(
65 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
66 )
67 )
68 ));
69 }
70
71 @Test
72 void deepNotEqualsTest() {
73 var actual = Dnf.builder("Actual").parameter(q).clause(
74 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
75 ).build();
76
77 var assertion = structurallyEqualTo(
78 List.of(new SymbolicParameter(q, ParameterDirection.OUT)),
79 List.of(
80 List.of(
81 Dnf.builder("Expected2")
82 .parameters(p)
83 .clause(friendView.call(p, p))
84 .build()
85 .call(q)
86 )
87 )
88 );
89 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
90 assertThat(error.getMessage(), allOf(containsString("Expected2"), containsString("Actual2")));
91 }
92
93 @Test
94 void parameterListLengthMismatchTest() {
95 var actual = Dnf.builder("Actual").parameters(p, q).clause(
96 friendView.call(p, q)
97 ).build();
98
99 var assertion = structurallyEqualTo(
100 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
101 List.of(List.of(friendView.call(p, p)))
102 );
103
104 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
105 }
106
107 @Test
108 void parameterDirectionMismatchTest() {
109 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
110 personView.call(p)
111 ).build();
112
113 var assertion = structurallyEqualTo(
114 List.of(new SymbolicParameter(p, ParameterDirection.OUT)),
115 List.of(List.of(personView.call(p)))
116 );
117
118 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
119 }
120
121 @Test
122 void clauseCountMismatchTest() {
123 var actual = Dnf.builder("Actual").parameters(p, q).clause(
124 friendView.call(p, q)
125 ).build();
126
127 var assertion = structurallyEqualTo(
128 List.of(
129 new SymbolicParameter(p, ParameterDirection.OUT),
130 new SymbolicParameter(q, ParameterDirection.OUT)
131 ),
132 List.of(
133 List.of(friendView.call(p, q)),
134 List.of(friendView.call(q, p))
135 )
136 );
137
138 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
139 }
140
141 @Test
142 void literalCountMismatchTest() {
143 var actual = Dnf.builder("Actual").parameters(p, q).clause(
144 friendView.call(p, q)
145 ).build();
146
147 var assertion = structurallyEqualTo(
148 List.of(
149 new SymbolicParameter(p, ParameterDirection.OUT),
150 new SymbolicParameter(q, ParameterDirection.OUT)
151 ),
152 List.of(
153 List.of(friendView.call(p, q), friendView.call(q, p))
154 )
155 );
156
157 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
158 }
159}
diff --git a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java
index a61e2b65..f716b805 100644
--- a/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java
+++ b/subprojects/store-query/src/test/java/tools/refinery/store/query/tests/StructurallyEqualToTest.java
@@ -1,9 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.tests; 6package tools.refinery.store.query.tests;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
4import tools.refinery.store.query.dnf.Dnf; 9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.ParameterDirection;
5import tools.refinery.store.query.term.Variable; 12import tools.refinery.store.query.term.Variable;
6import tools.refinery.store.query.view.KeyOnlyRelationView; 13import tools.refinery.store.query.view.AnySymbolView;
14import tools.refinery.store.query.view.KeyOnlyView;
7import tools.refinery.store.representation.Symbol; 15import tools.refinery.store.representation.Symbol;
8 16
9import static org.hamcrest.CoreMatchers.containsString; 17import static org.hamcrest.CoreMatchers.containsString;
@@ -12,13 +20,15 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
12import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo; 20import static tools.refinery.store.query.tests.QueryMatchers.structurallyEqualTo;
13 21
14class StructurallyEqualToTest { 22class StructurallyEqualToTest {
23 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
24 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
25 private static final AnySymbolView personView = new KeyOnlyView<>(person);
26 private static final AnySymbolView friendView = new KeyOnlyView<>(friend);
27 private static final NodeVariable p = Variable.of("p");
28 private static final NodeVariable q = Variable.of("q");
29
15 @Test 30 @Test
16 void flatEqualsTest() { 31 void flatEqualsTest() {
17 var p = Variable.of("p");
18 var q = Variable.of("q");
19 var person = new Symbol<>("Person", 1, Boolean.class, false);
20 var personView = new KeyOnlyRelationView<>(person);
21
22 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build(); 32 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
23 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build(); 33 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(p)).build();
24 34
@@ -27,13 +37,8 @@ class StructurallyEqualToTest {
27 37
28 @Test 38 @Test
29 void flatNotEqualsTest() { 39 void flatNotEqualsTest() {
30 var p = Variable.of("p"); 40 var expected = Dnf.builder("Expected").parameters(q).clause(friendView.call(q, q)).build();
31 var q = Variable.of("q"); 41 var actual = Dnf.builder("Actual").parameters(p).clause(friendView.call(p, q)).build();
32 var person = new Symbol<>("Person", 1, Boolean.class, false);
33 var personView = new KeyOnlyRelationView<>(person);
34
35 var expected = Dnf.builder("Expected").parameters(q).clause(personView.call(q)).build();
36 var actual = Dnf.builder("Actual").parameters(p).clause(personView.call(q)).build();
37 42
38 var assertion = structurallyEqualTo(expected); 43 var assertion = structurallyEqualTo(expected);
39 assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); 44 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
@@ -41,11 +46,6 @@ class StructurallyEqualToTest {
41 46
42 @Test 47 @Test
43 void deepEqualsTest() { 48 void deepEqualsTest() {
44 var p = Variable.of("p");
45 var q = Variable.of("q");
46 var person = new Symbol<>("Person", 1, Boolean.class, false);
47 var personView = new KeyOnlyRelationView<>(person);
48
49 var expected = Dnf.builder("Expected").parameters(q).clause( 49 var expected = Dnf.builder("Expected").parameters(q).clause(
50 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) 50 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q)
51 ).build(); 51 ).build();
@@ -58,20 +58,70 @@ class StructurallyEqualToTest {
58 58
59 @Test 59 @Test
60 void deepNotEqualsTest() { 60 void deepNotEqualsTest() {
61 var p = Variable.of("p");
62 var q = Variable.of("q");
63 var person = new Symbol<>("Person", 1, Boolean.class, false);
64 var personView = new KeyOnlyRelationView<>(person);
65
66 var expected = Dnf.builder("Expected").parameters(q).clause( 61 var expected = Dnf.builder("Expected").parameters(q).clause(
67 Dnf.builder("Expected2").parameters(p).clause(personView.call(p)).build().call(q) 62 Dnf.builder("Expected2").parameters(p).clause(friendView.call(p, p)).build().call(q)
68 ).build(); 63 ).build();
69 var actual = Dnf.builder("Actual").parameters(q).clause( 64 var actual = Dnf.builder("Actual").parameter(q).clause(
70 Dnf.builder("Actual2").parameters(p).clause(personView.call(q)).build().call(q) 65 Dnf.builder("Actual2").parameters(p).clause(friendView.call(p, q)).build().call(q)
71 ).build(); 66 ).build();
72 67
73 var assertion = structurallyEqualTo(expected); 68 var assertion = structurallyEqualTo(expected);
74 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion)); 69 var error = assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
75 assertThat(error.getMessage(), containsString(" called from Expected/1 ")); 70 assertThat(error.getMessage(), containsString(" called from Expected/1 "));
76 } 71 }
72
73 @Test
74 void parameterListLengthMismatchTest() {
75 var expected = Dnf.builder("Expected").parameter(p).clause(
76 friendView.call(p, p)
77 ).build();
78 var actual = Dnf.builder("Actual").parameters(p, q).clause(
79 friendView.call(p, q)
80 ).build();
81
82 var assertion = structurallyEqualTo(expected);
83 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
84 }
85
86 @Test
87 void parameterDirectionMismatchTest() {
88 var expected = Dnf.builder("Expected").parameter(p, ParameterDirection.OUT).clause(
89 personView.call(p)
90 ).build();
91 var actual = Dnf.builder("Actual").parameter(p, ParameterDirection.IN).clause(
92 personView.call(p)
93 ).build();
94
95 var assertion = structurallyEqualTo(expected);
96 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
97 }
98
99 @Test
100 void clauseCountMismatchTest() {
101 var expected = Dnf.builder("Expected")
102 .parameters(p, q)
103 .clause(friendView.call(p, q))
104 .clause(friendView.call(q, p))
105 .build();
106 var actual = Dnf.builder("Actual").parameters(p, q).clause(
107 friendView.call(p, q)
108 ).build();
109
110 var assertion = structurallyEqualTo(expected);
111 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
112 }
113
114 @Test
115 void literalCountMismatchTest() {
116 var expected = Dnf.builder("Expected").parameters(p, q).clause(
117 friendView.call(p, q),
118 friendView.call(q, p)
119 ).build();
120 var actual = Dnf.builder("Actual").parameters(p, q).clause(
121 friendView.call(p, q)
122 ).build();
123
124 var assertion = structurallyEqualTo(expected);
125 assertThrows(AssertionError.class, () -> assertThat(actual, assertion));
126 }
77} 127}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java
index 685957c9..6a3301b3 100644
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java
+++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/MismatchDescribingDnfEqualityChecker.java
@@ -1,27 +1,52 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.tests; 6package tools.refinery.store.query.tests;
2 7
3import org.hamcrest.Description; 8import org.hamcrest.Description;
9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
4import tools.refinery.store.query.equality.DeepDnfEqualityChecker; 11import tools.refinery.store.query.equality.DeepDnfEqualityChecker;
12import tools.refinery.store.query.literal.Literal;
13
14import java.util.List;
5 15
6class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker { 16class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker {
7 private final Description description; 17 private final Description description;
8 private boolean described; 18 private boolean raw;
19 private boolean needsDescription = true;
9 20
10 MismatchDescribingDnfEqualityChecker(Description description) { 21 MismatchDescribingDnfEqualityChecker(Description description) {
11 this.description = description; 22 this.description = description;
12 } 23 }
13 24
14 public boolean isDescribed() { 25 public boolean needsDescription() {
15 return described; 26 return needsDescription;
27 }
28
29 @Override
30 public boolean dnfEqualRaw(List<SymbolicParameter> symbolicParameters, List<? extends List<? extends Literal>> clauses, Dnf other) {
31 try {
32 raw = true;
33 boolean result = super.dnfEqualRaw(symbolicParameters, clauses, other);
34 if (!result && needsDescription) {
35 description.appendText("was ").appendText(other.toDefinitionString());
36 }
37 return false;
38 } finally {
39 raw = false;
40 }
16 } 41 }
17 42
18 @Override 43 @Override
19 protected boolean doCheckEqual(Pair pair) { 44 protected boolean doCheckEqual(Pair pair) {
20 boolean result = super.doCheckEqual(pair); 45 boolean result = super.doCheckEqual(pair);
21 if (!result && !described) { 46 if (!result && needsDescription) {
22 describeMismatch(pair); 47 describeMismatch(pair);
23 // Only describe the first found (innermost) mismatch. 48 // Only describe the first found (innermost) mismatch.
24 described = true; 49 needsDescription = false;
25 } 50 }
26 return result; 51 return result;
27 } 52 }
@@ -29,12 +54,12 @@ class MismatchDescribingDnfEqualityChecker extends DeepDnfEqualityChecker {
29 private void describeMismatch(Pair pair) { 54 private void describeMismatch(Pair pair) {
30 var inProgress = getInProgress(); 55 var inProgress = getInProgress();
31 int size = inProgress.size(); 56 int size = inProgress.size();
32 if (size <= 1) { 57 if (size <= 1 && !raw) {
33 description.appendText("was ").appendText(pair.left().toDefinitionString()); 58 description.appendText("was ").appendText(pair.right().toDefinitionString());
34 return; 59 return;
35 } 60 }
36 var last = inProgress.get(size - 1); 61 var last = inProgress.get(size - 1);
37 description.appendText("expected ").appendText(last.right().toDefinitionString()); 62 description.appendText("expected ").appendText(last.left().toDefinitionString());
38 for (int i = size - 2; i >= 0; i--) { 63 for (int i = size - 2; i >= 0; i--) {
39 description.appendText(" called from ").appendText(inProgress.get(i).left().toString()); 64 description.appendText(" called from ").appendText(inProgress.get(i).left().toString());
40 } 65 }
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java
index bf1c1b74..cd449a6a 100644
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java
+++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/QueryMatchers.java
@@ -1,14 +1,46 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.tests; 6package tools.refinery.store.query.tests;
2 7
3import org.hamcrest.Matcher; 8import org.hamcrest.Matcher;
4import tools.refinery.store.query.dnf.Dnf; 9import tools.refinery.store.query.dnf.Dnf;
10import tools.refinery.store.query.dnf.SymbolicParameter;
11import tools.refinery.store.query.literal.Literal;
12
13import java.util.List;
5 14
6public final class QueryMatchers { 15public final class QueryMatchers {
7 private QueryMatchers() { 16 private QueryMatchers() {
8 throw new IllegalStateException("This is a static utility class and should not be instantiated directly"); 17 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
9 } 18 }
10 19
20 /**
21 * Compare two {@link Dnf} instances up to renaming of variables.
22 *
23 * @param expected The expected {@link Dnf} instance.
24 * @return A Hamcrest matcher for equality up to renaming of variables.
25 */
11 public static Matcher<Dnf> structurallyEqualTo(Dnf expected) { 26 public static Matcher<Dnf> structurallyEqualTo(Dnf expected) {
12 return new StructurallyEqualTo(expected); 27 return new StructurallyEqualTo(expected);
13 } 28 }
29
30 /**
31 * Compare a {@link Dnf} instance to another predicate in DNF form without constructing it.
32 * <p>
33 * This matcher should be used instead of {@link #structurallyEqualTo(Dnf)} when the validation and
34 * pre-processing associated with the {@link Dnf} constructor, i.e., validation of parameter directions,
35 * topological sorting of literals, and the reduction of trivial predicates is not desired. In particular, this
36 * matcher can be used to test for exact order of literal after pre-processing.
37 *
38 * @param expectedSymbolicParameters The expected list of symbolic parameters.
39 * @param expectedLiterals The expected clauses. Each clause is represented by a list of literals.
40 * @return A Hamcrest matcher for equality up to renaming of variables.
41 */
42 public static Matcher<Dnf> structurallyEqualTo(List<SymbolicParameter> expectedSymbolicParameters,
43 List<? extends List<? extends Literal>> expectedLiterals) {
44 return new StructurallyEqualToRaw(expectedSymbolicParameters, expectedLiterals);
45 }
14} 46}
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java
index a9a78f88..86149141 100644
--- a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java
+++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualTo.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.query.tests; 6package tools.refinery.store.query.tests;
2 7
3import org.hamcrest.Description; 8import org.hamcrest.Description;
@@ -24,7 +29,7 @@ public class StructurallyEqualTo extends TypeSafeMatcher<Dnf> {
24 if (describingChecker.dnfEqual(expected, item)) { 29 if (describingChecker.dnfEqual(expected, item)) {
25 throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison"); 30 throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison");
26 } 31 }
27 if (!describingChecker.isDescribed()) { 32 if (describingChecker.needsDescription()) {
28 super.describeMismatchSafely(item, mismatchDescription); 33 super.describeMismatchSafely(item, mismatchDescription);
29 } 34 }
30 } 35 }
diff --git a/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java
new file mode 100644
index 00000000..2f8c2944
--- /dev/null
+++ b/subprojects/store-query/src/testFixtures/java/tools/refinery/store/query/tests/StructurallyEqualToRaw.java
@@ -0,0 +1,51 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.query.tests;
7
8import org.hamcrest.Description;
9import org.hamcrest.TypeSafeMatcher;
10import tools.refinery.store.query.dnf.Dnf;
11import tools.refinery.store.query.dnf.SymbolicParameter;
12import tools.refinery.store.query.equality.DeepDnfEqualityChecker;
13import tools.refinery.store.query.literal.Literal;
14
15import java.util.List;
16
17public class StructurallyEqualToRaw extends TypeSafeMatcher<Dnf> {
18 private final List<SymbolicParameter> expectedSymbolicParameters;
19 private final List<? extends List<? extends Literal>> expectedClauses;
20
21 public StructurallyEqualToRaw(List<SymbolicParameter> expectedSymbolicParameters,
22 List<? extends List<? extends Literal>> expectedClauses) {
23 this.expectedSymbolicParameters = expectedSymbolicParameters;
24 this.expectedClauses = expectedClauses;
25 }
26
27 @Override
28 protected boolean matchesSafely(Dnf item) {
29 var checker = new DeepDnfEqualityChecker();
30 return checker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item);
31 }
32
33 @Override
34 protected void describeMismatchSafely(Dnf item, Description mismatchDescription) {
35 var describingChecker = new MismatchDescribingDnfEqualityChecker(mismatchDescription);
36 if (describingChecker.dnfEqualRaw(expectedSymbolicParameters, expectedClauses, item)) {
37 throw new IllegalStateException("Mismatched Dnf was matching on repeated comparison");
38 }
39 if (describingChecker.needsDescription()) {
40 super.describeMismatchSafely(item, mismatchDescription);
41 }
42 }
43
44 @Override
45 public void describeTo(Description description) {
46 description.appendText("structurally equal to ")
47 .appendValueList("(", ", ", ")", expectedSymbolicParameters)
48 .appendText(" <-> ")
49 .appendValueList("", ", ", ".", expectedClauses);
50 }
51}
diff --git a/subprojects/store-reasoning/build.gradle b/subprojects/store-reasoning/build.gradle
deleted file mode 100644
index cb440d9f..00000000
--- a/subprojects/store-reasoning/build.gradle
+++ /dev/null
@@ -1,7 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3}
4
5dependencies {
6 api project(':refinery-store-query')
7}
diff --git a/subprojects/store-reasoning/build.gradle.kts b/subprojects/store-reasoning/build.gradle.kts
new file mode 100644
index 00000000..abad0491
--- /dev/null
+++ b/subprojects/store-reasoning/build.gradle.kts
@@ -0,0 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9}
10
11dependencies {
12 api(project(":refinery-store-query"))
13}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java
index ebe82c8b..000171a1 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/AnyPartialInterpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 8import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java
index 0d51598b..d3a216d8 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/MergeResult.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3public enum MergeResult { 8public enum MergeResult {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java
index 4f195e97..4140d640 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/PartialInterpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3import tools.refinery.store.reasoning.representation.PartialSymbol; 8import tools.refinery.store.reasoning.representation.PartialSymbol;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java
deleted file mode 100644
index d7d0a999..00000000
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/Reasoning.java
+++ /dev/null
@@ -1,24 +0,0 @@
1package tools.refinery.store.reasoning;
2
3import tools.refinery.store.reasoning.internal.ReasoningBuilderImpl;
4import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
5import tools.refinery.store.model.ModelStoreBuilder;
6import tools.refinery.store.reasoning.representation.PartialRelation;
7
8public final class Reasoning extends ModelAdapterBuilderFactory<ReasoningAdapter,
9 ReasoningStoreAdapter, ReasoningBuilder> {
10 public static final Reasoning ADAPTER = new Reasoning();
11
12 public static final PartialRelation EXISTS = new PartialRelation("exists", 1);
13
14 public static final PartialRelation EQUALS = new PartialRelation("equals", 1);
15
16 private Reasoning() {
17 super(ReasoningAdapter.class, ReasoningStoreAdapter.class, ReasoningBuilder.class);
18 }
19
20 @Override
21 public ReasoningBuilder createBuilder(ModelStoreBuilder storeBuilder) {
22 return new ReasoningBuilderImpl(storeBuilder);
23 }
24}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
index de039dd9..8f319242 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningAdapter.java
@@ -1,12 +1,20 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.query.ResultSet;
10import tools.refinery.store.query.dnf.Dnf;
4import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 11import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
12import tools.refinery.store.reasoning.representation.PartialRelation;
5import tools.refinery.store.reasoning.representation.PartialSymbol; 13import tools.refinery.store.reasoning.representation.PartialSymbol;
6import tools.refinery.store.query.dnf.Dnf;
7import tools.refinery.store.query.ResultSet;
8 14
9public interface ReasoningAdapter extends ModelAdapter { 15public interface ReasoningAdapter extends ModelAdapter {
16 PartialRelation EXISTS = new PartialRelation("exists", 1);
17
10 @Override 18 @Override
11 ReasoningStoreAdapter getStoreAdapter(); 19 ReasoningStoreAdapter getStoreAdapter();
12 20
@@ -18,5 +26,5 @@ public interface ReasoningAdapter extends ModelAdapter {
18 26
19 <A, C> PartialInterpretation<A, C> getPartialInterpretation(PartialSymbol<A, C> partialSymbol); 27 <A, C> PartialInterpretation<A, C> getPartialInterpretation(PartialSymbol<A, C> partialSymbol);
20 28
21 ResultSet getLiftedResultSet(Dnf query); 29 ResultSet<Boolean> getLiftedResultSet(Dnf query);
22} 30}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
index 4030d296..d3a337e8 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningBuilder.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
@@ -24,5 +29,5 @@ public interface ReasoningBuilder extends ModelAdapterBuilder {
24 Dnf lift(Modality modality, Dnf query); 29 Dnf lift(Modality modality, Dnf query);
25 30
26 @Override 31 @Override
27 ReasoningStoreAdapter createStoreAdapter(ModelStore store); 32 ReasoningStoreAdapter build(ModelStore store);
28} 33}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java
index f6a6e414..c9795255 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/ReasoningStoreAdapter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning; 6package tools.refinery.store.reasoning;
2 7
3import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
index 0acf0d49..33b6f3c6 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningAdapterImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.internal; 6package tools.refinery.store.reasoning.internal;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
@@ -32,7 +37,7 @@ public class ReasoningAdapterImpl implements ReasoningAdapter {
32 } 37 }
33 38
34 @Override 39 @Override
35 public ResultSet getLiftedResultSet(Dnf query) { 40 public ResultSet<Boolean> getLiftedResultSet(Dnf query) {
36 return null; 41 return null;
37 } 42 }
38} 43}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
index e11b14bf..aa71496c 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningBuilderImpl.java
@@ -1,17 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.internal; 6package tools.refinery.store.reasoning.internal;
2 7
3import tools.refinery.store.adapter.AbstractModelAdapterBuilder; 8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
4import tools.refinery.store.model.ModelStore; 9import tools.refinery.store.model.ModelStore;
5import tools.refinery.store.model.ModelStoreBuilder; 10import tools.refinery.store.query.dnf.Dnf;
6import tools.refinery.store.reasoning.ReasoningBuilder; 11import tools.refinery.store.reasoning.ReasoningBuilder;
7import tools.refinery.store.reasoning.literal.Modality; 12import tools.refinery.store.reasoning.literal.Modality;
8import tools.refinery.store.query.dnf.Dnf;
9
10public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder implements ReasoningBuilder {
11 public ReasoningBuilderImpl(ModelStoreBuilder storeBuilder) {
12 super(storeBuilder);
13 }
14 13
14public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder<ReasoningStoreAdapterImpl>
15 implements ReasoningBuilder {
15 @Override 16 @Override
16 public ReasoningBuilder liftedQuery(Dnf liftedQuery) { 17 public ReasoningBuilder liftedQuery(Dnf liftedQuery) {
17 return null; 18 return null;
@@ -19,11 +20,12 @@ public class ReasoningBuilderImpl extends AbstractModelAdapterBuilder implements
19 20
20 @Override 21 @Override
21 public Dnf lift(Modality modality, Dnf query) { 22 public Dnf lift(Modality modality, Dnf query) {
23 checkNotConfigured();
22 return null; 24 return null;
23 } 25 }
24 26
25 @Override 27 @Override
26 public ReasoningStoreAdapterImpl createStoreAdapter(ModelStore store) { 28 public ReasoningStoreAdapterImpl doBuild(ModelStore store) {
27 return null; 29 return null;
28 } 30 }
29} 31}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
index ac06e68b..cdddd8d6 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/internal/ReasoningStoreAdapterImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.internal; 6package tools.refinery.store.reasoning.internal;
2 7
3import tools.refinery.store.reasoning.ReasoningStoreAdapter; 8import tools.refinery.store.reasoning.ReasoningStoreAdapter;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
index 2b0e0f08..ac41d170 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/DnfLifter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.lifting; 6package tools.refinery.store.reasoning.lifting;
2 7
3import org.jetbrains.annotations.Nullable; 8import org.jetbrains.annotations.Nullable;
@@ -7,16 +12,16 @@ import tools.refinery.store.query.dnf.DnfClause;
7import tools.refinery.store.query.literal.CallLiteral; 12import tools.refinery.store.query.literal.CallLiteral;
8import tools.refinery.store.query.literal.CallPolarity; 13import tools.refinery.store.query.literal.CallPolarity;
9import tools.refinery.store.query.literal.Literal; 14import tools.refinery.store.query.literal.Literal;
10import tools.refinery.store.query.term.DataVariable; 15import tools.refinery.store.query.term.NodeVariable;
11import tools.refinery.store.query.term.Variable; 16import tools.refinery.store.query.term.Variable;
12import tools.refinery.store.reasoning.Reasoning; 17import tools.refinery.store.reasoning.ReasoningAdapter;
13import tools.refinery.store.reasoning.literal.ModalConstraint; 18import tools.refinery.store.reasoning.literal.ModalConstraint;
14import tools.refinery.store.reasoning.literal.Modality; 19import tools.refinery.store.reasoning.literal.Modality;
15import tools.refinery.store.reasoning.literal.PartialLiterals; 20import tools.refinery.store.reasoning.literal.PartialLiterals;
16import tools.refinery.store.util.CycleDetectingMapper; 21import tools.refinery.store.util.CycleDetectingMapper;
17 22
18import java.util.ArrayList; 23import java.util.ArrayList;
19import java.util.HashSet; 24import java.util.LinkedHashSet;
20import java.util.List; 25import java.util.List;
21 26
22public class DnfLifter { 27public class DnfLifter {
@@ -31,10 +36,10 @@ public class DnfLifter {
31 var modality = modalDnf.modality(); 36 var modality = modalDnf.modality();
32 var dnf = modalDnf.dnf(); 37 var dnf = modalDnf.dnf();
33 var builder = Dnf.builder(); 38 var builder = Dnf.builder();
34 builder.parameters(dnf.getParameters()); 39 builder.symbolicParameters(dnf.getSymbolicParameters());
35 boolean changed = false; 40 boolean changed = false;
36 for (var clause : dnf.getClauses()) { 41 for (var clause : dnf.getClauses()) {
37 if (liftClause(modality, clause, builder)) { 42 if (liftClause(modality, dnf, clause, builder)) {
38 changed = true; 43 changed = true;
39 } 44 }
40 } 45 }
@@ -44,12 +49,9 @@ public class DnfLifter {
44 return dnf; 49 return dnf;
45 } 50 }
46 51
47 private boolean liftClause(Modality modality, DnfClause clause, DnfBuilder builder) { 52 private boolean liftClause(Modality modality, Dnf originalDnf, DnfClause clause, DnfBuilder builder) {
48 boolean changed = false; 53 boolean changed = false;
49 var quantifiedVariables = new HashSet<>(clause.boundVariables() 54 var quantifiedVariables = getQuantifiedDataVariables(originalDnf, clause);
50 .stream()
51 .filter(DataVariable.class::isInstance)
52 .toList());
53 var literals = clause.literals(); 55 var literals = clause.literals();
54 var liftedLiterals = new ArrayList<Literal>(literals.size()); 56 var liftedLiterals = new ArrayList<Literal>(literals.size());
55 for (var literal : literals) { 57 for (var literal : literals) {
@@ -69,20 +71,30 @@ public class DnfLifter {
69 } 71 }
70 for (var quantifiedVariable : quantifiedVariables) { 72 for (var quantifiedVariable : quantifiedVariables) {
71 // Quantify over data variables that are not already quantified with the expected modality. 73 // Quantify over data variables that are not already quantified with the expected modality.
72 liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE, new ModalConstraint(modality, Reasoning.EXISTS), 74 liftedLiterals.add(new CallLiteral(CallPolarity.POSITIVE,
73 List.of(quantifiedVariable))); 75 new ModalConstraint(modality, ReasoningAdapter.EXISTS), List.of(quantifiedVariable)));
74 } 76 }
75 builder.clause(liftedLiterals); 77 builder.clause(liftedLiterals);
76 return changed || !quantifiedVariables.isEmpty(); 78 return changed || !quantifiedVariables.isEmpty();
77 } 79 }
78 80
81 private static LinkedHashSet<Variable> getQuantifiedDataVariables(Dnf originalDnf, DnfClause clause) {
82 var quantifiedVariables = new LinkedHashSet<>(clause.positiveVariables());
83 for (var symbolicParameter : originalDnf.getSymbolicParameters()) {
84 // The existence of parameters will be checked outside this DNF.
85 quantifiedVariables.remove(symbolicParameter.getVariable());
86 }
87 quantifiedVariables.removeIf(variable -> !(variable instanceof NodeVariable));
88 return quantifiedVariables;
89 }
90
79 @Nullable 91 @Nullable
80 private Variable isExistsLiteralForVariable(Modality modality, Literal literal) { 92 private Variable isExistsLiteralForVariable(Modality modality, Literal literal) {
81 if (literal instanceof CallLiteral callLiteral && 93 if (literal instanceof CallLiteral callLiteral &&
82 callLiteral.getPolarity() == CallPolarity.POSITIVE && 94 callLiteral.getPolarity() == CallPolarity.POSITIVE &&
83 callLiteral.getTarget() instanceof ModalConstraint modalConstraint && 95 callLiteral.getTarget() instanceof ModalConstraint modalConstraint &&
84 modalConstraint.modality() == modality && 96 modalConstraint.modality() == modality &&
85 modalConstraint.constraint().equals(Reasoning.EXISTS)) { 97 modalConstraint.constraint().equals(ReasoningAdapter.EXISTS)) {
86 return callLiteral.getArguments().get(0); 98 return callLiteral.getArguments().get(0);
87 } 99 }
88 return null; 100 return null;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java
index ec381bb8..16fb8fbf 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/lifting/ModalDnf.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.lifting; 6package tools.refinery.store.reasoning.lifting;
2 7
3import tools.refinery.store.query.dnf.Dnf; 8import tools.refinery.store.query.dnf.Dnf;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java
index 2fbb4607..5ad1d5f8 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/ModalConstraint.java
@@ -1,9 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.literal; 6package tools.refinery.store.reasoning.literal;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
4import tools.refinery.store.query.equality.LiteralEqualityHelper; 9import tools.refinery.store.query.equality.LiteralEqualityHelper;
5import tools.refinery.store.query.literal.LiteralReduction; 10import tools.refinery.store.query.Reduction;
6import tools.refinery.store.query.term.Sort; 11import tools.refinery.store.query.term.Parameter;
7 12
8import java.util.List; 13import java.util.List;
9 14
@@ -16,12 +21,12 @@ public record ModalConstraint(Modality modality, Constraint constraint) implemen
16 } 21 }
17 22
18 @Override 23 @Override
19 public List<Sort> getSorts() { 24 public List<Parameter> getParameters() {
20 return constraint.getSorts(); 25 return constraint.getParameters();
21 } 26 }
22 27
23 @Override 28 @Override
24 public LiteralReduction getReduction() { 29 public Reduction getReduction() {
25 return constraint.getReduction(); 30 return constraint.getReduction();
26 } 31 }
27 32
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java
index f0cb59de..96466d5c 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/Modality.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.literal; 6package tools.refinery.store.reasoning.literal;
2 7
3import tools.refinery.store.query.literal.CallPolarity; 8import tools.refinery.store.query.literal.CallPolarity;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java
index f991f87f..0e46a795 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/literal/PartialLiterals.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.literal; 6package tools.refinery.store.reasoning.literal;
2 7
3import tools.refinery.store.query.literal.CallLiteral; 8import tools.refinery.store.query.literal.CallLiteral;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java
index e74cd58b..8d2cb5cf 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialFunction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.representation; 6package tools.refinery.store.reasoning.representation;
2 7
3public sealed interface AnyPartialFunction extends AnyPartialSymbol permits PartialFunction { 8public sealed interface AnyPartialFunction extends AnyPartialSymbol permits PartialFunction {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java
index 6ff5031b..788eef73 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/AnyPartialSymbol.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.representation; 6package tools.refinery.store.reasoning.representation;
2 7
3import tools.refinery.store.representation.AnyAbstractDomain; 8import tools.refinery.store.representation.AnyAbstractDomain;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java
index 59eeeefe..d58d026f 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialFunction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.representation; 6package tools.refinery.store.reasoning.representation;
2 7
3import tools.refinery.store.representation.AbstractDomain; 8import tools.refinery.store.representation.AbstractDomain;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java
index 9bae53a9..6b2f050b 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialRelation.java
@@ -1,8 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.representation; 6package tools.refinery.store.reasoning.representation;
2 7
3import tools.refinery.store.query.Constraint; 8import tools.refinery.store.query.Constraint;
4import tools.refinery.store.query.term.NodeSort; 9import tools.refinery.store.query.term.Parameter;
5import tools.refinery.store.query.term.Sort;
6import tools.refinery.store.representation.AbstractDomain; 10import tools.refinery.store.representation.AbstractDomain;
7import tools.refinery.store.representation.TruthValue; 11import tools.refinery.store.representation.TruthValue;
8import tools.refinery.store.representation.TruthValueDomain; 12import tools.refinery.store.representation.TruthValueDomain;
@@ -27,10 +31,10 @@ public record PartialRelation(String name, int arity) implements PartialSymbol<T
27 } 31 }
28 32
29 @Override 33 @Override
30 public List<Sort> getSorts() { 34 public List<Parameter> getParameters() {
31 var sorts = new Sort[arity()]; 35 var parameters = new Parameter[arity];
32 Arrays.fill(sorts, NodeSort.INSTANCE); 36 Arrays.fill(parameters, Parameter.NODE_OUT);
33 return List.of(sorts); 37 return List.of(parameters);
34 } 38 }
35 39
36 @Override 40 @Override
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java
index 1af11f2e..3a08bdd8 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/representation/PartialSymbol.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.representation; 6package tools.refinery.store.reasoning.representation;
2 7
3import tools.refinery.store.representation.AbstractDomain; 8import tools.refinery.store.representation.AbstractDomain;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java
index e8ed05a3..0beee248 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RelationRefinementAction.java
@@ -1,6 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.rule; 6package tools.refinery.store.reasoning.rule;
2 7
3import tools.refinery.store.reasoning.Reasoning; 8import tools.refinery.store.reasoning.ReasoningAdapter;
4import tools.refinery.store.reasoning.representation.PartialRelation; 9import tools.refinery.store.reasoning.representation.PartialRelation;
5import tools.refinery.store.model.Model; 10import tools.refinery.store.model.Model;
6import tools.refinery.store.query.term.Variable; 11import tools.refinery.store.query.term.Variable;
@@ -23,7 +28,7 @@ public record RelationRefinementAction(PartialRelation target, List<Variable> ar
23 28
24 @Override 29 @Override
25 public RuleActionExecutor createExecutor(int[] argumentIndices, Model model) { 30 public RuleActionExecutor createExecutor(int[] argumentIndices, Model model) {
26 var targetInterpretation = model.getAdapter(Reasoning.ADAPTER).getPartialInterpretation(target); 31 var targetInterpretation = model.getAdapter(ReasoningAdapter.class).getPartialInterpretation(target);
27 return activationTuple -> { 32 return activationTuple -> {
28 int arity = argumentIndices.length; 33 int arity = argumentIndices.length;
29 var arguments = new int[arity]; 34 var arguments = new int[arity];
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java
index c7b16d47..45b0f02e 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/Rule.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.rule; 6package tools.refinery.store.reasoning.rule;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java
index 4753b8bc..97ea7313 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleAction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.rule; 6package tools.refinery.store.reasoning.rule;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
index 80bfa6f8..5d743869 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleActionExecutor.java
@@ -1,9 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.rule; 6package tools.refinery.store.reasoning.rule;
2 7
3import tools.refinery.store.reasoning.MergeResult; 8import tools.refinery.store.reasoning.MergeResult;
4import tools.refinery.store.tuple.TupleLike; 9import tools.refinery.store.tuple.Tuple;
5 10
6@FunctionalInterface 11@FunctionalInterface
7public interface RuleActionExecutor { 12public interface RuleActionExecutor {
8 MergeResult execute(TupleLike activationTuple); 13 MergeResult execute(Tuple activationTuple);
9} 14}
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
index 1e5322b4..32cf13ea 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/rule/RuleExecutor.java
@@ -1,8 +1,13 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.rule; 6package tools.refinery.store.reasoning.rule;
2 7
3import tools.refinery.store.reasoning.MergeResult;
4import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
5import tools.refinery.store.tuple.TupleLike; 9import tools.refinery.store.reasoning.MergeResult;
10import tools.refinery.store.tuple.Tuple;
6 11
7import java.util.List; 12import java.util.List;
8 13
@@ -24,7 +29,8 @@ public final class RuleExecutor {
24 public Model getModel() { 29 public Model getModel() {
25 return model; 30 return model;
26 } 31 }
27 public MergeResult execute(TupleLike activationTuple) { 32
33 public MergeResult execute(Tuple activationTuple) {
28 MergeResult mergeResult = MergeResult.UNCHANGED; 34 MergeResult mergeResult = MergeResult.UNCHANGED;
29 for (var actionExecutor : actionExecutors) { 35 for (var actionExecutor : actionExecutors) {
30 mergeResult = mergeResult.andAlso(actionExecutor.execute(activationTuple)); 36 mergeResult = mergeResult.andAlso(actionExecutor.execute(activationTuple));
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
index 90633495..08079f12 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/Seed.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.seed; 6package tools.refinery.store.reasoning.seed;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java
index a030f6ea..451d1513 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/seed/UniformSeed.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.seed; 6package tools.refinery.store.reasoning.seed;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java
index 5cdfedf7..d6a9e02c 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/Advice.java
@@ -1,10 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
2 7
8import tools.refinery.store.query.substitution.Substitution;
3import tools.refinery.store.reasoning.representation.AnyPartialSymbol; 9import tools.refinery.store.reasoning.representation.AnyPartialSymbol;
4import tools.refinery.store.reasoning.representation.PartialRelation; 10import tools.refinery.store.reasoning.representation.PartialRelation;
5import tools.refinery.store.query.term.Variable; 11import tools.refinery.store.query.term.Variable;
6import tools.refinery.store.query.literal.Literal; 12import tools.refinery.store.query.literal.Literal;
7import tools.refinery.store.query.substitution.Substitutions;
8 13
9import java.util.*; 14import java.util.*;
10 15
@@ -61,14 +66,9 @@ public final class Advice {
61 public List<Literal> substitute(List<Variable> substituteParameters) { 66 public List<Literal> substitute(List<Variable> substituteParameters) {
62 checkArity(substituteParameters); 67 checkArity(substituteParameters);
63 markProcessed(); 68 markProcessed();
64 int arity = parameters.size();
65 var variableMap = new HashMap<Variable, Variable>(arity);
66 for (int i = 0; i < arity; i++) {
67 variableMap.put(parameters.get(i), substituteParameters.get(i));
68 }
69 // Use a renewing substitution to remove any non-parameter variables and avoid clashed between variables 69 // Use a renewing substitution to remove any non-parameter variables and avoid clashed between variables
70 // coming from different advice in the same clause. 70 // coming from different advice in the same clause.
71 var substitution = Substitutions.renewing(variableMap); 71 var substitution = Substitution.builder().putManyChecked(parameters, substituteParameters).renewing().build();
72 return literals.stream().map(literal -> literal.substitute(substitution)).toList(); 72 return literals.stream().map(literal -> literal.substitute(substitution)).toList();
73 } 73 }
74 74
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java
index f3bd9c5e..bab20340 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/AdviceSlot.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
2 7
3import tools.refinery.store.representation.TruthValue; 8import tools.refinery.store.representation.TruthValue;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java
index 9bab80c9..4a5a8843 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslatedRelation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java
index 24b93911..6e44a7d7 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/TranslationUnit.java
@@ -1,7 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator; 6package tools.refinery.store.reasoning.translator;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStoreBuilder;
5import tools.refinery.store.reasoning.ReasoningBuilder; 9import tools.refinery.store.reasoning.ReasoningBuilder;
6 10
7import java.util.Collection; 11import java.util.Collection;
@@ -18,10 +22,6 @@ public abstract class TranslationUnit {
18 configureReasoningBuilder(); 22 configureReasoningBuilder();
19 } 23 }
20 24
21 protected ModelStoreBuilder getModelStoreBuilder() {
22 return reasoningBuilder.getStoreBuilder();
23 }
24
25 protected void configureReasoningBuilder() { 25 protected void configureReasoningBuilder() {
26 // Nothing to configure by default. 26 // Nothing to configure by default.
27 } 27 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java
index b703f142..e7b67ae4 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionInterpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.base; 6package tools.refinery.store.reasoning.translator.base;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java
index 36e2782a..a1e4b816 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/BaseDecisionTranslationUnit.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.base; 6package tools.refinery.store.reasoning.translator.base;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
@@ -24,7 +29,7 @@ public class BaseDecisionTranslationUnit extends TranslationUnit {
24 } 29 }
25 this.partialRelation = partialRelation; 30 this.partialRelation = partialRelation;
26 this.seed = seed; 31 this.seed = seed;
27 symbol = new Symbol<>(partialRelation.name(), partialRelation.arity(), TruthValue.class, TruthValue.UNKNOWN); 32 symbol = Symbol.of(partialRelation.name(), partialRelation.arity(), TruthValue.class, TruthValue.UNKNOWN);
28 } 33 }
29 34
30 public BaseDecisionTranslationUnit(PartialRelation partialRelation) { 35 public BaseDecisionTranslationUnit(PartialRelation partialRelation) {
@@ -32,11 +37,6 @@ public class BaseDecisionTranslationUnit extends TranslationUnit {
32 } 37 }
33 38
34 @Override 39 @Override
35 protected void configureReasoningBuilder() {
36 getModelStoreBuilder().symbol(symbol);
37 }
38
39 @Override
40 public Collection<TranslatedRelation> getTranslatedRelations() { 40 public Collection<TranslatedRelation> getTranslatedRelations() {
41 return List.of(new TranslatedBaseDecision(getReasoningBuilder(), partialRelation, symbol)); 41 return List.of(new TranslatedBaseDecision(getReasoningBuilder(), partialRelation, symbol));
42 } 42 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java
index 2294b4fd..4782eb46 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/base/TranslatedBaseDecision.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.base; 6package tools.refinery.store.reasoning.translator.base;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java
index 1b8d7cc9..6e4728db 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/EliminatedType.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java
index 43b8e1dd..7a917dcf 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/ExtendedTypeInfo.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import org.jetbrains.annotations.NotNull; 8import org.jetbrains.annotations.NotNull;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java
index 12c37c86..ce2d6ff3 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeRelationView.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMayTypeView.java
@@ -1,13 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
4import tools.refinery.store.query.view.TuplePreservingRelationView; 9import tools.refinery.store.query.view.TuplePreservingView;
5import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
6 11
7class InferredMayTypeRelationView extends TuplePreservingRelationView<InferredType> { 12class InferredMayTypeView extends TuplePreservingView<InferredType> {
8 private final PartialRelation type; 13 private final PartialRelation type;
9 14
10 InferredMayTypeRelationView(PartialRelation type) { 15 InferredMayTypeView(PartialRelation type) {
11 super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#may".formatted(type)); 16 super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#may".formatted(type));
12 this.type = type; 17 this.type = type;
13 } 18 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java
index 975f627e..beda1796 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeRelationView.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredMustTypeView.java
@@ -1,13 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
4import tools.refinery.store.query.view.TuplePreservingRelationView; 9import tools.refinery.store.query.view.TuplePreservingView;
5import tools.refinery.store.tuple.Tuple; 10import tools.refinery.store.tuple.Tuple;
6 11
7class InferredMustTypeRelationView extends TuplePreservingRelationView<InferredType> { 12class InferredMustTypeView extends TuplePreservingView<InferredType> {
8 private final PartialRelation type; 13 private final PartialRelation type;
9 14
10 InferredMustTypeRelationView(PartialRelation type) { 15 InferredMustTypeView(PartialRelation type) {
11 super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#must".formatted(type)); 16 super(TypeHierarchyTranslationUnit.INFERRED_TYPE_SYMBOL, "%s#must".formatted(type));
12 this.type = type; 17 this.type = type;
13 } 18 }
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
index a366e262..fd05158b 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredType.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java
index 63dba964..0696f4c3 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/PreservedType.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
index 4f915108..fbf8a7c9 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalysisResult.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3sealed interface TypeAnalysisResult permits EliminatedType, PreservedType { 8sealed interface TypeAnalysisResult permits EliminatedType, PreservedType {
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java
index 62f8e750..e97ce954 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzer.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java
index 4b0761f2..06e3c05f 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeHierarchyTranslationUnit.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
@@ -11,8 +16,8 @@ import java.util.List;
11import java.util.Map; 16import java.util.Map;
12 17
13public class TypeHierarchyTranslationUnit extends TranslationUnit { 18public class TypeHierarchyTranslationUnit extends TranslationUnit {
14 static final Symbol<InferredType> INFERRED_TYPE_SYMBOL = new Symbol<>("inferredType", 1, 19 static final Symbol<InferredType> INFERRED_TYPE_SYMBOL = Symbol.of(
15 InferredType.class, InferredType.UNTYPED); 20 "inferredType", 1, InferredType.class, InferredType.UNTYPED);
16 21
17 private final TypeAnalyzer typeAnalyzer; 22 private final TypeAnalyzer typeAnalyzer;
18 23
diff --git a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
index 313df4df..9f897e46 100644
--- a/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
+++ b/subprojects/store-reasoning/src/main/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeInfo.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java
index a8df2312..1d76855c 100644
--- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java
+++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/InferredTypeTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java
index b2c1ef1b..05a476c6 100644
--- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java
+++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerExampleHierarchyTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import org.junit.jupiter.api.BeforeEach; 8import org.junit.jupiter.api.BeforeEach;
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java
index b7b69ed8..d0ef9d57 100644
--- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java
+++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java
index 56407730..2924816e 100644
--- a/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java
+++ b/subprojects/store-reasoning/src/test/java/tools/refinery/store/reasoning/translator/typehierarchy/TypeAnalyzerTester.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.reasoning.translator.typehierarchy; 6package tools.refinery.store.reasoning.translator.typehierarchy;
2 7
3import tools.refinery.store.reasoning.representation.PartialRelation; 8import tools.refinery.store.reasoning.representation.PartialRelation;
diff --git a/subprojects/store/build.gradle b/subprojects/store/build.gradle
deleted file mode 100644
index 370d094b..00000000
--- a/subprojects/store/build.gradle
+++ /dev/null
@@ -1,4 +0,0 @@
1plugins {
2 id 'refinery-java-library'
3 id 'refinery-jmh'
4}
diff --git a/subprojects/store/build.gradle.kts b/subprojects/store/build.gradle.kts
new file mode 100644
index 00000000..2c485020
--- /dev/null
+++ b/subprojects/store/build.gradle.kts
@@ -0,0 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6
7plugins {
8 id("tools.refinery.gradle.java-library")
9 id("tools.refinery.gradle.jmh")
10}
diff --git a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java
index cdf3d3c8..485fda3d 100644
--- a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java
+++ b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutBenchmark.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.benchmarks; 6package tools.refinery.store.map.benchmarks;
2 7
3import java.util.ArrayList; 8import java.util.ArrayList;
diff --git a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java
index 756d504e..edd4f53e 100644
--- a/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java
+++ b/subprojects/store/src/jmh/java/tools/refinery/store/map/benchmarks/ImmutablePutExecutionPlan.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.benchmarks; 6package tools.refinery.store.map.benchmarks;
2 7
3import java.util.Random; 8import java.util.Random;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
index 4c142217..8d3e998e 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AbstractModelAdapterBuilder.java
@@ -1,27 +1,48 @@
1package tools.refinery.store.adapter; 1package tools.refinery.store.adapter;
2 2/*
3 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: EPL-2.0
6 */
3import tools.refinery.store.model.ModelStore; 7import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder; 8import tools.refinery.store.model.ModelStoreBuilder;
5 9
6public abstract class AbstractModelAdapterBuilder implements ModelAdapterBuilder { 10public abstract class AbstractModelAdapterBuilder<T extends ModelStoreAdapter> implements ModelAdapterBuilder {
7 private final ModelStoreBuilder storeBuilder; 11 private boolean configured;
8 12
9 protected AbstractModelAdapterBuilder(ModelStoreBuilder storeBuilder) { 13 @Override
10 this.storeBuilder = storeBuilder; 14 public boolean isConfigured() {
15 return configured;
11 } 16 }
12 17
13 @Override 18 protected void checkConfigured() {
14 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) { 19 if (!configured) {
15 return storeBuilder.with(adapterBuilderFactory); 20 throw new IllegalStateException("Model adapter builder was not configured");
21 }
22 }
23
24 protected void checkNotConfigured() {
25 if (configured) {
26 throw new IllegalStateException("Model adapter builder was already configured");
27 }
28 }
29
30 protected void doConfigure(ModelStoreBuilder storeBuilder) {
31 // Nothing to configure by default.
16 } 32 }
17 33
18 @Override 34 @Override
19 public ModelStoreBuilder getStoreBuilder() { 35 public final void configure(ModelStoreBuilder storeBuilder) {
20 return storeBuilder; 36 checkNotConfigured();
37 doConfigure(storeBuilder);
38 configured = true;
21 } 39 }
22 40
41 protected abstract T doBuild(ModelStore store);
42
23 @Override 43 @Override
24 public ModelStore build() { 44 public final T build(ModelStore store) {
25 return storeBuilder.build(); 45 checkConfigured();
46 return doBuild(store);
26 } 47 }
27} 48}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
deleted file mode 100644
index 74bae6f0..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterList.java
+++ /dev/null
@@ -1,97 +0,0 @@
1package tools.refinery.store.adapter;
2
3import org.jetbrains.annotations.NotNull;
4
5import java.util.*;
6import java.util.function.Consumer;
7
8public class AdapterList<T> implements Iterable<T> {
9 private final List<AnyModelAdapterType> adapterTypes;
10 private final List<T> adapters;
11
12 public AdapterList() {
13 adapterTypes = new ArrayList<>();
14 adapters = new ArrayList<>();
15 }
16
17 public AdapterList(int adapterCount) {
18 adapterTypes = new ArrayList<>(adapterCount);
19 adapters = new ArrayList<>(adapterCount);
20 }
21
22 public int size() {
23 return adapters.size();
24 }
25
26 public void add(AnyModelAdapterType adapterType, T adapter) {
27 adapterTypes.add(adapterType);
28 adapters.add(adapter);
29 }
30
31 public <U extends T> Optional<U> tryGet(AnyModelAdapterType adapterType, Class<? extends U> adapterClass) {
32 int size = size();
33 for (int i = 0; i < size; i++) {
34 if (getType(i).supports(adapterType)) {
35 return Optional.of(adapterClass.cast(get(i)));
36 }
37 }
38 return Optional.empty();
39 }
40
41 public <U extends T> U get(AnyModelAdapterType adapterType, Class<U> adapterClass) {
42 return tryGet(adapterType, adapterClass).orElseThrow(() -> new IllegalArgumentException(
43 "No %s was configured".formatted(adapterType)));
44 }
45
46 public AnyModelAdapterType getType(int i) {
47 return adapterTypes.get(i);
48 }
49
50 public T get(int i) {
51 return adapters.get(i);
52 }
53
54 public Collection<AnyModelAdapterType> getAdapterTypes() {
55 return Collections.unmodifiableCollection(adapterTypes);
56 }
57
58 public Iterable<Entry<T>> withAdapterTypes() {
59 return () -> new Iterator<>() {
60 private int i = 0;
61
62 @Override
63 public boolean hasNext() {
64 return i < size();
65 }
66
67 @Override
68 public Entry<T> next() {
69 if (i >= size()) {
70 throw new NoSuchElementException();
71 }
72 var entry = new Entry<>(getType(i), get(i));
73 i++;
74 return entry;
75 }
76 };
77 }
78
79 @NotNull
80 @Override
81 public Iterator<T> iterator() {
82 return adapters.iterator();
83 }
84
85 @Override
86 public void forEach(Consumer<? super T> action) {
87 adapters.forEach(action);
88 }
89
90 @Override
91 public Spliterator<T> spliterator() {
92 return adapters.spliterator();
93 }
94
95 public record Entry<T>(AnyModelAdapterType adapterType, T adapter) {
96 }
97}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java
new file mode 100644
index 00000000..556e99f0
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/AdapterUtils.java
@@ -0,0 +1,33 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.adapter;
7
8import java.util.Collection;
9import java.util.Optional;
10
11public class AdapterUtils {
12 private AdapterUtils() {
13 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
14 }
15
16 public static <T, U extends T> Optional<U> tryGetAdapter(Collection<T> adapters, Class<? extends U> type) {
17 var iterator = adapters.stream().filter(type::isInstance).iterator();
18 if (!iterator.hasNext()) {
19 return Optional.empty();
20 }
21 var adapter = type.cast(iterator.next());
22 if (iterator.hasNext()) {
23 throw new IllegalArgumentException("Ambiguous adapter: both %s and %s match %s"
24 .formatted(adapter.getClass().getName(), iterator.next().getClass().getName(), type.getName()));
25 }
26 return Optional.of(adapter);
27 }
28
29 public static <T> T getAdapter(Collection<? super T> adapters, Class<T> type) {
30 return tryGetAdapter(adapters, type).orElseThrow(() -> new IllegalArgumentException(
31 "No %s adapter was configured".formatted(type.getName())));
32 }
33}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
deleted file mode 100644
index 37a247fe..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/AnyModelAdapterType.java
+++ /dev/null
@@ -1,19 +0,0 @@
1package tools.refinery.store.adapter;
2
3import java.util.Collection;
4
5public sealed interface AnyModelAdapterType permits ModelAdapterType {
6 Class<? extends ModelAdapter> getModelAdapterClass();
7
8 Class<? extends ModelStoreAdapter> getModelStoreAdapterClass();
9
10 Class<? extends ModelAdapterBuilder> getModelAdapterBuilderClass();
11
12 Collection<AnyModelAdapterType> getSupportedAdapterTypes();
13
14 default boolean supports(AnyModelAdapterType targetAdapter) {
15 return getSupportedAdapterTypes().contains(targetAdapter);
16 }
17
18 String getName();
19}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
index aa079e01..672007aa 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.adapter; 6package tools.refinery.store.adapter;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
index 64b3e59f..75e5e07d 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilder.java
@@ -1,17 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.adapter; 6package tools.refinery.store.adapter;
2 7
3import tools.refinery.store.model.ModelStore; 8import tools.refinery.store.model.ModelStore;
4import tools.refinery.store.model.ModelStoreBuilder; 9import tools.refinery.store.model.ModelStoreBuilder;
5 10
6public interface ModelAdapterBuilder { 11public interface ModelAdapterBuilder {
7 ModelStoreAdapter createStoreAdapter(ModelStore store); 12 boolean isConfigured();
8 13
9 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory); 14 void configure(ModelStoreBuilder storeBuilder);
10 15
11 ModelStoreBuilder getStoreBuilder(); 16 ModelStoreAdapter build(ModelStore store);
12
13 default void configure() {
14 }
15
16 ModelStore build();
17} 17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
deleted file mode 100644
index 7c9b01bc..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterBuilderFactory.java
+++ /dev/null
@@ -1,14 +0,0 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.ModelStoreBuilder;
4
5public abstract class ModelAdapterBuilderFactory<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
6 T3 extends ModelAdapterBuilder> extends ModelAdapterType<T1, T2, T3> {
7
8 protected ModelAdapterBuilderFactory(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
9 Class<T3> modelAdapterBuilderClass) {
10 super(modelAdapterClass, modelStoreAdapterClass, modelAdapterBuilderClass);
11 }
12
13 public abstract T3 createBuilder(ModelStoreBuilder storeBuilder);
14}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
deleted file mode 100644
index 82ddeb12..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelAdapterType.java
+++ /dev/null
@@ -1,79 +0,0 @@
1package tools.refinery.store.adapter;
2
3import tools.refinery.store.model.Model;
4import tools.refinery.store.model.ModelStore;
5
6import java.lang.reflect.Method;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.HashSet;
10import java.util.Set;
11
12public abstract non-sealed class ModelAdapterType<T1 extends ModelAdapter, T2 extends ModelStoreAdapter,
13 T3 extends ModelAdapterBuilder> implements AnyModelAdapterType {
14 private final Class<? extends T1> modelAdapterClass;
15 private final Class<? extends T2> modelStoreAdapterClass;
16 private final Class<? extends T3> modelAdapterBuilderClass;
17 private final Set<AnyModelAdapterType> supportedAdapters = new HashSet<>();
18
19 protected ModelAdapterType(Class<T1> modelAdapterClass, Class<T2> modelStoreAdapterClass,
20 Class<T3> modelAdapterBuilderClass) {
21 checkReturnType(modelAdapterClass, modelStoreAdapterClass, "createModelAdapter", Model.class);
22 checkReturnType(modelStoreAdapterClass, modelAdapterBuilderClass, "createStoreAdapter", ModelStore.class);
23 this.modelAdapterClass = modelAdapterClass;
24 this.modelStoreAdapterClass = modelStoreAdapterClass;
25 this.modelAdapterBuilderClass = modelAdapterBuilderClass;
26 supportedAdapters.add(this);
27 }
28
29 private void checkReturnType(Class<?> expectedReturnType, Class<?> ownerClass, String methodName,
30 Class<?>... argumentTypes) {
31 Method method;
32 try {
33 method = ownerClass.getMethod(methodName, argumentTypes);
34 } catch (NoSuchMethodException e) {
35 throw new IllegalStateException("Invalid %s: %s#%s method is required"
36 .formatted(this, ownerClass.getName(), methodName), e);
37 }
38 var returnType = method.getReturnType();
39 if (!expectedReturnType.isAssignableFrom(returnType)) {
40 throw new IllegalStateException("Invalid %s: %s is not assignable from the return type %s of %s#%s"
41 .formatted(this, expectedReturnType.getName(), returnType.getCanonicalName(),
42 ownerClass.getName(), methodName));
43 }
44 }
45
46 protected void extendsAdapter(ModelAdapterType<? super T1, ? super T2, ? super T3> superAdapter) {
47 supportedAdapters.addAll(superAdapter.supportedAdapters);
48 }
49
50 @Override
51 public final Class<? extends T1> getModelAdapterClass() {
52 return modelAdapterClass;
53 }
54
55 @Override
56 public final Class<? extends T2> getModelStoreAdapterClass() {
57 return modelStoreAdapterClass;
58 }
59
60 @Override
61 public final Class<? extends T3> getModelAdapterBuilderClass() {
62 return modelAdapterBuilderClass;
63 }
64
65 @Override
66 public Collection<AnyModelAdapterType> getSupportedAdapterTypes() {
67 return Collections.unmodifiableCollection(supportedAdapters);
68 }
69
70 @Override
71 public String getName() {
72 return "%s.ADAPTER".formatted(this.getClass().getName());
73 }
74
75 @Override
76 public String toString() {
77 return getName();
78 }
79}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
index 1eb40ada..bc5f7b6b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/adapter/ModelStoreAdapter.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.adapter; 6package tools.refinery.store.adapter;
2 7
3import tools.refinery.store.model.Model; 8import tools.refinery.store.model.Model;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java
index f82a8bb1..25fc91e6 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/AnyVersionedMap.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public sealed interface AnyVersionedMap extends Versioned permits VersionedMap { 8public sealed interface AnyVersionedMap extends Versioned permits VersionedMap {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java
index 8deeab23..cbea05e1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContentHashCode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public enum ContentHashCode { 8public enum ContentHashCode {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java
index 75f1e2ab..8e451230 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/ContinousHashProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import tools.refinery.store.map.internal.Node; 8import tools.refinery.store.map.internal.Node;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java
index b420585c..3bdca104 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/Cursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import java.util.Set; 8import java.util.Set;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java b/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java
index 65ae6648..c7e4d279 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/CursorAsIterator.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import java.util.Iterator; 8import java.util.Iterator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java
index fc8e628b..0a94d449 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/Cursors.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public final class Cursors { 8public final class Cursors {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java
index 701f3ec8..4322e041 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/DiffCursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public interface DiffCursor<K, V> extends Cursor<K,V> { 8public interface DiffCursor<K, V> extends Cursor<K,V> {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java b/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java
index 6b986732..199b548f 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/MapAsIterable.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import java.util.Iterator; 8import java.util.Iterator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
index 6a23e9d5..55720db3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/Versioned.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public interface Versioned { 8public interface Versioned {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java
index 31985e94..9bbde24d 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMap.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public non-sealed interface VersionedMap<K, V> extends AnyVersionedMap { 8public non-sealed interface VersionedMap<K, V> extends AnyVersionedMap {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
index a8d7fb1a..5aafa338 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStore.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import java.util.Set; 8import java.util.Set;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java
index 3856460d..b00cd961 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreConfiguration.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3public class VersionedMapStoreConfiguration { 8public class VersionedMapStoreConfiguration {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java
index 113874e7..aade4aeb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/VersionedMapStoreImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map; 6package tools.refinery.store.map;
2 7
3import tools.refinery.store.map.internal.ImmutableNode; 8import tools.refinery.store.map.internal.ImmutableNode;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java
index 5402ed4a..61b3d1b8 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/HashClash.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3enum HashClash { 8enum HashClash {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java
index 9397dede..03dffc15 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/ImmutableNode.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3import java.util.Arrays; 8import java.util.Arrays;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java
index 91a71e3d..f34ec7bb 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapCursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3import tools.refinery.store.map.AnyVersionedMap; 8import tools.refinery.store.map.AnyVersionedMap;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java
index 9cd78113..d31f1a05 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MapDiffCursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3import tools.refinery.store.map.AnyVersionedMap; 8import tools.refinery.store.map.AnyVersionedMap;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java
index 7c3cf7e8..1129ee5a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/MutableNode.java
@@ -1,10 +1,15 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
8import tools.refinery.store.map.ContinousHashProvider;
9
3import java.util.Arrays; 10import java.util.Arrays;
4import java.util.Map; 11import java.util.Map;
5 12
6import tools.refinery.store.map.ContinousHashProvider;
7
8public class MutableNode<K, V> extends Node<K, V> { 13public class MutableNode<K, V> extends Node<K, V> {
9 int cachedHash; 14 int cachedHash;
10 protected Object[] content; 15 protected Object[] content;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java
index 2260cd5b..958d645f 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/Node.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3import java.util.Map; 8import java.util.Map;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java
index 5534c703..354af51d 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/OldValueBox.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3public class OldValueBox<V>{ 8public class OldValueBox<V>{
diff --git a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java
index 301bcb95..7abece0d 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/map/internal/VersionedMapImpl.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.internal; 6package tools.refinery.store.map.internal;
2 7
3import tools.refinery.store.map.*; 8import tools.refinery.store.map.*;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
index d18ba71d..f906b48a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/AnyInterpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.representation.AnySymbol; 8import tools.refinery.store.representation.AnySymbol;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
index 55949d0c..26ad9a69 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Interpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
index 73950779..6f7b24c1 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/InterpretationListener.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.tuple.Tuple; 8import tools.refinery.store.tuple.Tuple;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
index 6ca1ac7b..d58d91c3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/Model.java
@@ -1,7 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.adapter.ModelAdapter; 8import tools.refinery.store.adapter.ModelAdapter;
4import tools.refinery.store.adapter.ModelAdapterType;
5import tools.refinery.store.map.Versioned; 9import tools.refinery.store.map.Versioned;
6import tools.refinery.store.representation.AnySymbol; 10import tools.refinery.store.representation.AnySymbol;
7import tools.refinery.store.representation.Symbol; 11import tools.refinery.store.representation.Symbol;
@@ -25,9 +29,9 @@ public interface Model extends Versioned {
25 29
26 ModelDiffCursor getDiffCursor(long to); 30 ModelDiffCursor getDiffCursor(long to);
27 31
28 <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType); 32 <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
29 33
30 <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType); 34 <T extends ModelAdapter> T getAdapter(Class<T> adapterType);
31 35
32 void addListener(ModelListener listener); 36 void addListener(ModelListener listener);
33 37
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
index 97bf2039..7b236891 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelDiffCursor.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.map.DiffCursor; 8import tools.refinery.store.map.DiffCursor;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
index f67540bb..a9ad8cfd 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelListener.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3public interface ModelListener { 8public interface ModelListener {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
index 2e7e62c3..b10eb8a4 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStore.java
@@ -1,6 +1,10 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.adapter.ModelAdapterType;
4import tools.refinery.store.adapter.ModelStoreAdapter; 8import tools.refinery.store.adapter.ModelStoreAdapter;
5import tools.refinery.store.model.internal.ModelStoreBuilderImpl; 9import tools.refinery.store.model.internal.ModelStoreBuilderImpl;
6import tools.refinery.store.representation.AnySymbol; 10import tools.refinery.store.representation.AnySymbol;
@@ -20,9 +24,9 @@ public interface ModelStore {
20 24
21 ModelDiffCursor getDiffCursor(long from, long to); 25 ModelDiffCursor getDiffCursor(long from, long to);
22 26
23 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType); 27 <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
24 28
25 <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType); 29 <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType);
26 30
27 static ModelStoreBuilder builder() { 31 static ModelStoreBuilder builder() {
28 return new ModelStoreBuilderImpl(); 32 return new ModelStoreBuilderImpl();
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
index 289099da..3a4024b5 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/ModelStoreBuilder.java
@@ -1,8 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.adapter.ModelAdapterBuilder; 8import tools.refinery.store.adapter.ModelAdapterBuilder;
4import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.representation.AnySymbol; 9import tools.refinery.store.representation.AnySymbol;
7import tools.refinery.store.representation.Symbol; 10import tools.refinery.store.representation.Symbol;
8 11
@@ -26,11 +29,11 @@ public interface ModelStoreBuilder {
26 29
27 <T> ModelStoreBuilder symbol(Symbol<T> symbol); 30 <T> ModelStoreBuilder symbol(Symbol<T> symbol);
28 31
29 <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory); 32 <T extends ModelAdapterBuilder> ModelStoreBuilder with(T adapterBuilder);
30 33
31 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType); 34 <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(Class<? extends T> adapterType);
32 35
33 <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType); 36 <T extends ModelAdapterBuilder> T getAdapter(Class<T> adapterType);
34 37
35 ModelStore build(); 38 ModelStore build();
36} 39}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
index 4bcf9ff4..fe1c2ab5 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProvider.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.map.ContinousHashProvider; 8import tools.refinery.store.map.ContinousHashProvider;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java
index 33059a1b..14116a90 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/TupleHashProviderBitMagic.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model; 6package tools.refinery.store.model;
2 7
3import tools.refinery.store.map.ContinousHashProvider; 8import tools.refinery.store.map.ContinousHashProvider;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
index f68859db..dbd95d80 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelAction.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3public enum ModelAction { 8public enum ModelAction {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
index 9eb438c4..c5475a1a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelImpl.java
@@ -1,9 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapter; 9import tools.refinery.store.adapter.ModelAdapter;
6import tools.refinery.store.adapter.ModelAdapterType;
7import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
8import tools.refinery.store.model.*; 11import tools.refinery.store.model.*;
9import tools.refinery.store.representation.AnySymbol; 12import tools.refinery.store.representation.AnySymbol;
@@ -16,7 +19,7 @@ public class ModelImpl implements Model {
16 private final ModelStore store; 19 private final ModelStore store;
17 private long state; 20 private long state;
18 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations; 21 private Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations;
19 private final AdapterList<ModelAdapter> adapters; 22 private final List<ModelAdapter> adapters;
20 private final List<ModelListener> listeners = new ArrayList<>(); 23 private final List<ModelListener> listeners = new ArrayList<>();
21 private boolean uncommittedChanges; 24 private boolean uncommittedChanges;
22 private ModelAction pendingAction = ModelAction.NONE; 25 private ModelAction pendingAction = ModelAction.NONE;
@@ -25,7 +28,7 @@ public class ModelImpl implements Model {
25 ModelImpl(ModelStore store, long state, int adapterCount) { 28 ModelImpl(ModelStore store, long state, int adapterCount) {
26 this.store = store; 29 this.store = store;
27 this.state = state; 30 this.state = state;
28 adapters = new AdapterList<>(adapterCount); 31 adapters = new ArrayList<>(adapterCount);
29 } 32 }
30 33
31 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) { 34 void setInterpretations(Map<? extends AnySymbol, ? extends VersionedInterpretation<?>> interpretations) {
@@ -162,17 +165,17 @@ public class ModelImpl implements Model {
162 } 165 }
163 166
164 @Override 167 @Override
165 public <T extends ModelAdapter> Optional<T> tryGetAdapter(ModelAdapterType<? extends T, ?, ?> adapterType) { 168 public <T extends ModelAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
166 return adapters.tryGet(adapterType, adapterType.getModelAdapterClass()); 169 return AdapterUtils.tryGetAdapter(adapters, adapterType);
167 } 170 }
168 171
169 @Override 172 @Override
170 public <T extends ModelAdapter> T getAdapter(ModelAdapterType<T, ?, ?> adapterType) { 173 public <T extends ModelAdapter> T getAdapter(Class<T> adapterType) {
171 return adapters.get(adapterType, adapterType.getModelAdapterClass()); 174 return AdapterUtils.getAdapter(adapters, adapterType);
172 } 175 }
173 176
174 void addAdapter(AnyModelAdapterType adapterType, ModelAdapter adapter) { 177 void addAdapter(ModelAdapter adapter) {
175 adapters.add(adapterType, adapter); 178 adapters.add(adapter);
176 } 179 }
177 180
178 @Override 181 @Override
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
index 79f7195d..aafbe130 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreBuilderImpl.java
@@ -1,9 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
4import tools.refinery.store.adapter.ModelAdapterBuilder; 9import tools.refinery.store.adapter.ModelAdapterBuilder;
5import tools.refinery.store.adapter.ModelAdapterBuilderFactory;
6import tools.refinery.store.adapter.ModelAdapterType;
7import tools.refinery.store.map.VersionedMapStore; 10import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl; 11import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.model.ModelStore; 12import tools.refinery.store.model.ModelStore;
@@ -18,7 +21,7 @@ import java.util.*;
18public class ModelStoreBuilderImpl implements ModelStoreBuilder { 21public class ModelStoreBuilderImpl implements ModelStoreBuilder {
19 private final Set<AnySymbol> allSymbols = new HashSet<>(); 22 private final Set<AnySymbol> allSymbols = new HashSet<>();
20 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>(); 23 private final Map<SymbolEquivalenceClass<?>, List<AnySymbol>> equivalenceClasses = new HashMap<>();
21 private final AdapterList<ModelAdapterBuilder> adapters = new AdapterList<>(); 24 private final List<ModelAdapterBuilder> adapters = new ArrayList<>();
22 25
23 @Override 26 @Override
24 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) { 27 public <T> ModelStoreBuilder symbol(Symbol<T> symbol) {
@@ -33,46 +36,25 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
33 } 36 }
34 37
35 @Override 38 @Override
36 public <T extends ModelAdapterBuilder> T with(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) { 39 public <T extends ModelAdapterBuilder> ModelStoreBuilder with(T adapterBuilder) {
37 return adapters.<T>tryGet(adapterBuilderFactory, adapterBuilderFactory.getModelAdapterBuilderClass()) 40 for (var existingAdapter : adapters) {
38 .orElseGet(() -> addAdapter(adapterBuilderFactory)); 41 if (existingAdapter.getClass().equals(adapterBuilder.getClass())) {
39 } 42 throw new IllegalArgumentException("%s adapter was already configured for store builder"
40 43 .formatted(adapterBuilder.getClass().getName()));
41 private <T extends ModelAdapterBuilder> T addAdapter(ModelAdapterBuilderFactory<?, ?, T> adapterBuilderFactory) {
42 for (var configuredAdapterType : adapters.getAdapterTypes()) {
43 var intersection = new HashSet<>(adapterBuilderFactory.getSupportedAdapterTypes());
44 intersection.retainAll(configuredAdapterType.getSupportedAdapterTypes());
45 if (!intersection.isEmpty()) {
46 if (configuredAdapterType.supports(adapterBuilderFactory)) {
47 // Impossible to end up here from <code>#with</code>, because we should have returned
48 // the existing adapter there instead of adding a new one.
49 throw new IllegalArgumentException(
50 "Cannot add %s, because it is already provided by configured adapter %s"
51 .formatted(adapterBuilderFactory, configuredAdapterType));
52 } else if (adapterBuilderFactory.supports(configuredAdapterType)) {
53 throw new IllegalArgumentException(
54 "Cannot add %s, because it provides already configured adapter %s"
55 .formatted(adapterBuilderFactory, configuredAdapterType));
56 } else {
57 throw new IllegalArgumentException(
58 "Cannot add %s, because configured adapter %s already provides %s"
59 .formatted(adapterBuilderFactory, configuredAdapterType, intersection));
60 }
61 } 44 }
62 } 45 }
63 var newAdapter = adapterBuilderFactory.createBuilder(this); 46 adapters.add(adapterBuilder);
64 adapters.add(adapterBuilderFactory, newAdapter); 47 return this;
65 return newAdapter;
66 } 48 }
67 49
68 @Override 50 @Override
69 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(ModelAdapterType<?, ?, ? extends T> adapterType) { 51 public <T extends ModelAdapterBuilder> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
70 return adapters.tryGet(adapterType, adapterType.getModelAdapterBuilderClass()); 52 return AdapterUtils.tryGetAdapter(adapters, adapterType);
71 } 53 }
72 54
73 @Override 55 @Override
74 public <T extends ModelAdapterBuilder> T getAdapter(ModelAdapterType<?, ?, T> adapterType) { 56 public <T extends ModelAdapterBuilder> T getAdapter(Class<T> adapterType) {
75 return adapters.get(adapterType, adapterType.getModelAdapterBuilderClass()); 57 return AdapterUtils.getAdapter(adapters, adapterType);
76 } 58 }
77 59
78 @Override 60 @Override
@@ -81,13 +63,13 @@ public class ModelStoreBuilderImpl implements ModelStoreBuilder {
81 for (var entry : equivalenceClasses.entrySet()) { 63 for (var entry : equivalenceClasses.entrySet()) {
82 createStores(stores, entry.getKey(), entry.getValue()); 64 createStores(stores, entry.getKey(), entry.getValue());
83 } 65 }
84 var modelStore = new ModelStoreImpl(stores, adapters.size());
85 for (int i = adapters.size() - 1; i >= 0; i--) { 66 for (int i = adapters.size() - 1; i >= 0; i--) {
86 adapters.get(i).configure(); 67 adapters.get(i).configure(this);
87 } 68 }
88 for (var entry : adapters.withAdapterTypes()) { 69 var modelStore = new ModelStoreImpl(stores, adapters.size());
89 var adapter = entry.adapter().createStoreAdapter(modelStore); 70 for (var adapterBuilder : adapters) {
90 modelStore.addAdapter(entry.adapterType(), adapter); 71 var storeAdapter = adapterBuilder.build(modelStore);
72 modelStore.addAdapter(storeAdapter);
91 } 73 }
92 return modelStore; 74 return modelStore;
93 } 75 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
index e8c205e4..60b735e6 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/ModelStoreImpl.java
@@ -1,8 +1,11 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3import tools.refinery.store.adapter.AdapterList; 8import tools.refinery.store.adapter.AdapterUtils;
4import tools.refinery.store.adapter.AnyModelAdapterType;
5import tools.refinery.store.adapter.ModelAdapterType;
6import tools.refinery.store.adapter.ModelStoreAdapter; 9import tools.refinery.store.adapter.ModelStoreAdapter;
7import tools.refinery.store.map.DiffCursor; 10import tools.refinery.store.map.DiffCursor;
8import tools.refinery.store.map.VersionedMapStore; 11import tools.refinery.store.map.VersionedMapStore;
@@ -16,11 +19,11 @@ import java.util.*;
16 19
17public class ModelStoreImpl implements ModelStore { 20public class ModelStoreImpl implements ModelStore {
18 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores; 21 private final Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores;
19 private final AdapterList<ModelStoreAdapter> adapters; 22 private final List<ModelStoreAdapter> adapters;
20 23
21 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) { 24 ModelStoreImpl(Map<? extends AnySymbol, ? extends VersionedMapStore<Tuple, ?>> stores, int adapterCount) {
22 this.stores = stores; 25 this.stores = stores;
23 adapters = new AdapterList<>(adapterCount); 26 adapters = new ArrayList<>(adapterCount);
24 } 27 }
25 28
26 @Override 29 @Override
@@ -59,9 +62,9 @@ public class ModelStoreImpl implements ModelStore {
59 } 62 }
60 63
61 private void adaptModel(ModelImpl model) { 64 private void adaptModel(ModelImpl model) {
62 for (var entry : adapters.withAdapterTypes()) { 65 for (var storeAdapter : adapters) {
63 var adapter = entry.adapter().createModelAdapter(model); 66 var adapter = storeAdapter.createModelAdapter(model);
64 model.addAdapter(entry.adapterType(), adapter); 67 model.addAdapter(adapter);
65 } 68 }
66 } 69 }
67 70
@@ -86,16 +89,16 @@ public class ModelStoreImpl implements ModelStore {
86 } 89 }
87 90
88 @Override 91 @Override
89 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(ModelAdapterType<?, ? extends T, ?> adapterType) { 92 public <T extends ModelStoreAdapter> Optional<T> tryGetAdapter(Class<? extends T> adapterType) {
90 return adapters.tryGet(adapterType, adapterType.getModelStoreAdapterClass()); 93 return AdapterUtils.tryGetAdapter(adapters, adapterType);
91 } 94 }
92 95
93 @Override 96 @Override
94 public <T extends ModelStoreAdapter> T getAdapter(ModelAdapterType<?, T, ?> adapterType) { 97 public <T extends ModelStoreAdapter> T getAdapter(Class<T> adapterType) {
95 return adapters.get(adapterType, adapterType.getModelStoreAdapterClass()); 98 return AdapterUtils.getAdapter(adapters, adapterType);
96 } 99 }
97 100
98 void addAdapter(AnyModelAdapterType adapterType, ModelStoreAdapter adapter) { 101 void addAdapter(ModelStoreAdapter adapter) {
99 adapters.add(adapterType, adapter); 102 adapters.add(adapter);
100 } 103 }
101} 104}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
index 5bf1b90d..136f2976 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/SymbolEquivalenceClass.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3import tools.refinery.store.representation.Symbol; 8import tools.refinery.store.representation.Symbol;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
index 6d82f5d7..86101ce3 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/model/internal/VersionedInterpretation.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.internal; 6package tools.refinery.store.model.internal;
2 7
3import tools.refinery.store.map.Cursor; 8import tools.refinery.store.map.Cursor;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java
index 18903ead..52c740e8 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AbstractDomain.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3import java.util.Optional; 8import java.util.Optional;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java
index 4c428a1e..c354fab7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnyAbstractDomain.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3public sealed interface AnyAbstractDomain permits AbstractDomain { 8public sealed interface AnyAbstractDomain permits AbstractDomain {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
index 20b9eead..b2377905 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/AnySymbol.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3public sealed interface AnySymbol permits Symbol { 8public sealed interface AnySymbol permits Symbol {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
index 30b1c03f..cc748180 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/Symbol.java
@@ -1,19 +1,25 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3public record Symbol<T>(String name, int arity, Class<T> valueType, T defaultValue) implements AnySymbol { 8public record Symbol<T>(String name, int arity, Class<T> valueType, T defaultValue) implements AnySymbol {
4 @Override 9 @Override
5 public boolean equals(Object o) { 10 public String toString() {
6 return this == o; 11 return "%s/%d".formatted(name, arity);
7 } 12 }
8 13
9 @Override 14 public static Symbol<Boolean> of(String name, int arity) {
10 public int hashCode() { 15 return of(name, arity, Boolean.class, false);
11 // Compare by identity to make hash table lookups more efficient.
12 return System.identityHashCode(this);
13 } 16 }
14 17
15 @Override 18 public static <T> Symbol<T> of(String name, int arity, Class<T> valueType) {
16 public String toString() { 19 return of(name, arity, valueType, null);
17 return "%s/%d".formatted(name, arity); 20 }
21
22 public static <T> Symbol<T> of(String name, int arity, Class<T> valueType, T defaultValue) {
23 return new Symbol<>(name, arity, valueType, defaultValue);
18 } 24 }
19} 25}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
index b7893fd3..40baf9a5 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValue.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3public enum TruthValue { 8public enum TruthValue {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java
index 29858bce..89f8dd19 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/TruthValueDomain.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation; 6package tools.refinery.store.representation;
2 7
3import java.util.Optional; 8import java.util.Optional;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
index 273d0de7..704ca2fc 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityInterval.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval { 8public sealed interface CardinalityInterval permits NonEmptyCardinalityInterval, EmptyCardinalityInterval {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
index e1a08bf9..ad16a3e8 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/CardinalityIntervals.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3public final class CardinalityIntervals { 8public final class CardinalityIntervals {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
index ab3ad9d1..49911c29 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/EmptyCardinalityInterval.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3public final class EmptyCardinalityInterval implements CardinalityInterval { 8public final class EmptyCardinalityInterval implements CardinalityInterval {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
index 381c8a57..82afdbbc 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinality.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.jetbrains.annotations.NotNull; 8import org.jetbrains.annotations.NotNull;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
index 32b3786f..38bd53bf 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/NonEmptyCardinalityInterval.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import java.util.function.BinaryOperator; 8import java.util.function.BinaryOperator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
index 593bc322..a5634020 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UnboundedUpperCardinality.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.jetbrains.annotations.NotNull; 8import org.jetbrains.annotations.NotNull;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
index d850fdc9..1e18dde0 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinalities.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3public final class UpperCardinalities { 8public final class UpperCardinalities {
diff --git a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
index c6e31cb7..5dbaa922 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/representation/cardinality/UpperCardinality.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality, 8public sealed interface UpperCardinality extends Comparable<UpperCardinality> permits FiniteUpperCardinality,
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java
index bf844c6d..6700417a 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple.java
@@ -1,28 +1,42 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.tuple; 6package tools.refinery.store.tuple;
2 7
3public sealed interface Tuple extends TupleLike permits Tuple0, Tuple1, Tuple2, TupleN { 8public sealed interface Tuple permits Tuple0, Tuple1, Tuple2, Tuple3, Tuple4, TupleN {
4 @Override 9 int getSize();
5 default Tuple toTuple() { 10
6 return this; 11 int get(int element);
7 }
8 12
9 static Tuple of() { 13 static Tuple0 of() {
10 return Tuple0.INSTANCE; 14 return Tuple0.INSTANCE;
11 } 15 }
12 16
13 static Tuple of(int value) { 17 static Tuple1 of(int value) {
14 return Tuple1.Cache.INSTANCE.getOrCreate(value); 18 return Tuple1.Cache.INSTANCE.getOrCreate(value);
15 } 19 }
16 20
17 static Tuple of(int value1, int value2) { 21 static Tuple2 of(int value1, int value2) {
18 return new Tuple2(value1, value2); 22 return new Tuple2(value1, value2);
19 } 23 }
20 24
25 static Tuple3 of(int value1, int value2, int value3) {
26 return new Tuple3(value1, value2, value3);
27 }
28
29 static Tuple4 of(int value1, int value2, int value3, int value4) {
30 return new Tuple4(value1, value2, value3, value4);
31 }
32
21 static Tuple of(int... values) { 33 static Tuple of(int... values) {
22 return switch (values.length) { 34 return switch (values.length) {
23 case 0 -> of(); 35 case 0 -> of();
24 case 1 -> of(values[0]); 36 case 1 -> of(values[0]);
25 case 2 -> of(values[0], values[1]); 37 case 2 -> of(values[0], values[1]);
38 case 3 -> of(values[0], values[1], values[2]);
39 case 4 -> of(values[0], values[1], values[2], values[3]);
26 default -> new TupleN(values); 40 default -> new TupleN(values);
27 }; 41 };
28 } 42 }
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java
index 8eea5c3a..1451099c 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple0.java
@@ -1,7 +1,18 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.tuple; 6package tools.refinery.store.tuple;
2 7
3public record Tuple0() implements Tuple { 8import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN;
4 public static Tuple0 INSTANCE = new Tuple0(); 9import static tools.refinery.store.tuple.TupleConstants.TUPLE_END;
10
11public final class Tuple0 implements Tuple {
12 public static final Tuple0 INSTANCE = new Tuple0();
13
14 private Tuple0() {
15 }
5 16
6 @Override 17 @Override
7 public int getSize() { 18 public int getSize() {
@@ -14,12 +25,7 @@ public record Tuple0() implements Tuple {
14 } 25 }
15 26
16 @Override 27 @Override
17 public int[] toArray() {
18 return new int[]{};
19 }
20
21 @Override
22 public String toString() { 28 public String toString() {
23 return "[]"; 29 return TUPLE_BEGIN + TUPLE_END;
24 } 30 }
25} 31}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java
index 07380966..cda145d7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple1.java
@@ -1,10 +1,28 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.tuple; 6package tools.refinery.store.tuple;
2 7
3import tools.refinery.store.model.TupleHashProvider; 8import tools.refinery.store.model.TupleHashProvider;
4 9
5import java.util.Arrays; 10import java.util.Arrays;
6 11
7public record Tuple1(int value0) implements Tuple { 12import static tools.refinery.store.tuple.TupleConstants.TUPLE_BEGIN;
13import static tools.refinery.store.tuple.TupleConstants.TUPLE_END;
14
15public final class Tuple1 implements Tuple {
16 private final int value0;
17
18 private Tuple1(int value0) {
19 this.value0 = value0;
20 }
21
22 public int value0() {
23 return value0;
24 }
25
8 @Override 26 @Override
9 public int getSize() { 27 public int getSize() {
10 return 1; 28 return 1;
@@ -19,13 +37,21 @@ public record Tuple1(int value0) implements Tuple {
19 } 37 }
20 38
21 @Override 39 @Override
22 public int[] toArray() { 40 public String toString() {
23 return new int[]{value0}; 41 return TUPLE_BEGIN + value0 + TUPLE_END;
24 } 42 }
25 43
26 @Override 44 @Override
27 public String toString() { 45 public boolean equals(Object o) {
28 return "[" + value0 + "]"; 46 if (this == o) return true;
47 if (o == null || getClass() != o.getClass()) return false;
48 Tuple1 tuple1 = (Tuple1) o;
49 return value0 == tuple1.value0;
50 }
51
52 @Override
53 public int hashCode() {
54 return 31 + value0;
29 } 55 }
30 56
31 /** 57 /**
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java
index 0836a32d..b669674b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple2.java
@@ -1,5 +1,12 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.tuple; 6package tools.refinery.store.tuple;
2 7
8import static tools.refinery.store.tuple.TupleConstants.*;
9
3public record Tuple2(int value0, int value1) implements Tuple { 10public record Tuple2(int value0, int value1) implements Tuple {
4 @Override 11 @Override
5 public int getSize() { 12 public int getSize() {
@@ -16,12 +23,22 @@ public record Tuple2(int value0, int value1) implements Tuple {
16 } 23 }
17 24
18 @Override 25 @Override
19 public int[] toArray() { 26 public String toString() {
20 return new int[]{value0, value1}; 27 return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_END;
21 } 28 }
22 29
23 @Override 30 @Override
24 public String toString() { 31 public boolean equals(Object o) {
25 return "[" + value0 + ", " + value1 + "]"; 32 if (this == o) return true;
33 if (o == null || getClass() != o.getClass()) return false;
34 Tuple2 tuple2 = (Tuple2) o;
35 return value0 == tuple2.value0 && value1 == tuple2.value1;
36 }
37
38 @Override
39 public int hashCode() {
40 int hash = 31 + value0;
41 hash = 31 * hash + value1;
42 return hash;
26 } 43 }
27} 44}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java
new file mode 100644
index 00000000..542ed328
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple3.java
@@ -0,0 +1,46 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.tuple;
7
8import static tools.refinery.store.tuple.TupleConstants.*;
9
10public record Tuple3(int value0, int value1, int value2) implements Tuple {
11 @Override
12 public int getSize() {
13 return 3;
14 }
15
16 @Override
17 public int get(int element) {
18 return switch (element) {
19 case 0 -> value0;
20 case 1 -> value1;
21 case 2 -> value2;
22 default -> throw new ArrayIndexOutOfBoundsException(element);
23 };
24 }
25
26 @Override
27 public String toString() {
28 return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_END;
29 }
30
31 @Override
32 public boolean equals(Object o) {
33 if (this == o) return true;
34 if (o == null || getClass() != o.getClass()) return false;
35 Tuple3 tuple3 = (Tuple3) o;
36 return value0 == tuple3.value0 && value1 == tuple3.value1 && value2 == tuple3.value2;
37 }
38
39 @Override
40 public int hashCode() {
41 int hash = 31 + value0;
42 hash = 31 * hash + value1;
43 hash = 31 * hash + value2;
44 return hash;
45 }
46}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java
new file mode 100644
index 00000000..121a15f6
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/Tuple4.java
@@ -0,0 +1,49 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.tuple;
7
8import static tools.refinery.store.tuple.TupleConstants.*;
9
10public record Tuple4(int value0, int value1, int value2, int value3) implements Tuple {
11 @Override
12 public int getSize() {
13 return 4;
14 }
15
16 @Override
17 public int get(int element) {
18 return switch (element) {
19 case 0 -> value0;
20 case 1 -> value1;
21 case 2 -> value2;
22 case 3 -> value3;
23 default -> throw new ArrayIndexOutOfBoundsException(element);
24 };
25 }
26
27 @Override
28 public String toString() {
29 return TUPLE_BEGIN + value0 + TUPLE_SEPARATOR + value1 + TUPLE_SEPARATOR + value2 + TUPLE_SEPARATOR + value3 +
30 TUPLE_END;
31 }
32
33 @Override
34 public boolean equals(Object o) {
35 if (this == o) return true;
36 if (o == null || getClass() != o.getClass()) return false;
37 Tuple4 tuple4 = (Tuple4) o;
38 return value0 == tuple4.value0 && value1 == tuple4.value1 && value2 == tuple4.value2 && value3 == tuple4.value3;
39 }
40
41 @Override
42 public int hashCode() {
43 int hash = 31 + value0;
44 hash = 31 * hash + value1;
45 hash = 31 * hash + value2;
46 hash = 31 * hash + value3;
47 return hash;
48 }
49}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java
new file mode 100644
index 00000000..f7d27848
--- /dev/null
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleConstants.java
@@ -0,0 +1,17 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.store.tuple;
7
8final class TupleConstants {
9 public static final int MAX_STATIC_ARITY_TUPLE_SIZE = 4;
10 public static final String TUPLE_BEGIN = "[";
11 public static final String TUPLE_SEPARATOR = ", ";
12 public static final String TUPLE_END = "]";
13
14 private TupleConstants() {
15 throw new IllegalArgumentException("This is a static utility class an should not instantiated directly");
16 }
17}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java
deleted file mode 100644
index 953ea9f8..00000000
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleLike.java
+++ /dev/null
@@ -1,35 +0,0 @@
1package tools.refinery.store.tuple;
2
3import java.util.stream.Collectors;
4import java.util.stream.IntStream;
5
6public interface TupleLike {
7 int getSize();
8
9 int get(int element);
10
11 default int[] toArray() {
12 int size = getSize();
13 var array = new int[size];
14 for (int i = 0; i < size; i++) {
15 array[i] = get(i);
16 }
17 return array;
18 }
19
20 default Tuple toTuple() {
21 return switch (getSize()) {
22 case 0 -> Tuple.of();
23 case 1 -> Tuple.of(get(0));
24 case 2 -> Tuple.of(get(0), get(1));
25 default -> Tuple.of(toArray());
26 };
27 }
28
29 static String toString(TupleLike tuple) {
30 var valuesString = IntStream.range(0, tuple.getSize())
31 .mapToObj(i -> Integer.toString(tuple.get(i)))
32 .collect(Collectors.joining(", "));
33 return "[" + valuesString + "]";
34 }
35}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java
index c3aed847..b66af491 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/tuple/TupleN.java
@@ -1,13 +1,23 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.tuple; 6package tools.refinery.store.tuple;
2 7
3import java.util.Arrays; 8import java.util.Arrays;
9import java.util.stream.Collectors;
4 10
5public record TupleN(int[] values) implements Tuple { 11import static tools.refinery.store.tuple.TupleConstants.*;
6 static final int CUSTOM_TUPLE_SIZE = 2;
7 12
8 public TupleN(int[] values) { 13public final class TupleN implements Tuple {
9 if (values.length < CUSTOM_TUPLE_SIZE) 14 private final int[] values;
10 throw new IllegalArgumentException(); 15
16 TupleN(int[] values) {
17 if (values.length < MAX_STATIC_ARITY_TUPLE_SIZE) {
18 throw new IllegalArgumentException("Tuples of size at most %d must use static arity Tuple classes"
19 .formatted(MAX_STATIC_ARITY_TUPLE_SIZE));
20 }
11 this.values = Arrays.copyOf(values, values.length); 21 this.values = Arrays.copyOf(values, values.length);
12 } 22 }
13 23
@@ -22,18 +32,11 @@ public record TupleN(int[] values) implements Tuple {
22 } 32 }
23 33
24 @Override 34 @Override
25 public int[] toArray() {
26 return values;
27 }
28
29 @Override
30 public String toString() { 35 public String toString() {
31 return TupleLike.toString(this); 36 var valuesString = Arrays.stream(values)
32 } 37 .mapToObj(Integer::toString)
33 38 .collect(Collectors.joining(TUPLE_SEPARATOR));
34 @Override 39 return TUPLE_BEGIN + valuesString + TUPLE_END;
35 public int hashCode() {
36 return Arrays.hashCode(values);
37 } 40 }
38 41
39 @Override 42 @Override
@@ -47,4 +50,9 @@ public record TupleN(int[] values) implements Tuple {
47 TupleN other = (TupleN) obj; 50 TupleN other = (TupleN) obj;
48 return Arrays.equals(values, other.values); 51 return Arrays.equals(values, other.values);
49 } 52 }
53
54 @Override
55 public int hashCode() {
56 return Arrays.hashCode(values);
57 }
50} 58}
diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java b/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java
index 841d0dfa..adecd79b 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/util/CollectionsUtil.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.util; 6package tools.refinery.store.util;
2 7
3import java.util.Iterator; 8import java.util.Iterator;
diff --git a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java
index 8a151d01..78ad2ad7 100644
--- a/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java
+++ b/subprojects/store/src/main/java/tools/refinery/store/util/CycleDetectingMapper.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.util; 6package tools.refinery.store.util;
2 7
3import java.util.*; 8import java.util.*;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
index 77c62305..153f2e78 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests; 6package tools.refinery.store.map.tests;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
index 1f9d022f..eabe5bd1 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java
index 93ecfec3..b0502a2b 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import org.junit.jupiter.api.Tag; 8import org.junit.jupiter.api.Tag;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
index e6334224..8274336e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
index 1ab431a8..ab2b9435 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
index f77f9ee5..502c8362 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import java.util.ArrayList; 8import java.util.ArrayList;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
index d40c49c4..32dde0da 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
index 410705a2..347c49be 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
index 2e29a03f..f7b9d61e 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import static org.junit.jupiter.api.Assertions.fail; 8import static org.junit.jupiter.api.Assertions.fail;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
index 914a0f63..4b4172d0 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz; 6package tools.refinery.store.map.tests.fuzz;
2 7
3import java.util.HashMap; 8import java.util.HashMap;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
index e75d7f5a..a819d348 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz.utils; 6package tools.refinery.store.map.tests.fuzz.utils;
2 7
3import java.util.Arrays; 8import java.util.Arrays;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
index 72f2a46c..dc621574 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.fuzz.utils; 6package tools.refinery.store.map.tests.fuzz.utils;
2 7
3import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java
index 2d03ebaf..f861f496 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.map.tests.utils; 6package tools.refinery.store.map.tests.utils;
2 7
3import tools.refinery.store.map.*; 8import tools.refinery.store.map.*;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
index bb083805..4d4f5e26 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.hashtests; 6package tools.refinery.store.model.hashtests;
2 7
3import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
index 9536a444..56b75804 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.model.tests; 6package tools.refinery.store.model.tests;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
@@ -9,27 +14,24 @@ import tools.refinery.store.tuple.Tuple;
9import static org.junit.jupiter.api.Assertions.*; 14import static org.junit.jupiter.api.Assertions.*;
10 15
11class ModelTest { 16class ModelTest {
17 private static final Symbol<Boolean> person = Symbol.of("Person", 1);
18 private static final Symbol<Integer> age = Symbol.of("age", 1, Integer.class);
19 private static final Symbol<Boolean> friend = Symbol.of("friend", 2);
20
12 @Test 21 @Test
13 void modelConstructionTest() { 22 void modelConstructionTest() {
14 var person = new Symbol<>("Person", 1, Boolean.class, false);
15 var friend = new Symbol<>("friend", 2, Boolean.class, false);
16
17 var store = ModelStore.builder().symbols(person, friend).build(); 23 var store = ModelStore.builder().symbols(person, friend).build();
18 var symbols = store.getSymbols(); 24 var symbols = store.getSymbols();
19 25
20 assertTrue(symbols.contains(person)); 26 assertTrue(symbols.contains(person));
21 assertTrue(symbols.contains(friend)); 27 assertTrue(symbols.contains(friend));
22 28
23 var other = new Symbol<>("other", 2, Integer.class, null); 29 var other = Symbol.of("other", 2, Integer.class);
24 assertFalse(symbols.contains(other)); 30 assertFalse(symbols.contains(other));
25 } 31 }
26 32
27 @Test 33 @Test
28 void modelBuildingTest() { 34 void modelBuildingTest() {
29 var person = new Symbol<>("Person", 1, Boolean.class, false);
30 var age = new Symbol<>("age", 1, Integer.class, null);
31 var friend = new Symbol<>("friend", 2, Boolean.class, false);
32
33 var store = ModelStore.builder().symbols(person, age, friend).build(); 35 var store = ModelStore.builder().symbols(person, age, friend).build();
34 var model = store.createEmptyModel(); 36 var model = store.createEmptyModel();
35 var personInterpretation = model.getInterpretation(person); 37 var personInterpretation = model.getInterpretation(person);
@@ -57,8 +59,6 @@ class ModelTest {
57 59
58 @Test 60 @Test
59 void modelBuildingArityFailTest() { 61 void modelBuildingArityFailTest() {
60 var person = new Symbol<>("Person", 1, Boolean.class, false);
61
62 var store = ModelStore.builder().symbols(person).build(); 62 var store = ModelStore.builder().symbols(person).build();
63 var model = store.createEmptyModel(); 63 var model = store.createEmptyModel();
64 var personInterpretation = model.getInterpretation(person); 64 var personInterpretation = model.getInterpretation(person);
@@ -70,8 +70,6 @@ class ModelTest {
70 70
71 @Test 71 @Test
72 void modelBuildingNullFailTest() { 72 void modelBuildingNullFailTest() {
73 var age = new Symbol<>("age", 1, Integer.class, null);
74
75 var store = ModelStore.builder().symbols(age).build(); 73 var store = ModelStore.builder().symbols(age).build();
76 var model = store.createEmptyModel(); 74 var model = store.createEmptyModel();
77 var ageInterpretation = model.getInterpretation(age); 75 var ageInterpretation = model.getInterpretation(age);
@@ -84,10 +82,6 @@ class ModelTest {
84 82
85 @Test 83 @Test
86 void modelUpdateTest() { 84 void modelUpdateTest() {
87 var person = new Symbol<>("Person", 1, Boolean.class, false);
88 var age = new Symbol<>("age", 1, Integer.class, null);
89 var friend = new Symbol<>("friend", 2, Boolean.class, false);
90
91 var store = ModelStore.builder().symbols(person, age, friend).build(); 85 var store = ModelStore.builder().symbols(person, age, friend).build();
92 var model = store.createEmptyModel(); 86 var model = store.createEmptyModel();
93 var personInterpretation = model.getInterpretation(person); 87 var personInterpretation = model.getInterpretation(person);
@@ -113,9 +107,6 @@ class ModelTest {
113 107
114 @Test 108 @Test
115 void restoreTest() { 109 void restoreTest() {
116 var person = new Symbol<>("Person", 1, Boolean.class, false);
117 var friend = new Symbol<>("friend", 2, Boolean.class, false);
118
119 var store = ModelStore.builder().symbols(person, friend).build(); 110 var store = ModelStore.builder().symbols(person, friend).build();
120 var model = store.createEmptyModel(); 111 var model = store.createEmptyModel();
121 var personInterpretation = model.getInterpretation(person); 112 var personInterpretation = model.getInterpretation(person);
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
index 96fdc49e..6a66fa84 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.params.ParameterizedTest; 8import org.junit.jupiter.params.ParameterizedTest;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
index 4a9ef8da..9fe76159 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/CardinalityIntervalsTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
index e8b77b9f..24a788a8 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/EmptyCardinalityIntervalTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
index 9a190818..6cf56fae 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteCardinalityIntervalTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
index 90c21759..7c641c47 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/FiniteUpperCardinalityTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
index 3c7c0320..e61f7b36 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalitiesTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.api.Test; 8import org.junit.jupiter.api.Test;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
index e87ce29b..10b4dd20 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/representation/cardinality/UpperCardinalityTest.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.representation.cardinality; 6package tools.refinery.store.representation.cardinality;
2 7
3import org.junit.jupiter.params.ParameterizedTest; 8import org.junit.jupiter.params.ParameterizedTest;
diff --git a/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java
index 171be0e5..8d50fa8a 100644
--- a/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java
+++ b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java
@@ -1,3 +1,8 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
1package tools.refinery.store.util; 6package tools.refinery.store.util;
2 7
3import static org.junit.jupiter.api.Assertions.assertEquals; 8import static org.junit.jupiter.api.Assertions.assertEquals;